Skip to content

Instantly share code, notes, and snippets.

@tca
Last active August 29, 2015 14:04
Show Gist options
  • Save tca/b2c2d3a86c3e6d301a11 to your computer and use it in GitHub Desktop.
Save tca/b2c2d3a86c3e6d301a11 to your computer and use it in GitHub Desktop.
signature AUTHORITY_CONF = sig
val hash_length : int
val iterations : int
val derive_salt : int -> string -> string -> transaction int
end
signature AUTHORITY = sig
val auth_user : string -> string -> transaction (option int)
val add_user : string -> string -> transaction (option int)
end
functor Authority(A : AUTHORITY_CONF) : AUTHORITY = struct
val hash_length = A.hash_length
val iterations = A.iterations
sequence user_counter
table users : { Id : int, UserName : string, PassHash : blob, PassSalt : string }
PRIMARY KEY (Id), CONSTRAINT UniqueUserName UNIQUE (UserName)
fun hash_pass pass salt = Pbkdf2.pkcs5_pbkdf2_hmac_sha1 hash_length iterations pass salt
fun auth_user uname pass =
user <- oneOrNoRows (SELECT *
FROM users
WHERE users.UserName={[uname]});
case user of
None => return None
| Some(user') =>
case (hash_pass pass user'.Users.PassSalt) of
None => return None
| Some(hash) => if (Pbkdf2.eq hash user'.Users.PassHash)
then return (Some user'.Users.Id)
else return None
fun add_user uname pass =
existing <- oneOrNoRows (SELECT users.Id
FROM users
WHERE users.UserName={[uname]});
case existing of
Some _ => return None
| None =>
user_id <- nextval user_counter;
salt' <- rand;
let
val salt = show salt'
in
case hash_pass pass salt of
None => return None
| Some(hash) =>
dml (INSERT INTO users (Id, UserName, PassHash, PassSalt)
VALUES ({[user_id]}, {[uname]}, {[hash]}, {[salt]}));
return (Some user_id)
end
end
structure Myauth = Authority(struct
val hash_length = 20
val iterations = 1024
fun derive_salt i u p = i <- rand; return i
end)
val auth_user = Myauth.auth_user
val add_user = Myauth.add_user
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment