mirror of
https://github.com/vlang/v.git
synced 2025-09-09 07:15:50 -04:00
94 lines
2.2 KiB
V
94 lines
2.2 KiB
V
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
|
|
// Use of this source code is governed by an MIT license
|
|
// that can be found in the LICENSE file.
|
|
module auth
|
|
|
|
import rand
|
|
import crypto.rand as crypto_rand
|
|
import crypto.hmac
|
|
import crypto.sha256
|
|
|
|
const max_safe_unsigned_integer = u32(4_294_967_295)
|
|
|
|
pub struct Auth[T] {
|
|
db T
|
|
// pub:
|
|
// salt string
|
|
}
|
|
|
|
pub struct Token {
|
|
pub:
|
|
id int @[primary; sql: serial]
|
|
user_id int
|
|
value string
|
|
// ip string
|
|
}
|
|
|
|
pub fn new[T](db T) Auth[T] {
|
|
set_rand_crypto_safe_seed()
|
|
sql db {
|
|
create table Token
|
|
} or { eprintln('veb.auth: failed to create table Token') }
|
|
return Auth[T]{
|
|
db: db
|
|
// salt: generate_salt()
|
|
}
|
|
}
|
|
|
|
// fn (mut app App) add_token(user_id int, ip string) !string {
|
|
pub fn (mut app Auth[T]) add_token(user_id int) !string {
|
|
mut uuid := rand.uuid_v4()
|
|
token := Token{
|
|
user_id: user_id
|
|
value: uuid
|
|
// ip: ip
|
|
}
|
|
sql app.db {
|
|
insert token into Token
|
|
}!
|
|
return uuid
|
|
}
|
|
|
|
pub fn (app &Auth[T]) find_token(value string) ?Token {
|
|
tokens := sql app.db {
|
|
select from Token where value == value limit 1
|
|
} or { []Token{} }
|
|
if tokens.len == 0 {
|
|
return none
|
|
}
|
|
return tokens.first()
|
|
}
|
|
|
|
pub fn (mut app Auth[T]) delete_tokens(user_id int) ! {
|
|
sql app.db {
|
|
delete from Token where user_id == user_id
|
|
}!
|
|
}
|
|
|
|
pub fn set_rand_crypto_safe_seed() {
|
|
first_seed := generate_crypto_safe_int_u32()
|
|
second_seed := generate_crypto_safe_int_u32()
|
|
rand.seed([first_seed, second_seed])
|
|
}
|
|
|
|
fn generate_crypto_safe_int_u32() u32 {
|
|
return u32(crypto_rand.int_u64(max_safe_unsigned_integer) or { 0 })
|
|
}
|
|
|
|
pub fn generate_salt() string {
|
|
return rand.i64().str()
|
|
}
|
|
|
|
pub fn hash_password_with_salt(plain_text_password string, salt string) string {
|
|
salted_password := '${plain_text_password}${salt}'
|
|
return sha256.sum(salted_password.bytes()).hex().str()
|
|
}
|
|
|
|
pub fn compare_password_with_hash(plain_text_password string, salt string, hashed string) bool {
|
|
digest := hash_password_with_salt(plain_text_password, salt)
|
|
// constant time comparison
|
|
// I know this is operating on the hex-encoded strings, but it's still constant time
|
|
// and better than not doing it at all
|
|
return hmac.equal(digest.bytes(), hashed.bytes())
|
|
}
|