Merge pull request #8997 from appwrite/feat-tokens-module

Feat: tokens
This commit is contained in:
Matej Bačo 2025-04-22 13:16:07 +02:00 committed by GitHub
commit 304f33991f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 9145 additions and 989 deletions

View file

@ -8,5 +8,4 @@ reviews:
base_branches:
- main
- 1.6.x
- 1.7.x
- feat-sites # temporary until merged to 1.7.x
- 1.7.x

View file

@ -228,7 +228,8 @@ jobs:
Webhooks,
VCS,
Messaging,
Migrations
Migrations,
Tokens
]
tables-mode: [
'Shared V1',

View file

@ -2402,4 +2402,77 @@ return [
]
],
],
'resourceTokens' => [
'$collection' => ID::custom(Database::METADATA),
'$id' => ID::custom('resourceTokens'),
'name' => 'Resource Tokens',
'attributes' => [
[
'$id' => ID::custom('resourceId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('resourceInternalId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('resourceType'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 100,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('secret'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 512,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => ['encrypt'],
],
[
'$id' => ID::custom('expire'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 255,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
]
],
'indexes' => [
[
'$id' => '_key_expiry_date',
'type' => Database::INDEX_KEY,
'attributes' => ['expire'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
],
],
];

View file

@ -488,6 +488,18 @@ return [
'code' => 403,
],
/** Tokens */
Exception::TOKEN_NOT_FOUND => [
'name' => Exception::TOKEN_NOT_FOUND,
'description' => 'The requested file token could not be found.',
'code' => 404,
],
Exception::TOKEN_EXPIRED => [
'name' => Exception::TOKEN_EXPIRED,
'description' => 'The requested file token has expired.',
'code' => 401,
],
/** VCS */
Exception::INSTALLATION_NOT_FOUND => [
'name' => Exception::INSTALLATION_NOT_FOUND,

View file

@ -81,6 +81,8 @@ $admins = [
'topics.read',
'subscribers.write',
'subscribers.read',
'tokens.read',
'tokens.write',
];
return [

View file

@ -142,4 +142,10 @@ return [ // List of publicly visible scopes
'assistant.read' => [
'description' => 'Access to read the Assistant service',
],
'tokens.read' => [
'description' => 'Access to read your project\'s tokens',
],
'tokens.write' => [
'description' => 'Access to create, update, and delete your project\'s tokens',
],
];

View file

@ -4748,7 +4748,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Get a list of all the current user function execution logs. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Executions List",
@ -4763,7 +4763,7 @@
},
"x-appwrite": {
"method": "listExecutions",
"weight": 383,
"weight": 384,
"cookies": false,
"type": "",
"deprecated": false,
@ -4822,7 +4822,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.",
"responses": {
"201": {
"description": "Execution",
@ -4837,7 +4837,7 @@
},
"x-appwrite": {
"method": "createExecution",
"weight": 381,
"weight": 382,
"cookies": false,
"type": "",
"deprecated": false,
@ -4936,7 +4936,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Get a function execution log by its unique ID.",
"responses": {
"200": {
"description": "Execution",
@ -4951,7 +4951,7 @@
},
"x-appwrite": {
"method": "getExecution",
"weight": 382,
"weight": 383,
"cookies": false,
"type": "",
"deprecated": false,
@ -5534,7 +5534,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
"weight": 348,
"weight": 349,
"cookies": false,
"type": "",
"deprecated": false,
@ -5616,7 +5616,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
"weight": 352,
"weight": 353,
"cookies": false,
"type": "",
"deprecated": false,
@ -7448,6 +7448,451 @@
}
}
}
},
"\/tokens\/buckets\/{bucketId}\/files\/{fileId}": {
"get": {
"summary": "List tokens",
"operationId": "tokensList",
"tags": [
"tokens"
],
"description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Resource Tokens List",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceTokenList"
}
}
}
}
},
"x-appwrite": {
"method": "list",
"weight": 432,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/list.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"schema": {
"type": "string",
"x-example": "<BUCKET_ID>"
},
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<FILE_ID>"
},
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire",
"required": false,
"schema": {
"type": "string",
"default": []
},
"in": "query"
}
]
},
"post": {
"summary": "Create file token",
"operationId": "tokensCreateFileToken",
"tags": [
"tokens"
],
"description": "Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"responses": {
"201": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "createFileToken",
"weight": 429,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/create-file-token.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"schema": {
"type": "string",
"x-example": "<BUCKET_ID>"
},
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<FILE_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "Token expiry date",
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
}
}
}
},
"\/tokens\/{tokenId}": {
"get": {
"summary": "Get token",
"operationId": "tokensGet",
"tags": [
"tokens"
],
"description": "Get a token by its unique ID.",
"responses": {
"200": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "get",
"weight": 430,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
},
"patch": {
"summary": "Update token",
"operationId": "tokensUpdate",
"tags": [
"tokens"
],
"description": "Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"responses": {
"200": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "update",
"weight": 433,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/update.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "File token expiry date",
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
}
}
},
"delete": {
"summary": "Delete token",
"operationId": "tokensDelete",
"tags": [
"tokens"
],
"description": "Delete a token by its unique ID.",
"responses": {
"204": {
"description": "No content"
}
},
"x-appwrite": {
"method": "delete",
"weight": 434,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/delete.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
}
},
"\/tokens\/{tokenId}\/jwt": {
"get": {
"summary": "Get token as JWT",
"operationId": "tokensGetJWT",
"tags": [
"tokens"
],
"description": "Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"responses": {
"200": {
"description": "JWT",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/jwt"
}
}
}
}
},
"x-appwrite": {
"method": "getJWT",
"weight": 431,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get-j-w-t.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "File token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
}
}
},
"tags": [
@ -7698,6 +8143,30 @@
"files"
]
},
"resourceTokenList": {
"description": "Resource Tokens List",
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of tokens documents that matched your query.",
"x-example": 5,
"format": "int32"
},
"tokens": {
"type": "array",
"description": "List of tokens.",
"items": {
"$ref": "#\/components\/schemas\/resourceToken"
},
"x-example": ""
}
},
"required": [
"total",
"tokens"
]
},
"teamList": {
"description": "Teams List",
"type": "object",
@ -8894,6 +9363,50 @@
"chunksUploaded"
]
},
"resourceToken": {
"description": "ResourceToken",
"type": "object",
"properties": {
"$id": {
"type": "string",
"description": "Token ID.",
"x-example": "bb8ea5c16897e"
},
"$createdAt": {
"type": "string",
"description": "Token creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"resourceId": {
"type": "string",
"description": "Resource ID.",
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
},
"resourceInternalId": {
"type": "string",
"description": "File ID.",
"x-example": "1:1"
},
"resourceType": {
"type": "string",
"description": "Resource type.",
"x-example": "file"
},
"expire": {
"type": "string",
"description": "Token expiration date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
"$id",
"$createdAt",
"resourceId",
"resourceInternalId",
"resourceType",
"expire"
]
},
"team": {
"description": "Team",
"type": "object",

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -7448,6 +7448,451 @@
}
}
}
},
"\/tokens\/buckets\/{bucketId}\/files\/{fileId}": {
"get": {
"summary": "List tokens",
"operationId": "tokensList",
"tags": [
"tokens"
],
"description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Resource Tokens List",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceTokenList"
}
}
}
}
},
"x-appwrite": {
"method": "list",
"weight": 432,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/list.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"schema": {
"type": "string",
"x-example": "<BUCKET_ID>"
},
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<FILE_ID>"
},
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire",
"required": false,
"schema": {
"type": "string",
"default": []
},
"in": "query"
}
]
},
"post": {
"summary": "Create file token",
"operationId": "tokensCreateFileToken",
"tags": [
"tokens"
],
"description": "Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"responses": {
"201": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "createFileToken",
"weight": 429,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/create-file-token.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"schema": {
"type": "string",
"x-example": "<BUCKET_ID>"
},
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<FILE_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "Token expiry date",
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
}
}
}
},
"\/tokens\/{tokenId}": {
"get": {
"summary": "Get token",
"operationId": "tokensGet",
"tags": [
"tokens"
],
"description": "Get a token by its unique ID.",
"responses": {
"200": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "get",
"weight": 430,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
},
"patch": {
"summary": "Update token",
"operationId": "tokensUpdate",
"tags": [
"tokens"
],
"description": "Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"responses": {
"200": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "update",
"weight": 433,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/update.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "File token expiry date",
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
}
}
},
"delete": {
"summary": "Delete token",
"operationId": "tokensDelete",
"tags": [
"tokens"
],
"description": "Delete a token by its unique ID.",
"responses": {
"204": {
"description": "No content"
}
},
"x-appwrite": {
"method": "delete",
"weight": 434,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/delete.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
}
},
"\/tokens\/{tokenId}\/jwt": {
"get": {
"summary": "Get token as JWT",
"operationId": "tokensGetJWT",
"tags": [
"tokens"
],
"description": "Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"responses": {
"200": {
"description": "JWT",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/jwt"
}
}
}
}
},
"x-appwrite": {
"method": "getJWT",
"weight": 431,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get-j-w-t.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "File token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
}
}
},
"tags": [
@ -7698,6 +8143,30 @@
"files"
]
},
"resourceTokenList": {
"description": "Resource Tokens List",
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of tokens documents that matched your query.",
"x-example": 5,
"format": "int32"
},
"tokens": {
"type": "array",
"description": "List of tokens.",
"items": {
"$ref": "#\/components\/schemas\/resourceToken"
},
"x-example": ""
}
},
"required": [
"total",
"tokens"
]
},
"teamList": {
"description": "Teams List",
"type": "object",
@ -8894,6 +9363,50 @@
"chunksUploaded"
]
},
"resourceToken": {
"description": "ResourceToken",
"type": "object",
"properties": {
"$id": {
"type": "string",
"description": "Token ID.",
"x-example": "bb8ea5c16897e"
},
"$createdAt": {
"type": "string",
"description": "Token creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"resourceId": {
"type": "string",
"description": "Resource ID.",
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
},
"resourceInternalId": {
"type": "string",
"description": "File ID.",
"x-example": "1:1"
},
"resourceType": {
"type": "string",
"description": "Resource type.",
"x-example": "file"
},
"expire": {
"type": "string",
"description": "Token expiration date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
"$id",
"$createdAt",
"resourceId",
"resourceInternalId",
"resourceType",
"expire"
]
},
"team": {
"description": "Team",
"type": "object",

View file

@ -29954,6 +29954,451 @@
}
}
},
"\/tokens\/buckets\/{bucketId}\/files\/{fileId}": {
"get": {
"summary": "List tokens",
"operationId": "tokensList",
"tags": [
"tokens"
],
"description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Resource Tokens List",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceTokenList"
}
}
}
}
},
"x-appwrite": {
"method": "list",
"weight": 432,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/list.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"schema": {
"type": "string",
"x-example": "<BUCKET_ID>"
},
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<FILE_ID>"
},
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire",
"required": false,
"schema": {
"type": "string",
"default": []
},
"in": "query"
}
]
},
"post": {
"summary": "Create file token",
"operationId": "tokensCreateFileToken",
"tags": [
"tokens"
],
"description": "Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"responses": {
"201": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "createFileToken",
"weight": 429,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/create-file-token.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"schema": {
"type": "string",
"x-example": "<BUCKET_ID>"
},
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<FILE_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "Token expiry date",
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
}
}
}
},
"\/tokens\/{tokenId}": {
"get": {
"summary": "Get token",
"operationId": "tokensGet",
"tags": [
"tokens"
],
"description": "Get a token by its unique ID.",
"responses": {
"200": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "get",
"weight": 430,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
},
"patch": {
"summary": "Update token",
"operationId": "tokensUpdate",
"tags": [
"tokens"
],
"description": "Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"responses": {
"200": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "update",
"weight": 433,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/update.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "File token expiry date",
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
}
}
},
"delete": {
"summary": "Delete token",
"operationId": "tokensDelete",
"tags": [
"tokens"
],
"description": "Delete a token by its unique ID.",
"responses": {
"204": {
"description": "No content"
}
},
"x-appwrite": {
"method": "delete",
"weight": 434,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/delete.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
}
},
"\/tokens\/{tokenId}\/jwt": {
"get": {
"summary": "Get token as JWT",
"operationId": "tokensGetJWT",
"tags": [
"tokens"
],
"description": "Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"responses": {
"200": {
"description": "JWT",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/jwt"
}
}
}
}
},
"x-appwrite": {
"method": "getJWT",
"weight": 431,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get-j-w-t.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "File token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
}
},
"\/users": {
"get": {
"summary": "List users",
@ -34306,6 +34751,30 @@
"buckets"
]
},
"resourceTokenList": {
"description": "Resource Tokens List",
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of tokens documents that matched your query.",
"x-example": 5,
"format": "int32"
},
"tokens": {
"type": "array",
"description": "List of tokens.",
"items": {
"$ref": "#\/components\/schemas\/resourceToken"
},
"x-example": ""
}
},
"required": [
"total",
"tokens"
]
},
"teamList": {
"description": "Teams List",
"type": "object",
@ -37209,6 +37678,50 @@
"antivirus"
]
},
"resourceToken": {
"description": "ResourceToken",
"type": "object",
"properties": {
"$id": {
"type": "string",
"description": "Token ID.",
"x-example": "bb8ea5c16897e"
},
"$createdAt": {
"type": "string",
"description": "Token creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"resourceId": {
"type": "string",
"description": "Resource ID.",
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
},
"resourceInternalId": {
"type": "string",
"description": "File ID.",
"x-example": "1:1"
},
"resourceType": {
"type": "string",
"description": "Resource type.",
"x-example": "file"
},
"expire": {
"type": "string",
"description": "Token expiration date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
"$id",
"$createdAt",
"resourceId",
"resourceInternalId",
"resourceType",
"expire"
]
},
"team": {
"description": "Team",
"type": "object",

View file

@ -21127,6 +21127,463 @@
}
}
},
"\/tokens\/buckets\/{bucketId}\/files\/{fileId}": {
"get": {
"summary": "List tokens",
"operationId": "tokensList",
"tags": [
"tokens"
],
"description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Resource Tokens List",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceTokenList"
}
}
}
}
},
"x-appwrite": {
"method": "list",
"weight": 432,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/list.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"schema": {
"type": "string",
"x-example": "<BUCKET_ID>"
},
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<FILE_ID>"
},
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire",
"required": false,
"schema": {
"type": "string",
"default": []
},
"in": "query"
}
]
},
"post": {
"summary": "Create file token",
"operationId": "tokensCreateFileToken",
"tags": [
"tokens"
],
"description": "Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"responses": {
"201": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "createFileToken",
"weight": 429,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/create-file-token.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"schema": {
"type": "string",
"x-example": "<BUCKET_ID>"
},
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<FILE_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "Token expiry date",
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
}
}
}
},
"\/tokens\/{tokenId}": {
"get": {
"summary": "Get token",
"operationId": "tokensGet",
"tags": [
"tokens"
],
"description": "Get a token by its unique ID.",
"responses": {
"200": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "get",
"weight": 430,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
},
"patch": {
"summary": "Update token",
"operationId": "tokensUpdate",
"tags": [
"tokens"
],
"description": "Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"responses": {
"200": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "update",
"weight": 433,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/update.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "File token expiry date",
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
}
}
},
"delete": {
"summary": "Delete token",
"operationId": "tokensDelete",
"tags": [
"tokens"
],
"description": "Delete a token by its unique ID.",
"responses": {
"204": {
"description": "No content"
}
},
"x-appwrite": {
"method": "delete",
"weight": 434,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/delete.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
}
},
"\/tokens\/{tokenId}\/jwt": {
"get": {
"summary": "Get token as JWT",
"operationId": "tokensGetJWT",
"tags": [
"tokens"
],
"description": "Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"responses": {
"200": {
"description": "JWT",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/jwt"
}
}
}
}
},
"x-appwrite": {
"method": "getJWT",
"weight": 431,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get-j-w-t.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "File token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
}
},
"\/users": {
"get": {
"summary": "List users",
@ -24706,6 +25163,30 @@
"buckets"
]
},
"resourceTokenList": {
"description": "Resource Tokens List",
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of tokens documents that matched your query.",
"x-example": 5,
"format": "int32"
},
"tokens": {
"type": "array",
"description": "List of tokens.",
"items": {
"$ref": "#\/components\/schemas\/resourceToken"
},
"x-example": ""
}
},
"required": [
"total",
"tokens"
]
},
"teamList": {
"description": "Teams List",
"type": "object",
@ -27273,6 +27754,50 @@
"antivirus"
]
},
"resourceToken": {
"description": "ResourceToken",
"type": "object",
"properties": {
"$id": {
"type": "string",
"description": "Token ID.",
"x-example": "bb8ea5c16897e"
},
"$createdAt": {
"type": "string",
"description": "Token creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"resourceId": {
"type": "string",
"description": "Resource ID.",
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
},
"resourceInternalId": {
"type": "string",
"description": "File ID.",
"x-example": "1:1"
},
"resourceType": {
"type": "string",
"description": "Resource type.",
"x-example": "file"
},
"expire": {
"type": "string",
"description": "Token expiration date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
"$id",
"$createdAt",
"resourceId",
"resourceInternalId",
"resourceType",
"expire"
]
},
"team": {
"description": "Team",
"type": "object",

View file

@ -4918,7 +4918,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Get a list of all the current user function execution logs. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Executions List",
@ -4929,7 +4929,7 @@
},
"x-appwrite": {
"method": "listExecutions",
"weight": 383,
"weight": 384,
"cookies": false,
"type": "",
"deprecated": false,
@ -4991,7 +4991,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.",
"responses": {
"201": {
"description": "Execution",
@ -5002,7 +5002,7 @@
},
"x-appwrite": {
"method": "createExecution",
"weight": 381,
"weight": 382,
"cookies": false,
"type": "",
"deprecated": false,
@ -5109,7 +5109,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Get a function execution log by its unique ID.",
"responses": {
"200": {
"description": "Execution",
@ -5120,7 +5120,7 @@
},
"x-appwrite": {
"method": "getExecution",
"weight": 382,
"weight": 383,
"cookies": false,
"type": "",
"deprecated": false,
@ -5761,7 +5761,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
"weight": 348,
"weight": 349,
"cookies": false,
"type": "",
"deprecated": false,
@ -5845,7 +5845,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
"weight": 352,
"weight": 353,
"cookies": false,
"type": "",
"deprecated": false,
@ -7653,6 +7653,451 @@
}
]
}
},
"\/tokens\/buckets\/{bucketId}\/files\/{fileId}": {
"get": {
"summary": "List tokens",
"operationId": "tokensList",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Resource Tokens List",
"schema": {
"$ref": "#\/definitions\/resourceTokenList"
}
}
},
"x-appwrite": {
"method": "list",
"weight": 432,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/list.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"type": "string",
"x-example": "<BUCKET_ID>",
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"type": "string",
"x-example": "<FILE_ID>",
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire",
"required": false,
"type": "array",
"collectionFormat": "multi",
"items": {
"type": "string"
},
"default": [],
"in": "query"
}
]
},
"post": {
"summary": "Create file token",
"operationId": "tokensCreateFileToken",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"responses": {
"201": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "createFileToken",
"weight": 429,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/create-file-token.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"type": "string",
"x-example": "<BUCKET_ID>",
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"type": "string",
"x-example": "<FILE_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "Token expiry date",
"default": null,
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": [],
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
]
}
},
"\/tokens\/{tokenId}": {
"get": {
"summary": "Get token",
"operationId": "tokensGet",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Get a token by its unique ID.",
"responses": {
"200": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "get",
"weight": 430,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
},
"patch": {
"summary": "Update token",
"operationId": "tokensUpdate",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"responses": {
"200": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "update",
"weight": 433,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/update.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token unique ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "File token expiry date",
"default": null,
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": null,
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
]
},
"delete": {
"summary": "Delete token",
"operationId": "tokensDelete",
"consumes": [
"application\/json"
],
"produces": [],
"tags": [
"tokens"
],
"description": "Delete a token by its unique ID.",
"responses": {
"204": {
"description": "No content"
}
},
"x-appwrite": {
"method": "delete",
"weight": 434,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/delete.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
}
},
"\/tokens\/{tokenId}\/jwt": {
"get": {
"summary": "Get token as JWT",
"operationId": "tokensGetJWT",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"responses": {
"200": {
"description": "JWT",
"schema": {
"$ref": "#\/definitions\/jwt"
}
}
},
"x-appwrite": {
"method": "getJWT",
"weight": 431,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get-j-w-t.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "File token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
}
}
},
"tags": [
@ -7875,6 +8320,31 @@
"files"
]
},
"resourceTokenList": {
"description": "Resource Tokens List",
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of tokens documents that matched your query.",
"x-example": 5,
"format": "int32"
},
"tokens": {
"type": "array",
"description": "List of tokens.",
"items": {
"type": "object",
"$ref": "#\/definitions\/resourceToken"
},
"x-example": ""
}
},
"required": [
"total",
"tokens"
]
},
"teamList": {
"description": "Teams List",
"type": "object",
@ -9082,6 +9552,50 @@
"chunksUploaded"
]
},
"resourceToken": {
"description": "ResourceToken",
"type": "object",
"properties": {
"$id": {
"type": "string",
"description": "Token ID.",
"x-example": "bb8ea5c16897e"
},
"$createdAt": {
"type": "string",
"description": "Token creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"resourceId": {
"type": "string",
"description": "Resource ID.",
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
},
"resourceInternalId": {
"type": "string",
"description": "File ID.",
"x-example": "1:1"
},
"resourceType": {
"type": "string",
"description": "Resource type.",
"x-example": "file"
},
"expire": {
"type": "string",
"description": "Token expiration date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
"$id",
"$createdAt",
"resourceId",
"resourceInternalId",
"resourceType",
"expire"
]
},
"team": {
"description": "Team",
"type": "object",

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -7653,6 +7653,451 @@
}
]
}
},
"\/tokens\/buckets\/{bucketId}\/files\/{fileId}": {
"get": {
"summary": "List tokens",
"operationId": "tokensList",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Resource Tokens List",
"schema": {
"$ref": "#\/definitions\/resourceTokenList"
}
}
},
"x-appwrite": {
"method": "list",
"weight": 432,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/list.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"type": "string",
"x-example": "<BUCKET_ID>",
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"type": "string",
"x-example": "<FILE_ID>",
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire",
"required": false,
"type": "array",
"collectionFormat": "multi",
"items": {
"type": "string"
},
"default": [],
"in": "query"
}
]
},
"post": {
"summary": "Create file token",
"operationId": "tokensCreateFileToken",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"responses": {
"201": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "createFileToken",
"weight": 429,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/create-file-token.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"type": "string",
"x-example": "<BUCKET_ID>",
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"type": "string",
"x-example": "<FILE_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "Token expiry date",
"default": null,
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": [],
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
]
}
},
"\/tokens\/{tokenId}": {
"get": {
"summary": "Get token",
"operationId": "tokensGet",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Get a token by its unique ID.",
"responses": {
"200": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "get",
"weight": 430,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
},
"patch": {
"summary": "Update token",
"operationId": "tokensUpdate",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"responses": {
"200": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "update",
"weight": 433,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/update.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token unique ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "File token expiry date",
"default": null,
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": null,
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
]
},
"delete": {
"summary": "Delete token",
"operationId": "tokensDelete",
"consumes": [
"application\/json"
],
"produces": [],
"tags": [
"tokens"
],
"description": "Delete a token by its unique ID.",
"responses": {
"204": {
"description": "No content"
}
},
"x-appwrite": {
"method": "delete",
"weight": 434,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/delete.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
}
},
"\/tokens\/{tokenId}\/jwt": {
"get": {
"summary": "Get token as JWT",
"operationId": "tokensGetJWT",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"responses": {
"200": {
"description": "JWT",
"schema": {
"$ref": "#\/definitions\/jwt"
}
}
},
"x-appwrite": {
"method": "getJWT",
"weight": 431,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get-j-w-t.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "File token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
}
}
},
"tags": [
@ -7875,6 +8320,31 @@
"files"
]
},
"resourceTokenList": {
"description": "Resource Tokens List",
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of tokens documents that matched your query.",
"x-example": 5,
"format": "int32"
},
"tokens": {
"type": "array",
"description": "List of tokens.",
"items": {
"type": "object",
"$ref": "#\/definitions\/resourceToken"
},
"x-example": ""
}
},
"required": [
"total",
"tokens"
]
},
"teamList": {
"description": "Teams List",
"type": "object",
@ -9082,6 +9552,50 @@
"chunksUploaded"
]
},
"resourceToken": {
"description": "ResourceToken",
"type": "object",
"properties": {
"$id": {
"type": "string",
"description": "Token ID.",
"x-example": "bb8ea5c16897e"
},
"$createdAt": {
"type": "string",
"description": "Token creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"resourceId": {
"type": "string",
"description": "Resource ID.",
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
},
"resourceInternalId": {
"type": "string",
"description": "File ID.",
"x-example": "1:1"
},
"resourceType": {
"type": "string",
"description": "Resource type.",
"x-example": "file"
},
"expire": {
"type": "string",
"description": "Token expiration date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
"$id",
"$createdAt",
"resourceId",
"resourceInternalId",
"resourceType",
"expire"
]
},
"team": {
"description": "Team",
"type": "object",

View file

@ -30481,6 +30481,451 @@
]
}
},
"\/tokens\/buckets\/{bucketId}\/files\/{fileId}": {
"get": {
"summary": "List tokens",
"operationId": "tokensList",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Resource Tokens List",
"schema": {
"$ref": "#\/definitions\/resourceTokenList"
}
}
},
"x-appwrite": {
"method": "list",
"weight": 432,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/list.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"type": "string",
"x-example": "<BUCKET_ID>",
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"type": "string",
"x-example": "<FILE_ID>",
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire",
"required": false,
"type": "array",
"collectionFormat": "multi",
"items": {
"type": "string"
},
"default": [],
"in": "query"
}
]
},
"post": {
"summary": "Create file token",
"operationId": "tokensCreateFileToken",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"responses": {
"201": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "createFileToken",
"weight": 429,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/create-file-token.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"type": "string",
"x-example": "<BUCKET_ID>",
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"type": "string",
"x-example": "<FILE_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "Token expiry date",
"default": null,
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": [],
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
]
}
},
"\/tokens\/{tokenId}": {
"get": {
"summary": "Get token",
"operationId": "tokensGet",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Get a token by its unique ID.",
"responses": {
"200": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "get",
"weight": 430,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
},
"patch": {
"summary": "Update token",
"operationId": "tokensUpdate",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"responses": {
"200": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "update",
"weight": 433,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/update.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token unique ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "File token expiry date",
"default": null,
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": null,
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
]
},
"delete": {
"summary": "Delete token",
"operationId": "tokensDelete",
"consumes": [
"application\/json"
],
"produces": [],
"tags": [
"tokens"
],
"description": "Delete a token by its unique ID.",
"responses": {
"204": {
"description": "No content"
}
},
"x-appwrite": {
"method": "delete",
"weight": 434,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/delete.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
}
},
"\/tokens\/{tokenId}\/jwt": {
"get": {
"summary": "Get token as JWT",
"operationId": "tokensGetJWT",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"responses": {
"200": {
"description": "JWT",
"schema": {
"$ref": "#\/definitions\/jwt"
}
}
},
"x-appwrite": {
"method": "getJWT",
"weight": 431,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get-j-w-t.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "File token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
}
},
"\/users": {
"get": {
"summary": "List users",
@ -34848,6 +35293,31 @@
"buckets"
]
},
"resourceTokenList": {
"description": "Resource Tokens List",
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of tokens documents that matched your query.",
"x-example": 5,
"format": "int32"
},
"tokens": {
"type": "array",
"description": "List of tokens.",
"items": {
"type": "object",
"$ref": "#\/definitions\/resourceToken"
},
"x-example": ""
}
},
"required": [
"total",
"tokens"
]
},
"teamList": {
"description": "Teams List",
"type": "object",
@ -37789,6 +38259,50 @@
"antivirus"
]
},
"resourceToken": {
"description": "ResourceToken",
"type": "object",
"properties": {
"$id": {
"type": "string",
"description": "Token ID.",
"x-example": "bb8ea5c16897e"
},
"$createdAt": {
"type": "string",
"description": "Token creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"resourceId": {
"type": "string",
"description": "Resource ID.",
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
},
"resourceInternalId": {
"type": "string",
"description": "File ID.",
"x-example": "1:1"
},
"resourceType": {
"type": "string",
"description": "Resource type.",
"x-example": "file"
},
"expire": {
"type": "string",
"description": "Token expiration date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
"$id",
"$createdAt",
"resourceId",
"resourceInternalId",
"resourceType",
"expire"
]
},
"team": {
"description": "Team",
"type": "object",

View file

@ -21628,6 +21628,463 @@
]
}
},
"\/tokens\/buckets\/{bucketId}\/files\/{fileId}": {
"get": {
"summary": "List tokens",
"operationId": "tokensList",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Resource Tokens List",
"schema": {
"$ref": "#\/definitions\/resourceTokenList"
}
}
},
"x-appwrite": {
"method": "list",
"weight": 432,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/list.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"type": "string",
"x-example": "<BUCKET_ID>",
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"type": "string",
"x-example": "<FILE_ID>",
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire",
"required": false,
"type": "array",
"collectionFormat": "multi",
"items": {
"type": "string"
},
"default": [],
"in": "query"
}
]
},
"post": {
"summary": "Create file token",
"operationId": "tokensCreateFileToken",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"responses": {
"201": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "createFileToken",
"weight": 429,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/create-file-token.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"type": "string",
"x-example": "<BUCKET_ID>",
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"type": "string",
"x-example": "<FILE_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "Token expiry date",
"default": null,
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": [],
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
]
}
},
"\/tokens\/{tokenId}": {
"get": {
"summary": "Get token",
"operationId": "tokensGet",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Get a token by its unique ID.",
"responses": {
"200": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "get",
"weight": 430,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
},
"patch": {
"summary": "Update token",
"operationId": "tokensUpdate",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"responses": {
"200": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "update",
"weight": 433,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/update.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token unique ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "File token expiry date",
"default": null,
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": null,
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
]
},
"delete": {
"summary": "Delete token",
"operationId": "tokensDelete",
"consumes": [
"application\/json"
],
"produces": [],
"tags": [
"tokens"
],
"description": "Delete a token by its unique ID.",
"responses": {
"204": {
"description": "No content"
}
},
"x-appwrite": {
"method": "delete",
"weight": 434,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/delete.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
}
},
"\/tokens\/{tokenId}\/jwt": {
"get": {
"summary": "Get token as JWT",
"operationId": "tokensGetJWT",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"responses": {
"200": {
"description": "JWT",
"schema": {
"$ref": "#\/definitions\/jwt"
}
}
},
"x-appwrite": {
"method": "getJWT",
"weight": 431,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get-j-w-t.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Session": []
}
},
"security": [
{
"Project": [],
"Session": [],
"Key": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "File token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
}
},
"\/users": {
"get": {
"summary": "List users",
@ -25231,6 +25688,31 @@
"buckets"
]
},
"resourceTokenList": {
"description": "Resource Tokens List",
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of tokens documents that matched your query.",
"x-example": 5,
"format": "int32"
},
"tokens": {
"type": "array",
"description": "List of tokens.",
"items": {
"type": "object",
"$ref": "#\/definitions\/resourceToken"
},
"x-example": ""
}
},
"required": [
"total",
"tokens"
]
},
"teamList": {
"description": "Teams List",
"type": "object",
@ -27822,6 +28304,50 @@
"antivirus"
]
},
"resourceToken": {
"description": "ResourceToken",
"type": "object",
"properties": {
"$id": {
"type": "string",
"description": "Token ID.",
"x-example": "bb8ea5c16897e"
},
"$createdAt": {
"type": "string",
"description": "Token creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"resourceId": {
"type": "string",
"description": "Resource ID.",
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
},
"resourceInternalId": {
"type": "string",
"description": "File ID.",
"x-example": "1:1"
},
"resourceType": {
"type": "string",
"description": "Resource type.",
"x-example": "file"
},
"expire": {
"type": "string",
"description": "Token expiration date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
"$id",
"$createdAt",
"resourceId",
"resourceInternalId",
"resourceType",
"expire"
]
},
"team": {
"description": "Team",
"type": "object",

View file

@ -936,9 +936,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true)
->inject('response')
->inject('dbForProject')
->inject('resourceToken')
->inject('deviceForFiles')
->inject('deviceForLocal')
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Response $response, Database $dbForProject, Device $deviceForFiles, Device $deviceForLocal) {
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Response $response, Database $dbForProject, Document $resourceToken, Device $deviceForFiles, Device $deviceForLocal) {
if (!\extension_loaded('imagick')) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
@ -953,19 +954,24 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId();
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($bucket->getRead());
if (!$fileSecurity && !$valid) {
if (!$fileSecurity && !$valid && !$isToken) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
if ($fileSecurity && !$valid) {
if ($fileSecurity && !$valid && !$isToken) {
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
}
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
@ -1765,6 +1771,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
$response->noContent();
});
/** Storage usage */
App::get('/v1/storage/usage')
->desc('Get storage usage stats')
->groups(['api', 'storage'])

View file

@ -1555,11 +1555,12 @@ foreach (Config::getParam('services', []) as $service) {
}
}
// Modules
$platform = new Appwrite();
$platform->init(Service::TYPE_HTTP);
// Check for any errors found while we were initialising the SDK Methods.
if (!empty(Method::getErrors())) {
throw new \Exception('Errors found during SDK initialization:' . PHP_EOL . implode(PHP_EOL, Method::getErrors()));
}
// Modules
$platform = new Appwrite();
$platform->init(Service::TYPE_HTTP);

View file

@ -399,11 +399,12 @@ App::init()
->inject('queueForStatsUsage')
->inject('dbForProject')
->inject('timelimit')
->inject('resourceToken')
->inject('mode')
->inject('apiKey')
->inject('plan')
->inject('devKey')
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, string $mode, ?Key $apiKey, array $plan, Document $devKey) use ($usageDatabaseListener, $eventDatabaseListener) {
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey) use ($usageDatabaseListener, $eventDatabaseListener) {
$route = $utopia->getRoute();
@ -554,6 +555,10 @@ App::init()
$bucketId = $parts[1] ?? null;
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId();
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAppUser && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
@ -561,20 +566,23 @@ App::init()
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($bucket->getRead());
if (!$fileSecurity && !$valid) {
if (!$fileSecurity && !$valid && !$isToken) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
$parts = explode('/', $cacheLog->getAttribute('resource'));
$fileId = $parts[1] ?? null;
if ($fileSecurity && !$valid) {
if ($fileSecurity && !$valid && !$isToken) {
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
}
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}

View file

@ -897,3 +897,46 @@ App::setResource('apiKey', function (Request $request, Document $project): ?Key
}, ['request', 'project']);
App::setResource('executor', fn () => new Executor(fn (string $projectId, string $deploymentId) => System::getEnv('_APP_EXECUTOR_HOST')));
App::setResource('resourceToken', function ($project, $dbForProject, $request) {
$tokenJWT = $request->getParam('token');
if (!empty($tokenJWT) && !$project->isEmpty()) { // JWT authentication
$jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
try {
$payload = $jwt->decode($tokenJWT);
} catch (JWTException $error) {
return new Document([]);
}
$tokenId = $payload['tokenId'] ?? '';
$secret = $payload['secret'] ?? '';
if (empty($tokenId) || empty($secret)) {
return new Document([]);
}
$token = Authorization::skip(fn () => $dbForProject->getDocument('resourceTokens', $tokenId));
if ($token->isEmpty() || $token->getAttribute('secret') !== $secret) {
return new Document([]);
}
if ($token->getAttribute('resourceType') === 'file') {
$internalIds = explode(':', $token->getAttribute('resourceInternalId'));
$ids = explode(':', $token->getAttribute('resourceId'));
if (count($internalIds) !== 2 || count($ids) !== 2) {
return new Document([]);
}
return new Document([
'bucketId' => $ids[0],
'fileId' => $ids[1],
'bucketInternalId' => $internalIds[0],
'fileInternalId' => $internalIds[1],
]);
}
}
return new Document([]);
}, ['project', 'dbForProject', 'request']);

View file

@ -318,6 +318,10 @@ class Exception extends \Exception
/** Schedules */
public const SCHEDULE_NOT_FOUND = 'schedule_not_found';
/** Tokens */
public const TOKEN_NOT_FOUND = 'token_not_found';
public const TOKEN_EXPIRED = 'token_expired';
protected string $type = '';
protected array $errors = [];

View file

@ -8,6 +8,7 @@ use Appwrite\Platform\Modules\Functions;
use Appwrite\Platform\Modules\Projects;
use Appwrite\Platform\Modules\Proxy;
use Appwrite\Platform\Modules\Sites;
use Appwrite\Platform\Modules\Storage;
use Utopia\Platform\Platform;
class Appwrite extends Platform
@ -20,5 +21,6 @@ class Appwrite extends Platform
$this->addModule(new Sites\Module());
$this->addModule(new Console\Module());
$this->addModule(new Proxy\Module());
$this->addModule(new Storage\Module());
}
}

View file

@ -0,0 +1,45 @@
<?php
namespace Appwrite\Platform\Modules\Storage\Http\Tokens\Buckets\Files;
use Appwrite\Auth\Auth;
use Appwrite\Extend\Exception;
use Utopia\Database\Database;
use Utopia\Database\Validator\Authorization;
use Utopia\Platform\Action as UtopiaAction;
class Action extends UtopiaAction
{
protected function getFileAndBucket(Database $dbForProject, string $bucketId, string $fileId): array
{
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($bucket->getRead());
if (!$valid) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
if ($fileSecurity) {
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
}
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
return [
'bucket' => $bucket,
'file' => $file,
];
}
}

View file

@ -0,0 +1,116 @@
<?php
namespace Appwrite\Platform\Modules\Storage\Http\Tokens\Buckets\Files;
use Appwrite\Auth\Auth;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\Permissions;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Nullable;
class Create extends Action
{
use HTTP;
public static function getName()
{
return 'createFileToken';
}
public function __construct()
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/tokens/buckets/:bucketId/files/:fileId')
->desc('Create file token')
->groups(['api', 'token'])
->label('scope', 'tokens.write')
->label('event', 'tokens.[tokenId].create')
->label('audits.event', 'token.create')
->label('audits.resource', 'token/{response.$id}')
->label('usage.metric', 'tokens.{scope}.requests.create')
->label('usage.params', ['resourceId:{request.resourceId}', 'resourceType:{request.resourceType}'])
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT)
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
->label('sdk', new Method(
namespace: 'tokens',
name: 'createFileToken',
description: <<<EOT
Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.
EOT,
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_CREATED,
model: Response::MODEL_RESOURCE_TOKEN,
)
],
contentType: ContentType::JSON
))
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).')
->param('fileId', '', new UID(), 'File unique ID.')
->param('expire', null, new Nullable(new DatetimeValidator()), 'Token expiry date', true)
->param('permissions', [], new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
->inject('response')
->inject('dbForProject')
->inject('user')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(string $bucketId, string $fileId, ?string $expire, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents)
{
/**
* @var Document $bucket
* @var Document $file
*/
['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $bucketId, $fileId);
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
$validator = new Authorization(Database::PERMISSION_UPDATE);
$bucketPermission = $validator->isValid($bucket->getUpdate());
if ($fileSecurity) {
$filePermission = $validator->isValid($file->getUpdate());
if (!$bucketPermission && !$filePermission) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
} elseif (!$bucketPermission) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
$token = $dbForProject->createDocument('resourceTokens', new Document([
'$id' => ID::unique(),
'secret' => Auth::tokenGenerator(128),
'resourceId' => $bucketId . ':' . $fileId,
'resourceInternalId' => $bucket->getInternalId() . ':' . $file->getInternalId(),
'resourceType' => 'files',
'expire' => $expire,
'$permissions' => $permissions
]));
$queueForEvents
->setParam('bucketId', $bucket->getId())
->setParam('fileId', $file->getId())
->setParam('tokenId', $token->getId())
->setContext('bucket', $bucket)
;
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($token, Response::MODEL_RESOURCE_TOKEN);
}
}

View file

@ -0,0 +1,91 @@
<?php
namespace Appwrite\Platform\Modules\Storage\Http\Tokens\Buckets\Files;
use Appwrite\Extend\Exception as ExtendException;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Database\Validator\Queries\FileTokens;
use Appwrite\Utopia\Response;
use Exception;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Scope\HTTP;
class XList extends Action
{
use HTTP;
public static function getName()
{
return 'listFileTokens';
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
->setHttpPath('/v1/tokens/buckets/:bucketId/files/:fileId')
->desc('List tokens')
->groups(['api', 'tokens'])
->label('scope', 'tokens.read')
->label('usage.metric', 'tokens.requests.read')
->label('sdk', new Method(
namespace: 'tokens',
name: 'list',
description: <<<EOT
List all the tokens created for a specific file or bucket. You can use the query params to filter your results.
EOT,
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_RESOURCE_TOKEN_LIST,
)
],
contentType: ContentType::JSON
))
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).')
->param('fileId', '', new UID(), 'File unique ID.')
->param('queries', [], new FileTokens(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', FileTokens::ALLOWED_ATTRIBUTES), true)
->inject('response')
->inject('dbForProject')
->callback([$this, 'action']);
}
public function action(string $bucketId, string $fileId, array $queries, Response $response, Database $dbForProject)
{
['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $bucketId, $fileId);
$queries = Query::parseQueries($queries);
$queries[] = Query::equal('resourceType', ["files"]);
$queries[] = Query::equal('resourceId', [$bucket->getInternalId() . ':' . $file->getInternalId()]);
// Get cursor document if there was a cursor query
$cursor = \array_filter($queries, function ($query) {
return \in_array($query->getMethod(), [Query::TYPE_CURSOR_AFTER, Query::TYPE_CURSOR_BEFORE]);
});
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
$tokenId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('resourceTokens', $tokenId);
if ($cursorDocument->isEmpty()) {
throw new Exception(ExtendException::GENERAL_CURSOR_NOT_FOUND, "File token '{$tokenId}' for the 'cursor' value not found.");
}
$cursor->setValue($cursorDocument);
}
$filterQueries = Query::groupByType($queries)['filters'];
$response->dynamic(new Document([
'tokens' => $dbForProject->find('resourceTokens', $queries),
'total' => $dbForProject->count('resourceTokens', $filterQueries, APP_LIMIT_COUNT),
]), Response::MODEL_RESOURCE_TOKEN_LIST);
}
}

View file

@ -0,0 +1,79 @@
<?php
namespace Appwrite\Platform\Modules\Storage\Http\Tokens;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
class Delete extends Action
{
use HTTP;
public static function getName()
{
return 'deleteToken';
}
public function __construct()
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_DELETE)
->setHttpPath('/v1/tokens/:tokenId')
->desc('Delete token')
->groups(['api', 'tokens'])
->label('scope', 'tokens.write')
->label('event', 'tokens.[tokenId].delete')
->label('audits.event', 'tokens.delete')
->label('audits.resource', 'token/{request.tokenId}')
->label('usage.metric', 'tokens.{scope}.requests.delete')
->label('usage.params', ['tokenId:{request.tokenId}'])
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT)
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
->label('sdk', new Method(
namespace: 'tokens',
name: 'delete',
description: <<<EOT
Delete a token by its unique ID.
EOT,
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_NOCONTENT,
model: Response::MODEL_NONE,
)
],
contentType: ContentType::NONE
))
->param('tokenId', '', new UID(), 'Token ID.')
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(string $tokenId, Response $response, Database $dbForProject, Event $queueForEvents)
{
$token = $dbForProject->getDocument('resourceTokens', $tokenId);
if ($token->isEmpty()) {
throw new Exception(Exception::TOKEN_NOT_FOUND);
}
$dbForProject->deleteDocument('resourceTokens', $tokenId);
$queueForEvents
->setParam('tokenId', $token->getId())
->setPayload($response->output($token, Response::MODEL_RESOURCE_TOKEN))
;
$response->noContent();
}
}

View file

@ -0,0 +1,65 @@
<?php
namespace Appwrite\Platform\Modules\Storage\Http\Tokens;
use Appwrite\Extend\Exception;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
class Get extends Action
{
use HTTP;
public static function getName()
{
return 'getToken';
}
public function __construct()
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
->setHttpPath('/v1/tokens/:tokenId')
->desc('Get token')
->groups(['api', 'tokens'])
->label('scope', 'tokens.read')
->label('usage.metric', 'tokens.{scope}.requests.read')
->label('usage.params', ['tokenId:{request.tokenId}'])
->label('sdk', new Method(
namespace: 'tokens',
name: 'get',
description: <<<EOT
Get a token by its unique ID.
EOT,
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_RESOURCE_TOKEN,
)
],
contentType: ContentType::JSON
))
->param('tokenId', '', new UID(), 'Token ID.')
->inject('response')
->inject('dbForProject')
->callback([$this, 'action']);
}
public function action(string $tokenId, Response $response, Database $dbForProject)
{
$token = $dbForProject->getDocument('resourceTokens', $tokenId);
if ($token->isEmpty()) {
throw new Exception(Exception::TOKEN_NOT_FOUND);
}
$response->dynamic($token, Response::MODEL_RESOURCE_TOKEN);
}
}

View file

@ -0,0 +1,90 @@
<?php
namespace Appwrite\Platform\Modules\Storage\Http\Tokens\JWT;
use Ahc\Jwt\JWT;
use Appwrite\Extend\Exception;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\System\System;
class Get extends Action
{
use HTTP;
public static function getName()
{
return 'getTokenJWT';
}
public function __construct()
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
->setHttpPath('/v1/tokens/:tokenId/jwt')
->desc('Get token as JWT')
->groups(['api', 'tokens'])
->label('scope', 'tokens.read')
->label('usage.metric', 'tokens.{scope}.requests.read')
->label('usage.params', ['tokenId:{request.tokenId}'])
->label('sdk', new Method(
namespace: 'tokens',
name: 'getJWT',
description: <<<EOT
Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.
EOT,
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_JWT,
)
],
contentType: ContentType::JSON
))
->param('tokenId', '', new UID(), 'File token ID.')
->inject('response')
->inject('dbForProject')
->callback([$this, 'action']);
}
public function action(string $tokenId, Response $response, Database $dbForProject)
{
$token = $dbForProject->getDocument('resourceTokens', $tokenId);
if ($token->isEmpty()) {
throw new Exception(Exception::TOKEN_NOT_FOUND);
}
// calculate maxAge based on expiry date
$maxAge = PHP_INT_MAX;
$expire = $token->getAttribute('expire');
if ($expire !== null) {
$now = new \DateTime();
$expiryDate = new \DateTime($expire);
if ($expiryDate < $now) {
throw new Exception(Exception::TOKEN_EXPIRED);
}
$maxAge = $expiryDate->getTimestamp() - $now->getTimestamp();
}
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $maxAge, 10); // Instantiate with key, algo, maxAge and leeway.
$response
->setStatusCode(Response::STATUS_CODE_OK)
->dynamic(new Document(['jwt' => $jwt->encode([
'resourceType' => $token->getAttribute('resourceType'),
'resourceId' => $token->getAttribute('resourceId'),
'resourceInternalId' => $token->getAttribute('resourceInternalId'),
'tokenId' => $token->getId(),
'secret' => $token->getAttribute('secret')
])]), Response::MODEL_JWT);
}
}

View file

@ -0,0 +1,124 @@
<?php
namespace Appwrite\Platform\Modules\Storage\Http\Tokens;
use Appwrite\Auth\Auth;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\Permissions;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Nullable;
class Update extends Action
{
use HTTP;
public static function getName()
{
return 'updateToken';
}
public function __construct()
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/tokens/:tokenId')
->desc('Update token')
->groups(['api', 'tokens'])
->label('scope', 'tokens.write')
->label('event', 'tokens.[tokenId].update')
->label('audits.event', 'tokens.update')
->label('audits.resource', 'tokens/{response.$id}')
->label('usage.metric', 'tokens.{scope}.requests.update')
->label('usage.params', ['tokenId:{request.tokenId}'])
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT)
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
->label('sdk', new Method(
namespace: 'tokens',
name: 'update',
description: <<<EOT
Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.
EOT,
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_RESOURCE_TOKEN,
)
],
contentType: ContentType::JSON
))
->param('tokenId', '', new UID(), 'Token unique ID.')
->param('expire', null, new Nullable(new DatetimeValidator()), 'File token expiry date', true)
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(string $tokenId, ?string $expire, ?array $permissions, Response $response, Database $dbForProject, Event $queueForEvents)
{
$token = $dbForProject->getDocument('resourceTokens', $tokenId);
if ($token->isEmpty()) {
throw new Exception(Exception::TOKEN_NOT_FOUND);
}
// Map aggregate permissions into the multiple permissions they represent.
$permissions = Permission::aggregate($permissions, [
Database::PERMISSION_READ,
Database::PERMISSION_UPDATE,
Database::PERMISSION_DELETE,
]);
// Users can only manage their own roles, API keys and Admin users can manage any
$roles = Authorization::getRoles();
if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) {
foreach (Database::PERMISSIONS as $type) {
foreach ($permissions as $permission) {
$permission = Permission::parse($permission);
if ($permission->getPermission() != $type) {
continue;
}
$role = (new Role(
$permission->getRole(),
$permission->getIdentifier(),
$permission->getDimension()
))->toString();
if (!Authorization::isRole($role)) {
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')');
}
}
}
}
if (\is_null($permissions)) {
$permissions = $token->getPermissions() ?? [];
}
$token
->setAttribute('expire', $expire)
->setAttribute('$permissions', $permissions);
$token = $dbForProject->updateDocument('resourceTokens', $tokenId, $token);
$queueForEvents
->setParam('tokenId', $token->getId())
;
$response->dynamic($token, Response::MODEL_RESOURCE_TOKEN);
}
}

View file

@ -0,0 +1,14 @@
<?php
namespace Appwrite\Platform\Modules\Storage;
use Appwrite\Platform\Modules\Storage\Services\Http;
use Utopia\Platform;
class Module extends Platform\Module
{
public function __construct()
{
$this->addService('http', new Http());
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace Appwrite\Platform\Modules\Storage\Services;
use Appwrite\Platform\Modules\Storage\Http\Tokens\Buckets\Files\Create as CreateFileToken;
use Appwrite\Platform\Modules\Storage\Http\Tokens\Buckets\Files\XList as ListFileTokens;
use Appwrite\Platform\Modules\Storage\Http\Tokens\Delete as DeleteToken;
use Appwrite\Platform\Modules\Storage\Http\Tokens\Get as GetToken;
use Appwrite\Platform\Modules\Storage\Http\Tokens\JWT\Get as GetTokenJWT;
use Appwrite\Platform\Modules\Storage\Http\Tokens\Update as UpdateToken;
use Utopia\Platform\Service;
class Http extends Service
{
public function __construct()
{
$this->type = Service::TYPE_HTTP;
$this
->addAction(CreateFileToken::getName(), new CreateFileToken())
->addAction(GetToken::getName(), new GetToken())
->addAction(GetTokenJWT::getName(), new GetTokenJWT())
->addAction(ListFileTokens::getName(), new ListFileTokens())
->addAction(UpdateToken::getName(), new UpdateToken())
->addAction(DeleteToken::getName(), new DeleteToken())
;
}
}

View file

@ -216,7 +216,10 @@ class Migrations extends Action
'databases.read',
'collections.read',
'documents.read',
],
'documents.write',
'tokens.read',
'tokens.write',
]
]);
return API_KEY_DYNAMIC . '_' . $apiKey;

View file

@ -0,0 +1,19 @@
<?php
namespace Appwrite\Utopia\Database\Validator\Queries;
class FileTokens extends Base
{
public const ALLOWED_ATTRIBUTES = [
'expire',
];
/**
* Expression constructor
*
*/
public function __construct()
{
parent::__construct('files', self::ALLOWED_ATTRIBUTES);
}
}

View file

@ -86,6 +86,7 @@ use Appwrite\Utopia\Response\Model\Provider;
use Appwrite\Utopia\Response\Model\ProviderRepository;
use Appwrite\Utopia\Response\Model\ProviderRepositoryFramework;
use Appwrite\Utopia\Response\Model\ProviderRepositoryRuntime;
use Appwrite\Utopia\Response\Model\ResourceToken;
use Appwrite\Utopia\Response\Model\Rule;
use Appwrite\Utopia\Response\Model\Runtime;
use Appwrite\Utopia\Response\Model\Session;
@ -211,6 +212,8 @@ class Response extends SwooleResponse
public const MODEL_FILE_LIST = 'fileList';
public const MODEL_BUCKET = 'bucket';
public const MODEL_BUCKET_LIST = 'bucketList';
public const MODEL_RESOURCE_TOKEN = 'resourceToken';
public const MODEL_RESOURCE_TOKEN_LIST = 'resourceTokenList';
// Locale
public const MODEL_LOCALE = 'locale';
@ -376,6 +379,7 @@ class Response extends SwooleResponse
->setModel(new BaseList('Logs List', self::MODEL_LOG_LIST, 'logs', self::MODEL_LOG))
->setModel(new BaseList('Files List', self::MODEL_FILE_LIST, 'files', self::MODEL_FILE))
->setModel(new BaseList('Buckets List', self::MODEL_BUCKET_LIST, 'buckets', self::MODEL_BUCKET))
->setModel(new BaseList('Resource Tokens List', self::MODEL_RESOURCE_TOKEN_LIST, 'tokens', self::MODEL_RESOURCE_TOKEN))
->setModel(new BaseList('Teams List', self::MODEL_TEAM_LIST, 'teams', self::MODEL_TEAM))
->setModel(new BaseList('Memberships List', self::MODEL_MEMBERSHIP_LIST, 'memberships', self::MODEL_MEMBERSHIP))
->setModel(new BaseList('Sites List', self::MODEL_SITE_LIST, 'sites', self::MODEL_SITE))
@ -451,6 +455,7 @@ class Response extends SwooleResponse
->setModel(new LocaleCode())
->setModel(new File())
->setModel(new Bucket())
->setModel(new ResourceToken())
->setModel(new Team())
->setModel(new Membership())
->setModel(new Site())

View file

@ -0,0 +1,71 @@
<?php
namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Model;
class ResourceToken extends Model
{
public function __construct()
{
$this
->addRule('$id', [
'type' => self::TYPE_STRING,
'description' => 'Token ID.',
'default' => '',
'example' => 'bb8ea5c16897e',
])
->addRule('$createdAt', [
'type' => self::TYPE_DATETIME,
'description' => 'Token creation date in ISO 8601 format.',
'default' => '',
'example' => self::TYPE_DATETIME_EXAMPLE,
])
->addRule('resourceId', [
'type' => self::TYPE_STRING,
'description' => 'Resource ID.',
'default' => '',
'example' => '5e5ea5c168bb8:5e5ea5c168bb8',
])
->addRule('resourceInternalId', [
'type' => self::TYPE_STRING,
'description' => 'File ID.',
'default' => '',
'example' => '1:1',
])
->addRule('resourceType', [
'type' => self::TYPE_STRING,
'description' => 'Resource type.',
'default' => '',
'example' => 'file',
])
->addRule('expire', [
'type' => self::TYPE_DATETIME,
'description' => 'Token expiration date in ISO 8601 format.',
'default' => '',
'example' => self::TYPE_DATETIME_EXAMPLE,
])
;
}
/**
* Get Name
*
* @return string
*/
public function getName(): string
{
return 'ResourceToken';
}
/**
* Get Type
*
* @return string
*/
public function getType(): string
{
return Response::MODEL_RESOURCE_TOKEN;
}
}

View file

@ -103,7 +103,9 @@ trait ProjectCustom
'subscribers.write',
'subscribers.read',
'migrations.write',
'migrations.read'
'migrations.read',
'tokens.read',
'tokens.write',
],
]);

View file

@ -13,6 +13,9 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator;
trait StorageBase
{
/**
* @group fileTokens
*/
public function testCreateBucketFile(): array
{
/**

View file

@ -0,0 +1,7 @@
<?php
namespace Tests\E2E\Services\Tokens;
trait TokensBase
{
}

View file

@ -0,0 +1,14 @@
<?php
namespace Tests\E2E\Services\Tokens;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideConsole;
class TokensConsoleClientTest extends Scope
{
use SideConsole;
use TokensBase;
use ProjectCustom;
}

View file

@ -0,0 +1,15 @@
<?php
namespace Tests\E2E\Services\Tokens;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideClient;
class TokensCustomClientTest extends Scope
{
use TokensBase;
use ProjectCustom;
use SideClient;
}

View file

@ -0,0 +1,112 @@
<?php
namespace Tests\E2E\Services\Tokens;
use CURLFile;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideServer;
use Utopia\Database\DateTime;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
class TokensCustomServerTest extends Scope
{
use TokensBase;
use ProjectCustom;
use SideServer;
public function testCreateToken(): array
{
$bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'bucketId' => ID::unique(),
'name' => 'Test Bucket',
'fileSecurity' => true,
'maximumFileSize' => 2000000, //2MB
'allowedFileExtensions' => ['jpg', 'png', 'jfif'],
'permissions' => [
Permission::read(Role::any()),
Permission::create(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
]);
$this->assertEquals(201, $bucket['headers']['status-code']);
$this->assertNotEmpty($bucket['body']['$id']);
$bucketId = $bucket['body']['$id'];
$file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'fileId' => ID::unique(),
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
'permissions' => [
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
]);
$this->assertEquals(201, $file['headers']['status-code']);
$this->assertNotEmpty($file['body']['$id']);
$fileId = $file['body']['$id'];
$res = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()));
$this->assertEquals(201, $res['headers']['status-code']);
$this->assertEquals('files', $res['body']['resourceType']);
$data = [];
$data['fileId'] = $fileId;
$data['bucketId'] = $bucketId;
$data['tokenId'] = $res['body']['$id'];
return $data;
}
/**
* @depends testCreateToken
*/
public function testUpdateToken(array $data): array
{
$tokenId = $data['tokenId'];
$expiry = DateTime::now();
$res = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'expire' => $expiry,
]);
$this->assertEquals($expiry, $res['body']['expire']);
return $data;
}
/**
* @depends testUpdateToken
*/
public function testDeleteToken(array $data): array
{
$tokenId = $data['tokenId'];
$res = $this->client->call(Client::METHOD_DELETE, '/tokens/' . $tokenId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(204, $res['headers']['status-code']);
return $data;
}
}