use super::funejson::Value; use super::auth_jwt_sign_jwt::sign_jwt; use super::time_unix_to_iso::unix_to_iso; /// A signed access token for a user who has just logged in, with the claims /// this API relies on: sub, name, email, ver (token version), jti, iat and /// exp. Everything that varies (the time, the random jti) is passed in. /// /// # Panics /// Panics on an empty subject or jti, a negative token version, a ttl below /// 1, or a secret under 32 bytes. #[allow(clippy::too_many_arguments)] pub fn issue_access_token( subject: &str, name: &str, email: &str, token_version: i64, jti: &str, now: i64, ttl_seconds: i64, secret: &[i64], ) -> AccessToken { if subject.is_empty() { panic!("subject must be a non-empty string"); } if token_version < 0 { panic!("tokenVersion must be a whole number, 0 or more"); } if jti.is_empty() { panic!("jti must be a non-empty string"); } if ttl_seconds < 1 { panic!("ttlSeconds must be a whole number of at least 1"); } let exp = now + ttl_seconds; let expires_at = unix_to_iso(exp); let claims = Value::obj(vec![ ("sub", Value::str(subject)), ("name", Value::str(name)), ("email", Value::str(email)), ("ver", Value::Int(token_version)), ("jti", Value::str(jti)), ("iat", Value::Int(now)), ("exp", Value::Int(exp)), ]); AccessToken { access_token: sign_jwt(&claims, secret), token_type: "Bearer".to_string(), expires_at, expires_in: ttl_seconds, } } pub fn access_token_to_value(token: &AccessToken) -> Value { Value::obj(vec![ ("accessToken", Value::str(&token.access_token)), ("tokenType", Value::str(&token.token_type)), ("expiresAt", Value::str(&token.expires_at)), ("expiresIn", Value::Int(token.expires_in)), ]) } pub fn fune_vector(args: &[Value]) -> Value { let text = |i: usize, message: &str| -> String { match &args[i] { Value::Str(s) => s.clone(), _ => panic!("{}", message), } }; let whole = |i: usize, message: &str| -> i64 { match &args[i] { Value::Int(n) => *n, _ => panic!("{}", message), } }; let secret: Vec = match &args[7] { Value::Arr(items) => items .iter() .map(|item| match item { Value::Int(i) => *i, _ => panic!("secret must be a list of integers from 0 to 255"), }) .collect(), _ => panic!("secret must be a list of integers from 0 to 255"), }; access_token_to_value(&issue_access_token( &text(0, "subject must be a non-empty string"), &text(1, "name must be a string"), &text(2, "email must be a string"), whole(3, "tokenVersion must be a whole number, 0 or more"), &text(4, "jti must be a non-empty string"), whole(5, "now must be a whole number of Unix seconds"), whole(6, "ttlSeconds must be a whole number of at least 1"), &secret, )) }