this repo has no description
1use crate::types::Handle; 2use chrono::{DateTime, Utc}; 3use serde::{Deserialize, Serialize}; 4use sqlx::PgPool; 5use uuid::Uuid; 6 7#[derive(Debug, Clone, Serialize, Deserialize)] 8pub struct DelegationGrant { 9 pub id: Uuid, 10 pub delegated_did: String, 11 pub controller_did: String, 12 pub granted_scopes: String, 13 pub granted_at: DateTime<Utc>, 14 pub granted_by: String, 15 pub revoked_at: Option<DateTime<Utc>>, 16 pub revoked_by: Option<String>, 17} 18 19#[derive(Debug, Clone, Serialize, Deserialize)] 20pub struct DelegatedAccountInfo { 21 pub did: String, 22 pub handle: Handle, 23 pub granted_scopes: String, 24 pub granted_at: DateTime<Utc>, 25} 26 27#[derive(Debug, Clone, Serialize, Deserialize)] 28pub struct ControllerInfo { 29 pub did: String, 30 pub handle: Handle, 31 pub granted_scopes: String, 32 pub granted_at: DateTime<Utc>, 33 pub is_active: bool, 34} 35 36pub async fn is_delegated_account(pool: &PgPool, did: &str) -> Result<bool, sqlx::Error> { 37 let result = sqlx::query_scalar!( 38 r#"SELECT account_type::text = 'delegated' as "is_delegated!" FROM users WHERE did = $1"#, 39 did 40 ) 41 .fetch_optional(pool) 42 .await?; 43 44 Ok(result.unwrap_or(false)) 45} 46 47pub async fn create_delegation( 48 pool: &PgPool, 49 delegated_did: &str, 50 controller_did: &str, 51 granted_scopes: &str, 52 granted_by: &str, 53) -> Result<Uuid, sqlx::Error> { 54 let id = sqlx::query_scalar!( 55 r#" 56 INSERT INTO account_delegations (delegated_did, controller_did, granted_scopes, granted_by) 57 VALUES ($1, $2, $3, $4) 58 RETURNING id 59 "#, 60 delegated_did, 61 controller_did, 62 granted_scopes, 63 granted_by 64 ) 65 .fetch_one(pool) 66 .await?; 67 68 Ok(id) 69} 70 71pub async fn revoke_delegation( 72 pool: &PgPool, 73 delegated_did: &str, 74 controller_did: &str, 75 revoked_by: &str, 76) -> Result<bool, sqlx::Error> { 77 let result = sqlx::query!( 78 r#" 79 UPDATE account_delegations 80 SET revoked_at = NOW(), revoked_by = $1 81 WHERE delegated_did = $2 AND controller_did = $3 AND revoked_at IS NULL 82 "#, 83 revoked_by, 84 delegated_did, 85 controller_did 86 ) 87 .execute(pool) 88 .await?; 89 90 Ok(result.rows_affected() > 0) 91} 92 93pub async fn update_delegation_scopes( 94 pool: &PgPool, 95 delegated_did: &str, 96 controller_did: &str, 97 new_scopes: &str, 98) -> Result<bool, sqlx::Error> { 99 let result = sqlx::query!( 100 r#" 101 UPDATE account_delegations 102 SET granted_scopes = $1 103 WHERE delegated_did = $2 AND controller_did = $3 AND revoked_at IS NULL 104 "#, 105 new_scopes, 106 delegated_did, 107 controller_did 108 ) 109 .execute(pool) 110 .await?; 111 112 Ok(result.rows_affected() > 0) 113} 114 115pub async fn get_delegation( 116 pool: &PgPool, 117 delegated_did: &str, 118 controller_did: &str, 119) -> Result<Option<DelegationGrant>, sqlx::Error> { 120 let grant = sqlx::query_as!( 121 DelegationGrant, 122 r#" 123 SELECT id, delegated_did, controller_did, granted_scopes, 124 granted_at, granted_by, revoked_at, revoked_by 125 FROM account_delegations 126 WHERE delegated_did = $1 AND controller_did = $2 AND revoked_at IS NULL 127 "#, 128 delegated_did, 129 controller_did 130 ) 131 .fetch_optional(pool) 132 .await?; 133 134 Ok(grant) 135} 136 137pub async fn get_delegations_for_account( 138 pool: &PgPool, 139 delegated_did: &str, 140) -> Result<Vec<ControllerInfo>, sqlx::Error> { 141 let controllers = sqlx::query_as!( 142 ControllerInfo, 143 r#" 144 SELECT 145 u.did, 146 u.handle, 147 d.granted_scopes, 148 d.granted_at, 149 (u.deactivated_at IS NULL AND u.takedown_ref IS NULL) as "is_active!" 150 FROM account_delegations d 151 JOIN users u ON u.did = d.controller_did 152 WHERE d.delegated_did = $1 AND d.revoked_at IS NULL 153 ORDER BY d.granted_at DESC 154 "#, 155 delegated_did 156 ) 157 .fetch_all(pool) 158 .await?; 159 160 Ok(controllers) 161} 162 163pub async fn get_accounts_controlled_by( 164 pool: &PgPool, 165 controller_did: &str, 166) -> Result<Vec<DelegatedAccountInfo>, sqlx::Error> { 167 let accounts = sqlx::query_as!( 168 DelegatedAccountInfo, 169 r#" 170 SELECT 171 u.did, 172 u.handle, 173 d.granted_scopes, 174 d.granted_at 175 FROM account_delegations d 176 JOIN users u ON u.did = d.delegated_did 177 WHERE d.controller_did = $1 178 AND d.revoked_at IS NULL 179 AND u.deactivated_at IS NULL 180 AND u.takedown_ref IS NULL 181 ORDER BY d.granted_at DESC 182 "#, 183 controller_did 184 ) 185 .fetch_all(pool) 186 .await?; 187 188 Ok(accounts) 189} 190 191pub async fn get_active_controllers_for_account( 192 pool: &PgPool, 193 delegated_did: &str, 194) -> Result<Vec<ControllerInfo>, sqlx::Error> { 195 let controllers = sqlx::query_as!( 196 ControllerInfo, 197 r#" 198 SELECT 199 u.did, 200 u.handle, 201 d.granted_scopes, 202 d.granted_at, 203 true as "is_active!" 204 FROM account_delegations d 205 JOIN users u ON u.did = d.controller_did 206 WHERE d.delegated_did = $1 207 AND d.revoked_at IS NULL 208 AND u.deactivated_at IS NULL 209 AND u.takedown_ref IS NULL 210 ORDER BY d.granted_at DESC 211 "#, 212 delegated_did 213 ) 214 .fetch_all(pool) 215 .await?; 216 217 Ok(controllers) 218} 219 220pub async fn count_active_controllers( 221 pool: &PgPool, 222 delegated_did: &str, 223) -> Result<i64, sqlx::Error> { 224 let count = sqlx::query_scalar!( 225 r#" 226 SELECT COUNT(*) as "count!" 227 FROM account_delegations d 228 JOIN users u ON u.did = d.controller_did 229 WHERE d.delegated_did = $1 230 AND d.revoked_at IS NULL 231 AND u.deactivated_at IS NULL 232 AND u.takedown_ref IS NULL 233 "#, 234 delegated_did 235 ) 236 .fetch_one(pool) 237 .await?; 238 239 Ok(count) 240} 241 242pub async fn has_any_controllers(pool: &PgPool, did: &str) -> Result<bool, sqlx::Error> { 243 let exists = sqlx::query_scalar!( 244 r#"SELECT EXISTS( 245 SELECT 1 FROM account_delegations 246 WHERE delegated_did = $1 AND revoked_at IS NULL 247 ) as "exists!""#, 248 did 249 ) 250 .fetch_one(pool) 251 .await?; 252 253 Ok(exists) 254} 255 256pub async fn controls_any_accounts(pool: &PgPool, did: &str) -> Result<bool, sqlx::Error> { 257 let exists = sqlx::query_scalar!( 258 r#"SELECT EXISTS( 259 SELECT 1 FROM account_delegations 260 WHERE controller_did = $1 AND revoked_at IS NULL 261 ) as "exists!""#, 262 did 263 ) 264 .fetch_one(pool) 265 .await?; 266 267 Ok(exists) 268}