mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-20 18:11:00 +00:00
feat(api): scoped, optionally expiring API tokens (#6201)
* security(api): add scoped expiring API tokens * security(api): make scoped token lifecycle enforceable --------- Co-authored-by: n0ctal <293235942+n0ctal@users.noreply.github.com>
This commit is contained in:
@@ -220,15 +220,19 @@ export const EXAMPLES: Record<string, unknown> = {
|
||||
"ApiToken": {
|
||||
"createdAt": 0,
|
||||
"enabled": false,
|
||||
"expiresAt": 0,
|
||||
"id": 0,
|
||||
"name": "",
|
||||
"scope": "",
|
||||
"token": ""
|
||||
},
|
||||
"ApiTokenView": {
|
||||
"createdAt": 1736000000,
|
||||
"enabled": true,
|
||||
"expiresAt": 0,
|
||||
"id": 2,
|
||||
"name": "central-panel-a",
|
||||
"scope": "admin",
|
||||
"token": "new-token-string"
|
||||
},
|
||||
"Client": {
|
||||
|
||||
@@ -937,12 +937,19 @@ export const SCHEMAS: Record<string, unknown> = {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"expiresAt": {
|
||||
"format": "int64",
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"scope": {
|
||||
"type": "string"
|
||||
},
|
||||
"token": {
|
||||
"description": "SHA-256 hash; the plaintext is shown only once at creation",
|
||||
"type": "string"
|
||||
@@ -951,8 +958,10 @@ export const SCHEMAS: Record<string, unknown> = {
|
||||
"required": [
|
||||
"createdAt",
|
||||
"enabled",
|
||||
"expiresAt",
|
||||
"id",
|
||||
"name",
|
||||
"scope",
|
||||
"token"
|
||||
],
|
||||
"type": "object"
|
||||
@@ -968,6 +977,11 @@ export const SCHEMAS: Record<string, unknown> = {
|
||||
"example": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"expiresAt": {
|
||||
"example": 0,
|
||||
"format": "int64",
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"example": 2,
|
||||
"type": "integer"
|
||||
@@ -976,6 +990,10 @@ export const SCHEMAS: Record<string, unknown> = {
|
||||
"example": "central-panel-a",
|
||||
"type": "string"
|
||||
},
|
||||
"scope": {
|
||||
"example": "admin",
|
||||
"type": "string"
|
||||
},
|
||||
"token": {
|
||||
"example": "new-token-string",
|
||||
"type": "string"
|
||||
@@ -984,8 +1002,10 @@ export const SCHEMAS: Record<string, unknown> = {
|
||||
"required": [
|
||||
"createdAt",
|
||||
"enabled",
|
||||
"expiresAt",
|
||||
"id",
|
||||
"name"
|
||||
"name",
|
||||
"scope"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
|
||||
@@ -229,16 +229,20 @@ export interface AllSettingView {
|
||||
export interface ApiToken {
|
||||
createdAt: number;
|
||||
enabled: boolean;
|
||||
expiresAt: number;
|
||||
id: number;
|
||||
name: string;
|
||||
scope: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface ApiTokenView {
|
||||
createdAt: number;
|
||||
enabled: boolean;
|
||||
expiresAt: number;
|
||||
id: number;
|
||||
name: string;
|
||||
scope: string;
|
||||
token?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -245,8 +245,10 @@ export type AllSettingView = z.infer<typeof AllSettingViewSchema>;
|
||||
export const ApiTokenSchema = z.object({
|
||||
createdAt: z.number().int(),
|
||||
enabled: z.boolean(),
|
||||
expiresAt: z.number().int(),
|
||||
id: z.number().int(),
|
||||
name: z.string(),
|
||||
scope: z.string(),
|
||||
token: z.string(),
|
||||
});
|
||||
export type ApiToken = z.infer<typeof ApiTokenSchema>;
|
||||
@@ -254,8 +256,10 @@ export type ApiToken = z.infer<typeof ApiTokenSchema>;
|
||||
export const ApiTokenViewSchema = z.object({
|
||||
createdAt: z.number().int(),
|
||||
enabled: z.boolean(),
|
||||
expiresAt: z.number().int(),
|
||||
id: z.number().int(),
|
||||
name: z.string(),
|
||||
scope: z.string(),
|
||||
token: z.string().optional(),
|
||||
});
|
||||
export type ApiTokenView = z.infer<typeof ApiTokenViewSchema>;
|
||||
|
||||
Reference in New Issue
Block a user