surrealdb_sql/statements/define/
user.rs1use crate::ctx::Context;
2use crate::dbs::{Options, Transaction};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::iam::{Action, ResourceKind};
6use crate::{escape::quote_str, fmt::Fmt, Base, Ident, Strand, Value};
7use argon2::{
8 password_hash::{PasswordHasher, SaltString},
9 Argon2,
10};
11use derive::Store;
12use rand::{distributions::Alphanumeric, rngs::OsRng, Rng};
13use revision::revisioned;
14use serde::{Deserialize, Serialize};
15use std::fmt::{self, Display};
16
17#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
18#[revisioned(revision = 1)]
19pub struct DefineUserStatement {
20 pub name: Ident,
21 pub base: Base,
22 pub hash: String,
23 pub code: String,
24 pub roles: Vec<Ident>,
25 pub comment: Option<Strand>,
26}
27
28impl From<(Base, &str, &str)> for DefineUserStatement {
29 fn from((base, user, pass): (Base, &str, &str)) -> Self {
30 DefineUserStatement {
31 base,
32 name: user.into(),
33 hash: Argon2::default()
34 .hash_password(pass.as_ref(), &SaltString::generate(&mut OsRng))
35 .unwrap()
36 .to_string(),
37 code: rand::thread_rng()
38 .sample_iter(&Alphanumeric)
39 .take(128)
40 .map(char::from)
41 .collect::<String>(),
42 roles: vec!["owner".into()],
43 comment: None,
44 }
45 }
46}
47
48impl DefineUserStatement {
49 #[doc(hidden)]
51 pub async fn compute(
52 &self,
53 _ctx: &Context<'_>,
54 opt: &Options,
55 txn: &Transaction,
56 _doc: Option<&CursorDoc<'_>>,
57 ) -> Result<Value, Error> {
58 opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
60
61 match self.base {
62 Base::Root => {
63 let mut run = txn.lock().await;
65 run.clear_cache();
67 let key = crate::key::root::us::new(&self.name);
69 run.set(key, self).await?;
70 Ok(Value::None)
72 }
73 Base::Ns => {
74 let mut run = txn.lock().await;
76 run.clear_cache();
78 let key = crate::key::namespace::us::new(opt.ns(), &self.name);
80 run.add_ns(opt.ns(), opt.strict).await?;
81 run.set(key, self).await?;
82 Ok(Value::None)
84 }
85 Base::Db => {
86 let mut run = txn.lock().await;
88 run.clear_cache();
90 let key = crate::key::database::us::new(opt.ns(), opt.db(), &self.name);
92 run.add_ns(opt.ns(), opt.strict).await?;
93 run.add_db(opt.ns(), opt.db(), opt.strict).await?;
94 run.set(key, self).await?;
95 Ok(Value::None)
97 }
98 _ => Err(Error::InvalidLevel(self.base.to_string())),
100 }
101 }
102}
103
104impl Display for DefineUserStatement {
105 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106 write!(
107 f,
108 "DEFINE USER {} ON {} PASSHASH {} ROLES {}",
109 self.name,
110 self.base,
111 quote_str(&self.hash),
112 Fmt::comma_separated(
113 &self.roles.iter().map(|r| r.to_string().to_uppercase()).collect::<Vec<String>>()
114 )
115 )?;
116 if let Some(ref v) = self.comment {
117 write!(f, " COMMENT {v}")?
118 }
119 Ok(())
120 }
121}