use crate::backend::NewToken;
use crate::proto::api::{ErrorCode, RegisterTokenRequest, RegisterTokenResponse, Scope, TokenSelf};
use crate::proto::audit::AuditAction;
use crate::server_core::auth::{Caller, Need, Principal, json};
use crate::server_core::error::CoreError;
use crate::server_core::{Core, CoreResponse};
pub(crate) fn register(
core: &Core,
caller: &Caller,
body: &[u8],
) -> Result<CoreResponse, CoreError> {
core.require(caller, Need::Owner, AuditAction::TokenMint, None)?;
let r: RegisterTokenRequest = json(body, "token registration")?;
let ttl = if r.ttl_secs == 0 {
r.scope.default_ttl_secs()
} else {
r.ttl_secs
};
if ttl > r.scope.max_ttl_secs() {
return Err(CoreError::new(
ErrorCode::TtlTooLong,
format!(
"a {} token lives at most {} days",
r.scope,
r.scope.max_ttl_secs() / 86_400
),
));
}
if r.allow_list.is_some() && r.scope != Scope::Read {
return Err(CoreError::invalid(
"only read tokens take a name allow-list",
));
}
if let Err(e) = r.bundle.verify(
&caller.vault.owner_sign_pub,
&caller.vault.vault_id,
&r.token_id,
r.scope.code(),
r.generation,
) {
core.refuse(caller, AuditAction::TokenMint, None);
return Err(e.into());
}
let now = core.now();
let token = NewToken {
token_id: r.token_id,
auth_pub: r.auth_pub,
box_pub: r.box_pub,
scope: r.scope,
expires_at: now + ttl as i64,
bundle: r.bundle,
generation: r.generation,
allow_list: r.allow_list,
};
let limits = core.policy().limits;
let row = core
.store()
.register_token(caller.vault.pk, &token, caller.ctx(now), &limits)?;
let response = RegisterTokenResponse::new(row.token_id, row.expires_at);
CoreResponse::json(201, &response)
}
pub(crate) fn whoami(caller: &Caller) -> Result<CoreResponse, CoreError> {
let Principal::Token(t) = &caller.principal else {
return Err(CoreError::invalid(
"the owner has no token; use GET /v1/vault for the owner bundle",
));
};
let me = TokenSelf::new(
t.token_id,
caller.vault.vault_id,
t.scope,
t.expires_at,
t.allow_list.clone(),
caller.vault.owner_sign_pub,
caller.vault.descriptor.clone(),
t.bundle.clone(),
);
CoreResponse::json(200, &me)
}