sofie_identity/tokens/
factory.rs1use sofie::auth::BearerToken;
2use sofie::core::Instant;
3use sofie::db::{Outcome, Plan, Reply, Stamp};
4use sofie::http::Area;
5use sofie::prelude::*;
6
7use super::{AccessToken, AccessTokenId};
8use crate::AccountId;
9use crate::membership::held;
10use crate::role_grant::factory::refuse_unless_permission;
11
12pub struct Issued {
14 token: AccessToken,
15 secret: BearerToken,
16}
17
18impl Issued {
19 #[must_use]
20 pub fn token(&self) -> &AccessToken {
21 &self.token
22 }
23
24 #[must_use]
25 pub fn secret(&self) -> &BearerToken {
26 &self.secret
27 }
28}
29
30impl Outcome for Issued {
31 fn plan(&self, plan: &mut Plan<'_>) -> Result<()> {
32 self.token.plan(plan)
33 }
34
35 fn committed(&mut self, stamp: Stamp) {
36 self.token.committed(stamp);
37 }
38
39 fn reply(self) -> Result<Reply> {
40 Ok(Reply::Json(sofie::serde_json::json!({
41 "id": self.token.id().uuid().to_string(),
42 "token": self.secret.expose(),
43 })))
44 }
45}
46
47pub async fn issue<A: Area>(
49 read: &Read,
50 account: AccountId,
51 scopes: &[&str],
52 expires_at: Instant,
53) -> Result<Issued> {
54 for scope in scopes {
55 refuse_unless_permission("scopes", scope)?;
56 }
57 if held(read, account, A::NAME).await?.is_none() {
58 return Err(Error::Rule(format!(
59 "a token for area `{}` needs its account to be a member there",
60 A::NAME
61 )));
62 }
63 let secret = BearerToken::generate()?;
64 let token = AccessToken {
65 meta: Meta::new()?,
66 account,
67 area: A::NAME.to_owned(),
68 digest: secret.digest(),
69 scopes: scopes.join(" "),
70 expires_at,
71 last_used_at: None,
72 };
73 Ok(Issued { token, secret })
74}
75
76pub async fn revoke(read: &Read, account: AccountId, token: AccessTokenId) -> Result<AccessToken> {
77 let mut held = AccessToken::query()
78 .where_(AccessToken::ID.eq(token))
79 .where_(AccessToken::ACCOUNT.eq(account))
80 .first(read)
81 .await?
82 .ok_or(Error::NotFound)?;
83 held.delete();
84 Ok(held)
85}
86
87pub async fn list(read: &Read, account: AccountId) -> Result<Vec<AccessToken>> {
89 AccessToken::query()
90 .where_(AccessToken::ACCOUNT.eq(account))
91 .latest()
92 .all(read)
93 .await
94}