merge upstream

This commit is contained in:
Hazelnoot 2025-03-25 16:14:53 -04:00
commit d8908ef2d8
1065 changed files with 32953 additions and 20092 deletions

View file

@ -5,10 +5,9 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UsersRepository } from '@/models/_.js';
import type { MiMeta, UsersRepository } from '@/models/_.js';
import { SignupService } from '@/core/SignupService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { InstanceActorService } from '@/core/InstanceActorService.js';
import { localUsernameSchema, passwordSchema } from '@/models/User.js';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
@ -90,20 +89,21 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.config)
private config: Config,
@Inject(DI.meta)
private serverSettings: MiMeta,
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private roleService: RoleService,
private userEntityService: UserEntityService,
private signupService: SignupService,
private instanceActorService: InstanceActorService,
private readonly moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, _me, token) => {
const me = _me ? await this.usersRepository.findOneByOrFail({ id: _me.id }) : null;
const realUsers = await this.instanceActorService.realLocalUsersPresent();
if (!realUsers && me == null && token == null) {
if (this.serverSettings.rootUserId == null && me == null && token == null) {
// 初回セットアップの場合
if (this.config.setupPassword != null) {
// 初期パスワードが設定されている場合
@ -127,7 +127,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
// Anonymous access is only allowed for initial instance setup (this check may be redundant)
if (!me && realUsers) {
if (!me && this.serverSettings.rootUserId != null) {
throw new ApiError(meta.errors.noCredential);
}
}

View file

@ -42,10 +42,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new Error('user not found');
}
if (user.isRoot) {
throw new Error('cannot delete a root account');
}
await this.deleteAccoountService.deleteAccount(user, me);
});
}

View file

@ -12,7 +12,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageAvatarDecorations',
requiredRolePolicy: 'canManageAvatarDecorations',
kind: 'write:admin:avatar-decorations',
res: {

View file

@ -13,7 +13,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageAvatarDecorations',
requiredRolePolicy: 'canManageAvatarDecorations',
kind: 'write:admin:avatar-decorations',
errors: {
},

View file

@ -13,7 +13,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageAvatarDecorations',
requiredRolePolicy: 'canManageAvatarDecorations',
kind: 'read:admin:avatar-decorations',
res: {

View file

@ -13,7 +13,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageAvatarDecorations',
requiredRolePolicy: 'canManageAvatarDecorations',
kind: 'write:admin:avatar-decorations',
errors: {

View file

@ -12,7 +12,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'write:admin:emoji',
} as const;

View file

@ -16,7 +16,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'write:admin:emoji',
errors: {

View file

@ -17,7 +17,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'write:admin:emoji',
errors: {

View file

@ -11,7 +11,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'write:admin:emoji',
} as const;

View file

@ -11,7 +11,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'write:admin:emoji',
errors: {

View file

@ -13,7 +13,7 @@ import { DI } from '@/di-symbols.js';
export const meta = {
secure: true,
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
} as const;
export const paramDef = {

View file

@ -16,7 +16,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'read:admin:emoji',
res: {

View file

@ -16,7 +16,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'read:admin:emoji',
res: {

View file

@ -12,7 +12,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'write:admin:emoji',
} as const;

View file

@ -12,7 +12,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'write:admin:emoji',
} as const;

View file

@ -12,7 +12,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'write:admin:emoji',
} as const;

View file

@ -12,7 +12,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'write:admin:emoji',
} as const;

View file

@ -14,7 +14,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
requiredRolePolicy: 'canManageCustomEmojis',
kind: 'write:admin:emoji',
errors: {

View file

@ -10,6 +10,7 @@ import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
import { instanceUnsignedFetchOptions } from '@/const.js';
import { SystemAccountService } from '@/core/SystemAccountService.js';
export const meta = {
tags: ['meta'],
@ -86,6 +87,10 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
googleAnalyticsMeasurementId: {
type: 'string',
optional: false, nullable: true,
},
swPublickey: {
type: 'string',
optional: false, nullable: true,
@ -265,7 +270,7 @@ export const meta = {
},
proxyAccountId: {
type: 'string',
optional: false, nullable: true,
optional: false, nullable: false,
format: 'id',
},
email: {
@ -580,6 +585,7 @@ export const meta = {
},
federation: {
type: 'string',
enum: ['all', 'specified', 'none'],
optional: false, nullable: false,
},
federationHosts: {
@ -617,10 +623,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private config: Config,
private metaService: MetaService,
private systemAccountService: SystemAccountService,
) {
super(meta, paramDef, async () => {
const instance = await this.metaService.fetch(true);
const proxy = await this.systemAccountService.fetch('proxy');
return {
maintainerName: instance.maintainerName,
maintainerEmail: instance.maintainerEmail,
@ -652,6 +661,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
enableFC: instance.enableFC,
fcSiteKey: instance.fcSiteKey,
enableTestcaptcha: instance.enableTestcaptcha,
googleAnalyticsMeasurementId: instance.googleAnalyticsMeasurementId,
swPublickey: instance.swPublicKey,
themeColor: instance.themeColor,
mascotImageUrl: instance.mascotImageUrl,
@ -693,7 +703,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically,
enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos,
enableBotTrending: instance.enableBotTrending,
proxyAccountId: instance.proxyAccountId,
proxyAccountId: proxy.id,
email: instance.email,
smtpSecure: instance.smtpSecure,
smtpHost: instance.smtpHost,

View file

@ -7,7 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
//import bcrypt from 'bcryptjs';
import * as argon2 from 'argon2';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UsersRepository, UserProfilesRepository } from '@/models/_.js';
import type { UsersRepository, UserProfilesRepository, MiMeta } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { secureRndstr } from '@/misc/secure-rndstr.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
@ -45,6 +45,9 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
@Inject(DI.meta)
private serverSettings: MiMeta,
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@ -60,7 +63,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new Error('user not found');
}
if (user.isRoot) {
if (this.serverSettings.rootUserId === user.id) {
throw new Error('cannot reset password of root');
}

View file

@ -91,12 +91,12 @@ export const paramDef = {
fcSiteKey: { type: 'string', nullable: true },
fcSecretKey: { type: 'string', nullable: true },
enableTestcaptcha: { type: 'boolean' },
googleAnalyticsMeasurementId: { type: 'string', nullable: true },
sensitiveMediaDetection: { type: 'string', enum: ['none', 'all', 'local', 'remote'] },
sensitiveMediaDetectionSensitivity: { type: 'string', enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'] },
setSensitiveFlagAutomatically: { type: 'boolean' },
enableSensitiveMediaDetectionForVideos: { type: 'boolean' },
enableBotTrending: { type: 'boolean' },
proxyAccountId: { type: 'string', format: 'misskey:id', nullable: true },
maintainerName: { type: 'string', nullable: true },
maintainerEmail: { type: 'string', nullable: true },
langs: {
@ -130,7 +130,7 @@ export const paramDef = {
useObjectStorage: { type: 'boolean' },
objectStorageBaseUrl: { type: 'string', nullable: true },
objectStorageBucket: { type: 'string', nullable: true },
objectStoragePrefix: { type: 'string', nullable: true },
objectStoragePrefix: { type: 'string', pattern: /^[a-zA-Z0-9-._]*$/.source, nullable: true },
objectStorageEndpoint: { type: 'string', nullable: true },
objectStorageRegion: { type: 'string', nullable: true },
objectStoragePort: { type: 'integer', nullable: true },
@ -413,6 +413,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.enableTestcaptcha = ps.enableTestcaptcha;
}
if (ps.googleAnalyticsMeasurementId !== undefined) {
// 空文字列をnullにしたいので??は使わない
set.googleAnalyticsMeasurementId = ps.googleAnalyticsMeasurementId || null;
}
if (ps.fcSiteKey !== undefined) {
set.fcSiteKey = ps.fcSiteKey;
}
@ -425,10 +430,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.enableBotTrending = ps.enableBotTrending;
}
if (ps.proxyAccountId !== undefined) {
set.proxyAccountId = ps.proxyAccountId;
}
if (ps.maintainerName !== undefined) {
set.maintainerName = ps.maintainerName;
}

View file

@ -0,0 +1,62 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import {
descriptionSchema,
} from '@/models/User.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { SystemAccountService } from '@/core/SystemAccountService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
kind: 'write:admin:account',
res: {
type: 'object',
nullable: false, optional: false,
ref: 'UserDetailed',
},
} as const;
export const paramDef = {
type: 'object',
properties: {
description: { ...descriptionSchema, nullable: true },
},
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private userEntityService: UserEntityService,
private moderationLogService: ModerationLogService,
private systemAccountService: SystemAccountService,
) {
super(meta, paramDef, async (ps, me) => {
const proxy = await this.systemAccountService.updateCorrespondingUserProfile('proxy', {
description: ps.description,
});
const updated = await this.userEntityService.pack(proxy.id, proxy, {
schema: 'MeDetailed',
});
if (ps.description !== undefined) {
this.moderationLogService.log(me, 'updateProxyAccountDescription', {
before: null, //TODO
after: ps.description,
});
}
return updated;
});
}
}