diff --git a/.gitignore b/.gitignore index 0ccf1d1..8b502a4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ frontend/app.js frontend/app.js.LICENSE.txt frontend/css frontend/js +frontend/api.html frontend/locale/*.untranslated.json frontend/webfonts frontend/*.woff2 diff --git a/Dockerfile b/Dockerfile index d618877..116476f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ RUN set -ex \ tar \ unzip \ && make -C src -f ../Makefile generate-inner \ - && make download_libs \ + && make download_libs generate-apidocs \ && go install \ -ldflags "-X main.version=$(git describe --tags --always || echo dev)" \ -mod=readonly diff --git a/Dockerfile.minimal b/Dockerfile.minimal index 2c3fc1f..5cf2f7c 100644 --- a/Dockerfile.minimal +++ b/Dockerfile.minimal @@ -17,7 +17,7 @@ RUN set -ex \ tar \ unzip \ && make -C src -f ../Makefile generate-inner \ - && make download_libs \ + && make download_libs generate-apidocs \ && go install \ -ldflags "-X main.version=$(git describe --tags --always || echo dev)" \ -mod=readonly diff --git a/Makefile b/Makefile index fe5511a..13d77ad 100644 --- a/Makefile +++ b/Makefile @@ -6,12 +6,17 @@ default: generate download_libs generate: docker run --rm -i -v $(CURDIR):$(CURDIR) -w $(CURDIR) node:14-alpine \ sh -exc "apk add make && make -C src -f ../Makefile generate-inner && chown -R $(shell id -u) frontend src/node_modules" + docker run --rm -ti -v $(CURDIR):$(CURDIR) -w $(CURDIR) node:14-alpine \ + sh -exc "apk add make && make generate-apidocs && chown -R $(shell id -u) frontend" + +generate-apidocs: + npx redoc-cli bundle docs/openapi.yaml --disableGoogleFont true -o frontend/api.html generate-inner: npx npm@lts ci npx npm@lts run build -publish: download_libs +publish: download_libs generate-apidocs $(MAKE) -C src -f ../Makefile generate-inner curl -sSLo golang.sh https://raw.githubusercontent.com/Luzifer/github-publish/master/golang.sh bash golang.sh diff --git a/docs/openapi.yaml b/docs/openapi.yaml new file mode 100644 index 0000000..86bd1b7 --- /dev/null +++ b/docs/openapi.yaml @@ -0,0 +1,147 @@ +openapi: 3.0.0 +info: + description: > + OTS is a one-time-secret sharing platform. + + + When using the web application, the secret is encrypted with a symmetric + 256bit AES encryption in the browser before being sent to the server. + Afterwards an URL containing the ID of the secret and the password is + generated. The password is never sent to the server so the server will never + be able to decrypt the secrets it delivers with a reasonable effort. + + + This API allows you to store and read the same secrets as the web + application. + title: Luzifer/OTS API + version: 0.x +externalDocs: + description: Luzifer/OTS on Github + url: https://github.com/Luzifer/ots +servers: + - url: https://ots.fyi/api + description: Public hosted instance +paths: + /create: + post: + summary: Store a new secret on the OTS server + description: >- + You should encrypt the secret prior to sending it to the server. For + maximum compatibility, [use the same encryption as the web + application](https://github.com/Luzifer/ots). Plain text secrets are + supported but not recommended. + + + To generate a URL that works with the web application, append + `#SECRET_ID|PASSWORD` after the URL. For an instance on + `https://ots.fyi`, the example response in this documentation would + become `https://ots.fyi/#5e0065ee-5734-4548-9fd3-bb0bcd4c899d|mypass`. + Note that you should correctly [percent + encode](https://datatracker.ietf.org/doc/html/rfc3986) the `|` (pipe) + character for it to work in all browsers. + operationId: createSecret + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Secret' + multipart/form-data: + schema: + $ref: '#/components/schemas/Secret' + responses: + '200': + description: Reference to the newly stored secret. + content: + application/json: + schema: + $ref: '#/components/schemas/CreatedSecret' + '400': + description: Secret missing or invalid JSON body. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal error, nothing is wrong with the request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /get/{id}: + get: + summary: Retrieve an existing secret from the OTS server + description: >- + You may need to decrypt the secret after retrieving it. For maximum + compatibility, [use the same encryption as the web + application](https://github.com/Luzifer/ots). Plain text secrets are + supported but not recommended. + operationId: getSecret + parameters: + - in: path + name: id + schema: + type: string + example: 5e0065ee-5734-4548-9fd3-bb0bcd4c899d + required: true + description: Reference to the stored secret. + responses: + '200': + description: Stored secret contents. + content: + application/json: + schema: + $ref: '#/components/schemas/RetrievedSecret' + '400': + description: Secret ID missing or invalid. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Secret does not exist, may be read by someone else. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal error, nothing is wrong with the request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' +components: + schemas: + Secret: + type: object + properties: + secret: + type: string + example: U2FsdGVkX18wJtHr6YpTe8QrvMUUdaLZ+JMBNi1OvOQ= + required: + - secret + CreatedSecret: + type: object + properties: + success: + type: boolean + secret_id: + type: string + example: 5e0065ee-5734-4548-9fd3-bb0bcd4c899d + RetrievedSecret: + type: object + properties: + success: + type: boolean + secret: + type: string + example: U2FsdGVkX18wJtHr6YpTe8QrvMUUdaLZ+JMBNi1OvOQ= + Error: + type: object + properties: + success: + type: boolean + example: false + error: + type: string + example: Something went wrong.