(defmodule lamina_auth_tests
(export all)
(include-lib "eunit/include/eunit.hrl"))
(defun setup ()
(lamina_auth:put-secret-key (crypto:strong_rand_bytes 32)))
(defun session-cookie-roundtrip_test ()
(setup)
(let ((cookie (cookie-value (lamina_auth:make-session-cookie "admin"))))
(case (lamina_auth:verify-cookie-value cookie)
(`#(ok ,username) (if (=:= username "admin") 'ok (erlang:error "wrong username")))
(other (erlang:error other)))))
(defun cookie-tamper-rejected_test ()
(setup)
(let ((cookie (cookie-value (lamina_auth:make-session-cookie "admin"))))
;; 构造同 payload 但签名错误的 cookie
(let ((payload-b64 (hd (string:split cookie "|" 'leading))))
(let ((tampered (lists:flatten (io_lib:format "~s|badsig==" (list payload-b64)))))
(case (lamina_auth:verify-cookie-value tampered)
('error 'ok)
(other (erlang:error "tampered cookie accepted")))))))
(defun expired-cookie-rejected_test ()
(setup)
(let ((payload "admin|1000")) ; 远早于当前时间
(let ((value (lists:flatten (io_lib:format "~s|~s"
(list (base64:encode payload) (lamina_auth:sign payload))))))
(case (lamina_auth:verify-cookie-value value)
('error 'ok)
(other (erlang:error "expired cookie accepted"))))))
(defun malformed-cookie-rejected-without-crash_test ()
(lists:foreach
(lambda (cookie)
(case (catch (lamina_auth:verify-cookie-value cookie))
('error 'ok)
(other (erlang:error (list "malformed cookie accepted" cookie other)))))
(list "not-base64|sig" "eA==|sig" "eA==|sig|extra" "%%%%|sig"))
'ok)
(defun csrf-test ()
(setup)
(let ((token (lamina_auth:csrf-token "admin")))
(if (and (lamina_auth:verify-csrf "admin" token)
(not (lamina_auth:verify-csrf "someone" token))
(not (lamina_auth:verify-csrf "admin" "bogus")))
'ok
(erlang:error "csrf token verification failed"))))
(defun rate-limit_test ()
(setup)
(lamina_auth:reset-fails)
(lists:foreach (lambda (_) (lamina_auth:register-fail)) (lists:seq 1 5))
(let ((locked (lamina_auth:locked?)))
(lamina_auth:reset-fails)
(if locked 'ok (erlang:error "not locked after 5 fails"))))
;;---- helpers ----
(defun cookie-value (cookie-string)
;; "lamina_session=<value>; Path=/..." -> <value>(注意 b64 含 = 填充)
(let ((rest (string:slice cookie-string (length "lamina_session=") (length cookie-string))))
(hd (string:split rest ";" 'leading))))
(defun login-cookie (username)
;; 不查库,直接构造会话(凭据校验单独测)
(lamina_auth:make-session-cookie username))