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:
Jesse Wierzbinski 2025-02-15 02:47:29 +01:00
parent d4afd84019
commit 54fd81f076
No known key found for this signature in database
118 changed files with 3892 additions and 5291 deletions

View file

@ -1,8 +1,8 @@
import { userAddressValidator } from "@/api.ts";
import { z } from "@hono/zod-openapi";
import type { Account as ApiAccount } from "@versia/client/types";
import { config } from "~/packages/config-manager";
import { zBoolean } from "~/packages/config-manager/config.type";
import { zBoolean } from "~/classes/schemas/common.ts";
import { config } from "~/config.ts";
import { iso631 } from "./common.ts";
import { CustomEmoji } from "./emoji.ts";
import { Role } from "./versia.ts";
@ -12,7 +12,7 @@ export const Field = z.object({
.string()
.trim()
.min(1)
.max(config.validation.max_field_name_size)
.max(config.validation.accounts.max_field_name_characters)
.openapi({
description: "The key of a given fields key-value pair.",
example: "Freak level",
@ -24,7 +24,7 @@ export const Field = z.object({
.string()
.trim()
.min(1)
.max(config.validation.max_field_value_size)
.max(config.validation.accounts.max_field_value_characters)
.openapi({
description: "The value associated with the name key.",
example: "<p>High</p>",
@ -87,9 +87,12 @@ export const Source = z
.string()
.trim()
.min(0)
.max(config.validation.max_bio_size)
.max(config.validation.accounts.max_bio_characters)
.refine(
(s) => !config.filters.bio.some((filter) => s.match(filter)),
(s) =>
!config.validation.filters.bio.some((filter) =>
filter.test(s),
),
"Bio contains blocked words",
)
.openapi({
@ -99,9 +102,12 @@ export const Source = z
url: "https://docs.joinmastodon.org/entities/Account/#source-note",
},
}),
fields: z.array(Field).max(config.validation.max_field_count).openapi({
description: "Metadata about the account.",
}),
fields: z
.array(Field)
.max(config.validation.accounts.max_field_count)
.openapi({
description: "Metadata about the account.",
}),
})
.openapi({
description:
@ -126,15 +132,25 @@ export const Account = z.object({
.string()
.min(3)
.trim()
.max(config.validation.max_username_size)
.max(config.validation.accounts.max_username_characters)
.regex(
/^[a-z0-9_-]+$/,
"Username can only contain letters, numbers, underscores and hyphens",
)
.refine(
(s) => !config.filters.username.some((filter) => s.match(filter)),
(s) =>
!config.validation.filters.username.some((filter) =>
filter.test(s),
),
"Username contains blocked words",
)
.refine(
(s) =>
!config.validation.accounts.disallowed_usernames.some((u) =>
u.test(s),
),
"Username is disallowed",
)
.openapi({
description: "The username of the account, not including domain.",
example: "lexi",
@ -169,10 +185,12 @@ export const Account = z.object({
.string()
.min(3)
.trim()
.max(config.validation.max_displayname_size)
.max(config.validation.accounts.max_displayname_characters)
.refine(
(s) =>
!config.filters.displayname.some((filter) => s.match(filter)),
!config.validation.filters.displayname.some((filter) =>
filter.test(s),
),
"Display name contains blocked words",
)
.openapi({
@ -185,10 +203,11 @@ export const Account = z.object({
note: z
.string()
.min(0)
.max(config.validation.max_bio_size)
.max(config.validation.accounts.max_bio_characters)
.trim()
.refine(
(s) => !config.filters.bio.some((filter) => s.match(filter)),
(s) =>
!config.validation.filters.bio.some((filter) => filter.test(s)),
"Bio contains blocked words",
)
.openapi({
@ -255,7 +274,7 @@ export const Account = z.object({
}),
fields: z
.array(Field)
.max(config.validation.max_field_count)
.max(config.validation.accounts.max_field_count)
.openapi({
description:
"Additional metadata attached to a profile as name-value pairs.",

View file

@ -1,5 +1,5 @@
import { z } from "@hono/zod-openapi";
import { config } from "~/packages/config-manager/index.ts";
import { config } from "~/config.ts";
import { Id } from "./common.ts";
export const Attachment = z
@ -54,7 +54,7 @@ export const Attachment = z
description: z
.string()
.trim()
.max(config.validation.max_media_description_size)
.max(config.validation.media.max_description_characters)
.nullable()
.openapi({
description:

View file

@ -4,3 +4,8 @@ import ISO6391 from "iso-639-1";
export const Id = z.string().uuid();
export const iso631 = z.enum(ISO6391.getAllCodes() as [string, ...string[]]);
export const zBoolean = z
.string()
.transform((v) => ["true", "1", "on"].includes(v.toLowerCase()))
.or(z.boolean());

View file

@ -1,7 +1,7 @@
import { emojiValidator } from "@/api.ts";
import { z } from "@hono/zod-openapi";
import { zBoolean } from "~/packages/config-manager/config.type";
import { config } from "~/packages/config-manager/index.ts";
import { zBoolean } from "~/classes/schemas/common.ts";
import { config } from "~/config.ts";
import { Id } from "./common.ts";
export const CustomEmoji = z
@ -15,7 +15,7 @@ export const CustomEmoji = z
.string()
.trim()
.min(1)
.max(config.validation.max_emoji_shortcode_size)
.max(config.validation.emojis.max_shortcode_characters)
.regex(
emojiValidator,
"Shortcode must only contain letters (any case), numbers, dashes or underscores.",
@ -77,7 +77,7 @@ export const CustomEmoji = z
/* Versia Server API extension */
description: z
.string()
.max(config.validation.max_emoji_description_size)
.max(config.validation.emojis.max_description_characters)
.nullable()
.openapi({
description:

View file

@ -1,6 +1,5 @@
import { z } from "@hono/zod-openapi";
import { zBoolean } from "~/packages/config-manager/config.type.ts";
import { Id } from "./common.ts";
import { Id, zBoolean } from "./common.ts";
export const FilterStatus = z
.object({

View file

@ -1,5 +1,5 @@
import { z } from "@hono/zod-openapi";
import { config } from "~/packages/config-manager/index.ts";
import { config } from "~/config.ts";
import { Id } from "./common.ts";
import { CustomEmoji } from "./emoji.ts";
@ -9,7 +9,7 @@ export const PollOption = z
.string()
.trim()
.min(1)
.max(config.validation.max_poll_option_size)
.max(config.validation.polls.max_option_characters)
.openapi({
description: "The text value of the poll option.",
example: "yes",

View file

@ -1,11 +1,10 @@
import { z } from "@hono/zod-openapi";
import type { Status as ApiNote } from "@versia/client/types";
import { zBoolean } from "~/packages/config-manager/config.type.ts";
import { config } from "~/packages/config-manager/index.ts";
import { config } from "~/config.ts";
import { Account } from "./account.ts";
import { Attachment } from "./attachment.ts";
import { PreviewCard } from "./card.ts";
import { Id, iso631 } from "./common.ts";
import { Id, iso631, zBoolean } from "./common.ts";
import { CustomEmoji } from "./emoji.ts";
import { FilterResult } from "./filters.ts";
import { Poll } from "./poll.ts";
@ -58,12 +57,12 @@ export const StatusSource = z
}),
text: z
.string()
.max(config.validation.max_note_size)
.max(config.validation.notes.max_characters)
.trim()
.refine(
(s) =>
!config.filters.note_content.some((filter) =>
s.match(filter),
!config.validation.filters.note_content.some((filter) =>
filter.test(s),
),
"Status contains blocked words",
)

View file

@ -1,6 +1,6 @@
import { z } from "@hono/zod-openapi";
import { RolePermission } from "@versia/client/types";
import { config } from "~/packages/config-manager/index.ts";
import { config } from "~/config.ts";
import { Id } from "./common.ts";
/* Versia Server API extension */
@ -56,7 +56,7 @@ export const NoteReaction = z
name: z
.string()
.min(1)
.max(config.validation.max_emoji_shortcode_size)
.max(config.validation.emojis.max_shortcode_characters)
.trim()
.openapi({
description: "Custom Emoji shortcode or Unicode emoji.",