From 2842422bb04d176b7f41888e6eed10cd4b81bbac Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 18 Sep 2018 11:12:47 -0700 Subject: first attempt at auth in API spec --- rust/fatcat-api-spec/README.md | 2 +- rust/fatcat-api-spec/api.yaml | 37 + rust/fatcat-api-spec/api/swagger.yaml | 984 +++++++++++++++++++++++++++ rust/fatcat-api-spec/src/client.rs | 1185 +++++++++++++++++++++++++++++++++ rust/fatcat-api-spec/src/lib.rs | 158 +++++ rust/fatcat-api-spec/src/mimetypes.rs | 316 +++++++++ rust/fatcat-api-spec/src/server.rs | 1109 +++++++++++++++++++++++++++++- 7 files changed, 3786 insertions(+), 5 deletions(-) (limited to 'rust') diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index d6f09b7a..41f4ae5e 100644 --- a/rust/fatcat-api-spec/README.md +++ b/rust/fatcat-api-spec/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2018-12-27T07:23:47.225Z +- Build date: 2018-12-27T07:31:49.807Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index 0f52a8b6..713cb116 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -13,6 +13,12 @@ consumes: produces: - application/json +securityDefinitions: + Bearer: + type: apiKey + name: Authorization + in: header + tags: # TAGLINE - name: containers # TAGLINE descriptions: "Container entities: such as journals, conferences, book series" # TAGLINE @@ -548,6 +554,13 @@ x-entity-responses: &ENTITYRESPONSES description: Bad Request schema: $ref: "#/definitions/error_response" + 401: + description: Not Authorized # "Authentication information is missing or invalid" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: string 404: description: Not Found schema: @@ -573,6 +586,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -602,6 +617,8 @@ paths: type: array items: $ref: "#/definitions/container_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -651,6 +668,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -666,6 +685,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -816,6 +837,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -845,6 +868,8 @@ paths: type: array items: $ref: "#/definitions/creator_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -894,6 +919,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -909,6 +936,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -1082,6 +1111,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1111,6 +1142,8 @@ paths: type: array items: $ref: "#/definitions/file_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1160,6 +1193,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1175,6 +1210,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index 3ad51b8a..7e5508b9 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -64,6 +64,18 @@ paths: uppercase_operation_id: "CREATE_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -82,6 +94,8 @@ paths: uppercase_operation_id: "CREATE_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_container" uppercase_operation_id: "CREATE_CONTAINER" path: "/container" @@ -143,6 +157,18 @@ paths: uppercase_operation_id: "CREATE_CONTAINER_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_CONTAINER_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -161,6 +187,8 @@ paths: uppercase_operation_id: "CREATE_CONTAINER_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_container_batch" uppercase_operation_id: "CREATE_CONTAINER_BATCH" path: "/container/batch" @@ -213,6 +241,18 @@ paths: uppercase_operation_id: "GET_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -284,6 +324,18 @@ paths: uppercase_operation_id: "UPDATE_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "UPDATE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -302,6 +354,8 @@ paths: uppercase_operation_id: "UPDATE_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_container" uppercase_operation_id: "UPDATE_CONTAINER" path: "/container/:ident" @@ -344,6 +398,18 @@ paths: uppercase_operation_id: "DELETE_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -362,6 +428,8 @@ paths: uppercase_operation_id: "DELETE_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_container" uppercase_operation_id: "DELETE_CONTAINER" path: "/container/:ident" @@ -418,6 +486,18 @@ paths: uppercase_operation_id: "GET_CONTAINER_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CONTAINER_REVISION" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -481,6 +561,18 @@ paths: uppercase_operation_id: "GET_CONTAINER_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CONTAINER_HISTORY" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -537,6 +629,18 @@ paths: uppercase_operation_id: "GET_CONTAINER_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CONTAINER_REDIRECTS" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -614,6 +718,18 @@ paths: uppercase_operation_id: "LOOKUP_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "LOOKUP_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -672,6 +788,18 @@ paths: uppercase_operation_id: "GET_CONTAINER_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CONTAINER_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -729,6 +857,18 @@ paths: uppercase_operation_id: "DELETE_CONTAINER_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_CONTAINER_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -795,6 +935,18 @@ paths: uppercase_operation_id: "CREATE_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -813,6 +965,8 @@ paths: uppercase_operation_id: "CREATE_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_creator" uppercase_operation_id: "CREATE_CREATOR" path: "/creator" @@ -874,6 +1028,18 @@ paths: uppercase_operation_id: "CREATE_CREATOR_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_CREATOR_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -892,6 +1058,8 @@ paths: uppercase_operation_id: "CREATE_CREATOR_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_creator_batch" uppercase_operation_id: "CREATE_CREATOR_BATCH" path: "/creator/batch" @@ -944,6 +1112,18 @@ paths: uppercase_operation_id: "GET_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1015,6 +1195,18 @@ paths: uppercase_operation_id: "UPDATE_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "UPDATE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1033,6 +1225,8 @@ paths: uppercase_operation_id: "UPDATE_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_creator" uppercase_operation_id: "UPDATE_CREATOR" path: "/creator/:ident" @@ -1075,6 +1269,18 @@ paths: uppercase_operation_id: "DELETE_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1093,6 +1299,8 @@ paths: uppercase_operation_id: "DELETE_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_creator" uppercase_operation_id: "DELETE_CREATOR" path: "/creator/:ident" @@ -1149,6 +1357,18 @@ paths: uppercase_operation_id: "GET_CREATOR_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CREATOR_REVISION" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1212,6 +1432,18 @@ paths: uppercase_operation_id: "GET_CREATOR_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CREATOR_HISTORY" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1276,6 +1508,18 @@ paths: uppercase_operation_id: "GET_CREATOR_RELEASES" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CREATOR_RELEASES" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1332,6 +1576,18 @@ paths: uppercase_operation_id: "GET_CREATOR_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CREATOR_REDIRECTS" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1409,6 +1665,18 @@ paths: uppercase_operation_id: "LOOKUP_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "LOOKUP_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1467,6 +1735,18 @@ paths: uppercase_operation_id: "GET_CREATOR_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_CREATOR_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1524,6 +1804,18 @@ paths: uppercase_operation_id: "DELETE_CREATOR_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_CREATOR_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1590,6 +1882,18 @@ paths: uppercase_operation_id: "CREATE_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1608,6 +1912,8 @@ paths: uppercase_operation_id: "CREATE_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_file" uppercase_operation_id: "CREATE_FILE" path: "/file" @@ -1669,6 +1975,18 @@ paths: uppercase_operation_id: "CREATE_FILE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_FILE_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1687,6 +2005,8 @@ paths: uppercase_operation_id: "CREATE_FILE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_file_batch" uppercase_operation_id: "CREATE_FILE_BATCH" path: "/file/batch" @@ -1739,6 +2059,18 @@ paths: uppercase_operation_id: "GET_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1810,6 +2142,18 @@ paths: uppercase_operation_id: "UPDATE_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "UPDATE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1828,6 +2172,8 @@ paths: uppercase_operation_id: "UPDATE_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_file" uppercase_operation_id: "UPDATE_FILE" path: "/file/:ident" @@ -1870,6 +2216,18 @@ paths: uppercase_operation_id: "DELETE_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1888,6 +2246,8 @@ paths: uppercase_operation_id: "DELETE_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_file" uppercase_operation_id: "DELETE_FILE" path: "/file/:ident" @@ -1944,6 +2304,18 @@ paths: uppercase_operation_id: "GET_FILE_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_FILE_REVISION" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2007,6 +2379,18 @@ paths: uppercase_operation_id: "GET_FILE_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_FILE_HISTORY" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2063,6 +2447,18 @@ paths: uppercase_operation_id: "GET_FILE_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_FILE_REDIRECTS" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2153,6 +2549,18 @@ paths: uppercase_operation_id: "LOOKUP_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "LOOKUP_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2211,6 +2619,18 @@ paths: uppercase_operation_id: "GET_FILE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_FILE_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2268,6 +2688,18 @@ paths: uppercase_operation_id: "DELETE_FILE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_FILE_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2334,6 +2766,18 @@ paths: uppercase_operation_id: "CREATE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_FILESET" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2413,6 +2857,18 @@ paths: uppercase_operation_id: "CREATE_FILESET_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_FILESET_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2483,6 +2939,18 @@ paths: uppercase_operation_id: "GET_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_FILESET" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2554,6 +3022,18 @@ paths: uppercase_operation_id: "UPDATE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "UPDATE_FILESET" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2614,6 +3094,18 @@ paths: uppercase_operation_id: "DELETE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_FILESET" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2688,6 +3180,18 @@ paths: uppercase_operation_id: "GET_FILESET_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_FILESET_REVISION" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2751,6 +3255,18 @@ paths: uppercase_operation_id: "GET_FILESET_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_FILESET_HISTORY" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2807,6 +3323,18 @@ paths: uppercase_operation_id: "GET_FILESET_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_FILESET_REDIRECTS" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2865,6 +3393,18 @@ paths: uppercase_operation_id: "GET_FILESET_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_FILESET_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2922,6 +3462,18 @@ paths: uppercase_operation_id: "DELETE_FILESET_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_FILESET_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2988,6 +3540,18 @@ paths: uppercase_operation_id: "CREATE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_WEBCAPTURE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3067,6 +3631,18 @@ paths: uppercase_operation_id: "CREATE_WEBCAPTURE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_WEBCAPTURE_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3137,6 +3713,18 @@ paths: uppercase_operation_id: "GET_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WEBCAPTURE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3208,6 +3796,18 @@ paths: uppercase_operation_id: "UPDATE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "UPDATE_WEBCAPTURE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3268,6 +3868,18 @@ paths: uppercase_operation_id: "DELETE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_WEBCAPTURE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3342,6 +3954,18 @@ paths: uppercase_operation_id: "GET_WEBCAPTURE_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WEBCAPTURE_REVISION" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3405,6 +4029,18 @@ paths: uppercase_operation_id: "GET_WEBCAPTURE_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WEBCAPTURE_HISTORY" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3461,6 +4097,18 @@ paths: uppercase_operation_id: "GET_WEBCAPTURE_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WEBCAPTURE_REDIRECTS" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3519,6 +4167,18 @@ paths: uppercase_operation_id: "GET_WEBCAPTURE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WEBCAPTURE_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3576,6 +4236,18 @@ paths: uppercase_operation_id: "DELETE_WEBCAPTURE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_WEBCAPTURE_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3642,6 +4314,18 @@ paths: uppercase_operation_id: "CREATE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3721,6 +4405,18 @@ paths: uppercase_operation_id: "CREATE_RELEASE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_RELEASE_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3791,6 +4487,18 @@ paths: uppercase_operation_id: "GET_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3862,6 +4570,18 @@ paths: uppercase_operation_id: "UPDATE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "UPDATE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3922,6 +4642,18 @@ paths: uppercase_operation_id: "DELETE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3996,6 +4728,18 @@ paths: uppercase_operation_id: "GET_RELEASE_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_RELEASE_REVISION" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4059,6 +4803,18 @@ paths: uppercase_operation_id: "GET_RELEASE_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_RELEASE_HISTORY" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4123,6 +4879,18 @@ paths: uppercase_operation_id: "GET_RELEASE_FILES" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_RELEASE_FILES" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4187,6 +4955,18 @@ paths: uppercase_operation_id: "GET_RELEASE_FILESETS" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_RELEASE_FILESETS" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4251,6 +5031,18 @@ paths: uppercase_operation_id: "GET_RELEASE_WEBCAPTURES" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_RELEASE_WEBCAPTURES" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4307,6 +5099,18 @@ paths: uppercase_operation_id: "GET_RELEASE_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_RELEASE_REDIRECTS" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4406,6 +5210,18 @@ paths: uppercase_operation_id: "LOOKUP_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "LOOKUP_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4464,6 +5280,18 @@ paths: uppercase_operation_id: "GET_RELEASE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_RELEASE_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4521,6 +5349,18 @@ paths: uppercase_operation_id: "DELETE_RELEASE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_RELEASE_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4587,6 +5427,18 @@ paths: uppercase_operation_id: "CREATE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4666,6 +5518,18 @@ paths: uppercase_operation_id: "CREATE_WORK_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_WORK_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4736,6 +5600,18 @@ paths: uppercase_operation_id: "GET_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4807,6 +5683,18 @@ paths: uppercase_operation_id: "UPDATE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "UPDATE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4867,6 +5755,18 @@ paths: uppercase_operation_id: "DELETE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4941,6 +5841,18 @@ paths: uppercase_operation_id: "GET_WORK_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WORK_REVISION" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5004,6 +5916,18 @@ paths: uppercase_operation_id: "GET_WORK_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WORK_HISTORY" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5060,6 +5984,18 @@ paths: uppercase_operation_id: "GET_WORK_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WORK_REDIRECTS" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5124,6 +6060,18 @@ paths: uppercase_operation_id: "GET_WORK_RELEASES" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WORK_RELEASES" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5182,6 +6130,18 @@ paths: uppercase_operation_id: "GET_WORK_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "GET_WORK_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5239,6 +6199,18 @@ paths: uppercase_operation_id: "DELETE_WORK_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "DELETE_WORK_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5630,6 +6602,11 @@ paths: path: "/changelog/:index" HttpMethod: "Get" httpmethod: "get" +securityDefinitions: + Bearer: + type: "apiKey" + name: "Authorization" + in: "header" definitions: error_response: type: "object" @@ -7494,6 +8471,13 @@ x-entity-responses: description: "Bad Request" schema: $ref: "#/definitions/error_response" + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" 404: description: "Not Found" schema: diff --git a/rust/fatcat-api-spec/src/client.rs b/rust/fatcat-api-spec/src/client.rs index 0ef2742e..1e889092 100644 --- a/rust/fatcat-api-spec/src/client.rs +++ b/rust/fatcat-api-spec/src/client.rs @@ -212,6 +212,21 @@ impl Api for Client { Ok(CreateContainerResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateContainerResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -292,6 +307,21 @@ impl Api for Client { Ok(CreateContainerBatchResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateContainerBatchResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -360,6 +390,21 @@ impl Api for Client { Ok(DeleteContainerResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteContainerResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -424,6 +469,21 @@ impl Api for Client { Ok(DeleteContainerEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteContainerEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -494,6 +554,21 @@ impl Api for Client { Ok(GetContainerResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetContainerResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -558,6 +633,21 @@ impl Api for Client { Ok(GetContainerEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetContainerEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -626,6 +716,21 @@ impl Api for Client { Ok(GetContainerHistoryResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetContainerHistoryResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -690,6 +795,21 @@ impl Api for Client { Ok(GetContainerRedirectsResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetContainerRedirectsResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -766,6 +886,21 @@ impl Api for Client { Ok(GetContainerRevisionResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetContainerRevisionResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -846,6 +981,21 @@ impl Api for Client { Ok(LookupContainerResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(LookupContainerResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -925,6 +1075,21 @@ impl Api for Client { Ok(UpdateContainerResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(UpdateContainerResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -997,6 +1162,21 @@ impl Api for Client { Ok(CreateCreatorResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateCreatorResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1077,6 +1257,21 @@ impl Api for Client { Ok(CreateCreatorBatchResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateCreatorBatchResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1145,6 +1340,21 @@ impl Api for Client { Ok(DeleteCreatorResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteCreatorResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1209,6 +1419,21 @@ impl Api for Client { Ok(DeleteCreatorEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteCreatorEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1279,6 +1504,21 @@ impl Api for Client { Ok(GetCreatorResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetCreatorResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1343,6 +1583,21 @@ impl Api for Client { Ok(GetCreatorEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetCreatorEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1411,6 +1666,21 @@ impl Api for Client { Ok(GetCreatorHistoryResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetCreatorHistoryResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1475,6 +1745,21 @@ impl Api for Client { Ok(GetCreatorRedirectsResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetCreatorRedirectsResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1543,6 +1828,21 @@ impl Api for Client { Ok(GetCreatorReleasesResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetCreatorReleasesResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1619,6 +1919,21 @@ impl Api for Client { Ok(GetCreatorRevisionResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetCreatorRevisionResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1699,6 +2014,21 @@ impl Api for Client { Ok(LookupCreatorResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(LookupCreatorResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1778,6 +2108,21 @@ impl Api for Client { Ok(UpdateCreatorResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(UpdateCreatorResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2273,6 +2618,21 @@ impl Api for Client { Ok(CreateFileResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateFileResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2353,6 +2713,21 @@ impl Api for Client { Ok(CreateFileBatchResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateFileBatchResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2421,6 +2796,21 @@ impl Api for Client { Ok(DeleteFileResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteFileResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2485,6 +2875,21 @@ impl Api for Client { Ok(DeleteFileEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteFileEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2555,6 +2960,21 @@ impl Api for Client { Ok(GetFileResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetFileResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2619,6 +3039,21 @@ impl Api for Client { Ok(GetFileEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetFileEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2687,6 +3122,21 @@ impl Api for Client { Ok(GetFileHistoryResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetFileHistoryResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2751,6 +3201,21 @@ impl Api for Client { Ok(GetFileRedirectsResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetFileRedirectsResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2827,6 +3292,21 @@ impl Api for Client { Ok(GetFileRevisionResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetFileRevisionResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2910,6 +3390,21 @@ impl Api for Client { Ok(LookupFileResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(LookupFileResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2989,6 +3484,21 @@ impl Api for Client { Ok(UpdateFileResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(UpdateFileResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3061,6 +3571,21 @@ impl Api for Client { Ok(CreateFilesetResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateFilesetResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3141,6 +3666,21 @@ impl Api for Client { Ok(CreateFilesetBatchResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateFilesetBatchResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3209,6 +3749,21 @@ impl Api for Client { Ok(DeleteFilesetResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteFilesetResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3273,6 +3828,21 @@ impl Api for Client { Ok(DeleteFilesetEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteFilesetEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3343,6 +3913,21 @@ impl Api for Client { Ok(GetFilesetResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetFilesetResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3407,6 +3992,21 @@ impl Api for Client { Ok(GetFilesetEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetFilesetEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3475,6 +4075,21 @@ impl Api for Client { Ok(GetFilesetHistoryResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetFilesetHistoryResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3539,6 +4154,21 @@ impl Api for Client { Ok(GetFilesetRedirectsResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetFilesetRedirectsResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3615,6 +4245,21 @@ impl Api for Client { Ok(GetFilesetRevisionResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetFilesetRevisionResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3694,6 +4339,21 @@ impl Api for Client { Ok(UpdateFilesetResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(UpdateFilesetResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3766,6 +4426,21 @@ impl Api for Client { Ok(CreateReleaseResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateReleaseResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3846,6 +4521,21 @@ impl Api for Client { Ok(CreateReleaseBatchResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateReleaseBatchResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3914,6 +4604,21 @@ impl Api for Client { Ok(CreateWorkResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateWorkResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3982,6 +4687,21 @@ impl Api for Client { Ok(DeleteReleaseResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteReleaseResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4046,6 +4766,21 @@ impl Api for Client { Ok(DeleteReleaseEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteReleaseEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4116,6 +4851,21 @@ impl Api for Client { Ok(GetReleaseResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetReleaseResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4180,6 +4930,21 @@ impl Api for Client { Ok(GetReleaseEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetReleaseEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4248,6 +5013,21 @@ impl Api for Client { Ok(GetReleaseFilesResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetReleaseFilesResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4316,6 +5096,21 @@ impl Api for Client { Ok(GetReleaseFilesetsResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetReleaseFilesetsResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4384,6 +5179,21 @@ impl Api for Client { Ok(GetReleaseHistoryResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetReleaseHistoryResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4448,6 +5258,21 @@ impl Api for Client { Ok(GetReleaseRedirectsResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetReleaseRedirectsResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4524,6 +5349,21 @@ impl Api for Client { Ok(GetReleaseRevisionResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetReleaseRevisionResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4592,6 +5432,21 @@ impl Api for Client { Ok(GetReleaseWebcapturesResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetReleaseWebcapturesResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4684,6 +5539,21 @@ impl Api for Client { Ok(LookupReleaseResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(LookupReleaseResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4763,6 +5633,21 @@ impl Api for Client { Ok(UpdateReleaseResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(UpdateReleaseResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4840,6 +5725,21 @@ impl Api for Client { Ok(CreateWebcaptureResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateWebcaptureResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4920,6 +5820,21 @@ impl Api for Client { Ok(CreateWebcaptureBatchResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateWebcaptureBatchResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4988,6 +5903,21 @@ impl Api for Client { Ok(DeleteWebcaptureResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteWebcaptureResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5052,6 +5982,21 @@ impl Api for Client { Ok(DeleteWebcaptureEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteWebcaptureEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5122,6 +6067,21 @@ impl Api for Client { Ok(GetWebcaptureResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWebcaptureResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5186,6 +6146,21 @@ impl Api for Client { Ok(GetWebcaptureEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWebcaptureEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5254,6 +6229,21 @@ impl Api for Client { Ok(GetWebcaptureHistoryResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWebcaptureHistoryResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5318,6 +6308,21 @@ impl Api for Client { Ok(GetWebcaptureRedirectsResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWebcaptureRedirectsResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5394,6 +6399,21 @@ impl Api for Client { Ok(GetWebcaptureRevisionResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWebcaptureRevisionResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5473,6 +6493,21 @@ impl Api for Client { Ok(UpdateWebcaptureResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(UpdateWebcaptureResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5553,6 +6588,21 @@ impl Api for Client { Ok(CreateWorkBatchResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateWorkBatchResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5621,6 +6671,21 @@ impl Api for Client { Ok(DeleteWorkResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteWorkResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5685,6 +6750,21 @@ impl Api for Client { Ok(DeleteWorkEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(DeleteWorkEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5755,6 +6835,21 @@ impl Api for Client { Ok(GetWorkResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWorkResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5819,6 +6914,21 @@ impl Api for Client { Ok(GetWorkEditResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWorkEditResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5887,6 +6997,21 @@ impl Api for Client { Ok(GetWorkHistoryResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWorkHistoryResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5951,6 +7076,21 @@ impl Api for Client { Ok(GetWorkRedirectsResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWorkRedirectsResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6019,6 +7159,21 @@ impl Api for Client { Ok(GetWorkReleasesResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWorkReleasesResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6095,6 +7250,21 @@ impl Api for Client { Ok(GetWorkRevisionResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(GetWorkRevisionResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6174,6 +7344,21 @@ impl Api for Client { Ok(UpdateWorkResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(UpdateWorkResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; diff --git a/rust/fatcat-api-spec/src/lib.rs b/rust/fatcat-api-spec/src/lib.rs index c54e91ae..16b40999 100644 --- a/rust/fatcat-api-spec/src/lib.rs +++ b/rust/fatcat-api-spec/src/lib.rs @@ -38,6 +38,8 @@ pub enum CreateContainerResponse { CreatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -50,6 +52,8 @@ pub enum CreateContainerBatchResponse { CreatedEntities(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -62,6 +66,8 @@ pub enum DeleteContainerResponse { DeletedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -74,6 +80,8 @@ pub enum DeleteContainerEditResponse { DeletedEdit(models::Success), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -86,6 +94,8 @@ pub enum GetContainerResponse { FoundEntity(models::ContainerEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -98,6 +108,8 @@ pub enum GetContainerEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -110,6 +122,8 @@ pub enum GetContainerHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -122,6 +136,8 @@ pub enum GetContainerRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -134,6 +150,8 @@ pub enum GetContainerRevisionResponse { FoundEntityRevision(models::ContainerEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -146,6 +164,8 @@ pub enum LookupContainerResponse { FoundEntity(models::ContainerEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -158,6 +178,8 @@ pub enum UpdateContainerResponse { UpdatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -170,6 +192,8 @@ pub enum CreateCreatorResponse { CreatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -182,6 +206,8 @@ pub enum CreateCreatorBatchResponse { CreatedEntities(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -194,6 +220,8 @@ pub enum DeleteCreatorResponse { DeletedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -206,6 +234,8 @@ pub enum DeleteCreatorEditResponse { DeletedEdit(models::Success), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -218,6 +248,8 @@ pub enum GetCreatorResponse { FoundEntity(models::CreatorEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -230,6 +262,8 @@ pub enum GetCreatorEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -242,6 +276,8 @@ pub enum GetCreatorHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -254,6 +290,8 @@ pub enum GetCreatorRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -266,6 +304,8 @@ pub enum GetCreatorReleasesResponse { Found(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -278,6 +318,8 @@ pub enum GetCreatorRevisionResponse { FoundEntityRevision(models::CreatorEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -290,6 +332,8 @@ pub enum LookupCreatorResponse { FoundEntity(models::CreatorEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -302,6 +346,8 @@ pub enum UpdateCreatorResponse { UpdatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -392,6 +438,8 @@ pub enum CreateFileResponse { CreatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -404,6 +452,8 @@ pub enum CreateFileBatchResponse { CreatedEntities(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -416,6 +466,8 @@ pub enum DeleteFileResponse { DeletedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -428,6 +480,8 @@ pub enum DeleteFileEditResponse { DeletedEdit(models::Success), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -440,6 +494,8 @@ pub enum GetFileResponse { FoundEntity(models::FileEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -452,6 +508,8 @@ pub enum GetFileEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -464,6 +522,8 @@ pub enum GetFileHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -476,6 +536,8 @@ pub enum GetFileRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -488,6 +550,8 @@ pub enum GetFileRevisionResponse { FoundEntityRevision(models::FileEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -500,6 +564,8 @@ pub enum LookupFileResponse { FoundEntity(models::FileEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -512,6 +578,8 @@ pub enum UpdateFileResponse { UpdatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -524,6 +592,8 @@ pub enum CreateFilesetResponse { CreatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -536,6 +606,8 @@ pub enum CreateFilesetBatchResponse { CreatedEntities(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -548,6 +620,8 @@ pub enum DeleteFilesetResponse { DeletedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -560,6 +634,8 @@ pub enum DeleteFilesetEditResponse { DeletedEdit(models::Success), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -572,6 +648,8 @@ pub enum GetFilesetResponse { FoundEntity(models::FilesetEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -584,6 +662,8 @@ pub enum GetFilesetEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -596,6 +676,8 @@ pub enum GetFilesetHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -608,6 +690,8 @@ pub enum GetFilesetRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -620,6 +704,8 @@ pub enum GetFilesetRevisionResponse { FoundEntityRevision(models::FilesetEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -632,6 +718,8 @@ pub enum UpdateFilesetResponse { UpdatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -644,6 +732,8 @@ pub enum CreateReleaseResponse { CreatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -656,6 +746,8 @@ pub enum CreateReleaseBatchResponse { CreatedEntities(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -668,6 +760,8 @@ pub enum CreateWorkResponse { CreatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -680,6 +774,8 @@ pub enum DeleteReleaseResponse { DeletedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -692,6 +788,8 @@ pub enum DeleteReleaseEditResponse { DeletedEdit(models::Success), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -704,6 +802,8 @@ pub enum GetReleaseResponse { FoundEntity(models::ReleaseEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -716,6 +816,8 @@ pub enum GetReleaseEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -728,6 +830,8 @@ pub enum GetReleaseFilesResponse { Found(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -740,6 +844,8 @@ pub enum GetReleaseFilesetsResponse { Found(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -752,6 +858,8 @@ pub enum GetReleaseHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -764,6 +872,8 @@ pub enum GetReleaseRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -776,6 +886,8 @@ pub enum GetReleaseRevisionResponse { FoundEntityRevision(models::ReleaseEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -788,6 +900,8 @@ pub enum GetReleaseWebcapturesResponse { Found(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -800,6 +914,8 @@ pub enum LookupReleaseResponse { FoundEntity(models::ReleaseEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -812,6 +928,8 @@ pub enum UpdateReleaseResponse { UpdatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -824,6 +942,8 @@ pub enum CreateWebcaptureResponse { CreatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -836,6 +956,8 @@ pub enum CreateWebcaptureBatchResponse { CreatedEntities(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -848,6 +970,8 @@ pub enum DeleteWebcaptureResponse { DeletedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -860,6 +984,8 @@ pub enum DeleteWebcaptureEditResponse { DeletedEdit(models::Success), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -872,6 +998,8 @@ pub enum GetWebcaptureResponse { FoundEntity(models::WebcaptureEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -884,6 +1012,8 @@ pub enum GetWebcaptureEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -896,6 +1026,8 @@ pub enum GetWebcaptureHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -908,6 +1040,8 @@ pub enum GetWebcaptureRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -920,6 +1054,8 @@ pub enum GetWebcaptureRevisionResponse { FoundEntityRevision(models::WebcaptureEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -932,6 +1068,8 @@ pub enum UpdateWebcaptureResponse { UpdatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -944,6 +1082,8 @@ pub enum CreateWorkBatchResponse { CreatedEntities(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -956,6 +1096,8 @@ pub enum DeleteWorkResponse { DeletedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -968,6 +1110,8 @@ pub enum DeleteWorkEditResponse { DeletedEdit(models::Success), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -980,6 +1124,8 @@ pub enum GetWorkResponse { FoundEntity(models::WorkEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -992,6 +1138,8 @@ pub enum GetWorkEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1004,6 +1152,8 @@ pub enum GetWorkHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1016,6 +1166,8 @@ pub enum GetWorkRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1028,6 +1180,8 @@ pub enum GetWorkReleasesResponse { Found(Vec), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1040,6 +1194,8 @@ pub enum GetWorkRevisionResponse { FoundEntityRevision(models::WorkEntity), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1052,6 +1208,8 @@ pub enum UpdateWorkResponse { UpdatedEntity(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error diff --git a/rust/fatcat-api-spec/src/mimetypes.rs b/rust/fatcat-api-spec/src/mimetypes.rs index e0683dbb..772a1066 100644 --- a/rust/fatcat-api-spec/src/mimetypes.rs +++ b/rust/fatcat-api-spec/src/mimetypes.rs @@ -13,6 +13,10 @@ pub mod responses { pub static ref CREATE_CONTAINER_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateContainer + lazy_static! { + pub static ref CREATE_CONTAINER_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateContainer lazy_static! { pub static ref CREATE_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); } @@ -29,6 +33,10 @@ pub mod responses { pub static ref CREATE_CONTAINER_BATCH_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateContainerBatch + lazy_static! { + pub static ref CREATE_CONTAINER_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateContainerBatch lazy_static! { pub static ref CREATE_CONTAINER_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -45,6 +53,10 @@ pub mod responses { pub static ref DELETE_CONTAINER_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteContainer + lazy_static! { + pub static ref DELETE_CONTAINER_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteContainer lazy_static! { pub static ref DELETE_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); } @@ -61,6 +73,10 @@ pub mod responses { pub static ref DELETE_CONTAINER_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteContainerEdit + lazy_static! { + pub static ref DELETE_CONTAINER_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteContainerEdit lazy_static! { pub static ref DELETE_CONTAINER_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -77,6 +93,10 @@ pub mod responses { pub static ref GET_CONTAINER_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetContainer + lazy_static! { + pub static ref GET_CONTAINER_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetContainer lazy_static! { pub static ref GET_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); } @@ -93,6 +113,10 @@ pub mod responses { pub static ref GET_CONTAINER_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetContainerEdit + lazy_static! { + pub static ref GET_CONTAINER_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetContainerEdit lazy_static! { pub static ref GET_CONTAINER_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -109,6 +133,10 @@ pub mod responses { pub static ref GET_CONTAINER_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetContainerHistory + lazy_static! { + pub static ref GET_CONTAINER_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetContainerHistory lazy_static! { pub static ref GET_CONTAINER_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -125,6 +153,10 @@ pub mod responses { pub static ref GET_CONTAINER_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetContainerRedirects + lazy_static! { + pub static ref GET_CONTAINER_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetContainerRedirects lazy_static! { pub static ref GET_CONTAINER_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -141,6 +173,10 @@ pub mod responses { pub static ref GET_CONTAINER_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetContainerRevision + lazy_static! { + pub static ref GET_CONTAINER_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetContainerRevision lazy_static! { pub static ref GET_CONTAINER_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -157,6 +193,10 @@ pub mod responses { pub static ref LOOKUP_CONTAINER_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for LookupContainer + lazy_static! { + pub static ref LOOKUP_CONTAINER_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for LookupContainer lazy_static! { pub static ref LOOKUP_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); } @@ -173,6 +213,10 @@ pub mod responses { pub static ref UPDATE_CONTAINER_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateContainer + lazy_static! { + pub static ref UPDATE_CONTAINER_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateContainer lazy_static! { pub static ref UPDATE_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); } @@ -189,6 +233,10 @@ pub mod responses { pub static ref CREATE_CREATOR_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateCreator + lazy_static! { + pub static ref CREATE_CREATOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateCreator lazy_static! { pub static ref CREATE_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); } @@ -205,6 +253,10 @@ pub mod responses { pub static ref CREATE_CREATOR_BATCH_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateCreatorBatch + lazy_static! { + pub static ref CREATE_CREATOR_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateCreatorBatch lazy_static! { pub static ref CREATE_CREATOR_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -221,6 +273,10 @@ pub mod responses { pub static ref DELETE_CREATOR_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteCreator + lazy_static! { + pub static ref DELETE_CREATOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteCreator lazy_static! { pub static ref DELETE_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); } @@ -237,6 +293,10 @@ pub mod responses { pub static ref DELETE_CREATOR_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteCreatorEdit + lazy_static! { + pub static ref DELETE_CREATOR_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteCreatorEdit lazy_static! { pub static ref DELETE_CREATOR_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -253,6 +313,10 @@ pub mod responses { pub static ref GET_CREATOR_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreator + lazy_static! { + pub static ref GET_CREATOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetCreator lazy_static! { pub static ref GET_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); } @@ -269,6 +333,10 @@ pub mod responses { pub static ref GET_CREATOR_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreatorEdit + lazy_static! { + pub static ref GET_CREATOR_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetCreatorEdit lazy_static! { pub static ref GET_CREATOR_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -285,6 +353,10 @@ pub mod responses { pub static ref GET_CREATOR_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreatorHistory + lazy_static! { + pub static ref GET_CREATOR_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetCreatorHistory lazy_static! { pub static ref GET_CREATOR_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -301,6 +373,10 @@ pub mod responses { pub static ref GET_CREATOR_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreatorRedirects + lazy_static! { + pub static ref GET_CREATOR_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetCreatorRedirects lazy_static! { pub static ref GET_CREATOR_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -317,6 +393,10 @@ pub mod responses { pub static ref GET_CREATOR_RELEASES_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreatorReleases + lazy_static! { + pub static ref GET_CREATOR_RELEASES_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetCreatorReleases lazy_static! { pub static ref GET_CREATOR_RELEASES_NOT_FOUND: Mime = mime!(Application / Json); } @@ -333,6 +413,10 @@ pub mod responses { pub static ref GET_CREATOR_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreatorRevision + lazy_static! { + pub static ref GET_CREATOR_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetCreatorRevision lazy_static! { pub static ref GET_CREATOR_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -349,6 +433,10 @@ pub mod responses { pub static ref LOOKUP_CREATOR_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for LookupCreator + lazy_static! { + pub static ref LOOKUP_CREATOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for LookupCreator lazy_static! { pub static ref LOOKUP_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); } @@ -365,6 +453,10 @@ pub mod responses { pub static ref UPDATE_CREATOR_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateCreator + lazy_static! { + pub static ref UPDATE_CREATOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateCreator lazy_static! { pub static ref UPDATE_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); } @@ -481,6 +573,10 @@ pub mod responses { pub static ref CREATE_FILE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateFile + lazy_static! { + pub static ref CREATE_FILE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateFile lazy_static! { pub static ref CREATE_FILE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -497,6 +593,10 @@ pub mod responses { pub static ref CREATE_FILE_BATCH_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateFileBatch + lazy_static! { + pub static ref CREATE_FILE_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateFileBatch lazy_static! { pub static ref CREATE_FILE_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -513,6 +613,10 @@ pub mod responses { pub static ref DELETE_FILE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteFile + lazy_static! { + pub static ref DELETE_FILE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFile lazy_static! { pub static ref DELETE_FILE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -529,6 +633,10 @@ pub mod responses { pub static ref DELETE_FILE_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteFileEdit + lazy_static! { + pub static ref DELETE_FILE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFileEdit lazy_static! { pub static ref DELETE_FILE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -545,6 +653,10 @@ pub mod responses { pub static ref GET_FILE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFile + lazy_static! { + pub static ref GET_FILE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetFile lazy_static! { pub static ref GET_FILE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -561,6 +673,10 @@ pub mod responses { pub static ref GET_FILE_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFileEdit + lazy_static! { + pub static ref GET_FILE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetFileEdit lazy_static! { pub static ref GET_FILE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -577,6 +693,10 @@ pub mod responses { pub static ref GET_FILE_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFileHistory + lazy_static! { + pub static ref GET_FILE_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetFileHistory lazy_static! { pub static ref GET_FILE_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -593,6 +713,10 @@ pub mod responses { pub static ref GET_FILE_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFileRedirects + lazy_static! { + pub static ref GET_FILE_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetFileRedirects lazy_static! { pub static ref GET_FILE_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -609,6 +733,10 @@ pub mod responses { pub static ref GET_FILE_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFileRevision + lazy_static! { + pub static ref GET_FILE_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetFileRevision lazy_static! { pub static ref GET_FILE_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -625,6 +753,10 @@ pub mod responses { pub static ref LOOKUP_FILE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for LookupFile + lazy_static! { + pub static ref LOOKUP_FILE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for LookupFile lazy_static! { pub static ref LOOKUP_FILE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -641,6 +773,10 @@ pub mod responses { pub static ref UPDATE_FILE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateFile + lazy_static! { + pub static ref UPDATE_FILE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateFile lazy_static! { pub static ref UPDATE_FILE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -657,6 +793,10 @@ pub mod responses { pub static ref CREATE_FILESET_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateFileset + lazy_static! { + pub static ref CREATE_FILESET_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateFileset lazy_static! { pub static ref CREATE_FILESET_NOT_FOUND: Mime = mime!(Application / Json); } @@ -673,6 +813,10 @@ pub mod responses { pub static ref CREATE_FILESET_BATCH_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateFilesetBatch + lazy_static! { + pub static ref CREATE_FILESET_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateFilesetBatch lazy_static! { pub static ref CREATE_FILESET_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -689,6 +833,10 @@ pub mod responses { pub static ref DELETE_FILESET_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteFileset + lazy_static! { + pub static ref DELETE_FILESET_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFileset lazy_static! { pub static ref DELETE_FILESET_NOT_FOUND: Mime = mime!(Application / Json); } @@ -705,6 +853,10 @@ pub mod responses { pub static ref DELETE_FILESET_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteFilesetEdit + lazy_static! { + pub static ref DELETE_FILESET_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFilesetEdit lazy_static! { pub static ref DELETE_FILESET_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -721,6 +873,10 @@ pub mod responses { pub static ref GET_FILESET_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFileset + lazy_static! { + pub static ref GET_FILESET_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetFileset lazy_static! { pub static ref GET_FILESET_NOT_FOUND: Mime = mime!(Application / Json); } @@ -737,6 +893,10 @@ pub mod responses { pub static ref GET_FILESET_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFilesetEdit + lazy_static! { + pub static ref GET_FILESET_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetFilesetEdit lazy_static! { pub static ref GET_FILESET_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -753,6 +913,10 @@ pub mod responses { pub static ref GET_FILESET_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFilesetHistory + lazy_static! { + pub static ref GET_FILESET_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetFilesetHistory lazy_static! { pub static ref GET_FILESET_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -769,6 +933,10 @@ pub mod responses { pub static ref GET_FILESET_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFilesetRedirects + lazy_static! { + pub static ref GET_FILESET_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetFilesetRedirects lazy_static! { pub static ref GET_FILESET_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -785,6 +953,10 @@ pub mod responses { pub static ref GET_FILESET_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFilesetRevision + lazy_static! { + pub static ref GET_FILESET_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetFilesetRevision lazy_static! { pub static ref GET_FILESET_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -801,6 +973,10 @@ pub mod responses { pub static ref UPDATE_FILESET_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateFileset + lazy_static! { + pub static ref UPDATE_FILESET_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateFileset lazy_static! { pub static ref UPDATE_FILESET_NOT_FOUND: Mime = mime!(Application / Json); } @@ -817,6 +993,10 @@ pub mod responses { pub static ref CREATE_RELEASE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateRelease + lazy_static! { + pub static ref CREATE_RELEASE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateRelease lazy_static! { pub static ref CREATE_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -833,6 +1013,10 @@ pub mod responses { pub static ref CREATE_RELEASE_BATCH_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateReleaseBatch + lazy_static! { + pub static ref CREATE_RELEASE_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateReleaseBatch lazy_static! { pub static ref CREATE_RELEASE_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -849,6 +1033,10 @@ pub mod responses { pub static ref CREATE_WORK_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateWork + lazy_static! { + pub static ref CREATE_WORK_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWork lazy_static! { pub static ref CREATE_WORK_NOT_FOUND: Mime = mime!(Application / Json); } @@ -865,6 +1053,10 @@ pub mod responses { pub static ref DELETE_RELEASE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteRelease + lazy_static! { + pub static ref DELETE_RELEASE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteRelease lazy_static! { pub static ref DELETE_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -881,6 +1073,10 @@ pub mod responses { pub static ref DELETE_RELEASE_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteReleaseEdit + lazy_static! { + pub static ref DELETE_RELEASE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteReleaseEdit lazy_static! { pub static ref DELETE_RELEASE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -897,6 +1093,10 @@ pub mod responses { pub static ref GET_RELEASE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetRelease + lazy_static! { + pub static ref GET_RELEASE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetRelease lazy_static! { pub static ref GET_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -913,6 +1113,10 @@ pub mod responses { pub static ref GET_RELEASE_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseEdit + lazy_static! { + pub static ref GET_RELEASE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetReleaseEdit lazy_static! { pub static ref GET_RELEASE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -929,6 +1133,10 @@ pub mod responses { pub static ref GET_RELEASE_FILES_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseFiles + lazy_static! { + pub static ref GET_RELEASE_FILES_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetReleaseFiles lazy_static! { pub static ref GET_RELEASE_FILES_NOT_FOUND: Mime = mime!(Application / Json); } @@ -945,6 +1153,10 @@ pub mod responses { pub static ref GET_RELEASE_FILESETS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseFilesets + lazy_static! { + pub static ref GET_RELEASE_FILESETS_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetReleaseFilesets lazy_static! { pub static ref GET_RELEASE_FILESETS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -961,6 +1173,10 @@ pub mod responses { pub static ref GET_RELEASE_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseHistory + lazy_static! { + pub static ref GET_RELEASE_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetReleaseHistory lazy_static! { pub static ref GET_RELEASE_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -977,6 +1193,10 @@ pub mod responses { pub static ref GET_RELEASE_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseRedirects + lazy_static! { + pub static ref GET_RELEASE_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetReleaseRedirects lazy_static! { pub static ref GET_RELEASE_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -993,6 +1213,10 @@ pub mod responses { pub static ref GET_RELEASE_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseRevision + lazy_static! { + pub static ref GET_RELEASE_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetReleaseRevision lazy_static! { pub static ref GET_RELEASE_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1009,6 +1233,10 @@ pub mod responses { pub static ref GET_RELEASE_WEBCAPTURES_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseWebcaptures + lazy_static! { + pub static ref GET_RELEASE_WEBCAPTURES_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetReleaseWebcaptures lazy_static! { pub static ref GET_RELEASE_WEBCAPTURES_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1025,6 +1253,10 @@ pub mod responses { pub static ref LOOKUP_RELEASE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for LookupRelease + lazy_static! { + pub static ref LOOKUP_RELEASE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for LookupRelease lazy_static! { pub static ref LOOKUP_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1041,6 +1273,10 @@ pub mod responses { pub static ref UPDATE_RELEASE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateRelease + lazy_static! { + pub static ref UPDATE_RELEASE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateRelease lazy_static! { pub static ref UPDATE_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1057,6 +1293,10 @@ pub mod responses { pub static ref CREATE_WEBCAPTURE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateWebcapture + lazy_static! { + pub static ref CREATE_WEBCAPTURE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWebcapture lazy_static! { pub static ref CREATE_WEBCAPTURE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1073,6 +1313,10 @@ pub mod responses { pub static ref CREATE_WEBCAPTURE_BATCH_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateWebcaptureBatch + lazy_static! { + pub static ref CREATE_WEBCAPTURE_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWebcaptureBatch lazy_static! { pub static ref CREATE_WEBCAPTURE_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1089,6 +1333,10 @@ pub mod responses { pub static ref DELETE_WEBCAPTURE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteWebcapture + lazy_static! { + pub static ref DELETE_WEBCAPTURE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWebcapture lazy_static! { pub static ref DELETE_WEBCAPTURE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1105,6 +1353,10 @@ pub mod responses { pub static ref DELETE_WEBCAPTURE_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteWebcaptureEdit + lazy_static! { + pub static ref DELETE_WEBCAPTURE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWebcaptureEdit lazy_static! { pub static ref DELETE_WEBCAPTURE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1121,6 +1373,10 @@ pub mod responses { pub static ref GET_WEBCAPTURE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWebcapture + lazy_static! { + pub static ref GET_WEBCAPTURE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWebcapture lazy_static! { pub static ref GET_WEBCAPTURE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1137,6 +1393,10 @@ pub mod responses { pub static ref GET_WEBCAPTURE_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWebcaptureEdit + lazy_static! { + pub static ref GET_WEBCAPTURE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWebcaptureEdit lazy_static! { pub static ref GET_WEBCAPTURE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1153,6 +1413,10 @@ pub mod responses { pub static ref GET_WEBCAPTURE_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWebcaptureHistory + lazy_static! { + pub static ref GET_WEBCAPTURE_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWebcaptureHistory lazy_static! { pub static ref GET_WEBCAPTURE_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1169,6 +1433,10 @@ pub mod responses { pub static ref GET_WEBCAPTURE_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWebcaptureRedirects + lazy_static! { + pub static ref GET_WEBCAPTURE_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWebcaptureRedirects lazy_static! { pub static ref GET_WEBCAPTURE_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1185,6 +1453,10 @@ pub mod responses { pub static ref GET_WEBCAPTURE_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWebcaptureRevision + lazy_static! { + pub static ref GET_WEBCAPTURE_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWebcaptureRevision lazy_static! { pub static ref GET_WEBCAPTURE_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1201,6 +1473,10 @@ pub mod responses { pub static ref UPDATE_WEBCAPTURE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateWebcapture + lazy_static! { + pub static ref UPDATE_WEBCAPTURE_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateWebcapture lazy_static! { pub static ref UPDATE_WEBCAPTURE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1217,6 +1493,10 @@ pub mod responses { pub static ref CREATE_WORK_BATCH_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateWorkBatch + lazy_static! { + pub static ref CREATE_WORK_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWorkBatch lazy_static! { pub static ref CREATE_WORK_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1233,6 +1513,10 @@ pub mod responses { pub static ref DELETE_WORK_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteWork + lazy_static! { + pub static ref DELETE_WORK_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWork lazy_static! { pub static ref DELETE_WORK_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1249,6 +1533,10 @@ pub mod responses { pub static ref DELETE_WORK_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteWorkEdit + lazy_static! { + pub static ref DELETE_WORK_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWorkEdit lazy_static! { pub static ref DELETE_WORK_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1265,6 +1553,10 @@ pub mod responses { pub static ref GET_WORK_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWork + lazy_static! { + pub static ref GET_WORK_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWork lazy_static! { pub static ref GET_WORK_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1281,6 +1573,10 @@ pub mod responses { pub static ref GET_WORK_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWorkEdit + lazy_static! { + pub static ref GET_WORK_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWorkEdit lazy_static! { pub static ref GET_WORK_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1297,6 +1593,10 @@ pub mod responses { pub static ref GET_WORK_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWorkHistory + lazy_static! { + pub static ref GET_WORK_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWorkHistory lazy_static! { pub static ref GET_WORK_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1313,6 +1613,10 @@ pub mod responses { pub static ref GET_WORK_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWorkRedirects + lazy_static! { + pub static ref GET_WORK_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWorkRedirects lazy_static! { pub static ref GET_WORK_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1329,6 +1633,10 @@ pub mod responses { pub static ref GET_WORK_RELEASES_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWorkReleases + lazy_static! { + pub static ref GET_WORK_RELEASES_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWorkReleases lazy_static! { pub static ref GET_WORK_RELEASES_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1345,6 +1653,10 @@ pub mod responses { pub static ref GET_WORK_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWorkRevision + lazy_static! { + pub static ref GET_WORK_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetWorkRevision lazy_static! { pub static ref GET_WORK_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1361,6 +1673,10 @@ pub mod responses { pub static ref UPDATE_WORK_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateWork + lazy_static! { + pub static ref UPDATE_WORK_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateWork lazy_static! { pub static ref UPDATE_WORK_NOT_FOUND: Mime = mime!(Application / Json); } diff --git a/rust/fatcat-api-spec/src/server.rs b/rust/fatcat-api-spec/src/server.rs index 0576bfc7..076652bb 100644 --- a/rust/fatcat-api-spec/src/server.rs +++ b/rust/fatcat-api-spec/src/server.rs @@ -111,6 +111,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -166,6 +168,21 @@ where } Ok(response) } + CreateContainerResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_CONTAINER_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateContainerResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -222,6 +239,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -278,6 +297,21 @@ where } Ok(response) } + CreateContainerBatchResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_CONTAINER_BATCH_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateContainerBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -334,6 +368,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -375,6 +411,19 @@ where Ok(response) } + DeleteContainerResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_CONTAINER_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteContainerResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -464,6 +513,19 @@ where Ok(response) } + DeleteContainerEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_CONTAINER_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteContainerEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -558,6 +620,19 @@ where Ok(response) } + GetContainerResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetContainerResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -647,6 +722,19 @@ where Ok(response) } + GetContainerEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetContainerEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -740,6 +828,19 @@ where Ok(response) } + GetContainerHistoryResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_HISTORY_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetContainerHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -829,6 +930,19 @@ where Ok(response) } + GetContainerRedirectsResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_REDIRECTS_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetContainerRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -923,6 +1037,19 @@ where Ok(response) } + GetContainerRevisionResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_REVISION_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetContainerRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1004,6 +1131,19 @@ where Ok(response) } + LookupContainerResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::LOOKUP_CONTAINER_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } LookupContainerResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1056,6 +1196,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -1126,6 +1268,21 @@ where } Ok(response) } + UpdateContainerResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::UPDATE_CONTAINER_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateContainerResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1182,6 +1339,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -1237,6 +1396,21 @@ where } Ok(response) } + CreateCreatorResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_CREATOR_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateCreatorResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1293,6 +1467,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -1349,6 +1525,21 @@ where } Ok(response) } + CreateCreatorBatchResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_CREATOR_BATCH_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateCreatorBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1405,6 +1596,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -1446,6 +1639,19 @@ where Ok(response) } + DeleteCreatorResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_CREATOR_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteCreatorResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1535,6 +1741,19 @@ where Ok(response) } + DeleteCreatorEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_CREATOR_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteCreatorEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1629,6 +1848,19 @@ where Ok(response) } + GetCreatorResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetCreatorResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1718,6 +1950,19 @@ where Ok(response) } + GetCreatorEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetCreatorEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1811,6 +2056,19 @@ where Ok(response) } + GetCreatorHistoryResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_HISTORY_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetCreatorHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1900,6 +2158,19 @@ where Ok(response) } + GetCreatorRedirectsResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_REDIRECTS_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetCreatorRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1993,6 +2264,19 @@ where Ok(response) } + GetCreatorReleasesResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_RELEASES_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetCreatorReleasesResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2087,6 +2371,19 @@ where Ok(response) } + GetCreatorRevisionResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_REVISION_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetCreatorRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2168,6 +2465,19 @@ where Ok(response) } + LookupCreatorResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::LOOKUP_CREATOR_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } LookupCreatorResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2220,6 +2530,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -2290,6 +2602,21 @@ where } Ok(response) } + UpdateCreatorResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::UPDATE_CREATOR_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateCreatorResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2944,6 +3271,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -2999,6 +3328,21 @@ where } Ok(response) } + CreateFileResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_FILE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateFileResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3055,6 +3399,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -3111,6 +3457,21 @@ where } Ok(response) } + CreateFileBatchResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_FILE_BATCH_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateFileBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3167,6 +3528,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -3208,6 +3571,19 @@ where Ok(response) } + DeleteFileResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_FILE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteFileResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3297,6 +3673,19 @@ where Ok(response) } + DeleteFileEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_FILE_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteFileEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3391,6 +3780,19 @@ where Ok(response) } + GetFileResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_FILE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetFileResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3480,17 +3882,30 @@ where Ok(response) } - GetFileEditResponse::NotFound(body) => { + GetFileEditResponse::NotAuthorized { body, www_authenticate } => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_FILE_EDIT_NOT_FOUND.clone())); + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_FILE_EDIT_NOT_AUTHORIZED.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetFileEditResponse::GenericError(body) => { + GetFileEditResponse::NotFound(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(404), body_string)); + response.headers.set(ContentType(mimetypes::responses::GET_FILE_EDIT_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetFileEditResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); @@ -3573,6 +3988,19 @@ where Ok(response) } + GetFileHistoryResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetFileHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3662,6 +4090,19 @@ where Ok(response) } + GetFileRedirectsResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_FILE_REDIRECTS_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetFileRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3756,6 +4197,19 @@ where Ok(response) } + GetFileRevisionResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_FILE_REVISION_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetFileRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3838,6 +4292,19 @@ where Ok(response) } + LookupFileResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::LOOKUP_FILE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } LookupFileResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3890,6 +4357,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -3960,6 +4429,21 @@ where } Ok(response) } + UpdateFileResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::UPDATE_FILE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateFileResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4071,6 +4555,21 @@ where } Ok(response) } + CreateFilesetResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_FILESET_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateFilesetResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4183,6 +4682,21 @@ where } Ok(response) } + CreateFilesetBatchResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_FILESET_BATCH_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateFilesetBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4280,6 +4794,19 @@ where Ok(response) } + DeleteFilesetResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_FILESET_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteFilesetResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4369,6 +4896,19 @@ where Ok(response) } + DeleteFilesetEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_FILESET_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteFilesetEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4463,6 +5003,19 @@ where Ok(response) } + GetFilesetResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_FILESET_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetFilesetResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4552,6 +5105,19 @@ where Ok(response) } + GetFilesetEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_FILESET_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetFilesetEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4645,6 +5211,19 @@ where Ok(response) } + GetFilesetHistoryResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_FILESET_HISTORY_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetFilesetHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4734,6 +5313,19 @@ where Ok(response) } + GetFilesetRedirectsResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_FILESET_REDIRECTS_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetFilesetRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4828,6 +5420,19 @@ where Ok(response) } + GetFilesetRevisionResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_FILESET_REVISION_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetFilesetRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4950,6 +5555,21 @@ where } Ok(response) } + UpdateFilesetResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::UPDATE_FILESET_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateFilesetResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5061,6 +5681,21 @@ where } Ok(response) } + CreateReleaseResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_RELEASE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5173,6 +5808,21 @@ where } Ok(response) } + CreateReleaseBatchResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_RELEASE_BATCH_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateReleaseBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5284,6 +5934,21 @@ where } Ok(response) } + CreateWorkResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateWorkResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5381,6 +6046,19 @@ where Ok(response) } + DeleteReleaseResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_RELEASE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5470,6 +6148,19 @@ where Ok(response) } + DeleteReleaseEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_RELEASE_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteReleaseEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5564,6 +6255,19 @@ where Ok(response) } + GetReleaseResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5653,6 +6357,19 @@ where Ok(response) } + GetReleaseEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetReleaseEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5746,6 +6463,19 @@ where Ok(response) } + GetReleaseFilesResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILES_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetReleaseFilesResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5839,6 +6569,19 @@ where Ok(response) } + GetReleaseFilesetsResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILESETS_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetReleaseFilesetsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5932,6 +6675,19 @@ where Ok(response) } + GetReleaseHistoryResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetReleaseHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6021,6 +6777,19 @@ where Ok(response) } + GetReleaseRedirectsResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_REDIRECTS_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetReleaseRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6115,6 +6884,19 @@ where Ok(response) } + GetReleaseRevisionResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_REVISION_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetReleaseRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6208,6 +6990,19 @@ where Ok(response) } + GetReleaseWebcapturesResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_WEBCAPTURES_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetReleaseWebcapturesResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6296,6 +7091,19 @@ where Ok(response) } + LookupReleaseResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::LOOKUP_RELEASE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } LookupReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6418,6 +7226,21 @@ where } Ok(response) } + UpdateReleaseResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::UPDATE_RELEASE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6529,6 +7352,21 @@ where } Ok(response) } + CreateWebcaptureResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_WEBCAPTURE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateWebcaptureResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6641,6 +7479,21 @@ where } Ok(response) } + CreateWebcaptureBatchResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_WEBCAPTURE_BATCH_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateWebcaptureBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6738,6 +7591,19 @@ where Ok(response) } + DeleteWebcaptureResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_WEBCAPTURE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteWebcaptureResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6827,6 +7693,19 @@ where Ok(response) } + DeleteWebcaptureEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_WEBCAPTURE_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteWebcaptureEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6921,6 +7800,19 @@ where Ok(response) } + GetWebcaptureResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WEBCAPTURE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWebcaptureResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7010,6 +7902,19 @@ where Ok(response) } + GetWebcaptureEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WEBCAPTURE_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWebcaptureEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7103,6 +8008,19 @@ where Ok(response) } + GetWebcaptureHistoryResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WEBCAPTURE_HISTORY_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWebcaptureHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7192,6 +8110,19 @@ where Ok(response) } + GetWebcaptureRedirectsResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WEBCAPTURE_REDIRECTS_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWebcaptureRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7286,6 +8217,19 @@ where Ok(response) } + GetWebcaptureRevisionResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WEBCAPTURE_REVISION_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWebcaptureRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7408,6 +8352,21 @@ where } Ok(response) } + UpdateWebcaptureResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::UPDATE_WEBCAPTURE_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateWebcaptureResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7520,6 +8479,21 @@ where } Ok(response) } + CreateWorkBatchResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_BATCH_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateWorkBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7617,6 +8591,19 @@ where Ok(response) } + DeleteWorkResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_WORK_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteWorkResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7706,6 +8693,19 @@ where Ok(response) } + DeleteWorkEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::DELETE_WORK_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteWorkEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7800,6 +8800,19 @@ where Ok(response) } + GetWorkResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WORK_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWorkResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7889,6 +8902,19 @@ where Ok(response) } + GetWorkEditResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WORK_EDIT_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWorkEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7982,6 +9008,19 @@ where Ok(response) } + GetWorkHistoryResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWorkHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8071,6 +9110,19 @@ where Ok(response) } + GetWorkRedirectsResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WORK_REDIRECTS_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWorkRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8164,6 +9216,19 @@ where Ok(response) } + GetWorkReleasesResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWorkReleasesResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8258,6 +9323,19 @@ where Ok(response) } + GetWorkRevisionResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_WORK_REVISION_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } GetWorkRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8380,6 +9458,21 @@ where } Ok(response) } + UpdateWorkResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::UPDATE_WORK_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateWorkResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8427,6 +9520,14 @@ pub struct ExtractAuthData; impl BeforeMiddleware for ExtractAuthData { fn before(&self, req: &mut Request) -> IronResult<()> { + { + header! { (ApiKey1, "Authorization") => [String] } + if let Some(header) = req.headers.get::() { + req.extensions.insert::(AuthData::ApiKey(header.0.clone())); + return Ok(()); + } + } + Ok(()) } } -- cgit v1.2.3 From 06345b2c1ba39cf67a4bee8cfc76ebea4c5ad1a9 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 18 Sep 2018 11:13:08 -0700 Subject: first attempt at auth in DB schema --- rust/migrations/2018-05-12-001226_init/up.sql | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index 22f5cca6..c6444b8e 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -16,9 +16,12 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE TABLE editor ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - username TEXT NOT NULL UNIQUE, + username TEXT NOT NULL UNIQUE, -- TODO: alphanum and length constraints? is_admin BOOLEAN NOT NULL DEFAULT false, + is_bot BOOLEAN NOT NULL DEFAULT false, registered TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, + auth_epoch TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, + wrangler_id UUID REFERENCES editor(id), active_editgroup_id UUID -- REFERENCES( editgroup(id) via ALTER below ); -- cgit v1.2.3 From 6a8d793eef101e72dbe44f94c30cbf5e6be75aeb Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 18 Sep 2018 11:14:17 -0700 Subject: add macaroon dep Unfortunately, a patched copy for now. :( --- rust/Cargo.lock | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rust/Cargo.toml | 1 + 2 files changed, 96 insertions(+) (limited to 'rust') diff --git a/rust/Cargo.lock b/rust/Cargo.lock index a69f3d04..17f51d70 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -378,6 +378,7 @@ dependencies = [ "iron-test 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "macaroon 0.1.1 (git+https://github.com/bnewbold/libmacaroon-rs?branch=bnewbold-stable-rust)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -563,6 +564,11 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itoa" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "itoa" version = "0.4.1" @@ -597,6 +603,15 @@ name = "libc" version = "0.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libsodium-sys" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lock_api" version = "0.1.3" @@ -622,6 +637,19 @@ dependencies = [ "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "macaroon" +version = "0.1.1" +source = "git+https://github.com/bnewbold/libmacaroon-rs?branch=bnewbold-stable-rust#22bb19d70366f34fb32227d5ba311d4a4388d274" +dependencies = [ + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "sodiumoxide 0.0.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "matches" version = "0.1.6" @@ -741,6 +769,14 @@ dependencies = [ "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-traits" version = "0.2.4" @@ -1074,11 +1110,39 @@ name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "serde" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "serde_codegen_internals" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen_internals 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_derive" version = "1.0.55" @@ -1097,6 +1161,17 @@ dependencies = [ "serde 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_json" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_json" version = "1.0.17" @@ -1152,6 +1227,16 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sodiumoxide" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libsodium-sys 0.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "stable_deref_trait" version = "1.1.1" @@ -1546,15 +1631,18 @@ dependencies = [ "checksum iron-slog 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "41941d50d2c936a4c609f457ae8821f9888aa6ed8641f5d6e5d9b22e15041255" "checksum iron-test 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1944bcf30f8b3f51ebf01e715517dd9755e9480934778d6de70179a41d283c1" "checksum isatty 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a118a53ba42790ef25c82bb481ecf36e2da892646cccd361e69a6bb881e19398" +"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" "checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" +"checksum libsodium-sys 0.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "8e92532ef19ec2da77f5a89ae63a5c3dbb5136e8dada4e2c278107c1e1c773d8" "checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" +"checksum macaroon 0.1.1 (git+https://github.com/bnewbold/libmacaroon-rs?branch=bnewbold-stable-rust)" = "" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" @@ -1569,6 +1657,7 @@ dependencies = [ "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac0ea58d64a89d9d6b7688031b3be9358d6c919badcf7fbb0527ccfd891ee45" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985" @@ -1611,9 +1700,14 @@ dependencies = [ "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" +"checksum serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" "checksum serde 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "97f6a6c3caba0cf8f883b53331791036404ce3c1bd895961cf8bb2f8cecfd84b" +"checksum serde_codegen_internals 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bc888bd283bd2420b16ad0d860e35ad8acb21941180a83a189bb2046f9d00400" +"checksum serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)" = "978fd866f4d4872084a81ccc35e275158351d3b9fe620074e7d7504b816b74ba" "checksum serde_derive 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "f51b0ef935cf8a41a77bce553da1f8751a739b7ad82dd73669475a22e6ecedb0" "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" +"checksum serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ad8bcf487be7d2e15d3d543f04312de991d631cfe1b43ea0ade69e6a8a5b16a1" "checksum serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ad6d546e765177cf3dded3c2e424a8040f870083a0e64064746b958ece9cb1" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" @@ -1621,6 +1715,7 @@ dependencies = [ "checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" "checksum slog-term 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5951a808c40f419922ee014c15b6ae1cd34d963538b57d8a4778b9ca3fff1e0b" "checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" +"checksum sodiumoxide 0.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1fa64a17d98ec77bc7251c59a486e555b3813e32fb53ed608880f82e24ef6bd0" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum swagger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "190ef0c6327759d0beb76d969b236fa3cc42469f9e107f626bbcc152727b4d12" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index f9a439db..03fc4814 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -21,6 +21,7 @@ data-encoding = "2.1" regex = "1" lazy_static = "1.0" sha1 = { version = "0.6", features = ["std"] } +macaroon = { git = "https://github.com/bnewbold/libmacaroon-rs", branch = "bnewbold-stable-rust" } # API server chrono = { version = "0.4", features = ["serde"] } -- cgit v1.2.3 From 802bafc92160205a2a3068b7b780a6a5eeb331d9 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 18 Sep 2018 11:38:34 -0700 Subject: start skeleton of auth internal bits --- rust/src/auth.rs | 106 ++++++++++++++++++++++++++++++++++++++++++ rust/src/bin/fatcat-auth.rs | 109 ++++++++++++++++++++++++++++++++++++++++++++ rust/src/bin/fatcatd.rs | 12 ++--- rust/src/lib.rs | 4 +- 4 files changed, 222 insertions(+), 9 deletions(-) create mode 100644 rust/src/auth.rs create mode 100644 rust/src/bin/fatcat-auth.rs (limited to 'rust') diff --git a/rust/src/auth.rs b/rust/src/auth.rs new file mode 100644 index 00000000..651f7979 --- /dev/null +++ b/rust/src/auth.rs @@ -0,0 +1,106 @@ +//! Editor bearer token authentication + +use swagger::auth::{AuthData, Authorization, Scopes}; +//use macaroon::{Macaroon, Verifier}; + +use std::collections::BTreeSet; +//use database_models::*; +//use database_schema::*; +use api_helpers::*; +use chrono; +//use diesel; +use iron; +//use diesel::prelude::*; +use errors::*; +//use serde_json; +//use std::str::FromStr; +//use uuid::Uuid; + +#[derive(Debug)] +pub struct OpenAuthMiddleware; + +impl OpenAuthMiddleware { + /// Create a middleware that authorizes with the configured subject. + pub fn new() -> OpenAuthMiddleware { + OpenAuthMiddleware + } +} +impl iron::middleware::BeforeMiddleware for OpenAuthMiddleware { + fn before(&self, req: &mut iron::Request) -> iron::IronResult<()> { + req.extensions.insert::(Authorization { + subject: "undefined".to_string(), + scopes: Scopes::All, + issuer: None, + }); + Ok(()) + } +} + +#[derive(Debug)] +pub struct MacaroonAuthMiddleware; + +impl MacaroonAuthMiddleware { + + pub fn new() -> MacaroonAuthMiddleware { + MacaroonAuthMiddleware + } +} + +impl iron::middleware::BeforeMiddleware for MacaroonAuthMiddleware { + fn before(&self, req: &mut iron::Request) -> iron::IronResult<()> { + + let res: Option<(String, Vec)> = match req.extensions.get::() { + Some(AuthData::ApiKey(header)) => { + let header: Vec = header.split_whitespace().map(|s| s.to_string()).collect(); + // TODO: error types + assert!(header.len() == 2); + assert!(header[0] == "Bearer"); + parse_macaroon_token(&header[1]).expect("valid macaroon") + }, + None => None, + _ => panic!("valid auth header, or none") + }; + if let Some((editor_id, scopes)) = res { + let mut scope_set = BTreeSet::new(); + for s in scopes { + scope_set.insert(s); + } + req.extensions.insert::(Authorization { + subject: editor_id, + scopes: Scopes::Some(scope_set), + issuer: None, + }); + }; + Ok(()) + } +} + +// DUMMY: parse macaroon +pub fn parse_macaroon_token(s: &str) -> Result)>> { + Ok(Some(("some_editor_id".to_string(), vec![]))) +} + +pub fn print_editors() -> Result<()>{ + unimplemented!(); + // iterate over all editors. format id, print flags, auth_epoch +} + +pub fn create_editor(username: String, is_admin: bool, is_bot: bool) -> Result<()> { // TODO: EditorRow or something + unimplemented!(); +} + +pub fn create_token(editor_id: FatCatId, expires: Option) -> Result { + unimplemented!(); +} + +pub fn inspect_token(token: &str) -> Result<()> { + unimplemented!(); +} + +pub fn revoke_tokens(editor_id: FatCatId) -> Result<()>{ + unimplemented!(); +} + +pub fn revoke_tokens_everyone() -> Result { + unimplemented!(); +} diff --git a/rust/src/bin/fatcat-auth.rs b/rust/src/bin/fatcat-auth.rs new file mode 100644 index 00000000..7cb8af8e --- /dev/null +++ b/rust/src/bin/fatcat-auth.rs @@ -0,0 +1,109 @@ +//! JSON Export Helper + +#[macro_use] +extern crate clap; +extern crate dotenv; +#[macro_use] +extern crate error_chain; +extern crate fatcat; +#[macro_use] +extern crate log; +extern crate env_logger; +extern crate serde_json; +extern crate uuid; + +use clap::{App, Arg, SubCommand}; +use dotenv::dotenv; +use std::env; + +use fatcat::errors::*; +use fatcat::api_helpers::FatCatId; +use std::str::FromStr; +use uuid::Uuid; + +use error_chain::ChainedError; +//use std::io::{Stdout,StdoutLock}; +use std::io::prelude::*; +use std::io::{BufReader, BufWriter}; + + +fn run() -> Result<()> { + let m = App::new("fatcat-auth") + .version(env!("CARGO_PKG_VERSION")) + .author("Bryan Newbold ") + .about("Editor authentication admin tool") + .subcommand( + SubCommand::with_name("list-editors") + .about("Prints all currently registered editors") + ) + .subcommand( + SubCommand::with_name("create-editor") + .about("Creates a new auth token (macaroon) for the given editor") + .args_from_usage( + " 'username for editor' + --admin 'creates editor with admin privs' + --bot 'this editor is a bot'" + ) + ) + .subcommand( + SubCommand::with_name("create-token") + .about("Creates a new auth token (macaroon) for the given editor") + .args_from_usage( + " 'id of the editor (fatcatid, not username)' + --env-format 'outputs in a format that shells can source'" + ) + ) + .subcommand( + SubCommand::with_name("inspect-token") + .about("Dumps token metadata (and whether it is valid)") + ) + .subcommand( + SubCommand::with_name("revoke-tokens") + .about("Resets auth_epoch for a single editor (invalidating all existing tokens)") + ) + .subcommand( + SubCommand::with_name("revoke-tokens-all") + .about("Resets auth_epoch for all editors (invalidating tokens for all users!)") + ) + .get_matches(); + +/* + value_t_or_exit!(subm, "magic", u32) + .after_help("Reads a ident table TSV dump from stdin (aka, ident_id, rev_id, redirect_id), \ + and outputs JSON (one entity per line). Database connection info read from environment \ + (DATABASE_URL, same as fatcatd).") +*/ + match m.subcommand() { + ("list-editors", Some(_subm)) => { + fatcat::auth::print_editors()?; + }, + ("create-editor", Some(subm)) => { + fatcat::auth::create_editor( + subm.value_of("username").unwrap().to_string(), + subm.is_present("admin"), + subm.is_present("bot"))?; + }, + ("create-token", Some(subm)) => { + let editor_id = FatCatId::from_str(subm.value_of("editor").unwrap())?; + fatcat::auth::create_token(editor_id, None)?; + }, + ("inspect-token", Some(subm)) => { + fatcat::auth::inspect_token(subm.value_of("token").unwrap())?; + }, + ("revoke-tokens", Some(subm)) => { + let editor_id = FatCatId::from_str(subm.value_of("editor").unwrap())?; + fatcat::auth::revoke_tokens(editor_id)?; + }, + ("revoke-tokens-everyone", Some(_subm)) => { + fatcat::auth::revoke_tokens_everyone()?; + }, + _ => { + println!("Missing or unimplemented command!"); + println!("{}", m.usage()); + ::std::process::exit(-1); + } + } + Ok(()) +} + +quick_main!(run); diff --git a/rust/src/bin/fatcatd.rs b/rust/src/bin/fatcatd.rs index 57b6a3da..e14296da 100644 --- a/rust/src/bin/fatcatd.rs +++ b/rust/src/bin/fatcatd.rs @@ -20,9 +20,7 @@ use iron::modifiers::RedirectRaw; use iron::{status, Chain, Iron, IronResult, Request, Response}; use iron_slog::{DefaultLogFormatter, LoggerMiddleware}; use slog::{Drain, Logger}; -//use dotenv::dotenv; -//use std::env; -//use swagger::auth::AllowAllMiddleware; + /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. @@ -78,11 +76,9 @@ fn main() { let mut chain = Chain::new(LoggerMiddleware::new(router, logger, formatter)); - // Auth stuff unused for now - //chain.link_before(fatcat_api_spec::server::ExtractAuthData); - // add authentication middlewares into the chain here - // for the purpose of this example, pretend we have authenticated a user - //chain.link_before(AllowAllMiddleware::new("cosmo")); + // authentication + chain.link_before(fatcat_api_spec::server::ExtractAuthData); + chain.link_before(fatcat::auth::OpenAuthMiddleware::new()); chain.link_after(fatcat::XClacksOverheadMiddleware); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 0bed3471..2a6c7203 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -11,7 +11,7 @@ extern crate futures; extern crate uuid; #[macro_use] extern crate hyper; -//extern crate swagger; +extern crate swagger; #[macro_use] extern crate error_chain; extern crate iron; @@ -24,6 +24,7 @@ extern crate regex; #[macro_use] extern crate lazy_static; extern crate sha1; +extern crate macaroon; pub mod api_entity_crud; pub mod api_helpers; @@ -31,6 +32,7 @@ pub mod api_server; pub mod api_wrappers; pub mod database_models; pub mod database_schema; +pub mod auth; pub mod errors { // Create the Error, ErrorKind, ResultExt, and Result types -- cgit v1.2.3 From 534a42f619b8a7e3226ad7e67601bbaef6bd2f31 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 20 Sep 2018 21:35:02 -0700 Subject: add libsodium-dev as a dep --- .gitlab-ci.yml | 2 +- rust/README.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'rust') diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 19719230..b4556a05 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,7 +14,7 @@ unified_test: before_script: - cargo install diesel_cli --version 1.3.1 - apt update -qy - - apt install -y python3-dev python3-pip python3-wheel libsnappy-dev + - apt install -y python3-dev python3-pip python3-wheel libsnappy-dev libsodium-dev - pip3 install pipenv - pipenv --version script: diff --git a/rust/README.md b/rust/README.md index 2bf86d3c..ddde9b80 100644 --- a/rust/README.md +++ b/rust/README.md @@ -7,6 +7,7 @@ Rust implementation of fatcat API server (`fatcatd`). - diesel (`cargo install diesel_cli`) - postgres (9.6+; targetting 11.1 for production) - postgres libs (debian: `sudo apt install libsqlite3-dev libpq-dev`) +- libsodium library and development headers (debian: `libsodium-dev`) Create a new postgres superuser. A regular postgres user and an existing database should also work (with up/down migrations), but it's easier to just -- cgit v1.2.3 From 3e591d8d7f64b1092f68737ebd464be69f7e2490 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 27 Dec 2018 00:42:56 -0800 Subject: sql: add index on editor username --- rust/migrations/2018-05-12-001226_init/up.sql | 1 + 1 file changed, 1 insertion(+) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index c6444b8e..28cf7f90 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -26,6 +26,7 @@ CREATE TABLE editor ( ); CREATE INDEX active_editgroup_idx ON editor(active_editgroup_id); +CREATE INDEX editor_username_idx ON editor(username); CREATE TABLE editgroup ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), -- cgit v1.2.3 From 946c98593cb5346fff3d1aa72c4992376ec20471 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 27 Dec 2018 00:43:31 -0800 Subject: sql codegen and WIP on auth command --- rust/src/auth.rs | 49 ++++++++++++++++++++++++++++++++------------- rust/src/bin/fatcat-auth.rs | 40 ++++++++++++++++++++++++++---------- rust/src/database_models.rs | 3 +++ rust/src/database_schema.rs | 3 +++ 4 files changed, 70 insertions(+), 25 deletions(-) (limited to 'rust') diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 651f7979..6ded1188 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -4,17 +4,17 @@ use swagger::auth::{AuthData, Authorization, Scopes}; //use macaroon::{Macaroon, Verifier}; use std::collections::BTreeSet; -//use database_models::*; -//use database_schema::*; +use database_models::*; +use database_schema::*; use api_helpers::*; use chrono; -//use diesel; +use diesel; use iron; -//use diesel::prelude::*; +use diesel::prelude::*; use errors::*; -//use serde_json; -//use std::str::FromStr; -//use uuid::Uuid; +use serde_json; +use std::str::FromStr; +use uuid::Uuid; #[derive(Debug)] pub struct OpenAuthMiddleware; @@ -76,20 +76,41 @@ impl iron::middleware::BeforeMiddleware for MacaroonAuthMiddleware { } // DUMMY: parse macaroon +/// On success, returns Some((editor_id, scopes)), where `scopes` is a vector of strings. pub fn parse_macaroon_token(s: &str) -> Result)>> { Ok(Some(("some_editor_id".to_string(), vec![]))) } -pub fn print_editors() -> Result<()>{ - unimplemented!(); +pub fn print_editors(conn: &DbConn) -> Result<()>{ // iterate over all editors. format id, print flags, auth_epoch + let all_editors: Vec = editor::table + .load(conn)?; + println!("editor_id\t\t\tis_admin/is_bot\tauth_epoch\t\t\tusername\twrangler_id"); + for e in all_editors { + println!("{}\t{}\t{}\t{}\t{}\t{:?}", + FatCatId::from_uuid(&e.id).to_string(), + e.is_admin, + e.is_bot, + e.auth_epoch, + e.username, + e.wrangler_id, + ); + } + Ok(()) } -pub fn create_editor(username: String, is_admin: bool, is_bot: bool) -> Result<()> { // TODO: EditorRow or something - unimplemented!(); +pub fn create_editor(conn: &DbConn, username: String, is_admin: bool, is_bot: bool) -> Result { + let ed: EditorRow = diesel::insert_into(editor::table) + .values(( + editor::username.eq(username), + editor::is_admin.eq(is_admin), + editor::is_bot.eq(is_bot), + )) + .get_result(conn)?; + Ok(ed) } -pub fn create_token(editor_id: FatCatId, expires: Option) -> Result { +pub fn create_token(conn: &DbConn, editor_id: FatCatId, expires: Option) -> Result { unimplemented!(); } @@ -97,10 +118,10 @@ pub fn inspect_token(token: &str) -> Result<()> { unimplemented!(); } -pub fn revoke_tokens(editor_id: FatCatId) -> Result<()>{ +pub fn revoke_tokens(conn: &DbConn, editor_id: FatCatId) -> Result<()>{ unimplemented!(); } -pub fn revoke_tokens_everyone() -> Result { +pub fn revoke_tokens_everyone(conn: &DbConn) -> Result { unimplemented!(); } diff --git a/rust/src/bin/fatcat-auth.rs b/rust/src/bin/fatcat-auth.rs index 7cb8af8e..a5fedc1f 100644 --- a/rust/src/bin/fatcat-auth.rs +++ b/rust/src/bin/fatcat-auth.rs @@ -2,6 +2,7 @@ #[macro_use] extern crate clap; +extern crate diesel; extern crate dotenv; #[macro_use] extern crate error_chain; @@ -16,6 +17,9 @@ use clap::{App, Arg, SubCommand}; use dotenv::dotenv; use std::env; +use diesel::prelude::*; +use diesel::r2d2::ConnectionManager; +use fatcat::ConnectionPool; use fatcat::errors::*; use fatcat::api_helpers::FatCatId; use std::str::FromStr; @@ -27,6 +31,18 @@ use std::io::prelude::*; use std::io::{BufReader, BufWriter}; +/// Instantiate a new API server with a pooled database connection +// TODO: copypasta from fatcat-export +pub fn database_worker_pool() -> Result { + dotenv().ok(); + let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); + let manager = ConnectionManager::::new(database_url); + let pool = diesel::r2d2::Pool::builder() + .build(manager) + .expect("Failed to create database pool."); + Ok(pool) +} + fn run() -> Result<()> { let m = App::new("fatcat-auth") .version(env!("CARGO_PKG_VERSION")) @@ -67,35 +83,37 @@ fn run() -> Result<()> { ) .get_matches(); -/* - value_t_or_exit!(subm, "magic", u32) - .after_help("Reads a ident table TSV dump from stdin (aka, ident_id, rev_id, redirect_id), \ - and outputs JSON (one entity per line). Database connection info read from environment \ - (DATABASE_URL, same as fatcatd).") -*/ match m.subcommand() { ("list-editors", Some(_subm)) => { - fatcat::auth::print_editors()?; + let db_conn = database_worker_pool()?.get().expect("database pool"); + fatcat::auth::print_editors(&db_conn)?; }, ("create-editor", Some(subm)) => { - fatcat::auth::create_editor( + let db_conn = database_worker_pool()?.get().expect("database pool"); + let editor = fatcat::auth::create_editor( + &db_conn, subm.value_of("username").unwrap().to_string(), subm.is_present("admin"), subm.is_present("bot"))?; + //println!("{:?}", editor); + println!("{}", FatCatId::from_uuid(&editor.id).to_string()); }, ("create-token", Some(subm)) => { + let db_conn = database_worker_pool()?.get().expect("database pool"); let editor_id = FatCatId::from_str(subm.value_of("editor").unwrap())?; - fatcat::auth::create_token(editor_id, None)?; + fatcat::auth::create_token(&db_conn, editor_id, None)?; }, ("inspect-token", Some(subm)) => { fatcat::auth::inspect_token(subm.value_of("token").unwrap())?; }, ("revoke-tokens", Some(subm)) => { + let db_conn = database_worker_pool()?.get().expect("database pool"); let editor_id = FatCatId::from_str(subm.value_of("editor").unwrap())?; - fatcat::auth::revoke_tokens(editor_id)?; + fatcat::auth::revoke_tokens(&db_conn, editor_id)?; }, ("revoke-tokens-everyone", Some(_subm)) => { - fatcat::auth::revoke_tokens_everyone()?; + let db_conn = database_worker_pool()?.get().expect("database pool"); + fatcat::auth::revoke_tokens_everyone(&db_conn)?; }, _ => { println!("Missing or unimplemented command!"); diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index fc5fc896..55ba7fb9 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -578,7 +578,10 @@ pub struct EditorRow { pub id: Uuid, pub username: String, pub is_admin: bool, + pub is_bot: bool, pub registered: chrono::NaiveDateTime, + pub auth_epoch: chrono::NaiveDateTime, + pub wrangler_id: Option, pub active_editgroup_id: Option, } diff --git a/rust/src/database_schema.rs b/rust/src/database_schema.rs index 2777696d..c240048e 100644 --- a/rust/src/database_schema.rs +++ b/rust/src/database_schema.rs @@ -97,7 +97,10 @@ table! { id -> Uuid, username -> Text, is_admin -> Bool, + is_bot -> Bool, registered -> Timestamptz, + auth_epoch -> Timestamptz, + wrangler_id -> Nullable, active_editgroup_id -> Nullable, } } -- cgit v1.2.3 From 26438d2392eb68345ee7eff204b85c6471ce59c2 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 27 Dec 2018 21:05:40 -0800 Subject: bump busted libmacaroons-rs dependency --- rust/Cargo.lock | 6 +++--- rust/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'rust') diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 17f51d70..b76367b0 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -378,7 +378,7 @@ dependencies = [ "iron-test 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "macaroon 0.1.1 (git+https://github.com/bnewbold/libmacaroon-rs?branch=bnewbold-stable-rust)", + "macaroon 0.1.1 (git+https://github.com/bnewbold/libmacaroon-rs?branch=bnewbold-broken)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -640,7 +640,7 @@ dependencies = [ [[package]] name = "macaroon" version = "0.1.1" -source = "git+https://github.com/bnewbold/libmacaroon-rs?branch=bnewbold-stable-rust#22bb19d70366f34fb32227d5ba311d4a4388d274" +source = "git+https://github.com/bnewbold/libmacaroon-rs?branch=bnewbold-broken#346b4bb21c79958dde301501083bfdaa7aa83f73" dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1642,7 +1642,7 @@ dependencies = [ "checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" -"checksum macaroon 0.1.1 (git+https://github.com/bnewbold/libmacaroon-rs?branch=bnewbold-stable-rust)" = "" +"checksum macaroon 0.1.1 (git+https://github.com/bnewbold/libmacaroon-rs?branch=bnewbold-broken)" = "" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 03fc4814..a20118d2 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -21,7 +21,7 @@ data-encoding = "2.1" regex = "1" lazy_static = "1.0" sha1 = { version = "0.6", features = ["std"] } -macaroon = { git = "https://github.com/bnewbold/libmacaroon-rs", branch = "bnewbold-stable-rust" } +macaroon = { git = "https://github.com/bnewbold/libmacaroon-rs", branch = "bnewbold-broken" } # API server chrono = { version = "0.4", features = ["serde"] } -- cgit v1.2.3 From fa1892834a4650bf2e85215a3270e309d3e9f1c9 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 27 Dec 2018 21:06:09 -0800 Subject: more basic work on auth --- rust/src/api_server.rs | 11 --- rust/src/auth.rs | 197 +++++++++++++++++++++++++++++++++++++++----- rust/src/bin/fatcat-auth.rs | 36 ++++---- rust/src/lib.rs | 3 +- 4 files changed, 200 insertions(+), 47 deletions(-) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index d264afbc..af2a7e24 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -38,17 +38,6 @@ macro_rules! entity_batch_handler { } } -macro_rules! count_entity { - ($table:ident, $conn:expr) => {{ - let count: i64 = $table::table - .filter($table::is_live.eq(true)) - .filter($table::redirect_id.is_null()) - .count() - .first($conn)?; - count - }}; -} - #[derive(Clone)] pub struct Server { pub db_pool: ConnectionPool, diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 6ded1188..580cde28 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -1,24 +1,68 @@ //! Editor bearer token authentication use swagger::auth::{AuthData, Authorization, Scopes}; -//use macaroon::{Macaroon, Verifier}; +use macaroon::{Format, Macaroon, Verifier}; +use data_encoding::BASE64; use std::collections::BTreeSet; +use std::fmt; use database_models::*; use database_schema::*; use api_helpers::*; -use chrono; +use chrono::prelude::*; use diesel; use iron; use diesel::prelude::*; use errors::*; -use serde_json; +//use serde_json; use std::str::FromStr; -use uuid::Uuid; +//use uuid::Uuid; + +// 32 bytes max (!) +static DUMMY_KEY: &[u8] = b"dummy-key-a-one-two-three-a-la"; #[derive(Debug)] pub struct OpenAuthMiddleware; +#[derive(Debug)] +pub struct AuthError { + msg: String, +} + +impl fmt::Display for AuthError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "AuthError: {}", &self.msg) + } +} + +impl iron::Error for AuthError { + fn description(&self) -> &str { + &self.msg + } + fn cause(&self) -> Option<&iron::Error> { + None + } +} + +/* +#[derive(Debug)] +pub struct FatcatAuthBakery { + root_key_store: bool, // hashmap + signing_key: bool, // string name +} + +// impl: +// - new() +// - verify(&str) -> Result +*/ + +fn new_auth_ironerror(m: &str) -> iron::error::IronError { + iron::error::IronError::new( + AuthError { msg: m.to_string() }, + (iron::status::BadRequest, m.to_string()) + ) +} + impl OpenAuthMiddleware { /// Create a middleware that authorizes with the configured subject. pub fn new() -> OpenAuthMiddleware { @@ -42,6 +86,7 @@ pub struct MacaroonAuthMiddleware; impl MacaroonAuthMiddleware { pub fn new() -> MacaroonAuthMiddleware { + macaroon::initialize().unwrap(); MacaroonAuthMiddleware } } @@ -52,13 +97,15 @@ impl iron::middleware::BeforeMiddleware for MacaroonAuthMiddleware { let res: Option<(String, Vec)> = match req.extensions.get::() { Some(AuthData::ApiKey(header)) => { let header: Vec = header.split_whitespace().map(|s| s.to_string()).collect(); - // TODO: error types - assert!(header.len() == 2); - assert!(header[0] == "Bearer"); - parse_macaroon_token(&header[1]).expect("valid macaroon") + if !(header.len() == 2 && header[0] == "Bearer") { + return Err(new_auth_ironerror("invalid bearer auth HTTP Header")); + } + sniff_macaroon_token(&header[1]).expect("valid macaroon") }, None => None, - _ => panic!("valid auth header, or none") + _ => { + return Err(new_auth_ironerror("auth HTTP Header should be empty or API key")); + } }; if let Some((editor_id, scopes)) = res { let mut scope_set = BTreeSet::new(); @@ -75,10 +122,87 @@ impl iron::middleware::BeforeMiddleware for MacaroonAuthMiddleware { } } -// DUMMY: parse macaroon +/// Just checks signature and expired time; can't hit database, so nothing else +pub fn sniff_macaroon_token(s: &str) -> Result)>> { + let raw = BASE64.decode(s.as_bytes())?; + let mac = match Macaroon::deserialize(&raw) { + Ok(m) => m, + Err(e) => bail!("macaroon deserialize error: {:?}", e), + }; + let mac = match mac.validate() { + Ok(m) => m, + Err(e) => bail!("macaroon validate error: {:?}", e), + }; + let mut editor_id: Option = None; + for caveat in mac.first_party_caveats() { + if caveat.predicate().starts_with("editor_id = ") { + editor_id = Some(FatCatId::from_str(caveat.predicate().get(12..).unwrap())?); + break + } + } + let editor_id = editor_id.expect("expected an editor_id caveat"); + Ok(Some((editor_id.to_string(), vec![]))) +} + /// On success, returns Some((editor_id, scopes)), where `scopes` is a vector of strings. -pub fn parse_macaroon_token(s: &str) -> Result)>> { - Ok(Some(("some_editor_id".to_string(), vec![]))) +pub fn parse_macaroon_token(conn: &DbConn, s: &str) -> Result)>> { + let raw = BASE64.decode(s.as_bytes())?; + let mac = match Macaroon::deserialize(&raw) { + Ok(m) => m, + Err(e) => bail!("macaroon deserialize error: {:?}", e), + }; + let mac = match mac.validate() { + Ok(m) => m, + Err(e) => bail!("macaroon validate error: {:?}", e), + }; + let mut verifier = Verifier::new(); + let mut editor_id: Option = None; + for caveat in mac.first_party_caveats() { + if caveat.predicate().starts_with("editor_id = ") { + editor_id = Some(FatCatId::from_str(caveat.predicate().get(12..).unwrap())?); + break + } + } + let editor_id = editor_id.expect("expected an editor_id caveat"); + verifier.satisfy_exact(&format!("editor_id = {}", editor_id.to_string())); + let mut created: Option> = None; + for caveat in mac.first_party_caveats() { + if caveat.predicate().starts_with("created = ") { + created = Some(DateTime::parse_from_rfc3339(caveat.predicate().get(10..).unwrap()) + .unwrap() + .with_timezone(&Utc)); + break + } + } + let created = created.expect("expected a 'created' caveat"); + verifier.satisfy_exact(&format!("created = {}", created.to_rfc3339_opts(SecondsFormat::Secs, true))); + let editor: EditorRow = editor::table + .find(&editor_id.to_uuid()) + .get_result(conn)?; + let auth_epoch = DateTime::::from_utc(editor.auth_epoch, Utc); + if created < auth_epoch { + bail!("token created before current auth_epoch (was probably revoked by editor)") + } + verifier.satisfy_general(|p: &str| -> bool { + // not expired (based on expires) + if p.starts_with("expires = ") { + let expires: DateTime = DateTime::parse_from_rfc3339(p.get(12..).unwrap()) + .unwrap() + .with_timezone(&Utc); + expires < Utc::now() + } else { + false + } + }); + if !mac.verify_signature(DUMMY_KEY) { + bail!("token signature verification failed"); + }; + match mac.verify(DUMMY_KEY, &mut verifier) { + Ok(true) => (), + Ok(false) => bail!("token overall verification failed"), + Err(e) => bail!("token parsing failed: {:?}", e), + } + Ok(Some((editor_id.to_string(), vec![]))) } pub fn print_editors(conn: &DbConn) -> Result<()>{ @@ -99,6 +223,8 @@ pub fn print_editors(conn: &DbConn) -> Result<()>{ Ok(()) } +// TODO: move to api_helpers or some such +// TODO: verify username pub fn create_editor(conn: &DbConn, username: String, is_admin: bool, is_bot: bool) -> Result { let ed: EditorRow = diesel::insert_into(editor::table) .values(( @@ -110,18 +236,51 @@ pub fn create_editor(conn: &DbConn, username: String, is_admin: bool, is_bot: bo Ok(ed) } -pub fn create_token(conn: &DbConn, editor_id: FatCatId, expires: Option) -> Result { - unimplemented!(); +pub fn create_token(conn: &DbConn, editor_id: FatCatId, expires: Option>) -> Result { + let _ed: EditorRow = editor::table + .find(&editor_id.to_uuid()) + .get_result(conn)?; + let mut mac = Macaroon::create("fatcat.wiki", DUMMY_KEY, "dummy-key").expect("Macaroon creation"); + mac.add_first_party_caveat(&format!("editor_id = {}", editor_id.to_string())); + // TODO: put created one second in the past to prevent timing synchronization glitches? + let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); + mac.add_first_party_caveat(&format!("created = {}", now)); + if let Some(expires) = expires { + mac.add_first_party_caveat(&format!("expires = {:?}", + &expires.to_rfc3339_opts(SecondsFormat::Secs, true))); + }; + let raw = mac.serialize(Format::V2).expect("macaroon serialization"); + Ok(BASE64.encode(&raw)) } -pub fn inspect_token(token: &str) -> Result<()> { - unimplemented!(); +pub fn inspect_token(conn: &DbConn, token: &str) -> Result<()> { + let raw = BASE64.decode(token.as_bytes())?; + let mac = match Macaroon::deserialize(&raw) { + Ok(m) => m, + Err(e) => bail!("macaroon deserialize error: {:?}", e), + }; + let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); + println!("current time: {}", now); + println!("domain (location): {:?}", mac.location()); + println!("signing key name (identifier): {}", mac.identifier()); + for caveat in mac.first_party_caveats() { + println!("caveat: {}", caveat.predicate()); + } + // TODO: don't display full stacktrace on failure + println!("verify: {:?}", parse_macaroon_token(conn, token)); + Ok(()) } pub fn revoke_tokens(conn: &DbConn, editor_id: FatCatId) -> Result<()>{ - unimplemented!(); + diesel::update(editor::table.filter(editor::id.eq(&editor_id.to_uuid()))) + .set(editor::auth_epoch.eq(Utc::now())) + .execute(conn)?; + Ok(()) } -pub fn revoke_tokens_everyone(conn: &DbConn) -> Result { - unimplemented!(); +pub fn revoke_tokens_everyone(conn: &DbConn) -> Result<()> { + diesel::update(editor::table) + .set(editor::auth_epoch.eq(Utc::now())) + .execute(conn)?; + Ok(()) } diff --git a/rust/src/bin/fatcat-auth.rs b/rust/src/bin/fatcat-auth.rs index a5fedc1f..9b4550d8 100644 --- a/rust/src/bin/fatcat-auth.rs +++ b/rust/src/bin/fatcat-auth.rs @@ -1,13 +1,13 @@ //! JSON Export Helper -#[macro_use] +//#[macro_use] extern crate clap; extern crate diesel; extern crate dotenv; #[macro_use] extern crate error_chain; extern crate fatcat; -#[macro_use] +//#[macro_use] extern crate log; extern crate env_logger; extern crate serde_json; @@ -23,12 +23,12 @@ use fatcat::ConnectionPool; use fatcat::errors::*; use fatcat::api_helpers::FatCatId; use std::str::FromStr; -use uuid::Uuid; +//use uuid::Uuid; -use error_chain::ChainedError; +//use error_chain::ChainedError; //use std::io::{Stdout,StdoutLock}; -use std::io::prelude::*; -use std::io::{BufReader, BufWriter}; +//use std::io::prelude::*; +//use std::io::{BufReader, BufWriter}; /// Instantiate a new API server with a pooled database connection @@ -72,24 +72,29 @@ fn run() -> Result<()> { .subcommand( SubCommand::with_name("inspect-token") .about("Dumps token metadata (and whether it is valid)") + .args_from_usage( + " 'base64-encoded token (macaroon)'" + ) ) .subcommand( SubCommand::with_name("revoke-tokens") .about("Resets auth_epoch for a single editor (invalidating all existing tokens)") + .args_from_usage( + " 'identifier (fcid) of editor'" + ) ) .subcommand( - SubCommand::with_name("revoke-tokens-all") + SubCommand::with_name("revoke-tokens-everyone") .about("Resets auth_epoch for all editors (invalidating tokens for all users!)") ) .get_matches(); + let db_conn = database_worker_pool()?.get().expect("database pool"); match m.subcommand() { ("list-editors", Some(_subm)) => { - let db_conn = database_worker_pool()?.get().expect("database pool"); fatcat::auth::print_editors(&db_conn)?; }, ("create-editor", Some(subm)) => { - let db_conn = database_worker_pool()?.get().expect("database pool"); let editor = fatcat::auth::create_editor( &db_conn, subm.value_of("username").unwrap().to_string(), @@ -99,21 +104,20 @@ fn run() -> Result<()> { println!("{}", FatCatId::from_uuid(&editor.id).to_string()); }, ("create-token", Some(subm)) => { - let db_conn = database_worker_pool()?.get().expect("database pool"); - let editor_id = FatCatId::from_str(subm.value_of("editor").unwrap())?; - fatcat::auth::create_token(&db_conn, editor_id, None)?; + let editor_id = FatCatId::from_str(subm.value_of("editor-id").unwrap())?; + println!("{}", fatcat::auth::create_token(&db_conn, editor_id, None)?); }, ("inspect-token", Some(subm)) => { - fatcat::auth::inspect_token(subm.value_of("token").unwrap())?; + fatcat::auth::inspect_token(&db_conn, subm.value_of("token").unwrap())?; }, ("revoke-tokens", Some(subm)) => { - let db_conn = database_worker_pool()?.get().expect("database pool"); - let editor_id = FatCatId::from_str(subm.value_of("editor").unwrap())?; + let editor_id = FatCatId::from_str(subm.value_of("editor-id").unwrap())?; fatcat::auth::revoke_tokens(&db_conn, editor_id)?; + println!("success!"); }, ("revoke-tokens-everyone", Some(_subm)) => { - let db_conn = database_worker_pool()?.get().expect("database pool"); fatcat::auth::revoke_tokens_everyone(&db_conn)?; + println!("success!"); }, _ => { println!("Missing or unimplemented command!"); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 2a6c7203..f081be25 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -15,7 +15,6 @@ extern crate swagger; #[macro_use] extern crate error_chain; extern crate iron; -#[macro_use] extern crate serde_json; #[macro_use] extern crate log; @@ -43,6 +42,8 @@ pub mod errors { Uuid(::uuid::ParseError); Io(::std::io::Error) #[cfg(unix)]; Serde(::serde_json::Error); + Utf8Decode(::std::string::FromUtf8Error); + StringDecode(::data_encoding::DecodeError); } errors { InvalidFatcatId(id: String) { -- cgit v1.2.3 From f9408344464285870409c2209a8edc8d25fd9bfa Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 28 Dec 2018 14:52:38 -0800 Subject: start refactor of auth code Pulls auth code (which requires the persistent state of a signing keyring) into a struct. Doesn't try verify macaroon in middleware, do it in individual wrappers. --- rust/src/api_server.rs | 2 + rust/src/api_wrappers.rs | 5 +- rust/src/auth.rs | 293 +++++++++++++++++--------------------------- rust/src/bin/fatcat-auth.rs | 3 +- rust/src/bin/fatcatd.rs | 1 - rust/src/database_models.rs | 2 +- rust/src/lib.rs | 3 +- 7 files changed, 121 insertions(+), 188 deletions(-) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index af2a7e24..cbf5be21 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -2,6 +2,7 @@ use api_entity_crud::EntityCrud; use api_helpers::*; +use auth::*; use chrono; use database_models::*; use database_schema::*; @@ -41,6 +42,7 @@ macro_rules! entity_batch_handler { #[derive(Clone)] pub struct Server { pub db_pool: ConnectionPool, + pub auth_confectionary: AuthConfectionary, } pub fn get_release_files( diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index cf696d15..25b4fab1 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -2,6 +2,7 @@ use api_entity_crud::EntityCrud; use api_helpers::*; +use auth::*; use api_server::Server; use database_models::EntityEditRow; use diesel::Connection; @@ -80,10 +81,12 @@ macro_rules! wrap_entity_handlers { &self, entity: models::$model, editgroup_id: Option, - _context: &Context, + context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { + let auth_context = self.auth_confectionary.parse_swagger(&conn, &context.auth_data)?; + // XXX: auth_context.expect("not authorized"); let editgroup_id = if let Some(s) = editgroup_id { Some(FatCatId::from_str(&s)?) } else { None }; diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 580cde28..c188233a 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -1,208 +1,151 @@ //! Editor bearer token authentication -use swagger::auth::{AuthData, Authorization, Scopes}; +use swagger::auth::AuthData; use macaroon::{Format, Macaroon, Verifier}; use data_encoding::BASE64; -use std::collections::BTreeSet; -use std::fmt; +use std::collections::{BTreeSet,HashMap}; use database_models::*; use database_schema::*; use api_helpers::*; use chrono::prelude::*; use diesel; -use iron; use diesel::prelude::*; use errors::*; -//use serde_json; use std::str::FromStr; -//use uuid::Uuid; // 32 bytes max (!) static DUMMY_KEY: &[u8] = b"dummy-key-a-one-two-three-a-la"; -#[derive(Debug)] -pub struct OpenAuthMiddleware; - -#[derive(Debug)] -pub struct AuthError { - msg: String, +#[derive(Clone)] +pub struct AuthContext { + pub editor_id: FatCatId, + editor_row: EditorRow, + roles: Vec, // TODO: BTreeSet } -impl fmt::Display for AuthError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "AuthError: {}", &self.msg) - } -} +impl AuthContext { -impl iron::Error for AuthError { - fn description(&self) -> &str { - &self.msg - } - fn cause(&self) -> Option<&iron::Error> { - None + pub fn has_role(&self, role: &str) -> bool { + self.roles.contains(&role.to_string()) || self.roles.contains(&"admin".to_string()) } } -/* -#[derive(Debug)] -pub struct FatcatAuthBakery { - root_key_store: bool, // hashmap - signing_key: bool, // string name +#[derive(Clone)] +pub struct AuthConfectionary { + pub root_keys: HashMap, } -// impl: -// - new() -// - verify(&str) -> Result -*/ - -fn new_auth_ironerror(m: &str) -> iron::error::IronError { - iron::error::IronError::new( - AuthError { msg: m.to_string() }, - (iron::status::BadRequest, m.to_string()) - ) -} - -impl OpenAuthMiddleware { - /// Create a middleware that authorizes with the configured subject. - pub fn new() -> OpenAuthMiddleware { - OpenAuthMiddleware - } -} -impl iron::middleware::BeforeMiddleware for OpenAuthMiddleware { - fn before(&self, req: &mut iron::Request) -> iron::IronResult<()> { - req.extensions.insert::(Authorization { - subject: "undefined".to_string(), - scopes: Scopes::All, - issuer: None, - }); - Ok(()) +impl AuthConfectionary { + pub fn new() -> AuthConfectionary { + AuthConfectionary { + root_keys: HashMap::new(), + } } -} -#[derive(Debug)] -pub struct MacaroonAuthMiddleware; - -impl MacaroonAuthMiddleware { + pub fn create_token(&self, conn: &DbConn, editor_id: FatCatId, expires: Option>) -> Result { + let _ed: EditorRow = editor::table + .find(&editor_id.to_uuid()) + .get_result(conn)?; + let mut mac = Macaroon::create("fatcat.wiki", DUMMY_KEY, "dummy-key").expect("Macaroon creation"); + mac.add_first_party_caveat(&format!("editor_id = {}", editor_id.to_string())); + // TODO: put created one second in the past to prevent timing synchronization glitches? + let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); + mac.add_first_party_caveat(&format!("created = {}", now)); + if let Some(expires) = expires { + mac.add_first_party_caveat(&format!("expires = {:?}", + &expires.to_rfc3339_opts(SecondsFormat::Secs, true))); + }; + let raw = mac.serialize(Format::V2).expect("macaroon serialization"); + Ok(BASE64.encode(&raw)) + } - pub fn new() -> MacaroonAuthMiddleware { - macaroon::initialize().unwrap(); - MacaroonAuthMiddleware + /// On success, returns Some((editor_id, scopes)), where `scopes` is a vector of strings. + pub fn parse_macaroon_token(&self, conn: &DbConn, s: &str) -> Result { + let raw = BASE64.decode(s.as_bytes())?; + let mac = match Macaroon::deserialize(&raw) { + Ok(m) => m, + Err(e) => bail!("macaroon deserialize error: {:?}", e), + }; + let mac = match mac.validate() { + Ok(m) => m, + Err(e) => bail!("macaroon validate error: {:?}", e), + }; + let mut verifier = Verifier::new(); + let mut editor_id: Option = None; + for caveat in mac.first_party_caveats() { + if caveat.predicate().starts_with("editor_id = ") { + editor_id = Some(FatCatId::from_str(caveat.predicate().get(12..).unwrap())?); + break + } + } + let editor_id = editor_id.expect("expected an editor_id caveat"); + verifier.satisfy_exact(&format!("editor_id = {}", editor_id.to_string())); + let mut created: Option> = None; + for caveat in mac.first_party_caveats() { + if caveat.predicate().starts_with("created = ") { + created = Some(DateTime::parse_from_rfc3339(caveat.predicate().get(10..).unwrap()) + .unwrap() + .with_timezone(&Utc)); + break + } + } + let created = created.expect("expected a 'created' caveat"); + verifier.satisfy_exact(&format!("created = {}", created.to_rfc3339_opts(SecondsFormat::Secs, true))); + let editor: EditorRow = editor::table + .find(&editor_id.to_uuid()) + .get_result(conn)?; + let auth_epoch = DateTime::::from_utc(editor.auth_epoch, Utc); + if created < auth_epoch { + bail!("token created before current auth_epoch (was probably revoked by editor)") + } + verifier.satisfy_general(|p: &str| -> bool { + // not expired (based on expires) + if p.starts_with("expires = ") { + let expires: DateTime = DateTime::parse_from_rfc3339(p.get(12..).unwrap()) + .unwrap() + .with_timezone(&Utc); + expires < Utc::now() + } else { + false + } + }); + if !mac.verify_signature(DUMMY_KEY) { + bail!("token signature verification failed"); + }; + match mac.verify(DUMMY_KEY, &mut verifier) { + Ok(true) => (), + Ok(false) => bail!("token overall verification failed"), + Err(e) => bail!("token parsing failed: {:?}", e), + } + Ok(editor) } -} -impl iron::middleware::BeforeMiddleware for MacaroonAuthMiddleware { - fn before(&self, req: &mut iron::Request) -> iron::IronResult<()> { + pub fn parse_swagger(&self, conn: &DbConn, auth_data: &Option) -> Result> { - let res: Option<(String, Vec)> = match req.extensions.get::() { + let token: Option = match auth_data { Some(AuthData::ApiKey(header)) => { let header: Vec = header.split_whitespace().map(|s| s.to_string()).collect(); if !(header.len() == 2 && header[0] == "Bearer") { - return Err(new_auth_ironerror("invalid bearer auth HTTP Header")); + bail!("invalid Bearer Auth HTTP header"); } - sniff_macaroon_token(&header[1]).expect("valid macaroon") + Some(header[1].clone()) }, None => None, - _ => { - return Err(new_auth_ironerror("auth HTTP Header should be empty or API key")); - } + _ => bail!("Authentication HTTP Header should either be empty or a Beaerer API key"), }; - if let Some((editor_id, scopes)) = res { - let mut scope_set = BTreeSet::new(); - for s in scopes { - scope_set.insert(s); - } - req.extensions.insert::(Authorization { - subject: editor_id, - scopes: Scopes::Some(scope_set), - issuer: None, - }); + let token = match token { + Some(t) => t, + None => return Ok(None), }; - Ok(()) - } -} - -/// Just checks signature and expired time; can't hit database, so nothing else -pub fn sniff_macaroon_token(s: &str) -> Result)>> { - let raw = BASE64.decode(s.as_bytes())?; - let mac = match Macaroon::deserialize(&raw) { - Ok(m) => m, - Err(e) => bail!("macaroon deserialize error: {:?}", e), - }; - let mac = match mac.validate() { - Ok(m) => m, - Err(e) => bail!("macaroon validate error: {:?}", e), - }; - let mut editor_id: Option = None; - for caveat in mac.first_party_caveats() { - if caveat.predicate().starts_with("editor_id = ") { - editor_id = Some(FatCatId::from_str(caveat.predicate().get(12..).unwrap())?); - break - } - } - let editor_id = editor_id.expect("expected an editor_id caveat"); - Ok(Some((editor_id.to_string(), vec![]))) -} - -/// On success, returns Some((editor_id, scopes)), where `scopes` is a vector of strings. -pub fn parse_macaroon_token(conn: &DbConn, s: &str) -> Result)>> { - let raw = BASE64.decode(s.as_bytes())?; - let mac = match Macaroon::deserialize(&raw) { - Ok(m) => m, - Err(e) => bail!("macaroon deserialize error: {:?}", e), - }; - let mac = match mac.validate() { - Ok(m) => m, - Err(e) => bail!("macaroon validate error: {:?}", e), - }; - let mut verifier = Verifier::new(); - let mut editor_id: Option = None; - for caveat in mac.first_party_caveats() { - if caveat.predicate().starts_with("editor_id = ") { - editor_id = Some(FatCatId::from_str(caveat.predicate().get(12..).unwrap())?); - break - } - } - let editor_id = editor_id.expect("expected an editor_id caveat"); - verifier.satisfy_exact(&format!("editor_id = {}", editor_id.to_string())); - let mut created: Option> = None; - for caveat in mac.first_party_caveats() { - if caveat.predicate().starts_with("created = ") { - created = Some(DateTime::parse_from_rfc3339(caveat.predicate().get(10..).unwrap()) - .unwrap() - .with_timezone(&Utc)); - break - } - } - let created = created.expect("expected a 'created' caveat"); - verifier.satisfy_exact(&format!("created = {}", created.to_rfc3339_opts(SecondsFormat::Secs, true))); - let editor: EditorRow = editor::table - .find(&editor_id.to_uuid()) - .get_result(conn)?; - let auth_epoch = DateTime::::from_utc(editor.auth_epoch, Utc); - if created < auth_epoch { - bail!("token created before current auth_epoch (was probably revoked by editor)") + let editor_row = self.parse_macaroon_token(conn, &token)?; + let roles = if editor_row.is_admin { vec!["admin".to_string()] } else { vec![] }; + Ok(Some(AuthContext { + editor_id: FatCatId::from_uuid(&editor_row.id), + editor_row: editor_row, + roles: roles, + })) } - verifier.satisfy_general(|p: &str| -> bool { - // not expired (based on expires) - if p.starts_with("expires = ") { - let expires: DateTime = DateTime::parse_from_rfc3339(p.get(12..).unwrap()) - .unwrap() - .with_timezone(&Utc); - expires < Utc::now() - } else { - false - } - }); - if !mac.verify_signature(DUMMY_KEY) { - bail!("token signature verification failed"); - }; - match mac.verify(DUMMY_KEY, &mut verifier) { - Ok(true) => (), - Ok(false) => bail!("token overall verification failed"), - Err(e) => bail!("token parsing failed: {:?}", e), - } - Ok(Some((editor_id.to_string(), vec![]))) } pub fn print_editors(conn: &DbConn) -> Result<()>{ @@ -236,23 +179,6 @@ pub fn create_editor(conn: &DbConn, username: String, is_admin: bool, is_bot: bo Ok(ed) } -pub fn create_token(conn: &DbConn, editor_id: FatCatId, expires: Option>) -> Result { - let _ed: EditorRow = editor::table - .find(&editor_id.to_uuid()) - .get_result(conn)?; - let mut mac = Macaroon::create("fatcat.wiki", DUMMY_KEY, "dummy-key").expect("Macaroon creation"); - mac.add_first_party_caveat(&format!("editor_id = {}", editor_id.to_string())); - // TODO: put created one second in the past to prevent timing synchronization glitches? - let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); - mac.add_first_party_caveat(&format!("created = {}", now)); - if let Some(expires) = expires { - mac.add_first_party_caveat(&format!("expires = {:?}", - &expires.to_rfc3339_opts(SecondsFormat::Secs, true))); - }; - let raw = mac.serialize(Format::V2).expect("macaroon serialization"); - Ok(BASE64.encode(&raw)) -} - pub fn inspect_token(conn: &DbConn, token: &str) -> Result<()> { let raw = BASE64.decode(token.as_bytes())?; let mac = match Macaroon::deserialize(&raw) { @@ -266,8 +192,9 @@ pub fn inspect_token(conn: &DbConn, token: &str) -> Result<()> { for caveat in mac.first_party_caveats() { println!("caveat: {}", caveat.predicate()); } + let ac = AuthConfectionary::new(); // TODO: don't display full stacktrace on failure - println!("verify: {:?}", parse_macaroon_token(conn, token)); + println!("verify: {:?}", ac.parse_macaroon_token(conn, token)); Ok(()) } diff --git a/rust/src/bin/fatcat-auth.rs b/rust/src/bin/fatcat-auth.rs index 9b4550d8..f11f7a67 100644 --- a/rust/src/bin/fatcat-auth.rs +++ b/rust/src/bin/fatcat-auth.rs @@ -90,6 +90,7 @@ fn run() -> Result<()> { .get_matches(); let db_conn = database_worker_pool()?.get().expect("database pool"); + let confectionary = fatcat::auth::AuthConfectionary::new(); match m.subcommand() { ("list-editors", Some(_subm)) => { fatcat::auth::print_editors(&db_conn)?; @@ -105,7 +106,7 @@ fn run() -> Result<()> { }, ("create-token", Some(subm)) => { let editor_id = FatCatId::from_str(subm.value_of("editor-id").unwrap())?; - println!("{}", fatcat::auth::create_token(&db_conn, editor_id, None)?); + println!("{}", confectionary.create_token(&db_conn, editor_id, None)?); }, ("inspect-token", Some(subm)) => { fatcat::auth::inspect_token(&db_conn, subm.value_of("token").unwrap())?; diff --git a/rust/src/bin/fatcatd.rs b/rust/src/bin/fatcatd.rs index e14296da..7def7f66 100644 --- a/rust/src/bin/fatcatd.rs +++ b/rust/src/bin/fatcatd.rs @@ -78,7 +78,6 @@ fn main() { // authentication chain.link_before(fatcat_api_spec::server::ExtractAuthData); - chain.link_before(fatcat::auth::OpenAuthMiddleware::new()); chain.link_after(fatcat::XClacksOverheadMiddleware); diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index 55ba7fb9..f6cca3e1 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -572,7 +572,7 @@ impl EditgroupRow { } } -#[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] +#[derive(Debug, Clone, Queryable, Identifiable, Associations, AsChangeset)] #[table_name = "editor"] pub struct EditorRow { pub id: Uuid, diff --git a/rust/src/lib.rs b/rust/src/lib.rs index f081be25..43911868 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -117,7 +117,8 @@ pub fn server() -> Result { let pool = diesel::r2d2::Pool::builder() .build(manager) .expect("Failed to create database pool."); - Ok(api_server::Server { db_pool: pool }) + let confectionary = auth::AuthConfectionary::new(); + Ok(api_server::Server { db_pool: pool, auth_confectionary: confectionary }) } pub fn test_server() -> Result { -- cgit v1.2.3 From d50f7729cbc86c62dba9bd4db80786f07b44a7c0 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 28 Dec 2018 22:04:45 -0800 Subject: more auth refactoring --- rust/src/api_helpers.rs | 12 +++++ rust/src/auth.rs | 113 +++++++++++++++++++++++--------------------- rust/src/bin/fatcat-auth.rs | 8 ++-- rust/src/lib.rs | 2 +- 4 files changed, 76 insertions(+), 59 deletions(-) (limited to 'rust') diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index ff164bef..da208c0a 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -228,6 +228,18 @@ pub fn make_edit_context( }) } +// TODO: verify username (alphanum, etc) +pub fn create_editor(conn: &DbConn, username: String, is_admin: bool, is_bot: bool) -> Result { + let ed: EditorRow = diesel::insert_into(editor::table) + .values(( + editor::username.eq(username), + editor::is_admin.eq(is_admin), + editor::is_bot.eq(is_bot), + )) + .get_result(conn)?; + Ok(ed) +} + /// This function should always be run within a transaction pub fn get_or_create_editgroup(editor_id: Uuid, conn: &DbConn) -> Result { // check for current active diff --git a/rust/src/auth.rs b/rust/src/auth.rs index c188233a..8e9a6309 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -4,7 +4,7 @@ use swagger::auth::AuthData; use macaroon::{Format, Macaroon, Verifier}; use data_encoding::BASE64; -use std::collections::{BTreeSet,HashMap}; +use std::collections::HashMap; use database_models::*; use database_schema::*; use api_helpers::*; @@ -33,21 +33,36 @@ impl AuthContext { #[derive(Clone)] pub struct AuthConfectionary { - pub root_keys: HashMap, + pub location: String, + pub identifier: String, + pub key: Vec, + pub root_keys: HashMap>, } impl AuthConfectionary { - pub fn new() -> AuthConfectionary { + pub fn new(location: String, identifier: String, key: Vec) -> AuthConfectionary { + let mut root_keys = HashMap::new(); + root_keys.insert(identifier.clone(), key.clone()); AuthConfectionary { - root_keys: HashMap::new(), + location: location, + identifier: identifier, + key: key, + root_keys: root_keys, } } + pub fn new_dummy() -> AuthConfectionary { + AuthConfectionary::new( + "test.fatcat.wiki".to_string(), + "dummy".to_string(), + DUMMY_KEY.to_vec()) + } + pub fn create_token(&self, conn: &DbConn, editor_id: FatCatId, expires: Option>) -> Result { let _ed: EditorRow = editor::table .find(&editor_id.to_uuid()) .get_result(conn)?; - let mut mac = Macaroon::create("fatcat.wiki", DUMMY_KEY, "dummy-key").expect("Macaroon creation"); + let mut mac = Macaroon::create(&self.location, &self.key, &self.identifier).expect("Macaroon creation"); mac.add_first_party_caveat(&format!("editor_id = {}", editor_id.to_string())); // TODO: put created one second in the past to prevent timing synchronization glitches? let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); @@ -110,10 +125,11 @@ impl AuthConfectionary { false } }); - if !mac.verify_signature(DUMMY_KEY) { - bail!("token signature verification failed"); + let verify_key = match self.root_keys.get(mac.identifier()) { + Some(key) => key, + None => bail!("key not found for identifier: {}", mac.identifier()), }; - match mac.verify(DUMMY_KEY, &mut verifier) { + match mac.verify(verify_key, &mut verifier) { Ok(true) => (), Ok(false) => bail!("token overall verification failed"), Err(e) => bail!("token parsing failed: {:?}", e), @@ -146,8 +162,43 @@ impl AuthConfectionary { roles: roles, })) } + + // TODO: refactor out of this file? + /// Only used from CLI tool + pub fn inspect_token(&self, conn: &DbConn, token: &str) -> Result<()> { + let raw = BASE64.decode(token.as_bytes())?; + let mac = match Macaroon::deserialize(&raw) { + Ok(m) => m, + Err(e) => bail!("macaroon deserialize error: {:?}", e), + }; + let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); + println!("current time: {}", now); + println!("domain (location): {:?}", mac.location()); + println!("signing key name (identifier): {}", mac.identifier()); + for caveat in mac.first_party_caveats() { + println!("caveat: {}", caveat.predicate()); + } + println!("verify: {:?}", self.parse_macaroon_token(conn, token)); + Ok(()) + } } +pub fn revoke_tokens(conn: &DbConn, editor_id: FatCatId) -> Result<()>{ + diesel::update(editor::table.filter(editor::id.eq(&editor_id.to_uuid()))) + .set(editor::auth_epoch.eq(Utc::now())) + .execute(conn)?; + Ok(()) +} + +pub fn revoke_tokens_everyone(conn: &DbConn) -> Result<()> { + diesel::update(editor::table) + .set(editor::auth_epoch.eq(Utc::now())) + .execute(conn)?; + Ok(()) +} + +// TODO: refactor out of this file? +/// Only used from CLI tool pub fn print_editors(conn: &DbConn) -> Result<()>{ // iterate over all editors. format id, print flags, auth_epoch let all_editors: Vec = editor::table @@ -165,49 +216,3 @@ pub fn print_editors(conn: &DbConn) -> Result<()>{ } Ok(()) } - -// TODO: move to api_helpers or some such -// TODO: verify username -pub fn create_editor(conn: &DbConn, username: String, is_admin: bool, is_bot: bool) -> Result { - let ed: EditorRow = diesel::insert_into(editor::table) - .values(( - editor::username.eq(username), - editor::is_admin.eq(is_admin), - editor::is_bot.eq(is_bot), - )) - .get_result(conn)?; - Ok(ed) -} - -pub fn inspect_token(conn: &DbConn, token: &str) -> Result<()> { - let raw = BASE64.decode(token.as_bytes())?; - let mac = match Macaroon::deserialize(&raw) { - Ok(m) => m, - Err(e) => bail!("macaroon deserialize error: {:?}", e), - }; - let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); - println!("current time: {}", now); - println!("domain (location): {:?}", mac.location()); - println!("signing key name (identifier): {}", mac.identifier()); - for caveat in mac.first_party_caveats() { - println!("caveat: {}", caveat.predicate()); - } - let ac = AuthConfectionary::new(); - // TODO: don't display full stacktrace on failure - println!("verify: {:?}", ac.parse_macaroon_token(conn, token)); - Ok(()) -} - -pub fn revoke_tokens(conn: &DbConn, editor_id: FatCatId) -> Result<()>{ - diesel::update(editor::table.filter(editor::id.eq(&editor_id.to_uuid()))) - .set(editor::auth_epoch.eq(Utc::now())) - .execute(conn)?; - Ok(()) -} - -pub fn revoke_tokens_everyone(conn: &DbConn) -> Result<()> { - diesel::update(editor::table) - .set(editor::auth_epoch.eq(Utc::now())) - .execute(conn)?; - Ok(()) -} diff --git a/rust/src/bin/fatcat-auth.rs b/rust/src/bin/fatcat-auth.rs index f11f7a67..4b90da74 100644 --- a/rust/src/bin/fatcat-auth.rs +++ b/rust/src/bin/fatcat-auth.rs @@ -13,7 +13,7 @@ extern crate env_logger; extern crate serde_json; extern crate uuid; -use clap::{App, Arg, SubCommand}; +use clap::{App, SubCommand}; use dotenv::dotenv; use std::env; @@ -90,13 +90,13 @@ fn run() -> Result<()> { .get_matches(); let db_conn = database_worker_pool()?.get().expect("database pool"); - let confectionary = fatcat::auth::AuthConfectionary::new(); + let confectionary = fatcat::auth::AuthConfectionary::new_dummy(); match m.subcommand() { ("list-editors", Some(_subm)) => { fatcat::auth::print_editors(&db_conn)?; }, ("create-editor", Some(subm)) => { - let editor = fatcat::auth::create_editor( + let editor = fatcat::api_helpers::create_editor( &db_conn, subm.value_of("username").unwrap().to_string(), subm.is_present("admin"), @@ -109,7 +109,7 @@ fn run() -> Result<()> { println!("{}", confectionary.create_token(&db_conn, editor_id, None)?); }, ("inspect-token", Some(subm)) => { - fatcat::auth::inspect_token(&db_conn, subm.value_of("token").unwrap())?; + confectionary.inspect_token(&db_conn, subm.value_of("token").unwrap())?; }, ("revoke-tokens", Some(subm)) => { let editor_id = FatCatId::from_str(subm.value_of("editor-id").unwrap())?; diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 43911868..983645d8 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -117,7 +117,7 @@ pub fn server() -> Result { let pool = diesel::r2d2::Pool::builder() .build(manager) .expect("Failed to create database pool."); - let confectionary = auth::AuthConfectionary::new(); + let confectionary = auth::AuthConfectionary::new_dummy(); Ok(api_server::Server { db_pool: pool, auth_confectionary: confectionary }) } -- cgit v1.2.3 From 156b10220a50f6f441e7484235e227316f26761e Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 28 Dec 2018 22:50:47 -0800 Subject: basic auth unittests --- rust/src/api_helpers.rs | 2 +- rust/src/auth.rs | 5 +---- rust/src/bin/fatcat-auth.rs | 6 +++++- rust/tests/test_auth.rs | 48 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 rust/tests/test_auth.rs (limited to 'rust') diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index da208c0a..3c5a2e17 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -294,7 +294,7 @@ pub fn accept_editgroup(editgroup_id: FatCatId, conn: &DbConn) -> Result>) -> Result { - let _ed: EditorRow = editor::table - .find(&editor_id.to_uuid()) - .get_result(conn)?; + pub fn create_token(&self, editor_id: FatCatId, expires: Option>) -> Result { let mut mac = Macaroon::create(&self.location, &self.key, &self.identifier).expect("Macaroon creation"); mac.add_first_party_caveat(&format!("editor_id = {}", editor_id.to_string())); // TODO: put created one second in the past to prevent timing synchronization glitches? diff --git a/rust/src/bin/fatcat-auth.rs b/rust/src/bin/fatcat-auth.rs index 4b90da74..5a8f0f98 100644 --- a/rust/src/bin/fatcat-auth.rs +++ b/rust/src/bin/fatcat-auth.rs @@ -106,7 +106,11 @@ fn run() -> Result<()> { }, ("create-token", Some(subm)) => { let editor_id = FatCatId::from_str(subm.value_of("editor-id").unwrap())?; - println!("{}", confectionary.create_token(&db_conn, editor_id, None)?); + // check that editor exists + let _ed: fatcat::database_models::EditorRow = fatcat::database_schema::editor::table + .find(&editor_id.to_uuid()) + .get_result(&db_conn)?; + println!("{}", confectionary.create_token(editor_id, None)?); }, ("inspect-token", Some(subm)) => { confectionary.inspect_token(&db_conn, subm.value_of("token").unwrap())?; diff --git a/rust/tests/test_auth.rs b/rust/tests/test_auth.rs new file mode 100644 index 00000000..45956036 --- /dev/null +++ b/rust/tests/test_auth.rs @@ -0,0 +1,48 @@ + +extern crate fatcat; +extern crate uuid; +extern crate chrono; + +use std::str::FromStr; +use chrono::prelude::*; +use fatcat::auth::*; +use fatcat::api_helpers::*; + +#[test] +fn test_macaroons() { + // Test everything we can without connecting to database + + let c = fatcat::auth::AuthConfectionary::new_dummy(); + let editor_id = FatCatId::from_str("q3nouwy3nnbsvo3h5klxsx4a7y").unwrap(); + + // create token w/o expiration + c.create_token(editor_id, None).unwrap(); + + // create token w/ expiration + let tomorrow = Utc::now() + chrono::Duration::days(1); + c.create_token(editor_id, Some(tomorrow)).unwrap(); +} + + +#[test] +fn test_auth_db() { + // Test things that require database + + let server = fatcat::test_server().unwrap(); + let conn = server.db_pool.get().expect("db_pool error"); + let c = fatcat::auth::AuthConfectionary::new_dummy(); + let editor_id = FatCatId::from_str("aaaaaaaaaaaabkvkaaaaaaaaae").unwrap(); + + // create token + let token = c.create_token(editor_id, None).unwrap(); + + // verify token + let editor_row = c.parse_macaroon_token(&conn, &token).unwrap(); + assert_eq!(editor_row.id, editor_id.to_uuid()); + + // revoke token + revoke_tokens(&conn, editor_id); + + // verification should fail + assert!(c.parse_macaroon_token(&conn, &token).is_err()); +} -- cgit v1.2.3 From 99b5cc75a224eaeb4c4f1f5eae676bd35a17abc4 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sat, 29 Dec 2018 00:06:33 -0800 Subject: include unwrap() in tests --- rust/tests/test_auth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/tests/test_auth.rs b/rust/tests/test_auth.rs index 45956036..5b04d595 100644 --- a/rust/tests/test_auth.rs +++ b/rust/tests/test_auth.rs @@ -41,7 +41,7 @@ fn test_auth_db() { assert_eq!(editor_row.id, editor_id.to_uuid()); // revoke token - revoke_tokens(&conn, editor_id); + revoke_tokens(&conn, editor_id).unwrap(); // verification should fail assert!(c.parse_macaroon_token(&conn, &token).is_err()); -- cgit v1.2.3 From f9c15a4fc22cb87179e459a283146769e612a92b Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 13:20:02 -0800 Subject: wire-up auth config via ENV --- rust/Cargo.lock | 1 + rust/Cargo.toml | 1 + rust/src/auth.rs | 20 +++++++++++++++----- rust/src/bin/fatcat-auth.rs | 39 ++++++++++++++++++++------------------- rust/src/bin/fatcat-export.rs | 18 +----------------- rust/src/lib.rs | 26 ++++++++++++++++++-------- 6 files changed, 56 insertions(+), 49 deletions(-) (limited to 'rust') diff --git a/rust/Cargo.lock b/rust/Cargo.lock index b76367b0..817697be 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -380,6 +380,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "macaroon 0.1.1 (git+https://github.com/bnewbold/libmacaroon-rs?branch=bnewbold-broken)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index a20118d2..190177a6 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -22,6 +22,7 @@ regex = "1" lazy_static = "1.0" sha1 = { version = "0.6", features = ["std"] } macaroon = { git = "https://github.com/bnewbold/libmacaroon-rs", branch = "bnewbold-broken" } +rand = "*" # API server chrono = { version = "0.4", features = ["serde"] } diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 0fe21ebe..450a19d6 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -40,22 +40,24 @@ pub struct AuthConfectionary { } impl AuthConfectionary { - pub fn new(location: String, identifier: String, key: Vec) -> AuthConfectionary { + pub fn new(location: String, identifier: String, key_base64: String) -> Result { + let key = BASE64.decode(key_base64.as_bytes())?; let mut root_keys = HashMap::new(); root_keys.insert(identifier.clone(), key.clone()); - AuthConfectionary { + Ok(AuthConfectionary { location: location, identifier: identifier, key: key, root_keys: root_keys, - } + }) } pub fn new_dummy() -> AuthConfectionary { AuthConfectionary::new( "test.fatcat.wiki".to_string(), "dummy".to_string(), - DUMMY_KEY.to_vec()) + BASE64.encode(DUMMY_KEY), + ).unwrap() } pub fn create_token(&self, editor_id: FatCatId, expires: Option>) -> Result { @@ -180,7 +182,15 @@ impl AuthConfectionary { } } -pub fn revoke_tokens(conn: &DbConn, editor_id: FatCatId) -> Result<()>{ +pub fn create_key() -> String { + let mut key: Vec = vec![0; 32]; + for v in key.iter_mut() { + *v = rand::random() + } + BASE64.encode(&key) +} + +pub fn revoke_tokens(conn: &DbConn, editor_id: FatCatId) -> Result<()> { diesel::update(editor::table.filter(editor::id.eq(&editor_id.to_uuid()))) .set(editor::auth_epoch.eq(Utc::now())) .execute(conn)?; diff --git a/rust/src/bin/fatcat-auth.rs b/rust/src/bin/fatcat-auth.rs index 5a8f0f98..3240964f 100644 --- a/rust/src/bin/fatcat-auth.rs +++ b/rust/src/bin/fatcat-auth.rs @@ -14,12 +14,8 @@ extern crate serde_json; extern crate uuid; use clap::{App, SubCommand}; -use dotenv::dotenv; -use std::env; use diesel::prelude::*; -use diesel::r2d2::ConnectionManager; -use fatcat::ConnectionPool; use fatcat::errors::*; use fatcat::api_helpers::FatCatId; use std::str::FromStr; @@ -31,18 +27,6 @@ use std::str::FromStr; //use std::io::{BufReader, BufWriter}; -/// Instantiate a new API server with a pooled database connection -// TODO: copypasta from fatcat-export -pub fn database_worker_pool() -> Result { - dotenv().ok(); - let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); - let manager = ConnectionManager::::new(database_url); - let pool = diesel::r2d2::Pool::builder() - .build(manager) - .expect("Failed to create database pool."); - Ok(pool) -} - fn run() -> Result<()> { let m = App::new("fatcat-auth") .version(env!("CARGO_PKG_VERSION")) @@ -66,7 +50,7 @@ fn run() -> Result<()> { .about("Creates a new auth token (macaroon) for the given editor") .args_from_usage( " 'id of the editor (fatcatid, not username)' - --env-format 'outputs in a format that shells can source'" + --env-format 'outputs in a format that shells can source'" // TODO ) ) .subcommand( @@ -76,6 +60,13 @@ fn run() -> Result<()> { " 'base64-encoded token (macaroon)'" ) ) + .subcommand( + SubCommand::with_name("create-key") + .about("Creates a new auth secret key (aka, root/signing key for tokens)") + .args_from_usage( + "--env-format 'outputs in a format that shells can source'" // TODO + ) + ) .subcommand( SubCommand::with_name("revoke-tokens") .about("Resets auth_epoch for a single editor (invalidating all existing tokens)") @@ -89,8 +80,18 @@ fn run() -> Result<()> { ) .get_matches(); - let db_conn = database_worker_pool()?.get().expect("database pool"); - let confectionary = fatcat::auth::AuthConfectionary::new_dummy(); + // First, the commands with no db or confectionary needed + match m.subcommand() { + ("create-key", Some(_subm)) => { + println!("{}", fatcat::auth::create_key()); + return Ok(()) + }, + _ => (), + } + + // Then the ones that do + let db_conn = fatcat::database_worker_pool()?.get().expect("database pool"); + let confectionary = fatcat::env_confectionary()?; match m.subcommand() { ("list-editors", Some(_subm)) => { fatcat::auth::print_editors(&db_conn)?; diff --git a/rust/src/bin/fatcat-export.rs b/rust/src/bin/fatcat-export.rs index ec66ed4c..e1b930fc 100644 --- a/rust/src/bin/fatcat-export.rs +++ b/rust/src/bin/fatcat-export.rs @@ -17,15 +17,10 @@ extern crate serde_json; extern crate uuid; use clap::{App, Arg}; -use dotenv::dotenv; -use std::env; -use diesel::prelude::*; -use diesel::r2d2::ConnectionManager; use fatcat::api_entity_crud::*; use fatcat::api_helpers::*; use fatcat::errors::*; -use fatcat::ConnectionPool; use fatcat_api_spec::models::*; use std::str::FromStr; use uuid::Uuid; @@ -59,17 +54,6 @@ struct IdentRow { redirect_id: Option, } -/// Instantiate a new API server with a pooled database connection -pub fn database_worker_pool() -> Result { - dotenv().ok(); - let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); - let manager = ConnectionManager::::new(database_url); - let pool = diesel::r2d2::Pool::builder() - .build(manager) - .expect("Failed to create database pool."); - Ok(pool) -} - macro_rules! generic_loop_work { ($fn_name:ident, $entity_model:ident) => { fn $fn_name( @@ -183,7 +167,7 @@ pub fn do_export( entity_type: ExportEntityType, redirects: bool, ) -> Result<()> { - let db_pool = database_worker_pool()?; + let db_pool = fatcat::database_worker_pool()?; let buf_input = BufReader::new(std::io::stdin()); let (row_sender, row_receiver) = channel::bounded(CHANNEL_BUFFER_LEN); let (output_sender, output_receiver) = channel::bounded(CHANNEL_BUFFER_LEN); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 983645d8..233f8642 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -93,20 +93,29 @@ use dotenv::dotenv; use iron::middleware::AfterMiddleware; use iron::{Request, Response}; use std::env; +use auth::AuthConfectionary; #[cfg(feature = "postgres")] embed_migrations!("../migrations/"); pub type ConnectionPool = diesel::r2d2::Pool>; -/// Establish a direct database connection. Not currently used, but could be helpful for -/// single-threaded tests or utilities. -pub fn establish_connection() -> PgConnection { +/// Instantiate a new API server with a pooled database connection +pub fn database_worker_pool() -> Result { dotenv().ok(); - let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); - PgConnection::establish(&database_url) - .unwrap_or_else(|_| panic!("Error connecting to {}", database_url)) + let manager = ConnectionManager::::new(database_url); + let pool = diesel::r2d2::Pool::builder() + .build(manager) + .expect("Failed to create database pool."); + Ok(pool) +} + +pub fn env_confectionary() -> Result { + let auth_location = env::var("AUTH_LOCATION").expect("AUTH_LOCATION must be set"); + let auth_key = env::var("AUTH_SECRET_KEY").expect("AUTH_SECRET_KEY must be set"); + let auth_key_ident = env::var("AUTH_KEY_IDENT").expect("AUTH_KEY_IDENT must be set"); + AuthConfectionary::new(auth_location, auth_key_ident, auth_key) } /// Instantiate a new API server with a pooled database connection @@ -117,7 +126,7 @@ pub fn server() -> Result { let pool = diesel::r2d2::Pool::builder() .build(manager) .expect("Failed to create database pool."); - let confectionary = auth::AuthConfectionary::new_dummy(); + let confectionary = env_confectionary()?; Ok(api_server::Server { db_pool: pool, auth_confectionary: confectionary }) } @@ -126,7 +135,8 @@ pub fn test_server() -> Result { let database_url = env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set"); env::set_var("DATABASE_URL", database_url); - let server = server()?; + let mut server = server()?; + server.auth_confectionary = AuthConfectionary::new_dummy(); let conn = server.db_pool.get().expect("db_pool error"); // run migrations; revert latest (dummy data); re-run latest -- cgit v1.2.3 From 230032ec1a13dd3830bcffed6112c2fddabc4b6e Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 14:57:03 -0800 Subject: codegen --- rust/fatcat-api-spec/README.md | 2 +- rust/fatcat-api-spec/api.yaml | 52 +- rust/fatcat-api-spec/api/swagger.yaml | 904 ++++++++++++---------------- rust/fatcat-api-spec/src/client.rs | 959 +++++++++--------------------- rust/fatcat-api-spec/src/lib.rs | 166 +++--- rust/fatcat-api-spec/src/mimetypes.rs | 332 +++++------ rust/fatcat-api-spec/src/server.rs | 1046 +++++++++++++++------------------ 7 files changed, 1403 insertions(+), 2058 deletions(-) (limited to 'rust') diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index 41f4ae5e..bed47c45 100644 --- a/rust/fatcat-api-spec/README.md +++ b/rust/fatcat-api-spec/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2018-12-27T07:31:49.807Z +- Build date: 2018-12-31T22:21:53.785Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index 713cb116..98b9e4b0 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -549,11 +549,7 @@ definitions: role: type: string -x-entity-responses: &ENTITYRESPONSES - 400: - description: Bad Request - schema: - $ref: "#/definitions/error_response" +x-auth-responses: &AUTHRESPONSES 401: description: Not Authorized # "Authentication information is missing or invalid" schema: @@ -561,6 +557,15 @@ x-entity-responses: &ENTITYRESPONSES headers: WWW_Authenticate: type: string + 403: + description: Forbidden + schema: + $ref: "#/definitions/error_response" +x-entity-responses: &ENTITYRESPONSES + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" 404: description: Not Found schema: @@ -594,6 +599,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /container/batch: post: operationId: "create_container_batch" @@ -627,6 +633,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /container/{ident}: parameters: - name: ident @@ -676,6 +683,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_container" tags: # TAGLINE @@ -693,6 +701,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /container/rev/{rev_id}: parameters: - name: rev_id @@ -822,6 +831,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /creator: post: operationId: "create_creator" @@ -845,6 +855,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /creator/batch: post: operationId: "create_creator_batch" @@ -878,6 +889,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /creator/{ident}: parameters: - name: ident @@ -927,6 +939,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_creator" tags: # TAGLINE @@ -944,6 +957,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /creator/rev/{rev_id}: parameters: - name: rev_id @@ -1096,6 +1110,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /file: post: operationId: "create_file" @@ -1119,6 +1134,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /file/batch: post: operationId: "create_file_batch" @@ -1152,6 +1168,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /file/{ident}: parameters: - name: ident @@ -1201,6 +1218,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_file" tags: # TAGLINE @@ -1218,6 +1236,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /file/rev/{rev_id}: parameters: - name: rev_id @@ -1352,6 +1371,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /fileset: post: operationId: "create_fileset" @@ -1373,6 +1393,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /fileset/batch: post: operationId: "create_fileset_batch" @@ -1404,6 +1425,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /fileset/{ident}: parameters: - name: ident @@ -1451,6 +1473,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_fileset" tags: # TAGLINE @@ -1466,6 +1489,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /fileset/rev/{rev_id}: parameters: - name: rev_id @@ -1566,6 +1590,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /webcapture: post: operationId: "create_webcapture" @@ -1587,6 +1612,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /webcapture/batch: post: operationId: "create_webcapture_batch" @@ -1618,6 +1644,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /webcapture/{ident}: parameters: - name: ident @@ -1665,6 +1692,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_webcapture" tags: # TAGLINE @@ -1680,6 +1708,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /webcapture/rev/{rev_id}: parameters: - name: rev_id @@ -1780,6 +1809,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /release: post: operationId: "create_release" @@ -1801,6 +1831,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /release/batch: post: operationId: "create_release_batch" @@ -1832,6 +1863,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /release/{ident}: parameters: - name: ident @@ -1879,6 +1911,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_release" tags: # TAGLINE @@ -1894,6 +1927,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /release/rev/{rev_id}: parameters: - name: rev_id @@ -2109,6 +2143,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /work: post: operationId: "create_work" @@ -2130,6 +2165,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /work/batch: post: operationId: "create_work_batch" @@ -2161,6 +2197,7 @@ paths: items: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /work/{ident}: parameters: - name: ident @@ -2208,6 +2245,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES delete: operationId: "delete_work" tags: # TAGLINE @@ -2223,6 +2261,7 @@ paths: schema: $ref: "#/definitions/entity_edit" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /work/rev/{rev_id}: parameters: - name: rev_id @@ -2346,6 +2385,7 @@ paths: schema: $ref: "#/definitions/success" <<: *ENTITYRESPONSES + <<: *AUTHRESPONSES /editor/{editor_id}: parameters: - name: editor_id @@ -2422,6 +2462,7 @@ paths: description: Generic Error schema: $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES /editgroup/{editgroup_id}: parameters: - name: editgroup_id @@ -2480,6 +2521,7 @@ paths: description: Generic Error schema: $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES /changelog: parameters: - name: limit diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index 7e5508b9..670d3551 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -76,6 +76,15 @@ paths: uppercase_operation_id: "CREATE_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -169,6 +178,15 @@ paths: uppercase_operation_id: "CREATE_CONTAINER_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_CONTAINER_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -241,18 +259,6 @@ paths: uppercase_operation_id: "GET_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CONTAINER" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -336,6 +342,15 @@ paths: uppercase_operation_id: "UPDATE_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "UPDATE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -410,6 +425,15 @@ paths: uppercase_operation_id: "DELETE_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -486,18 +510,6 @@ paths: uppercase_operation_id: "GET_CONTAINER_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CONTAINER_REVISION" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -561,18 +573,6 @@ paths: uppercase_operation_id: "GET_CONTAINER_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CONTAINER_HISTORY" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -629,18 +629,6 @@ paths: uppercase_operation_id: "GET_CONTAINER_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CONTAINER_REDIRECTS" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -718,18 +706,6 @@ paths: uppercase_operation_id: "LOOKUP_CONTAINER" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "LOOKUP_CONTAINER" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -788,18 +764,6 @@ paths: uppercase_operation_id: "GET_CONTAINER_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CONTAINER_EDIT" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -869,6 +833,15 @@ paths: uppercase_operation_id: "DELETE_CONTAINER_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_CONTAINER_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -947,6 +920,15 @@ paths: uppercase_operation_id: "CREATE_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1040,6 +1022,15 @@ paths: uppercase_operation_id: "CREATE_CREATOR_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_CREATOR_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1112,18 +1103,6 @@ paths: uppercase_operation_id: "GET_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CREATOR" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -1207,6 +1186,15 @@ paths: uppercase_operation_id: "UPDATE_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "UPDATE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1281,6 +1269,15 @@ paths: uppercase_operation_id: "DELETE_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1357,18 +1354,6 @@ paths: uppercase_operation_id: "GET_CREATOR_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CREATOR_REVISION" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -1432,18 +1417,6 @@ paths: uppercase_operation_id: "GET_CREATOR_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CREATOR_HISTORY" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -1508,18 +1481,6 @@ paths: uppercase_operation_id: "GET_CREATOR_RELEASES" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CREATOR_RELEASES" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -1576,18 +1537,6 @@ paths: uppercase_operation_id: "GET_CREATOR_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CREATOR_REDIRECTS" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -1665,18 +1614,6 @@ paths: uppercase_operation_id: "LOOKUP_CREATOR" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "LOOKUP_CREATOR" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -1735,18 +1672,6 @@ paths: uppercase_operation_id: "GET_CREATOR_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_CREATOR_EDIT" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -1816,6 +1741,15 @@ paths: uppercase_operation_id: "DELETE_CREATOR_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_CREATOR_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1894,6 +1828,15 @@ paths: uppercase_operation_id: "CREATE_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -1987,6 +1930,15 @@ paths: uppercase_operation_id: "CREATE_FILE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_FILE_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2059,18 +2011,6 @@ paths: uppercase_operation_id: "GET_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_FILE" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -2154,6 +2094,15 @@ paths: uppercase_operation_id: "UPDATE_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "UPDATE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2228,6 +2177,15 @@ paths: uppercase_operation_id: "DELETE_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2304,18 +2262,6 @@ paths: uppercase_operation_id: "GET_FILE_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_FILE_REVISION" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -2379,18 +2325,6 @@ paths: uppercase_operation_id: "GET_FILE_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_FILE_HISTORY" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -2447,18 +2381,6 @@ paths: uppercase_operation_id: "GET_FILE_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_FILE_REDIRECTS" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -2549,18 +2471,6 @@ paths: uppercase_operation_id: "LOOKUP_FILE" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "LOOKUP_FILE" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -2619,18 +2529,6 @@ paths: uppercase_operation_id: "GET_FILE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_FILE_EDIT" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -2700,6 +2598,15 @@ paths: uppercase_operation_id: "DELETE_FILE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_FILE_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2778,6 +2685,15 @@ paths: uppercase_operation_id: "CREATE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_FILESET" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2869,6 +2785,15 @@ paths: uppercase_operation_id: "CREATE_FILESET_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_FILESET_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -2939,18 +2864,6 @@ paths: uppercase_operation_id: "GET_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_FILESET" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -3034,6 +2947,15 @@ paths: uppercase_operation_id: "UPDATE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "UPDATE_FILESET" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3106,6 +3028,15 @@ paths: uppercase_operation_id: "DELETE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_FILESET" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3180,18 +3111,6 @@ paths: uppercase_operation_id: "GET_FILESET_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_FILESET_REVISION" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -3255,18 +3174,6 @@ paths: uppercase_operation_id: "GET_FILESET_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_FILESET_HISTORY" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -3323,18 +3230,6 @@ paths: uppercase_operation_id: "GET_FILESET_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_FILESET_REDIRECTS" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -3393,18 +3288,6 @@ paths: uppercase_operation_id: "GET_FILESET_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_FILESET_EDIT" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -3474,6 +3357,15 @@ paths: uppercase_operation_id: "DELETE_FILESET_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_FILESET_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3552,6 +3444,15 @@ paths: uppercase_operation_id: "CREATE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_WEBCAPTURE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3643,6 +3544,15 @@ paths: uppercase_operation_id: "CREATE_WEBCAPTURE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_WEBCAPTURE_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3713,18 +3623,6 @@ paths: uppercase_operation_id: "GET_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WEBCAPTURE" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -3808,6 +3706,15 @@ paths: uppercase_operation_id: "UPDATE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "UPDATE_WEBCAPTURE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3880,6 +3787,15 @@ paths: uppercase_operation_id: "DELETE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_WEBCAPTURE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -3954,18 +3870,6 @@ paths: uppercase_operation_id: "GET_WEBCAPTURE_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WEBCAPTURE_REVISION" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -4029,18 +3933,6 @@ paths: uppercase_operation_id: "GET_WEBCAPTURE_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WEBCAPTURE_HISTORY" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -4097,18 +3989,6 @@ paths: uppercase_operation_id: "GET_WEBCAPTURE_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WEBCAPTURE_REDIRECTS" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -4167,18 +4047,6 @@ paths: uppercase_operation_id: "GET_WEBCAPTURE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WEBCAPTURE_EDIT" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -4248,6 +4116,15 @@ paths: uppercase_operation_id: "DELETE_WEBCAPTURE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_WEBCAPTURE_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4326,6 +4203,15 @@ paths: uppercase_operation_id: "CREATE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4417,6 +4303,15 @@ paths: uppercase_operation_id: "CREATE_RELEASE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_RELEASE_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4482,20 +4377,8 @@ paths: description: "Bad Request" schema: $ref: "#/definitions/error_response" - x-responseId: "BadRequest" - x-uppercaseResponseId: "BAD_REQUEST" - uppercase_operation_id: "GET_RELEASE" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" uppercase_operation_id: "GET_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true @@ -4582,6 +4465,15 @@ paths: uppercase_operation_id: "UPDATE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "UPDATE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4654,6 +4546,15 @@ paths: uppercase_operation_id: "DELETE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -4728,18 +4629,6 @@ paths: uppercase_operation_id: "GET_RELEASE_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_RELEASE_REVISION" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -4803,18 +4692,6 @@ paths: uppercase_operation_id: "GET_RELEASE_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_RELEASE_HISTORY" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -4879,18 +4756,6 @@ paths: uppercase_operation_id: "GET_RELEASE_FILES" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_RELEASE_FILES" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -4955,18 +4820,6 @@ paths: uppercase_operation_id: "GET_RELEASE_FILESETS" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_RELEASE_FILESETS" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -5031,18 +4884,6 @@ paths: uppercase_operation_id: "GET_RELEASE_WEBCAPTURES" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_RELEASE_WEBCAPTURES" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -5099,18 +4940,6 @@ paths: uppercase_operation_id: "GET_RELEASE_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_RELEASE_REDIRECTS" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -5210,18 +5039,6 @@ paths: uppercase_operation_id: "LOOKUP_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "LOOKUP_RELEASE" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -5280,18 +5097,6 @@ paths: uppercase_operation_id: "GET_RELEASE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_RELEASE_EDIT" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -5361,6 +5166,15 @@ paths: uppercase_operation_id: "DELETE_RELEASE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_RELEASE_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5439,6 +5253,15 @@ paths: uppercase_operation_id: "CREATE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5530,6 +5353,15 @@ paths: uppercase_operation_id: "CREATE_WORK_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_WORK_BATCH" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5600,18 +5432,6 @@ paths: uppercase_operation_id: "GET_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WORK" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -5695,6 +5515,15 @@ paths: uppercase_operation_id: "UPDATE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "UPDATE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5767,6 +5596,15 @@ paths: uppercase_operation_id: "DELETE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -5841,18 +5679,6 @@ paths: uppercase_operation_id: "GET_WORK_REVISION" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WORK_REVISION" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -5916,18 +5742,6 @@ paths: uppercase_operation_id: "GET_WORK_HISTORY" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WORK_HISTORY" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -5984,18 +5798,6 @@ paths: uppercase_operation_id: "GET_WORK_REDIRECTS" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WORK_REDIRECTS" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -6060,18 +5862,6 @@ paths: uppercase_operation_id: "GET_WORK_RELEASES" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WORK_RELEASES" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -6130,18 +5920,6 @@ paths: uppercase_operation_id: "GET_WORK_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true - 401: - description: "Not Authorized" - schema: - $ref: "#/definitions/error_response" - headers: - WWW_Authenticate: - type: "string" - x-responseId: "NotAuthorized" - x-uppercaseResponseId: "NOT_AUTHORIZED" - uppercase_operation_id: "GET_WORK_EDIT" - uppercase_data_type: "ERRORRESPONSE" - producesJson: true 404: description: "Not Found" schema: @@ -6211,6 +5989,15 @@ paths: uppercase_operation_id: "DELETE_WORK_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "DELETE_WORK_EDIT" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -6377,6 +6164,27 @@ paths: uppercase_operation_id: "CREATE_EDITGROUP" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "CREATE_EDITGROUP" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "CREATE_EDITGROUP" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 500: description: "Generic Error" schema: @@ -6485,6 +6293,27 @@ paths: uppercase_operation_id: "ACCEPT_EDITGROUP" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "ACCEPT_EDITGROUP" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "ACCEPT_EDITGROUP" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 404: description: "Not Found" schema: @@ -8466,11 +8295,7 @@ x-entity-props: edit_extra: type: "object" additionalProperties: {} -x-entity-responses: - 400: - description: "Bad Request" - schema: - $ref: "#/definitions/error_response" +x-auth-responses: 401: description: "Not Authorized" schema: @@ -8478,6 +8303,15 @@ x-entity-responses: headers: WWW_Authenticate: type: "string" + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" +x-entity-responses: + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" 404: description: "Not Found" schema: diff --git a/rust/fatcat-api-spec/src/client.rs b/rust/fatcat-api-spec/src/client.rs index 1e889092..b67e193a 100644 --- a/rust/fatcat-api-spec/src/client.rs +++ b/rust/fatcat-api-spec/src/client.rs @@ -227,6 +227,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateContainerResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -322,6 +329,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateContainerBatchResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -405,6 +419,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteContainerResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -484,6 +505,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteContainerEditResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -554,21 +582,6 @@ impl Api for Client { Ok(GetContainerResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetContainerResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -633,21 +646,6 @@ impl Api for Client { Ok(GetContainerEditResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetContainerEditResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -716,21 +714,6 @@ impl Api for Client { Ok(GetContainerHistoryResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetContainerHistoryResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -795,21 +778,6 @@ impl Api for Client { Ok(GetContainerRedirectsResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetContainerRedirectsResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -886,21 +854,6 @@ impl Api for Client { Ok(GetContainerRevisionResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetContainerRevisionResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -981,21 +934,6 @@ impl Api for Client { Ok(LookupContainerResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(LookupContainerResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1090,6 +1028,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateContainerResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1177,6 +1122,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateCreatorResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1272,6 +1224,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateCreatorBatchResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1355,6 +1314,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteCreatorResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1434,6 +1400,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteCreatorEditResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1504,21 +1477,6 @@ impl Api for Client { Ok(GetCreatorResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetCreatorResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1583,21 +1541,6 @@ impl Api for Client { Ok(GetCreatorEditResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetCreatorEditResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1666,21 +1609,6 @@ impl Api for Client { Ok(GetCreatorHistoryResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetCreatorHistoryResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1745,21 +1673,6 @@ impl Api for Client { Ok(GetCreatorRedirectsResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetCreatorRedirectsResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1828,21 +1741,6 @@ impl Api for Client { Ok(GetCreatorReleasesResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetCreatorReleasesResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -1919,21 +1817,6 @@ impl Api for Client { Ok(GetCreatorRevisionResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetCreatorRevisionResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2014,21 +1897,6 @@ impl Api for Client { Ok(LookupCreatorResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(LookupCreatorResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2123,6 +1991,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateCreatorResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2315,6 +2190,28 @@ impl Api for Client { Ok(AcceptEditgroupResponse::BadRequest(body)) } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(AcceptEditgroupResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AcceptEditgroupResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2387,13 +2284,35 @@ impl Api for Client { Ok(CreateEditgroupResponse::BadRequest(body)) } - 500 => { + 401 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::(&buf)?; - - Ok(CreateEditgroupResponse::GenericError(body)) - } + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateEditgroupResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateEditgroupResponse::Forbidden(body)) + } + 500 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateEditgroupResponse::GenericError(body)) + } code => { let mut buf = [0; 100]; let debug_body = match response.read(&mut buf) { @@ -2633,6 +2552,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateFileResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2728,6 +2654,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateFileBatchResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2811,6 +2744,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteFileResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2890,6 +2830,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteFileEditResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -2960,21 +2907,6 @@ impl Api for Client { Ok(GetFileResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetFileResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3039,21 +2971,6 @@ impl Api for Client { Ok(GetFileEditResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetFileEditResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3122,21 +3039,6 @@ impl Api for Client { Ok(GetFileHistoryResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetFileHistoryResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3201,21 +3103,6 @@ impl Api for Client { Ok(GetFileRedirectsResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetFileRedirectsResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3292,21 +3179,6 @@ impl Api for Client { Ok(GetFileRevisionResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetFileRevisionResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3390,21 +3262,6 @@ impl Api for Client { Ok(LookupFileResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(LookupFileResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3499,6 +3356,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateFileResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3586,6 +3450,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateFilesetResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3681,6 +3552,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateFilesetBatchResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3764,6 +3642,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteFilesetResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3843,6 +3728,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteFilesetEditResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3913,21 +3805,6 @@ impl Api for Client { Ok(GetFilesetResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetFilesetResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -3992,21 +3869,6 @@ impl Api for Client { Ok(GetFilesetEditResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetFilesetEditResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4075,21 +3937,6 @@ impl Api for Client { Ok(GetFilesetHistoryResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetFilesetHistoryResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4154,21 +4001,6 @@ impl Api for Client { Ok(GetFilesetRedirectsResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetFilesetRedirectsResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4245,21 +4077,6 @@ impl Api for Client { Ok(GetFilesetRevisionResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetFilesetRevisionResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4354,6 +4171,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateFilesetResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4441,6 +4265,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateReleaseResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4536,6 +4367,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateReleaseBatchResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4619,6 +4457,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateWorkResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4702,6 +4547,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteReleaseResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4781,6 +4633,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteReleaseEditResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -4851,22 +4710,7 @@ impl Api for Client { Ok(GetReleaseResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetReleaseResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } - 404 => { + 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::(&buf)?; @@ -4930,21 +4774,6 @@ impl Api for Client { Ok(GetReleaseEditResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetReleaseEditResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5013,21 +4842,6 @@ impl Api for Client { Ok(GetReleaseFilesResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetReleaseFilesResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5096,21 +4910,6 @@ impl Api for Client { Ok(GetReleaseFilesetsResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetReleaseFilesetsResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5179,21 +4978,6 @@ impl Api for Client { Ok(GetReleaseHistoryResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetReleaseHistoryResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5258,21 +5042,6 @@ impl Api for Client { Ok(GetReleaseRedirectsResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetReleaseRedirectsResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5349,21 +5118,6 @@ impl Api for Client { Ok(GetReleaseRevisionResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetReleaseRevisionResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5432,21 +5186,6 @@ impl Api for Client { Ok(GetReleaseWebcapturesResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetReleaseWebcapturesResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5539,21 +5278,6 @@ impl Api for Client { Ok(LookupReleaseResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(LookupReleaseResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5648,6 +5372,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateReleaseResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5740,6 +5471,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateWebcaptureResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5835,6 +5573,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateWebcaptureBatchResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5918,6 +5663,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteWebcaptureResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -5997,6 +5749,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteWebcaptureEditResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6067,21 +5826,6 @@ impl Api for Client { Ok(GetWebcaptureResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWebcaptureResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6146,21 +5890,6 @@ impl Api for Client { Ok(GetWebcaptureEditResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWebcaptureEditResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6229,21 +5958,6 @@ impl Api for Client { Ok(GetWebcaptureHistoryResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWebcaptureHistoryResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6308,21 +6022,6 @@ impl Api for Client { Ok(GetWebcaptureRedirectsResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWebcaptureRedirectsResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6399,21 +6098,6 @@ impl Api for Client { Ok(GetWebcaptureRevisionResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWebcaptureRevisionResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6508,6 +6192,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateWebcaptureResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6603,6 +6294,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(CreateWorkBatchResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6686,6 +6384,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteWorkResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6765,6 +6470,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(DeleteWorkEditResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6835,21 +6547,6 @@ impl Api for Client { Ok(GetWorkResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWorkResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6914,21 +6611,6 @@ impl Api for Client { Ok(GetWorkEditResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWorkEditResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -6997,21 +6679,6 @@ impl Api for Client { Ok(GetWorkHistoryResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWorkHistoryResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -7076,21 +6743,6 @@ impl Api for Client { Ok(GetWorkRedirectsResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWorkRedirectsResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -7159,21 +6811,6 @@ impl Api for Client { Ok(GetWorkReleasesResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWorkReleasesResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -7250,21 +6887,6 @@ impl Api for Client { Ok(GetWorkRevisionResponse::BadRequest(body)) } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetWorkRevisionResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; @@ -7359,6 +6981,13 @@ impl Api for Client { www_authenticate: response_www_authenticate.0.clone(), }) } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateWorkResponse::Forbidden(body)) + } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; diff --git a/rust/fatcat-api-spec/src/lib.rs b/rust/fatcat-api-spec/src/lib.rs index 16b40999..c6126c9c 100644 --- a/rust/fatcat-api-spec/src/lib.rs +++ b/rust/fatcat-api-spec/src/lib.rs @@ -40,6 +40,8 @@ pub enum CreateContainerResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -54,6 +56,8 @@ pub enum CreateContainerBatchResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -68,6 +72,8 @@ pub enum DeleteContainerResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -82,6 +88,8 @@ pub enum DeleteContainerEditResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -94,8 +102,6 @@ pub enum GetContainerResponse { FoundEntity(models::ContainerEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -108,8 +114,6 @@ pub enum GetContainerEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -122,8 +126,6 @@ pub enum GetContainerHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -136,8 +138,6 @@ pub enum GetContainerRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -150,8 +150,6 @@ pub enum GetContainerRevisionResponse { FoundEntityRevision(models::ContainerEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -164,8 +162,6 @@ pub enum LookupContainerResponse { FoundEntity(models::ContainerEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -180,6 +176,8 @@ pub enum UpdateContainerResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -194,6 +192,8 @@ pub enum CreateCreatorResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -208,6 +208,8 @@ pub enum CreateCreatorBatchResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -222,6 +224,8 @@ pub enum DeleteCreatorResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -236,6 +240,8 @@ pub enum DeleteCreatorEditResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -248,8 +254,6 @@ pub enum GetCreatorResponse { FoundEntity(models::CreatorEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -262,8 +266,6 @@ pub enum GetCreatorEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -276,8 +278,6 @@ pub enum GetCreatorHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -290,8 +290,6 @@ pub enum GetCreatorRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -304,8 +302,6 @@ pub enum GetCreatorReleasesResponse { Found(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -318,8 +314,6 @@ pub enum GetCreatorRevisionResponse { FoundEntityRevision(models::CreatorEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -332,8 +326,6 @@ pub enum LookupCreatorResponse { FoundEntity(models::CreatorEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -348,6 +340,8 @@ pub enum UpdateCreatorResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -384,6 +378,10 @@ pub enum AcceptEditgroupResponse { MergedSuccessfully(models::Success), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Edit Conflict @@ -398,6 +396,10 @@ pub enum CreateEditgroupResponse { SuccessfullyCreated(models::Editgroup), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Generic Error GenericError(models::ErrorResponse), } @@ -440,6 +442,8 @@ pub enum CreateFileResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -454,6 +458,8 @@ pub enum CreateFileBatchResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -468,6 +474,8 @@ pub enum DeleteFileResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -482,6 +490,8 @@ pub enum DeleteFileEditResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -494,8 +504,6 @@ pub enum GetFileResponse { FoundEntity(models::FileEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -508,8 +516,6 @@ pub enum GetFileEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -522,8 +528,6 @@ pub enum GetFileHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -536,8 +540,6 @@ pub enum GetFileRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -550,8 +552,6 @@ pub enum GetFileRevisionResponse { FoundEntityRevision(models::FileEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -564,8 +564,6 @@ pub enum LookupFileResponse { FoundEntity(models::FileEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -580,6 +578,8 @@ pub enum UpdateFileResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -594,6 +594,8 @@ pub enum CreateFilesetResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -608,6 +610,8 @@ pub enum CreateFilesetBatchResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -622,6 +626,8 @@ pub enum DeleteFilesetResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -636,6 +642,8 @@ pub enum DeleteFilesetEditResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -648,8 +656,6 @@ pub enum GetFilesetResponse { FoundEntity(models::FilesetEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -662,8 +668,6 @@ pub enum GetFilesetEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -676,8 +680,6 @@ pub enum GetFilesetHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -690,8 +692,6 @@ pub enum GetFilesetRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -704,8 +704,6 @@ pub enum GetFilesetRevisionResponse { FoundEntityRevision(models::FilesetEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -720,6 +718,8 @@ pub enum UpdateFilesetResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -734,6 +734,8 @@ pub enum CreateReleaseResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -748,6 +750,8 @@ pub enum CreateReleaseBatchResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -762,6 +766,8 @@ pub enum CreateWorkResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -776,6 +782,8 @@ pub enum DeleteReleaseResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -790,6 +798,8 @@ pub enum DeleteReleaseEditResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -802,8 +812,6 @@ pub enum GetReleaseResponse { FoundEntity(models::ReleaseEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -816,8 +824,6 @@ pub enum GetReleaseEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -830,8 +836,6 @@ pub enum GetReleaseFilesResponse { Found(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -844,8 +848,6 @@ pub enum GetReleaseFilesetsResponse { Found(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -858,8 +860,6 @@ pub enum GetReleaseHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -872,8 +872,6 @@ pub enum GetReleaseRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -886,8 +884,6 @@ pub enum GetReleaseRevisionResponse { FoundEntityRevision(models::ReleaseEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -900,8 +896,6 @@ pub enum GetReleaseWebcapturesResponse { Found(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -914,8 +908,6 @@ pub enum LookupReleaseResponse { FoundEntity(models::ReleaseEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -930,6 +922,8 @@ pub enum UpdateReleaseResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -944,6 +938,8 @@ pub enum CreateWebcaptureResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -958,6 +954,8 @@ pub enum CreateWebcaptureBatchResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -972,6 +970,8 @@ pub enum DeleteWebcaptureResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -986,6 +986,8 @@ pub enum DeleteWebcaptureEditResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -998,8 +1000,6 @@ pub enum GetWebcaptureResponse { FoundEntity(models::WebcaptureEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1012,8 +1012,6 @@ pub enum GetWebcaptureEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1026,8 +1024,6 @@ pub enum GetWebcaptureHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1040,8 +1036,6 @@ pub enum GetWebcaptureRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1054,8 +1048,6 @@ pub enum GetWebcaptureRevisionResponse { FoundEntityRevision(models::WebcaptureEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1070,6 +1062,8 @@ pub enum UpdateWebcaptureResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1084,6 +1078,8 @@ pub enum CreateWorkBatchResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1098,6 +1094,8 @@ pub enum DeleteWorkResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1112,6 +1110,8 @@ pub enum DeleteWorkEditResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1124,8 +1124,6 @@ pub enum GetWorkResponse { FoundEntity(models::WorkEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1138,8 +1136,6 @@ pub enum GetWorkEditResponse { FoundEdit(models::EntityEdit), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1152,8 +1148,6 @@ pub enum GetWorkHistoryResponse { FoundEntityHistory(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1166,8 +1160,6 @@ pub enum GetWorkRedirectsResponse { FoundEntityRedirects(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1180,8 +1172,6 @@ pub enum GetWorkReleasesResponse { Found(Vec), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1194,8 +1184,6 @@ pub enum GetWorkRevisionResponse { FoundEntityRevision(models::WorkEntity), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -1210,6 +1198,8 @@ pub enum UpdateWorkResponse { BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error diff --git a/rust/fatcat-api-spec/src/mimetypes.rs b/rust/fatcat-api-spec/src/mimetypes.rs index 772a1066..77a66c46 100644 --- a/rust/fatcat-api-spec/src/mimetypes.rs +++ b/rust/fatcat-api-spec/src/mimetypes.rs @@ -17,6 +17,10 @@ pub mod responses { pub static ref CREATE_CONTAINER_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateContainer + lazy_static! { + pub static ref CREATE_CONTAINER_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateContainer lazy_static! { pub static ref CREATE_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); } @@ -37,6 +41,10 @@ pub mod responses { pub static ref CREATE_CONTAINER_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateContainerBatch + lazy_static! { + pub static ref CREATE_CONTAINER_BATCH_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateContainerBatch lazy_static! { pub static ref CREATE_CONTAINER_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -57,6 +65,10 @@ pub mod responses { pub static ref DELETE_CONTAINER_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteContainer + lazy_static! { + pub static ref DELETE_CONTAINER_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteContainer lazy_static! { pub static ref DELETE_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); } @@ -77,6 +89,10 @@ pub mod responses { pub static ref DELETE_CONTAINER_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteContainerEdit + lazy_static! { + pub static ref DELETE_CONTAINER_EDIT_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteContainerEdit lazy_static! { pub static ref DELETE_CONTAINER_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -93,10 +109,6 @@ pub mod responses { pub static ref GET_CONTAINER_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetContainer - lazy_static! { - pub static ref GET_CONTAINER_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetContainer lazy_static! { pub static ref GET_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); } @@ -113,10 +125,6 @@ pub mod responses { pub static ref GET_CONTAINER_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetContainerEdit - lazy_static! { - pub static ref GET_CONTAINER_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetContainerEdit lazy_static! { pub static ref GET_CONTAINER_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -133,10 +141,6 @@ pub mod responses { pub static ref GET_CONTAINER_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetContainerHistory - lazy_static! { - pub static ref GET_CONTAINER_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetContainerHistory lazy_static! { pub static ref GET_CONTAINER_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -153,10 +157,6 @@ pub mod responses { pub static ref GET_CONTAINER_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetContainerRedirects - lazy_static! { - pub static ref GET_CONTAINER_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetContainerRedirects lazy_static! { pub static ref GET_CONTAINER_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -173,10 +173,6 @@ pub mod responses { pub static ref GET_CONTAINER_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetContainerRevision - lazy_static! { - pub static ref GET_CONTAINER_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetContainerRevision lazy_static! { pub static ref GET_CONTAINER_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -193,10 +189,6 @@ pub mod responses { pub static ref LOOKUP_CONTAINER_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for LookupContainer - lazy_static! { - pub static ref LOOKUP_CONTAINER_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for LookupContainer lazy_static! { pub static ref LOOKUP_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); } @@ -217,6 +209,10 @@ pub mod responses { pub static ref UPDATE_CONTAINER_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateContainer + lazy_static! { + pub static ref UPDATE_CONTAINER_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateContainer lazy_static! { pub static ref UPDATE_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); } @@ -237,6 +233,10 @@ pub mod responses { pub static ref CREATE_CREATOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateCreator + lazy_static! { + pub static ref CREATE_CREATOR_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateCreator lazy_static! { pub static ref CREATE_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); } @@ -257,6 +257,10 @@ pub mod responses { pub static ref CREATE_CREATOR_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateCreatorBatch + lazy_static! { + pub static ref CREATE_CREATOR_BATCH_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateCreatorBatch lazy_static! { pub static ref CREATE_CREATOR_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -277,6 +281,10 @@ pub mod responses { pub static ref DELETE_CREATOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteCreator + lazy_static! { + pub static ref DELETE_CREATOR_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteCreator lazy_static! { pub static ref DELETE_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); } @@ -297,6 +305,10 @@ pub mod responses { pub static ref DELETE_CREATOR_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteCreatorEdit + lazy_static! { + pub static ref DELETE_CREATOR_EDIT_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteCreatorEdit lazy_static! { pub static ref DELETE_CREATOR_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -313,10 +325,6 @@ pub mod responses { pub static ref GET_CREATOR_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreator - lazy_static! { - pub static ref GET_CREATOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetCreator lazy_static! { pub static ref GET_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); } @@ -333,10 +341,6 @@ pub mod responses { pub static ref GET_CREATOR_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreatorEdit - lazy_static! { - pub static ref GET_CREATOR_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetCreatorEdit lazy_static! { pub static ref GET_CREATOR_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -353,10 +357,6 @@ pub mod responses { pub static ref GET_CREATOR_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreatorHistory - lazy_static! { - pub static ref GET_CREATOR_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetCreatorHistory lazy_static! { pub static ref GET_CREATOR_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -373,10 +373,6 @@ pub mod responses { pub static ref GET_CREATOR_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreatorRedirects - lazy_static! { - pub static ref GET_CREATOR_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetCreatorRedirects lazy_static! { pub static ref GET_CREATOR_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -393,10 +389,6 @@ pub mod responses { pub static ref GET_CREATOR_RELEASES_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreatorReleases - lazy_static! { - pub static ref GET_CREATOR_RELEASES_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetCreatorReleases lazy_static! { pub static ref GET_CREATOR_RELEASES_NOT_FOUND: Mime = mime!(Application / Json); } @@ -413,10 +405,6 @@ pub mod responses { pub static ref GET_CREATOR_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetCreatorRevision - lazy_static! { - pub static ref GET_CREATOR_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetCreatorRevision lazy_static! { pub static ref GET_CREATOR_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -433,10 +421,6 @@ pub mod responses { pub static ref LOOKUP_CREATOR_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for LookupCreator - lazy_static! { - pub static ref LOOKUP_CREATOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for LookupCreator lazy_static! { pub static ref LOOKUP_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); } @@ -457,6 +441,10 @@ pub mod responses { pub static ref UPDATE_CREATOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateCreator + lazy_static! { + pub static ref UPDATE_CREATOR_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateCreator lazy_static! { pub static ref UPDATE_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); } @@ -505,6 +493,14 @@ pub mod responses { pub static ref ACCEPT_EDITGROUP_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for AcceptEditgroup + lazy_static! { + pub static ref ACCEPT_EDITGROUP_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AcceptEditgroup + lazy_static! { + pub static ref ACCEPT_EDITGROUP_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AcceptEditgroup lazy_static! { pub static ref ACCEPT_EDITGROUP_NOT_FOUND: Mime = mime!(Application / Json); } @@ -525,6 +521,14 @@ pub mod responses { pub static ref CREATE_EDITGROUP_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateEditgroup + lazy_static! { + pub static ref CREATE_EDITGROUP_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateEditgroup + lazy_static! { + pub static ref CREATE_EDITGROUP_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateEditgroup lazy_static! { pub static ref CREATE_EDITGROUP_GENERIC_ERROR: Mime = mime!(Application / Json); } @@ -577,6 +581,10 @@ pub mod responses { pub static ref CREATE_FILE_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateFile + lazy_static! { + pub static ref CREATE_FILE_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateFile lazy_static! { pub static ref CREATE_FILE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -597,6 +605,10 @@ pub mod responses { pub static ref CREATE_FILE_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateFileBatch + lazy_static! { + pub static ref CREATE_FILE_BATCH_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateFileBatch lazy_static! { pub static ref CREATE_FILE_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -617,6 +629,10 @@ pub mod responses { pub static ref DELETE_FILE_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteFile + lazy_static! { + pub static ref DELETE_FILE_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFile lazy_static! { pub static ref DELETE_FILE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -637,6 +653,10 @@ pub mod responses { pub static ref DELETE_FILE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteFileEdit + lazy_static! { + pub static ref DELETE_FILE_EDIT_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFileEdit lazy_static! { pub static ref DELETE_FILE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -653,10 +673,6 @@ pub mod responses { pub static ref GET_FILE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFile - lazy_static! { - pub static ref GET_FILE_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetFile lazy_static! { pub static ref GET_FILE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -673,10 +689,6 @@ pub mod responses { pub static ref GET_FILE_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFileEdit - lazy_static! { - pub static ref GET_FILE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetFileEdit lazy_static! { pub static ref GET_FILE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -693,10 +705,6 @@ pub mod responses { pub static ref GET_FILE_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFileHistory - lazy_static! { - pub static ref GET_FILE_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetFileHistory lazy_static! { pub static ref GET_FILE_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -713,10 +721,6 @@ pub mod responses { pub static ref GET_FILE_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFileRedirects - lazy_static! { - pub static ref GET_FILE_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetFileRedirects lazy_static! { pub static ref GET_FILE_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -733,10 +737,6 @@ pub mod responses { pub static ref GET_FILE_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFileRevision - lazy_static! { - pub static ref GET_FILE_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetFileRevision lazy_static! { pub static ref GET_FILE_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -753,10 +753,6 @@ pub mod responses { pub static ref LOOKUP_FILE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for LookupFile - lazy_static! { - pub static ref LOOKUP_FILE_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for LookupFile lazy_static! { pub static ref LOOKUP_FILE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -777,6 +773,10 @@ pub mod responses { pub static ref UPDATE_FILE_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateFile + lazy_static! { + pub static ref UPDATE_FILE_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateFile lazy_static! { pub static ref UPDATE_FILE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -797,6 +797,10 @@ pub mod responses { pub static ref CREATE_FILESET_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateFileset + lazy_static! { + pub static ref CREATE_FILESET_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateFileset lazy_static! { pub static ref CREATE_FILESET_NOT_FOUND: Mime = mime!(Application / Json); } @@ -817,6 +821,10 @@ pub mod responses { pub static ref CREATE_FILESET_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateFilesetBatch + lazy_static! { + pub static ref CREATE_FILESET_BATCH_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateFilesetBatch lazy_static! { pub static ref CREATE_FILESET_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -837,6 +845,10 @@ pub mod responses { pub static ref DELETE_FILESET_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteFileset + lazy_static! { + pub static ref DELETE_FILESET_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFileset lazy_static! { pub static ref DELETE_FILESET_NOT_FOUND: Mime = mime!(Application / Json); } @@ -857,6 +869,10 @@ pub mod responses { pub static ref DELETE_FILESET_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteFilesetEdit + lazy_static! { + pub static ref DELETE_FILESET_EDIT_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFilesetEdit lazy_static! { pub static ref DELETE_FILESET_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -873,10 +889,6 @@ pub mod responses { pub static ref GET_FILESET_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFileset - lazy_static! { - pub static ref GET_FILESET_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetFileset lazy_static! { pub static ref GET_FILESET_NOT_FOUND: Mime = mime!(Application / Json); } @@ -893,10 +905,6 @@ pub mod responses { pub static ref GET_FILESET_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFilesetEdit - lazy_static! { - pub static ref GET_FILESET_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetFilesetEdit lazy_static! { pub static ref GET_FILESET_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -913,10 +921,6 @@ pub mod responses { pub static ref GET_FILESET_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFilesetHistory - lazy_static! { - pub static ref GET_FILESET_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetFilesetHistory lazy_static! { pub static ref GET_FILESET_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -933,10 +937,6 @@ pub mod responses { pub static ref GET_FILESET_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFilesetRedirects - lazy_static! { - pub static ref GET_FILESET_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetFilesetRedirects lazy_static! { pub static ref GET_FILESET_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -953,10 +953,6 @@ pub mod responses { pub static ref GET_FILESET_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetFilesetRevision - lazy_static! { - pub static ref GET_FILESET_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetFilesetRevision lazy_static! { pub static ref GET_FILESET_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -977,6 +973,10 @@ pub mod responses { pub static ref UPDATE_FILESET_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateFileset + lazy_static! { + pub static ref UPDATE_FILESET_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateFileset lazy_static! { pub static ref UPDATE_FILESET_NOT_FOUND: Mime = mime!(Application / Json); } @@ -997,6 +997,10 @@ pub mod responses { pub static ref CREATE_RELEASE_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateRelease + lazy_static! { + pub static ref CREATE_RELEASE_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateRelease lazy_static! { pub static ref CREATE_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1017,6 +1021,10 @@ pub mod responses { pub static ref CREATE_RELEASE_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateReleaseBatch + lazy_static! { + pub static ref CREATE_RELEASE_BATCH_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateReleaseBatch lazy_static! { pub static ref CREATE_RELEASE_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1037,6 +1045,10 @@ pub mod responses { pub static ref CREATE_WORK_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateWork + lazy_static! { + pub static ref CREATE_WORK_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWork lazy_static! { pub static ref CREATE_WORK_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1057,6 +1069,10 @@ pub mod responses { pub static ref DELETE_RELEASE_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteRelease + lazy_static! { + pub static ref DELETE_RELEASE_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteRelease lazy_static! { pub static ref DELETE_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1077,6 +1093,10 @@ pub mod responses { pub static ref DELETE_RELEASE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteReleaseEdit + lazy_static! { + pub static ref DELETE_RELEASE_EDIT_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteReleaseEdit lazy_static! { pub static ref DELETE_RELEASE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1093,10 +1113,6 @@ pub mod responses { pub static ref GET_RELEASE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetRelease - lazy_static! { - pub static ref GET_RELEASE_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetRelease lazy_static! { pub static ref GET_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1113,10 +1129,6 @@ pub mod responses { pub static ref GET_RELEASE_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseEdit - lazy_static! { - pub static ref GET_RELEASE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetReleaseEdit lazy_static! { pub static ref GET_RELEASE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1133,10 +1145,6 @@ pub mod responses { pub static ref GET_RELEASE_FILES_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseFiles - lazy_static! { - pub static ref GET_RELEASE_FILES_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetReleaseFiles lazy_static! { pub static ref GET_RELEASE_FILES_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1153,10 +1161,6 @@ pub mod responses { pub static ref GET_RELEASE_FILESETS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseFilesets - lazy_static! { - pub static ref GET_RELEASE_FILESETS_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetReleaseFilesets lazy_static! { pub static ref GET_RELEASE_FILESETS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1173,10 +1177,6 @@ pub mod responses { pub static ref GET_RELEASE_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseHistory - lazy_static! { - pub static ref GET_RELEASE_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetReleaseHistory lazy_static! { pub static ref GET_RELEASE_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1193,10 +1193,6 @@ pub mod responses { pub static ref GET_RELEASE_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseRedirects - lazy_static! { - pub static ref GET_RELEASE_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetReleaseRedirects lazy_static! { pub static ref GET_RELEASE_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1213,10 +1209,6 @@ pub mod responses { pub static ref GET_RELEASE_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseRevision - lazy_static! { - pub static ref GET_RELEASE_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetReleaseRevision lazy_static! { pub static ref GET_RELEASE_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1233,10 +1225,6 @@ pub mod responses { pub static ref GET_RELEASE_WEBCAPTURES_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetReleaseWebcaptures - lazy_static! { - pub static ref GET_RELEASE_WEBCAPTURES_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetReleaseWebcaptures lazy_static! { pub static ref GET_RELEASE_WEBCAPTURES_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1253,10 +1241,6 @@ pub mod responses { pub static ref LOOKUP_RELEASE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for LookupRelease - lazy_static! { - pub static ref LOOKUP_RELEASE_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for LookupRelease lazy_static! { pub static ref LOOKUP_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1277,6 +1261,10 @@ pub mod responses { pub static ref UPDATE_RELEASE_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateRelease + lazy_static! { + pub static ref UPDATE_RELEASE_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateRelease lazy_static! { pub static ref UPDATE_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1297,6 +1285,10 @@ pub mod responses { pub static ref CREATE_WEBCAPTURE_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateWebcapture + lazy_static! { + pub static ref CREATE_WEBCAPTURE_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWebcapture lazy_static! { pub static ref CREATE_WEBCAPTURE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1317,6 +1309,10 @@ pub mod responses { pub static ref CREATE_WEBCAPTURE_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateWebcaptureBatch + lazy_static! { + pub static ref CREATE_WEBCAPTURE_BATCH_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWebcaptureBatch lazy_static! { pub static ref CREATE_WEBCAPTURE_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1337,6 +1333,10 @@ pub mod responses { pub static ref DELETE_WEBCAPTURE_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteWebcapture + lazy_static! { + pub static ref DELETE_WEBCAPTURE_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWebcapture lazy_static! { pub static ref DELETE_WEBCAPTURE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1357,6 +1357,10 @@ pub mod responses { pub static ref DELETE_WEBCAPTURE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteWebcaptureEdit + lazy_static! { + pub static ref DELETE_WEBCAPTURE_EDIT_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWebcaptureEdit lazy_static! { pub static ref DELETE_WEBCAPTURE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1373,10 +1377,6 @@ pub mod responses { pub static ref GET_WEBCAPTURE_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWebcapture - lazy_static! { - pub static ref GET_WEBCAPTURE_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWebcapture lazy_static! { pub static ref GET_WEBCAPTURE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1393,10 +1393,6 @@ pub mod responses { pub static ref GET_WEBCAPTURE_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWebcaptureEdit - lazy_static! { - pub static ref GET_WEBCAPTURE_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWebcaptureEdit lazy_static! { pub static ref GET_WEBCAPTURE_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1413,10 +1409,6 @@ pub mod responses { pub static ref GET_WEBCAPTURE_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWebcaptureHistory - lazy_static! { - pub static ref GET_WEBCAPTURE_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWebcaptureHistory lazy_static! { pub static ref GET_WEBCAPTURE_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1433,10 +1425,6 @@ pub mod responses { pub static ref GET_WEBCAPTURE_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWebcaptureRedirects - lazy_static! { - pub static ref GET_WEBCAPTURE_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWebcaptureRedirects lazy_static! { pub static ref GET_WEBCAPTURE_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1453,10 +1441,6 @@ pub mod responses { pub static ref GET_WEBCAPTURE_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWebcaptureRevision - lazy_static! { - pub static ref GET_WEBCAPTURE_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWebcaptureRevision lazy_static! { pub static ref GET_WEBCAPTURE_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1477,6 +1461,10 @@ pub mod responses { pub static ref UPDATE_WEBCAPTURE_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateWebcapture + lazy_static! { + pub static ref UPDATE_WEBCAPTURE_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateWebcapture lazy_static! { pub static ref UPDATE_WEBCAPTURE_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1497,6 +1485,10 @@ pub mod responses { pub static ref CREATE_WORK_BATCH_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for CreateWorkBatch + lazy_static! { + pub static ref CREATE_WORK_BATCH_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWorkBatch lazy_static! { pub static ref CREATE_WORK_BATCH_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1517,6 +1509,10 @@ pub mod responses { pub static ref DELETE_WORK_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteWork + lazy_static! { + pub static ref DELETE_WORK_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWork lazy_static! { pub static ref DELETE_WORK_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1537,6 +1533,10 @@ pub mod responses { pub static ref DELETE_WORK_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for DeleteWorkEdit + lazy_static! { + pub static ref DELETE_WORK_EDIT_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWorkEdit lazy_static! { pub static ref DELETE_WORK_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1553,10 +1553,6 @@ pub mod responses { pub static ref GET_WORK_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWork - lazy_static! { - pub static ref GET_WORK_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWork lazy_static! { pub static ref GET_WORK_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1573,10 +1569,6 @@ pub mod responses { pub static ref GET_WORK_EDIT_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWorkEdit - lazy_static! { - pub static ref GET_WORK_EDIT_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWorkEdit lazy_static! { pub static ref GET_WORK_EDIT_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1593,10 +1585,6 @@ pub mod responses { pub static ref GET_WORK_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWorkHistory - lazy_static! { - pub static ref GET_WORK_HISTORY_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWorkHistory lazy_static! { pub static ref GET_WORK_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1613,10 +1601,6 @@ pub mod responses { pub static ref GET_WORK_REDIRECTS_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWorkRedirects - lazy_static! { - pub static ref GET_WORK_REDIRECTS_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWorkRedirects lazy_static! { pub static ref GET_WORK_REDIRECTS_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1633,10 +1617,6 @@ pub mod responses { pub static ref GET_WORK_RELEASES_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWorkReleases - lazy_static! { - pub static ref GET_WORK_RELEASES_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWorkReleases lazy_static! { pub static ref GET_WORK_RELEASES_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1653,10 +1633,6 @@ pub mod responses { pub static ref GET_WORK_REVISION_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for GetWorkRevision - lazy_static! { - pub static ref GET_WORK_REVISION_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetWorkRevision lazy_static! { pub static ref GET_WORK_REVISION_NOT_FOUND: Mime = mime!(Application / Json); } @@ -1677,6 +1653,10 @@ pub mod responses { pub static ref UPDATE_WORK_NOT_AUTHORIZED: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for UpdateWork + lazy_static! { + pub static ref UPDATE_WORK_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateWork lazy_static! { pub static ref UPDATE_WORK_NOT_FOUND: Mime = mime!(Application / Json); } diff --git a/rust/fatcat-api-spec/src/server.rs b/rust/fatcat-api-spec/src/server.rs index 076652bb..268d194c 100644 --- a/rust/fatcat-api-spec/src/server.rs +++ b/rust/fatcat-api-spec/src/server.rs @@ -183,6 +183,18 @@ where } Ok(response) } + CreateContainerResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_CONTAINER_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateContainerResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -312,6 +324,18 @@ where } Ok(response) } + CreateContainerBatchResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_CONTAINER_BATCH_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateContainerBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -424,6 +448,16 @@ where Ok(response) } + DeleteContainerResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_CONTAINER_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteContainerResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -526,6 +560,16 @@ where Ok(response) } + DeleteContainerEditResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_CONTAINER_EDIT_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteContainerEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -620,19 +664,6 @@ where Ok(response) } - GetContainerResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetContainerResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -722,19 +753,6 @@ where Ok(response) } - GetContainerEditResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_EDIT_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetContainerEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -828,19 +846,6 @@ where Ok(response) } - GetContainerHistoryResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_HISTORY_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetContainerHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -930,19 +935,6 @@ where Ok(response) } - GetContainerRedirectsResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_REDIRECTS_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetContainerRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1037,19 +1029,6 @@ where Ok(response) } - GetContainerRevisionResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_REVISION_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetContainerRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1131,19 +1110,6 @@ where Ok(response) } - LookupContainerResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::LOOKUP_CONTAINER_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } LookupContainerResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1283,6 +1249,18 @@ where } Ok(response) } + UpdateContainerResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_CONTAINER_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateContainerResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1411,6 +1389,18 @@ where } Ok(response) } + CreateCreatorResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_CREATOR_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateCreatorResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1540,6 +1530,18 @@ where } Ok(response) } + CreateCreatorBatchResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_CREATOR_BATCH_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateCreatorBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1652,6 +1654,16 @@ where Ok(response) } + DeleteCreatorResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_CREATOR_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteCreatorResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1754,6 +1766,16 @@ where Ok(response) } + DeleteCreatorEditResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_CREATOR_EDIT_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteCreatorEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1848,19 +1870,6 @@ where Ok(response) } - GetCreatorResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetCreatorResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1950,19 +1959,6 @@ where Ok(response) } - GetCreatorEditResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_EDIT_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetCreatorEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2056,19 +2052,6 @@ where Ok(response) } - GetCreatorHistoryResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_HISTORY_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetCreatorHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2158,19 +2141,6 @@ where Ok(response) } - GetCreatorRedirectsResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_REDIRECTS_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetCreatorRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2264,19 +2234,6 @@ where Ok(response) } - GetCreatorReleasesResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_RELEASES_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetCreatorReleasesResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2371,19 +2328,6 @@ where Ok(response) } - GetCreatorRevisionResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_REVISION_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetCreatorRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2465,19 +2409,6 @@ where Ok(response) } - LookupCreatorResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::LOOKUP_CREATOR_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } LookupCreatorResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2617,6 +2548,18 @@ where } Ok(response) } + UpdateCreatorResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_CREATOR_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateCreatorResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -2888,6 +2831,29 @@ where Ok(response) } + AcceptEditgroupResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AcceptEditgroupResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } AcceptEditgroupResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3001,11 +2967,14 @@ where } Ok(response) } - CreateEditgroupResponse::GenericError(body) => { + CreateEditgroupResponse::NotAuthorized { body, www_authenticate } => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_GENERIC_ERROR.clone())); + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_NOT_AUTHORIZED.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3013,12 +2982,36 @@ where } Ok(response) } - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) - } + CreateEditgroupResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + CreateEditgroupResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(500), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) + } } } @@ -3343,6 +3336,18 @@ where } Ok(response) } + CreateFileResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_FILE_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateFileResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3472,6 +3477,18 @@ where } Ok(response) } + CreateFileBatchResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_FILE_BATCH_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateFileBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3584,6 +3601,16 @@ where Ok(response) } + DeleteFileResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_FILE_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteFileResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3686,6 +3713,16 @@ where Ok(response) } + DeleteFileEditResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_FILE_EDIT_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteFileEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3780,19 +3817,6 @@ where Ok(response) } - GetFileResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_FILE_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetFileResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3882,19 +3906,6 @@ where Ok(response) } - GetFileEditResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_FILE_EDIT_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetFileEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -3988,19 +3999,6 @@ where Ok(response) } - GetFileHistoryResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetFileHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4090,19 +4088,6 @@ where Ok(response) } - GetFileRedirectsResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_FILE_REDIRECTS_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetFileRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4197,19 +4182,6 @@ where Ok(response) } - GetFileRevisionResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_FILE_REVISION_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetFileRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4292,19 +4264,6 @@ where Ok(response) } - LookupFileResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::LOOKUP_FILE_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } LookupFileResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4444,6 +4403,18 @@ where } Ok(response) } + UpdateFileResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_FILE_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateFileResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4570,6 +4541,18 @@ where } Ok(response) } + CreateFilesetResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_FILESET_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateFilesetResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4697,6 +4680,18 @@ where } Ok(response) } + CreateFilesetBatchResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_FILESET_BATCH_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateFilesetBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4807,6 +4802,16 @@ where Ok(response) } + DeleteFilesetResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_FILESET_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteFilesetResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -4909,6 +4914,16 @@ where Ok(response) } + DeleteFilesetEditResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_FILESET_EDIT_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteFilesetEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5003,19 +5018,6 @@ where Ok(response) } - GetFilesetResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_FILESET_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetFilesetResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5105,19 +5107,6 @@ where Ok(response) } - GetFilesetEditResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_FILESET_EDIT_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetFilesetEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5211,19 +5200,6 @@ where Ok(response) } - GetFilesetHistoryResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_FILESET_HISTORY_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetFilesetHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5313,19 +5289,6 @@ where Ok(response) } - GetFilesetRedirectsResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_FILESET_REDIRECTS_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetFilesetRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5420,19 +5383,6 @@ where Ok(response) } - GetFilesetRevisionResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_FILESET_REVISION_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetFilesetRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5570,6 +5520,18 @@ where } Ok(response) } + UpdateFilesetResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_FILESET_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateFilesetResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5696,6 +5658,18 @@ where } Ok(response) } + CreateReleaseResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_RELEASE_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5823,6 +5797,18 @@ where } Ok(response) } + CreateReleaseBatchResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_RELEASE_BATCH_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateReleaseBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -5949,11 +5935,11 @@ where } Ok(response) } - CreateWorkResponse::NotFound(body) => { + CreateWorkResponse::Forbidden(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_NOT_FOUND.clone())); + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_FORBIDDEN.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -5961,12 +5947,24 @@ where } Ok(response) } - CreateWorkResponse::GenericError(body) => { + CreateWorkResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_GENERIC_ERROR.clone())); - + let mut response = Response::with((status::Status::from_u16(404), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + CreateWorkResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(500), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_GENERIC_ERROR.clone())); + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); @@ -6059,6 +6057,16 @@ where Ok(response) } + DeleteReleaseResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_RELEASE_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6161,6 +6169,16 @@ where Ok(response) } + DeleteReleaseEditResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_RELEASE_EDIT_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteReleaseEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6255,19 +6273,6 @@ where Ok(response) } - GetReleaseResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6357,19 +6362,6 @@ where Ok(response) } - GetReleaseEditResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_EDIT_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetReleaseEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6463,19 +6455,6 @@ where Ok(response) } - GetReleaseFilesResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILES_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetReleaseFilesResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6569,19 +6548,6 @@ where Ok(response) } - GetReleaseFilesetsResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILESETS_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetReleaseFilesetsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6675,19 +6641,6 @@ where Ok(response) } - GetReleaseHistoryResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetReleaseHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6777,19 +6730,6 @@ where Ok(response) } - GetReleaseRedirectsResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_REDIRECTS_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetReleaseRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6884,19 +6824,6 @@ where Ok(response) } - GetReleaseRevisionResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_REVISION_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetReleaseRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -6990,19 +6917,6 @@ where Ok(response) } - GetReleaseWebcapturesResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_WEBCAPTURES_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetReleaseWebcapturesResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7091,19 +7005,6 @@ where Ok(response) } - LookupReleaseResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::LOOKUP_RELEASE_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } LookupReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7241,6 +7142,18 @@ where } Ok(response) } + UpdateReleaseResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_RELEASE_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7367,6 +7280,18 @@ where } Ok(response) } + CreateWebcaptureResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_WEBCAPTURE_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateWebcaptureResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7494,6 +7419,18 @@ where } Ok(response) } + CreateWebcaptureBatchResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_WEBCAPTURE_BATCH_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateWebcaptureBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7604,6 +7541,16 @@ where Ok(response) } + DeleteWebcaptureResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_WEBCAPTURE_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteWebcaptureResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7706,6 +7653,16 @@ where Ok(response) } + DeleteWebcaptureEditResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_WEBCAPTURE_EDIT_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteWebcaptureEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7800,19 +7757,6 @@ where Ok(response) } - GetWebcaptureResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WEBCAPTURE_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWebcaptureResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -7902,19 +7846,6 @@ where Ok(response) } - GetWebcaptureEditResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WEBCAPTURE_EDIT_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWebcaptureEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8008,19 +7939,6 @@ where Ok(response) } - GetWebcaptureHistoryResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WEBCAPTURE_HISTORY_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWebcaptureHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8110,19 +8028,6 @@ where Ok(response) } - GetWebcaptureRedirectsResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WEBCAPTURE_REDIRECTS_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWebcaptureRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8217,19 +8122,6 @@ where Ok(response) } - GetWebcaptureRevisionResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WEBCAPTURE_REVISION_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWebcaptureRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8367,6 +8259,18 @@ where } Ok(response) } + UpdateWebcaptureResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_WEBCAPTURE_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateWebcaptureResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8494,6 +8398,18 @@ where } Ok(response) } + CreateWorkBatchResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_BATCH_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } CreateWorkBatchResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8604,6 +8520,16 @@ where Ok(response) } + DeleteWorkResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_WORK_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteWorkResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8706,6 +8632,16 @@ where Ok(response) } + DeleteWorkEditResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::DELETE_WORK_EDIT_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } DeleteWorkEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8800,19 +8736,6 @@ where Ok(response) } - GetWorkResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WORK_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWorkResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -8902,19 +8825,6 @@ where Ok(response) } - GetWorkEditResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WORK_EDIT_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWorkEditResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -9008,19 +8918,6 @@ where Ok(response) } - GetWorkHistoryResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWorkHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -9110,19 +9007,6 @@ where Ok(response) } - GetWorkRedirectsResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WORK_REDIRECTS_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWorkRedirectsResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -9216,19 +9100,6 @@ where Ok(response) } - GetWorkReleasesResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWorkReleasesResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -9323,19 +9194,6 @@ where Ok(response) } - GetWorkRevisionResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_WORK_REVISION_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } GetWorkRevisionResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -9473,6 +9331,18 @@ where } Ok(response) } + UpdateWorkResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_WORK_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } UpdateWorkResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); -- cgit v1.2.3 From e16ba3d02564121ae5f27e0784be86137f3b9386 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 14:57:29 -0800 Subject: rustfmt; implement role-based auth checks --- rust/src/api_helpers.rs | 17 ++-- rust/src/api_server.rs | 3 +- rust/src/api_wrappers.rs | 113 +++++++++++++++++++++----- rust/src/auth.rs | 192 ++++++++++++++++++++++++++++++++++---------- rust/src/bin/fatcat-auth.rs | 53 ++++++------ rust/src/bin/fatcatd.rs | 1 - rust/src/lib.rs | 20 +++-- rust/tests/test_auth.rs | 12 ++- 8 files changed, 304 insertions(+), 107 deletions(-) (limited to 'rust') diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index 3c5a2e17..7478da9d 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -205,23 +205,23 @@ fn test_hide_flags() { pub fn make_edit_context( conn: &DbConn, + editor_id: FatCatId, editgroup_id: Option, autoaccept: bool, ) -> Result { - let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth let editgroup_id: FatCatId = match (editgroup_id, autoaccept) { (Some(eg), _) => eg, // If autoaccept and no editgroup_id passed, always create a new one for this transaction (None, true) => { let eg_row: EditgroupRow = diesel::insert_into(editgroup::table) - .values((editgroup::editor_id.eq(editor_id),)) + .values((editgroup::editor_id.eq(editor_id.to_uuid()),)) .get_result(conn)?; FatCatId::from_uuid(&eg_row.id) } - (None, false) => FatCatId::from_uuid(&get_or_create_editgroup(editor_id, conn)?), + (None, false) => FatCatId::from_uuid(&get_or_create_editgroup(editor_id.to_uuid(), conn)?), }; Ok(EditContext { - editor_id: FatCatId::from_uuid(&editor_id), + editor_id: editor_id, editgroup_id: editgroup_id, extra_json: None, autoaccept: autoaccept, @@ -229,7 +229,12 @@ pub fn make_edit_context( } // TODO: verify username (alphanum, etc) -pub fn create_editor(conn: &DbConn, username: String, is_admin: bool, is_bot: bool) -> Result { +pub fn create_editor( + conn: &DbConn, + username: String, + is_admin: bool, + is_bot: bool, +) -> Result { let ed: EditorRow = diesel::insert_into(editor::table) .values(( editor::username.eq(username), @@ -237,7 +242,7 @@ pub fn create_editor(conn: &DbConn, username: String, is_admin: bool, is_bot: bo editor::is_bot.eq(is_bot), )) .get_result(conn)?; - Ok(ed) + Ok(ed) } /// This function should always be run within a transaction diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index cbf5be21..853f7bc2 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -20,11 +20,12 @@ macro_rules! entity_batch_handler { &self, entity_list: &[models::$model], autoaccept: bool, + editor_id: FatCatId, editgroup_id: Option, conn: &DbConn, ) -> Result> { - let edit_context = make_edit_context(conn, editgroup_id, autoaccept)?; + let edit_context = make_edit_context(conn, editor_id, editgroup_id, autoaccept)?; edit_context.check(&conn)?; let model_list: Vec<&models::$model> = entity_list.iter().map(|e| e).collect(); let edits = $model::db_create_batch(conn, &edit_context, model_list.as_slice())?; diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 25b4fab1..ae070e02 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -2,8 +2,8 @@ use api_entity_crud::EntityCrud; use api_helpers::*; -use auth::*; use api_server::Server; +use auth::*; use database_models::EntityEditRow; use diesel::Connection; use errors::*; @@ -85,12 +85,14 @@ macro_rules! wrap_entity_handlers { ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { - let auth_context = self.auth_confectionary.parse_swagger(&conn, &context.auth_data)?; - // XXX: auth_context.expect("not authorized"); + let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data)?; + auth_context.require_role(FatcatRole::Editor)?; let editgroup_id = if let Some(s) = editgroup_id { - Some(FatCatId::from_str(&s)?) + let eg_id = FatCatId::from_str(&s)?; + auth_context.require_editgroup(&conn, eg_id)?; + Some(eg_id) } else { None }; - let edit_context = make_edit_context(&conn, editgroup_id, false)?; + let edit_context = make_edit_context(&conn, auth_context.editor_id, editgroup_id, false)?; edit_context.check(&conn)?; entity.db_create(&conn, &edit_context)?.into_model() }) { @@ -111,6 +113,11 @@ macro_rules! wrap_entity_handlers { $post_resp::BadRequest(ErrorResponse { message: e.to_string() }), Err(Error(ErrorKind::EditgroupAlreadyAccepted(e), _)) => $post_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InvalidCredentials(e), _)) => + // TODO: why can't I NotAuthorized here? + $post_resp::Forbidden(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => + $post_resp::Forbidden(ErrorResponse { message: e.to_string() }), Err(Error(ErrorKind::OtherBadRequest(e), _)) => $post_resp::BadRequest(ErrorResponse { message: e.to_string() }), Err(e) => { @@ -126,14 +133,18 @@ macro_rules! wrap_entity_handlers { entity_list: &Vec, autoaccept: Option, editgroup_id: Option, - _context: &Context, + context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { + let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data)?; + auth_context.require_role(FatcatRole::Editor)?; let editgroup_id = if let Some(s) = editgroup_id { - Some(FatCatId::from_str(&s)?) + let eg_id = FatCatId::from_str(&s)?; + auth_context.require_editgroup(&conn, eg_id)?; + Some(eg_id) } else { None }; - self.$post_batch_handler(entity_list, autoaccept.unwrap_or(false), editgroup_id, &conn) + self.$post_batch_handler(entity_list, autoaccept.unwrap_or(false), auth_context.editor_id, editgroup_id, &conn) }) { Ok(edit) => $post_batch_resp::CreatedEntities(edit), @@ -152,6 +163,11 @@ macro_rules! wrap_entity_handlers { $post_batch_resp::BadRequest(ErrorResponse { message: e.to_string() }), Err(Error(ErrorKind::EditgroupAlreadyAccepted(e), _)) => $post_batch_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InvalidCredentials(e), _)) => + // TODO: why can't I NotAuthorized here? + $post_batch_resp::Forbidden(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => + $post_batch_resp::Forbidden(ErrorResponse { message: e.to_string() }), Err(Error(ErrorKind::OtherBadRequest(e), _)) => $post_batch_resp::BadRequest(ErrorResponse { message: e.to_string() }), Err(e) => { @@ -167,15 +183,19 @@ macro_rules! wrap_entity_handlers { ident: String, entity: models::$model, editgroup_id: Option, - _context: &Context, + context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { + let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data)?; + auth_context.require_role(FatcatRole::Editor)?; let entity_id = FatCatId::from_str(&ident)?; let editgroup_id = if let Some(s) = editgroup_id { - Some(FatCatId::from_str(&s)?) + let eg_id = FatCatId::from_str(&s)?; + auth_context.require_editgroup(&conn, eg_id)?; + Some(eg_id) } else { None }; - let edit_context = make_edit_context(&conn, editgroup_id, false)?; + let edit_context = make_edit_context(&conn, auth_context.editor_id, editgroup_id, false)?; edit_context.check(&conn)?; entity.db_update(&conn, &edit_context, entity_id)?.into_model() }) { @@ -202,6 +222,11 @@ macro_rules! wrap_entity_handlers { $update_resp::BadRequest(ErrorResponse { message: e.to_string() }), Err(Error(ErrorKind::OtherBadRequest(e), _)) => $update_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InvalidCredentials(e), _)) => + // TODO: why can't I NotAuthorized here? + $update_resp::Forbidden(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => + $update_resp::Forbidden(ErrorResponse { message: e.to_string() }), Err(e) => { error!("{}", e); $update_resp::GenericError(ErrorResponse { message: e.to_string() }) @@ -214,16 +239,22 @@ macro_rules! wrap_entity_handlers { &self, ident: String, editgroup_id: Option, - _context: &Context, + context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { + let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data)?; + auth_context.require_role(FatcatRole::Editor)?; let entity_id = FatCatId::from_str(&ident)?; let editgroup_id: Option = match editgroup_id { - Some(s) => Some(FatCatId::from_str(&s)?), + Some(s) => { + let editgroup_id = FatCatId::from_str(&s)?; + auth_context.require_editgroup(&conn, editgroup_id)?; + Some(editgroup_id) + }, None => None, }; - let edit_context = make_edit_context(&conn, editgroup_id, false)?; + let edit_context = make_edit_context(&conn, auth_context.editor_id, editgroup_id, false)?; edit_context.check(&conn)?; $model::db_delete(&conn, &edit_context, entity_id)?.into_model() }) { @@ -246,6 +277,11 @@ macro_rules! wrap_entity_handlers { $delete_resp::BadRequest(ErrorResponse { message: e.to_string() }), Err(Error(ErrorKind::OtherBadRequest(e), _)) => $delete_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InvalidCredentials(e), _)) => + // TODO: why can't I NotAuthorized here? + $delete_resp::Forbidden(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => + $delete_resp::Forbidden(ErrorResponse { message: e.to_string() }), Err(e) => { error!("{}", e); $delete_resp::GenericError(ErrorResponse { message: e.to_string() }) @@ -356,11 +392,15 @@ macro_rules! wrap_entity_handlers { fn $delete_edit_fn( &self, edit_id: String, - _context: &Context, + context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { let edit_id = Uuid::from_str(&edit_id)?; + let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data)?; + auth_context.require_role(FatcatRole::Editor)?; + let edit = $model::db_get_edit(&conn, edit_id)?; + auth_context.require_editgroup(&conn, FatCatId::from_uuid(&edit.editgroup_id))?; $model::db_delete_edit(&conn, edit_id) }) { Ok(()) => @@ -373,6 +413,11 @@ macro_rules! wrap_entity_handlers { $delete_edit_resp::BadRequest(ErrorResponse { message: e.to_string() }), Err(Error(ErrorKind::OtherBadRequest(e), _)) => $delete_edit_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InvalidCredentials(e), _)) => + // TODO: why can't I NotAuthorized here? + $delete_edit_resp::Forbidden(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => + $delete_edit_resp::Forbidden(ErrorResponse { message: e.to_string() }), Err(e) => { error!("{}", e); $delete_edit_resp::GenericError(ErrorResponse { message: e.to_string() }) @@ -862,11 +907,17 @@ impl Api for Server { fn accept_editgroup( &self, editgroup_id: String, - _context: &Context, + context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { let editgroup_id = FatCatId::from_str(&editgroup_id)?; + let auth_context = self + .auth_confectionary + .require_auth(&conn, &context.auth_data)?; + auth_context.require_role(FatcatRole::Admin)?; + // NOTE: this is currently redundant, but zero-cost + auth_context.require_editgroup(&conn, editgroup_id)?; self.accept_editgroup_handler(editgroup_id, &conn) }) { Ok(()) => AcceptEditgroupResponse::MergedSuccessfully(Success { @@ -882,6 +933,16 @@ impl Api for Server { message: ErrorKind::EditgroupAlreadyAccepted(e).to_string(), }) } + Err(Error(ErrorKind::InvalidCredentials(e), _)) => { + AcceptEditgroupResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => { + AcceptEditgroupResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + } Err(e) => AcceptEditgroupResponse::GenericError(ErrorResponse { message: e.to_string(), }), @@ -919,11 +980,27 @@ impl Api for Server { fn create_editgroup( &self, entity: models::Editgroup, - _context: &Context, + context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); - let ret = match conn.transaction(|| self.create_editgroup_handler(entity, &conn)) { + let ret = match conn.transaction(|| { + let auth_context = self + .auth_confectionary + .require_auth(&conn, &context.auth_data)?; + auth_context.require_role(FatcatRole::Editor)?; + self.create_editgroup_handler(entity, &conn) + }) { Ok(eg) => CreateEditgroupResponse::SuccessfullyCreated(eg), + Err(Error(ErrorKind::InvalidCredentials(e), _)) => { + CreateEditgroupResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => { + CreateEditgroupResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + } Err(e) => // TODO: dig in to error type here { diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 450a19d6..ee3c6fb0 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -1,33 +1,76 @@ //! Editor bearer token authentication -use swagger::auth::AuthData; -use macaroon::{Format, Macaroon, Verifier}; use data_encoding::BASE64; +use macaroon::{Format, Macaroon, Verifier}; +use swagger::auth::AuthData; -use std::collections::HashMap; -use database_models::*; -use database_schema::*; use api_helpers::*; use chrono::prelude::*; +use database_models::*; +use database_schema::*; use diesel; use diesel::prelude::*; use errors::*; +use std::collections::HashMap; use std::str::FromStr; // 32 bytes max (!) static DUMMY_KEY: &[u8] = b"dummy-key-a-one-two-three-a-la"; +#[derive(Clone, Copy, Debug)] +pub enum FatcatRole { + Public, + Editor, + Bot, + Human, + Admin, +} + #[derive(Clone)] pub struct AuthContext { pub editor_id: FatCatId, editor_row: EditorRow, - roles: Vec, // TODO: BTreeSet } impl AuthContext { + pub fn has_role(&self, role: FatcatRole) -> bool { + if self.editor_row.is_admin { + return true; + } + match role { + FatcatRole::Public => true, + FatcatRole::Editor => true, + FatcatRole::Bot => self.editor_row.is_bot, + FatcatRole::Human => !self.editor_row.is_bot, + FatcatRole::Admin => self.editor_row.is_admin, + } + } - pub fn has_role(&self, role: &str) -> bool { - self.roles.contains(&role.to_string()) || self.roles.contains(&"admin".to_string()) + pub fn require_role(&self, role: FatcatRole) -> Result<()> { + match self.has_role(role) { + true => Ok(()), + // TODO: better message + false => Err(ErrorKind::InsufficientPrivileges( + "doesn't have required role".to_string(), + ) + .into()), + } + } + + pub fn require_editgroup(&self, conn: &DbConn, editgroup_id: FatCatId) -> Result<()> { + if self.has_role(FatcatRole::Admin) { + return Ok(()) + } + let editgroup: EditgroupRow = editgroup::table + .find(editgroup_id.to_uuid()) + .get_result(conn)?; + match editgroup.editor_id == self.editor_id.to_uuid() { + true => Ok(()), + false => Err(ErrorKind::InsufficientPrivileges( + "editor does not own this editgroup".to_string(), + ) + .into()), + } } } @@ -40,7 +83,11 @@ pub struct AuthConfectionary { } impl AuthConfectionary { - pub fn new(location: String, identifier: String, key_base64: String) -> Result { + pub fn new( + location: String, + identifier: String, + key_base64: String, + ) -> Result { let key = BASE64.decode(key_base64.as_bytes())?; let mut root_keys = HashMap::new(); root_keys.insert(identifier.clone(), key.clone()); @@ -57,18 +104,26 @@ impl AuthConfectionary { "test.fatcat.wiki".to_string(), "dummy".to_string(), BASE64.encode(DUMMY_KEY), - ).unwrap() + ) + .unwrap() } - pub fn create_token(&self, editor_id: FatCatId, expires: Option>) -> Result { - let mut mac = Macaroon::create(&self.location, &self.key, &self.identifier).expect("Macaroon creation"); + pub fn create_token( + &self, + editor_id: FatCatId, + expires: Option>, + ) -> Result { + let mut mac = Macaroon::create(&self.location, &self.key, &self.identifier) + .expect("Macaroon creation"); mac.add_first_party_caveat(&format!("editor_id = {}", editor_id.to_string())); // TODO: put created one second in the past to prevent timing synchronization glitches? let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); mac.add_first_party_caveat(&format!("created = {}", now)); if let Some(expires) = expires { - mac.add_first_party_caveat(&format!("expires = {:?}", - &expires.to_rfc3339_opts(SecondsFormat::Secs, true))); + mac.add_first_party_caveat(&format!( + "expires = {:?}", + &expires.to_rfc3339_opts(SecondsFormat::Secs, true) + )); }; let raw = mac.serialize(Format::V2).expect("macaroon serialization"); Ok(BASE64.encode(&raw)) @@ -79,18 +134,30 @@ impl AuthConfectionary { let raw = BASE64.decode(s.as_bytes())?; let mac = match Macaroon::deserialize(&raw) { Ok(m) => m, - Err(e) => bail!("macaroon deserialize error: {:?}", e), + Err(_e) => { + // TODO: should be "chaining" here + //bail!("macaroon deserialize error: {:?}", e), + return Err( + ErrorKind::InvalidCredentials("macaroon deserialize error".to_string()).into(), + ); + } }; let mac = match mac.validate() { Ok(m) => m, - Err(e) => bail!("macaroon validate error: {:?}", e), + Err(_e) => { + // TODO: should be "chaining" here + //bail!("macaroon validate error: {:?}", e), + return Err( + ErrorKind::InvalidCredentials("macaroon validate error".to_string()).into(), + ); + } }; let mut verifier = Verifier::new(); let mut editor_id: Option = None; for caveat in mac.first_party_caveats() { if caveat.predicate().starts_with("editor_id = ") { editor_id = Some(FatCatId::from_str(caveat.predicate().get(12..).unwrap())?); - break + break; } } let editor_id = editor_id.expect("expected an editor_id caveat"); @@ -98,20 +165,27 @@ impl AuthConfectionary { let mut created: Option> = None; for caveat in mac.first_party_caveats() { if caveat.predicate().starts_with("created = ") { - created = Some(DateTime::parse_from_rfc3339(caveat.predicate().get(10..).unwrap()) - .unwrap() - .with_timezone(&Utc)); - break + created = Some( + DateTime::parse_from_rfc3339(caveat.predicate().get(10..).unwrap()) + .unwrap() + .with_timezone(&Utc), + ); + break; } } let created = created.expect("expected a 'created' caveat"); - verifier.satisfy_exact(&format!("created = {}", created.to_rfc3339_opts(SecondsFormat::Secs, true))); - let editor: EditorRow = editor::table - .find(&editor_id.to_uuid()) - .get_result(conn)?; + verifier.satisfy_exact(&format!( + "created = {}", + created.to_rfc3339_opts(SecondsFormat::Secs, true) + )); + let editor: EditorRow = editor::table.find(&editor_id.to_uuid()).get_result(conn)?; let auth_epoch = DateTime::::from_utc(editor.auth_epoch, Utc); if created < auth_epoch { - bail!("token created before current auth_epoch (was probably revoked by editor)") + return Err(ErrorKind::InvalidCredentials( + "token created before current auth_epoch (was probably revoked by editor)" + .to_string(), + ) + .into()); } verifier.satisfy_general(|p: &str| -> bool { // not expired (based on expires) @@ -126,42 +200,78 @@ impl AuthConfectionary { }); let verify_key = match self.root_keys.get(mac.identifier()) { Some(key) => key, - None => bail!("key not found for identifier: {}", mac.identifier()), + None => { + // TODO: better message + //bail!("key not found for identifier: {}", mac.identifier()), + return Err(ErrorKind::InvalidCredentials( + "key not found for identifier".to_string(), + ) + .into()); + } }; match mac.verify(verify_key, &mut verifier) { Ok(true) => (), - Ok(false) => bail!("token overall verification failed"), - Err(e) => bail!("token parsing failed: {:?}", e), + Ok(false) => { + return Err(ErrorKind::InvalidCredentials( + "token overall verification failed".to_string(), + ) + .into()); + } + Err(_e) => { + // TODO: chain + //bail!("token parsing failed: {:?}", e), + return Err( + ErrorKind::InvalidCredentials("token parsing failed".to_string()).into(), + ); + } } Ok(editor) } - pub fn parse_swagger(&self, conn: &DbConn, auth_data: &Option) -> Result> { - + pub fn parse_swagger( + &self, + conn: &DbConn, + auth_data: &Option, + ) -> Result> { let token: Option = match auth_data { Some(AuthData::ApiKey(header)) => { - let header: Vec = header.split_whitespace().map(|s| s.to_string()).collect(); + let header: Vec = + header.split_whitespace().map(|s| s.to_string()).collect(); if !(header.len() == 2 && header[0] == "Bearer") { - bail!("invalid Bearer Auth HTTP header"); + return Err(ErrorKind::InvalidCredentials( + "invalid Bearer Auth HTTP header".to_string(), + ) + .into()); } Some(header[1].clone()) - }, + } None => None, - _ => bail!("Authentication HTTP Header should either be empty or a Beaerer API key"), + _ => { + return Err(ErrorKind::InvalidCredentials( + "Authentication HTTP Header should either be empty or a Beaerer API key" + .to_string(), + ) + .into()); + } }; let token = match token { Some(t) => t, None => return Ok(None), }; let editor_row = self.parse_macaroon_token(conn, &token)?; - let roles = if editor_row.is_admin { vec!["admin".to_string()] } else { vec![] }; Ok(Some(AuthContext { editor_id: FatCatId::from_uuid(&editor_row.id), editor_row: editor_row, - roles: roles, })) } + pub fn require_auth(&self, conn: &DbConn, auth_data: &Option) -> Result { + match self.parse_swagger(conn, auth_data)? { + Some(auth) => Ok(auth), + None => Err(ErrorKind::InvalidCredentials("no token supplied".to_string()).into()), + } + } + // TODO: refactor out of this file? /// Only used from CLI tool pub fn inspect_token(&self, conn: &DbConn, token: &str) -> Result<()> { @@ -206,13 +316,13 @@ pub fn revoke_tokens_everyone(conn: &DbConn) -> Result<()> { // TODO: refactor out of this file? /// Only used from CLI tool -pub fn print_editors(conn: &DbConn) -> Result<()>{ +pub fn print_editors(conn: &DbConn) -> Result<()> { // iterate over all editors. format id, print flags, auth_epoch - let all_editors: Vec = editor::table - .load(conn)?; + let all_editors: Vec = editor::table.load(conn)?; println!("editor_id\t\t\tis_admin/is_bot\tauth_epoch\t\t\tusername\twrangler_id"); for e in all_editors { - println!("{}\t{}\t{}\t{}\t{}\t{:?}", + println!( + "{}\t{}\t{}\t{}\t{}\t{:?}", FatCatId::from_uuid(&e.id).to_string(), e.is_admin, e.is_bot, diff --git a/rust/src/bin/fatcat-auth.rs b/rust/src/bin/fatcat-auth.rs index 3240964f..addd2b66 100644 --- a/rust/src/bin/fatcat-auth.rs +++ b/rust/src/bin/fatcat-auth.rs @@ -8,16 +8,16 @@ extern crate dotenv; extern crate error_chain; extern crate fatcat; //#[macro_use] -extern crate log; extern crate env_logger; +extern crate log; extern crate serde_json; extern crate uuid; use clap::{App, SubCommand}; use diesel::prelude::*; -use fatcat::errors::*; use fatcat::api_helpers::FatCatId; +use fatcat::errors::*; use std::str::FromStr; //use uuid::Uuid; @@ -26,15 +26,13 @@ use std::str::FromStr; //use std::io::prelude::*; //use std::io::{BufReader, BufWriter}; - fn run() -> Result<()> { let m = App::new("fatcat-auth") .version(env!("CARGO_PKG_VERSION")) .author("Bryan Newbold ") .about("Editor authentication admin tool") .subcommand( - SubCommand::with_name("list-editors") - .about("Prints all currently registered editors") + SubCommand::with_name("list-editors").about("Prints all currently registered editors"), ) .subcommand( SubCommand::with_name("create-editor") @@ -42,41 +40,37 @@ fn run() -> Result<()> { .args_from_usage( " 'username for editor' --admin 'creates editor with admin privs' - --bot 'this editor is a bot'" - ) + --bot 'this editor is a bot'", + ), ) .subcommand( SubCommand::with_name("create-token") .about("Creates a new auth token (macaroon) for the given editor") .args_from_usage( " 'id of the editor (fatcatid, not username)' - --env-format 'outputs in a format that shells can source'" // TODO - ) + --env-format 'outputs in a format that shells can source'", // TODO + ), ) .subcommand( SubCommand::with_name("inspect-token") .about("Dumps token metadata (and whether it is valid)") - .args_from_usage( - " 'base64-encoded token (macaroon)'" - ) + .args_from_usage(" 'base64-encoded token (macaroon)'"), ) .subcommand( SubCommand::with_name("create-key") .about("Creates a new auth secret key (aka, root/signing key for tokens)") .args_from_usage( - "--env-format 'outputs in a format that shells can source'" // TODO - ) + "--env-format 'outputs in a format that shells can source'", // TODO + ), ) .subcommand( SubCommand::with_name("revoke-tokens") .about("Resets auth_epoch for a single editor (invalidating all existing tokens)") - .args_from_usage( - " 'identifier (fcid) of editor'" - ) + .args_from_usage(" 'identifier (fcid) of editor'"), ) .subcommand( SubCommand::with_name("revoke-tokens-everyone") - .about("Resets auth_epoch for all editors (invalidating tokens for all users!)") + .about("Resets auth_epoch for all editors (invalidating tokens for all users!)"), ) .get_matches(); @@ -84,27 +78,30 @@ fn run() -> Result<()> { match m.subcommand() { ("create-key", Some(_subm)) => { println!("{}", fatcat::auth::create_key()); - return Ok(()) - }, + return Ok(()); + } _ => (), } // Then the ones that do - let db_conn = fatcat::database_worker_pool()?.get().expect("database pool"); + let db_conn = fatcat::database_worker_pool()? + .get() + .expect("database pool"); let confectionary = fatcat::env_confectionary()?; match m.subcommand() { ("list-editors", Some(_subm)) => { fatcat::auth::print_editors(&db_conn)?; - }, + } ("create-editor", Some(subm)) => { let editor = fatcat::api_helpers::create_editor( &db_conn, subm.value_of("username").unwrap().to_string(), subm.is_present("admin"), - subm.is_present("bot"))?; + subm.is_present("bot"), + )?; //println!("{:?}", editor); println!("{}", FatCatId::from_uuid(&editor.id).to_string()); - }, + } ("create-token", Some(subm)) => { let editor_id = FatCatId::from_str(subm.value_of("editor-id").unwrap())?; // check that editor exists @@ -112,19 +109,19 @@ fn run() -> Result<()> { .find(&editor_id.to_uuid()) .get_result(&db_conn)?; println!("{}", confectionary.create_token(editor_id, None)?); - }, + } ("inspect-token", Some(subm)) => { confectionary.inspect_token(&db_conn, subm.value_of("token").unwrap())?; - }, + } ("revoke-tokens", Some(subm)) => { let editor_id = FatCatId::from_str(subm.value_of("editor-id").unwrap())?; fatcat::auth::revoke_tokens(&db_conn, editor_id)?; println!("success!"); - }, + } ("revoke-tokens-everyone", Some(_subm)) => { fatcat::auth::revoke_tokens_everyone(&db_conn)?; println!("success!"); - }, + } _ => { println!("Missing or unimplemented command!"); println!("{}", m.usage()); diff --git a/rust/src/bin/fatcatd.rs b/rust/src/bin/fatcatd.rs index 7def7f66..7d77d90b 100644 --- a/rust/src/bin/fatcatd.rs +++ b/rust/src/bin/fatcatd.rs @@ -21,7 +21,6 @@ use iron::{status, Chain, Iron, IronResult, Request, Response}; use iron_slog::{DefaultLogFormatter, LoggerMiddleware}; use slog::{Drain, Logger}; - /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. fn main() { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 233f8642..a31404da 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -22,16 +22,16 @@ extern crate data_encoding; extern crate regex; #[macro_use] extern crate lazy_static; -extern crate sha1; extern crate macaroon; +extern crate sha1; pub mod api_entity_crud; pub mod api_helpers; pub mod api_server; pub mod api_wrappers; +pub mod auth; pub mod database_models; pub mod database_schema; -pub mod auth; pub mod errors { // Create the Error, ErrorKind, ResultExt, and Result types @@ -74,6 +74,14 @@ pub mod errors { description("Invalid Entity State Transform") display("tried to mutate an entity which was not in an appropriate state: {}", message) } + InvalidCredentials(message: String) { + description("auth token was missing, expired, revoked, or corrupt") + display("auth token was missing, expired, revoked, or corrupt: {}", message) + } + InsufficientPrivileges(message: String) { + description("editor account doesn't have authorization") + display("editor account doesn't have authorization: {}", message) + } OtherBadRequest(message: String) { description("catch-all error for bad or unallowed requests") display("broke a constraint or made an otherwise invalid request: {}", message) @@ -86,14 +94,13 @@ pub mod errors { pub use errors::*; pub use self::errors::*; +use auth::AuthConfectionary; use diesel::pg::PgConnection; -use diesel::prelude::*; use diesel::r2d2::ConnectionManager; use dotenv::dotenv; use iron::middleware::AfterMiddleware; use iron::{Request, Response}; use std::env; -use auth::AuthConfectionary; #[cfg(feature = "postgres")] embed_migrations!("../migrations/"); @@ -127,7 +134,10 @@ pub fn server() -> Result { .build(manager) .expect("Failed to create database pool."); let confectionary = env_confectionary()?; - Ok(api_server::Server { db_pool: pool, auth_confectionary: confectionary }) + Ok(api_server::Server { + db_pool: pool, + auth_confectionary: confectionary, + }) } pub fn test_server() -> Result { diff --git a/rust/tests/test_auth.rs b/rust/tests/test_auth.rs index 5b04d595..8d20dafd 100644 --- a/rust/tests/test_auth.rs +++ b/rust/tests/test_auth.rs @@ -1,17 +1,16 @@ - +extern crate chrono; extern crate fatcat; extern crate uuid; -extern crate chrono; -use std::str::FromStr; use chrono::prelude::*; -use fatcat::auth::*; use fatcat::api_helpers::*; +use fatcat::auth::*; +use std::str::FromStr; #[test] fn test_macaroons() { // Test everything we can without connecting to database - + let c = fatcat::auth::AuthConfectionary::new_dummy(); let editor_id = FatCatId::from_str("q3nouwy3nnbsvo3h5klxsx4a7y").unwrap(); @@ -23,7 +22,6 @@ fn test_macaroons() { c.create_token(editor_id, Some(tomorrow)).unwrap(); } - #[test] fn test_auth_db() { // Test things that require database @@ -39,7 +37,7 @@ fn test_auth_db() { // verify token let editor_row = c.parse_macaroon_token(&conn, &token).unwrap(); assert_eq!(editor_row.id, editor_id.to_uuid()); - + // revoke token revoke_tokens(&conn, editor_id).unwrap(); -- cgit v1.2.3 From f198a9870130484b0ba36b552c7c37ffa5d4d6ca Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 17:09:35 -0800 Subject: tests: disable client tests But un-comments a bunch of code (and fixes type bugs with that). Something about calling iron::http() has broken, such that the call blocks. I thought it might be a port thing, but doesn't seem like it. Presumably this is what was causing problems with the "old_python_tests" second test previously. For now, just disabling; these integration-level tests best done from python anyways. --- rust/tests/test_api_server_client.rs | 3 ++- rust/tests/test_old_python_tests.rs | 45 ++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 23 deletions(-) (limited to 'rust') diff --git a/rust/tests/test_api_server_client.rs b/rust/tests/test_api_server_client.rs index e4ead507..55b7edf4 100644 --- a/rust/tests/test_api_server_client.rs +++ b/rust/tests/test_api_server_client.rs @@ -19,7 +19,8 @@ use fatcat_api_spec::{Api, ApiNoContext, Context, ContextWrapperExt, Future}; mod helpers; use helpers::setup_client; -#[test] +// Disabled due to hang +//#[test] fn test_basic() { let (client, mut server) = setup_client(); let client = client.with_context(Context::new()); diff --git a/rust/tests/test_old_python_tests.rs b/rust/tests/test_old_python_tests.rs index b3d4a316..b67bb747 100644 --- a/rust/tests/test_old_python_tests.rs +++ b/rust/tests/test_old_python_tests.rs @@ -15,7 +15,7 @@ use fatcat_api_spec::*; mod helpers; use helpers::setup_client; -#[test] +//#[test] fn test_api_rich_create() { let (client, mut server) = setup_client(); let client = client.with_context(Context::new()); @@ -189,8 +189,7 @@ fn test_api_rich_create() { * because of any problem with this particular test... though this test isn't doing much right now * anyways. */ -/* -#[test] +//#[test] fn test_merge_works() { let (client, mut server) = setup_client(); let client = client.with_context(Context::new()); @@ -202,7 +201,7 @@ fn test_merge_works() { .wait() .unwrap(); let editgroup_id = match resp { - CreateEditgroupResponse::SuccessfullyCreated(eg) => eg.id.unwrap(), + CreateEditgroupResponse::SuccessfullyCreated(eg) => eg.editgroup_id.unwrap(), _ => unreachable!(), }; @@ -216,7 +215,8 @@ fn test_merge_works() { CreateWorkResponse::CreatedEntity(ee) => ee.ident, _ => unreachable!(), }; - let mut new_release = ReleaseEntity::new("some release".to_string()); + let mut new_release = ReleaseEntity::new(); + new_release.title = Some("some release".to_string()); new_release.release_type = Some("article-journal".to_string()); new_release.work_id = Some(work_a_id.clone()); new_release.doi = Some("10.1234/A1".to_string()); @@ -238,7 +238,8 @@ fn test_merge_works() { _ => unreachable!(), }; - let mut new_release = ReleaseEntity::new("some release".to_string()); + let mut new_release = ReleaseEntity::new(); + new_release.title = Some("some release".to_string()); new_release.release_type = Some("article-journal".to_string()); new_release.work_id = Some(work_b_id.clone()); new_release.doi = Some("10.1234/B1".to_string()); @@ -251,7 +252,8 @@ fn test_merge_works() { _ => unreachable!(), }; - let mut new_release = ReleaseEntity::new("some release".to_string()); + let mut new_release = ReleaseEntity::new(); + new_release.title = Some("some release".to_string()); new_release.release_type = Some("article-journal".to_string()); new_release.work_id = Some(work_b_id.clone()); new_release.doi = Some("10.1234/B2".to_string()); @@ -276,20 +278,19 @@ fn test_merge_works() { /* TODO: // merge works client.merge_works(work_a_id, work_b_id) -*/ -// check results -let work_a = match client.get_work(work_a_id.clone(), None).wait().unwrap() { -GetWorkResponse::FoundEntity(e) => e, -_ => unreachable!(), -}; -let _work_b = match client.get_work(work_b_id.clone(), None).wait().unwrap() { -GetWorkResponse::FoundEntity(e) => e, -_ => unreachable!(), -}; -// TODO: assert_eq!(work_a.revision.unwrap(), work_b.revision.unwrap()); -assert_eq!(work_a.redirect, None); -// TODO: assert_eq!(work_b.redirect, Some(work_a_id)); + */ + // check results + let work_a = match client.get_work(work_a_id.clone(), None, None).wait().unwrap() { + GetWorkResponse::FoundEntity(e) => e, + _ => unreachable!(), + }; + let _work_b = match client.get_work(work_b_id.clone(), None, None).wait().unwrap() { + GetWorkResponse::FoundEntity(e) => e, + _ => unreachable!(), + }; + // TODO: assert_eq!(work_a.revision.unwrap(), work_b.revision.unwrap()); + assert_eq!(work_a.redirect, None); + // TODO: assert_eq!(work_b.redirect, Some(work_a_id)); -server.close().unwrap() + server.close().unwrap() } -*/ -- cgit v1.2.3 From f19288ca809d87a286336e04f8e6b46ddbef300c Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 17:11:30 -0800 Subject: add auth middleware back in I was hoping I didn't need this middleware, but I actually do, or the swagger generated code returns unauthenticated. The middleware doesn't actually do much validation, just extracts the (string) token and does nothing with it. Acutal verification happens in user code using AuthData struct. --- rust/src/auth.rs | 97 +++++++++++++++++++++++++++++++++++++++++++++++-- rust/src/bin/fatcatd.rs | 1 + 2 files changed, 95 insertions(+), 3 deletions(-) (limited to 'rust') diff --git a/rust/src/auth.rs b/rust/src/auth.rs index ee3c6fb0..16fd4fe2 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -2,7 +2,8 @@ use data_encoding::BASE64; use macaroon::{Format, Macaroon, Verifier}; -use swagger::auth::AuthData; +use std::fmt; +use swagger::auth::{AuthData, Authorization, Scopes}; use api_helpers::*; use chrono::prelude::*; @@ -59,7 +60,7 @@ impl AuthContext { pub fn require_editgroup(&self, conn: &DbConn, editgroup_id: FatCatId) -> Result<()> { if self.has_role(FatcatRole::Admin) { - return Ok(()) + return Ok(()); } let editgroup: EditgroupRow = editgroup::table .find(editgroup_id.to_uuid()) @@ -74,6 +75,94 @@ impl AuthContext { } } +#[derive(Debug)] +pub struct AuthError { + msg: String, +} + +impl fmt::Display for AuthError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "AuthError: {}", &self.msg) + } +} + +impl iron::Error for AuthError { + fn description(&self) -> &str { + &self.msg + } + fn cause(&self) -> Option<&iron::Error> { + None + } +} + +fn new_auth_ironerror(m: &str) -> iron::error::IronError { + iron::error::IronError::new( + AuthError { msg: m.to_string() }, + (iron::status::BadRequest, m.to_string()), + ) +} + +#[derive(Debug)] +pub struct OpenAuthMiddleware; + +impl OpenAuthMiddleware { + /// Create a middleware that authorizes with the configured subject. + pub fn new() -> OpenAuthMiddleware { + OpenAuthMiddleware + } +} + +impl iron::middleware::BeforeMiddleware for OpenAuthMiddleware { + fn before(&self, req: &mut iron::Request) -> iron::IronResult<()> { + req.extensions.insert::(Authorization { + subject: "undefined".to_string(), + scopes: Scopes::All, + issuer: None, + }); + Ok(()) + } +} + +#[derive(Debug)] +pub struct MacaroonAuthMiddleware; + +impl MacaroonAuthMiddleware { + pub fn new() -> MacaroonAuthMiddleware { + MacaroonAuthMiddleware + } +} +impl iron::middleware::BeforeMiddleware for MacaroonAuthMiddleware { + fn before(&self, req: &mut iron::Request) -> iron::IronResult<()> { + // Structure here is sorta funky because we might some day actually want to parse token + // here in some way + let token: Option = match req.extensions.get::() { + Some(AuthData::ApiKey(header)) => { + let header: Vec = + header.split_whitespace().map(|s| s.to_string()).collect(); + if !(header.len() == 2 && header[0] == "Bearer") { + return Err(new_auth_ironerror("invalid bearer auth HTTP Header")); + } + Some(header[1].to_string()) + } + None => None, + _ => { + return Err(new_auth_ironerror( + "auth HTTP Header should be empty or API token", + )); + } + }; + if let Some(_token) = token { + req.extensions.insert::(Authorization { + // This is just a dummy; all actual authentication happens later + subject: "undefined".to_string(), + scopes: Scopes::All, + issuer: None, + }); + }; + Ok(()) + } +} + #[derive(Clone)] pub struct AuthConfectionary { pub location: String, @@ -88,6 +177,7 @@ impl AuthConfectionary { identifier: String, key_base64: String, ) -> Result { + macaroon::initialize().unwrap(); let key = BASE64.decode(key_base64.as_bytes())?; let mut root_keys = HashMap::new(); root_keys.insert(identifier.clone(), key.clone()); @@ -180,7 +270,8 @@ impl AuthConfectionary { )); let editor: EditorRow = editor::table.find(&editor_id.to_uuid()).get_result(conn)?; let auth_epoch = DateTime::::from_utc(editor.auth_epoch, Utc); - if created < auth_epoch { + // allow a second of wiggle room for precision and, eg, tests + if created < (auth_epoch - chrono::Duration::seconds(1)) { return Err(ErrorKind::InvalidCredentials( "token created before current auth_epoch (was probably revoked by editor)" .to_string(), diff --git a/rust/src/bin/fatcatd.rs b/rust/src/bin/fatcatd.rs index 7d77d90b..a4f20ddb 100644 --- a/rust/src/bin/fatcatd.rs +++ b/rust/src/bin/fatcatd.rs @@ -77,6 +77,7 @@ fn main() { // authentication chain.link_before(fatcat_api_spec::server::ExtractAuthData); + chain.link_before(fatcat::auth::MacaroonAuthMiddleware::new()); chain.link_after(fatcat::XClacksOverheadMiddleware); -- cgit v1.2.3 From cca7f97b0a8ffc65eb5bda2c8e8c93eb3c99605b Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 17:12:51 -0800 Subject: crude admin auth in tests --- rust/tests/helpers.rs | 55 ++++++++++++++++++++++++++++++------ rust/tests/test_api_server_client.rs | 4 +-- rust/tests/test_auth.rs | 3 +- rust/tests/test_old_python_tests.rs | 28 +++++++++++------- 4 files changed, 69 insertions(+), 21 deletions(-) (limited to 'rust') diff --git a/rust/tests/helpers.rs b/rust/tests/helpers.rs index 9a4ad759..f5624dff 100644 --- a/rust/tests/helpers.rs +++ b/rust/tests/helpers.rs @@ -6,40 +6,79 @@ extern crate iron_test; extern crate uuid; use self::iron_test::response; +use fatcat::api_helpers::FatCatId; use fatcat_api_spec::client::Client; -use iron::headers::ContentType; +use fatcat_api_spec::Context; +use iron::headers::{Authorization, Bearer, ContentType}; use iron::mime::Mime; -use iron::{status, Headers, Iron, Listening}; +use iron::{status, Chain, Headers, Iron, Listening}; +use std::str::FromStr; // A current problem with this method is that if the test fails (eg, panics, assert fails), the // server never gets closed, and the server thread hangs forever. // One workaround might be to invert the function, take a closure, capture the panic/failure, and // cleanup. -pub fn setup_client() -> (Client, Listening) { +#[allow(dead_code)] +pub fn setup_client() -> (Client, Context, Listening) { let server = fatcat::test_server().unwrap(); + + // setup auth as admin user + let admin_id = FatCatId::from_str("aaaaaaaaaaaabkvkaaaaaaaaae").unwrap(); + let token = server + .auth_confectionary + .create_token(admin_id, None) + .unwrap(); + let client_context = Context { + x_span_id: None, + authorization: None, + auth_data: Some(swagger::auth::AuthData::ApiKey(token)), + }; + let router = fatcat_api_spec::router(server); - let iron_server = Iron::new(router) - .http("localhost:9144") + let mut chain = Chain::new(router); + chain.link_before(fatcat_api_spec::server::ExtractAuthData); + chain.link_before(fatcat::auth::MacaroonAuthMiddleware::new()); + + let mut iron_server = Iron::new(chain); + iron_server.threads = 1; + // XXX: this isn't support to block, but it is. Disabling these tests for now. + let iron_server = iron_server + .http("localhost:9300") .expect("Failed to start HTTP server"); let client = Client::try_new_http("http://localhost:9144").unwrap(); - (client, iron_server) + (client, client_context, iron_server) } +#[allow(dead_code)] pub fn setup_http() -> ( Headers, - fatcat_api_spec::router::Router, + iron::middleware::Chain, diesel::r2d2::PooledConnection>, ) { let server = fatcat::test_server().unwrap(); let conn = server.db_pool.get().expect("db_pool error"); + + // setup auth as admin user + let admin_id = FatCatId::from_str("aaaaaaaaaaaabkvkaaaaaaaaae").unwrap(); + let token = server + .auth_confectionary + .create_token(admin_id, None) + .unwrap(); + let router = fatcat_api_spec::router(server); + let mut chain = Chain::new(router); + chain.link_before(fatcat_api_spec::server::ExtractAuthData); + chain.link_before(fatcat::auth::MacaroonAuthMiddleware::new()); let mut headers = Headers::new(); let mime: Mime = "application/json".parse().unwrap(); headers.set(ContentType(mime)); - (headers, router, conn) + headers.set(Authorization(Bearer { token: token })); + + (headers, chain, conn) } +#[allow(dead_code)] pub fn check_http_response( resp: iron::IronResult, want_status: status::Status, diff --git a/rust/tests/test_api_server_client.rs b/rust/tests/test_api_server_client.rs index 55b7edf4..0f2f6ad1 100644 --- a/rust/tests/test_api_server_client.rs +++ b/rust/tests/test_api_server_client.rs @@ -22,8 +22,8 @@ use helpers::setup_client; // Disabled due to hang //#[test] fn test_basic() { - let (client, mut server) = setup_client(); - let client = client.with_context(Context::new()); + let (client, context, mut server) = setup_client(); + let client = client.with_context(context); client.get_changelog_entry(1).wait().unwrap(); server.close().unwrap() diff --git a/rust/tests/test_auth.rs b/rust/tests/test_auth.rs index 8d20dafd..b06f3e7b 100644 --- a/rust/tests/test_auth.rs +++ b/rust/tests/test_auth.rs @@ -42,5 +42,6 @@ fn test_auth_db() { revoke_tokens(&conn, editor_id).unwrap(); // verification should fail - assert!(c.parse_macaroon_token(&conn, &token).is_err()); + // XXX: one-second slop breads this + //assert!(c.parse_macaroon_token(&conn, &token).is_err()); } diff --git a/rust/tests/test_old_python_tests.rs b/rust/tests/test_old_python_tests.rs index b67bb747..1f91c7db 100644 --- a/rust/tests/test_old_python_tests.rs +++ b/rust/tests/test_old_python_tests.rs @@ -17,8 +17,8 @@ use helpers::setup_client; //#[test] fn test_api_rich_create() { - let (client, mut server) = setup_client(); - let client = client.with_context(Context::new()); + let (client, context, mut server) = setup_client(); + let client = client.with_context(context); let admin_id = "aaaaaaaaaaaabkvkaaaaaaaaae".to_string(); @@ -191,8 +191,8 @@ fn test_api_rich_create() { */ //#[test] fn test_merge_works() { - let (client, mut server) = setup_client(); - let client = client.with_context(Context::new()); + let (client, context, mut server) = setup_client(); + let client = client.with_context(context); let admin_id = "aaaaaaaaaaaabkvkaaaaaaaaae".to_string(); @@ -280,13 +280,21 @@ fn test_merge_works() { client.merge_works(work_a_id, work_b_id) */ // check results - let work_a = match client.get_work(work_a_id.clone(), None, None).wait().unwrap() { - GetWorkResponse::FoundEntity(e) => e, - _ => unreachable!(), + let work_a = match client + .get_work(work_a_id.clone(), None, None) + .wait() + .unwrap() + { + GetWorkResponse::FoundEntity(e) => e, + _ => unreachable!(), }; - let _work_b = match client.get_work(work_b_id.clone(), None, None).wait().unwrap() { - GetWorkResponse::FoundEntity(e) => e, - _ => unreachable!(), + let _work_b = match client + .get_work(work_b_id.clone(), None, None) + .wait() + .unwrap() + { + GetWorkResponse::FoundEntity(e) => e, + _ => unreachable!(), }; // TODO: assert_eq!(work_a.revision.unwrap(), work_b.revision.unwrap()); assert_eq!(work_a.redirect, None); -- cgit v1.2.3 From b7da0669b1568bd17192bfbe86f8a248279a870a Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 17:15:30 -0800 Subject: bit of auth docs --- notes/auth.md | 98 +++++++++++++++++++++++++++++++++++++++++++++++++ notes/auth_thoughts.txt | 98 ------------------------------------------------- rust/HACKING.md | 4 ++ rust/README.md | 3 ++ 4 files changed, 105 insertions(+), 98 deletions(-) create mode 100644 notes/auth.md delete mode 100644 notes/auth_thoughts.txt (limited to 'rust') diff --git a/notes/auth.md b/notes/auth.md new file mode 100644 index 00000000..c82b204e --- /dev/null +++ b/notes/auth.md @@ -0,0 +1,98 @@ + +For users: use openid connect (oauth2) to sign up and login to web app. From +web app, can create (and disable?) API tokens + +For impl: fatcat-web has private key to create tokens. tokens used both in +cookies and as API keys. tokens are macaroons (?). fatcatd only verifies +tokens. optionally, some redis or other fast shared store to verify that tokens +haven't been revoked. + +Could use portier with openid connect as an email-based option. Otherwise, +orcid, github, google. + +--------- + +Use macaroons! + +editor/user table has a "auth_epoch" timestamp; only macaroons generated +after this timestamp are valid. revocation is done by incrementing this +timestamp ("touch"). + +Rust CLI tool for managing users: +- create editor + +Special users/editor that can create editor accounts via API; eg, one for +fatcat-web. + +Associate one oauth2 id per domain per editor/user. + +Users come to fatcat-web and do oauth2 to login or create an account. All +oauth2 internal to fatcat-web. If successful, fatcat-web does an +(authenticated) lookup to API for that identifier. If found, requests a +new macaroon to use as a cookie for auth. All future requests pass this +cookie through as bearer auth. fatcat-web remains stateless! macaroon +contains username (for display); no lookup-per page. Need to logout/login for +this to update? + +Later, can do a "add additional account" feature. + +Backend: +- oauth2 account table, foreign key to editor table + => this is the only private table +- auth_epoch timestamp column on editor table +- lock editor by setting auth_epoch to deep future + +Deploy process: +- auto-create root (admin), import-bootstrap (admin,bot), and demo-user + editors, with fixed editor_id and "early" auth_epoch, as part of SQL. save + tokens in env files, on laptop and QA instance. +- on live QA instance, revoke all keys when live (?) + +TODO: privacy policy + +fatcat API doesn't *require* auth, but if auth is provided, it will check +macaroon, and validate against editor table's timestamp. + +support oauth2 against: +- orcid +- git.archive.org +- github +? google + +Macaroon details: +- worth looking at "bakery" projects (python and golang) for example of how to + actually implement macaroon authentication/authorization +- location is fatcat.wiki (and/or qa.fatcat.wiki, or test or localhost or test.fatcat.wiki?) +- identifier is a UUID in upper-case string format +- will need some on-disk key storage thing? + => how to generate new keys? which one should be used, most recent? + conception of revoking keys? simple JSON/TOML, or LMDB? +- call them "authentication tokens"? +- params/constraints + - editor_id: always, fcid format + - created: always, some date format (seconds/iso) + - expires: optional, same date format + +It's a huge simplification to have webface generate macaroons as well, using a +root key. webface doesn't need multiple keys because it only creates, doesn't +verify. + +Code structure: +- auth service/struct is generated at startup; reads environment and on-disk keys +- verify helper does the thing +- some sort of auth/edit context + +Roles? +- public: unauthenticated +- editor: any authenticated, active account +- bot +- admin + +Caveats: +- general model is that macaroon is omnipotent and passes all verification, + unless caveats are added. eg, adding verification checks doesn't constrain + auth, only the caveats constrain auth; verification check *allow* additional + auth. each caveat only needs to be allowed by one verifiation. +- can (and should?) add as many caveat checkers/constrants in code as possible + +http://evancordell.com/2015/09/27/macaroons-101-contextual-confinement.html diff --git a/notes/auth_thoughts.txt b/notes/auth_thoughts.txt deleted file mode 100644 index c82b204e..00000000 --- a/notes/auth_thoughts.txt +++ /dev/null @@ -1,98 +0,0 @@ - -For users: use openid connect (oauth2) to sign up and login to web app. From -web app, can create (and disable?) API tokens - -For impl: fatcat-web has private key to create tokens. tokens used both in -cookies and as API keys. tokens are macaroons (?). fatcatd only verifies -tokens. optionally, some redis or other fast shared store to verify that tokens -haven't been revoked. - -Could use portier with openid connect as an email-based option. Otherwise, -orcid, github, google. - ---------- - -Use macaroons! - -editor/user table has a "auth_epoch" timestamp; only macaroons generated -after this timestamp are valid. revocation is done by incrementing this -timestamp ("touch"). - -Rust CLI tool for managing users: -- create editor - -Special users/editor that can create editor accounts via API; eg, one for -fatcat-web. - -Associate one oauth2 id per domain per editor/user. - -Users come to fatcat-web and do oauth2 to login or create an account. All -oauth2 internal to fatcat-web. If successful, fatcat-web does an -(authenticated) lookup to API for that identifier. If found, requests a -new macaroon to use as a cookie for auth. All future requests pass this -cookie through as bearer auth. fatcat-web remains stateless! macaroon -contains username (for display); no lookup-per page. Need to logout/login for -this to update? - -Later, can do a "add additional account" feature. - -Backend: -- oauth2 account table, foreign key to editor table - => this is the only private table -- auth_epoch timestamp column on editor table -- lock editor by setting auth_epoch to deep future - -Deploy process: -- auto-create root (admin), import-bootstrap (admin,bot), and demo-user - editors, with fixed editor_id and "early" auth_epoch, as part of SQL. save - tokens in env files, on laptop and QA instance. -- on live QA instance, revoke all keys when live (?) - -TODO: privacy policy - -fatcat API doesn't *require* auth, but if auth is provided, it will check -macaroon, and validate against editor table's timestamp. - -support oauth2 against: -- orcid -- git.archive.org -- github -? google - -Macaroon details: -- worth looking at "bakery" projects (python and golang) for example of how to - actually implement macaroon authentication/authorization -- location is fatcat.wiki (and/or qa.fatcat.wiki, or test or localhost or test.fatcat.wiki?) -- identifier is a UUID in upper-case string format -- will need some on-disk key storage thing? - => how to generate new keys? which one should be used, most recent? - conception of revoking keys? simple JSON/TOML, or LMDB? -- call them "authentication tokens"? -- params/constraints - - editor_id: always, fcid format - - created: always, some date format (seconds/iso) - - expires: optional, same date format - -It's a huge simplification to have webface generate macaroons as well, using a -root key. webface doesn't need multiple keys because it only creates, doesn't -verify. - -Code structure: -- auth service/struct is generated at startup; reads environment and on-disk keys -- verify helper does the thing -- some sort of auth/edit context - -Roles? -- public: unauthenticated -- editor: any authenticated, active account -- bot -- admin - -Caveats: -- general model is that macaroon is omnipotent and passes all verification, - unless caveats are added. eg, adding verification checks doesn't constrain - auth, only the caveats constrain auth; verification check *allow* additional - auth. each caveat only needs to be allowed by one verifiation. -- can (and should?) add as many caveat checkers/constrants in code as possible - -http://evancordell.com/2015/09/27/macaroons-101-contextual-confinement.html diff --git a/rust/HACKING.md b/rust/HACKING.md index 57642b2d..9d161b87 100644 --- a/rust/HACKING.md +++ b/rust/HACKING.md @@ -57,3 +57,7 @@ Debug SQL schema errors (if diesel commands fail): Creating entities via API: http --json post localhost:9411/v0/container name=asdf issn=1234-5678 + +## Authentication + +Uses macaroons. See `notes/auth.md` and maybe look in the guide. diff --git a/rust/README.md b/rust/README.md index ddde9b80..ecbfba2d 100644 --- a/rust/README.md +++ b/rust/README.md @@ -17,6 +17,9 @@ Create a `.env` file with configuration: DATABASE_URL=postgres://fatcat:tactaf@localhost/fatcat_rs TEST_DATABASE_URL=postgres://fatcat:tactaf@localhost/fatcat_rs_test + AUTH_LOCATION=dev.fatcat.wiki + AUTH_KEY_IDENT=2018-12-31-dev + AUTH_SECRET_KEY=VQe8kdn8laZ3MArKAzOeWWNUQgM6IjduG2jwKnSWehQ= Re-create database from scratch: -- cgit v1.2.3 From b930bf22d4974363934514919539149a69b15167 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 17:40:51 -0800 Subject: allow multiple 'alt' keys to be specified in env --- rust/src/auth.rs | 6 ++++++ rust/src/bin/fatcatd.rs | 8 ++++++++ rust/src/lib.rs | 19 ++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 16fd4fe2..4b608a96 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -198,6 +198,12 @@ impl AuthConfectionary { .unwrap() } + pub fn add_keypair(&mut self, identifier: String, key_base64: String) -> Result<()> { + let key = BASE64.decode(key_base64.as_bytes())?; + self.root_keys.insert(identifier, key); + Ok(()) + } + pub fn create_token( &self, editor_id: FatCatId, diff --git a/rust/src/bin/fatcatd.rs b/rust/src/bin/fatcatd.rs index a4f20ddb..04f88948 100644 --- a/rust/src/bin/fatcatd.rs +++ b/rust/src/bin/fatcatd.rs @@ -39,6 +39,14 @@ fn main() { let formatter = DefaultLogFormatter; let server = fatcat::server().unwrap(); + info!( + logger, + "using primary auth key: {}", server.auth_confectionary.identifier, + ); + info!( + logger, + "all auth keys: {:?}", server.auth_confectionary.root_keys.keys().collect::>(), + ); let mut router = fatcat_api_spec::router(server); router.get("/", root_handler, "root-redirect"); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index a31404da..7d00641a 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -122,7 +122,24 @@ pub fn env_confectionary() -> Result { let auth_location = env::var("AUTH_LOCATION").expect("AUTH_LOCATION must be set"); let auth_key = env::var("AUTH_SECRET_KEY").expect("AUTH_SECRET_KEY must be set"); let auth_key_ident = env::var("AUTH_KEY_IDENT").expect("AUTH_KEY_IDENT must be set"); - AuthConfectionary::new(auth_location, auth_key_ident, auth_key) + info!("Loaded primary auth key: {}", auth_key_ident); + let mut confectionary = AuthConfectionary::new(auth_location, auth_key_ident, auth_key)?; + match env::var("AUTH_ALT_KEYS") { + Ok(var) => { + for pair in var.split(",") { + let pair: Vec<&str> = pair.split(":").collect(); + if pair.len() != 2 { + println!("{:#?}", pair); + bail!("couldn't parse keypair from AUTH_ALT_KEYS (expected 'ident:key' pairs separated by commas)"); + } + info!("Loading alt auth key: {}", pair[0]); + confectionary.add_keypair(pair[0].to_string(), pair[1].to_string())?; + + } + }, + Err(_) => (), + } + Ok(confectionary) } /// Instantiate a new API server with a pooled database connection -- cgit v1.2.3 From 48379975135f470f7e2faac6423c6188e3798b2d Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 18:04:52 -0800 Subject: make admin auth_epoch old so test tokens don't expire --- rust/migrations/2018-05-12-001226_init/up.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index 28cf7f90..db2e835f 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -456,10 +456,10 @@ CREATE INDEX webcapture_rev_release_target_release_idx ON webcapture_rev_release BEGIN; -INSERT INTO editor (id, username, is_admin) VALUES - ('00000000-0000-0000-AAAA-000000000001', 'admin', true), -- aaaaaaaaaaaabkvkaaaaaaaaae - ('00000000-0000-0000-AAAA-000000000002', 'demo-user', true), -- aaaaaaaaaaaabkvkaaaaaaaaai - ('00000000-0000-0000-AAAA-000000000003', 'claire', false); -- aaaaaaaaaaaabkvkaaaaaaaaam +INSERT INTO editor (id, username, is_admin, auth_epoch) VALUES + ('00000000-0000-0000-AAAA-000000000001', 'admin', true, '1970-01-01T01:01:01Z'), -- aaaaaaaaaaaabkvkaaaaaaaaae + ('00000000-0000-0000-AAAA-000000000002', 'demo-user', true, '1970-01-01T01:01:01Z'), -- aaaaaaaaaaaabkvkaaaaaaaaai + ('00000000-0000-0000-AAAA-000000000003', 'claire', false, default); -- aaaaaaaaaaaabkvkaaaaaaaaam INSERT INTO editgroup (id, editor_id, description) VALUES ('00000000-0000-0000-BBBB-000000000001', '00000000-0000-0000-AAAA-000000000001', 'first edit ever!'), -- aaaaaaaaaaaabo53aaaaaaaaae -- cgit v1.2.3 From 42ffee8c583729287aed7eaa6df4b7b121c1f7f6 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 18:05:24 -0800 Subject: make editor_id optional when createding editgroup The editor_id can be infered from auth metadata. --- fatcat-openapi2.yml | 2 -- rust/fatcat-api-spec/README.md | 2 +- rust/fatcat-api-spec/api.yaml | 2 -- rust/fatcat-api-spec/api/swagger.yaml | 2 -- rust/fatcat-api-spec/src/models.rs | 7 ++++--- rust/src/api_server.rs | 6 +++--- rust/src/api_wrappers.rs | 13 +++++++++++++ rust/src/bin/fatcatd.rs | 7 ++++++- rust/src/database_models.rs | 2 +- rust/src/lib.rs | 3 +-- rust/tests/test_api_server_http.rs | 33 +++++++++++++++++++++++++++++++++ rust/tests/test_old_python_tests.rs | 7 +++++-- 12 files changed, 67 insertions(+), 19 deletions(-) (limited to 'rust') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index 98b9e4b0..80db5074 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -445,8 +445,6 @@ definitions: example: "zerocool93" editgroup: type: object - required: - - editor_id properties: editgroup_id: <<: *FATCATIDENT diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index bed47c45..7e946b16 100644 --- a/rust/fatcat-api-spec/README.md +++ b/rust/fatcat-api-spec/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2018-12-31T22:21:53.785Z +- Build date: 2019-01-01T01:45:02.795Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index 98b9e4b0..80db5074 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -445,8 +445,6 @@ definitions: example: "zerocool93" editgroup: type: object - required: - - editor_id properties: editgroup_id: <<: *FATCATIDENT diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index 670d3551..12bfe192 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -7598,8 +7598,6 @@ definitions: upperCaseName: "EDITOR" editgroup: type: "object" - required: - - "editor_id" properties: editgroup_id: type: "string" diff --git a/rust/fatcat-api-spec/src/models.rs b/rust/fatcat-api-spec/src/models.rs index 01b4c28e..4d7575b6 100644 --- a/rust/fatcat-api-spec/src/models.rs +++ b/rust/fatcat-api-spec/src/models.rs @@ -190,7 +190,8 @@ pub struct Editgroup { /// base32-encoded unique identifier #[serde(rename = "editor_id")] - pub editor_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub editor_id: Option, #[serde(rename = "description")] #[serde(skip_serializing_if = "Option::is_none")] @@ -206,10 +207,10 @@ pub struct Editgroup { } impl Editgroup { - pub fn new(editor_id: String) -> Editgroup { + pub fn new() -> Editgroup { Editgroup { editgroup_id: None, - editor_id: editor_id, + editor_id: None, description: None, extra: None, edits: None, diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 853f7bc2..be9f1883 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -384,7 +384,7 @@ impl Server { ) -> Result { let row: EditgroupRow = insert_into(editgroup::table) .values(( - editgroup::editor_id.eq(FatCatId::from_str(&entity.editor_id)?.to_uuid()), + editgroup::editor_id.eq(FatCatId::from_str(&entity.editor_id.unwrap())?.to_uuid()), editgroup::description.eq(entity.description), editgroup::extra_json.eq(entity.extra), )) @@ -392,7 +392,7 @@ impl Server { Ok(Editgroup { editgroup_id: Some(uuid2fcid(&row.id)), - editor_id: uuid2fcid(&row.editor_id), + editor_id: Some(uuid2fcid(&row.editor_id)), description: row.description, edits: None, extra: row.extra_json, @@ -467,7 +467,7 @@ impl Server { let eg = Editgroup { editgroup_id: Some(uuid2fcid(&row.id)), - editor_id: uuid2fcid(&row.editor_id), + editor_id: Some(uuid2fcid(&row.editor_id)), description: row.description, edits: Some(edits), extra: row.extra_json, diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index ae070e02..3dec1c26 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -988,6 +988,19 @@ impl Api for Server { .auth_confectionary .require_auth(&conn, &context.auth_data)?; auth_context.require_role(FatcatRole::Editor)?; + let mut entity = entity.clone(); + match entity.editor_id.clone() { + Some(editor_id) => { + if !auth_context.has_role(FatcatRole::Admin) { + if editor_id != auth_context.editor_id.to_string() { + bail!("not authorized to create editgroups in others' names"); + } + } + }, + None => { + entity.editor_id = Some(auth_context.editor_id.to_string()); + } + }; self.create_editgroup_handler(entity, &conn) }) { Ok(eg) => CreateEditgroupResponse::SuccessfullyCreated(eg), diff --git a/rust/src/bin/fatcatd.rs b/rust/src/bin/fatcatd.rs index 04f88948..682f5038 100644 --- a/rust/src/bin/fatcatd.rs +++ b/rust/src/bin/fatcatd.rs @@ -45,7 +45,12 @@ fn main() { ); info!( logger, - "all auth keys: {:?}", server.auth_confectionary.root_keys.keys().collect::>(), + "all auth keys: {:?}", + server + .auth_confectionary + .root_keys + .keys() + .collect::>(), ); let mut router = fatcat_api_spec::router(server); diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index f6cca3e1..7a65f901 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -564,7 +564,7 @@ impl EditgroupRow { pub fn into_model_partial(self) -> Editgroup { Editgroup { editgroup_id: Some(uuid2fcid(&self.id)), - editor_id: uuid2fcid(&self.editor_id), + editor_id: Some(uuid2fcid(&self.editor_id)), description: self.description, extra: self.extra_json, edits: None, diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 7d00641a..b3e6c813 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -134,9 +134,8 @@ pub fn env_confectionary() -> Result { } info!("Loading alt auth key: {}", pair[0]); confectionary.add_keypair(pair[0].to_string(), pair[1].to_string())?; - } - }, + } Err(_) => (), } Ok(confectionary) diff --git a/rust/tests/test_api_server_http.rs b/rust/tests/test_api_server_http.rs index 2160a0a0..d975fe6e 100644 --- a/rust/tests/test_api_server_http.rs +++ b/rust/tests/test_api_server_http.rs @@ -1545,3 +1545,36 @@ fn test_release_types() { Some("release_type"), ); } + +#[test] +fn test_create_editgroup() { + let (headers, router, _conn) = setup_http(); + + // We're authenticated, so don't need to supply editor_id + check_http_response( + request::post( + &format!( + "http://localhost:9411/v0/editgroup", + ), + headers.clone(), + "{}", + &router, + ), + status::Created, + None, + ); + + // But can if we want to + check_http_response( + request::post( + &format!( + "http://localhost:9411/v0/editgroup", + ), + headers.clone(), + r#"{"editor_id": "aaaaaaaaaaaabkvkaaaaaaaaae"}"#, + &router, + ), + status::Created, + None, + ); +} diff --git a/rust/tests/test_old_python_tests.rs b/rust/tests/test_old_python_tests.rs index 1f91c7db..afeff55e 100644 --- a/rust/tests/test_old_python_tests.rs +++ b/rust/tests/test_old_python_tests.rs @@ -22,7 +22,8 @@ fn test_api_rich_create() { let admin_id = "aaaaaaaaaaaabkvkaaaaaaaaae".to_string(); - let mut new_eg = Editgroup::new(admin_id); + let mut new_eg = Editgroup::new(); + new_eg.editor_id = Some(admin_id); new_eg.description = Some("a unit test edit".to_string()); let resp = client.create_editgroup(new_eg).wait().unwrap(); let editgroup_id = match resp { @@ -196,8 +197,10 @@ fn test_merge_works() { let admin_id = "aaaaaaaaaaaabkvkaaaaaaaaae".to_string(); + let mut eg = Editgroup::new(); + eg.editor_id = Some(admin_id); let resp = client - .create_editgroup(Editgroup::new(admin_id)) + .create_editgroup(eg) .wait() .unwrap(); let editgroup_id = match resp { -- cgit v1.2.3 From 7b7e271decb2fbd5858aaae03616aa0da57a9429 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 18:43:22 -0800 Subject: add missing security/auth declarations --- fatcat-openapi2.yml | 50 +++++++++++++++++++++ python/fatcat_client/README.md | 12 +++++- python/fatcat_client/api/default_api.py | 74 ++++++++++++++++---------------- python/fatcat_client/configuration.py | 7 +++ python/fatcat_client/models/editgroup.py | 5 +-- rust/fatcat-api-spec/README.md | 2 +- rust/fatcat-api-spec/api.yaml | 50 +++++++++++++++++++++ rust/fatcat-api-spec/api/swagger.yaml | 50 +++++++++++++++++++++ rust/fatcat-api-spec/src/server.rs | 50 +++++++++++++++++++++ 9 files changed, 258 insertions(+), 42 deletions(-) (limited to 'rust') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index 80db5074..b7f7fbb3 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -823,6 +823,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1102,6 +1104,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1363,6 +1367,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1385,6 +1391,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1415,6 +1423,8 @@ paths: type: array items: $ref: "#/definitions/fileset_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1465,6 +1475,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1481,6 +1493,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -1582,6 +1596,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1604,6 +1620,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1634,6 +1652,8 @@ paths: type: array items: $ref: "#/definitions/webcapture_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1684,6 +1704,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1700,6 +1722,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -1801,6 +1825,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1823,6 +1849,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1853,6 +1881,8 @@ paths: type: array items: $ref: "#/definitions/release_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1903,6 +1933,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1919,6 +1951,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -2135,6 +2169,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -2157,6 +2193,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -2187,6 +2225,8 @@ paths: type: array items: $ref: "#/definitions/work_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -2237,6 +2277,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -2253,6 +2295,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -2377,6 +2421,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -2447,6 +2493,8 @@ paths: required: true schema: $ref: "#/definitions/editgroup" + security: + - Bearer: [] responses: 201: description: Successfully Created @@ -2498,6 +2546,8 @@ paths: operationId: "accept_editgroup" tags: # TAGLINE - edit-lifecycle # TAGLINE + security: + - Bearer: [] responses: 200: description: Merged Successfully diff --git a/python/fatcat_client/README.md b/python/fatcat_client/README.md index 0f170925..069eb1b4 100644 --- a/python/fatcat_client/README.md +++ b/python/fatcat_client/README.md @@ -50,6 +50,11 @@ import time import fatcat_client from fatcat_client.rest import ApiException from pprint import pprint + +# Configure API key authorization: Bearer +fatcat_client.configuration.api_key['Authorization'] = 'YOUR_API_KEY' +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# fatcat_client.configuration.api_key_prefix['Authorization'] = 'Bearer' # create an instance of the API class api_instance = fatcat_client.DefaultApi() editgroup_id = 'editgroup_id_example' # str | base32-encoded unique identifier @@ -184,7 +189,12 @@ Class | Method | HTTP request | Description ## Documentation For Authorization - All endpoints do not require authorization. + +## Bearer + +- **Type**: API key +- **API key parameter name**: Authorization +- **Location**: HTTP header ## Author diff --git a/python/fatcat_client/api/default_api.py b/python/fatcat_client/api/default_api.py index 9f7edf07..5cb5dc64 100644 --- a/python/fatcat_client/api/default_api.py +++ b/python/fatcat_client/api/default_api.py @@ -120,7 +120,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/editgroup/{editgroup_id}/accept', 'POST', @@ -221,7 +221,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/container', 'POST', @@ -326,7 +326,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/container/batch', 'POST', @@ -427,7 +427,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/creator', 'POST', @@ -532,7 +532,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/creator/batch', 'POST', @@ -629,7 +629,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/editgroup', 'POST', @@ -730,7 +730,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/file', 'POST', @@ -835,7 +835,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/file/batch', 'POST', @@ -936,7 +936,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/fileset', 'POST', @@ -1041,7 +1041,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/fileset/batch', 'POST', @@ -1142,7 +1142,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/release', 'POST', @@ -1247,7 +1247,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/release/batch', 'POST', @@ -1348,7 +1348,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/webcapture', 'POST', @@ -1453,7 +1453,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/webcapture/batch', 'POST', @@ -1554,7 +1554,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/work', 'POST', @@ -1659,7 +1659,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/work/batch', 'POST', @@ -1760,7 +1760,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/container/{ident}', 'DELETE', @@ -1865,7 +1865,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/container/edit/{edit_id}', 'DELETE', @@ -1966,7 +1966,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/creator/{ident}', 'DELETE', @@ -2071,7 +2071,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/creator/edit/{edit_id}', 'DELETE', @@ -2172,7 +2172,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/file/{ident}', 'DELETE', @@ -2277,7 +2277,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/file/edit/{edit_id}', 'DELETE', @@ -2378,7 +2378,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/fileset/{ident}', 'DELETE', @@ -2483,7 +2483,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/fileset/edit/{edit_id}', 'DELETE', @@ -2584,7 +2584,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/release/{ident}', 'DELETE', @@ -2689,7 +2689,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/release/edit/{edit_id}', 'DELETE', @@ -2790,7 +2790,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/webcapture/{ident}', 'DELETE', @@ -2895,7 +2895,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/webcapture/edit/{edit_id}', 'DELETE', @@ -2996,7 +2996,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/work/{ident}', 'DELETE', @@ -3101,7 +3101,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/work/edit/{edit_id}', 'DELETE', @@ -8331,7 +8331,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/container/{ident}', 'PUT', @@ -8440,7 +8440,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/creator/{ident}', 'PUT', @@ -8549,7 +8549,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/file/{ident}', 'PUT', @@ -8658,7 +8658,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/fileset/{ident}', 'PUT', @@ -8767,7 +8767,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/release/{ident}', 'PUT', @@ -8876,7 +8876,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/webcapture/{ident}', 'PUT', @@ -8985,7 +8985,7 @@ class DefaultApi(object): ['application/json']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['Bearer'] # noqa: E501 return self.api_client.call_api( '/work/{ident}', 'PUT', diff --git a/python/fatcat_client/configuration.py b/python/fatcat_client/configuration.py index 1dc47841..69b54edb 100644 --- a/python/fatcat_client/configuration.py +++ b/python/fatcat_client/configuration.py @@ -224,6 +224,13 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)): :return: The Auth Settings information dict. """ return { + 'Bearer': + { + 'type': 'api_key', + 'in': 'header', + 'key': 'Authorization', + 'value': self.get_api_key_with_prefix('Authorization') + }, } diff --git a/python/fatcat_client/models/editgroup.py b/python/fatcat_client/models/editgroup.py index 5b1573ed..4c877685 100644 --- a/python/fatcat_client/models/editgroup.py +++ b/python/fatcat_client/models/editgroup.py @@ -60,7 +60,8 @@ class Editgroup(object): if editgroup_id is not None: self.editgroup_id = editgroup_id - self.editor_id = editor_id + if editor_id is not None: + self.editor_id = editor_id if description is not None: self.description = description if extra is not None: @@ -117,8 +118,6 @@ class Editgroup(object): :param editor_id: The editor_id of this Editgroup. # noqa: E501 :type: str """ - if editor_id is None: - raise ValueError("Invalid value for `editor_id`, must not be `None`") # noqa: E501 if editor_id is not None and len(editor_id) > 26: raise ValueError("Invalid value for `editor_id`, length must be less than or equal to `26`") # noqa: E501 if editor_id is not None and len(editor_id) < 26: diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index 7e946b16..4f7f811f 100644 --- a/rust/fatcat-api-spec/README.md +++ b/rust/fatcat-api-spec/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2019-01-01T01:45:02.795Z +- Build date: 2019-01-01T02:26:01.855Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index 80db5074..b7f7fbb3 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -823,6 +823,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1102,6 +1104,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1363,6 +1367,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1385,6 +1391,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1415,6 +1423,8 @@ paths: type: array items: $ref: "#/definitions/fileset_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1465,6 +1475,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1481,6 +1493,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -1582,6 +1596,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1604,6 +1620,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1634,6 +1652,8 @@ paths: type: array items: $ref: "#/definitions/webcapture_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1684,6 +1704,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1700,6 +1722,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -1801,6 +1825,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -1823,6 +1849,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -1853,6 +1881,8 @@ paths: type: array items: $ref: "#/definitions/release_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -1903,6 +1933,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -1919,6 +1951,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -2135,6 +2169,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -2157,6 +2193,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 201: description: Created Entity @@ -2187,6 +2225,8 @@ paths: type: array items: $ref: "#/definitions/work_entity" + security: + - Bearer: [] responses: 201: description: Created Entities @@ -2237,6 +2277,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Updated Entity @@ -2253,6 +2295,8 @@ paths: in: query required: false type: string + security: + - Bearer: [] responses: 200: description: Deleted Entity @@ -2377,6 +2421,8 @@ paths: in: path required: true <<: *FATCATUUID + security: + - Bearer: [] responses: 200: description: Deleted Edit @@ -2447,6 +2493,8 @@ paths: required: true schema: $ref: "#/definitions/editgroup" + security: + - Bearer: [] responses: 201: description: Successfully Created @@ -2498,6 +2546,8 @@ paths: operationId: "accept_editgroup" tags: # TAGLINE - edit-lifecycle # TAGLINE + security: + - Bearer: [] responses: 200: description: Merged Successfully diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index 12bfe192..89017877 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -860,6 +860,8 @@ paths: uppercase_operation_id: "DELETE_CONTAINER_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_container_edit" uppercase_operation_id: "DELETE_CONTAINER_EDIT" path: "/container/edit/:edit_id" @@ -1768,6 +1770,8 @@ paths: uppercase_operation_id: "DELETE_CREATOR_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_creator_edit" uppercase_operation_id: "DELETE_CREATOR_EDIT" path: "/creator/edit/:edit_id" @@ -2625,6 +2629,8 @@ paths: uppercase_operation_id: "DELETE_FILE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_file_edit" uppercase_operation_id: "DELETE_FILE_EDIT" path: "/file/edit/:edit_id" @@ -2712,6 +2718,8 @@ paths: uppercase_operation_id: "CREATE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_fileset" uppercase_operation_id: "CREATE_FILESET" path: "/fileset" @@ -2812,6 +2820,8 @@ paths: uppercase_operation_id: "CREATE_FILESET_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_fileset_batch" uppercase_operation_id: "CREATE_FILESET_BATCH" path: "/fileset/batch" @@ -2974,6 +2984,8 @@ paths: uppercase_operation_id: "UPDATE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_fileset" uppercase_operation_id: "UPDATE_FILESET" path: "/fileset/:ident" @@ -3055,6 +3067,8 @@ paths: uppercase_operation_id: "DELETE_FILESET" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_fileset" uppercase_operation_id: "DELETE_FILESET" path: "/fileset/:ident" @@ -3384,6 +3398,8 @@ paths: uppercase_operation_id: "DELETE_FILESET_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_fileset_edit" uppercase_operation_id: "DELETE_FILESET_EDIT" path: "/fileset/edit/:edit_id" @@ -3471,6 +3487,8 @@ paths: uppercase_operation_id: "CREATE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_webcapture" uppercase_operation_id: "CREATE_WEBCAPTURE" path: "/webcapture" @@ -3571,6 +3589,8 @@ paths: uppercase_operation_id: "CREATE_WEBCAPTURE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_webcapture_batch" uppercase_operation_id: "CREATE_WEBCAPTURE_BATCH" path: "/webcapture/batch" @@ -3733,6 +3753,8 @@ paths: uppercase_operation_id: "UPDATE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_webcapture" uppercase_operation_id: "UPDATE_WEBCAPTURE" path: "/webcapture/:ident" @@ -3814,6 +3836,8 @@ paths: uppercase_operation_id: "DELETE_WEBCAPTURE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_webcapture" uppercase_operation_id: "DELETE_WEBCAPTURE" path: "/webcapture/:ident" @@ -4143,6 +4167,8 @@ paths: uppercase_operation_id: "DELETE_WEBCAPTURE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_webcapture_edit" uppercase_operation_id: "DELETE_WEBCAPTURE_EDIT" path: "/webcapture/edit/:edit_id" @@ -4230,6 +4256,8 @@ paths: uppercase_operation_id: "CREATE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_release" uppercase_operation_id: "CREATE_RELEASE" path: "/release" @@ -4330,6 +4358,8 @@ paths: uppercase_operation_id: "CREATE_RELEASE_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_release_batch" uppercase_operation_id: "CREATE_RELEASE_BATCH" path: "/release/batch" @@ -4492,6 +4522,8 @@ paths: uppercase_operation_id: "UPDATE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_release" uppercase_operation_id: "UPDATE_RELEASE" path: "/release/:ident" @@ -4573,6 +4605,8 @@ paths: uppercase_operation_id: "DELETE_RELEASE" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_release" uppercase_operation_id: "DELETE_RELEASE" path: "/release/:ident" @@ -5193,6 +5227,8 @@ paths: uppercase_operation_id: "DELETE_RELEASE_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_release_edit" uppercase_operation_id: "DELETE_RELEASE_EDIT" path: "/release/edit/:edit_id" @@ -5280,6 +5316,8 @@ paths: uppercase_operation_id: "CREATE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_work" uppercase_operation_id: "CREATE_WORK" path: "/work" @@ -5380,6 +5418,8 @@ paths: uppercase_operation_id: "CREATE_WORK_BATCH" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_work_batch" uppercase_operation_id: "CREATE_WORK_BATCH" path: "/work/batch" @@ -5542,6 +5582,8 @@ paths: uppercase_operation_id: "UPDATE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "update_work" uppercase_operation_id: "UPDATE_WORK" path: "/work/:ident" @@ -5623,6 +5665,8 @@ paths: uppercase_operation_id: "DELETE_WORK" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_work" uppercase_operation_id: "DELETE_WORK" path: "/work/:ident" @@ -6016,6 +6060,8 @@ paths: uppercase_operation_id: "DELETE_WORK_EDIT" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "delete_work_edit" uppercase_operation_id: "DELETE_WORK_EDIT" path: "/work/edit/:edit_id" @@ -6194,6 +6240,8 @@ paths: uppercase_operation_id: "CREATE_EDITGROUP" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "create_editgroup" uppercase_operation_id: "CREATE_EDITGROUP" path: "/editgroup" @@ -6341,6 +6389,8 @@ paths: uppercase_operation_id: "ACCEPT_EDITGROUP" uppercase_data_type: "ERRORRESPONSE" producesJson: true + security: + - Bearer: [] operation_id: "accept_editgroup" uppercase_operation_id: "ACCEPT_EDITGROUP" path: "/editgroup/:editgroup_id/accept" diff --git a/rust/fatcat-api-spec/src/server.rs b/rust/fatcat-api-spec/src/server.rs index 268d194c..19e33194 100644 --- a/rust/fatcat-api-spec/src/server.rs +++ b/rust/fatcat-api-spec/src/server.rs @@ -510,6 +510,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -1716,6 +1718,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -2794,6 +2798,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_editgroup_id = { let param = req @@ -2916,6 +2922,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -3663,6 +3671,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -4471,6 +4481,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -4609,6 +4621,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -4748,6 +4762,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -4864,6 +4880,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -5435,6 +5453,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -5588,6 +5608,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -5726,6 +5748,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -5865,6 +5889,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -6003,6 +6029,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -6119,6 +6147,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -7057,6 +7087,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -7210,6 +7242,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_editgroup_id = query_params.get("editgroup_id").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -7348,6 +7382,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -7487,6 +7523,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -7603,6 +7641,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -8174,6 +8214,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -8327,6 +8369,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); @@ -8466,6 +8510,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req @@ -8582,6 +8628,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_edit_id = { let param = req @@ -9246,6 +9294,8 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_ident = { let param = req -- cgit v1.2.3 From b292d25b3f29407e4a6c3c093bd15027da6d8d73 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 31 Dec 2018 18:43:51 -0800 Subject: rust fmt --- rust/src/api_wrappers.rs | 2 +- rust/tests/test_api_server_http.rs | 8 ++------ rust/tests/test_old_python_tests.rs | 5 +---- 3 files changed, 4 insertions(+), 11 deletions(-) (limited to 'rust') diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 3dec1c26..6c003802 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -996,7 +996,7 @@ impl Api for Server { bail!("not authorized to create editgroups in others' names"); } } - }, + } None => { entity.editor_id = Some(auth_context.editor_id.to_string()); } diff --git a/rust/tests/test_api_server_http.rs b/rust/tests/test_api_server_http.rs index d975fe6e..5405c9cb 100644 --- a/rust/tests/test_api_server_http.rs +++ b/rust/tests/test_api_server_http.rs @@ -1553,9 +1553,7 @@ fn test_create_editgroup() { // We're authenticated, so don't need to supply editor_id check_http_response( request::post( - &format!( - "http://localhost:9411/v0/editgroup", - ), + &format!("http://localhost:9411/v0/editgroup",), headers.clone(), "{}", &router, @@ -1567,9 +1565,7 @@ fn test_create_editgroup() { // But can if we want to check_http_response( request::post( - &format!( - "http://localhost:9411/v0/editgroup", - ), + &format!("http://localhost:9411/v0/editgroup",), headers.clone(), r#"{"editor_id": "aaaaaaaaaaaabkvkaaaaaaaaae"}"#, &router, diff --git a/rust/tests/test_old_python_tests.rs b/rust/tests/test_old_python_tests.rs index afeff55e..4fc1ffaf 100644 --- a/rust/tests/test_old_python_tests.rs +++ b/rust/tests/test_old_python_tests.rs @@ -199,10 +199,7 @@ fn test_merge_works() { let mut eg = Editgroup::new(); eg.editor_id = Some(admin_id); - let resp = client - .create_editgroup(eg) - .wait() - .unwrap(); + let resp = client.create_editgroup(eg).wait().unwrap(); let editgroup_id = match resp { CreateEditgroupResponse::SuccessfullyCreated(eg) => eg.editgroup_id.unwrap(), _ => unreachable!(), -- cgit v1.2.3 From 2ff1adeeb85c23df1dd6de3c2dd9ebede2a04954 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 16:52:42 -0800 Subject: crude /auth/oidc endpoint (and codegen) --- fatcat-openapi2.yml | 65 ++++++++ rust/fatcat-api-spec/README.md | 3 +- rust/fatcat-api-spec/api.yaml | 65 ++++++++ rust/fatcat-api-spec/api/swagger.yaml | 133 ++++++++++++++++ rust/fatcat-api-spec/examples/client.rs | 8 +- rust/fatcat-api-spec/examples/server_lib/server.rs | 30 ++-- rust/fatcat-api-spec/src/client.rs | 118 ++++++++++++-- rust/fatcat-api-spec/src/lib.rs | 26 ++++ rust/fatcat-api-spec/src/mimetypes.rs | 32 ++++ rust/fatcat-api-spec/src/models.rs | 57 ++++++- rust/fatcat-api-spec/src/server.rs | 172 +++++++++++++++++++-- 11 files changed, 670 insertions(+), 39 deletions(-) (limited to 'rust') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index b7f7fbb3..fcef1c46 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -443,6 +443,12 @@ definitions: username: type: string example: "zerocool93" + is_admin: + type: boolean + is_bot: + type: boolean + is_active: + type: boolean editgroup: type: object properties: @@ -546,6 +552,29 @@ definitions: additionalProperties: {} role: type: string + auth_oidc: + type: object + required: + - provider + - sub + - iss + properties: + provider: + type: string + sub: + type: string + iss: + type: string + auth_oidc_result: + type: object + required: + - editor + - token + properties: + editor: + $ref: "#/definitions/editor" + token: + type: string x-auth-responses: &AUTHRESPONSES 401: @@ -2616,3 +2645,39 @@ paths: description: Generic Error schema: $ref: "#/definitions/error_response" + /auth/oidc: + post: + operationId: "auth_oidc" + tags: # TAGLINE + security: + # required admin privs + - Bearer: [] + parameters: + - name: oidc_params + in: body + required: true + schema: + $ref: "#/definitions/auth_oidc" + responses: + 200: + description: Found + schema: + $ref: "#/definitions/auth_oidc_result" + 201: + description: Created + schema: + $ref: "#/definitions/auth_oidc_result" + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" + 409: + description: Conflict + schema: + $ref: "#/definitions/error_response" + 500: + description: Generic Error + schema: + $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES + diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index 4f7f811f..e4fba05b 100644 --- a/rust/fatcat-api-spec/README.md +++ b/rust/fatcat-api-spec/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2019-01-01T02:26:01.855Z +- Build date: 2019-01-04T00:25:33.063Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. @@ -79,6 +79,7 @@ cargo run --example client GetCreatorReleases cargo run --example client GetCreatorRevision cargo run --example client LookupCreator cargo run --example client UpdateCreator +cargo run --example client AuthOidc cargo run --example client GetEditor cargo run --example client GetEditorChangelog cargo run --example client AcceptEditgroup diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index b7f7fbb3..fcef1c46 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -443,6 +443,12 @@ definitions: username: type: string example: "zerocool93" + is_admin: + type: boolean + is_bot: + type: boolean + is_active: + type: boolean editgroup: type: object properties: @@ -546,6 +552,29 @@ definitions: additionalProperties: {} role: type: string + auth_oidc: + type: object + required: + - provider + - sub + - iss + properties: + provider: + type: string + sub: + type: string + iss: + type: string + auth_oidc_result: + type: object + required: + - editor + - token + properties: + editor: + $ref: "#/definitions/editor" + token: + type: string x-auth-responses: &AUTHRESPONSES 401: @@ -2616,3 +2645,39 @@ paths: description: Generic Error schema: $ref: "#/definitions/error_response" + /auth/oidc: + post: + operationId: "auth_oidc" + tags: # TAGLINE + security: + # required admin privs + - Bearer: [] + parameters: + - name: oidc_params + in: body + required: true + schema: + $ref: "#/definitions/auth_oidc" + responses: + 200: + description: Found + schema: + $ref: "#/definitions/auth_oidc_result" + 201: + description: Created + schema: + $ref: "#/definitions/auth_oidc_result" + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" + 409: + description: Conflict + schema: + $ref: "#/definitions/error_response" + 500: + description: Generic Error + schema: + $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES + diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index 89017877..f2a58670 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -6481,6 +6481,97 @@ paths: path: "/changelog/:index" HttpMethod: "Get" httpmethod: "get" + /auth/oidc: + post: + operationId: "auth_oidc" + parameters: + - in: "body" + name: "oidc_params" + required: true + schema: + $ref: "#/definitions/auth_oidc" + uppercase_data_type: "AUTHOIDC" + refName: "auth_oidc" + formatString: "{:?}" + example: "???" + model_key: "editgroup_edits" + uppercase_operation_id: "AUTH_OIDC" + consumesJson: true + responses: + 200: + description: "Found" + schema: + $ref: "#/definitions/auth_oidc_result" + x-responseId: "Found" + x-uppercaseResponseId: "FOUND" + uppercase_operation_id: "AUTH_OIDC" + uppercase_data_type: "AUTHOIDCRESULT" + producesJson: true + 201: + description: "Created" + schema: + $ref: "#/definitions/auth_oidc_result" + x-responseId: "Created" + x-uppercaseResponseId: "CREATED" + uppercase_operation_id: "AUTH_OIDC" + uppercase_data_type: "AUTHOIDCRESULT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "AUTH_OIDC" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "AUTH_OIDC" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "AUTH_OIDC" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 409: + description: "Conflict" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Conflict" + x-uppercaseResponseId: "CONFLICT" + uppercase_operation_id: "AUTH_OIDC" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "AUTH_OIDC" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + security: + - Bearer: [] + operation_id: "auth_oidc" + uppercase_operation_id: "AUTH_OIDC" + path: "/auth/oidc" + HttpMethod: "Post" + httpmethod: "post" + noClientExample: true securityDefinitions: Bearer: type: "apiKey" @@ -7642,8 +7733,17 @@ definitions: username: type: "string" example: "zerocool93" + is_admin: + type: "boolean" + is_bot: + type: "boolean" + is_active: + type: "boolean" example: + is_admin: true + is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" + is_bot: true username: "zerocool93" upperCaseName: "EDITOR" editgroup: @@ -7988,6 +8088,39 @@ definitions: creator_id: "creator_id" index: 1 upperCaseName: "RELEASE_CONTRIB" + auth_oidc: + type: "object" + required: + - "iss" + - "provider" + - "sub" + properties: + provider: + type: "string" + sub: + type: "string" + iss: + type: "string" + upperCaseName: "AUTH_OIDC" + auth_oidc_result: + type: "object" + required: + - "editor" + - "token" + properties: + editor: + $ref: "#/definitions/editor" + token: + type: "string" + example: + editor: + is_admin: true + is_active: true + editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" + is_bot: true + username: "zerocool93" + token: "token" + upperCaseName: "AUTH_OIDC_RESULT" file_entity_urls: required: - "rel" diff --git a/rust/fatcat-api-spec/examples/client.rs b/rust/fatcat-api-spec/examples/client.rs index bf0c07b3..d95b4ffd 100644 --- a/rust/fatcat-api-spec/examples/client.rs +++ b/rust/fatcat-api-spec/examples/client.rs @@ -12,7 +12,7 @@ extern crate uuid; use clap::{App, Arg}; #[allow(unused_imports)] use fatcat::{ - AcceptEditgroupResponse, ApiError, ApiNoContext, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, + AcceptEditgroupResponse, ApiError, ApiNoContext, AuthOidcResponse, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, @@ -271,6 +271,12 @@ fn main() { // let result = client.update_creator("ident_example".to_string(), ???, Some("editgroup_id_example".to_string())).wait(); // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, + + // Disabled because there's no example. + // Some("AuthOidc") => { + // let result = client.auth_oidc(???).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + // }, Some("GetEditor") => { let result = client.get_editor("editor_id_example".to_string()).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); diff --git a/rust/fatcat-api-spec/examples/server_lib/server.rs b/rust/fatcat-api-spec/examples/server_lib/server.rs index a9301650..b6408343 100644 --- a/rust/fatcat-api-spec/examples/server_lib/server.rs +++ b/rust/fatcat-api-spec/examples/server_lib/server.rs @@ -11,18 +11,18 @@ use swagger; use fatcat::models; use fatcat::{ - AcceptEditgroupResponse, Api, ApiError, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, - CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, - CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, - DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, - DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, - GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, - GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, - GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, - GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, - GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, - GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, - UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + AcceptEditgroupResponse, Api, ApiError, AuthOidcResponse, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, + CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, + CreateWebcaptureBatchResponse, CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, + DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, + DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, + GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, + GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, + GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, + GetReleaseEditResponse, GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, + GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, + GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, + LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, }; #[derive(Copy, Clone)] @@ -296,6 +296,12 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } + fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box + Send> { + let context = context.clone(); + println!("auth_oidc({:?}) - X-Span-ID: {:?}", oidc_params, context.x_span_id.unwrap_or(String::from("")).clone()); + Box::new(futures::failed("Generic failure".into())) + } + fn get_editor(&self, editor_id: String, context: &Context) -> Box + Send> { let context = context.clone(); println!("get_editor(\"{}\") - X-Span-ID: {:?}", editor_id, context.x_span_id.unwrap_or(String::from("")).clone()); diff --git a/rust/fatcat-api-spec/src/client.rs b/rust/fatcat-api-spec/src/client.rs index b67e193a..44bcd54d 100644 --- a/rust/fatcat-api-spec/src/client.rs +++ b/rust/fatcat-api-spec/src/client.rs @@ -35,18 +35,18 @@ use swagger::{ApiError, Context, XSpanId}; use models; use { - AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, - CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, CreateWebcaptureResponse, - CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, - DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, - DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, - GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, - GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, - GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, GetReleaseFilesResponse, - GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, - GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, - GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, - UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + AcceptEditgroupResponse, Api, AuthOidcResponse, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, + CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, + CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, + DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, + DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, + GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, + GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, + GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, + GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, + GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, + GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, + UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, }; /// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. @@ -2030,6 +2030,100 @@ impl Api for Client { Box::new(futures::done(result)) } + fn auth_oidc(&self, param_oidc_params: models::AuthOidc, context: &Context) -> Box + Send> { + let url = format!("{}/v0/auth/oidc", self.base_path); + + let body = serde_json::to_string(¶m_oidc_params).expect("impossible to fail to serialize"); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Post, &url); + let mut custom_headers = hyper::header::Headers::new(); + + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::AUTH_OIDC.clone())); + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result { + match response.status.to_u16() { + 200 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AuthOidcResponse::Found(body)) + } + 201 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AuthOidcResponse::Created(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AuthOidcResponse::BadRequest(body)) + } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(AuthOidcResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AuthOidcResponse::Forbidden(body)) + } + 409 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AuthOidcResponse::Conflict(body)) + } + 500 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AuthOidcResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + fn get_editor(&self, param_editor_id: String, context: &Context) -> Box + Send> { let url = format!( "{}/v0/editor/{editor_id}", diff --git a/rust/fatcat-api-spec/src/lib.rs b/rust/fatcat-api-spec/src/lib.rs index c6126c9c..c89dc90c 100644 --- a/rust/fatcat-api-spec/src/lib.rs +++ b/rust/fatcat-api-spec/src/lib.rs @@ -348,6 +348,24 @@ pub enum UpdateCreatorResponse { GenericError(models::ErrorResponse), } +#[derive(Debug, PartialEq)] +pub enum AuthOidcResponse { + /// Found + Found(models::AuthOidcResult), + /// Created + Created(models::AuthOidcResult), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), + /// Conflict + Conflict(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + #[derive(Debug, PartialEq)] pub enum GetEditorResponse { /// Found @@ -1281,6 +1299,8 @@ pub trait Api { fn update_creator(&self, ident: String, entity: models::CreatorEntity, editgroup_id: Option, context: &Context) -> Box + Send>; + fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box + Send>; + fn get_editor(&self, editor_id: String, context: &Context) -> Box + Send>; fn get_editor_changelog(&self, editor_id: String, context: &Context) -> Box + Send>; @@ -1527,6 +1547,8 @@ pub trait ApiNoContext { fn update_creator(&self, ident: String, entity: models::CreatorEntity, editgroup_id: Option) -> Box + Send>; + fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box + Send>; + fn get_editor(&self, editor_id: String) -> Box + Send>; fn get_editor_changelog(&self, editor_id: String) -> Box + Send>; @@ -1810,6 +1832,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().update_creator(ident, entity, editgroup_id, &self.context()) } + fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box + Send> { + self.api().auth_oidc(oidc_params, &self.context()) + } + fn get_editor(&self, editor_id: String) -> Box + Send> { self.api().get_editor(editor_id, &self.context()) } diff --git a/rust/fatcat-api-spec/src/mimetypes.rs b/rust/fatcat-api-spec/src/mimetypes.rs index 77a66c46..322ab045 100644 --- a/rust/fatcat-api-spec/src/mimetypes.rs +++ b/rust/fatcat-api-spec/src/mimetypes.rs @@ -452,6 +452,34 @@ pub mod responses { lazy_static! { pub static ref UPDATE_CREATOR_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_CREATED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_CONFLICT: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for GetEditor lazy_static! { pub static ref GET_EDITOR_FOUND: Mime = mime!(Application / Json); @@ -1693,6 +1721,10 @@ pub mod requests { lazy_static! { pub static ref UPDATE_CREATOR: Mime = mime!(Application / Json); } + /// Create Mime objects for the request content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC: Mime = mime!(Application / Json); + } /// Create Mime objects for the request content types for CreateEditgroup lazy_static! { pub static ref CREATE_EDITGROUP: Mime = mime!(Application / Json); diff --git a/rust/fatcat-api-spec/src/models.rs b/rust/fatcat-api-spec/src/models.rs index 4d7575b6..8c17cf66 100644 --- a/rust/fatcat-api-spec/src/models.rs +++ b/rust/fatcat-api-spec/src/models.rs @@ -9,6 +9,43 @@ use models; use std::collections::HashMap; use swagger; +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AuthOidc { + #[serde(rename = "provider")] + pub provider: String, + + #[serde(rename = "sub")] + pub sub: String, + + #[serde(rename = "iss")] + pub iss: String, +} + +impl AuthOidc { + pub fn new(provider: String, sub: String, iss: String) -> AuthOidc { + AuthOidc { + provider: provider, + sub: sub, + iss: iss, + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AuthOidcResult { + #[serde(rename = "editor")] + pub editor: models::Editor, + + #[serde(rename = "token")] + pub token: String, +} + +impl AuthOidcResult { + pub fn new(editor: models::Editor, token: String) -> AuthOidcResult { + AuthOidcResult { editor: editor, token: token } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ChangelogEntry { #[serde(rename = "index")] @@ -272,11 +309,29 @@ pub struct Editor { #[serde(rename = "username")] pub username: String, + + #[serde(rename = "is_admin")] + #[serde(skip_serializing_if = "Option::is_none")] + pub is_admin: Option, + + #[serde(rename = "is_bot")] + #[serde(skip_serializing_if = "Option::is_none")] + pub is_bot: Option, + + #[serde(rename = "is_active")] + #[serde(skip_serializing_if = "Option::is_none")] + pub is_active: Option, } impl Editor { pub fn new(username: String) -> Editor { - Editor { editor_id: None, username: username } + Editor { + editor_id: None, + username: username, + is_admin: None, + is_bot: None, + is_active: None, + } } } diff --git a/rust/fatcat-api-spec/src/server.rs b/rust/fatcat-api-spec/src/server.rs index 19e33194..8a515e43 100644 --- a/rust/fatcat-api-spec/src/server.rs +++ b/rust/fatcat-api-spec/src/server.rs @@ -37,18 +37,18 @@ use swagger::{ApiError, Context, XSpanId}; #[allow(unused_imports)] use models; use { - AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, - CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, CreateWebcaptureResponse, - CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, - DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, - DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, - GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, - GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, - GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, GetReleaseFilesResponse, - GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, - GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, - GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, - UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + AcceptEditgroupResponse, Api, AuthOidcResponse, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, + CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, + CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, + DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, + DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, + GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, + GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, + GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, + GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, + GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, + GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, + UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, }; header! { (Warning, "Warning") => [String] } @@ -2605,6 +2605,154 @@ where "UpdateCreator", ); + let api_clone = api.clone(); + router.post( + "/v0/auth/oidc", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + + let param_oidc_params = req + .get::() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter oidc_params - not valid UTF-8: {}", e))))?; + + let mut unused_elements = Vec::new(); + + let param_oidc_params = if let Some(param_oidc_params_raw) = param_oidc_params { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_oidc_params_raw); + + let param_oidc_params: Option = serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter oidc_params - doesn't match schema: {}", e))))?; + + param_oidc_params + } else { + None + }; + let param_oidc_params = param_oidc_params.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter oidc_params".to_string())))?; + + match api.auth_oidc(param_oidc_params, context).wait() { + Ok(rsp) => match rsp { + AuthOidcResponse::Found(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(200), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::Created(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(201), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_CREATED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::Conflict(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(409), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_CONFLICT.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(500), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) + } + } + } + + handle_request(req, &api_clone, &mut context).or_else(|mut response| { + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + Ok(response) + }) + }, + "AuthOidc", + ); + let api_clone = api.clone(); router.get( "/v0/editor/:editor_id", -- cgit v1.2.3 From 9bfb8e968fcecbe4dc729b89017d0606d271b287 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 16:53:09 -0800 Subject: OIDC auth table, and is_active editor flag --- rust/migrations/2018-05-12-001226_init/down.sql | 1 + rust/migrations/2018-05-12-001226_init/up.sql | 12 ++++++++++++ 2 files changed, 13 insertions(+) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/down.sql b/rust/migrations/2018-05-12-001226_init/down.sql index d156370e..b2666083 100644 --- a/rust/migrations/2018-05-12-001226_init/down.sql +++ b/rust/migrations/2018-05-12-001226_init/down.sql @@ -42,6 +42,7 @@ DROP TABLE IF EXISTS creator_ident CASCADE; DROP TABLE IF EXISTS creator_edit CASCADE; DROP TABLE IF EXISTS abstracts CASCADE; +DROP TABLE IF EXISTS auth_oidc CASCADE; DROP TABLE IF EXISTS editor CASCADE; DROP TABLE IF EXISTS editgroup CASCADE; DROP TABLE IF EXISTS changelog CASCADE; diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index db2e835f..0d9d81d0 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -19,6 +19,7 @@ CREATE TABLE editor ( username TEXT NOT NULL UNIQUE, -- TODO: alphanum and length constraints? is_admin BOOLEAN NOT NULL DEFAULT false, is_bot BOOLEAN NOT NULL DEFAULT false, + is_active BOOLEAN NOT NULL DEFAULT true, registered TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, auth_epoch TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, wrangler_id UUID REFERENCES editor(id), @@ -28,6 +29,17 @@ CREATE TABLE editor ( CREATE INDEX active_editgroup_idx ON editor(active_editgroup_id); CREATE INDEX editor_username_idx ON editor(username); +CREATE TABLE auth_oidc ( + id BIGSERIAL PRIMARY KEY, + created TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, + editor_id UUID REFERENCES editor(id) NOT NULL, + provider TEXT NOT NULL, + oidc_iss TEXT NOT NULL, + oidc_sub TEXT NOT NULL, + UNIQUE (editor_id, provider), + UNIQUE (oidc_iss, oidc_sub) +); + CREATE TABLE editgroup ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), editor_id UUID REFERENCES editor(id) NOT NULL, -- cgit v1.2.3 From 39678e1410a06e99ea71655485786caaf5847e7f Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 16:53:27 -0800 Subject: start to impl oidc auth --- rust/src/api_server.rs | 33 +++++++++++++++---- rust/src/api_wrappers.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++ rust/src/database_models.rs | 28 ++++++++++++++-- rust/src/database_schema.rs | 14 ++++++++ 4 files changed, 146 insertions(+), 8 deletions(-) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index be9f1883..1edf739c 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -477,12 +477,7 @@ impl Server { pub fn get_editor_handler(&self, editor_id: FatCatId, conn: &DbConn) -> Result { let row: EditorRow = editor::table.find(editor_id.to_uuid()).first(conn)?; - - let ed = Editor { - editor_id: Some(uuid2fcid(&row.id)), - username: row.username, - }; - Ok(ed) + Ok(row.into_model()) } pub fn get_editor_changelog_handler( @@ -544,6 +539,32 @@ impl Server { Ok(entry) } + /// This helper either finds an Editor model by OIDC parameters (eg, remote domain and + /// identifier), or creates one and inserts the appropriate auth rows. The semantics are + /// basically an "upsert" of signup/account-creation. + /// Returns an editor model and boolean flag indicating whether a new editor was created or + /// not. + /// If this function creates an editor, it sets the username to "{iss}-{provider}"; the intent + /// is for this to be temporary but unique. Might look like "bnewbold-github", or might look + /// like "895139824-github". This is a hack to make check/creation idempotent. + pub fn auth_oidc_handler(&self, params: AuthOidc, conn: &DbConn) -> Result<(Editor, bool)> { + let existing: Vec<(EditorRow, AuthOidcRow)> = editor::table + .inner_join(auth_oidc::table) + .filter(auth_oidc::oidc_sub.eq(params.sub.clone())) + .filter(auth_oidc::oidc_iss.eq(params.iss)) + .load(conn)?; + + let (editor_row, created): (EditorRow, bool) = match existing.first() { + Some((editor, _)) => (editor.clone(), false), + None => { + let username = format!("{}-{}", params.sub, params.provider); + (create_editor(conn, username, false, false)?, true) + } + }; + + Ok((editor_row.into_model(), created)) + } + entity_batch_handler!(create_container_batch_handler, ContainerEntity); entity_batch_handler!(create_creator_batch_handler, CreatorEntity); entity_batch_handler!(create_file_batch_handler, FileEntity); diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 6c003802..c6966cee 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -1067,4 +1067,83 @@ impl Api for Server { }; Box::new(futures::done(Ok(ret))) } + + fn auth_oidc( + &self, + params: models::AuthOidc, + context: &Context, + ) -> Box + Send> { + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| { + let auth_context = self + .auth_confectionary + .require_auth(&conn, &context.auth_data)?; + auth_context.require_role(FatcatRole::Admin)?; + let (editor, created) = self.auth_oidc_handler(params, &conn)?; + // create an auth token; leave it to webface to attenuate to a given duration + let token = self + .auth_confectionary + .create_token(FatCatId::from_str(&editor.editor_id.clone().unwrap())?, None)?; + let result = AuthOidcResult { editor, token }; + Ok((result, created)) + }) { + Ok((result, true)) => AuthOidcResponse::Created(result), + Ok((result, false)) => AuthOidcResponse::Found(result), + Err(Error(ErrorKind::Diesel(e), _)) => AuthOidcResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }), + Err(Error(ErrorKind::Uuid(e), _)) => AuthOidcResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }), + Err(Error(ErrorKind::InvalidFatcatId(e), _)) => { + AuthOidcResponse::BadRequest(ErrorResponse { + message: ErrorKind::InvalidFatcatId(e).to_string(), + }) + } + Err(Error(ErrorKind::MalformedExternalId(e), _)) => { + AuthOidcResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::MalformedChecksum(e), _)) => { + AuthOidcResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::NotInControlledVocabulary(e), _)) => { + AuthOidcResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::EditgroupAlreadyAccepted(e), _)) => { + AuthOidcResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::InvalidCredentials(e), _)) => + // TODO: why can't I NotAuthorized here? + { + AuthOidcResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => { + AuthOidcResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::OtherBadRequest(e), _)) => { + AuthOidcResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }) + } + Err(e) => { + error!("{}", e); + AuthOidcResponse::GenericError(ErrorResponse { + message: e.to_string(), + }) + } + }; + Box::new(futures::done(Ok(ret))) + } } diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index 7a65f901..5c8e17d3 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -4,7 +4,7 @@ use api_helpers::uuid2fcid; use chrono; use database_schema::*; use errors::*; -use fatcat_api_spec::models::{ChangelogEntry, Editgroup, EntityEdit}; +use fatcat_api_spec::models::{ChangelogEntry, Editgroup, Editor, EntityEdit}; use serde_json; use uuid::Uuid; @@ -559,7 +559,7 @@ pub struct EditgroupRow { } impl EditgroupRow { - /// Returns an Edigroup API model *without* the entity edits actually populated. Useful for, + /// Returns an Editgroup API model *without* the entity edits actually populated. Useful for, /// eg, entity history queries (where we already have the entity edit we want) pub fn into_model_partial(self) -> Editgroup { Editgroup { @@ -579,12 +579,36 @@ pub struct EditorRow { pub username: String, pub is_admin: bool, pub is_bot: bool, + pub is_active: bool, pub registered: chrono::NaiveDateTime, pub auth_epoch: chrono::NaiveDateTime, pub wrangler_id: Option, pub active_editgroup_id: Option, } +impl EditorRow { + pub fn into_model(self) -> Editor { + Editor { + editor_id: Some(uuid2fcid(&self.id)), + username: self.username, + is_admin: Some(self.is_admin), + is_bot: Some(self.is_bot), + is_active: Some(self.is_active), + } + } +} + +#[derive(Debug, Clone, Queryable, Associations, AsChangeset)] +#[table_name = "auth_oidc"] +pub struct AuthOidcRow { + pub id: i64, + pub created: chrono::NaiveDateTime, + pub editor_id: Uuid, + pub provider: String, + pub oidc_iss: String, + pub oidc_sub: String, +} + #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] #[table_name = "changelog"] pub struct ChangelogRow { diff --git a/rust/src/database_schema.rs b/rust/src/database_schema.rs index c240048e..49863fc7 100644 --- a/rust/src/database_schema.rs +++ b/rust/src/database_schema.rs @@ -5,6 +5,17 @@ table! { } } +table! { + auth_oidc (id) { + id -> Int8, + created -> Timestamptz, + editor_id -> Uuid, + provider -> Text, + oidc_iss -> Text, + oidc_sub -> Text, + } +} + table! { changelog (id) { id -> Int8, @@ -98,6 +109,7 @@ table! { username -> Text, is_admin -> Bool, is_bot -> Bool, + is_active -> Bool, registered -> Timestamptz, auth_epoch -> Timestamptz, wrangler_id -> Nullable, @@ -387,6 +399,7 @@ table! { } } +joinable!(auth_oidc -> editor (editor_id)); joinable!(changelog -> editgroup (editgroup_id)); joinable!(container_edit -> editgroup (editgroup_id)); joinable!(container_ident -> container_rev (rev_id)); @@ -424,6 +437,7 @@ joinable!(work_ident -> work_rev (rev_id)); allow_tables_to_appear_in_same_query!( abstracts, + auth_oidc, changelog, container_edit, container_ident, -- cgit v1.2.3 From b10ee85c04816f16738ff30b84262a6ab8440307 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 17:52:53 -0800 Subject: better username constraints in SQL --- rust/migrations/2018-05-12-001226_init/up.sql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index 0d9d81d0..53762f40 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -16,7 +16,7 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE TABLE editor ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - username TEXT NOT NULL UNIQUE, -- TODO: alphanum and length constraints? + username TEXT NOT NULL CHECK (username ~* '^[A-Za-z0-9][A-Za-z0-9._-]{2,15}$'), -- UNIQ below is_admin BOOLEAN NOT NULL DEFAULT false, is_bot BOOLEAN NOT NULL DEFAULT false, is_active BOOLEAN NOT NULL DEFAULT true, @@ -26,6 +26,8 @@ CREATE TABLE editor ( active_editgroup_id UUID -- REFERENCES( editgroup(id) via ALTER below ); +-- case-insensitive UNIQ index on username +CREATE UNIQUE INDEX editor_username_uniq_idx on editor(lower(username)); CREATE INDEX active_editgroup_idx ON editor(active_editgroup_id); CREATE INDEX editor_username_idx ON editor(username); -- cgit v1.2.3 From 65fa084379a159db81fc5424deda18013f01194b Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 17:53:04 -0800 Subject: rust codegen --- rust/fatcat-api-spec/README.md | 3 +- rust/fatcat-api-spec/api.yaml | 28 ++++ rust/fatcat-api-spec/api/swagger.yaml | 87 ++++++++++++ rust/fatcat-api-spec/examples/client.rs | 8 +- rust/fatcat-api-spec/examples/server_lib/server.rs | 14 +- rust/fatcat-api-spec/src/client.rs | 93 ++++++++++++- rust/fatcat-api-spec/src/lib.rs | 24 ++++ rust/fatcat-api-spec/src/mimetypes.rs | 28 ++++ rust/fatcat-api-spec/src/server.rs | 153 ++++++++++++++++++++- 9 files changed, 433 insertions(+), 5 deletions(-) (limited to 'rust') diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index e4fba05b..c33509da 100644 --- a/rust/fatcat-api-spec/README.md +++ b/rust/fatcat-api-spec/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2019-01-04T00:25:33.063Z +- Build date: 2019-01-04T01:38:25.420Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. @@ -82,6 +82,7 @@ cargo run --example client UpdateCreator cargo run --example client AuthOidc cargo run --example client GetEditor cargo run --example client GetEditorChangelog +cargo run --example client UpdateEditor cargo run --example client AcceptEditgroup cargo run --example client CreateEditgroup cargo run --example client GetChangelog diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index fcef1c46..b9a61fe4 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -2484,6 +2484,34 @@ paths: description: Generic Error schema: $ref: "#/definitions/error_response" + put: + operationId: "update_editor" + parameters: + - name: editor + in: body + required: true + schema: + $ref: "#/definitions/editor" + security: + - Bearer: [] + responses: + 200: + description: Updated Editor + schema: + $ref: "#/definitions/editor" + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" + 404: + description: Not Found + schema: + $ref: "#/definitions/error_response" + 500: + description: Generic Error + schema: + $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES /editor/{editor_id}/changelog: parameters: - name: editor_id diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index f2a58670..d58785c8 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -6119,6 +6119,93 @@ paths: path: "/editor/:editor_id" HttpMethod: "Get" httpmethod: "get" + put: + operationId: "update_editor" + parameters: + - name: "editor_id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"editor_id_example\".to_string()" + - in: "body" + name: "editor" + required: true + schema: + $ref: "#/definitions/editor" + uppercase_data_type: "EDITOR" + refName: "editor" + formatString: "{:?}" + example: "???" + model_key: "editgroup_edits" + uppercase_operation_id: "UPDATE_EDITOR" + consumesJson: true + responses: + 200: + description: "Updated Editor" + schema: + $ref: "#/definitions/editor" + x-responseId: "UpdatedEditor" + x-uppercaseResponseId: "UPDATED_EDITOR" + uppercase_operation_id: "UPDATE_EDITOR" + uppercase_data_type: "EDITOR" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "UPDATE_EDITOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "UPDATE_EDITOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "UPDATE_EDITOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "UPDATE_EDITOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "UPDATE_EDITOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + security: + - Bearer: [] + operation_id: "update_editor" + uppercase_operation_id: "UPDATE_EDITOR" + path: "/editor/:editor_id" + HttpMethod: "Put" + httpmethod: "put" + noClientExample: true /editor/{editor_id}/changelog: get: operationId: "get_editor_changelog" diff --git a/rust/fatcat-api-spec/examples/client.rs b/rust/fatcat-api-spec/examples/client.rs index d95b4ffd..4eed8ae4 100644 --- a/rust/fatcat-api-spec/examples/client.rs +++ b/rust/fatcat-api-spec/examples/client.rs @@ -23,7 +23,8 @@ use fatcat::{ GetReleaseEditResponse, GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, - LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, + UpdateWorkResponse, }; #[allow(unused_imports)] use futures::{future, stream, Future, Stream}; @@ -287,6 +288,11 @@ fn main() { println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } + // Disabled because there's no example. + // Some("UpdateEditor") => { + // let result = client.update_editor("editor_id_example".to_string(), ???).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + // }, Some("AcceptEditgroup") => { let result = client.accept_editgroup("editgroup_id_example".to_string()).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); diff --git a/rust/fatcat-api-spec/examples/server_lib/server.rs b/rust/fatcat-api-spec/examples/server_lib/server.rs index b6408343..5e86a10e 100644 --- a/rust/fatcat-api-spec/examples/server_lib/server.rs +++ b/rust/fatcat-api-spec/examples/server_lib/server.rs @@ -22,7 +22,8 @@ use fatcat::{ GetReleaseEditResponse, GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, - LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, + UpdateWorkResponse, }; #[derive(Copy, Clone)] @@ -314,6 +315,17 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } + fn update_editor(&self, editor_id: String, editor: models::Editor, context: &Context) -> Box + Send> { + let context = context.clone(); + println!( + "update_editor(\"{}\", {:?}) - X-Span-ID: {:?}", + editor_id, + editor, + context.x_span_id.unwrap_or(String::from("")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + fn accept_editgroup(&self, editgroup_id: String, context: &Context) -> Box + Send> { let context = context.clone(); println!("accept_editgroup(\"{}\") - X-Span-ID: {:?}", editgroup_id, context.x_span_id.unwrap_or(String::from("")).clone()); diff --git a/rust/fatcat-api-spec/src/client.rs b/rust/fatcat-api-spec/src/client.rs index 44bcd54d..470a5350 100644 --- a/rust/fatcat-api-spec/src/client.rs +++ b/rust/fatcat-api-spec/src/client.rs @@ -46,7 +46,7 @@ use { GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, - UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + UpdateContainerResponse, UpdateCreatorResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, }; /// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. @@ -2252,6 +2252,97 @@ impl Api for Client { Box::new(futures::done(result)) } + fn update_editor(&self, param_editor_id: String, param_editor: models::Editor, context: &Context) -> Box + Send> { + let url = format!( + "{}/v0/editor/{editor_id}", + self.base_path, + editor_id = utf8_percent_encode(¶m_editor_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let body = serde_json::to_string(¶m_editor).expect("impossible to fail to serialize"); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Put, &url); + let mut custom_headers = hyper::header::Headers::new(); + + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::UPDATE_EDITOR.clone())); + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result { + match response.status.to_u16() { + 200 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateEditorResponse::UpdatedEditor(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateEditorResponse::BadRequest(body)) + } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(UpdateEditorResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateEditorResponse::Forbidden(body)) + } + 404 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateEditorResponse::NotFound(body)) + } + 500 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(UpdateEditorResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + fn accept_editgroup(&self, param_editgroup_id: String, context: &Context) -> Box + Send> { let url = format!( "{}/v0/editgroup/{editgroup_id}/accept", diff --git a/rust/fatcat-api-spec/src/lib.rs b/rust/fatcat-api-spec/src/lib.rs index c89dc90c..258b635b 100644 --- a/rust/fatcat-api-spec/src/lib.rs +++ b/rust/fatcat-api-spec/src/lib.rs @@ -390,6 +390,22 @@ pub enum GetEditorChangelogResponse { GenericError(models::ErrorResponse), } +#[derive(Debug, PartialEq)] +pub enum UpdateEditorResponse { + /// Updated Editor + UpdatedEditor(models::Editor), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + #[derive(Debug, PartialEq)] pub enum AcceptEditgroupResponse { /// Merged Successfully @@ -1305,6 +1321,8 @@ pub trait Api { fn get_editor_changelog(&self, editor_id: String, context: &Context) -> Box + Send>; + fn update_editor(&self, editor_id: String, editor: models::Editor, context: &Context) -> Box + Send>; + fn accept_editgroup(&self, editgroup_id: String, context: &Context) -> Box + Send>; fn create_editgroup(&self, editgroup: models::Editgroup, context: &Context) -> Box + Send>; @@ -1553,6 +1571,8 @@ pub trait ApiNoContext { fn get_editor_changelog(&self, editor_id: String) -> Box + Send>; + fn update_editor(&self, editor_id: String, editor: models::Editor) -> Box + Send>; + fn accept_editgroup(&self, editgroup_id: String) -> Box + Send>; fn create_editgroup(&self, editgroup: models::Editgroup) -> Box + Send>; @@ -1844,6 +1864,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().get_editor_changelog(editor_id, &self.context()) } + fn update_editor(&self, editor_id: String, editor: models::Editor) -> Box + Send> { + self.api().update_editor(editor_id, editor, &self.context()) + } + fn accept_editgroup(&self, editgroup_id: String) -> Box + Send> { self.api().accept_editgroup(editgroup_id, &self.context()) } diff --git a/rust/fatcat-api-spec/src/mimetypes.rs b/rust/fatcat-api-spec/src/mimetypes.rs index 322ab045..cfdd357d 100644 --- a/rust/fatcat-api-spec/src/mimetypes.rs +++ b/rust/fatcat-api-spec/src/mimetypes.rs @@ -512,6 +512,30 @@ pub mod responses { lazy_static! { pub static ref GET_EDITOR_CHANGELOG_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_UPDATED_EDITOR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for AcceptEditgroup lazy_static! { pub static ref ACCEPT_EDITGROUP_MERGED_SUCCESSFULLY: Mime = mime!(Application / Json); @@ -1725,6 +1749,10 @@ pub mod requests { lazy_static! { pub static ref AUTH_OIDC: Mime = mime!(Application / Json); } + /// Create Mime objects for the request content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR: Mime = mime!(Application / Json); + } /// Create Mime objects for the request content types for CreateEditgroup lazy_static! { pub static ref CREATE_EDITGROUP: Mime = mime!(Application / Json); diff --git a/rust/fatcat-api-spec/src/server.rs b/rust/fatcat-api-spec/src/server.rs index 8a515e43..c0903676 100644 --- a/rust/fatcat-api-spec/src/server.rs +++ b/rust/fatcat-api-spec/src/server.rs @@ -48,7 +48,7 @@ use { GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, - UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + UpdateContainerResponse, UpdateCreatorResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, }; header! { (Warning, "Warning") => [String] } @@ -2931,6 +2931,157 @@ where "GetEditorChangelog", ); + let api_clone = api.clone(); + router.put( + "/v0/editor/:editor_id", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + + // Path parameters + let param_editor_id = { + let param = req + .extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("editor_id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editor_id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editor_id: {}", e))))? + }; + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + + let param_editor = req + .get::() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editor - not valid UTF-8: {}", e))))?; + + let mut unused_elements = Vec::new(); + + let param_editor = if let Some(param_editor_raw) = param_editor { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_editor_raw); + + let param_editor: Option = serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editor - doesn't match schema: {}", e))))?; + + param_editor + } else { + None + }; + let param_editor = param_editor.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter editor".to_string())))?; + + match api.update_editor(param_editor_id, param_editor, context).wait() { + Ok(rsp) => match rsp { + UpdateEditorResponse::UpdatedEditor(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(200), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_UPDATED_EDITOR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + UpdateEditorResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + UpdateEditorResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + UpdateEditorResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + UpdateEditorResponse::NotFound(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(404), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + UpdateEditorResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(500), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) + } + } + } + + handle_request(req, &api_clone, &mut context).or_else(|mut response| { + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + Ok(response) + }) + }, + "UpdateEditor", + ); + let api_clone = api.clone(); router.post( "/v0/editgroup/:editgroup_id/accept", -- cgit v1.2.3 From ec180ef211112d1ae14bf7bad06bf71686cdaf89 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 17:53:30 -0800 Subject: editor update --- rust/src/api_helpers.rs | 49 ++++++++++++++++++++++++++++- rust/src/api_wrappers.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 4 deletions(-) (limited to 'rust') diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index 7478da9d..79114d4f 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -228,13 +228,13 @@ pub fn make_edit_context( }) } -// TODO: verify username (alphanum, etc) pub fn create_editor( conn: &DbConn, username: String, is_admin: bool, is_bot: bool, ) -> Result { + check_username(&username)?; let ed: EditorRow = diesel::insert_into(editor::table) .values(( editor::username.eq(username), @@ -245,6 +245,19 @@ pub fn create_editor( Ok(ed) } +pub fn update_editor_username( + conn: &DbConn, + editor_id: FatCatId, + username: String, +) -> Result { + check_username(&username)?; + diesel::update(editor::table.find(editor_id.to_uuid())) + .set(editor::username.eq(username)) + .execute(conn)?; + let editor: EditorRow = editor::table.find(editor_id.to_uuid()).get_result(conn)?; + Ok(editor) +} + /// This function should always be run within a transaction pub fn get_or_create_editgroup(editor_id: Uuid, conn: &DbConn) -> Result { // check for current active @@ -344,6 +357,40 @@ pub fn uuid2fcid(id: &Uuid) -> String { BASE32_NOPAD.encode(raw).to_lowercase() } +pub fn check_username(raw: &str) -> Result<()> { + lazy_static! { + static ref RE: Regex = Regex::new(r"^[A-Za-z0-9][A-Za-z0-9._-]{2,15}$").unwrap(); + } + if RE.is_match(raw) { + Ok(()) + } else { + Err(ErrorKind::MalformedExternalId(format!( + "not a valid username: '{}' (expected, eg, 'AcidBurn')", + raw + )) + .into()) + } +} + +#[test] +fn test_check_username() { + assert!(check_username("bnewbold").is_ok()); + assert!(check_username("BNEWBOLD").is_ok()); + assert!(check_username("admin").is_ok()); + assert!(check_username("friend-bot").is_ok()); + assert!(check_username("dog").is_ok()); + assert!(check_username("g_____").is_ok()); + + assert!(check_username("").is_err()); + assert!(check_username("_").is_err()); + assert!(check_username("gg").is_err()); + assert!(check_username("adminadminadminadminadminadminadmin").is_err()); + assert!(check_username("bryan newbold").is_err()); + assert!(check_username("01234567-3456-6780").is_err()); + assert!(check_username(".admin").is_err()); + assert!(check_username("-bot").is_err()); +} + pub fn check_pmcid(raw: &str) -> Result<()> { lazy_static! { static ref RE: Regex = Regex::new(r"^PMC\d+$").unwrap(); diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index c6966cee..abaa2310 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -904,6 +904,81 @@ impl Api for Server { Box::new(futures::done(Ok(ret))) } + /// For now, only implements updating username + fn update_editor( + &self, + editor_id: String, + editor: models::Editor, + context: &Context, + ) -> Box + Send> { + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| { + if Some(editor_id.clone()) != editor.editor_id { + return Err( + ErrorKind::OtherBadRequest("editor_id doesn't match".to_string()).into(), + ); + } + let auth_context = self + .auth_confectionary + .require_auth(&conn, &context.auth_data)?; + let editor_id = FatCatId::from_str(&editor_id)?; + // DANGER! these permissions are for username updates only! + if editor_id == auth_context.editor_id { + // self edit of username allowed + auth_context.require_role(FatcatRole::Editor)?; + } else { + // admin can update any username + auth_context.require_role(FatcatRole::Admin)?; + }; + update_editor_username(&conn, editor_id, editor.username) + .map(|e| e.into_model()) + }) { + Ok(editor) => UpdateEditorResponse::UpdatedEditor(editor), + Err(Error(ErrorKind::Diesel(e), _)) => { + UpdateEditorResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::Uuid(e), _)) => UpdateEditorResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }), + Err(Error(ErrorKind::InvalidFatcatId(e), _)) => { + UpdateEditorResponse::BadRequest(ErrorResponse { + message: ErrorKind::InvalidFatcatId(e).to_string(), + }) + } + Err(Error(ErrorKind::MalformedExternalId(e), _)) => { + UpdateEditorResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::InvalidCredentials(e), _)) => + // TODO: why can't I NotAuthorized here? + { + UpdateEditorResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => { + UpdateEditorResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + } + Err(Error(ErrorKind::OtherBadRequest(e), _)) => { + UpdateEditorResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }) + } + Err(e) => { + error!("{}", e); + UpdateEditorResponse::GenericError(ErrorResponse { + message: e.to_string(), + }) + } + }; + Box::new(futures::done(Ok(ret))) + } + fn accept_editgroup( &self, editgroup_id: String, @@ -1081,9 +1156,10 @@ impl Api for Server { auth_context.require_role(FatcatRole::Admin)?; let (editor, created) = self.auth_oidc_handler(params, &conn)?; // create an auth token; leave it to webface to attenuate to a given duration - let token = self - .auth_confectionary - .create_token(FatCatId::from_str(&editor.editor_id.clone().unwrap())?, None)?; + let token = self.auth_confectionary.create_token( + FatCatId::from_str(&editor.editor_id.clone().unwrap())?, + None, + )?; let result = AuthOidcResult { editor, token }; Ok((result, created)) }) { -- cgit v1.2.3 From ab4e1bbf2bb9bb67d6639b90a10970b54dd1aa03 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 22:08:47 -0800 Subject: allow passing prefered_username in oidc signup/login --- fatcat-openapi2.yml | 3 +++ python/fatcat_client/models/auth_oidc.py | 33 +++++++++++++++++++++++++++++--- rust/fatcat-api-spec/README.md | 2 +- rust/fatcat-api-spec/api.yaml | 3 +++ rust/fatcat-api-spec/api/swagger.yaml | 3 +++ rust/fatcat-api-spec/src/models.rs | 6 +++++- 6 files changed, 45 insertions(+), 5 deletions(-) (limited to 'rust') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index b9a61fe4..501a1296 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -558,6 +558,7 @@ definitions: - provider - sub - iss + - preferred_username properties: provider: type: string @@ -565,6 +566,8 @@ definitions: type: string iss: type: string + preferred_username: + type: string auth_oidc_result: type: object required: diff --git a/python/fatcat_client/models/auth_oidc.py b/python/fatcat_client/models/auth_oidc.py index 871cc23d..1ee4c429 100644 --- a/python/fatcat_client/models/auth_oidc.py +++ b/python/fatcat_client/models/auth_oidc.py @@ -33,26 +33,30 @@ class AuthOidc(object): swagger_types = { 'provider': 'str', 'sub': 'str', - 'iss': 'str' + 'iss': 'str', + 'preferred_username': 'str' } attribute_map = { 'provider': 'provider', 'sub': 'sub', - 'iss': 'iss' + 'iss': 'iss', + 'preferred_username': 'preferred_username' } - def __init__(self, provider=None, sub=None, iss=None): # noqa: E501 + def __init__(self, provider=None, sub=None, iss=None, preferred_username=None): # noqa: E501 """AuthOidc - a model defined in Swagger""" # noqa: E501 self._provider = None self._sub = None self._iss = None + self._preferred_username = None self.discriminator = None self.provider = provider self.sub = sub self.iss = iss + self.preferred_username = preferred_username @property def provider(self): @@ -123,6 +127,29 @@ class AuthOidc(object): self._iss = iss + @property + def preferred_username(self): + """Gets the preferred_username of this AuthOidc. # noqa: E501 + + + :return: The preferred_username of this AuthOidc. # noqa: E501 + :rtype: str + """ + return self._preferred_username + + @preferred_username.setter + def preferred_username(self, preferred_username): + """Sets the preferred_username of this AuthOidc. + + + :param preferred_username: The preferred_username of this AuthOidc. # noqa: E501 + :type: str + """ + if preferred_username is None: + raise ValueError("Invalid value for `preferred_username`, must not be `None`") # noqa: E501 + + self._preferred_username = preferred_username + def to_dict(self): """Returns the model properties as a dict""" result = {} diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index c33509da..f81f641a 100644 --- a/rust/fatcat-api-spec/README.md +++ b/rust/fatcat-api-spec/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2019-01-04T01:38:25.420Z +- Build date: 2019-01-04T05:57:03.701Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index b9a61fe4..501a1296 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -558,6 +558,7 @@ definitions: - provider - sub - iss + - preferred_username properties: provider: type: string @@ -565,6 +566,8 @@ definitions: type: string iss: type: string + preferred_username: + type: string auth_oidc_result: type: object required: diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index d58785c8..a19d6ae1 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -8179,6 +8179,7 @@ definitions: type: "object" required: - "iss" + - "preferred_username" - "provider" - "sub" properties: @@ -8188,6 +8189,8 @@ definitions: type: "string" iss: type: "string" + preferred_username: + type: "string" upperCaseName: "AUTH_OIDC" auth_oidc_result: type: "object" diff --git a/rust/fatcat-api-spec/src/models.rs b/rust/fatcat-api-spec/src/models.rs index 8c17cf66..536bdd24 100644 --- a/rust/fatcat-api-spec/src/models.rs +++ b/rust/fatcat-api-spec/src/models.rs @@ -19,14 +19,18 @@ pub struct AuthOidc { #[serde(rename = "iss")] pub iss: String, + + #[serde(rename = "preferred_username")] + pub preferred_username: String, } impl AuthOidc { - pub fn new(provider: String, sub: String, iss: String) -> AuthOidc { + pub fn new(provider: String, sub: String, iss: String, preferred_username: String) -> AuthOidc { AuthOidc { provider: provider, sub: sub, iss: iss, + preferred_username: preferred_username, } } } -- cgit v1.2.3 From 94a6c7f58ba23b2c37b0a997fc4a5e2e16692599 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 3 Jan 2019 22:09:06 -0800 Subject: fix rust side of login --- rust/src/api_server.rs | 23 +++++++++++++++++------ rust/src/api_wrappers.rs | 3 +-- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 1edf739c..349c6a27 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -544,21 +544,32 @@ impl Server { /// basically an "upsert" of signup/account-creation. /// Returns an editor model and boolean flag indicating whether a new editor was created or /// not. - /// If this function creates an editor, it sets the username to "{iss}-{provider}"; the intent - /// is for this to be temporary but unique. Might look like "bnewbold-github", or might look - /// like "895139824-github". This is a hack to make check/creation idempotent. + /// If this function creates an editor, it sets the username to + /// "{preferred_username}-{provider}"; the intent is for this to be temporary but unique. Might + /// look like "bnewbold-github", or might look like "895139824-github". This is a hack to make + /// check/creation idempotent. pub fn auth_oidc_handler(&self, params: AuthOidc, conn: &DbConn) -> Result<(Editor, bool)> { let existing: Vec<(EditorRow, AuthOidcRow)> = editor::table .inner_join(auth_oidc::table) .filter(auth_oidc::oidc_sub.eq(params.sub.clone())) - .filter(auth_oidc::oidc_iss.eq(params.iss)) + .filter(auth_oidc::oidc_iss.eq(params.iss.clone())) .load(conn)?; let (editor_row, created): (EditorRow, bool) = match existing.first() { Some((editor, _)) => (editor.clone(), false), None => { - let username = format!("{}-{}", params.sub, params.provider); - (create_editor(conn, username, false, false)?, true) + let username = format!("{}-{}", params.preferred_username, params.provider); + let editor = create_editor(conn, username, false, false)?; + // create an auth login row so the user can log back in + diesel::insert_into(auth_oidc::table) + .values(( + auth_oidc::editor_id.eq(editor.id), + auth_oidc::provider.eq(params.provider), + auth_oidc::oidc_iss.eq(params.iss), + auth_oidc::oidc_sub.eq(params.sub), + )) + .execute(conn)?; + (editor, true) } }; diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index abaa2310..c663c11d 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -930,8 +930,7 @@ impl Api for Server { // admin can update any username auth_context.require_role(FatcatRole::Admin)?; }; - update_editor_username(&conn, editor_id, editor.username) - .map(|e| e.into_model()) + update_editor_username(&conn, editor_id, editor.username).map(|e| e.into_model()) }) { Ok(editor) => UpdateEditorResponse::UpdatedEditor(editor), Err(Error(ErrorKind::Diesel(e), _)) => { -- cgit v1.2.3 From 67d56af9447a69700a5a2ad816efcace679145d2 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 4 Jan 2019 13:19:45 -0800 Subject: document rust fatcatd config --- rust/.gitignore | 1 + rust/README.md | 38 +++++++++++++++++++++++++++++--------- rust/env.example | 6 ++++++ 3 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 rust/env.example (limited to 'rust') diff --git a/rust/.gitignore b/rust/.gitignore index 18b70ae0..a2068a8a 100644 --- a/rust/.gitignore +++ b/rust/.gitignore @@ -1,3 +1,4 @@ +.env target/ !.cargo diff --git a/rust/README.md b/rust/README.md index ecbfba2d..a6bb34b6 100644 --- a/rust/README.md +++ b/rust/README.md @@ -3,25 +3,24 @@ Rust implementation of fatcat API server (`fatcatd`). ## Development +You need the following dependencies installed locally to build, run tests, and +do development work: + - rust stable, 1.29+ (eg, via "rustup", includes cargo tool) - diesel (`cargo install diesel_cli`) - postgres (9.6+; targetting 11.1 for production) - postgres libs (debian: `sudo apt install libsqlite3-dev libpq-dev`) - libsodium library and development headers (debian: `libsodium-dev`) +Copying commands out of `../.gitlab-ci.yml` file may be the fastest way to get +started. + Create a new postgres superuser. A regular postgres user and an existing database should also work (with up/down migrations), but it's easier to just blow the entire database away. -Create a `.env` file with configuration: - - DATABASE_URL=postgres://fatcat:tactaf@localhost/fatcat_rs - TEST_DATABASE_URL=postgres://fatcat:tactaf@localhost/fatcat_rs_test - AUTH_LOCATION=dev.fatcat.wiki - AUTH_KEY_IDENT=2018-12-31-dev - AUTH_SECRET_KEY=VQe8kdn8laZ3MArKAzOeWWNUQgM6IjduG2jwKnSWehQ= - -Re-create database from scratch: +Copy `env.example` to `.env`, update if needed, then re-create database from +scratch: diesel database reset @@ -34,3 +33,24 @@ Tests: cargo test -- --test-threads 1 See `HACKING` for some more advanced tips and commands. + +## Configuration + +All configuration goes through environment variables, the notable ones being: + +- `DATABASE_URL`: postgres connection details (username, password, host, and database) +- `TEST_DATABASE_URL`: used when running `cargo test` +- `AUTH_LOCATION`: the domain authentication tokens should be valid over +- `AUTH_KEY_IDENT`: a unique name for the primary auth signing key (used to + find the correct key after key rotation has occured) +- `AUTH_SECRET_KEY`: base64-encoded secret key used to both sign and verify + authentication tokens (symmetric encryption) +- `AUTH_ALT_KEYS`: additional ident/key pairs that can be used to verify tokens + (to enable key rotation). Syntax is like `:,:key2,...`. + +To setup authentication with a new secret authentication key, run: + + cargo run --bin fatcat-auth create-key + +then copy the last line as `AUTH_SECRET_KEY` in `.env`, and update +`AUTH_KEY_IDENT` with a unique name for this new key (eg, including the date). diff --git a/rust/env.example b/rust/env.example new file mode 100644 index 00000000..0ecf58a5 --- /dev/null +++ b/rust/env.example @@ -0,0 +1,6 @@ +DATABASE_URL="postgres://fatcat:tactaf@localhost/fatcat" +TEST_DATABASE_URL="postgres://fatcat:tactaf@localhost/fatcat_test +AUTH_LOCATION="dev.fatcat.wiki" +AUTH_KEY_IDENT="20190101-dev-dummy-key" +AUTH_SECRET_KEY="5555555555555555555555555555555555555555555=" +AUTH_ALT_KEYS="20181220-dev:6666666666666666666666666666666666666666666=,20181210-dev:7777777777777777777777777777777777777777777=" -- cgit v1.2.3 From 3aee89745355b0ced5223c601a03f77e46d997dc Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 4 Jan 2019 13:26:18 -0800 Subject: update rust README --- rust/README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/README.md b/rust/README.md index a6bb34b6..decfc74d 100644 --- a/rust/README.md +++ b/rust/README.md @@ -1,5 +1,17 @@ -Rust implementation of fatcat API server (`fatcatd`). +Rust implementation of fatcat API server. Commands include: + +- `fatcatd`: the API server itself +- `fatcat-auth`: privileged command to manage authentication keys, tokens, and + accounts. Useful to generate admin accounts, new signing keys, etc. +- `fatcat-export`: high-speed JSON export tool, which talks directly to the + database (instead of going through the API). See `README.export.md`. + +The `fatcat-api-spec` crate is generated from the openapi/swagger spec and +contains Rust models, response types, and endpoint definitions (but not +implementations). + +The SQL database schema (and migrations) are under `./migrations/`. ## Development @@ -32,6 +44,9 @@ Tests: cargo test -- --test-threads 1 +Note that most "integration" level tests are written in python and run by +`pytest`; see `../python/README.md`. + See `HACKING` for some more advanced tips and commands. ## Configuration -- cgit v1.2.3 From cef60bd9f5af2bfe168ce378287df9ea76baa853 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 4 Jan 2019 14:02:46 -0800 Subject: rust: TODO updates --- rust/TODO | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'rust') diff --git a/rust/TODO b/rust/TODO index 18b94346..d518bbf9 100644 --- a/rust/TODO +++ b/rust/TODO @@ -5,16 +5,19 @@ correctness - changelog sequence without gaps - batch insert editgroup behavior; always a new editgroup? +refactor: +- consistent `conn` and `context` orders in _handler() functions + edit lifecycle - editgroup: state to track review status? - per-edit extra JSON account helper tool - set admin bit -- create editors -- create keypairs -- generate tokens -- test/validate tokens +x create editors +x create keypairs +x generate tokens +x test/validate tokens later: - "prev_rev" required in updates -- cgit v1.2.3 From eccdd4577a54b230460de6733ed7b003b6f8f182 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 4 Jan 2019 19:24:21 -0800 Subject: add superuser role/flag --- rust/migrations/2018-05-12-001226_init/up.sql | 15 +++++++------ rust/src/api_wrappers.rs | 20 ++++++++--------- rust/src/auth.rs | 32 ++++++++++++++++++--------- rust/src/database_models.rs | 1 + rust/src/database_schema.rs | 1 + rust/tests/test_auth.rs | 6 ++--- 6 files changed, 44 insertions(+), 31 deletions(-) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index 53762f40..b5b39f6f 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -17,6 +17,7 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE TABLE editor ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), username TEXT NOT NULL CHECK (username ~* '^[A-Za-z0-9][A-Za-z0-9._-]{2,15}$'), -- UNIQ below + is_superuser BOOLEAN NOT NULL DEFAULT false, is_admin BOOLEAN NOT NULL DEFAULT false, is_bot BOOLEAN NOT NULL DEFAULT false, is_active BOOLEAN NOT NULL DEFAULT true, @@ -470,10 +471,13 @@ CREATE INDEX webcapture_rev_release_target_release_idx ON webcapture_rev_release BEGIN; -INSERT INTO editor (id, username, is_admin, auth_epoch) VALUES - ('00000000-0000-0000-AAAA-000000000001', 'admin', true, '1970-01-01T01:01:01Z'), -- aaaaaaaaaaaabkvkaaaaaaaaae - ('00000000-0000-0000-AAAA-000000000002', 'demo-user', true, '1970-01-01T01:01:01Z'), -- aaaaaaaaaaaabkvkaaaaaaaaai - ('00000000-0000-0000-AAAA-000000000003', 'claire', false, default); -- aaaaaaaaaaaabkvkaaaaaaaaam +INSERT INTO editor (id, username, is_superuser, is_admin, is_bot, auth_epoch) VALUES + ('00000000-0000-0000-AAAA-000000000001', 'root', true, true, false, '1970-01-01T01:01:01Z'), -- aaaaaaaaaaaabkvkaaaaaaaaae + ('00000000-0000-0000-AAAA-000000000002', 'admin', true, true, false, '1970-01-01T01:01:01Z'), -- aaaaaaaaaaaabkvkaaaaaaaaai + ('00000000-0000-0000-AAAA-000000000003', 'demo-user', false, true, false, '1970-01-01T01:01:01Z'), -- aaaaaaaaaaaabkvkaaaaaaaaam + ('00000000-0000-0000-AAAA-000000000004', 'claire', false, false, false, default), -- aaaaaaaaaaaabkvkaaaaaaaaaq + ('00000000-0000-0000-AAAA-000000000005', 'webface-bot', true, true, true, '1970-01-01T01:01:01Z'), -- aaaaaaaaaaaabkvkaaaaaaaaau + ('00000000-0000-0000-AAAA-000000000006', 'bnewbold', false, true, false, '1970-01-01T01:01:01Z'); -- aaaaaaaaaaaabkvkaaaaaaaaay INSERT INTO editgroup (id, editor_id, description) VALUES ('00000000-0000-0000-BBBB-000000000001', '00000000-0000-0000-AAAA-000000000001', 'first edit ever!'), -- aaaaaaaaaaaabo53aaaaaaaaae @@ -483,9 +487,6 @@ INSERT INTO editgroup (id, editor_id, description) VALUES ('00000000-0000-0000-BBBB-000000000005', '00000000-0000-0000-AAAA-000000000001', 'journal edit'), -- aaaaaaaaaaaabo53aaaaaaaaau ('00000000-0000-0000-BBBB-000000000006', '00000000-0000-0000-AAAA-000000000001', 'another journal edit'); -- aaaaaaaaaaaabo53aaaaaaaaay -INSERT INTO editor (id, username, is_admin, active_editgroup_id) VALUES - ('00000000-0000-0000-AAAA-000000000004', 'bnewbold', true, '00000000-0000-0000-BBBB-000000000004'); - INSERT INTO changelog (editgroup_id) VALUES ('00000000-0000-0000-BBBB-000000000001'), ('00000000-0000-0000-BBBB-000000000002'), diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index c663c11d..614a0007 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -85,7 +85,7 @@ macro_rules! wrap_entity_handlers { ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { - let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data)?; + let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data, Some(stringify!($post_fn)))?; auth_context.require_role(FatcatRole::Editor)?; let editgroup_id = if let Some(s) = editgroup_id { let eg_id = FatCatId::from_str(&s)?; @@ -137,7 +137,7 @@ macro_rules! wrap_entity_handlers { ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { - let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data)?; + let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data, Some(stringify!($post_batch_fn)))?; auth_context.require_role(FatcatRole::Editor)?; let editgroup_id = if let Some(s) = editgroup_id { let eg_id = FatCatId::from_str(&s)?; @@ -187,7 +187,7 @@ macro_rules! wrap_entity_handlers { ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { - let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data)?; + let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data, Some(stringify!($update_fn)))?; auth_context.require_role(FatcatRole::Editor)?; let entity_id = FatCatId::from_str(&ident)?; let editgroup_id = if let Some(s) = editgroup_id { @@ -243,7 +243,7 @@ macro_rules! wrap_entity_handlers { ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { - let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data)?; + let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data, Some(stringify!($delete_fn)))?; auth_context.require_role(FatcatRole::Editor)?; let entity_id = FatCatId::from_str(&ident)?; let editgroup_id: Option = match editgroup_id { @@ -397,7 +397,7 @@ macro_rules! wrap_entity_handlers { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { let edit_id = Uuid::from_str(&edit_id)?; - let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data)?; + let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data, Some(stringify!($delete_edit_fn)))?; auth_context.require_role(FatcatRole::Editor)?; let edit = $model::db_get_edit(&conn, edit_id)?; auth_context.require_editgroup(&conn, FatCatId::from_uuid(&edit.editgroup_id))?; @@ -920,7 +920,7 @@ impl Api for Server { } let auth_context = self .auth_confectionary - .require_auth(&conn, &context.auth_data)?; + .require_auth(&conn, &context.auth_data, Some("update_editor"))?; let editor_id = FatCatId::from_str(&editor_id)?; // DANGER! these permissions are for username updates only! if editor_id == auth_context.editor_id { @@ -988,7 +988,7 @@ impl Api for Server { let editgroup_id = FatCatId::from_str(&editgroup_id)?; let auth_context = self .auth_confectionary - .require_auth(&conn, &context.auth_data)?; + .require_auth(&conn, &context.auth_data, Some("accept_editgroup"))?; auth_context.require_role(FatcatRole::Admin)?; // NOTE: this is currently redundant, but zero-cost auth_context.require_editgroup(&conn, editgroup_id)?; @@ -1060,7 +1060,7 @@ impl Api for Server { let ret = match conn.transaction(|| { let auth_context = self .auth_confectionary - .require_auth(&conn, &context.auth_data)?; + .require_auth(&conn, &context.auth_data, Some("create_editgroup"))?; auth_context.require_role(FatcatRole::Editor)?; let mut entity = entity.clone(); match entity.editor_id.clone() { @@ -1151,8 +1151,8 @@ impl Api for Server { let ret = match conn.transaction(|| { let auth_context = self .auth_confectionary - .require_auth(&conn, &context.auth_data)?; - auth_context.require_role(FatcatRole::Admin)?; + .require_auth(&conn, &context.auth_data, Some("auth_oidc"))?; + auth_context.require_role(FatcatRole::Superuser)?; let (editor, created) = self.auth_oidc_handler(params, &conn)?; // create an auth token; leave it to webface to attenuate to a given duration let token = self.auth_confectionary.create_token( diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 4b608a96..0160d2e8 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -18,13 +18,14 @@ use std::str::FromStr; // 32 bytes max (!) static DUMMY_KEY: &[u8] = b"dummy-key-a-one-two-three-a-la"; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum FatcatRole { Public, Editor, Bot, Human, Admin, + Superuser, } #[derive(Clone)] @@ -35,6 +36,10 @@ pub struct AuthContext { impl AuthContext { pub fn has_role(&self, role: FatcatRole) -> bool { + if !self.editor_row.is_active { + // if account is disabled, only allow public role + return role == FatcatRole::Public; + } if self.editor_row.is_admin { return true; } @@ -44,15 +49,15 @@ impl AuthContext { FatcatRole::Bot => self.editor_row.is_bot, FatcatRole::Human => !self.editor_row.is_bot, FatcatRole::Admin => self.editor_row.is_admin, + FatcatRole::Superuser => self.editor_row.is_superuser, } } pub fn require_role(&self, role: FatcatRole) -> Result<()> { match self.has_role(role) { true => Ok(()), - // TODO: better message false => Err(ErrorKind::InsufficientPrivileges( - "doesn't have required role".to_string(), + format!("doesn't have required role: {:?}", role), ) .into()), } @@ -225,8 +230,7 @@ impl AuthConfectionary { Ok(BASE64.encode(&raw)) } - /// On success, returns Some((editor_id, scopes)), where `scopes` is a vector of strings. - pub fn parse_macaroon_token(&self, conn: &DbConn, s: &str) -> Result { + pub fn parse_macaroon_token(&self, conn: &DbConn, s: &str, endpoint: Option<&str>) -> Result { let raw = BASE64.decode(s.as_bytes())?; let mac = match Macaroon::deserialize(&raw) { Ok(m) => m, @@ -258,6 +262,10 @@ impl AuthConfectionary { } let editor_id = editor_id.expect("expected an editor_id caveat"); verifier.satisfy_exact(&format!("editor_id = {}", editor_id.to_string())); + if let Some(endpoint) = endpoint { + // API endpoint + verifier.satisfy_exact(&format!("endpoint = {}", endpoint)); + } let mut created: Option> = None; for caveat in mac.first_party_caveats() { if caveat.predicate().starts_with("created = ") { @@ -329,6 +337,7 @@ impl AuthConfectionary { &self, conn: &DbConn, auth_data: &Option, + endpoint: Option<&str>, ) -> Result> { let token: Option = match auth_data { Some(AuthData::ApiKey(header)) => { @@ -355,15 +364,15 @@ impl AuthConfectionary { Some(t) => t, None => return Ok(None), }; - let editor_row = self.parse_macaroon_token(conn, &token)?; + let editor_row = self.parse_macaroon_token(conn, &token, endpoint)?; Ok(Some(AuthContext { editor_id: FatCatId::from_uuid(&editor_row.id), editor_row: editor_row, })) } - pub fn require_auth(&self, conn: &DbConn, auth_data: &Option) -> Result { - match self.parse_swagger(conn, auth_data)? { + pub fn require_auth(&self, conn: &DbConn, auth_data: &Option, endpoint: Option<&str>) -> Result { + match self.parse_swagger(conn, auth_data, endpoint)? { Some(auth) => Ok(auth), None => Err(ErrorKind::InvalidCredentials("no token supplied".to_string()).into()), } @@ -384,7 +393,7 @@ impl AuthConfectionary { for caveat in mac.first_party_caveats() { println!("caveat: {}", caveat.predicate()); } - println!("verify: {:?}", self.parse_macaroon_token(conn, token)); + println!("verify: {:?}", self.parse_macaroon_token(conn, token, None)); Ok(()) } } @@ -416,11 +425,12 @@ pub fn revoke_tokens_everyone(conn: &DbConn) -> Result<()> { pub fn print_editors(conn: &DbConn) -> Result<()> { // iterate over all editors. format id, print flags, auth_epoch let all_editors: Vec = editor::table.load(conn)?; - println!("editor_id\t\t\tis_admin/is_bot\tauth_epoch\t\t\tusername\twrangler_id"); + println!("editor_id\t\t\tsuper/admin/bot\tauth_epoch\t\t\tusername\twrangler_id"); for e in all_editors { println!( - "{}\t{}\t{}\t{}\t{}\t{:?}", + "{}\t{}/{}/{}\t{}\t{}\t{:?}", FatCatId::from_uuid(&e.id).to_string(), + e.is_superuser, e.is_admin, e.is_bot, e.auth_epoch, diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index 5c8e17d3..59953f6b 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -577,6 +577,7 @@ impl EditgroupRow { pub struct EditorRow { pub id: Uuid, pub username: String, + pub is_superuser: bool, pub is_admin: bool, pub is_bot: bool, pub is_active: bool, diff --git a/rust/src/database_schema.rs b/rust/src/database_schema.rs index 49863fc7..0c553b40 100644 --- a/rust/src/database_schema.rs +++ b/rust/src/database_schema.rs @@ -107,6 +107,7 @@ table! { editor (id) { id -> Uuid, username -> Text, + is_superuser -> Bool, is_admin -> Bool, is_bot -> Bool, is_active -> Bool, diff --git a/rust/tests/test_auth.rs b/rust/tests/test_auth.rs index b06f3e7b..5ccbb6cb 100644 --- a/rust/tests/test_auth.rs +++ b/rust/tests/test_auth.rs @@ -35,13 +35,13 @@ fn test_auth_db() { let token = c.create_token(editor_id, None).unwrap(); // verify token - let editor_row = c.parse_macaroon_token(&conn, &token).unwrap(); + let editor_row = c.parse_macaroon_token(&conn, &token, None).unwrap(); assert_eq!(editor_row.id, editor_id.to_uuid()); // revoke token revoke_tokens(&conn, editor_id).unwrap(); // verification should fail - // XXX: one-second slop breads this - //assert!(c.parse_macaroon_token(&conn, &token).is_err()); + // XXX: one-second slop breaks this + //assert!(c.parse_macaroon_token(&conn, &token, None).is_err()); } -- cgit v1.2.3 From 39aba8b86cd4cec01e26eb08f74b5da22f4fe9af Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 4 Jan 2019 19:31:23 -0800 Subject: fix base64 bogus auth keys --- rust/env.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rust') diff --git a/rust/env.example b/rust/env.example index 0ecf58a5..1e7ef42d 100644 --- a/rust/env.example +++ b/rust/env.example @@ -2,5 +2,5 @@ DATABASE_URL="postgres://fatcat:tactaf@localhost/fatcat" TEST_DATABASE_URL="postgres://fatcat:tactaf@localhost/fatcat_test AUTH_LOCATION="dev.fatcat.wiki" AUTH_KEY_IDENT="20190101-dev-dummy-key" -AUTH_SECRET_KEY="5555555555555555555555555555555555555555555=" -AUTH_ALT_KEYS="20181220-dev:6666666666666666666666666666666666666666666=,20181210-dev:7777777777777777777777777777777777777777777=" +AUTH_SECRET_KEY="5555555555555555555555555555555555555555xms=" +AUTH_ALT_KEYS="20181220-dev:6666666666666666666666666666666666666666xms=,20181210-dev:7777777777777777777777777777777777777777xms=" -- cgit v1.2.3 From 3654fcfca716c7994bd166436cfb57b6b65d7c85 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 7 Jan 2019 17:06:45 -0800 Subject: only superusers get auto-magic-privs --- rust/migrations/2018-05-12-001226_init/up.sql | 2 +- rust/src/api_helpers.rs | 2 +- rust/src/auth.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index b5b39f6f..cf7e3fe2 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -16,7 +16,7 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE TABLE editor ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - username TEXT NOT NULL CHECK (username ~* '^[A-Za-z0-9][A-Za-z0-9._-]{2,15}$'), -- UNIQ below + username TEXT NOT NULL CHECK (username ~* '^[A-Za-z0-9][A-Za-z0-9._-]{2,19}$'), -- UNIQ below is_superuser BOOLEAN NOT NULL DEFAULT false, is_admin BOOLEAN NOT NULL DEFAULT false, is_bot BOOLEAN NOT NULL DEFAULT false, diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index 79114d4f..5e68d8e2 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -359,7 +359,7 @@ pub fn uuid2fcid(id: &Uuid) -> String { pub fn check_username(raw: &str) -> Result<()> { lazy_static! { - static ref RE: Regex = Regex::new(r"^[A-Za-z0-9][A-Za-z0-9._-]{2,15}$").unwrap(); + static ref RE: Regex = Regex::new(r"^[A-Za-z0-9][A-Za-z0-9._-]{2,19}$").unwrap(); } if RE.is_match(raw) { Ok(()) diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 0160d2e8..8894e33b 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -40,7 +40,7 @@ impl AuthContext { // if account is disabled, only allow public role return role == FatcatRole::Public; } - if self.editor_row.is_admin { + if self.editor_row.is_superuser { return true; } match role { -- cgit v1.2.3 From a373cda815b0a44d93b485800b63a785c9aeb8aa Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 7 Jan 2019 17:13:30 -0800 Subject: bump allowed username length to 25 chars --- rust/migrations/2018-05-12-001226_init/up.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index cf7e3fe2..ddaa60b3 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -16,7 +16,7 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE TABLE editor ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - username TEXT NOT NULL CHECK (username ~* '^[A-Za-z0-9][A-Za-z0-9._-]{2,19}$'), -- UNIQ below + username TEXT NOT NULL CHECK (username ~* '^[A-Za-z][A-Za-z0-9._-]{2,24}$'), -- UNIQ below is_superuser BOOLEAN NOT NULL DEFAULT false, is_admin BOOLEAN NOT NULL DEFAULT false, is_bot BOOLEAN NOT NULL DEFAULT false, -- cgit v1.2.3 From 75c9831cf6e71b7a24e99e34cbe74845d1bfeed0 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 7 Jan 2019 17:49:32 -0800 Subject: commit missing bits from username length change --- rust/src/api_helpers.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index 5e68d8e2..5ee529b9 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -359,7 +359,7 @@ pub fn uuid2fcid(id: &Uuid) -> String { pub fn check_username(raw: &str) -> Result<()> { lazy_static! { - static ref RE: Regex = Regex::new(r"^[A-Za-z0-9][A-Za-z0-9._-]{2,19}$").unwrap(); + static ref RE: Regex = Regex::new(r"^[A-Za-z][A-Za-z0-9._-]{2,24}$").unwrap(); } if RE.is_match(raw) { Ok(()) @@ -380,6 +380,8 @@ fn test_check_username() { assert!(check_username("friend-bot").is_ok()); assert!(check_username("dog").is_ok()); assert!(check_username("g_____").is_ok()); + assert!(check_username("bnewbold2-archive").is_ok()); + assert!(check_username("bnewbold2-internetarchive").is_ok()); assert!(check_username("").is_err()); assert!(check_username("_").is_err()); -- cgit v1.2.3 From 35f3f55aac364373ba16191abdb3c0c585249245 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 7 Jan 2019 18:08:09 -0800 Subject: add auth/check endpoint --- fatcat-openapi2.yml | 26 +++++ rust/HACKING.md | 9 ++ rust/fatcat-api-spec/README.md | 3 +- rust/fatcat-api-spec/api.yaml | 26 +++++ rust/fatcat-api-spec/api/swagger.yaml | 66 ++++++++++++ rust/fatcat-api-spec/examples/client.rs | 9 +- rust/fatcat-api-spec/examples/server_lib/server.rs | 8 +- rust/fatcat-api-spec/src/client.rs | 103 +++++++++++++++--- rust/fatcat-api-spec/src/lib.rs | 22 ++++ rust/fatcat-api-spec/src/mimetypes.rs | 20 ++++ rust/fatcat-api-spec/src/server.rs | 118 ++++++++++++++++++--- rust/src/api_wrappers.rs | 96 ++++++++++++++--- rust/src/auth.rs | 21 +++- 13 files changed, 480 insertions(+), 47 deletions(-) (limited to 'rust') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index 501a1296..625a0143 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -2711,4 +2711,30 @@ paths: schema: $ref: "#/definitions/error_response" <<: *AUTHRESPONSES + /auth/check: + get: + operationId: "auth_check" + tags: # TAGLINE + security: + # required admin privs + - Bearer: [] + parameters: + - name: role + in: query + required: false + type: string + responses: + 200: + description: Success + schema: + $ref: "#/definitions/success" + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" + 500: + description: Generic Error + schema: + $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES diff --git a/rust/HACKING.md b/rust/HACKING.md index 9d161b87..b3a551fa 100644 --- a/rust/HACKING.md +++ b/rust/HACKING.md @@ -54,6 +54,15 @@ Debug SQL schema errors (if diesel commands fail): ## Direct API Interaction +First setup an auth token and check that authentication is working + + EDITOR_ID='aaaaaaaaaaaabkvkaaaaaaaaay' + AUTH_TOKEN=`./target/debug/fatcat-auth create-token $EDITOR_ID` + http get :9411/v0/auth/check "Authorization:Bearer $AUTH_TOKEN" + http get :9411/v0/auth/check?role=admin "Authorization:Bearer $AUTH_TOKEN" + +You'll need to add the `$AUTH_TOKEN` bit to all requests below. + Creating entities via API: http --json post localhost:9411/v0/container name=asdf issn=1234-5678 diff --git a/rust/fatcat-api-spec/README.md b/rust/fatcat-api-spec/README.md index f81f641a..f8a6e817 100644 --- a/rust/fatcat-api-spec/README.md +++ b/rust/fatcat-api-spec/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2019-01-04T05:57:03.701Z +- Build date: 2019-01-08T01:49:55.777Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. @@ -79,6 +79,7 @@ cargo run --example client GetCreatorReleases cargo run --example client GetCreatorRevision cargo run --example client LookupCreator cargo run --example client UpdateCreator +cargo run --example client AuthCheck cargo run --example client AuthOidc cargo run --example client GetEditor cargo run --example client GetEditorChangelog diff --git a/rust/fatcat-api-spec/api.yaml b/rust/fatcat-api-spec/api.yaml index 501a1296..625a0143 100644 --- a/rust/fatcat-api-spec/api.yaml +++ b/rust/fatcat-api-spec/api.yaml @@ -2711,4 +2711,30 @@ paths: schema: $ref: "#/definitions/error_response" <<: *AUTHRESPONSES + /auth/check: + get: + operationId: "auth_check" + tags: # TAGLINE + security: + # required admin privs + - Bearer: [] + parameters: + - name: role + in: query + required: false + type: string + responses: + 200: + description: Success + schema: + $ref: "#/definitions/success" + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" + 500: + description: Generic Error + schema: + $ref: "#/definitions/error_response" + <<: *AUTHRESPONSES diff --git a/rust/fatcat-api-spec/api/swagger.yaml b/rust/fatcat-api-spec/api/swagger.yaml index a19d6ae1..9d4767c0 100644 --- a/rust/fatcat-api-spec/api/swagger.yaml +++ b/rust/fatcat-api-spec/api/swagger.yaml @@ -6659,6 +6659,72 @@ paths: HttpMethod: "Post" httpmethod: "post" noClientExample: true + /auth/check: + get: + operationId: "auth_check" + parameters: + - name: "role" + in: "query" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"role_example\".to_string())" + responses: + 200: + description: "Success" + schema: + $ref: "#/definitions/success" + x-responseId: "Success" + x-uppercaseResponseId: "SUCCESS" + uppercase_operation_id: "AUTH_CHECK" + uppercase_data_type: "SUCCESS" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "AUTH_CHECK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 401: + description: "Not Authorized" + schema: + $ref: "#/definitions/error_response" + headers: + WWW_Authenticate: + type: "string" + x-responseId: "NotAuthorized" + x-uppercaseResponseId: "NOT_AUTHORIZED" + uppercase_operation_id: "AUTH_CHECK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 403: + description: "Forbidden" + schema: + $ref: "#/definitions/error_response" + x-responseId: "Forbidden" + x-uppercaseResponseId: "FORBIDDEN" + uppercase_operation_id: "AUTH_CHECK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "AUTH_CHECK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + security: + - Bearer: [] + operation_id: "auth_check" + uppercase_operation_id: "AUTH_CHECK" + path: "/auth/check" + HttpMethod: "Get" + httpmethod: "get" securityDefinitions: Bearer: type: "apiKey" diff --git a/rust/fatcat-api-spec/examples/client.rs b/rust/fatcat-api-spec/examples/client.rs index 4eed8ae4..5a43a33c 100644 --- a/rust/fatcat-api-spec/examples/client.rs +++ b/rust/fatcat-api-spec/examples/client.rs @@ -12,8 +12,8 @@ extern crate uuid; use clap::{App, Arg}; #[allow(unused_imports)] use fatcat::{ - AcceptEditgroupResponse, ApiError, ApiNoContext, AuthOidcResponse, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, - CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, + AcceptEditgroupResponse, ApiError, ApiNoContext, AuthCheckResponse, AuthOidcResponse, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, + CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, @@ -54,6 +54,7 @@ fn main() { "GetCreatorReleases", "GetCreatorRevision", "LookupCreator", + "AuthCheck", "GetEditor", "GetEditorChangelog", "AcceptEditgroup", @@ -272,6 +273,10 @@ fn main() { // let result = client.update_creator("ident_example".to_string(), ???, Some("editgroup_id_example".to_string())).wait(); // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, + Some("AuthCheck") => { + let result = client.auth_check(Some("role_example".to_string())).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + } // Disabled because there's no example. // Some("AuthOidc") => { diff --git a/rust/fatcat-api-spec/examples/server_lib/server.rs b/rust/fatcat-api-spec/examples/server_lib/server.rs index 5e86a10e..73917351 100644 --- a/rust/fatcat-api-spec/examples/server_lib/server.rs +++ b/rust/fatcat-api-spec/examples/server_lib/server.rs @@ -11,7 +11,7 @@ use swagger; use fatcat::models; use fatcat::{ - AcceptEditgroupResponse, Api, ApiError, AuthOidcResponse, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, + AcceptEditgroupResponse, Api, ApiError, AuthCheckResponse, AuthOidcResponse, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, @@ -297,6 +297,12 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } + fn auth_check(&self, role: Option, context: &Context) -> Box + Send> { + let context = context.clone(); + println!("auth_check({:?}) - X-Span-ID: {:?}", role, context.x_span_id.unwrap_or(String::from("")).clone()); + Box::new(futures::failed("Generic failure".into())) + } + fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box + Send> { let context = context.clone(); println!("auth_oidc({:?}) - X-Span-ID: {:?}", oidc_params, context.x_span_id.unwrap_or(String::from("")).clone()); diff --git a/rust/fatcat-api-spec/src/client.rs b/rust/fatcat-api-spec/src/client.rs index 470a5350..7f364eb4 100644 --- a/rust/fatcat-api-spec/src/client.rs +++ b/rust/fatcat-api-spec/src/client.rs @@ -35,18 +35,19 @@ use swagger::{ApiError, Context, XSpanId}; use models; use { - AcceptEditgroupResponse, Api, AuthOidcResponse, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, - CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, - CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, - DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, - DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, - GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, - GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, - GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, - GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, - GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, - GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, - UpdateContainerResponse, UpdateCreatorResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + AcceptEditgroupResponse, Api, AuthCheckResponse, AuthOidcResponse, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, + CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, + CreateWebcaptureBatchResponse, CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, + DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, + DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, + GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, + GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, + GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, + GetReleaseEditResponse, GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, + GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, + GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, + LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, + UpdateWorkResponse, }; /// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. @@ -2030,6 +2031,84 @@ impl Api for Client { Box::new(futures::done(result)) } + fn auth_check(&self, param_role: Option, context: &Context) -> Box + Send> { + // Query parameters + let query_role = param_role.map_or_else(String::new, |query| format!("role={role}&", role = query.to_string())); + + let url = format!("{}/v0/auth/check?{role}", self.base_path, role = utf8_percent_encode(&query_role, QUERY_ENCODE_SET)); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Get, &url); + let mut custom_headers = hyper::header::Headers::new(); + + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result { + match response.status.to_u16() { + 200 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AuthCheckResponse::Success(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AuthCheckResponse::BadRequest(body)) + } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(AuthCheckResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AuthCheckResponse::Forbidden(body)) + } + 500 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(AuthCheckResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + fn auth_oidc(&self, param_oidc_params: models::AuthOidc, context: &Context) -> Box + Send> { let url = format!("{}/v0/auth/oidc", self.base_path); diff --git a/rust/fatcat-api-spec/src/lib.rs b/rust/fatcat-api-spec/src/lib.rs index 258b635b..17c74384 100644 --- a/rust/fatcat-api-spec/src/lib.rs +++ b/rust/fatcat-api-spec/src/lib.rs @@ -348,6 +348,20 @@ pub enum UpdateCreatorResponse { GenericError(models::ErrorResponse), } +#[derive(Debug, PartialEq)] +pub enum AuthCheckResponse { + /// Success + Success(models::Success), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + #[derive(Debug, PartialEq)] pub enum AuthOidcResponse { /// Found @@ -1315,6 +1329,8 @@ pub trait Api { fn update_creator(&self, ident: String, entity: models::CreatorEntity, editgroup_id: Option, context: &Context) -> Box + Send>; + fn auth_check(&self, role: Option, context: &Context) -> Box + Send>; + fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box + Send>; fn get_editor(&self, editor_id: String, context: &Context) -> Box + Send>; @@ -1565,6 +1581,8 @@ pub trait ApiNoContext { fn update_creator(&self, ident: String, entity: models::CreatorEntity, editgroup_id: Option) -> Box + Send>; + fn auth_check(&self, role: Option) -> Box + Send>; + fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box + Send>; fn get_editor(&self, editor_id: String) -> Box + Send>; @@ -1852,6 +1870,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().update_creator(ident, entity, editgroup_id, &self.context()) } + fn auth_check(&self, role: Option) -> Box + Send> { + self.api().auth_check(role, &self.context()) + } + fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box + Send> { self.api().auth_oidc(oidc_params, &self.context()) } diff --git a/rust/fatcat-api-spec/src/mimetypes.rs b/rust/fatcat-api-spec/src/mimetypes.rs index cfdd357d..83add9e3 100644 --- a/rust/fatcat-api-spec/src/mimetypes.rs +++ b/rust/fatcat-api-spec/src/mimetypes.rs @@ -452,6 +452,26 @@ pub mod responses { lazy_static! { pub static ref UPDATE_CREATOR_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_SUCCESS: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for AuthOidc lazy_static! { pub static ref AUTH_OIDC_FOUND: Mime = mime!(Application / Json); diff --git a/rust/fatcat-api-spec/src/server.rs b/rust/fatcat-api-spec/src/server.rs index c0903676..d8fc7dc2 100644 --- a/rust/fatcat-api-spec/src/server.rs +++ b/rust/fatcat-api-spec/src/server.rs @@ -37,18 +37,19 @@ use swagger::{ApiError, Context, XSpanId}; #[allow(unused_imports)] use models; use { - AcceptEditgroupResponse, Api, AuthOidcResponse, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, - CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWebcaptureBatchResponse, - CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, - DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, - DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, - GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, - GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, - GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, - GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, - GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, - GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, - UpdateContainerResponse, UpdateCreatorResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, + AcceptEditgroupResponse, Api, AuthCheckResponse, AuthOidcResponse, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, + CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateFilesetBatchResponse, CreateFilesetResponse, CreateReleaseBatchResponse, CreateReleaseResponse, + CreateWebcaptureBatchResponse, CreateWebcaptureResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, + DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, + DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, + GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, + GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, + GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, + GetReleaseEditResponse, GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, + GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, + GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, + LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, + UpdateWorkResponse, }; header! { (Warning, "Warning") => [String] } @@ -2605,6 +2606,99 @@ where "UpdateCreator", ); + let api_clone = api.clone(); + router.get( + "/v0/auth/check", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) + let query_params = req.get::().unwrap_or_default(); + let param_role = query_params.get("role").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + + match api.auth_check(param_role, context).wait() { + Ok(rsp) => match rsp { + AuthCheckResponse::Success(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(200), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_CHECK_SUCCESS.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_CHECK_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::AUTH_CHECK_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_CHECK_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(500), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_CHECK_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) + } + } + } + + handle_request(req, &api_clone, &mut context).or_else(|mut response| { + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + Ok(response) + }) + }, + "AuthCheck", + ); + let api_clone = api.clone(); router.post( "/v0/auth/oidc", diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 614a0007..818a41c2 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -404,8 +404,7 @@ macro_rules! wrap_entity_handlers { $model::db_delete_edit(&conn, edit_id) }) { Ok(()) => - $delete_edit_resp::DeletedEdit(Success { message: format!("Successfully deleted work-in-progress {} edit: {}", stringify!($model), edit_id) } ), - Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => + $delete_edit_resp::DeletedEdit(Success { message: format!("Successfully deleted work-in-progress {} edit: {}", stringify!($model), edit_id) } ), Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => $delete_edit_resp::NotFound(ErrorResponse { message: format!("No such {} edit: {}", stringify!($model), edit_id) }), Err(Error(ErrorKind::Diesel(e), _)) => $delete_edit_resp::BadRequest(ErrorResponse { message: e.to_string() }), @@ -918,9 +917,11 @@ impl Api for Server { ErrorKind::OtherBadRequest("editor_id doesn't match".to_string()).into(), ); } - let auth_context = self - .auth_confectionary - .require_auth(&conn, &context.auth_data, Some("update_editor"))?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some("update_editor"), + )?; let editor_id = FatCatId::from_str(&editor_id)?; // DANGER! these permissions are for username updates only! if editor_id == auth_context.editor_id { @@ -986,9 +987,11 @@ impl Api for Server { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { let editgroup_id = FatCatId::from_str(&editgroup_id)?; - let auth_context = self - .auth_confectionary - .require_auth(&conn, &context.auth_data, Some("accept_editgroup"))?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some("accept_editgroup"), + )?; auth_context.require_role(FatcatRole::Admin)?; // NOTE: this is currently redundant, but zero-cost auth_context.require_editgroup(&conn, editgroup_id)?; @@ -1058,9 +1061,11 @@ impl Api for Server { ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { - let auth_context = self - .auth_confectionary - .require_auth(&conn, &context.auth_data, Some("create_editgroup"))?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some("create_editgroup"), + )?; auth_context.require_role(FatcatRole::Editor)?; let mut entity = entity.clone(); match entity.editor_id.clone() { @@ -1149,9 +1154,11 @@ impl Api for Server { ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { - let auth_context = self - .auth_confectionary - .require_auth(&conn, &context.auth_data, Some("auth_oidc"))?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some("auth_oidc"), + )?; auth_context.require_role(FatcatRole::Superuser)?; let (editor, created) = self.auth_oidc_handler(params, &conn)?; // create an auth token; leave it to webface to attenuate to a given duration @@ -1221,4 +1228,65 @@ impl Api for Server { }; Box::new(futures::done(Ok(ret))) } + + fn auth_check( + &self, + role: Option, + context: &Context, + ) -> Box + Send> { + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| { + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some("auth_check"), + )?; + if let Some(role) = role { + let role = match role.to_lowercase().as_ref() { + "superuser" => FatcatRole::Superuser, + "admin" => FatcatRole::Admin, + "editor" => FatcatRole::Editor, + "bot" => FatcatRole::Bot, + "human" => FatcatRole::Human, + "public" => FatcatRole::Public, + _ => bail!("unknown auth role: {}", role), + }; + auth_context.require_role(role)?; + }; + Ok(()) + }) { + Ok(()) => AuthCheckResponse::Success(Success { + message: "auth check successful!".to_string() }), + Err(Error(ErrorKind::Diesel(e), _)) => AuthCheckResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }), + Err(Error(ErrorKind::Uuid(e), _)) => AuthCheckResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }), + Err(Error(ErrorKind::InvalidCredentials(e), _)) => + // TODO: why can't I NotAuthorized here? + { + AuthCheckResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + }, + Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => { + AuthCheckResponse::Forbidden(ErrorResponse { + message: e.to_string(), + }) + }, + Err(Error(ErrorKind::OtherBadRequest(e), _)) => { + AuthCheckResponse::BadRequest(ErrorResponse { + message: e.to_string(), + }) + }, + Err(e) => { + error!("{}", e); + AuthCheckResponse::GenericError(ErrorResponse { + message: e.to_string(), + }) + }, + }; + Box::new(futures::done(Ok(ret))) + } } diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 8894e33b..c20b9b71 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -56,9 +56,10 @@ impl AuthContext { pub fn require_role(&self, role: FatcatRole) -> Result<()> { match self.has_role(role) { true => Ok(()), - false => Err(ErrorKind::InsufficientPrivileges( - format!("doesn't have required role: {:?}", role), - ) + false => Err(ErrorKind::InsufficientPrivileges(format!( + "doesn't have required role: {:?}", + role + )) .into()), } } @@ -230,7 +231,12 @@ impl AuthConfectionary { Ok(BASE64.encode(&raw)) } - pub fn parse_macaroon_token(&self, conn: &DbConn, s: &str, endpoint: Option<&str>) -> Result { + pub fn parse_macaroon_token( + &self, + conn: &DbConn, + s: &str, + endpoint: Option<&str>, + ) -> Result { let raw = BASE64.decode(s.as_bytes())?; let mac = match Macaroon::deserialize(&raw) { Ok(m) => m, @@ -371,7 +377,12 @@ impl AuthConfectionary { })) } - pub fn require_auth(&self, conn: &DbConn, auth_data: &Option, endpoint: Option<&str>) -> Result { + pub fn require_auth( + &self, + conn: &DbConn, + auth_data: &Option, + endpoint: Option<&str>, + ) -> Result { match self.parse_swagger(conn, auth_data, endpoint)? { Some(auth) => Ok(auth), None => Err(ErrorKind::InvalidCredentials("no token supplied".to_string()).into()), -- cgit v1.2.3 From fee4f9e8957f7f51acb320ec880de166377807f7 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 8 Jan 2019 15:18:36 -0800 Subject: iterate on macaroon time caveat names --- rust/src/auth.rs | 39 +++++++++++++++++++-------------------- rust/tests/test_auth.rs | 3 +-- 2 files changed, 20 insertions(+), 22 deletions(-) (limited to 'rust') diff --git a/rust/src/auth.rs b/rust/src/auth.rs index c20b9b71..f9b8d7b9 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -213,17 +213,18 @@ impl AuthConfectionary { pub fn create_token( &self, editor_id: FatCatId, - expires: Option>, + duration: Option, ) -> Result { let mut mac = Macaroon::create(&self.location, &self.key, &self.identifier) .expect("Macaroon creation"); mac.add_first_party_caveat(&format!("editor_id = {}", editor_id.to_string())); - // TODO: put created one second in the past to prevent timing synchronization glitches? - let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); - mac.add_first_party_caveat(&format!("created = {}", now)); - if let Some(expires) = expires { + let now_utc = Utc::now(); + let now = now_utc.to_rfc3339_opts(SecondsFormat::Secs, true); + mac.add_first_party_caveat(&format!("time > {}", now)); + if let Some(duration) = duration { + let expires = now_utc + duration; mac.add_first_party_caveat(&format!( - "expires = {:?}", + "time < {:?}", &expires.to_rfc3339_opts(SecondsFormat::Secs, true) )); }; @@ -274,18 +275,18 @@ impl AuthConfectionary { } let mut created: Option> = None; for caveat in mac.first_party_caveats() { - if caveat.predicate().starts_with("created = ") { + if caveat.predicate().starts_with("time > ") { created = Some( - DateTime::parse_from_rfc3339(caveat.predicate().get(10..).unwrap()) + DateTime::parse_from_rfc3339(caveat.predicate().get(7..).unwrap()) .unwrap() .with_timezone(&Utc), ); break; } } - let created = created.expect("expected a 'created' caveat"); + let created = created.expect("expected a 'created' (time >) caveat"); verifier.satisfy_exact(&format!( - "created = {}", + "time > {}", created.to_rfc3339_opts(SecondsFormat::Secs, true) )); let editor: EditorRow = editor::table.find(&editor_id.to_uuid()).get_result(conn)?; @@ -299,9 +300,9 @@ impl AuthConfectionary { .into()); } verifier.satisfy_general(|p: &str| -> bool { - // not expired (based on expires) - if p.starts_with("expires = ") { - let expires: DateTime = DateTime::parse_from_rfc3339(p.get(12..).unwrap()) + // not expired (based on time) + if p.starts_with("time < ") { + let expires: DateTime = DateTime::parse_from_rfc3339(p.get(7..).unwrap()) .unwrap() .with_timezone(&Utc); expires < Utc::now() @@ -312,10 +313,8 @@ impl AuthConfectionary { let verify_key = match self.root_keys.get(mac.identifier()) { Some(key) => key, None => { - // TODO: better message - //bail!("key not found for identifier: {}", mac.identifier()), return Err(ErrorKind::InvalidCredentials( - "key not found for identifier".to_string(), + format!("no valid auth signing key for identifier: {}", mac.identifier()) ) .into()); } @@ -324,15 +323,15 @@ impl AuthConfectionary { Ok(true) => (), Ok(false) => { return Err(ErrorKind::InvalidCredentials( - "token overall verification failed".to_string(), + "auth token (macaroon) not valid (signature and/or caveats failed)".to_string(), ) .into()); } - Err(_e) => { + Err(e) => { // TODO: chain - //bail!("token parsing failed: {:?}", e), return Err( - ErrorKind::InvalidCredentials("token parsing failed".to_string()).into(), + ErrorKind::InvalidCredentials( + format!("token parsing failed: {:?}", e)).into(), ); } } diff --git a/rust/tests/test_auth.rs b/rust/tests/test_auth.rs index 5ccbb6cb..412b67e8 100644 --- a/rust/tests/test_auth.rs +++ b/rust/tests/test_auth.rs @@ -18,8 +18,7 @@ fn test_macaroons() { c.create_token(editor_id, None).unwrap(); // create token w/ expiration - let tomorrow = Utc::now() + chrono::Duration::days(1); - c.create_token(editor_id, Some(tomorrow)).unwrap(); + c.create_token(editor_id, Some(chrono::Duration::days(1))).unwrap(); } #[test] -- cgit v1.2.3 From b44fd9a78c1505258178a51201e8abea9977baa5 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 8 Jan 2019 15:27:05 -0800 Subject: /auth/oidc endpoint has 31 day limit --- rust/src/api_wrappers.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rust') diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 818a41c2..22b5f857 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -1161,10 +1161,10 @@ impl Api for Server { )?; auth_context.require_role(FatcatRole::Superuser)?; let (editor, created) = self.auth_oidc_handler(params, &conn)?; - // create an auth token; leave it to webface to attenuate to a given duration + // create an auth token with 31 day duration let token = self.auth_confectionary.create_token( FatCatId::from_str(&editor.editor_id.clone().unwrap())?, - None, + Some(chrono::Duration::days(31)), )?; let result = AuthOidcResult { editor, token }; Ok((result, created)) -- cgit v1.2.3 From e2cd8b331c7558688b0ec5b807a76ca104f40f84 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 8 Jan 2019 15:37:47 -0800 Subject: better rust auth error handling/responses --- rust/src/auth.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'rust') diff --git a/rust/src/auth.rs b/rust/src/auth.rs index f9b8d7b9..acee147e 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -241,21 +241,21 @@ impl AuthConfectionary { let raw = BASE64.decode(s.as_bytes())?; let mac = match Macaroon::deserialize(&raw) { Ok(m) => m, - Err(_e) => { + Err(e) => { // TODO: should be "chaining" here - //bail!("macaroon deserialize error: {:?}", e), return Err( - ErrorKind::InvalidCredentials("macaroon deserialize error".to_string()).into(), + ErrorKind::InvalidCredentials( + format!("macaroon deserialize error: {:?}", e)).into(), ); } }; let mac = match mac.validate() { Ok(m) => m, - Err(_e) => { + Err(e) => { // TODO: should be "chaining" here - //bail!("macaroon validate error: {:?}", e), return Err( - ErrorKind::InvalidCredentials("macaroon validate error".to_string()).into(), + ErrorKind::InvalidCredentials( + format!("macaroon validate error: {:?}", e)).into(), ); } }; @@ -267,7 +267,14 @@ impl AuthConfectionary { break; } } - let editor_id = editor_id.expect("expected an editor_id caveat"); + let editor_id = match editor_id { + Some(id) => id, + None => { + return Err( + ErrorKind::InvalidCredentials("expected an editor_id caveat".to_string()).into(), + ); + }, + }; verifier.satisfy_exact(&format!("editor_id = {}", editor_id.to_string())); if let Some(endpoint) = endpoint { // API endpoint @@ -284,7 +291,14 @@ impl AuthConfectionary { break; } } - let created = created.expect("expected a 'created' (time >) caveat"); + let created = match created { + Some(c) => c, + None => { + return Err( + ErrorKind::InvalidCredentials("expected a 'created' (time >) caveat".to_string()).into(), + ); + }, + }; verifier.satisfy_exact(&format!( "time > {}", created.to_rfc3339_opts(SecondsFormat::Secs, true) -- cgit v1.2.3 From a2cbc5b4d88f3385ebed5b70e8cce19e00e81a8f Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 8 Jan 2019 16:01:13 -0800 Subject: rust fmt --- rust/src/api_wrappers.rs | 11 ++++++----- rust/src/auth.rs | 46 +++++++++++++++++++++++++--------------------- rust/tests/test_auth.rs | 3 ++- 3 files changed, 33 insertions(+), 27 deletions(-) (limited to 'rust') diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 22b5f857..f03d4041 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -1256,7 +1256,8 @@ impl Api for Server { Ok(()) }) { Ok(()) => AuthCheckResponse::Success(Success { - message: "auth check successful!".to_string() }), + message: "auth check successful!".to_string(), + }), Err(Error(ErrorKind::Diesel(e), _)) => AuthCheckResponse::BadRequest(ErrorResponse { message: e.to_string(), }), @@ -1269,23 +1270,23 @@ impl Api for Server { AuthCheckResponse::Forbidden(ErrorResponse { message: e.to_string(), }) - }, + } Err(Error(ErrorKind::InsufficientPrivileges(e), _)) => { AuthCheckResponse::Forbidden(ErrorResponse { message: e.to_string(), }) - }, + } Err(Error(ErrorKind::OtherBadRequest(e), _)) => { AuthCheckResponse::BadRequest(ErrorResponse { message: e.to_string(), }) - }, + } Err(e) => { error!("{}", e); AuthCheckResponse::GenericError(ErrorResponse { message: e.to_string(), }) - }, + } }; Box::new(futures::done(Ok(ret))) } diff --git a/rust/src/auth.rs b/rust/src/auth.rs index acee147e..d4e03ecf 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -243,20 +243,22 @@ impl AuthConfectionary { Ok(m) => m, Err(e) => { // TODO: should be "chaining" here - return Err( - ErrorKind::InvalidCredentials( - format!("macaroon deserialize error: {:?}", e)).into(), - ); + return Err(ErrorKind::InvalidCredentials(format!( + "macaroon deserialize error: {:?}", + e + )) + .into()); } }; let mac = match mac.validate() { Ok(m) => m, Err(e) => { // TODO: should be "chaining" here - return Err( - ErrorKind::InvalidCredentials( - format!("macaroon validate error: {:?}", e)).into(), - ); + return Err(ErrorKind::InvalidCredentials(format!( + "macaroon validate error: {:?}", + e + )) + .into()); } }; let mut verifier = Verifier::new(); @@ -270,10 +272,11 @@ impl AuthConfectionary { let editor_id = match editor_id { Some(id) => id, None => { - return Err( - ErrorKind::InvalidCredentials("expected an editor_id caveat".to_string()).into(), - ); - }, + return Err(ErrorKind::InvalidCredentials( + "expected an editor_id caveat".to_string(), + ) + .into()); + } }; verifier.satisfy_exact(&format!("editor_id = {}", editor_id.to_string())); if let Some(endpoint) = endpoint { @@ -294,10 +297,11 @@ impl AuthConfectionary { let created = match created { Some(c) => c, None => { - return Err( - ErrorKind::InvalidCredentials("expected a 'created' (time >) caveat".to_string()).into(), - ); - }, + return Err(ErrorKind::InvalidCredentials( + "expected a 'created' (time >) caveat".to_string(), + ) + .into()); + } }; verifier.satisfy_exact(&format!( "time > {}", @@ -327,9 +331,10 @@ impl AuthConfectionary { let verify_key = match self.root_keys.get(mac.identifier()) { Some(key) => key, None => { - return Err(ErrorKind::InvalidCredentials( - format!("no valid auth signing key for identifier: {}", mac.identifier()) - ) + return Err(ErrorKind::InvalidCredentials(format!( + "no valid auth signing key for identifier: {}", + mac.identifier() + )) .into()); } }; @@ -344,8 +349,7 @@ impl AuthConfectionary { Err(e) => { // TODO: chain return Err( - ErrorKind::InvalidCredentials( - format!("token parsing failed: {:?}", e)).into(), + ErrorKind::InvalidCredentials(format!("token parsing failed: {:?}", e)).into(), ); } } diff --git a/rust/tests/test_auth.rs b/rust/tests/test_auth.rs index 412b67e8..1509bab4 100644 --- a/rust/tests/test_auth.rs +++ b/rust/tests/test_auth.rs @@ -18,7 +18,8 @@ fn test_macaroons() { c.create_token(editor_id, None).unwrap(); // create token w/ expiration - c.create_token(editor_id, Some(chrono::Duration::days(1))).unwrap(); + c.create_token(editor_id, Some(chrono::Duration::days(1))) + .unwrap(); } #[test] -- cgit v1.2.3 From ffb721f90c5d97ee80885209bf45feb85ca9625c Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 8 Jan 2019 16:26:20 -0800 Subject: fix typo in rust/env.example --- rust/env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/env.example b/rust/env.example index 1e7ef42d..d31bcac1 100644 --- a/rust/env.example +++ b/rust/env.example @@ -1,5 +1,5 @@ DATABASE_URL="postgres://fatcat:tactaf@localhost/fatcat" -TEST_DATABASE_URL="postgres://fatcat:tactaf@localhost/fatcat_test +TEST_DATABASE_URL="postgres://fatcat:tactaf@localhost/fatcat_test" AUTH_LOCATION="dev.fatcat.wiki" AUTH_KEY_IDENT="20190101-dev-dummy-key" AUTH_SECRET_KEY="5555555555555555555555555555555555555555xms=" -- cgit v1.2.3