Password hasher¶
Для шифрования паролей и их проверки воспользуемся библиотекой buddy-hashers.
Напомню абстракцию:
(ns publicator.domain.abstractions.password-hasher
(:refer-clojure :exclude [derive])
(:require [clojure.spec.alpha :as s]))
;; check нужет, т.к. derive для одного и того же пароля может давать разные результаты,
;; т.к. результат может содержать случайную соль
(defprotocol PasswordHasher
(-derive [this password])
(-check [this attempt encrypted]))
(declare ^:dynamic *password-hasher*)
(s/def ::password string?)
(s/def ::encrypted string?)
(s/fdef derive
:args (s/cat :password ::password)
:ret ::encrypted
:fn #(not= (-> % :args :password)
(-> % :ret)))
(defn derive [password]
(-derive *password-hasher* password))
(s/fdef check
:args (s/cat :attempt ::password
:encrypted ::encrypted)
:ret boolean?)
(defn check [attempt encrypted]
(-check *password-hasher* attempt encrypted))
Вот ее реализация:
(ns publicator.crypto.password-hasher
(:require
[buddy.hashers]
[publicator.domain.abstractions.password-hasher :as password-hasher]))
(deftype PasswordHasher []
password-hasher/PasswordHasher
(-derive [_ password]
(buddy.hashers/derive password))
(-check [_ attempt encrypted]
(buddy.hashers/check attempt encrypted)))
(defn binding-map []
{#'password-hasher/*password-hasher* (PasswordHasher.)})
И тест:
(ns publicator.crypto.password-hasher-test
(:require
[clojure.test :as t]
[publicator.utils.test.instrument :as instrument]
[publicator.crypto.password-hasher :as sut]
[publicator.domain.abstractions.password-hasher :as password-hasher]))
(defn- setup [t]
(with-bindings (sut/binding-map)
(t)))
(t/use-fixtures :once
instrument/fixture)
(t/use-fixtures :each
setup)
(t/deftest ok
(let [pass "strong password"
digest (password-hasher/derive pass)]
(t/is (password-hasher/check pass digest))))