Skip to main content

surrealdb_expr/expr/convert/statements/define/
user.rs

1//! `sql` -> `expr` conversions for [`crate::sql::statements::define::user`].
2//!
3//! Lives in core rather than beside the AST: `surrealdb-sql` sits below
4//! core, so it cannot name `expr` types.
5
6use rand::distr::{Alphanumeric, SampleString};
7
8use crate::iam::ScramCredential;
9use crate::sql::statements::define::user::*;
10
11#[allow(clippy::fallible_impl_from)]
12impl From<DefineUserStatement> for crate::expr::statements::DefineUserStatement {
13	fn from(v: DefineUserStatement) -> Self {
14		// An explicit PASSSCRAM verifier takes precedence (import/round-trip);
15		// otherwise derive from the plaintext password when one is provided.
16		// The verifier is validated at parse time (both DEFINE USER parsers call
17		// `from_verifier_string` and bail on error), so `expect` upholds that
18		// invariant loudly instead of silently dropping a bad verifier — the same
19		// way the Argon2 hashing treats its impossible failure.
20		let scram = if let Some(ref s) = v.scram {
21			Some(
22				ScramCredential::from_verifier_string(s)
23					.expect("PASSSCRAM verifier must be validated at parse time"),
24			)
25		} else if let PassType::Password(ref p) = v.pass_type {
26			Some(ScramCredential::generate(p))
27		} else {
28			None
29		};
30
31		let hash = match v.pass_type {
32			PassType::Unset => String::new(),
33			PassType::Hash(x) => x,
34			// TODO: Move out of AST.
35			PassType::Password(p) => crate::iam::hash_password(&p),
36		};
37
38		let code = Alphanumeric.sample_string(&mut rand::rng(), 128);
39
40		Self {
41			kind: v.kind.into(),
42			name: v.name.into(),
43			base: v.base.into(),
44			hash,
45			code,
46			scram,
47			roles: v.roles,
48			duration: crate::expr::user::UserDuration {
49				token: v.token_duration.into(),
50				session: v.session_duration.into(),
51			},
52			comment: v.comment.into(),
53		}
54	}
55}
56
57impl From<crate::expr::statements::DefineUserStatement> for DefineUserStatement {
58	fn from(v: crate::expr::statements::DefineUserStatement) -> Self {
59		Self {
60			kind: v.kind.into(),
61			name: v.name.into(),
62			base: v.base.into(),
63			pass_type: PassType::Hash(v.hash),
64			scram: v.scram.as_ref().map(|c| c.to_verifier_string()),
65			roles: v.roles,
66			token_duration: v.duration.token.into(),
67			session_duration: v.duration.session.into(),
68			comment: v.comment.into(),
69		}
70	}
71}