mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Forge jwt for tests
This commit is contained in:
parent
49f700ca6e
commit
0aab4cd84c
1
.github/workflows/api-test.yml
vendored
1
.github/workflows/api-test.yml
vendored
@ -36,5 +36,4 @@ jobs:
|
|||||||
working-directory: ./api
|
working-directory: ./api
|
||||||
run: bun test
|
run: bun test
|
||||||
env:
|
env:
|
||||||
JWT_SECRET: "TODO"
|
|
||||||
POSTGRES_SERVER: localhost
|
POSTGRES_SERVER: localhost
|
||||||
|
@ -14,13 +14,18 @@ const jwks = createRemoteJWKSet(
|
|||||||
|
|
||||||
const Jwt = t.Object({
|
const Jwt = t.Object({
|
||||||
sub: t.String({ description: "User id" }),
|
sub: t.String({ description: "User id" }),
|
||||||
username: t.String(),
|
|
||||||
sid: t.String({ description: "Session id" }),
|
sid: t.String({ description: "Session id" }),
|
||||||
|
username: t.String(),
|
||||||
permissions: t.Array(t.String()),
|
permissions: t.Array(t.String()),
|
||||||
});
|
});
|
||||||
const validator = TypeCompiler.Compile(Jwt);
|
const validator = TypeCompiler.Compile(Jwt);
|
||||||
|
|
||||||
export const auth = new Elysia({ name: "auth" })
|
export const auth = new Elysia({ name: "auth" })
|
||||||
|
.guard({
|
||||||
|
headers: t.Object({
|
||||||
|
authorization: t.TemplateLiteral("Bearer ${string}"),
|
||||||
|
}),
|
||||||
|
})
|
||||||
.macro({
|
.macro({
|
||||||
permissions(perms: string[]) {
|
permissions(perms: string[]) {
|
||||||
return {
|
return {
|
||||||
|
@ -11,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 { KError } from "./models/error";
|
import type { KError } from "./models/error";
|
||||||
|
|
||||||
export const base = new Elysia({ name: "base" })
|
export const base = new Elysia({ name: "base" })
|
||||||
.onError(({ code, error }) => {
|
.onError(({ code, error }) => {
|
||||||
@ -61,11 +61,12 @@ export const app = new Elysia({ prefix })
|
|||||||
detail: {
|
detail: {
|
||||||
security: [{ bearer: ["core.read"] }, { api: ["core.read"] }],
|
security: [{ bearer: ["core.read"] }, { api: ["core.read"] }],
|
||||||
},
|
},
|
||||||
response: {
|
// See https://github.com/elysiajs/elysia/issues/1158
|
||||||
401: { ...KError, description: "" },
|
// response: {
|
||||||
403: { ...KError, description: "" },
|
// 401: { ...KError, description: "" },
|
||||||
},
|
// 403: { ...KError, description: "" },
|
||||||
perms: ["core.read"],
|
// },
|
||||||
|
permissions: ["core.read"],
|
||||||
},
|
},
|
||||||
(app) =>
|
(app) =>
|
||||||
app
|
app
|
||||||
@ -84,11 +85,12 @@ export const app = new Elysia({ prefix })
|
|||||||
detail: {
|
detail: {
|
||||||
security: [{ bearer: ["core.write"] }, { api: ["core.write"] }],
|
security: [{ bearer: ["core.write"] }, { api: ["core.write"] }],
|
||||||
},
|
},
|
||||||
response: {
|
// See https://github.com/elysiajs/elysia/issues/1158
|
||||||
401: { ...KError, description: "" },
|
// response: {
|
||||||
403: { ...KError, description: "" },
|
// 401: { ...KError, description: "" },
|
||||||
},
|
// 403: { ...KError, description: "" },
|
||||||
perms: ["core.read"],
|
// },
|
||||||
|
permissions: ["core.write"],
|
||||||
},
|
},
|
||||||
(app) => app.use(videosH).use(seed),
|
(app) => app.use(videosH).use(seed),
|
||||||
);
|
);
|
||||||
|
17
api/tests/helpers/jwt.ts
Normal file
17
api/tests/helpers/jwt.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { SignJWT } from "jose";
|
||||||
|
|
||||||
|
export async function getJwtHeaders() {
|
||||||
|
const jwt = await new SignJWT({
|
||||||
|
sub: "39158be0-3f59-4c45-b00d-d25b3bc2b884",
|
||||||
|
sid: "04ac7ecc-255b-481d-b0c8-537c1578e3d5",
|
||||||
|
username: "test-username",
|
||||||
|
permissions: ["core.read", "core.write"],
|
||||||
|
})
|
||||||
|
.setProtectedHeader({ alg: "HS256" })
|
||||||
|
.setIssuedAt()
|
||||||
|
.setIssuer(process.env.JWT_ISSUER!)
|
||||||
|
.setExpirationTime("2h")
|
||||||
|
.sign(new TextEncoder().encode(process.env.JWT_SECRET));
|
||||||
|
|
||||||
|
return { Authorization: `Bearer ${jwt}` };
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import { buildUrl } from "tests/utils";
|
import { buildUrl } from "tests/utils";
|
||||||
import { app } from "~/base";
|
import { app } from "~/base";
|
||||||
import type { SeedMovie } from "~/models/movie";
|
import type { SeedMovie } from "~/models/movie";
|
||||||
|
import { getJwtHeaders } from "./jwt";
|
||||||
|
|
||||||
export const getMovie = async (
|
export const getMovie = async (
|
||||||
id: string,
|
id: string,
|
||||||
@ -15,8 +16,9 @@ export const getMovie = async (
|
|||||||
headers: langs
|
headers: langs
|
||||||
? {
|
? {
|
||||||
"Accept-Language": langs,
|
"Accept-Language": langs,
|
||||||
|
...(await getJwtHeaders()),
|
||||||
}
|
}
|
||||||
: {},
|
: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -41,8 +43,9 @@ export const getMovies = async ({
|
|||||||
headers: langs
|
headers: langs
|
||||||
? {
|
? {
|
||||||
"Accept-Language": langs,
|
"Accept-Language": langs,
|
||||||
|
...(await getJwtHeaders()),
|
||||||
}
|
}
|
||||||
: {},
|
: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -56,6 +59,7 @@ export const createMovie = async (movie: SeedMovie) => {
|
|||||||
body: JSON.stringify(movie),
|
body: JSON.stringify(movie),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
...(await getJwtHeaders()),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { buildUrl } from "tests/utils";
|
import { buildUrl } from "tests/utils";
|
||||||
import { app } from "~/base";
|
import { app } from "~/base";
|
||||||
import type { SeedSerie } from "~/models/serie";
|
import type { SeedSerie } from "~/models/serie";
|
||||||
|
import { getJwtHeaders } from "./jwt";
|
||||||
|
|
||||||
export const createSerie = async (serie: SeedSerie) => {
|
export const createSerie = async (serie: SeedSerie) => {
|
||||||
const resp = await app.handle(
|
const resp = await app.handle(
|
||||||
@ -9,6 +10,7 @@ export const createSerie = async (serie: SeedSerie) => {
|
|||||||
body: JSON.stringify(serie),
|
body: JSON.stringify(serie),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
...(await getJwtHeaders()),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -29,8 +31,9 @@ export const getSerie = async (
|
|||||||
headers: langs
|
headers: langs
|
||||||
? {
|
? {
|
||||||
"Accept-Language": langs,
|
"Accept-Language": langs,
|
||||||
|
...(await getJwtHeaders()),
|
||||||
}
|
}
|
||||||
: {},
|
: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -58,8 +61,9 @@ export const getSeasons = async (
|
|||||||
headers: langs
|
headers: langs
|
||||||
? {
|
? {
|
||||||
"Accept-Language": langs,
|
"Accept-Language": langs,
|
||||||
|
...(await getJwtHeaders()),
|
||||||
}
|
}
|
||||||
: {},
|
: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -87,8 +91,9 @@ export const getEntries = async (
|
|||||||
headers: langs
|
headers: langs
|
||||||
? {
|
? {
|
||||||
"Accept-Language": langs,
|
"Accept-Language": langs,
|
||||||
|
...(await getJwtHeaders()),
|
||||||
}
|
}
|
||||||
: {},
|
: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -108,6 +113,7 @@ export const getExtras = async (
|
|||||||
const resp = await app.handle(
|
const resp = await app.handle(
|
||||||
new Request(buildUrl(`series/${serie}/extras`, opts), {
|
new Request(buildUrl(`series/${serie}/extras`, opts), {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
headers: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -124,6 +130,7 @@ export const getUnknowns = async (opts: {
|
|||||||
const resp = await app.handle(
|
const resp = await app.handle(
|
||||||
new Request(buildUrl("unknowns", opts), {
|
new Request(buildUrl("unknowns", opts), {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
headers: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -147,8 +154,9 @@ export const getNews = async ({
|
|||||||
headers: langs
|
headers: langs
|
||||||
? {
|
? {
|
||||||
"Accept-Language": langs,
|
"Accept-Language": langs,
|
||||||
|
...(await getJwtHeaders()),
|
||||||
}
|
}
|
||||||
: {},
|
: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { buildUrl } from "tests/utils";
|
import { buildUrl } from "tests/utils";
|
||||||
import { app } from "~/base";
|
import { app } from "~/base";
|
||||||
|
import { getJwtHeaders } from "./jwt";
|
||||||
|
|
||||||
export const getStaff = async (id: string, query: {}) => {
|
export const getStaff = async (id: string, query: {}) => {
|
||||||
const resp = await app.handle(
|
const resp = await app.handle(
|
||||||
new Request(buildUrl(`staff/${id}`, query), {
|
new Request(buildUrl(`staff/${id}`, query), {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
headers: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -32,8 +34,9 @@ export const getStaffRoles = async (
|
|||||||
headers: langs
|
headers: langs
|
||||||
? {
|
? {
|
||||||
"Accept-Language": langs,
|
"Accept-Language": langs,
|
||||||
|
...(await getJwtHeaders()),
|
||||||
}
|
}
|
||||||
: {},
|
: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -52,6 +55,7 @@ export const getSerieStaff = async (
|
|||||||
const resp = await app.handle(
|
const resp = await app.handle(
|
||||||
new Request(buildUrl(`series/${serie}/staff`, opts), {
|
new Request(buildUrl(`series/${serie}/staff`, opts), {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
headers: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -70,6 +74,7 @@ export const getMovieStaff = async (
|
|||||||
const resp = await app.handle(
|
const resp = await app.handle(
|
||||||
new Request(buildUrl(`movies/${movie}/staff`, opts), {
|
new Request(buildUrl(`movies/${movie}/staff`, opts), {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
headers: await getJwtHeaders(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { buildUrl } from "tests/utils";
|
import { buildUrl } from "tests/utils";
|
||||||
import { app } from "~/base";
|
import { app } from "~/base";
|
||||||
|
import { getJwtHeaders } from "./jwt";
|
||||||
|
|
||||||
export const getStudio = async (
|
export const getStudio = async (
|
||||||
id: string,
|
id: string,
|
||||||
@ -11,8 +12,9 @@ export const getStudio = async (
|
|||||||
headers: langs
|
headers: langs
|
||||||
? {
|
? {
|
||||||
"Accept-Language": langs,
|
"Accept-Language": langs,
|
||||||
|
...await getJwtHeaders()
|
||||||
}
|
}
|
||||||
: {},
|
: await getJwtHeaders()
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
@ -40,8 +42,9 @@ export const getShowsByStudio = async (
|
|||||||
headers: langs
|
headers: langs
|
||||||
? {
|
? {
|
||||||
"Accept-Language": langs,
|
"Accept-Language": langs,
|
||||||
|
...await getJwtHeaders()
|
||||||
}
|
}
|
||||||
: {},
|
: await getJwtHeaders()
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const body = await resp.json();
|
const body = await resp.json();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { buildUrl } from "tests/utils";
|
import { buildUrl } from "tests/utils";
|
||||||
import { app } from "~/base";
|
import { app } from "~/base";
|
||||||
import type { SeedVideo } from "~/models/video";
|
import type { SeedVideo } from "~/models/video";
|
||||||
|
import { getJwtHeaders } from "./jwt";
|
||||||
|
|
||||||
export const createVideo = async (video: SeedVideo | SeedVideo[]) => {
|
export const createVideo = async (video: SeedVideo | SeedVideo[]) => {
|
||||||
const resp = await app.handle(
|
const resp = await app.handle(
|
||||||
@ -9,6 +10,7 @@ export const createVideo = async (video: SeedVideo | SeedVideo[]) => {
|
|||||||
body: JSON.stringify(Array.isArray(video) ? video : [video]),
|
body: JSON.stringify(Array.isArray(video) ? video : [video]),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
...(await getJwtHeaders()),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { beforeAll, describe, expect, it } from "bun:test";
|
import { beforeAll, describe, expect, it } from "bun:test";
|
||||||
|
import { getJwtHeaders } from "tests/helpers/jwt";
|
||||||
import { expectStatus } from "tests/utils";
|
import { expectStatus } from "tests/utils";
|
||||||
import { db } from "~/db";
|
import { db } from "~/db";
|
||||||
import { shows } from "~/db/schema";
|
import { shows } from "~/db/schema";
|
||||||
@ -10,8 +11,8 @@ import { app, createMovie, getMovies } from "../helpers";
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await db.delete(shows);
|
await db.delete(shows);
|
||||||
for (const movie of [bubble, dune1984, dune]) {
|
for (const movie of [bubble, dune1984, dune]) {
|
||||||
const [ret, _] = await createMovie(movie);
|
const [ret, body] = await createMovie(movie);
|
||||||
expect(ret.status).toBe(201);
|
expectStatus(ret, body).toBe(201);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -73,7 +74,9 @@ describe("with a null value", () => {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
resp = await app.handle(new Request(next));
|
resp = await app.handle(
|
||||||
|
new Request(next, { headers: await getJwtHeaders() }),
|
||||||
|
);
|
||||||
body = await resp.json();
|
body = await resp.json();
|
||||||
|
|
||||||
expectStatus(resp, body).toBe(200);
|
expectStatus(resp, body).toBe(200);
|
||||||
@ -120,7 +123,9 @@ describe("with a null value", () => {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
resp = await app.handle(new Request(next));
|
resp = await app.handle(
|
||||||
|
new Request(next, { headers: await getJwtHeaders() }),
|
||||||
|
);
|
||||||
body = await resp.json();
|
body = await resp.json();
|
||||||
|
|
||||||
expectStatus(resp, body).toBe(200);
|
expectStatus(resp, body).toBe(200);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { beforeAll, describe, expect, it } from "bun:test";
|
import { beforeAll, describe, expect, it } from "bun:test";
|
||||||
|
import { getJwtHeaders } from "tests/helpers/jwt";
|
||||||
import { expectStatus } from "tests/utils";
|
import { expectStatus } from "tests/utils";
|
||||||
import { db } from "~/db";
|
import { db } from "~/db";
|
||||||
import { shows } from "~/db/schema";
|
import { shows } from "~/db/schema";
|
||||||
@ -71,7 +72,9 @@ describe("Get all movies", () => {
|
|||||||
});
|
});
|
||||||
expectStatus(resp, body).toBe(200);
|
expectStatus(resp, body).toBe(200);
|
||||||
|
|
||||||
resp = await app.handle(new Request(body.next));
|
resp = await app.handle(
|
||||||
|
new Request(body.next, { headers: await getJwtHeaders() }),
|
||||||
|
);
|
||||||
body = await resp.json();
|
body = await resp.json();
|
||||||
|
|
||||||
expectStatus(resp, body).toBe(200);
|
expectStatus(resp, body).toBe(200);
|
||||||
@ -104,7 +107,9 @@ describe("Get all movies", () => {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
resp = await app.handle(new Request(next));
|
resp = await app.handle(
|
||||||
|
new Request(next, { headers: await getJwtHeaders() }),
|
||||||
|
);
|
||||||
body = await resp.json();
|
body = await resp.json();
|
||||||
|
|
||||||
expectStatus(resp, body).toBe(200);
|
expectStatus(resp, body).toBe(200);
|
||||||
@ -160,7 +165,9 @@ describe("Get all movies", () => {
|
|||||||
expect(items.length).toBe(1);
|
expect(items.length).toBe(1);
|
||||||
expect(items[0].id).toBe(expectedIds[0]);
|
expect(items[0].id).toBe(expectedIds[0]);
|
||||||
// Get Second Page
|
// Get Second Page
|
||||||
resp = await app.handle(new Request(body.next));
|
resp = await app.handle(
|
||||||
|
new Request(body.next, { headers: await getJwtHeaders() }),
|
||||||
|
);
|
||||||
body = await resp.json();
|
body = await resp.json();
|
||||||
|
|
||||||
expectStatus(resp, body).toBe(200);
|
expectStatus(resp, body).toBe(200);
|
||||||
@ -175,7 +182,9 @@ describe("Get all movies", () => {
|
|||||||
});
|
});
|
||||||
expectStatus(resp, body).toBe(200);
|
expectStatus(resp, body).toBe(200);
|
||||||
|
|
||||||
const resp2 = await app.handle(new Request(body.next));
|
const resp2 = await app.handle(
|
||||||
|
new Request(body.next, { headers: await getJwtHeaders() }),
|
||||||
|
);
|
||||||
const body2 = await resp2.json();
|
const body2 = await resp2.json();
|
||||||
expectStatus(resp2, body).toBe(200);
|
expectStatus(resp2, body).toBe(200);
|
||||||
|
|
||||||
@ -187,7 +196,9 @@ describe("Get all movies", () => {
|
|||||||
|
|
||||||
it("Get /random", async () => {
|
it("Get /random", async () => {
|
||||||
const resp = await app.handle(
|
const resp = await app.handle(
|
||||||
new Request("http://localhost/movies/random"),
|
new Request("http://localhost/movies/random", {
|
||||||
|
headers: await getJwtHeaders(),
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
expect(resp.status).toBe(302);
|
expect(resp.status).toBe(302);
|
||||||
const location = resp.headers.get("location")!;
|
const location = resp.headers.get("location")!;
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { beforeAll } from "bun:test";
|
import { beforeAll } from "bun:test";
|
||||||
import { migrate } from "~/db";
|
import { migrate } from "~/db";
|
||||||
|
|
||||||
|
process.env.JWT_SECRET = "this is a secret";
|
||||||
|
process.env.JWT_ISSUER = "https://kyoo.zoriya.dev";
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await migrate();
|
await migrate();
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user