mirror of
https://github.com/versia-pub/server.git
synced 2026-03-13 05:49:16 +01:00
refactor(config): ♻️ Redo config structure from scratch, simplify validation code, improve checks, add support for loading sensitive data from paths
This commit is contained in:
parent
d4afd84019
commit
54fd81f076
118 changed files with 3892 additions and 5291 deletions
|
|
@ -1,10 +1,10 @@
|
|||
import { z } from "@hono/zod-openapi";
|
||||
import { Hooks, Plugin } from "@versia/kit";
|
||||
import { User } from "@versia/kit/db";
|
||||
import chalk from "chalk";
|
||||
import { getCookie } from "hono/cookie";
|
||||
import { jwtVerify } from "jose";
|
||||
import { JOSEError, JWTExpired } from "jose/errors";
|
||||
import { keyPair, sensitiveString } from "~/classes/config/schema.ts";
|
||||
import { ApiError } from "~/classes/errors/api-error.ts";
|
||||
import { RolePermissions } from "~/drizzle/schema.ts";
|
||||
import authorizeRoute from "./routes/authorize.ts";
|
||||
|
|
@ -26,64 +26,12 @@ const configSchema = z.object({
|
|||
id: z.string().min(1),
|
||||
url: z.string().min(1),
|
||||
client_id: z.string().min(1),
|
||||
client_secret: z.string().min(1),
|
||||
client_secret: sensitiveString,
|
||||
icon: z.string().min(1).optional(),
|
||||
}),
|
||||
)
|
||||
.default([]),
|
||||
keys: z
|
||||
.object({
|
||||
public: z
|
||||
.string()
|
||||
.min(1)
|
||||
.transform(async (v) => {
|
||||
try {
|
||||
return await crypto.subtle.importKey(
|
||||
"spki",
|
||||
Buffer.from(v, "base64"),
|
||||
"Ed25519",
|
||||
true,
|
||||
["verify"],
|
||||
);
|
||||
} catch {
|
||||
throw new Error(
|
||||
"Public key at oidc.keys.public is invalid",
|
||||
);
|
||||
}
|
||||
}),
|
||||
private: z
|
||||
.string()
|
||||
.min(1)
|
||||
.transform(async (v) => {
|
||||
try {
|
||||
return await crypto.subtle.importKey(
|
||||
"pkcs8",
|
||||
Buffer.from(v, "base64"),
|
||||
"Ed25519",
|
||||
true,
|
||||
["sign"],
|
||||
);
|
||||
} catch {
|
||||
throw new Error(
|
||||
"Private key at oidc.keys.private is invalid",
|
||||
);
|
||||
}
|
||||
}),
|
||||
})
|
||||
.optional()
|
||||
.transform(async (v, ctx) => {
|
||||
if (!(v?.private && v?.public)) {
|
||||
const { public_key, private_key } = await User.generateKeys();
|
||||
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `Keys are missing, please add the following to your config:\n\nkeys.public: ${chalk.gray(public_key)}\nkeys.private: ${chalk.gray(private_key)}
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
return v as Exclude<typeof v, undefined>;
|
||||
}),
|
||||
keys: keyPair,
|
||||
});
|
||||
|
||||
const plugin = new Plugin(configSchema);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { randomString } from "@/math";
|
|||
import { Application } from "@versia/kit/db";
|
||||
import { RolePermissions } from "@versia/kit/tables";
|
||||
import { SignJWT } from "jose";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
import { fakeRequest, getTestUsers } from "~/tests/utils";
|
||||
|
||||
const { deleteUsers, tokens, users } = await getTestUsers(1);
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ export default (plugin: PluginType): void =>
|
|||
...payload,
|
||||
name: user.data.displayName,
|
||||
preferred_username: user.data.username,
|
||||
picture: user.getAvatarUrl(context.get("config")),
|
||||
picture: user.getAvatarUrl(),
|
||||
updated_at: new Date(
|
||||
user.data.updatedAt,
|
||||
).toISOString(),
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { OpenIdAccounts, RolePermissions, Users } from "@versia/kit/tables";
|
|||
import { setCookie } from "hono/cookie";
|
||||
import { SignJWT } from "jose";
|
||||
import { ApiError } from "~/classes/errors/api-error.ts";
|
||||
import { Account as AccountSchema } from "~/classes/schemas/account.ts";
|
||||
import type { PluginType } from "../../index.ts";
|
||||
import { automaticOidcFlow } from "../../utils.ts";
|
||||
|
||||
|
|
@ -199,30 +200,8 @@ export default (plugin: PluginType): void => {
|
|||
email?.split("@")[0] ??
|
||||
randomString(8, "hex");
|
||||
|
||||
const usernameValidator = z
|
||||
.string()
|
||||
.regex(/^[a-z0-9_]+$/)
|
||||
.min(3)
|
||||
.max(
|
||||
context.get("config").validation
|
||||
.max_username_size,
|
||||
)
|
||||
.refine(
|
||||
(value) =>
|
||||
!context
|
||||
.get("config")
|
||||
.validation.username_blacklist.includes(
|
||||
value,
|
||||
),
|
||||
)
|
||||
.refine((value) =>
|
||||
context
|
||||
.get("config")
|
||||
.filters.username.some((filter) =>
|
||||
value.match(filter),
|
||||
),
|
||||
)
|
||||
.refine(
|
||||
const usernameValidator =
|
||||
AccountSchema.shape.username.refine(
|
||||
async (value) =>
|
||||
!(await User.fromSql(
|
||||
and(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue