From 1b7cd2877b976f5aed66003b78bfac46ce7f1687 Mon Sep 17 00:00:00 2001 From: Iain Sproat <68657+iainsproat@users.noreply.github.com> Date: Tue, 31 Dec 2024 14:12:46 +0000 Subject: [PATCH] Update openapi specification and skip unimplemented endpoint --- setup/fuzzer/dictionary.restler.json | 4 +- setup/fuzzer/settings.restler.json | 8 +- setup/fuzzer/speckle-server.openapi.json | 199 +++++++++++++++++++---- 3 files changed, 180 insertions(+), 31 deletions(-) diff --git a/setup/fuzzer/dictionary.restler.json b/setup/fuzzer/dictionary.restler.json index 826669edda..ebdf7e2893 100644 --- a/setup/fuzzer/dictionary.restler.json +++ b/setup/fuzzer/dictionary.restler.json @@ -11,7 +11,9 @@ "restler_fuzzable_number": ["1.23"], "restler_fuzzable_bool": ["true"], "restler_fuzzable_object": ["{ \"fuzz\": false }"], - "restler_custom_payload": {}, + "restler_custom_payload": { + "/graphql/post/Content-Type": ["application/json"] + }, "restler_custom_payload_unquoted": {}, "restler_custom_payload_uuid4_suffix": {}, "restler_custom_payload_header": {}, diff --git a/setup/fuzzer/settings.restler.json b/setup/fuzzer/settings.restler.json index 68f9340260..9076368e86 100644 --- a/setup/fuzzer/settings.restler.json +++ b/setup/fuzzer/settings.restler.json @@ -3,5 +3,11 @@ "max_combinations": 20, "target_ip": "127.0.0.1", "target_port": 3000, - "ignore_decoding_failures": true + "ignore_decoding_failures": true, + "exclude_requests": [ + { + "endpoint": "/api/stream/{streamId}/blobs", + "methods": ["DELETE"] + } + ] } diff --git a/setup/fuzzer/speckle-server.openapi.json b/setup/fuzzer/speckle-server.openapi.json index e0e2db7a7e..8e2965342c 100644 --- a/setup/fuzzer/speckle-server.openapi.json +++ b/setup/fuzzer/speckle-server.openapi.json @@ -18,15 +18,32 @@ }, "/auth/local/login": { "post": { + "parameters": [ + { + "in": "query", + "name": "challenge", + "required": true, + "schema": { "type": "string" } + } + ], "description": "Login with email and password", "responses": { "200": { "description": "User logged in successfully" }, + "400": { "description": "Invalid input" }, "401": { "description": "Invalid credentials" } } } }, "/auth/local/register": { "post": { + "parameters": [ + { + "in": "query", + "name": "challenge", + "required": true, + "schema": { "type": "string" } + } + ], "description": "Register with email and password", "responses": { "200": { "description": "User registered successfully" }, @@ -37,6 +54,14 @@ }, "/auth/accesscode": { "get": { + "parameters": [ + { + "in": "query", + "name": "appId", + "required": true, + "schema": { "type": "string" } + } + ], "description": "Generates an access code for an app.", "responses": { "200": { "description": "Returns an access code in the body" }, @@ -55,7 +80,27 @@ "/auth/token": { "post": { "description": "Generates a new API token", - "responses": { "200": { "description": "Generates a new API token" } } + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "appId": { "type": "string" }, + "appSecret": { "type": "string" }, + "accessCode": { "type": "string" }, + "challenge": { "type": "string" }, + "refreshToken": { "type": "string" } + }, + "required": ["appId", "appSecret"] + } + } + } + }, + "responses": { + "200": { "description": "Generates a new API token" }, + "401": { "description": "Unauthorized" } + } } }, "/auth/logout": { @@ -70,18 +115,43 @@ "/api/stream/{streamId}/blob": { "post": { "description": "Upload a new blob to a project (stream)", - "parameters": [{ "in": "path", "name": "streamId", "required": true }], + "parameters": [ + { + "in": "path", + "name": "streamId", + "required": true, + "schema": { "type": "string" } + } + ], "responses": { "200": { "description": "Successfully uploaded a blob to the project" - } + }, + "404": { "description": "Stream could not be found" } } } }, - "/api/stream/{streamId}/diff": { + "/api/stream/{streamId}/blob/diff": { "post": { "description": "Determine the difference (diff) between the provided array of blob Ids and those stored on the server", - "parameters": [{ "in": "path", "name": "streamId", "required": true }], + "parameters": [ + { + "in": "path", + "name": "streamId", + "required": true, + "schema": { "type": "string" } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "type": "string" } + } + } + } + }, "responses": { "200": { "description": "The difference between the list of blob Ids provided in the body of the request and those stored on the server" @@ -90,28 +160,37 @@ } }, "/api/stream/{streamId}/blob/{blobId}": { + "parameters": [ + { + "in": "path", + "name": "streamId", + "required": true, + "schema": { "type": "string" } + }, + { + "in": "path", + "name": "blobId", + "required": true, + "schema": { "type": "string" } + } + ], "get": { "description": "Gets a blob from a project (stream)", - "parameters": [ - { "in": "path", "name": "streamId", "required": true }, - { "in": "path", "name": "blobId", "required": true } - ], "responses": { "200": { "description": "Successfully retrieved a blob from the project" - } + }, + "401": { "description": "Unauthorized" }, + "404": { "description": "Stream or blob could not be found." } } }, "delete": { "description": "Deletes a blob from a project (stream)", - "parameters": [ - { "in": "path", "name": "streamId", "required": true }, - { "in": "path", "name": "blobId", "required": true } - ], "responses": { "204": { "description": "Successfully deleted a blob from the project" - } + }, + "404": { "description": "Stream or blob could not be found." } } } }, @@ -129,7 +208,9 @@ "responses": { "200": { "description": "Successfully retrieved all the blobs from the project" - } + }, + "401": { "description": "Unauthorized" }, + "404": { "description": "Stream could not be found." } } }, "delete": { @@ -137,7 +218,7 @@ "responses": { "501": { "description": "Not implemented." } } } }, - "/static": { + "/static/": { "get": { "description": "Static assets", "responses": { "200": { "description": "An asset was retrieved." } } @@ -181,7 +262,8 @@ "post": { "description": "Upload objects to the project (stream)", "responses": { - "200": { "description": "Objects were successfully uploaded." } + "200": { "description": "Objects were successfully uploaded." }, + "401": { "description": "Unauthorized" } } } }, @@ -206,7 +288,10 @@ }, "get": { "description": "Download objects from a project (stream)", - "responses": { "200": { "description": "Objects were downloaded." } } + "responses": { + "200": { "description": "Objects were downloaded." }, + "401": { "description": "Unauthorized" } + } } }, "/objects/{streamId}/{objectId}/single": { @@ -230,7 +315,10 @@ }, "get": { "description": "Options for downloading a single object from a project (stream)", - "responses": { "200": { "description": "An object was retrieved." } } + "responses": { + "200": { "description": "An object was retrieved." }, + "401": { "description": "Unauthorized" } + } } }, "/api/diff/{streamId}": { @@ -248,8 +336,22 @@ }, "post": { "description": "Options for getting the diff of objects for a project (stream)", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "objects": { "type": "array", "items": { "type": "string" } } + }, + "required": ["objects"] + } + } + } + }, "responses": { - "200": { "description": "A diff was successfully computed." } + "200": { "description": "A diff was successfully computed." }, + "401": { "description": "Unauthorized" } } } }, @@ -269,7 +371,8 @@ "post": { "description": "Get all objects for a project (stream)", "responses": { - "200": { "description": "All objects were successfully retrieved." } + "200": { "description": "All objects were successfully retrieved." }, + "401": { "description": "Unauthorized" } } } }, @@ -277,7 +380,23 @@ "get": { "summary": "Verify email", "description": "Verifies an email address", - "responses": { "302": { "description": "Redirects to the home page." } } + "responses": { + "302": { + "description": "Redirects to the home page.", + "headers": { + "Location": { + "schema": { "type": "string" } + } + }, + "parameters": [ + { + "in": "query", + "name": "emailverifiederror", + "schema": { "type": "string" } + } + ] + } + } } }, "/api/file/{fileType}/{streamId}/{branchName}": { @@ -286,7 +405,12 @@ "in": "path", "name": "fileType", "required": true, - "schema": { "type": "string" } + "schema": { + "oneOf": [ + { "type": "string" }, + { "type": "string", "enum": ["autodetect"] } + ] + } }, { "in": "path", @@ -306,6 +430,9 @@ "responses": { "200": { "description": "file successfully uploaded to the project (stream)" + }, + "404": { + "description": "Stream or branch could not be found." } } } @@ -466,10 +593,9 @@ { "in": "path", "name": "angle", - "required": true, "schema": { "oneOf": [ - { "type": "integer", "minimum": 0 }, + { "type": "integer", "minimum": 0, "maximum": 360 }, { "type": "string", "enum": ["all"] } ] } @@ -491,22 +617,37 @@ "schema": { "type": "string", "format": "binary" } } } - } + }, + "403": { "description": "Forbidden" } } } }, "/auth/pwdreset/request": { "post": { "description": "Reset a password", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { "type": "string", "format": "email" } + }, + "required": ["email"] + } + } + } + }, "responses": { "200": { "description": "The password reset workflow was successfully started." - } + }, + "400": { "description": "Invalid input" } } } }, "/auth/pwdreset/finalize": { - "get": { + "post": { "description": "Finish resetting a password", "responses": { "200": { "description": "The password was successfully reset." }