diff --git a/.config/example.yml b/.config/example.yml index 3f0ce40311..8e881c1879 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -79,8 +79,8 @@ redis: # host: localhost # port: 9200 # ssl: false -# user: -# pass: +# user: +# pass: # ┌───────────────┐ #───┘ ID generation └─────────────────────────────────────────── @@ -109,6 +109,19 @@ id: 'aid' # Maximum lenght of an image caption or file comment (default 1500, max 8192) #maxCaptionLength: 1500 +# Reserved usernames that only the administrator can register with +reservedUsernames: + - root + - admin + - system + - test + - proxy + - relay + - mod + - moderator + - info + - information + # Whether disable HSTS #disableHsts: true @@ -211,4 +224,4 @@ id: 'aid' # !!!!!!!!!! # Seriously. Do NOT fill out the above settings if you're self-hosting. -# They're much better off being set from the control panel. +# They're much better off being set from the control panel. diff --git a/packages/backend/src/config/types.ts b/packages/backend/src/config/types.ts index a7cdc89cf2..4f367debe0 100644 --- a/packages/backend/src/config/types.ts +++ b/packages/backend/src/config/types.ts @@ -77,6 +77,8 @@ export type Source = { sha256CertFingerprints?: string[]; }; + reservedUsernames?: string[]; + // Managed hosting stuff maxUserSignups?: number; isManagedHosting?: boolean; diff --git a/packages/backend/src/server/api/endpoints/username/available.ts b/packages/backend/src/server/api/endpoints/username/available.ts index f5aa4ed1ea..6fa09ba369 100644 --- a/packages/backend/src/server/api/endpoints/username/available.ts +++ b/packages/backend/src/server/api/endpoints/username/available.ts @@ -1,5 +1,6 @@ import { IsNull } from "typeorm"; import { Users, UsedUsernames } from "@/models/index.js"; +import config from "@/config/index.js"; import define from "../../define.js"; export const meta = { @@ -40,7 +41,11 @@ export default define(meta, paramDef, async (ps) => { username: ps.username.toLowerCase(), }); + const reserved = config.reservedUsernames?.includes( + ps.username.toLowerCase(), + ); + return { - available: exist === 0 && exist2 === 0, + available: exist === 0 && exist2 === 0 && !reserved, }; }); diff --git a/packages/backend/src/server/api/private/signup.ts b/packages/backend/src/server/api/private/signup.ts index 754d86c3b8..d24a74c12a 100644 --- a/packages/backend/src/server/api/private/signup.ts +++ b/packages/backend/src/server/api/private/signup.ts @@ -44,6 +44,11 @@ export default async (ctx: Koa.Context) => { const invitationCode = body["invitationCode"]; const emailAddress = body["emailAddress"]; + if (config.reservedUsernames?.includes(username.toLowerCase())) { + ctx.status = 400; + return; + } + if (instance.emailRequiredForSignup) { if (emailAddress == null || typeof emailAddress !== "string") { ctx.status = 400; diff --git a/packages/client/src/components/MkInstanceTicker.vue b/packages/client/src/components/MkInstanceTicker.vue index 3558b53d8c..6deb428f0d 100644 --- a/packages/client/src/components/MkInstanceTicker.vue +++ b/packages/client/src/components/MkInstanceTicker.vue @@ -35,7 +35,7 @@ const instance = props.instance ?? { 'meta[name="theme-color-orig"]' ) as HTMLMetaElement )?.content, - software: Instance.softwareName || "Calckey", + softwareName: Instance.softwareName || "Calckey", }; const capitalize = (s: string) => s && s[0].toUpperCase() + s.slice(1); diff --git a/packages/client/src/components/MkSubNoteContent.vue b/packages/client/src/components/MkSubNoteContent.vue index 132c4966d5..a345b23f54 100644 --- a/packages/client/src/components/MkSubNoteContent.vue +++ b/packages/client/src/components/MkSubNoteContent.vue @@ -251,14 +251,18 @@ let showContent = $ref(false); min-height: 2em; max-height: 5em; filter: blur(4px); + :deep(span) { + animation: none !important; + transform: none !important; + } + :deep(img) { + filter: blur(12px); + } } :deep(.fade) { inset: 0; top: 40px; } - :deep(span) { - animation: none !important; - } } :deep(.fade) { diff --git a/packages/client/src/style.scss b/packages/client/src/style.scss index c1a1820bcb..051edf6e0f 100644 --- a/packages/client/src/style.scss +++ b/packages/client/src/style.scss @@ -12,6 +12,24 @@ --margin: var(--marginHalf); } + // https://larsenwork.com/easing-gradients/ + --gradient: hsl(0, 0%, 0%) 0%, + hsla(0, 0%, 0%, 0.987) 8.1%, + hsla(0, 0%, 0%, 0.951) 15.5%, + hsla(0, 0%, 0%, 0.896) 22.5%, + hsla(0, 0%, 0%, 0.825) 29%, + hsla(0, 0%, 0%, 0.741) 35.3%, + hsla(0, 0%, 0%, 0.648) 41.2%, + hsla(0, 0%, 0%, 0.55) 47.1%, + hsla(0, 0%, 0%, 0.45) 52.9%, + hsla(0, 0%, 0%, 0.352) 58.8%, + hsla(0, 0%, 0%, 0.259) 64.7%, + hsla(0, 0%, 0%, 0.175) 71%, + hsla(0, 0%, 0%, 0.104) 77.5%, + hsla(0, 0%, 0%, 0.049) 84.5%, + hsla(0, 0%, 0%, 0.013) 91.9%, + hsla(0, 0%, 0%, 0) 100%; + //--ad: rgb(255 169 0 / 10%); } @@ -36,32 +54,6 @@ html { text-size-adjust: 100%; tab-size: 2; - &, * { - scrollbar-color: var(--scrollbarHandle) inherit; - scrollbar-width: thin; - - &::-webkit-scrollbar { - width: 6px; - height: 6px; - } - - &::-webkit-scrollbar-track { - background: inherit; - } - - &::-webkit-scrollbar-thumb { - background: var(--scrollbarHandle); - - &:hover { - background: var(--scrollbarHandleHover); - } - - &:active { - background: var(--accent); - } - } - } - &.f-1 { font-size: 15px; } @@ -78,6 +70,37 @@ html { font-family: sans-serif; } } +body::-webkit-scrollbar { + width: 12px; + height: 12px; + +} +body::-webkit-scrollbar-thumb { + border-radius: 100px; + background-clip: content-box; + border: 3px solid transparent; +} +::-webkit-scrollbar { + width: 6px; + height: 6px; +} +::-webkit-scrollbar-track { + background: inherit; +} +::-webkit-scrollbar-thumb { + background: var(--scrollbarHandle); + min-height: 80px; + + &:hover { + background: var(--scrollbarHandleHover); + background-clip: content-box; + } + + &:active { + background: var(--accent); + background-clip: content-box; + } +} html._themeChanging_ { &, * { diff --git a/packages/client/src/ui/_common_/navbar.vue b/packages/client/src/ui/_common_/navbar.vue index 023b4d4933..380f77c3c4 100644 --- a/packages/client/src/ui/_common_/navbar.vue +++ b/packages/client/src/ui/_common_/navbar.vue @@ -278,16 +278,8 @@ function more(ev: MouseEvent) { height: 100%; background-size: cover; background-position: center center; - -webkit-mask-image: linear-gradient( - 0deg, - rgba(0, 0, 0, 0) 15%, - rgba(0, 0, 0, 0.75) 100% - ); - mask-image: linear-gradient( - 0deg, - rgba(0, 0, 0, 0) 15%, - rgba(0, 0, 0, 0.75) 100% - ); + -webkit-mask-image: linear-gradient(var(--gradient)); + mask-image: linear-gradient(var(--gradient)); } > .account {