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