Skip to main content

wire/
auth_token.rs

1// SPDX-License-Identifier: Apache-2.0
2use serde::{Deserialize, Serialize};
3
4use crate::{Permission, scope_contains};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct AuthToken {
8    pub id: String,
9    pub user: String,
10    pub permissions: Vec<Permission>,
11    pub expires_at: u64,
12    pub scope: TokenScope,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub enum TokenScope {
17    Global,
18    Repositories(Vec<String>),
19    NamespaceTree(String),
20}
21
22impl AuthToken {
23    pub fn new(id: impl Into<String>, user: impl Into<String>) -> Self {
24        Self {
25            id: id.into(),
26            user: user.into(),
27            permissions: vec![Permission::Read],
28            expires_at: 0,
29            scope: TokenScope::Global,
30        }
31    }
32
33    pub fn with_permissions(mut self, permissions: Vec<Permission>) -> Self {
34        self.permissions = permissions;
35        self
36    }
37
38    pub fn with_expiration(mut self, expires_at: u64) -> Self {
39        self.expires_at = expires_at;
40        self
41    }
42
43    pub fn with_scope(mut self, scope: TokenScope) -> Self {
44        self.scope = scope;
45        self
46    }
47
48    pub fn has_permission(&self, perm: Permission) -> bool {
49        self.permissions.contains(&perm)
50    }
51
52    pub fn is_expired(&self) -> bool {
53        if self.expires_at == 0 {
54            return false;
55        }
56        let now = match std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) {
57            Ok(d) => d.as_secs(),
58            Err(_) => return true,
59        };
60        now > self.expires_at
61    }
62
63    pub fn can_access_repo(&self, repo: &str) -> bool {
64        match &self.scope {
65            TokenScope::Global => true,
66            TokenScope::Repositories(repos) => repos.contains(&repo.to_string()),
67            TokenScope::NamespaceTree(namespace) => scope_contains(namespace, repo),
68        }
69    }
70
71    pub fn to_bytes(&self) -> Vec<u8> {
72        self.id.as_bytes().to_vec()
73    }
74
75    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
76        let token_str = std::str::from_utf8(bytes).ok()?.trim().to_string();
77        if token_str.is_empty() {
78            return None;
79        }
80        let id = token_str.split(':').next()?.to_string();
81        Some(Self {
82            id,
83            user: String::new(),
84            permissions: vec![],
85            expires_at: 0,
86            scope: TokenScope::Global,
87        })
88    }
89}