Internal create: returns `(key_id, token)` so callers like `rotate()` don't have to re-parse the token to recover the key_id. Parsing the token would require a silent fallback on malformed input; the internal pair makes that impossible.
(
&self,
auth_user_id: &str,
tenant_id: u64,
scopes: Vec<String>,
rate_limit_qps: u64,
rate_limit_burst: u64,
expires_days: u64,
)
| 120 | /// token would require a silent fallback on malformed input; the internal |
| 121 | /// pair makes that impossible. |
| 122 | fn create_key_inner( |
| 123 | &self, |
| 124 | auth_user_id: &str, |
| 125 | tenant_id: u64, |
| 126 | scopes: Vec<String>, |
| 127 | rate_limit_qps: u64, |
| 128 | rate_limit_burst: u64, |
| 129 | expires_days: u64, |
| 130 | ) -> (String, String) { |
| 131 | let key_id = generate_key_id(); |
| 132 | let secret = generate_secret(); |
| 133 | let token = format!("nda_{key_id}_{secret}"); |
| 134 | |
| 135 | let secret_hash = hash_secret(&secret); |
| 136 | let now = now_secs(); |
| 137 | let expires_at = if expires_days > 0 { |
| 138 | now + expires_days * 86_400 |
| 139 | } else { |
| 140 | 0 |
| 141 | }; |
| 142 | |
| 143 | let record = AuthApiKey { |
| 144 | key_id: key_id.clone(), |
| 145 | secret_hash: secret_hash.clone(), |
| 146 | auth_user_id: auth_user_id.into(), |
| 147 | tenant_id, |
| 148 | scopes, |
| 149 | rate_limit_qps, |
| 150 | rate_limit_burst, |
| 151 | expires_at, |
| 152 | created_at: now, |
| 153 | is_revoked: false, |
| 154 | last_used_at: 0, |
| 155 | last_used_ip: String::new(), |
| 156 | replaces_key_id: None, |
| 157 | superseded_at: 0, |
| 158 | superseded_by: None, |
| 159 | }; |
| 160 | |
| 161 | let hash_hex = hex_encode(&secret_hash); |
| 162 | let mut keys = self.keys.write().unwrap_or_else(|p| p.into_inner()); |
| 163 | let mut idx = self.hash_index.write().unwrap_or_else(|p| p.into_inner()); |
| 164 | keys.insert(key_id.clone(), record); |
| 165 | idx.insert(hash_hex, key_id.clone()); |
| 166 | |
| 167 | (key_id, token) |
| 168 | } |
| 169 | |
| 170 | /// Verify an `nda_` token. Returns the key record if valid. |
| 171 | pub fn verify(&self, token: &str) -> Option<AuthApiKey> { |
no test coverage detected