diff --git a/dbschema/default.esdl b/dbschema/default.esdl index 4430594..e993ff5 100644 --- a/dbschema/default.esdl +++ b/dbschema/default.esdl @@ -10,6 +10,7 @@ module default { required multi authmethod: Authmethod; multi tokens: RefreshToken { constraint exclusive; + on target delete allow; }; # keys: Authmethods diff --git a/dbschema/migrations/00012.edgeql b/dbschema/migrations/00012.edgeql new file mode 100644 index 0000000..6eed87c --- /dev/null +++ b/dbschema/migrations/00012.edgeql @@ -0,0 +1,9 @@ +CREATE MIGRATION m1y23sawvajv4ba3unhkalgzsrnvpadjdkzpsa7vhqbm2ln65wt3dq + ONTO m1whcftw3ixmaofcafcskg2ttd5f4kpecobinvtejd66vge4p5whxq +{ + ALTER TYPE default::User { + ALTER LINK tokens { + ON TARGET DELETE ALLOW; + }; + }; +}; diff --git a/src/constants/responses.ts b/src/constants/responses.ts index 4723bf1..be455c6 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -24,6 +24,14 @@ export const DATABASE_READ_FAILED = responseBuilder("error", { error: "An error occurred while reading from the database", }); +/** + * A response indicating that an error occurred while deleting from the database + * Use with `500 Internal Server Error` + */ +export const DATABASE_DELETE_FAILED = responseBuilder("error", { + error: "An error occurred while deleting from the database", +}); + /** * A response indicating that the user does not have permission to access the resource * Use with `403 Forbidden` diff --git a/src/routes/auth/refreshToken.ts b/src/routes/auth/refreshToken.ts index 01ad6b8..30f56ad 100644 --- a/src/routes/auth/refreshToken.ts +++ b/src/routes/auth/refreshToken.ts @@ -1,8 +1,13 @@ import e from "@edgedb"; -import { DATABASE_WRITE_FAILED } from "constants/responses"; +import { + DATABASE_DELETE_FAILED, + DATABASE_WRITE_FAILED, + UNAUTHORIZED, +} from "constants/responses"; import { Elysia, t } from "elysia"; import { HttpStatusCode } from "elysia-http-status-code"; import { client } from "index"; +import { auth } from "plugins/auth"; import { passowrdAuthSecret } from "schemas/auth"; import { createToken } from "utils/auth/jwt"; import { promiseResult } from "utils/errors"; @@ -12,6 +17,7 @@ import { wait } from "utils/time"; export const refreshTokenRouter = new Elysia({ prefix: "/refresh-token" }) .use(HttpStatusCode()) + .use(auth) .post( "/password", async ({ body, set, httpStatus }) => { @@ -92,4 +98,69 @@ export const refreshTokenRouter = new Elysia({ prefix: "/refresh-token" }) }), detail: { tags: ["Auth"] }, }, - ); + ) + .delete("/all", async ({ auth, set, httpStatus }) => { + if (!auth.isAuthorized) { + set.status = httpStatus.HTTP_401_UNAUTHORIZED; + return UNAUTHORIZED; + } + if (auth.createdBy !== "login") { + set.status = httpStatus.HTTP_403_FORBIDDEN; + return responseBuilder("error", { + error: + "Access token must be generated using log in and not a refresh token", + }); + } + + const delQuery = e.count( + e.delete(e.RefreshToken, (t) => ({ + filter: e.op(t[" { + if (!auth.isAuthorized) { + set.status = httpStatus.HTTP_401_UNAUTHORIZED; + return UNAUTHORIZED; + } + + const delQuery = e.delete(e.RefreshToken, (t) => ({ + filter_single: e.op( + e.op(t["