mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Check for permissions on each routes
This commit is contained in:
parent
8110f7de66
commit
49f700ca6e
@ -1,6 +1,6 @@
|
|||||||
import Elysia, { getSchemaValidator, t } from "elysia";
|
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
||||||
|
import Elysia, { t } from "elysia";
|
||||||
import { createRemoteJWKSet, jwtVerify } from "jose";
|
import { createRemoteJWKSet, jwtVerify } from "jose";
|
||||||
import { KError } from "./models/error";
|
|
||||||
|
|
||||||
const jwtSecret = process.env.JWT_SECRET
|
const jwtSecret = process.env.JWT_SECRET
|
||||||
? new TextEncoder().encode(process.env.JWT_SECRET)
|
? new TextEncoder().encode(process.env.JWT_SECRET)
|
||||||
@ -16,33 +16,40 @@ const Jwt = t.Object({
|
|||||||
sub: t.String({ description: "User id" }),
|
sub: t.String({ description: "User id" }),
|
||||||
username: t.String(),
|
username: t.String(),
|
||||||
sid: t.String({ description: "Session id" }),
|
sid: t.String({ description: "Session id" }),
|
||||||
|
permissions: t.Array(t.String()),
|
||||||
});
|
});
|
||||||
const validator = getSchemaValidator(Jwt);
|
const validator = TypeCompiler.Compile(Jwt);
|
||||||
|
|
||||||
export const auth = new Elysia({ name: "auth" })
|
export const auth = new Elysia({ name: "auth" })
|
||||||
.guard({
|
|
||||||
// Those are not applied for now. See https://github.com/elysiajs/elysia/issues/1139
|
|
||||||
detail: {
|
|
||||||
security: [{ bearer: ["read"] }, { api: ["read"] }],
|
|
||||||
},
|
|
||||||
response: {
|
|
||||||
401: { ...KError, description: "" },
|
|
||||||
403: { ...KError, description: "" },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.macro({
|
.macro({
|
||||||
permissions(perms: string[]) {
|
permissions(perms: string[]) {
|
||||||
return {
|
return {
|
||||||
resolve: async ({ headers: { authorization }, error }) => {
|
resolve: async ({ headers: { authorization }, error }) => {
|
||||||
console.log(process.env.JWT_ISSUER);
|
|
||||||
const bearer = authorization?.slice(7);
|
const bearer = authorization?.slice(7);
|
||||||
if (!bearer) return { jwt: false };
|
if (!bearer) {
|
||||||
|
return error(500, {
|
||||||
|
status: 500,
|
||||||
|
message: "No jwt, auth server configuration error.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-expect-error ts can't understand that there's two overload idk why
|
// @ts-expect-error ts can't understand that there's two overload idk why
|
||||||
const { payload } = await jwtVerify(bearer, jwtSecret ?? jwks, {
|
const { payload } = await jwtVerify(bearer, jwtSecret ?? jwks, {
|
||||||
issuer: process.env.JWT_ISSUER,
|
issuer: process.env.JWT_ISSUER,
|
||||||
});
|
});
|
||||||
// TODO: use perms
|
const jwt = validator.Decode(payload);
|
||||||
return { jwt: validator.Decode<typeof Jwt>(payload) };
|
|
||||||
|
for (const perm of perms) {
|
||||||
|
if (!jwt.permissions.includes(perm)) {
|
||||||
|
return error(403, {
|
||||||
|
status: 403,
|
||||||
|
message: `Missing permission: '${perm}'.`,
|
||||||
|
details: { current: jwt.permissions, required: perms },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { jwt };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Elysia, t } from "elysia";
|
import { Elysia, t } from "elysia";
|
||||||
|
import { auth } from "./auth";
|
||||||
import { entriesH } from "./controllers/entries";
|
import { entriesH } from "./controllers/entries";
|
||||||
import { imagesH } from "./controllers/images";
|
import { imagesH } from "./controllers/images";
|
||||||
import { seasonsH } from "./controllers/seasons";
|
import { seasonsH } from "./controllers/seasons";
|
||||||
@ -10,7 +11,7 @@ import { showsH } from "./controllers/shows/shows";
|
|||||||
import { staffH } from "./controllers/staff";
|
import { staffH } from "./controllers/staff";
|
||||||
import { studiosH } from "./controllers/studios";
|
import { studiosH } from "./controllers/studios";
|
||||||
import { videosH } from "./controllers/videos";
|
import { videosH } from "./controllers/videos";
|
||||||
import type { KError } from "./models/error";
|
import { KError } from "./models/error";
|
||||||
|
|
||||||
export const base = new Elysia({ name: "base" })
|
export const base = new Elysia({ name: "base" })
|
||||||
.onError(({ code, error }) => {
|
.onError(({ code, error }) => {
|
||||||
@ -53,14 +54,41 @@ export const base = new Elysia({ name: "base" })
|
|||||||
export const prefix = process.env.KYOO_PREFIX ?? "";
|
export const prefix = process.env.KYOO_PREFIX ?? "";
|
||||||
export const app = new Elysia({ prefix })
|
export const app = new Elysia({ prefix })
|
||||||
.use(base)
|
.use(base)
|
||||||
.use(showsH)
|
.use(auth)
|
||||||
.use(movies)
|
.guard(
|
||||||
.use(series)
|
{
|
||||||
.use(collections)
|
// Those are not applied for now. See https://github.com/elysiajs/elysia/issues/1139
|
||||||
.use(entriesH)
|
detail: {
|
||||||
.use(seasonsH)
|
security: [{ bearer: ["core.read"] }, { api: ["core.read"] }],
|
||||||
.use(studiosH)
|
},
|
||||||
.use(staffH)
|
response: {
|
||||||
.use(videosH)
|
401: { ...KError, description: "" },
|
||||||
.use(imagesH)
|
403: { ...KError, description: "" },
|
||||||
.use(seed);
|
},
|
||||||
|
perms: ["core.read"],
|
||||||
|
},
|
||||||
|
(app) =>
|
||||||
|
app
|
||||||
|
.use(showsH)
|
||||||
|
.use(movies)
|
||||||
|
.use(series)
|
||||||
|
.use(collections)
|
||||||
|
.use(entriesH)
|
||||||
|
.use(seasonsH)
|
||||||
|
.use(studiosH)
|
||||||
|
.use(staffH)
|
||||||
|
.use(imagesH),
|
||||||
|
)
|
||||||
|
.guard(
|
||||||
|
{
|
||||||
|
detail: {
|
||||||
|
security: [{ bearer: ["core.write"] }, { api: ["core.write"] }],
|
||||||
|
},
|
||||||
|
response: {
|
||||||
|
401: { ...KError, description: "" },
|
||||||
|
403: { ...KError, description: "" },
|
||||||
|
},
|
||||||
|
perms: ["core.read"],
|
||||||
|
},
|
||||||
|
(app) => app.use(videosH).use(seed),
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user