From ae9e0af6f8e385f97532b00ca04e74e9f6ffd075 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 3 May 2024 09:12:01 +0200 Subject: [PATCH] feat(ban): Contract for banning attendees and IP/ranges Signed-off-by: Joas Schilling --- appinfo/routes.php | 1 + appinfo/routes/routesBanController.php | 22 ++ docs/capabilities.md | 3 + lib/Capabilities.php | 1 + lib/Controller/BanController.php | 126 ++++++++ lib/Controller/RoomController.php | 18 +- lib/ResponseDefinitions.php | 10 + openapi-full.json | 389 ++++++++++++++++++++++++- openapi.json | 389 ++++++++++++++++++++++++- src/types/openapi/openapi-full.ts | 148 +++++++++- src/types/openapi/openapi.ts | 148 +++++++++- tests/php/CapabilitiesTest.php | 1 + 12 files changed, 1250 insertions(+), 6 deletions(-) create mode 100644 appinfo/routes/routesBanController.php create mode 100644 lib/Controller/BanController.php diff --git a/appinfo/routes.php b/appinfo/routes.php index 66e72865d3e2..51f312e5bd77 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -9,6 +9,7 @@ return array_merge_recursive( include(__DIR__ . '/routes/routesAvatarController.php'), + include(__DIR__ . '/routes/routesBanController.php'), include(__DIR__ . '/routes/routesBotController.php'), include(__DIR__ . '/routes/routesBreakoutRoomController.php'), include(__DIR__ . '/routes/routesCallController.php'), diff --git a/appinfo/routes/routesBanController.php b/appinfo/routes/routesBanController.php new file mode 100644 index 000000000000..d38bb639750e --- /dev/null +++ b/appinfo/routes/routesBanController.php @@ -0,0 +1,22 @@ + '(v1)', + 'token' => '[a-z0-9]{4,30}', +]; +return [ + 'ocs' => [ + /** @see \OCA\Talk\Controller\BanController::banActor() */ + ['name' => 'Ban#banActor', 'url' => '/api/{apiVersion}/ban/{token}', 'verb' => 'POST', 'requirements' => $requirements], + /** @see \OCA\Talk\Controller\BanController::listBans() */ + ['name' => 'Ban#listBans', 'url' => '/api/{apiVersion}/ban/{token}', 'verb' => 'GET', 'requirements' => $requirements], + /** @see \OCA\Talk\Controller\BanController::unbanActor() */ + ['name' => 'Ban#unbanActor', 'url' => '/api/{apiVersion}/ban/{token}', 'verb' => 'DELETE', 'requirements' => $requirements], + ], +]; diff --git a/docs/capabilities.md b/docs/capabilities.md index 1f8987a1e491..5aa9d9e170e7 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -149,3 +149,6 @@ * `config => federation => incoming-enabled` - Boolean, whether users are allowed to be invited into federated conversations on other servers * `config => federation => outgoing-enabled` - Boolean, whether users are allowed to invited federated users of other servers into conversations * `config => federation => only-trusted-servers` - Boolean, whether federation invites are limited to trusted servers + +## 20 +* `ban-v1` - Whether the API to ban attendees is available diff --git a/lib/Capabilities.php b/lib/Capabilities.php index c76b79808941..8d3c5017e6b7 100644 --- a/lib/Capabilities.php +++ b/lib/Capabilities.php @@ -125,6 +125,7 @@ public function getCapabilities(): array { 'silent-send-state', 'chat-read-last', 'federation-v1', + 'ban-v1', ], 'config' => [ 'attachments' => [ diff --git a/lib/Controller/BanController.php b/lib/Controller/BanController.php new file mode 100644 index 000000000000..8373ae52da78 --- /dev/null +++ b/lib/Controller/BanController.php @@ -0,0 +1,126 @@ +|DataResponse + * + * 200: Ban successfully + * 400: Actor information is invalid + */ + #[PublicPage] + #[RequireModeratorParticipant] + public function banActor(string $token, string $actorType, string $actorId, string $internalNote): DataResponse { + if ($actorId === 'wrong') { + return new DataResponse([ + 'error' => 'actor', + ], Http::STATUS_BAD_REQUEST); + } + + + return new DataResponse( + [ + 'id' => random_int(1, 1337), + 'actorType' => $this->participant->getAttendee()->getActorType(), + 'actorId' => $this->participant->getAttendee()->getActorId(), + 'bannedType' => $actorType, + 'bannedId' => $actorId, + 'bannedTime' => time(), + 'internalNote' => $internalNote ?: 'Lorem ipsum', + ], + Http::STATUS_OK + ); + } + + /** + * List the bans of a conversation + * + * Required capability: `ban-v1` + * + * @param string $token Conversation token + * @return DataResponse, array{}> + * + * 200: List all bans + */ + #[PublicPage] + #[RequireModeratorParticipant] + public function listBans(string $token): DataResponse { + return new DataResponse([ + $this->randomBan(Attendee::ACTOR_USERS, 'test'), + $this->randomBan(Attendee::ACTOR_USERS, '123456'), + $this->randomBan(Attendee::ACTOR_FEDERATED_USERS, 'admin@nextcloud.local'), + $this->randomBan('ip', '127.0.0.1'), + $this->randomBan('ip', '127.0.0.1/32'), + $this->randomBan('ip', '127.0.0.0/24'), + $this->randomBan('ip', '::1/24'), + $this->randomBan('ip', '2001:0db8:85a3::/48'), + ], Http::STATUS_OK); + } + + /** + * Unban an actor or IP address + * + * Required capability: `ban-v1` + * + * @param string $token Conversation token + * @param int $banId ID of the ban to be removed + * @return DataResponse, array{}> + * + * 200: Unban successfully or not found + */ + #[PublicPage] + #[RequireModeratorParticipant] + public function unbanActor(string $token, int $banId): DataResponse { + return new DataResponse([], Http::STATUS_OK); + } + + /** + * @psalm-return TalkBan + */ + protected function randomBan(string $actorType, string $actorId): array { + return [ + 'id' => random_int(1, 1337), + 'actorType' => $this->participant->getAttendee()->getActorType(), + 'actorId' => $this->participant->getAttendee()->getActorId(), + 'bannedType' => $actorType, + 'bannedId' => $actorId, + 'bannedTime' => random_int(1514747958, 1714747958), + 'internalNote' => '#NOTE#' . $actorType . '#' . $actorId . '#' . sha1($actorType . $actorId), + ]; + } +} diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php index f930192eb329..3aa5d4de1a6a 100644 --- a/lib/Controller/RoomController.php +++ b/lib/Controller/RoomController.php @@ -1474,7 +1474,7 @@ public function setPassword(string $password): DataResponse { * @param string $token Token of the room * @param string $password Password of the room * @param bool $force Create a new session if necessary - * @return DataResponse|DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse>|DataResponse, array>|DataResponse> * * 200: Room joined successfully * 403: Joining room is not allowed @@ -1512,6 +1512,18 @@ public function joinRoom(string $token, string $password = '', bool $force = tru return $response; } + if (strtolower($room->getName()) === 'ban user' && $this->userId === 'banned') { + return new DataResponse([ + 'error' => 'ban', + ], Http::STATUS_FORBIDDEN); + } + + if (strtolower($room->getName()) === 'ban guest' && !$this->userId) { + return new DataResponse([ + 'error' => 'ban', + ], Http::STATUS_FORBIDDEN); + } + /** @var Participant|null $previousSession */ $previousParticipant = null; /** @var Session|null $previousSession */ @@ -1585,7 +1597,9 @@ public function joinRoom(string $token, string $password = '', bool $force = tru $this->throttler->resetDelay($this->request->getRemoteAddress(), 'talkRoomPassword', ['token' => $token, 'action' => 'talkRoomPassword']); $this->throttler->resetDelay($this->request->getRemoteAddress(), 'talkRoomToken', ['token' => $token, 'action' => 'talkRoomToken']); } catch (InvalidPasswordException $e) { - $response = new DataResponse([], Http::STATUS_FORBIDDEN); + $response = new DataResponse([ + 'error' => 'password', + ], Http::STATUS_FORBIDDEN); $response->throttle(['token' => $token, 'action' => 'talkRoomPassword']); return $response; } catch (UnauthorizedException $e) { diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index 54d788661e44..e2bd54ed819b 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -10,6 +10,16 @@ namespace OCA\Talk; /** + * @psalm-type TalkBan = array{ + * id: int, + * actorType: string, + * actorId: string, + * bannedType: string, + * bannedId: string, + * bannedTime: int, + * internalNote: string, + * } + * * @psalm-type TalkBot = array{ * description: ?string, * id: int, diff --git a/openapi-full.json b/openapi-full.json index 8aec51d898f2..131d0e3ea7ee 100644 --- a/openapi-full.json +++ b/openapi-full.json @@ -20,6 +20,43 @@ } }, "schemas": { + "Ban": { + "type": "object", + "required": [ + "id", + "actorType", + "actorId", + "bannedType", + "bannedId", + "bannedTime", + "internalNote" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "actorType": { + "type": "string" + }, + "actorId": { + "type": "string" + }, + "bannedType": { + "type": "string" + }, + "bannedId": { + "type": "string" + }, + "bannedTime": { + "type": "integer", + "format": "int64" + }, + "internalNote": { + "type": "string" + } + } + }, "BaseMessage": { "type": "object", "required": [ @@ -1883,6 +1920,342 @@ } } }, + "/ocs/v2.php/apps/spreed/api/{apiVersion}/ban/{token}": { + "post": { + "operationId": "ban-ban-actor", + "summary": "Ban an actor or IP address", + "description": "Required capability: `ban-v1`", + "tags": [ + "ban" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "actorType", + "in": "query", + "description": "Type of actor to ban, or `ip` when banning a clients remote address", + "required": true, + "schema": { + "type": "string", + "enum": [ + "users", + "groups", + "circles", + "emails", + "federated_users", + "phones", + "ip" + ] + } + }, + { + "name": "actorId", + "in": "query", + "description": "Actor ID or the IP address or range in case of type `ip`", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "internalNote", + "in": "query", + "description": "Optional internal note", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "token", + "in": "path", + "description": "Conversation token", + "required": true, + "schema": { + "type": "string", + "pattern": "^[a-z0-9]{4,30}$" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Ban successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Ban" + } + } + } + } + } + } + } + }, + "400": { + "description": "Actor information is invalid", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + }, + "get": { + "operationId": "ban-list-bans", + "summary": "List the bans of a conversation", + "description": "Required capability: `ban-v1`", + "tags": [ + "ban" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "token", + "in": "path", + "description": "Conversation token", + "required": true, + "schema": { + "type": "string", + "pattern": "^[a-z0-9]{4,30}$" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "List all bans", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Ban" + } + } + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "ban-unban-actor", + "summary": "Unban an actor or IP address", + "description": "Required capability: `ban-v1`", + "tags": [ + "ban" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "banId", + "in": "query", + "description": "ID of the ban to be removed", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "token", + "in": "path", + "description": "Conversation token", + "required": true, + "schema": { + "type": "string", + "pattern": "^[a-z0-9]{4,30}$" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Unban successfully or not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, "/ocs/v2.php/apps/spreed/api/{apiVersion}/bot/{token}": { "get": { "operationId": "bot-list-bots", @@ -12399,7 +12772,21 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "ban", + "password" + ] + } + } + } } } } diff --git a/openapi.json b/openapi.json index a0d74b9d13c6..2df6d305e0da 100644 --- a/openapi.json +++ b/openapi.json @@ -20,6 +20,43 @@ } }, "schemas": { + "Ban": { + "type": "object", + "required": [ + "id", + "actorType", + "actorId", + "bannedType", + "bannedId", + "bannedTime", + "internalNote" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "actorType": { + "type": "string" + }, + "actorId": { + "type": "string" + }, + "bannedType": { + "type": "string" + }, + "bannedId": { + "type": "string" + }, + "bannedTime": { + "type": "integer", + "format": "int64" + }, + "internalNote": { + "type": "string" + } + } + }, "BaseMessage": { "type": "object", "required": [ @@ -1770,6 +1807,342 @@ } } }, + "/ocs/v2.php/apps/spreed/api/{apiVersion}/ban/{token}": { + "post": { + "operationId": "ban-ban-actor", + "summary": "Ban an actor or IP address", + "description": "Required capability: `ban-v1`", + "tags": [ + "ban" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "actorType", + "in": "query", + "description": "Type of actor to ban, or `ip` when banning a clients remote address", + "required": true, + "schema": { + "type": "string", + "enum": [ + "users", + "groups", + "circles", + "emails", + "federated_users", + "phones", + "ip" + ] + } + }, + { + "name": "actorId", + "in": "query", + "description": "Actor ID or the IP address or range in case of type `ip`", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "internalNote", + "in": "query", + "description": "Optional internal note", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "token", + "in": "path", + "description": "Conversation token", + "required": true, + "schema": { + "type": "string", + "pattern": "^[a-z0-9]{4,30}$" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Ban successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Ban" + } + } + } + } + } + } + } + }, + "400": { + "description": "Actor information is invalid", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + }, + "get": { + "operationId": "ban-list-bans", + "summary": "List the bans of a conversation", + "description": "Required capability: `ban-v1`", + "tags": [ + "ban" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "token", + "in": "path", + "description": "Conversation token", + "required": true, + "schema": { + "type": "string", + "pattern": "^[a-z0-9]{4,30}$" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "List all bans", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Ban" + } + } + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "ban-unban-actor", + "summary": "Unban an actor or IP address", + "description": "Required capability: `ban-v1`", + "tags": [ + "ban" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "banId", + "in": "query", + "description": "ID of the ban to be removed", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "token", + "in": "path", + "description": "Conversation token", + "required": true, + "schema": { + "type": "string", + "pattern": "^[a-z0-9]{4,30}$" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Unban successfully or not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, "/ocs/v2.php/apps/spreed/api/{apiVersion}/bot/{token}": { "get": { "operationId": "bot-list-bots", @@ -12509,7 +12882,21 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "ban", + "password" + ] + } + } + } } } } diff --git a/src/types/openapi/openapi-full.ts b/src/types/openapi/openapi-full.ts index 66bd34df6120..dd12a138c23e 100644 --- a/src/types/openapi/openapi-full.ts +++ b/src/types/openapi/openapi-full.ts @@ -26,6 +26,23 @@ export type paths = { /** Get the dark mode avatar of a room */ get: operations["avatar-get-avatar-dark"]; }; + "/ocs/v2.php/apps/spreed/api/{apiVersion}/ban/{token}": { + /** + * List the bans of a conversation + * @description Required capability: `ban-v1` + */ + get: operations["ban-list-bans"]; + /** + * Ban an actor or IP address + * @description Required capability: `ban-v1` + */ + post: operations["ban-ban-actor"]; + /** + * Unban an actor or IP address + * @description Required capability: `ban-v1` + */ + delete: operations["ban-unban-actor"]; + }; "/ocs/v2.php/apps/spreed/api/{apiVersion}/bot/{token}": { /** List bots */ get: operations["bot-list-bots"]; @@ -532,6 +549,17 @@ export type webhooks = Record; export type components = { schemas: { + Ban: { + /** Format: int64 */ + id: number; + actorType: string; + actorId: string; + bannedType: string; + bannedId: string; + /** Format: int64 */ + bannedTime: number; + internalNote: string; + }; BaseMessage: { actorDisplayName: string; actorId: string; @@ -1095,6 +1123,121 @@ export type operations = { }; }; }; + /** + * List the bans of a conversation + * @description Required capability: `ban-v1` + */ + "ban-list-bans": { + parameters: { + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Conversation token */ + token: string; + }; + }; + responses: { + /** @description List all bans */ + 200: { + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: components["schemas"]["Ban"][]; + }; + }; + }; + }; + }; + }; + /** + * Ban an actor or IP address + * @description Required capability: `ban-v1` + */ + "ban-ban-actor": { + parameters: { + query: { + /** @description Type of actor to ban, or `ip` when banning a clients remote address */ + actorType: "users" | "groups" | "circles" | "emails" | "federated_users" | "phones" | "ip"; + /** @description Actor ID or the IP address or range in case of type `ip` */ + actorId: string; + /** @description Optional internal note */ + internalNote: string; + }; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Conversation token */ + token: string; + }; + }; + responses: { + /** @description Ban successfully */ + 200: { + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: components["schemas"]["Ban"]; + }; + }; + }; + }; + /** @description Actor information is invalid */ + 400: { + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + }; + }; + }; + }; + }; + }; + }; + /** + * Unban an actor or IP address + * @description Required capability: `ban-v1` + */ + "ban-unban-actor": { + parameters: { + query: { + /** @description ID of the ban to be removed */ + banId: number; + }; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Conversation token */ + token: string; + }; + }; + responses: { + /** @description Unban successfully or not found */ + 200: { + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: unknown; + }; + }; + }; + }; + }; + }; /** List bots */ "bot-list-bots": { parameters: { @@ -4599,7 +4742,10 @@ export type operations = { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "ban" | "password"; + }; }; }; }; diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts index 86e715f60d20..0f8c8aa87fb2 100644 --- a/src/types/openapi/openapi.ts +++ b/src/types/openapi/openapi.ts @@ -26,6 +26,23 @@ export type paths = { /** Get the dark mode avatar of a room */ get: operations["avatar-get-avatar-dark"]; }; + "/ocs/v2.php/apps/spreed/api/{apiVersion}/ban/{token}": { + /** + * List the bans of a conversation + * @description Required capability: `ban-v1` + */ + get: operations["ban-list-bans"]; + /** + * Ban an actor or IP address + * @description Required capability: `ban-v1` + */ + post: operations["ban-ban-actor"]; + /** + * Unban an actor or IP address + * @description Required capability: `ban-v1` + */ + delete: operations["ban-unban-actor"]; + }; "/ocs/v2.php/apps/spreed/api/{apiVersion}/bot/{token}": { /** List bots */ get: operations["bot-list-bots"]; @@ -385,6 +402,17 @@ export type webhooks = Record; export type components = { schemas: { + Ban: { + /** Format: int64 */ + id: number; + actorType: string; + actorId: string; + bannedType: string; + bannedId: string; + /** Format: int64 */ + bannedTime: number; + internalNote: string; + }; BaseMessage: { actorDisplayName: string; actorId: string; @@ -918,6 +946,121 @@ export type operations = { }; }; }; + /** + * List the bans of a conversation + * @description Required capability: `ban-v1` + */ + "ban-list-bans": { + parameters: { + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Conversation token */ + token: string; + }; + }; + responses: { + /** @description List all bans */ + 200: { + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: components["schemas"]["Ban"][]; + }; + }; + }; + }; + }; + }; + /** + * Ban an actor or IP address + * @description Required capability: `ban-v1` + */ + "ban-ban-actor": { + parameters: { + query: { + /** @description Type of actor to ban, or `ip` when banning a clients remote address */ + actorType: "users" | "groups" | "circles" | "emails" | "federated_users" | "phones" | "ip"; + /** @description Actor ID or the IP address or range in case of type `ip` */ + actorId: string; + /** @description Optional internal note */ + internalNote: string; + }; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Conversation token */ + token: string; + }; + }; + responses: { + /** @description Ban successfully */ + 200: { + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: components["schemas"]["Ban"]; + }; + }; + }; + }; + /** @description Actor information is invalid */ + 400: { + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + }; + }; + }; + }; + }; + }; + }; + /** + * Unban an actor or IP address + * @description Required capability: `ban-v1` + */ + "ban-unban-actor": { + parameters: { + query: { + /** @description ID of the ban to be removed */ + banId: number; + }; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Conversation token */ + token: string; + }; + }; + responses: { + /** @description Unban successfully or not found */ + 200: { + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: unknown; + }; + }; + }; + }; + }; + }; /** List bots */ "bot-list-bots": { parameters: { @@ -4500,7 +4643,10 @@ export type operations = { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "ban" | "password"; + }; }; }; }; diff --git a/tests/php/CapabilitiesTest.php b/tests/php/CapabilitiesTest.php index 3112d29a957e..07d928877577 100644 --- a/tests/php/CapabilitiesTest.php +++ b/tests/php/CapabilitiesTest.php @@ -135,6 +135,7 @@ public function setUp(): void { 'silent-send-state', 'chat-read-last', 'federation-v1', + 'ban-v1', 'message-expiration', 'reactions', ];