Admin API to list user registration tokens

This commit is contained in:
Quentin Gliech
2025-06-03 10:07:21 +02:00
parent 8a6fd1d6b2
commit 35a33f3464
6 changed files with 1537 additions and 0 deletions

View File

@@ -73,6 +73,11 @@ fn finish(t: TransformOpenApi) -> TransformOpenApi {
description: Some("Manage browser sessions of users".to_owned()),
..Tag::default()
})
.tag(Tag {
name: "user-registration-token".to_owned(),
description: Some("Manage user registration tokens".to_owned()),
..Tag::default()
})
.tag(Tag {
name: "upstream-oauth-link".to_owned(),
description: Some(

View File

@@ -602,3 +602,83 @@ impl PolicyData {
}]
}
}
/// A registration token
#[derive(Serialize, JsonSchema)]
pub struct UserRegistrationToken {
#[serde(skip)]
id: Ulid,
/// The token string
token: String,
/// Maximum number of times this token can be used
usage_limit: Option<u32>,
/// Number of times this token has been used
times_used: u32,
/// When the token was created
created_at: DateTime<Utc>,
/// When the token was last used. If null, the token has never been used.
last_used_at: Option<DateTime<Utc>>,
/// When the token expires. If null, the token never expires.
expires_at: Option<DateTime<Utc>>,
/// When the token was revoked. If null, the token is not revoked.
revoked_at: Option<DateTime<Utc>>,
}
impl From<mas_data_model::UserRegistrationToken> for UserRegistrationToken {
fn from(token: mas_data_model::UserRegistrationToken) -> Self {
Self {
id: token.id,
token: token.token,
usage_limit: token.usage_limit,
times_used: token.times_used,
created_at: token.created_at,
last_used_at: token.last_used_at,
expires_at: token.expires_at,
revoked_at: token.revoked_at,
}
}
}
impl Resource for UserRegistrationToken {
const KIND: &'static str = "user-registration_token";
const PATH: &'static str = "/api/admin/v1/user-registration-tokens";
fn id(&self) -> Ulid {
self.id
}
}
impl UserRegistrationToken {
/// Samples of registration tokens
pub fn samples() -> [Self; 2] {
[
Self {
id: Ulid::from_bytes([0x01; 16]),
token: "abc123def456".to_owned(),
usage_limit: Some(10),
times_used: 5,
created_at: DateTime::default(),
last_used_at: Some(DateTime::default()),
expires_at: Some(DateTime::default() + chrono::Duration::days(30)),
revoked_at: None,
},
Self {
id: Ulid::from_bytes([0x02; 16]),
token: "xyz789abc012".to_owned(),
usage_limit: None,
times_used: 0,
created_at: DateTime::default(),
last_used_at: None,
expires_at: None,
revoked_at: Some(DateTime::default()),
},
]
}
}

View File

@@ -23,6 +23,7 @@ mod oauth2_sessions;
mod policy_data;
mod upstream_oauth_links;
mod user_emails;
mod user_registration_tokens;
mod user_sessions;
mod users;
@@ -119,6 +120,13 @@ where
"/user-sessions/{id}",
get_with(self::user_sessions::get, self::user_sessions::get_doc),
)
.api_route(
"/user-registration-tokens",
get_with(
self::user_registration_tokens::list,
self::user_registration_tokens::list_doc,
),
)
.api_route(
"/upstream-oauth-links",
get_with(

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
// Copyright 2025 The Matrix.org Foundation C.I.C.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
mod list;
pub use self::list::{doc as list_doc, handler as list};

View File

@@ -2132,6 +2132,166 @@
}
}
},
"/api/admin/v1/user-registration-tokens": {
"get": {
"tags": [
"user-registration-token"
],
"summary": "List user registration tokens",
"operationId": "listUserRegistrationTokens",
"parameters": [
{
"in": "query",
"name": "page[before]",
"description": "Retrieve the items before the given ID",
"schema": {
"description": "Retrieve the items before the given ID",
"$ref": "#/components/schemas/ULID",
"nullable": true
},
"style": "form"
},
{
"in": "query",
"name": "page[after]",
"description": "Retrieve the items after the given ID",
"schema": {
"description": "Retrieve the items after the given ID",
"$ref": "#/components/schemas/ULID",
"nullable": true
},
"style": "form"
},
{
"in": "query",
"name": "page[first]",
"description": "Retrieve the first N items",
"schema": {
"description": "Retrieve the first N items",
"type": "integer",
"format": "uint",
"minimum": 1.0,
"nullable": true
},
"style": "form"
},
{
"in": "query",
"name": "page[last]",
"description": "Retrieve the last N items",
"schema": {
"description": "Retrieve the last N items",
"type": "integer",
"format": "uint",
"minimum": 1.0,
"nullable": true
},
"style": "form"
},
{
"in": "query",
"name": "filter[used]",
"description": "Retrieve tokens that have (or have not) been used at least once",
"schema": {
"description": "Retrieve tokens that have (or have not) been used at least once",
"type": "boolean",
"nullable": true
},
"style": "form"
},
{
"in": "query",
"name": "filter[revoked]",
"description": "Retrieve tokens that are (or are not) revoked",
"schema": {
"description": "Retrieve tokens that are (or are not) revoked",
"type": "boolean",
"nullable": true
},
"style": "form"
},
{
"in": "query",
"name": "filter[expired]",
"description": "Retrieve tokens that are (or are not) expired",
"schema": {
"description": "Retrieve tokens that are (or are not) expired",
"type": "boolean",
"nullable": true
},
"style": "form"
},
{
"in": "query",
"name": "filter[valid]",
"description": "Retrieve tokens that are (or are not) valid\n\nValid means that the token has not expired, is not revoked, and has not reached its usage limit.",
"schema": {
"description": "Retrieve tokens that are (or are not) valid\n\nValid means that the token has not expired, is not revoked, and has not reached its usage limit.",
"type": "boolean",
"nullable": true
},
"style": "form"
}
],
"responses": {
"200": {
"description": "Paginated response of registration tokens",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedResponse_for_UserRegistrationToken"
},
"example": {
"meta": {
"count": 42
},
"data": [
{
"type": "user-registration_token",
"id": "01040G2081040G2081040G2081",
"attributes": {
"token": "abc123def456",
"usage_limit": 10,
"times_used": 5,
"created_at": "1970-01-01T00:00:00Z",
"last_used_at": "1970-01-01T00:00:00Z",
"expires_at": "1970-01-31T00:00:00Z",
"revoked_at": null
},
"links": {
"self": "/api/admin/v1/user-registration-tokens/01040G2081040G2081040G2081"
}
},
{
"type": "user-registration_token",
"id": "02081040G2081040G2081040G2",
"attributes": {
"token": "xyz789abc012",
"usage_limit": null,
"times_used": 0,
"created_at": "1970-01-01T00:00:00Z",
"last_used_at": null,
"expires_at": null,
"revoked_at": "1970-01-01T00:00:00Z"
},
"links": {
"self": "/api/admin/v1/user-registration-tokens/02081040G2081040G2081040G2"
}
}
],
"links": {
"self": "/api/admin/v1/user-registration-tokens?page[first]=2",
"first": "/api/admin/v1/user-registration-tokens?page[first]=2",
"last": "/api/admin/v1/user-registration-tokens?page[last]=2",
"next": "/api/admin/v1/user-registration-tokens?page[after]=02081040G2081040G2081040G2&page[first]=2"
}
}
}
}
}
}
}
},
"/api/admin/v1/upstream-oauth-links": {
"get": {
"tags": [
@@ -3588,6 +3748,136 @@
}
}
},
"RegistrationTokenFilter": {
"type": "object",
"properties": {
"filter[used]": {
"description": "Retrieve tokens that have (or have not) been used at least once",
"type": "boolean",
"nullable": true
},
"filter[revoked]": {
"description": "Retrieve tokens that are (or are not) revoked",
"type": "boolean",
"nullable": true
},
"filter[expired]": {
"description": "Retrieve tokens that are (or are not) expired",
"type": "boolean",
"nullable": true
},
"filter[valid]": {
"description": "Retrieve tokens that are (or are not) valid\n\nValid means that the token has not expired, is not revoked, and has not reached its usage limit.",
"type": "boolean",
"nullable": true
}
}
},
"PaginatedResponse_for_UserRegistrationToken": {
"description": "A top-level response with a page of resources",
"type": "object",
"required": [
"data",
"links",
"meta"
],
"properties": {
"meta": {
"description": "Response metadata",
"$ref": "#/components/schemas/PaginationMeta"
},
"data": {
"description": "The list of resources",
"type": "array",
"items": {
"$ref": "#/components/schemas/SingleResource_for_UserRegistrationToken"
}
},
"links": {
"description": "Related links",
"$ref": "#/components/schemas/PaginationLinks"
}
}
},
"SingleResource_for_UserRegistrationToken": {
"description": "A single resource, with its type, ID, attributes and related links",
"type": "object",
"required": [
"attributes",
"id",
"links",
"type"
],
"properties": {
"type": {
"description": "The type of the resource",
"type": "string"
},
"id": {
"description": "The ID of the resource",
"$ref": "#/components/schemas/ULID"
},
"attributes": {
"description": "The attributes of the resource",
"$ref": "#/components/schemas/UserRegistrationToken"
},
"links": {
"description": "Related links",
"$ref": "#/components/schemas/SelfLinks"
}
}
},
"UserRegistrationToken": {
"description": "A registration token",
"type": "object",
"required": [
"created_at",
"times_used",
"token"
],
"properties": {
"token": {
"description": "The token string",
"type": "string"
},
"usage_limit": {
"description": "Maximum number of times this token can be used",
"type": "integer",
"format": "uint32",
"minimum": 0.0,
"nullable": true
},
"times_used": {
"description": "Number of times this token has been used",
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"created_at": {
"description": "When the token was created",
"type": "string",
"format": "date-time"
},
"last_used_at": {
"description": "When the token was last used. If null, the token has never been used.",
"type": "string",
"format": "date-time",
"nullable": true
},
"expires_at": {
"description": "When the token expires. If null, the token never expires.",
"type": "string",
"format": "date-time",
"nullable": true
},
"revoked_at": {
"description": "When the token was revoked. If null, the token is not revoked.",
"type": "string",
"format": "date-time",
"nullable": true
}
}
},
"UpstreamOAuthLinkFilter": {
"type": "object",
"properties": {
@@ -3779,6 +4069,10 @@
"name": "user-session",
"description": "Manage browser sessions of users"
},
{
"name": "user-registration-token",
"description": "Manage user registration tokens"
},
{
"name": "upstream-oauth-link",
"description": "Manage links between local users and identities from upstream OAuth 2.0 providers"