example registration and login with token
cargo devel CI / cargo CI (push) Failing after 1m48s
Details
cargo devel CI / cargo CI (push) Failing after 1m48s
Details
This commit is contained in:
parent
32f9bc2ab7
commit
8173a8da7a
|
@ -101,6 +101,18 @@ version = "1.0.80"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argon2"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"blake2",
|
||||||
|
"cpufeatures",
|
||||||
|
"password-hash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-stream"
|
name = "async-stream"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
|
@ -176,6 +188,12 @@ version = "0.21.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64ct"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "binascii"
|
name = "binascii"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
|
@ -194,6 +212,15 @@ version = "2.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blake2"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
version = "0.10.4"
|
version = "0.10.4"
|
||||||
|
@ -626,6 +653,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer",
|
"block-buffer",
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1534,6 +1562,14 @@ version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "onlytoken"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"argon2",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oorandom"
|
name = "oorandom"
|
||||||
version = "11.1.3"
|
version = "11.1.3"
|
||||||
|
@ -1573,6 +1609,17 @@ dependencies = [
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "password-hash"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pear"
|
name = "pear"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
@ -2339,6 +2386,12 @@ version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "1.0.109"
|
||||||
|
|
|
@ -22,9 +22,11 @@ members = [
|
||||||
"members/rest-queued",
|
"members/rest-queued",
|
||||||
"members/fluent-demo",
|
"members/fluent-demo",
|
||||||
"members/fluent-webserv",
|
"members/fluent-webserv",
|
||||||
|
"members/onlytoken",
|
||||||
]
|
]
|
||||||
default-members = [
|
default-members = [
|
||||||
".",
|
".",
|
||||||
|
"members/onlytoken",
|
||||||
"members/fluent-webserv",
|
"members/fluent-webserv",
|
||||||
"members/fluent-demo",
|
"members/fluent-demo",
|
||||||
"members/echargs",
|
"members/echargs",
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "onlytoken"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
argon2 = "0.5.3"
|
||||||
|
rand = "0.8.5"
|
|
@ -0,0 +1,123 @@
|
||||||
|
use argon2::{
|
||||||
|
password_hash::{rand_core::OsRng, PasswordHasher, SaltString},
|
||||||
|
Argon2,
|
||||||
|
};
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
use std::{collections::HashMap, hash::Hash};
|
||||||
|
|
||||||
|
pub const ALPHABET: &str = "qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM";
|
||||||
|
pub const TOK_LEN: usize = 40;
|
||||||
|
pub type HashedToken = String;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Token {
|
||||||
|
inner: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Token {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let mut data = ALPHABET.to_string().into_bytes();
|
||||||
|
data.repeat(TOK_LEN);
|
||||||
|
data.shuffle(&mut rng);
|
||||||
|
Self {
|
||||||
|
inner: String::from_utf8(data[..TOK_LEN].to_vec()).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.inner.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn hash(&self, salt: &SaltString) -> HashedToken {
|
||||||
|
let argon2 = Argon2::default();
|
||||||
|
let hash = argon2
|
||||||
|
.hash_password(self.as_bytes(), salt)
|
||||||
|
.expect("could not hash")
|
||||||
|
.to_string();
|
||||||
|
println!("hashed token: {hash}");
|
||||||
|
hash
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_bytes(&self) -> &[u8] {
|
||||||
|
self.inner.as_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Token {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
struct User {
|
||||||
|
data: String,
|
||||||
|
hashed_tok: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl User {
|
||||||
|
fn new(data: String, salt: &SaltString) -> (Self, Token, HashedToken) {
|
||||||
|
let token = Token::new();
|
||||||
|
let hashed_tok = token.hash(salt);
|
||||||
|
(
|
||||||
|
User {
|
||||||
|
data,
|
||||||
|
hashed_tok: hashed_tok.clone(),
|
||||||
|
},
|
||||||
|
token,
|
||||||
|
hashed_tok,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Store {
|
||||||
|
users: HashMap<HashedToken, User>,
|
||||||
|
salt: SaltString,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Store {
|
||||||
|
fn new() -> Self {
|
||||||
|
let salt = SaltString::generate(&mut OsRng);
|
||||||
|
Self {
|
||||||
|
salt,
|
||||||
|
users: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn register(&mut self) -> Token {
|
||||||
|
let (user, token, hashed_tok) = User::new("garbage data".into(), &self.salt);
|
||||||
|
self.users.insert(hashed_tok, user);
|
||||||
|
token
|
||||||
|
}
|
||||||
|
fn login(&self, tok: Token) -> Option<&User> {
|
||||||
|
self.users.get(&tok.hash(&self.salt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// create the user store
|
||||||
|
// In a real application, this would be deserialized from a file or lazy-loaded from a database
|
||||||
|
let mut store = Store::new();
|
||||||
|
for _ in 0..4 {
|
||||||
|
// register a few users as noise
|
||||||
|
let _ = store.register();
|
||||||
|
}
|
||||||
|
// create our user and keep the token for that user this time
|
||||||
|
let tok = store.register();
|
||||||
|
|
||||||
|
println!("token of our user is: {tok:?}");
|
||||||
|
|
||||||
|
// try to log in with our user
|
||||||
|
let logged_in = store.login(tok.clone());
|
||||||
|
|
||||||
|
// did it work?
|
||||||
|
assert!(logged_in.is_some());
|
||||||
|
dbg!(logged_in.unwrap());
|
||||||
|
}
|
Loading…
Reference in New Issue