Files
inbuxa-server/crates/common/src/auth/credential.rs
T
jcoffey-dev 7dae9b29fd Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f
Enterprise-only files removed or emptied: 63
Enterprise-only snippets removed: 117 in 50 files
Dangling module declarations removed: 5
Cargo edits turning enterprise off: 14
Verification: clean
Enterprise feature gates left for rebuilt features: 19 in 18 files

Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
2026-09-18 10:21:56 -07:00

94 lines
2.6 KiB
Rust

/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
use std::io::Write;
use store::{
U32_LEN,
rand::{self},
};
use utils::codec::base32_custom::{Base32Reader, Base32Writer};
pub struct ApiKey {
pub account_id: u32,
pub credential_id: u32,
pub secret: [u8; 20],
}
pub struct AppPassword {
pub credential_id: u32,
pub secret: [u8; 18],
}
impl ApiKey {
pub fn new(account_id: u32, credential_id: u32) -> Self {
ApiKey {
account_id,
credential_id,
secret: rand::random::<[u8; 20]>(),
}
}
pub fn parse(token: &str) -> Option<Self> {
let decoded = URL_SAFE_NO_PAD.decode(token.strip_prefix("API_")?).ok()?;
Some(ApiKey {
account_id: u32::from_be_bytes(decoded.get(0..U32_LEN)?.try_into().ok()?),
credential_id: u32::from_be_bytes(decoded.get(U32_LEN..U32_LEN * 2)?.try_into().ok()?),
secret: decoded.get(U32_LEN * 2..)?.try_into().ok()?,
})
}
pub fn build(&self) -> String {
let mut bytes = Vec::with_capacity(U32_LEN * 2 + self.secret.len());
bytes.extend_from_slice(&self.account_id.to_be_bytes());
bytes.extend_from_slice(&self.credential_id.to_be_bytes());
bytes.extend_from_slice(&self.secret);
format!("API_{}", URL_SAFE_NO_PAD.encode(bytes))
}
}
impl AppPassword {
pub fn new(credential_id: u32) -> Self {
AppPassword {
credential_id,
secret: rand::random::<[u8; 18]>(),
}
}
pub fn parse(token: &str) -> Option<Self> {
let token = token.strip_prefix("app")?;
let mut reader = Base32Reader::new(token.as_bytes().get(1..)?);
let mut credential_id = [0u8; 4];
let mut secret = [0u8; 18];
for byte in credential_id.iter_mut() {
*byte = reader.next()?;
}
for byte in secret.iter_mut() {
*byte = reader.next()?;
}
if reader.next().is_none() {
Some(AppPassword {
credential_id: u32::from_be_bytes(credential_id),
secret,
})
} else {
None
}
}
pub fn build(&self) -> String {
let mut writer = Base32Writer::with_capacity(std::mem::size_of::<Self>().div_ceil(5) * 8);
writer.push_string("app_");
let _ = writer.write(&self.credential_id.to_be_bytes());
let _ = writer.write_all(&self.secret);
writer.finalize()
}
}