From 9f5b0c3ca10432fd94d3afa76fa4dc5ea786f104 Mon Sep 17 00:00:00 2001 From: mattyatea Date: Wed, 17 Jul 2024 21:24:04 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20=E3=83=9E=E3=83=8D=E3=83=BC=E3=82=B8?= =?UTF-8?q?=E3=83=89=E3=81=AA=E3=82=B5=E3=83=BC=E3=83=93=E3=82=B9=E3=81=A7?= =?UTF-8?q?=E4=BD=BF=E3=81=88=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit オブジェクトストレージの設定を秘匿するように Config で設定できます。 その他バグ修正 --- .config/example.yml | 18 + locales/index.d.ts | 4 + locales/ja-JP.yml | 2 +- package.json | 4 +- packages/backend/src/boot/entry.ts | 4 +- packages/backend/src/boot/master.ts | 29 +- packages/backend/src/config.ts | 37 +- packages/backend/src/core/S3Service.ts | 75 +++- packages/backend/src/core/SignupService.ts | 8 +- packages/backend/src/env.ts | 1 + packages/backend/src/models/Meta.ts | 4 +- .../src/server/NodeinfoServerService.ts | 2 +- .../src/server/api/endpoints/admin/meta.ts | 378 ++++++++++++------ .../server/api/endpoints/admin/update-meta.ts | 183 ++++----- .../backend/src/server/api/endpoints/i.ts | 10 +- packages/frontend/src/components/MkMenu.vue | 158 +++----- packages/frontend/src/pages/about-type4ny.vue | 2 +- .../frontend/src/pages/about.overview.vue | 9 +- .../frontend/src/pages/admin/moderation.vue | 9 +- .../src/pages/admin/object-storage.vue | 9 +- .../src/pages/admin/other-settings.vue | 9 +- .../frontend/src/pages/admin/settings.vue | 20 +- .../src/scripts/get-timeline-available.ts | 6 +- packages/frontend/src/ui/visitor.vue | 2 +- packages/sw/src/sw.ts | 2 +- 25 files changed, 599 insertions(+), 386 deletions(-) diff --git a/.config/example.yml b/.config/example.yml index ff83777ca3..fe110bdf85 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -186,6 +186,24 @@ redis: # index: '' # scope: local +# ┌─────────────────────────────┐ +#───┘ ObjectStorage configuration └───────────────────────────── + +#objectStorage: +# useObjectStorage: true +# objectStorageBaseUrl: 'https://' +# objectStorageBucket: '' +# objectStoragePrefix: '' +# objectStorageEndpoint: '' # Please enter the following format: s3.example.com +# objectStorageRegion: '' +# objectStoragePort: 443 +# objectStorageAccessKey: '' +# objectStorageSecretKey: '' +# objectStorageUseSSL: true +# objectStorageUseProxy: false +# objectStorageSetPublicRead: true +# objectStorageS3ForcePathStyle: true + # ┌───────────────┐ #───┘ ID generation └─────────────────────────────────────────── diff --git a/locales/index.d.ts b/locales/index.d.ts index 31051acd42..d585601d18 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -60,6 +60,10 @@ export interface Locale extends ILocale { * OK */ "ok": string; + /** + * マネージドインスタンスではこの設定は変更することができません。 + */ + "managedInstanceIsNotEditable": string; /** * ノートの投稿フォームを開き直した際に、下書きを復元しないようにします。 */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 804770f7f6..1d01807d7b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -11,7 +11,7 @@ password: "パスワード" forgotPassword: "パスワードを忘れた" fetchingAsApObject: "連合に照会中" ok: "OK" - +managedInstanceIsNotEditable: "マネージドインスタンスではこの設定は変更することができません。" disableNoteDraftingDescription: "ノートの投稿フォームを開き直した際に、下書きを復元しないようにします。" setDefaultProfileConfirm: "このプロファイルをデフォルトにしますか?" emojiPickerProfile: "絵文字ピッカーのプロファイル" diff --git a/package.json b/package.json index 139479371e..89fd0a01d2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "type4ny", - "version": "2024.5.0-mattyatea4", - "codename": "nasubi", + "version": "0.1.0-beta", + "codename": "apollo-11", "repository": { "type": "git", "url": "https://github.com/type4ny-project/type4ny.git" diff --git a/packages/backend/src/boot/entry.ts b/packages/backend/src/boot/entry.ts index 6f3407632c..d156ed353d 100644 --- a/packages/backend/src/boot/entry.ts +++ b/packages/backend/src/boot/entry.ts @@ -4,7 +4,7 @@ */ /** - * Misskey Entry Point! + * Type4ny Entry Point! */ import cluster from 'node:cluster'; @@ -19,7 +19,7 @@ import { readyRef } from './ready.js'; import 'reflect-metadata'; -process.title = `Misskey (${cluster.isPrimary ? 'master' : 'worker'})`; +process.title = `Type4ny (${cluster.isPrimary ? 'master' : 'worker'})`; Error.stackTraceLimit = Infinity; EventEmitter.defaultMaxListeners = 128; diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index 6f06d454e3..b7c8d9387a 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -27,28 +27,29 @@ const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json const logger = new Logger('core', 'cyan'); const bootLogger = logger.createSubLogger('boot', 'magenta'); -const themeColor = chalk.hex('#86b300'); +const themeColor = chalk.hex('#00a968'); function greet() { if (!envOption.quiet) { - //#region Misskey logo + //#region Type4ny logo const v = `v${meta.version}`; - console.log(themeColor(' _____ _ _ ')); - console.log(themeColor(' | |_|___ ___| |_ ___ _ _ ')); - console.log(themeColor(' | | | | |_ -|_ -| \'_| -_| | |')); - console.log(themeColor(' |_|_|_|_|___|___|_,_|___|_ |')); - console.log(' ' + chalk.gray(v) + themeColor(' |___|\n'.substring(v.length))); + console.log(themeColor(' _____ _ _ ')); + console.log(themeColor('|_ _| _ _ __ ___| | | _ _ _ _ ')); + console.log(themeColor(' | || || | \'_ \\/ -_)_ _| \' \\ || |')); + console.log(themeColor(' |_| \\_, | .__/\\___| |_||_||_\\_, |')); + console.log(themeColor(' |__/|_| |__/ ')); + console.log(chalk.gray(v)); //#endregion - console.log(' Misskey is an open-source decentralized microblogging platform.'); - console.log(chalk.rgb(255, 136, 0)(' If you like Misskey, please donate to support development. https://www.patreon.com/syuilo')); + console.log(' Type4ny is an open-source decentralized microblogging platform.'); + console.log(chalk.rgb(255, 136, 0)(' If you like Type4ny, please donate to support development. https://mattyatea.fanbox.cc')); console.log(''); console.log(chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`); } - bootLogger.info('Welcome to Misskey!'); - bootLogger.info(`Misskey v${meta.version}`, null, true); + bootLogger.info('Welcome to Type4ny!'); + bootLogger.info(`Type4ny v${meta.version}`, null, true); } /** @@ -71,7 +72,7 @@ export async function masterMain() { process.exit(1); } - bootLogger.succ('Misskey initialized'); + bootLogger.succ('Type4ny initialized'); if (config.sentryForBackend) { Sentry.init({ @@ -121,6 +122,7 @@ export async function masterMain() { function showEnvironment(): void { const env = process.env.NODE_ENV; + const managed = process.env.IS_MANAGED === 'true'; const logger = bootLogger.createSubLogger('env'); logger.info(typeof env === 'undefined' ? 'NODE_ENV is not set' : `NODE_ENV: ${env}`); @@ -128,6 +130,9 @@ function showEnvironment(): void { logger.warn('The environment is not in production mode.'); logger.warn('DO NOT USE FOR PRODUCTION PURPOSE!', null, true); } + if (managed) { + logger.info('Type4ny is running in a managed mode.'); + } } function showNodejsVersion(): void { diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index 95599bdde7..7e10dd435c 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -62,6 +62,22 @@ type Source = { publishTarballInsteadOfProvideRepositoryUrl?: boolean; + objectStorage?: { + useObjectStorage: boolean; + objectStorageBaseUrl: string; + objectStorageBucket: string; + objectStoragePrefix: string; + objectStorageEndpoint: string; + objectStorageRegion: string; + objectStoragePort?: number; + objectStorageAccessKey: string; + objectStorageSecretKey: string; + objectStorageUseSSL?: boolean; + objectStorageUseProxy?: boolean; + objectStorageSetPublicRead?: boolean; + objectStorageS3ForcePathStyle?: boolean; + }; + proxy?: string; proxySmtp?: string; proxyBypassHosts?: string[]; @@ -95,6 +111,7 @@ type Source = { perChannelMaxNoteCacheCount?: number; perUserNotificationsMaxCount?: number; deactivateAntennaThreshold?: number; + maxLocalUsers?: number; pidFile: string; }; @@ -174,6 +191,22 @@ export type Config = { perChannelMaxNoteCacheCount: number; perUserNotificationsMaxCount: number; deactivateAntennaThreshold: number; + maxLocalUsers: number; + objectStorage?: { + useObjectStorage?: boolean; + objectStorageBaseUrl?: string; + objectStorageBucket?: string; + objectStoragePrefix?: string; + objectStorageEndpoint?: string; + objectStorageRegion?: string; + objectStoragePort?: number; + objectStorageAccessKey?: string; + objectStorageSecretKey?: string; + objectStorageUseSSL?: boolean; + objectStorageUseProxy?: boolean; + objectStorageSetPublicRead?: boolean; + objectStorageS3ForcePathStyle?: boolean; + }; pidFile: string; }; @@ -269,12 +302,14 @@ export function loadConfig(): Config { videoThumbnailGenerator: config.videoThumbnailGenerator ? config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator : null, - userAgent: `Misskey/${version} (${config.url})`, + userAgent: `Type4ny/${version} (${config.url})`, clientEntry: clientManifest['src/_boot_.ts'], clientManifestExists: clientManifestExists, perChannelMaxNoteCacheCount: config.perChannelMaxNoteCacheCount ?? 1000, perUserNotificationsMaxCount: config.perUserNotificationsMaxCount ?? 500, deactivateAntennaThreshold: config.deactivateAntennaThreshold ?? (1000 * 60 * 60 * 24 * 7), + maxLocalUsers: config.maxLocalUsers ?? -1, + objectStorage: config.objectStorage ?? {}, pidFile: config.pidFile, }; } diff --git a/packages/backend/src/core/S3Service.ts b/packages/backend/src/core/S3Service.ts index c5b51ce700..7161562381 100644 --- a/packages/backend/src/core/S3Service.ts +++ b/packages/backend/src/core/S3Service.ts @@ -6,47 +6,79 @@ import { URL } from 'node:url'; import * as http from 'node:http'; import * as https from 'node:https'; -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3'; import { Upload } from '@aws-sdk/lib-storage'; import { NodeHttpHandler, NodeHttpHandlerOptions } from '@smithy/node-http-handler'; import type { MiMeta } from '@/models/Meta.js'; import { HttpRequestService } from '@/core/HttpRequestService.js'; import { bindThis } from '@/decorators.js'; +import { DI } from '@/di-symbols.js'; +import type { Config } from '@/config.js'; +import { envOption } from '@/env.js'; import type { DeleteObjectCommandInput, PutObjectCommandInput } from '@aws-sdk/client-s3'; @Injectable() export class S3Service { constructor( private httpRequestService: HttpRequestService, + @Inject(DI.config) + private config: Config, ) { } @bindThis public getS3Client(meta: MiMeta): S3Client { - const u = meta.objectStorageEndpoint - ? `${meta.objectStorageUseSSL ? 'https' : 'http'}://${meta.objectStorageEndpoint}` - : `${meta.objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent + if (envOption.managed){ + const objectStorageConfig = this.config.objectStorage; + const u = objectStorageConfig?.objectStorageEndpoint + ? `${objectStorageConfig.objectStorageUseSSL ? 'https' : 'http'}://${objectStorageConfig.objectStorageEndpoint}` + : `${objectStorageConfig?.objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent - const agent = this.httpRequestService.getAgentByUrl(new URL(u), !meta.objectStorageUseProxy); - const handlerOption: NodeHttpHandlerOptions = {}; - if (meta.objectStorageUseSSL) { - handlerOption.httpsAgent = agent as https.Agent; + const agent = this.httpRequestService.getAgentByUrl(new URL(u), !objectStorageConfig?.objectStorageUseProxy); + const handlerOption: NodeHttpHandlerOptions = {}; + if (meta.objectStorageUseSSL) { + handlerOption.httpsAgent = agent as https.Agent; + } else { + handlerOption.httpAgent = agent as http.Agent; + } + + return new S3Client({ + endpoint: objectStorageConfig?.objectStorageEndpoint ? u : undefined, + credentials: (objectStorageConfig?.objectStorageAccessKey && objectStorageConfig?.objectStorageSecretKey ) ? { + accessKeyId: objectStorageConfig.objectStorageAccessKey, + secretAccessKey: objectStorageConfig.objectStorageSecretKey, + } : undefined, + region: objectStorageConfig?.objectStorageRegion ? objectStorageConfig.objectStorageRegion : undefined, // 空文字列もundefinedにするため ?? は使わない + tls: objectStorageConfig?.objectStorageUseSSL ?? false, + forcePathStyle: objectStorageConfig?.objectStorageEndpoint ? objectStorageConfig?.objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted + requestHandler: new NodeHttpHandler(handlerOption), + }); } else { - handlerOption.httpAgent = agent as http.Agent; - } + const u = meta.objectStorageEndpoint + ? `${meta.objectStorageUseSSL ? 'https' : 'http'}://${meta.objectStorageEndpoint}` + : `${meta.objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent - return new S3Client({ - endpoint: meta.objectStorageEndpoint ? u : undefined, - credentials: (meta.objectStorageAccessKey !== null && meta.objectStorageSecretKey !== null) ? { - accessKeyId: meta.objectStorageAccessKey, - secretAccessKey: meta.objectStorageSecretKey, - } : undefined, - region: meta.objectStorageRegion ? meta.objectStorageRegion : undefined, // 空文字列もundefinedにするため ?? は使わない - tls: meta.objectStorageUseSSL, - forcePathStyle: meta.objectStorageEndpoint ? meta.objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted - requestHandler: new NodeHttpHandler(handlerOption), - }); + const agent = this.httpRequestService.getAgentByUrl(new URL(u), !meta.objectStorageUseProxy); + const handlerOption: NodeHttpHandlerOptions = {}; + if (meta.objectStorageUseSSL) { + handlerOption.httpsAgent = agent as https.Agent; + } else { + handlerOption.httpAgent = agent as http.Agent; + } + + return new S3Client({ + endpoint: meta.objectStorageEndpoint ? u : undefined, + credentials: (meta.objectStorageAccessKey !== null && meta.objectStorageSecretKey !== null) ? { + accessKeyId: meta.objectStorageAccessKey, + secretAccessKey: meta.objectStorageSecretKey, + } : undefined, + region: meta.objectStorageRegion ? meta.objectStorageRegion : undefined, // 空文字列もundefinedにするため ?? は使わない + tls: meta.objectStorageUseSSL, + forcePathStyle: meta.objectStorageEndpoint ? meta.objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted + requestHandler: new NodeHttpHandler(handlerOption), + }); + } } @bindThis @@ -67,3 +99,4 @@ export class S3Service { return client.send(new DeleteObjectCommand(input)); } } + diff --git a/packages/backend/src/core/SignupService.ts b/packages/backend/src/core/SignupService.ts index 6df9d0fcc8..0454b7258e 100644 --- a/packages/backend/src/core/SignupService.ts +++ b/packages/backend/src/core/SignupService.ts @@ -21,6 +21,7 @@ import { bindThis } from '@/decorators.js'; import UsersChart from '@/core/chart/charts/users.js'; import { UtilityService } from '@/core/UtilityService.js'; import { MetaService } from '@/core/MetaService.js'; +import type { Config } from '@/config.js'; @Injectable() export class SignupService { @@ -34,6 +35,9 @@ export class SignupService { @Inject(DI.usedUsernamesRepository) private usedUsernamesRepository: UsedUsernamesRepository, + @Inject(DI.config) + private config: Config, + private utilityService: UtilityService, private userEntityService: UserEntityService, private idService: IdService, @@ -58,7 +62,9 @@ export class SignupService { if (!this.userEntityService.validateLocalUsername(username)) { throw new Error('INVALID_USERNAME'); } - + if (this.config.maxLocalUsers !== -1 && await this.usersRepository.count({ where: { host: IsNull() } }) >= this.config.maxLocalUsers) { + throw new Error('MAX_LOCAL_USERS'); + } if (password != null && passwordHash == null) { // Validate password if (!this.userEntityService.validatePassword(password)) { diff --git a/packages/backend/src/env.ts b/packages/backend/src/env.ts index 2f1817bd77..4441bc8aff 100644 --- a/packages/backend/src/env.ts +++ b/packages/backend/src/env.ts @@ -11,6 +11,7 @@ const envOption = { verbose: false, withLogTime: false, quiet: false, + managed: true, }; for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) { diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index 10fabf9a46..d39cfba585 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -379,14 +379,14 @@ export class MiMeta { @Column('varchar', { length: 1024, - default: 'https://github.com/misskey-dev/misskey', + default: 'https://github.com/type4ny-project/type4ny', nullable: true, }) public repositoryUrl: string | null; @Column('varchar', { length: 1024, - default: 'https://github.com/misskey-dev/misskey/issues/new', + default: 'https://github.com/type4ny-project/type4ny/issues/new', nullable: true, }) public feedbackUrl: string | null; diff --git a/packages/backend/src/server/NodeinfoServerService.ts b/packages/backend/src/server/NodeinfoServerService.ts index 731b9c9820..959654ef79 100644 --- a/packages/backend/src/server/NodeinfoServerService.ts +++ b/packages/backend/src/server/NodeinfoServerService.ts @@ -124,7 +124,7 @@ export class NodeinfoServerService { enableEmail: meta.enableEmail, enableServiceWorker: meta.enableServiceWorker, proxyAccountName: proxyAccount ? proxyAccount.username : null, - themeColor: meta.themeColor ?? '#86b300', + themeColor: meta.themeColor ?? '#00a968', }, }; if (version >= 21) { diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 66ee9572f7..66cccdfd24 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -9,6 +9,7 @@ import { MetaService } from '@/core/MetaService.js'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; +import {envOption} from "@/env.js"; export const meta = { tags: ['meta'], @@ -525,131 +526,260 @@ export default class extends Endpoint { // eslint- ) { super(meta, paramDef, async () => { const instance = await this.metaService.fetch(true); + if (!envOption.managed) { + return { + maintainerName: instance.maintainerName, + maintainerEmail: instance.maintainerEmail, + version: this.config.version, + name: instance.name, + shortName: instance.shortName, + uri: this.config.url, + description: instance.description, + langs: instance.langs, + tosUrl: instance.termsOfServiceUrl, + repositoryUrl: instance.repositoryUrl, + feedbackUrl: instance.feedbackUrl, + impressumUrl: instance.impressumUrl, + privacyPolicyUrl: instance.privacyPolicyUrl, + inquiryUrl: instance.inquiryUrl, + disableRegistration: instance.disableRegistration, + emailRequiredForSignup: instance.emailRequiredForSignup, + enableHcaptcha: instance.enableHcaptcha, + hcaptchaSiteKey: instance.hcaptchaSiteKey, + enableMcaptcha: instance.enableMcaptcha, + mcaptchaSiteKey: instance.mcaptchaSitekey, + mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl, + enableRecaptcha: instance.enableRecaptcha, + recaptchaSiteKey: instance.recaptchaSiteKey, + enableTurnstile: instance.enableTurnstile, + turnstileSiteKey: instance.turnstileSiteKey, + swPublickey: instance.swPublicKey, + themeColor: instance.themeColor, + requestEmojiAllOk: instance.requestEmojiAllOk, + mascotImageUrl: instance.mascotImageUrl, + bannerUrl: instance.bannerUrl, + serverErrorImageUrl: instance.serverErrorImageUrl, + notFoundImageUrl: instance.notFoundImageUrl, + infoImageUrl: instance.infoImageUrl, + iconUrl: instance.iconUrl, + app192IconUrl: instance.app192IconUrl, + app512IconUrl: instance.app512IconUrl, + backgroundImageUrl: instance.backgroundImageUrl, + logoImageUrl: instance.logoImageUrl, + defaultLightTheme: instance.defaultLightTheme, + defaultDarkTheme: instance.defaultDarkTheme, + enableEmail: instance.enableEmail, + enableServiceWorker: instance.enableServiceWorker, + translatorAvailable: instance.deeplAuthKey != null, + cacheRemoteFiles: instance.cacheRemoteFiles, + cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles, + pinnedUsers: instance.pinnedUsers, + hiddenTags: instance.hiddenTags, + blockedHosts: instance.blockedHosts, + silencedHosts: instance.silencedHosts, + sensitiveWords: instance.sensitiveWords, + prohibitedWords: instance.prohibitedWords, + preservedUsernames: instance.preservedUsernames, + hcaptchaSecretKey: instance.hcaptchaSecretKey, + mcaptchaSecretKey: instance.mcaptchaSecretKey, + recaptchaSecretKey: instance.recaptchaSecretKey, + turnstileSecretKey: instance.turnstileSecretKey, + sensitiveMediaDetection: instance.sensitiveMediaDetection, + sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity, + setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically, + enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos, + proxyAccountId: instance.proxyAccountId, + email: instance.email, + smtpSecure: instance.smtpSecure, + smtpHost: instance.smtpHost, + smtpPort: instance.smtpPort, + smtpUser: instance.smtpUser, + smtpPass: instance.smtpPass, + swPrivateKey: instance.swPrivateKey, + useObjectStorage: instance.useObjectStorage, + objectStorageBaseUrl: instance.objectStorageBaseUrl, + objectStorageBucket: instance.objectStorageBucket, + objectStoragePrefix: instance.objectStoragePrefix, + objectStorageEndpoint: instance.objectStorageEndpoint, + objectStorageRegion: instance.objectStorageRegion, + objectStoragePort: instance.objectStoragePort, + objectStorageAccessKey: instance.objectStorageAccessKey, + objectStorageSecretKey: instance.objectStorageSecretKey, + objectStorageUseSSL: instance.objectStorageUseSSL, + objectStorageUseProxy: instance.objectStorageUseProxy, + objectStorageSetPublicRead: instance.objectStorageSetPublicRead, + objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle, + deeplAuthKey: instance.deeplAuthKey, + deeplIsPro: instance.deeplIsPro, + enableIpLogging: instance.enableIpLogging, + enableActiveEmailValidation: instance.enableActiveEmailValidation, + enableVerifymailApi: instance.enableVerifymailApi, + verifymailAuthKey: instance.verifymailAuthKey, + enableTruemailApi: instance.enableTruemailApi, + truemailInstance: instance.truemailInstance, + truemailAuthKey: instance.truemailAuthKey, + enableChartsForRemoteUser: instance.enableChartsForRemoteUser, + enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances, + enableServerMachineStats: instance.enableServerMachineStats, + enableIdenticonGeneration: instance.enableIdenticonGeneration, + bannedEmailDomains: instance.bannedEmailDomains, + policies: { ...DEFAULT_POLICIES, ...instance.policies }, + manifestJsonOverride: instance.manifestJsonOverride, + enableFanoutTimeline: instance.enableFanoutTimeline, + enableFanoutTimelineDbFallback: instance.enableFanoutTimelineDbFallback, + perLocalUserUserTimelineCacheMax: instance.perLocalUserUserTimelineCacheMax, + perRemoteUserUserTimelineCacheMax: instance.perRemoteUserUserTimelineCacheMax, + perUserHomeTimelineCacheMax: instance.perUserHomeTimelineCacheMax, + perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax, + notesPerOneAd: instance.notesPerOneAd, + DiscordWebhookUrl: instance.DiscordWebhookUrl, + DiscordWebhookUrlWordBlock: instance.DiscordWebhookUrlWordBlock, + EmojiBotToken: instance.EmojiBotToken, + ApiBase: instance.ApiBase, + enableGDPRMode: instance.enableGDPRMode, + enableProxyCheckio: instance.enableProxyCheckio, + proxyCheckioApiKey: instance.proxyCheckioApiKey, + summalyProxy: instance.urlPreviewSummaryProxyUrl, + urlPreviewEnabled: instance.urlPreviewEnabled, + urlPreviewTimeout: instance.urlPreviewTimeout, + urlPreviewMaximumContentLength: instance.urlPreviewMaximumContentLength, + urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength, + urlPreviewUserAgent: instance.urlPreviewUserAgent, + urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl, + iconLight: instance.iconLight, + iconDark: instance.iconDark, + bannerLight: instance.bannerLight, + bannerDark: instance.bannerDark, + isManaged: false, - return { - maintainerName: instance.maintainerName, - maintainerEmail: instance.maintainerEmail, - version: this.config.version, - name: instance.name, - shortName: instance.shortName, - uri: this.config.url, - description: instance.description, - langs: instance.langs, - tosUrl: instance.termsOfServiceUrl, - repositoryUrl: instance.repositoryUrl, - feedbackUrl: instance.feedbackUrl, - impressumUrl: instance.impressumUrl, - privacyPolicyUrl: instance.privacyPolicyUrl, - inquiryUrl: instance.inquiryUrl, - disableRegistration: instance.disableRegistration, - emailRequiredForSignup: instance.emailRequiredForSignup, - enableHcaptcha: instance.enableHcaptcha, - hcaptchaSiteKey: instance.hcaptchaSiteKey, - enableMcaptcha: instance.enableMcaptcha, - mcaptchaSiteKey: instance.mcaptchaSitekey, - mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl, - enableRecaptcha: instance.enableRecaptcha, - recaptchaSiteKey: instance.recaptchaSiteKey, - enableTurnstile: instance.enableTurnstile, - turnstileSiteKey: instance.turnstileSiteKey, - swPublickey: instance.swPublicKey, - themeColor: instance.themeColor, - requestEmojiAllOk: instance.requestEmojiAllOk, - mascotImageUrl: instance.mascotImageUrl, - bannerUrl: instance.bannerUrl, - serverErrorImageUrl: instance.serverErrorImageUrl, - notFoundImageUrl: instance.notFoundImageUrl, - infoImageUrl: instance.infoImageUrl, - iconUrl: instance.iconUrl, - app192IconUrl: instance.app192IconUrl, - app512IconUrl: instance.app512IconUrl, - backgroundImageUrl: instance.backgroundImageUrl, - logoImageUrl: instance.logoImageUrl, - defaultLightTheme: instance.defaultLightTheme, - defaultDarkTheme: instance.defaultDarkTheme, - enableEmail: instance.enableEmail, - enableServiceWorker: instance.enableServiceWorker, - translatorAvailable: instance.deeplAuthKey != null, - cacheRemoteFiles: instance.cacheRemoteFiles, - cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles, - pinnedUsers: instance.pinnedUsers, - hiddenTags: instance.hiddenTags, - blockedHosts: instance.blockedHosts, - silencedHosts: instance.silencedHosts, - sensitiveWords: instance.sensitiveWords, - prohibitedWords: instance.prohibitedWords, - preservedUsernames: instance.preservedUsernames, - hcaptchaSecretKey: instance.hcaptchaSecretKey, - mcaptchaSecretKey: instance.mcaptchaSecretKey, - recaptchaSecretKey: instance.recaptchaSecretKey, - turnstileSecretKey: instance.turnstileSecretKey, - sensitiveMediaDetection: instance.sensitiveMediaDetection, - sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity, - setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically, - enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos, - proxyAccountId: instance.proxyAccountId, - email: instance.email, - smtpSecure: instance.smtpSecure, - smtpHost: instance.smtpHost, - smtpPort: instance.smtpPort, - smtpUser: instance.smtpUser, - smtpPass: instance.smtpPass, - swPrivateKey: instance.swPrivateKey, - useObjectStorage: instance.useObjectStorage, - objectStorageBaseUrl: instance.objectStorageBaseUrl, - objectStorageBucket: instance.objectStorageBucket, - objectStoragePrefix: instance.objectStoragePrefix, - objectStorageEndpoint: instance.objectStorageEndpoint, - objectStorageRegion: instance.objectStorageRegion, - objectStoragePort: instance.objectStoragePort, - objectStorageAccessKey: instance.objectStorageAccessKey, - objectStorageSecretKey: instance.objectStorageSecretKey, - objectStorageUseSSL: instance.objectStorageUseSSL, - objectStorageUseProxy: instance.objectStorageUseProxy, - objectStorageSetPublicRead: instance.objectStorageSetPublicRead, - objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle, - deeplAuthKey: instance.deeplAuthKey, - deeplIsPro: instance.deeplIsPro, - enableIpLogging: instance.enableIpLogging, - enableActiveEmailValidation: instance.enableActiveEmailValidation, - enableVerifymailApi: instance.enableVerifymailApi, - verifymailAuthKey: instance.verifymailAuthKey, - enableTruemailApi: instance.enableTruemailApi, - truemailInstance: instance.truemailInstance, - truemailAuthKey: instance.truemailAuthKey, - enableChartsForRemoteUser: instance.enableChartsForRemoteUser, - enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances, - enableServerMachineStats: instance.enableServerMachineStats, - enableIdenticonGeneration: instance.enableIdenticonGeneration, - bannedEmailDomains: instance.bannedEmailDomains, - policies: { ...DEFAULT_POLICIES, ...instance.policies }, - manifestJsonOverride: instance.manifestJsonOverride, - enableFanoutTimeline: instance.enableFanoutTimeline, - enableFanoutTimelineDbFallback: instance.enableFanoutTimelineDbFallback, - perLocalUserUserTimelineCacheMax: instance.perLocalUserUserTimelineCacheMax, - perRemoteUserUserTimelineCacheMax: instance.perRemoteUserUserTimelineCacheMax, - perUserHomeTimelineCacheMax: instance.perUserHomeTimelineCacheMax, - perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax, - notesPerOneAd: instance.notesPerOneAd, - DiscordWebhookUrl: instance.DiscordWebhookUrl, - DiscordWebhookUrlWordBlock: instance.DiscordWebhookUrlWordBlock, - EmojiBotToken: instance.EmojiBotToken, - ApiBase: instance.ApiBase, - enableGDPRMode: instance.enableGDPRMode, - enableProxyCheckio: instance.enableProxyCheckio, - proxyCheckioApiKey: instance.proxyCheckioApiKey, - summalyProxy: instance.urlPreviewSummaryProxyUrl, - urlPreviewEnabled: instance.urlPreviewEnabled, - urlPreviewTimeout: instance.urlPreviewTimeout, - urlPreviewMaximumContentLength: instance.urlPreviewMaximumContentLength, - urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength, - urlPreviewUserAgent: instance.urlPreviewUserAgent, - urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl, - iconLight: instance.iconLight, - iconDark: instance.iconDark, - bannerLight: instance.bannerLight, - bannerDark: instance.bannerDark, - }; + }; + } else { + return { + maintainerName: instance.maintainerName, + maintainerEmail: instance.maintainerEmail, + version: this.config.version, + name: instance.name, + shortName: instance.shortName, + uri: this.config.url, + description: instance.description, + langs: instance.langs, + tosUrl: instance.termsOfServiceUrl, + repositoryUrl: instance.repositoryUrl, + feedbackUrl: instance.feedbackUrl, + impressumUrl: instance.impressumUrl, + privacyPolicyUrl: instance.privacyPolicyUrl, + inquiryUrl: instance.inquiryUrl, + disableRegistration: instance.disableRegistration, + emailRequiredForSignup: instance.emailRequiredForSignup, + enableHcaptcha: instance.enableHcaptcha, + hcaptchaSiteKey: instance.hcaptchaSiteKey, + enableMcaptcha: instance.enableMcaptcha, + mcaptchaSiteKey: instance.mcaptchaSitekey, + mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl, + enableRecaptcha: instance.enableRecaptcha, + recaptchaSiteKey: instance.recaptchaSiteKey, + enableTurnstile: instance.enableTurnstile, + turnstileSiteKey: instance.turnstileSiteKey, + swPublickey: instance.swPublicKey, + themeColor: instance.themeColor, + requestEmojiAllOk: instance.requestEmojiAllOk, + mascotImageUrl: instance.mascotImageUrl, + bannerUrl: instance.bannerUrl, + serverErrorImageUrl: instance.serverErrorImageUrl, + notFoundImageUrl: instance.notFoundImageUrl, + infoImageUrl: instance.infoImageUrl, + iconUrl: instance.iconUrl, + app192IconUrl: instance.app192IconUrl, + app512IconUrl: instance.app512IconUrl, + backgroundImageUrl: instance.backgroundImageUrl, + logoImageUrl: instance.logoImageUrl, + defaultLightTheme: instance.defaultLightTheme, + defaultDarkTheme: instance.defaultDarkTheme, + enableEmail: instance.enableEmail, + enableServiceWorker: instance.enableServiceWorker, + translatorAvailable: instance.deeplAuthKey != null, + cacheRemoteFiles: instance.cacheRemoteFiles, + cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles, + pinnedUsers: instance.pinnedUsers, + hiddenTags: instance.hiddenTags, + blockedHosts: instance.blockedHosts, + silencedHosts: instance.silencedHosts, + sensitiveWords: instance.sensitiveWords, + prohibitedWords: instance.prohibitedWords, + preservedUsernames: instance.preservedUsernames, + hcaptchaSecretKey: instance.hcaptchaSecretKey, + mcaptchaSecretKey: instance.mcaptchaSecretKey, + recaptchaSecretKey: instance.recaptchaSecretKey, + turnstileSecretKey: instance.turnstileSecretKey, + sensitiveMediaDetection: instance.sensitiveMediaDetection, + sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity, + setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically, + enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos, + proxyAccountId: instance.proxyAccountId, + email: instance.email, + smtpSecure: instance.smtpSecure, + smtpHost: instance.smtpHost, + smtpPort: instance.smtpPort, + smtpUser: instance.smtpUser, + smtpPass: instance.smtpPass, + swPrivateKey: instance.swPrivateKey, + useObjectStorage: true, + objectStorageBaseUrl: 'Masked', + objectStorageBucket: 'Masked', + objectStoragePrefix: 'Masked', + objectStorageEndpoint: 'Masked', + objectStorageRegion: 'Masked', + objectStoragePort: 0, + objectStorageAccessKey: 'Masked', + objectStorageSecretKey: 'Masked', + objectStorageUseSSL: false, + objectStorageUseProxy: false, + objectStorageSetPublicRead: false, + objectStorageS3ForcePathStyle: false, + deeplAuthKey: instance.deeplAuthKey, + deeplIsPro: instance.deeplIsPro, + enableIpLogging: instance.enableIpLogging, + enableActiveEmailValidation: instance.enableActiveEmailValidation, + enableVerifymailApi: instance.enableVerifymailApi, + verifymailAuthKey: instance.verifymailAuthKey, + enableTruemailApi: instance.enableTruemailApi, + truemailInstance: instance.truemailInstance, + truemailAuthKey: instance.truemailAuthKey, + enableChartsForRemoteUser: instance.enableChartsForRemoteUser, + enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances, + enableServerMachineStats: instance.enableServerMachineStats, + enableIdenticonGeneration: instance.enableIdenticonGeneration, + bannedEmailDomains: instance.bannedEmailDomains, + policies: { ...DEFAULT_POLICIES, ...instance.policies }, + manifestJsonOverride: instance.manifestJsonOverride, + enableFanoutTimeline: instance.enableFanoutTimeline, + enableFanoutTimelineDbFallback: instance.enableFanoutTimelineDbFallback, + perLocalUserUserTimelineCacheMax: instance.perLocalUserUserTimelineCacheMax, + perRemoteUserUserTimelineCacheMax: instance.perRemoteUserUserTimelineCacheMax, + perUserHomeTimelineCacheMax: instance.perUserHomeTimelineCacheMax, + perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax, + notesPerOneAd: instance.notesPerOneAd, + DiscordWebhookUrl: instance.DiscordWebhookUrl, + DiscordWebhookUrlWordBlock: instance.DiscordWebhookUrlWordBlock, + EmojiBotToken: instance.EmojiBotToken, + ApiBase: instance.ApiBase, + enableGDPRMode: instance.enableGDPRMode, + enableProxyCheckio: instance.enableProxyCheckio, + proxyCheckioApiKey: instance.proxyCheckioApiKey, + summalyProxy: instance.urlPreviewSummaryProxyUrl, + urlPreviewEnabled: instance.urlPreviewEnabled, + urlPreviewTimeout: instance.urlPreviewTimeout, + urlPreviewMaximumContentLength: instance.urlPreviewMaximumContentLength, + urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength, + urlPreviewUserAgent: instance.urlPreviewUserAgent, + urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl, + iconLight: instance.iconLight, + iconDark: instance.iconDark, + bannerLight: instance.bannerLight, + bannerDark: instance.bannerDark, + isManaged: true, + }; + } }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index d28ec641e8..4983bae8f3 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -8,6 +8,7 @@ import type { MiMeta } from '@/models/Meta.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { MetaService } from '@/core/MetaService.js'; +import { envOption } from '@/env.js'; export const meta = { tags: ['admin'], @@ -91,7 +92,6 @@ export const paramDef = { type: 'string', }, }, - summalyProxy: { type: 'string', nullable: true }, DiscordWebhookUrl: { type: 'string', nullable: true }, DiscordWebhookUrlWordBlock: { type: 'string', nullable: true }, deeplAuthKey: { type: 'string', nullable: true }, @@ -190,9 +190,98 @@ export default class extends Endpoint { // eslint- ) { super(meta, paramDef, async (ps, me) => { const set = {} as Partial; + if (!envOption.managed) { + if (typeof ps.disableRegistration === 'boolean') { + set.disableRegistration = ps.disableRegistration; + } - if (typeof ps.disableRegistration === 'boolean') { - set.disableRegistration = ps.disableRegistration; + if (ps.useObjectStorage !== undefined) { + set.useObjectStorage = ps.useObjectStorage; + } + + if (ps.objectStorageBaseUrl !== undefined) { + set.objectStorageBaseUrl = ps.objectStorageBaseUrl; + } + + if (ps.objectStorageBucket !== undefined) { + set.objectStorageBucket = ps.objectStorageBucket; + } + + if (ps.objectStoragePrefix !== undefined) { + set.objectStoragePrefix = ps.objectStoragePrefix; + } + + if (ps.objectStorageEndpoint !== undefined) { + set.objectStorageEndpoint = ps.objectStorageEndpoint; + } + + if (ps.objectStorageRegion !== undefined) { + set.objectStorageRegion = ps.objectStorageRegion; + } + + if (ps.objectStoragePort !== undefined) { + set.objectStoragePort = ps.objectStoragePort; + } + + if (ps.objectStorageAccessKey !== undefined) { + set.objectStorageAccessKey = ps.objectStorageAccessKey; + } + + if (ps.objectStorageSecretKey !== undefined) { + set.objectStorageSecretKey = ps.objectStorageSecretKey; + } + + if (ps.objectStorageUseSSL !== undefined) { + set.objectStorageUseSSL = ps.objectStorageUseSSL; + } + + if (ps.objectStorageUseProxy !== undefined) { + set.objectStorageUseProxy = ps.objectStorageUseProxy; + } + + if (ps.objectStorageSetPublicRead !== undefined) { + set.objectStorageSetPublicRead = ps.objectStorageSetPublicRead; + } + + if (ps.objectStorageS3ForcePathStyle !== undefined) { + set.objectStorageS3ForcePathStyle = ps.objectStorageS3ForcePathStyle; + } + + if (ps.enableServerMachineStats !== undefined) { + set.enableServerMachineStats = ps.enableServerMachineStats; + } + + if (ps.cacheRemoteFiles !== undefined) { + set.cacheRemoteFiles = ps.cacheRemoteFiles; + } + + if (ps.cacheRemoteSensitiveFiles !== undefined) { + set.cacheRemoteSensitiveFiles = ps.cacheRemoteSensitiveFiles; + } + + if (ps.enableFanoutTimeline !== undefined) { + set.enableFanoutTimeline = ps.enableFanoutTimeline; + } + + if (ps.enableFanoutTimelineDbFallback !== undefined) { + set.enableFanoutTimelineDbFallback = ps.enableFanoutTimelineDbFallback; + } + + if (ps.perLocalUserUserTimelineCacheMax !== undefined) { + set.perLocalUserUserTimelineCacheMax = ps.perLocalUserUserTimelineCacheMax; + } + + if (ps.perRemoteUserUserTimelineCacheMax !== undefined) { + set.perRemoteUserUserTimelineCacheMax = ps.perRemoteUserUserTimelineCacheMax; + } + + if (ps.perUserHomeTimelineCacheMax !== undefined) { + set.perUserHomeTimelineCacheMax = ps.perUserHomeTimelineCacheMax; + } + + if (ps.perUserListTimelineCacheMax !== undefined) { + set.perUserListTimelineCacheMax = ps.perUserListTimelineCacheMax; + } } if (Array.isArray(ps.pinnedUsers)) { @@ -313,14 +402,6 @@ export default class extends Endpoint { // eslint- set.defaultDarkTheme = ps.defaultDarkTheme; } - if (ps.cacheRemoteFiles !== undefined) { - set.cacheRemoteFiles = ps.cacheRemoteFiles; - } - - if (ps.cacheRemoteSensitiveFiles !== undefined) { - set.cacheRemoteSensitiveFiles = ps.cacheRemoteSensitiveFiles; - } - if (ps.emailRequiredForSignup !== undefined) { set.emailRequiredForSignup = ps.emailRequiredForSignup; } @@ -473,58 +554,6 @@ export default class extends Endpoint { // eslint- set.inquiryUrl = ps.inquiryUrl; } - if (ps.useObjectStorage !== undefined) { - set.useObjectStorage = ps.useObjectStorage; - } - - if (ps.objectStorageBaseUrl !== undefined) { - set.objectStorageBaseUrl = ps.objectStorageBaseUrl; - } - - if (ps.objectStorageBucket !== undefined) { - set.objectStorageBucket = ps.objectStorageBucket; - } - - if (ps.objectStoragePrefix !== undefined) { - set.objectStoragePrefix = ps.objectStoragePrefix; - } - - if (ps.objectStorageEndpoint !== undefined) { - set.objectStorageEndpoint = ps.objectStorageEndpoint; - } - - if (ps.objectStorageRegion !== undefined) { - set.objectStorageRegion = ps.objectStorageRegion; - } - - if (ps.objectStoragePort !== undefined) { - set.objectStoragePort = ps.objectStoragePort; - } - - if (ps.objectStorageAccessKey !== undefined) { - set.objectStorageAccessKey = ps.objectStorageAccessKey; - } - - if (ps.objectStorageSecretKey !== undefined) { - set.objectStorageSecretKey = ps.objectStorageSecretKey; - } - - if (ps.objectStorageUseSSL !== undefined) { - set.objectStorageUseSSL = ps.objectStorageUseSSL; - } - - if (ps.objectStorageUseProxy !== undefined) { - set.objectStorageUseProxy = ps.objectStorageUseProxy; - } - - if (ps.objectStorageSetPublicRead !== undefined) { - set.objectStorageSetPublicRead = ps.objectStorageSetPublicRead; - } - - if (ps.objectStorageS3ForcePathStyle !== undefined) { - set.objectStorageS3ForcePathStyle = ps.objectStorageS3ForcePathStyle; - } - if (ps.deeplAuthKey !== undefined) { if (ps.deeplAuthKey === '') { set.deeplAuthKey = null; @@ -585,10 +614,6 @@ export default class extends Endpoint { // eslint- set.enableChartsForFederatedInstances = ps.enableChartsForFederatedInstances; } - if (ps.enableServerMachineStats !== undefined) { - set.enableServerMachineStats = ps.enableServerMachineStats; - } - if (ps.enableIdenticonGeneration !== undefined) { set.enableIdenticonGeneration = ps.enableIdenticonGeneration; } @@ -605,30 +630,6 @@ export default class extends Endpoint { // eslint- set.manifestJsonOverride = ps.manifestJsonOverride; } - if (ps.enableFanoutTimeline !== undefined) { - set.enableFanoutTimeline = ps.enableFanoutTimeline; - } - - if (ps.enableFanoutTimelineDbFallback !== undefined) { - set.enableFanoutTimelineDbFallback = ps.enableFanoutTimelineDbFallback; - } - - if (ps.perLocalUserUserTimelineCacheMax !== undefined) { - set.perLocalUserUserTimelineCacheMax = ps.perLocalUserUserTimelineCacheMax; - } - - if (ps.perRemoteUserUserTimelineCacheMax !== undefined) { - set.perRemoteUserUserTimelineCacheMax = ps.perRemoteUserUserTimelineCacheMax; - } - - if (ps.perUserHomeTimelineCacheMax !== undefined) { - set.perUserHomeTimelineCacheMax = ps.perUserHomeTimelineCacheMax; - } - - if (ps.perUserListTimelineCacheMax !== undefined) { - set.perUserListTimelineCacheMax = ps.perUserListTimelineCacheMax; - } - if (ps.notesPerOneAd !== undefined) { set.notesPerOneAd = ps.notesPerOneAd; } diff --git a/packages/backend/src/server/api/endpoints/i.ts b/packages/backend/src/server/api/endpoints/i.ts index 88d666d96a..8baf5a5eb8 100644 --- a/packages/backend/src/server/api/endpoints/i.ts +++ b/packages/backend/src/server/api/endpoints/i.ts @@ -73,24 +73,28 @@ export default class extends Endpoint { // eslint- const range = max - min + 1; const randomBuffer = new Uint32Array(1); crypto.getRandomValues(randomBuffer); - const randomNumber = randomBuffer[0] / (0xFFFFFFFF + 1); // 0から1未満の浮動小数点数 + const randomNumber = randomBuffer[0] / (0xFFFFFFFF + 1); return Math.floor(randomNumber * range) + min; } if (!userProfile.loggedInDates.includes(today)) { + todayGetPoints = generateSecureRandomNumber(1, 5); - this.userProfilesRepository.update({ userId: user.id }, { + + void this.userProfilesRepository.update({ userId: user.id }, { loggedInDates: [...userProfile.loggedInDates, today], }); + const user_ = await this.usersRepository.findOne({ where: { id: user.id, }, }); + if (user_ == null) { throw new ApiError(meta.errors.userIsDeleted); } - this.usersRepository.update( user.id, { + void this.usersRepository.update( user.id, { getPoints: user_.getPoints + todayGetPoints, }); this.notificationService.createNotification(user.id, 'loginbonus', { diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index fcde00b650..5fa4e8f2e8 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -1,5 +1,5 @@ @@ -10,7 +10,13 @@ SPDX-License-Identifier: AGPL-3.0-only v-hotkey="keymap" tabindex="0" class="_popup _shadow" - :class="[$style.root, { [$style.center]: align === 'center', [$style.asDrawer]: asDrawer },{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]" + :class="{ + [$style.root]: true, + [$style.center]: align === 'center', + [$style.asDrawer]: asDrawer, + [$style.gamingDark]: gamingType === 'dark', + [$style.gamingLight]: gamingType === 'light' + }" :style="{ width: (width && !asDrawer) ? `${width}px` : '', maxHeight: maxHeight ? `${maxHeight}px` : '', @@ -20,21 +26,22 @@ SPDX-License-Identifier: AGPL-3.0-only > @@ -488,35 +497,6 @@ onBeforeUnmount(() => { border-radius: 6px; } - &:not(:disabled):hover { - color: var(--accent); - text-decoration: none; - &:before { - background: var(--accentedBg); - } - &.gamingDark{ - color:black !important; - } - &.gamingLight{ - color:white !important; - } - &.gamingDark:before{ - color:black !important; - background: linear-gradient(270deg, #e7a2a2, #e3cfa2, #ebefa1, #b3e7a6, #a6ebe7, #aec5e3, #cabded, #e0b9e3, #f4bddd); background-size: 1800% 1800%; - -webkit-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite; - -moz-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite; - animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite; - - } - &.gamingLight:before{ - color:white !important; - background: linear-gradient(270deg, #c06161, #c0a567, #b6ba69, #81bc72, #63c3be, #8bacd6, #9f8bd6, #d18bd6, #d883b4); background-size: 1800% 1800% !important; - -webkit-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; - -moz-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; - animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; - - } - &:focus-visible { outline: none; @@ -531,6 +511,27 @@ onBeforeUnmount(() => { &:focus-visible:active, &:focus-visible.active { color: var(--menuHoverFg, var(--accent)); + &.gamingDark{ + color:black !important; + } + &.gamingLight{ + color:white !important; + } + &.gamingDark:before{ + color:black !important; + background: linear-gradient(270deg, #e7a2a2, #e3cfa2, #ebefa1, #b3e7a6, #a6ebe7, #aec5e3, #cabded, #e0b9e3, #f4bddd); background-size: 1800% 1800%; + -webkit-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite; + -moz-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite; + animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite; + + } + &.gamingLight:before{ + color:white !important; + background: linear-gradient(270deg, #c06161, #c0a567, #b6ba69, #81bc72, #63c3be, #8bacd6, #9f8bd6, #d18bd6, #d883b4); background-size: 1800% 1800% !important; + -webkit-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; + -moz-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; + animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; + } &::before { background-color: var(--menuHoverBg, var(--accentedBg)); @@ -587,9 +588,6 @@ onBeforeUnmount(() => { -moz-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; } - &.radio { - --menuActiveFg: var(--accent); - --menuActiveBg: var(--accentedBg); } &.parent { @@ -612,45 +610,6 @@ onBeforeUnmount(() => { pointer-events: none; opacity: 0.7; } - - &.parent { - pointer-events: auto; - display: flex; - align-items: center; - cursor: default; - - &.childShowing { - color: var(--accent); - text-decoration: none; - - &:before { - background: var(--accentedBg); - } - &.gamingDark{ - color:black !important; - } - &.gamingLight{ - color:white !important; - } - &.gamingDark:before{ - color:black !important; - background: linear-gradient(270deg, #e7a2a2, #e3cfa2, #ebefa1, #b3e7a6, #a6ebe7, #aec5e3, #cabded, #e0b9e3, #f4bddd); background-size: 1800% 1800%; - -webkit-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite; - -moz-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite; - animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite; - } - - &.gamingLight:before{ - color:white !important; - background: linear-gradient(270deg, #c06161, #c0a567, #b6ba69, #81bc72, #63c3be, #8bacd6, #9f8bd6, #d18bd6, #d883b4); background-size: 1800% 1800% !important; - -webkit-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; - -moz-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; - animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important; - - } - - } - } } .item_content { @@ -696,11 +655,10 @@ onBeforeUnmount(() => { } .indicator { - position: absolute; - top: 5px; - right: 18px; + display: flex; + align-items: center; color: var(--indicator); - font-size: 8px; + font-size: 12px; animation: global-blink 1s infinite; } @@ -800,7 +758,5 @@ onBeforeUnmount(() => { 100% { background-position: 0% 50% } -} - } } diff --git a/packages/frontend/src/pages/about-type4ny.vue b/packages/frontend/src/pages/about-type4ny.vue index f3de10849b..b223bc3ce7 100644 --- a/packages/frontend/src/pages/about-type4ny.vue +++ b/packages/frontend/src/pages/about-type4ny.vue @@ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only - +
{{ i18n.tsx._aboutType4ny.thisIsModifiedVersion({ name: instance.name }) }} diff --git a/packages/frontend/src/pages/about.overview.vue b/packages/frontend/src/pages/about.overview.vue index 84419b3bef..10270f45ab 100644 --- a/packages/frontend/src/pages/about.overview.vue +++ b/packages/frontend/src/pages/about.overview.vue @@ -22,14 +22,14 @@ SPDX-License-Identifier: AGPL-3.0-only
- + -
+
- + - {{ i18n.ts.aboutMisskey }} + {{ i18n.ts.aboutType4ny }} @@ -138,6 +138,7 @@ import FormSuspense from '@/components/form/suspense.vue'; import MkFolder from '@/components/MkFolder.vue'; import MkKeyValue from '@/components/MkKeyValue.vue'; import MkLink from '@/components/MkLink.vue'; +import MkInfo from "@/components/MkInfo.vue"; const initStats = () => misskeyApi('stats', {}); diff --git a/packages/frontend/src/pages/admin/moderation.vue b/packages/frontend/src/pages/admin/moderation.vue index 324f8c04dd..a6e8d7e3c3 100644 --- a/packages/frontend/src/pages/admin/moderation.vue +++ b/packages/frontend/src/pages/admin/moderation.vue @@ -10,8 +10,11 @@ SPDX-License-Identifier: AGPL-3.0-only
- - + + + @@ -89,6 +92,7 @@ import MkButton from '@/components/MkButton.vue'; import FormLink from '@/components/form/link.vue'; const enableRegistration = ref(false); +const isManaged = ref(false); const emailRequiredForSignup = ref(false); const sensitiveWords = ref(''); const prohibitedWords = ref(''); @@ -101,6 +105,7 @@ const enableGDPRMode = ref(false); async function init() { const meta = await misskeyApi('admin/meta'); + isManaged.value = meta.isManaged; enableRegistration.value = !meta.disableRegistration; emailRequiredForSignup.value = meta.emailRequiredForSignup; sensitiveWords.value = meta.sensitiveWords.join('\n'); diff --git a/packages/frontend/src/pages/admin/object-storage.vue b/packages/frontend/src/pages/admin/object-storage.vue index 66d46f2fb4..0aecb077e6 100644 --- a/packages/frontend/src/pages/admin/object-storage.vue +++ b/packages/frontend/src/pages/admin/object-storage.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only -
+
{{ i18n.ts.useObjectStorage }}
+
+ {{i18n.ts.managedInstanceIsNotEditable}} +
@@ -109,9 +112,11 @@ const objectStorageUseSSL = ref(false); const objectStorageUseProxy = ref(false); const objectStorageSetPublicRead = ref(false); const objectStorageS3ForcePathStyle = ref(true); +const isManaged = ref(false); async function init() { const meta = await misskeyApi('admin/meta'); + isManaged.value = meta.isManaged; useObjectStorage.value = meta.useObjectStorage; objectStorageBaseUrl.value = meta.objectStorageBaseUrl; objectStorageBucket.value = meta.objectStorageBucket; diff --git a/packages/frontend/src/pages/admin/other-settings.vue b/packages/frontend/src/pages/admin/other-settings.vue index 6dac86c03e..be570d25b8 100644 --- a/packages/frontend/src/pages/admin/other-settings.vue +++ b/packages/frontend/src/pages/admin/other-settings.vue @@ -10,9 +10,12 @@ SPDX-License-Identifier: AGPL-3.0-only
- + - +
@@ -78,6 +81,7 @@ const enableIdenticonGeneration = ref(false); const enableChartsForRemoteUser = ref(false); const enableChartsForFederatedInstances = ref(false); const requestEmojiAllOk = ref(false); +const isManaged = ref(false); let DiscordWebhookUrl = ref(null); let DiscordWebhookUrlWordBlock = ref(null); let EmojiBotToken = ref(null); @@ -89,6 +93,7 @@ async function init() { enableIdenticonGeneration.value = meta.enableIdenticonGeneration; enableChartsForRemoteUser.value = meta.enableChartsForRemoteUser; enableChartsForFederatedInstances.value = meta.enableChartsForFederatedInstances; + isManaged.value = meta.isManaged; requestEmojiAllOk.value = meta.requestEmojiAllOk; DiscordWebhookUrl.value = meta.DiscordWebhookUrl; DiscordWebhookUrlWordBlock.value = meta.DiscordWebhookUrlWordBlock; diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue index 99ad853309..60dcfc0182 100644 --- a/packages/frontend/src/pages/admin/settings.vue +++ b/packages/frontend/src/pages/admin/settings.vue @@ -57,9 +57,9 @@ SPDX-License-Identifier: AGPL-3.0-only - +
- + @@ -98,31 +98,32 @@ SPDX-License-Identifier: AGPL-3.0-only +
- + - + - + - + - + - +
@@ -249,7 +250,7 @@ const urlPreviewMaximumContentLength = ref(1024 * 1024 * 10); const urlPreviewRequireContentLength = ref(true); const urlPreviewUserAgent = ref(null); const urlPreviewSummaryProxyUrl = ref(null); - +const isManaged = ref(false); async function init(): Promise { const meta = await misskeyApi('admin/meta'); name.value = meta.name; @@ -278,6 +279,7 @@ async function init(): Promise { urlPreviewRequireContentLength.value = meta.urlPreviewRequireContentLength; urlPreviewUserAgent.value = meta.urlPreviewUserAgent; urlPreviewSummaryProxyUrl.value = meta.urlPreviewSummaryProxyUrl; + isManaged.value = meta.isManaged; } async function save() { diff --git a/packages/frontend/src/scripts/get-timeline-available.ts b/packages/frontend/src/scripts/get-timeline-available.ts index 30197441ea..297e4bf9e2 100644 --- a/packages/frontend/src/scripts/get-timeline-available.ts +++ b/packages/frontend/src/scripts/get-timeline-available.ts @@ -4,5 +4,7 @@ */ import { $i } from '@/account.js'; import { instance } from '@/instance.js'; -export const isLocalTimelineAvailable = ($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable); -export const isGlobalTimelineAvailable = ($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable); +// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition +export const isLocalTimelineAvailable = ($i == null && instance?.policies?.ltlAvailable) || ($i != null && $i?.policies?.ltlAvailable); +// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition +export const isGlobalTimelineAvailable = ($i == null && instance?.policies?.gtlAvailable) || ($i != null && $i?.policies?.gtlAvailable); diff --git a/packages/frontend/src/ui/visitor.vue b/packages/frontend/src/ui/visitor.vue index 3fe46cc995..14a99bcb62 100644 --- a/packages/frontend/src/ui/visitor.vue +++ b/packages/frontend/src/ui/visitor.vue @@ -4,7 +4,7 @@ SPDX-FileCopyrightText: syuilo and misskey-project , Type4ny-projectSPDX-License