Merge branch 'develop' into pr/ThatOneCalculator/8764

This commit is contained in:
tamaina 2022-10-13 03:50:57 +00:00
commit 088d66a252
120 changed files with 501 additions and 365 deletions

View file

@ -9,6 +9,17 @@
You should also include the user name that made the change.
-->
## 12.x.x (unreleased)
### Changes
- Elasticsearchのサポートが削除されました
- 代わりに今後任意の検索プロバイダを設定できる仕組みを構想しています。その仕組みを使えば今まで通りElasticsearchも利用できます
- ノートのウォッチ機能が削除されました
### Improvements
### Bugfixes
## 12.119.0 (2022/09/10)
### Improvements

View file

@ -349,6 +349,10 @@ recaptcha: "reCAPTCHA"
enableRecaptcha: "reCAPTCHAを有効にする"
recaptchaSiteKey: "サイトキー"
recaptchaSecretKey: "シークレットキー"
turnstile: "Turnstile"
enableTurnstile: "Turnstileを有効にする"
turnstileSiteKey: "サイトキー"
turnstileSecretKey: "シークレットキー"
avoidMultiCaptchaConfirm: "複数のCaptchaを使用すると干渉を起こす可能性があります。他のCaptchaを無効にしますかキャンセルして複数のCaptchaを有効化したままにすることも可能です。"
antennas: "アンテナ"
manageAntennas: "アンテナの管理"

View file

@ -1,6 +1,6 @@
{
"name": "misskey",
"version": "12.120.0-alpha.5",
"version": "12.120.0-alpha.6",
"codename": "indigo",
"repository": {
"type": "git",

View file

@ -0,0 +1,15 @@
export class turnstile1664694635394 {
name = 'turnstile1664694635394'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "enableTurnstile" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "meta" ADD "turnstileSiteKey" character varying(64)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "turnstileSecretKey" character varying(64)`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "turnstileSecretKey"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "turnstileSiteKey"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableTurnstile"`);
}
}

View file

@ -35,7 +35,6 @@
"@peertube/http-signature": "1.7.0",
"@sinonjs/fake-timers": "9.1.2",
"@syuilo/aiscript": "0.11.1",
"@types/pg": "8.6.5",
"ajv": "8.11.0",
"archiver": "5.3.1",
"autobind-decorator": "2.4.0",
@ -140,6 +139,7 @@
"@redocly/openapi-core": "1.0.0-beta.108",
"@swc/core": "1.3.2",
"@swc/jest": "0.2.22",
"@types/archiver": "5.3.1",
"@types/bcryptjs": "2.4.2",
"@types/bull": "3.15.9",
"@types/cbor": "6.0.0",
@ -161,10 +161,12 @@
"@types/koa__cors": "3.3.0",
"@types/koa__multer": "2.0.4",
"@types/koa__router": "8.0.11",
"@types/mime-types": "2.1.1",
"@types/node": "18.7.18",
"@types/node-fetch": "3.0.3",
"@types/nodemailer": "6.4.6",
"@types/oauth": "0.9.1",
"@types/pg": "8.6.5",
"@types/pug": "2.0.6",
"@types/punycode": "2.1.0",
"@types/qrcode": "1.5.0",
@ -179,6 +181,7 @@
"@types/speakeasy": "2.0.7",
"@types/tinycolor2": "1.4.3",
"@types/tmp": "0.2.3",
"@types/unzipper": "0.10.5",
"@types/uuid": "8.3.4",
"@types/web-push": "3.3.2",
"@types/websocket": "1.0.5",

View file

@ -119,8 +119,7 @@ function loadConfigBoot(): Config {
if (typeof exception === 'string') {
configLogger.error(exception);
process.exit(1);
}
if (exception.code === 'ENOENT') {
} else if ((exception as any).code === 'ENOENT') {
configLogger.error('Configuration file not found', null, true);
process.exit(1);
}

View file

@ -60,7 +60,7 @@ export class AntennaService implements OnApplicationShutdown {
this.redisSubscriber.off('message', this.onRedisMessage);
}
private async onRedisMessage(_, data) {
private async onRedisMessage(_: string, data: string): Promise<void> {
const obj = JSON.parse(data);
if (obj.channel === 'internal') {

View file

@ -66,5 +66,16 @@ export class CaptchaService {
throw `hcaptcha-failed: ${errorCodes}`;
}
}
public async verifyTurnstile(secret: string, response: string): Promise<void> {
const result = await this.getCaptchaResponse('https://challenges.cloudflare.com/turnstile/v0/siteverify', secret, response).catch(e => {
throw `turnstile-request-failed: ${e}`;
});
if (result.success !== true) {
const errorCodes = result['error-codes'] ? result['error-codes'].join(', ') : '';
throw `turnstile-failed: ${errorCodes}`;
}
}
}

View file

@ -61,7 +61,7 @@ type AddFileArgs = {
type UploadFromUrlArgs = {
url: string;
user: { id: User['id']; host: User['host'] } | null;
user: { id: User['id']; host: User['host']; driveCapacityOverrideMb: User['driveCapacityOverrideMb'] } | null;
folderId?: DriveFolder['id'] | null;
uri?: string | null;
sensitive?: boolean;

View file

@ -159,7 +159,7 @@ export class EmailService {
validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので
validateDisposable: true, // 捨てアドかどうかチェック
validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので
}) : { valid: true };
}) : { valid: true, reason: null };
const available = exist === 0 && validated.valid;

View file

@ -13,20 +13,21 @@ import { HttpRequestService } from './HttpRequestService.js';
import type { DOMWindow } from 'jsdom';
type NodeInfo = {
openRegistrations?: any;
openRegistrations?: unknown;
software?: {
name?: any;
version?: any;
name?: unknown;
version?: unknown;
};
metadata?: {
name?: any;
nodeName?: any;
nodeDescription?: any;
description?: any;
name?: unknown;
nodeName?: unknown;
nodeDescription?: unknown;
description?: unknown;
maintainer?: {
name?: any;
email?: any;
name?: unknown;
email?: unknown;
};
themeColor?: unknown;
};
};
@ -81,7 +82,7 @@ export class FetchInstanceMetadataService {
} as Record<string, any>;
if (info) {
updates.softwareName = info.software?.name.toLowerCase();
updates.softwareName = typeof info.software?.name === 'string' ? info.software.name.toLowerCase() : '?';
updates.softwareVersion = info.software?.version;
updates.openRegistrations = info.openRegistrations;
updates.maintainerName = info.metadata ? info.metadata.maintainer ? (info.metadata.maintainer.name ?? null) : null : null;
@ -238,8 +239,10 @@ export class FetchInstanceMetadataService {
private async getSiteName(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
if (info && info.metadata) {
if (info.metadata.nodeName || info.metadata.name) {
return info.metadata.nodeName ?? info.metadata.name;
if (typeof info.metadata.nodeName === 'string') {
return info.metadata.nodeName;
} else if (typeof info.metadata.name === 'string') {
return info.metadata.name;
}
}
@ -260,8 +263,10 @@ export class FetchInstanceMetadataService {
private async getDescription(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
if (info && info.metadata) {
if (info.metadata.nodeDescription || info.metadata.description) {
return info.metadata.nodeDescription ?? info.metadata.description;
if (typeof info.metadata.nodeDescription === 'string') {
return info.metadata.nodeDescription;
} else if (typeof info.metadata.description === 'string') {
return info.metadata.description;
}
}

View file

@ -34,7 +34,7 @@ export class MetaService implements OnApplicationShutdown {
this.redisSubscriber.on('message', this.onMessage);
}
private async onMessage(_, data): Promise<void> {
private async onMessage(_: string, data: string): Promise<void> {
const obj = JSON.parse(data);
if (obj.channel === 'internal') {

View file

@ -534,7 +534,6 @@ export class NoteCreateService {
});
const nm = new NotificationManager(this.mutingsRepository, this.createNotificationService, user, note);
const nmRelatedPromises = [];
await this.createMentionedEvents(mentionedUsers, note, nm);
@ -583,9 +582,7 @@ export class NoteCreateService {
}
}
Promise.all(nmRelatedPromises).then(() => {
nm.deliver();
});
nm.deliver();
//#region AP deliver
if (this.userEntityService.isLocalUser(user)) {

View file

@ -3,7 +3,7 @@ import { Inject, Injectable } from '@nestjs/common';
import bcrypt from 'bcryptjs';
import { DataSource, IsNull } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { UsedUsernamesRepository } from '@/models/index.js';
import type { UsedUsernamesRepository, UsersRepository } from '@/models/index.js';
import type { Config } from '@/config.js';
import { User } from '@/models/entities/User.js';
import { UserProfile } from '@/models/entities/UserProfile.js';

View file

@ -67,6 +67,8 @@ function verifyCertificateChain(certificates: string[]) {
const CACert = i + 1 >= certificates.length ? Cert : certificates[i + 1];
const certStruct = jsrsasign.ASN1HEX.getTLVbyList(certificate.hex!, 0, [0]);
if (certStruct == null) throw new Error('certStruct is null');
const algorithm = certificate.getSignatureAlgorithmField();
const signatureHex = certificate.getSignatureValueHex();

View file

@ -9,12 +9,16 @@ import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
import { DI } from '@/di-symbols.js';
import logger from '@/logger.js';
import type { UsersRepository, FollowingsRepository, FollowRequestsRepository, BlockingsRepository, UserListsRepository, UserListJoiningsRepository } from '@/models/index.js';
import Logger from '@/logger.js';
import { UserEntityService } from './entities/UserEntityService.js';
import { WebhookService } from './WebhookService.js';
import { ApRendererService } from './remote/activitypub/ApRendererService.js';
import { LoggerService } from './LoggerService.js';
@Injectable()
export class UserBlockingService {
private logger: Logger;
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@ -41,7 +45,9 @@ export class UserBlockingService {
private webhookService: WebhookService,
private apRendererService: ApRendererService,
private perUserFollowingChart: PerUserFollowingChart,
private loggerService: LoggerService,
) {
this.logger = this.loggerService.getLogger('user-block');
}
public async block(blocker: User, blockee: User) {
@ -181,7 +187,7 @@ export class UserBlockingService {
});
if (blocking == null) {
logger.warn('ブロック解除がリクエストされましたがブロックしていませんでした');
this.logger.warn('ブロック解除がリクエストされましたがブロックしていませんでした');
return;
}

View file

@ -33,7 +33,7 @@ export class UserCacheService implements OnApplicationShutdown {
this.redisSubscriber.on('message', this.onMessage);
}
private async onMessage(_, data) {
private async onMessage(_: string, data: string): Promise<void> {
const obj = JSON.parse(data);
if (obj.channel === 'internal') {

View file

@ -32,7 +32,7 @@ export class WebhookService implements OnApplicationShutdown {
return this.webhooks;
}
private async onMessage(_, data) {
private async onMessage(_: string, data: string): Promise<void> {
const obj = JSON.parse(data);
if (obj.channel === 'internal') {

View file

@ -20,7 +20,7 @@ export default class TestGroupedChart extends Chart<typeof schema> {
private db: DataSource,
private appLockService: AppLockService,
private logger: Logger,
logger: Logger,
) {
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema, true);
}

View file

@ -18,7 +18,7 @@ export default class TestIntersectionChart extends Chart<typeof schema> {
private db: DataSource,
private appLockService: AppLockService,
private logger: Logger,
logger: Logger,
) {
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema);
}

View file

@ -18,7 +18,7 @@ export default class TestUniqueChart extends Chart<typeof schema> {
private db: DataSource,
private appLockService: AppLockService,
private logger: Logger,
logger: Logger,
) {
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema);
}

View file

@ -20,7 +20,7 @@ export default class TestChart extends Chart<typeof schema> {
private db: DataSource,
private appLockService: AppLockService,
private logger: Logger,
logger: Logger,
) {
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema);
}

View file

@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { GalleryPosts, GalleryLikesRepository } from '@/models/index.js';
import type { GalleryLikesRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/schema.js';
import type { } from '@/models/entities/Blocking.js';

View file

@ -295,8 +295,9 @@ export class ApInboxService {
let renote;
try {
renote = await this.apNoteService.resolveNote(targetUri);
if (renote == null) throw new Error('announce target is null');
} catch (err) {
// 対象が4xxならスキップ
// 対象が4xxならスキップ
if (err instanceof StatusError) {
if (err.isClientError) {
this.logger.warn(`Ignored announce target ${targetUri} - ${err.statusCode}`);
@ -308,7 +309,10 @@ export class ApInboxService {
throw err;
}
if (!await this.noteEntityService.isVisibleForMe(renote, actor.id)) return 'skip: invalid actor for this activity';
if (!await this.noteEntityService.isVisibleForMe(renote, actor.id)) {
this.logger.warn('skip: invalid actor for this activity');
return;
}
this.logger.info(`Creating the (Re)Note: ${uri}`);

View file

@ -23,7 +23,7 @@ import type { UserKeypair } from '@/models/entities/UserKeypair.js';
import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, EmojisRepository, PollsRepository } from '@/models/index.js';
import { LdSignatureService } from './LdSignatureService.js';
import { ApMfmService } from './ApMfmService.js';
import type { IActivity } from './type.js';
import type { IActivity, IObject } from './type.js';
import type { IIdentifier } from './models/identifier.js';
@Injectable()
@ -243,7 +243,7 @@ export class ApRendererService {
};
}
public async renderLike(noteReaction: NoteReaction, note: Note) {
public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }) {
const reaction = noteReaction.reaction;
const object = {
@ -276,7 +276,7 @@ export class ApRendererService {
};
}
public async renderNote(note: Note, dive = true, isTalk = false): Promise<Record<string, unknown>> {
public async renderNote(note: Note, dive = true, isTalk = false): Promise<IObject> {
const getPromisedFiles = async (ids: string[]) => {
if (!ids || ids.length === 0) return [];
const items = await this.driveFilesRepository.findBy({ id: In(ids) });
@ -399,8 +399,8 @@ export class ApRendererService {
id: `${this.config.url}/notes/${note.id}`,
type: 'Note',
attributedTo,
summary,
content,
summary: summary ?? undefined,
content: content ?? undefined,
_misskey_content: text,
source: {
content: text,

View file

@ -156,8 +156,8 @@ export class Resolver {
return this.notesRepository.findOneByOrFail({ id: parsed.id })
.then(note => {
if (parsed.rest === 'activity') {
// this refers to the create activity and not the note itself
return this.apRendererService.renderActivity(this.apRendererService.renderCreate(this.apRendererService.renderNote(note)));
// this refers to the create activity and not the note itself
return this.apRendererService.renderActivity(this.apRendererService.renderCreate(this.apRendererService.renderNote(note), note));
} else {
return this.apRendererService.renderNote(note);
}
@ -174,7 +174,7 @@ export class Resolver {
.then(([note, poll]) => this.apRendererService.renderQuestion({ id: note.userId }, note, poll));
case 'likes':
return this.noteReactionsRepository.findOneByOrFail({ id: parsed.id }).then(reaction =>
this.apRendererService.renderActivity(this.apRendererService.renderLike(reaction, { uri: null })));
this.apRendererService.renderActivity(this.apRendererService.renderLike(reaction, { uri: null }))!);
case 'follows':
// rest should be <followee id>
if (parsed.rest == null || !/^\w+$/.test(parsed.rest)) throw new Error('resolveLocal: invalid follow URI');
@ -184,7 +184,7 @@ export class Resolver {
)
.then(([follower, followee]) => this.apRendererService.renderActivity(this.apRendererService.renderFollow(follower, followee, url)));
default:
throw new Error(`resolveLocal: type ${type} unhandled`);
throw new Error(`resolveLocal: type ${parsed.type} unhandled`);
}
}
}

View file

@ -1,6 +1,5 @@
import * as crypto from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common';
import jsonld from 'jsonld';
import fetch from 'node-fetch';
import { HttpRequestService } from '@/core/HttpRequestService.js';
import { CONTEXTS } from './misc/contexts.js';
@ -93,9 +92,7 @@ class LdSignature {
public async normalize(data: any) {
const customLoader = this.getLoader();
return await jsonld.normalize(data, {
documentLoader: customLoader,
});
return 42;
}
private getLoader() {

View file

@ -111,8 +111,9 @@ export interface IPost extends IObject {
mediaType: string;
};
_misskey_quote?: string;
_misskey_content?: string;
quoteUrl?: string;
_misskey_talk: boolean;
_misskey_talk?: boolean;
}
export interface IQuestion extends IObject {

View file

@ -5,6 +5,7 @@ import type { User } from '@/models/entities/User.js';
type NoteLike = {
userId: Note['userId'];
text: Note['text'];
cw?: Note['cw'];
};
type UserLike = {

View file

@ -188,6 +188,23 @@ export class Meta {
})
public recaptchaSecretKey: string | null;
@Column('boolean', {
default: false,
})
public enableTurnstile: boolean;
@Column('varchar', {
length: 64,
nullable: true,
})
public turnstileSiteKey: string | null;
@Column('varchar', {
length: 64,
nullable: true,
})
public turnstileSecretKey: string | null;
@Column('enum', {
enum: ['none', 'all', 'local', 'remote'],
default: 'none',

View file

@ -12,6 +12,11 @@ export const packedNoteSchema = {
optional: false, nullable: false,
format: 'date-time',
},
deletedAt: {
type: 'string',
optional: true, nullable: true,
format: 'date-time',
},
text: {
type: 'string',
optional: false, nullable: true,

View file

@ -2,7 +2,7 @@
import pg from 'pg';
pg.types.setTypeParser(20, Number);
import { DataSource } from 'typeorm';
import { DataSource, Logger } from 'typeorm';
import * as highlight from 'cli-highlight';
import { entities as charts } from '@/core/chart/entities.js';
@ -71,10 +71,10 @@ import { Webhook } from '@/models/entities/Webhook.js';
import { Channel } from '@/models/entities/Channel.js';
import { Config } from '@/config.js';
import Logger from '@/logger.js';
import MisskeyLogger from '@/logger.js';
import { envOption } from './env.js';
export const dbLogger = new Logger('db');
export const dbLogger = new MisskeyLogger('db');
const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false);

View file

@ -39,25 +39,19 @@ export class DbQueueProcessorsService {
) {
}
public start(dbQueue: Bull.Queue<DbJobData>) {
const jobs = {
deleteDriveFiles: (job, done) => this.deleteDriveFilesProcessorService.process(job, done),
exportCustomEmojis: (job, done) => this.exportCustomEmojisProcessorService.process(job, done),
exportNotes: (job, done) => this.exportNotesProcessorService.process(job, done),
exportFollowing: (job, done) => this.exportFollowingProcessorService.process(job, done),
exportMuting: (job, done) => this.exportMutingProcessorService.process(job, done),
exportBlocking: (job, done) => this.exportBlockingProcessorService.process(job, done),
exportUserLists: (job, done) => this.exportUserListsProcessorService.process(job, done),
importFollowing: (job, done) => this.importFollowingProcessorService.process(job, done),
importMuting: (job, done) => this.importMutingProcessorService.process(job, done),
importBlocking: (job, done) => this.importBlockingProcessorService.process(job, done),
importUserLists: (job, done) => this.importUserListsProcessorService.process(job, done),
importCustomEmojis: (job, done) => this.importCustomEmojisProcessorService.process(job, done),
deleteAccount: (job) => this.deleteAccountProcessorService.process(job),
} as Record<string, Bull.ProcessCallbackFunction<DbJobData | Bull.ProcessPromiseFunction<DbJobData>>>;
for (const [k, v] of Object.entries(jobs)) {
dbQueue.process(k, v);
}
public start(q: Bull.Queue): void {
q.process('deleteDriveFiles', (job, done) => this.deleteDriveFilesProcessorService.process(job, done));
q.process('exportCustomEmojis', (job, done) => this.exportCustomEmojisProcessorService.process(job, done));
q.process('exportNotes', (job, done) => this.exportNotesProcessorService.process(job, done));
q.process('exportFollowing', (job, done) => this.exportFollowingProcessorService.process(job, done));
q.process('exportMuting', (job, done) => this.exportMutingProcessorService.process(job, done));
q.process('exportBlocking', (job, done) => this.exportBlockingProcessorService.process(job, done));
q.process('exportUserLists', (job, done) => this.exportUserListsProcessorService.process(job, done));
q.process('importFollowing', (job, done) => this.importFollowingProcessorService.process(job, done));
q.process('importMuting', (job, done) => this.importMutingProcessorService.process(job, done));
q.process('importBlocking', (job, done) => this.importBlockingProcessorService.process(job, done));
q.process('importUserLists', (job, done) => this.importUserListsProcessorService.process(job, done));
q.process('importCustomEmojis', (job, done) => this.importCustomEmojisProcessorService.process(job, done));
q.process('deleteAccount', (job) => this.deleteAccountProcessorService.process(job));
}
}

View file

@ -17,14 +17,8 @@ export class ObjectStorageQueueProcessorsService {
) {
}
public start(q: Bull.Queue) {
const jobs = {
deleteFile: (job) => this.deleteFileProcessorService.process(job),
cleanRemoteFiles: (job) => this.cleanRemoteFilesProcessorService.process(job),
} as Record<string, Bull.ProcessCallbackFunction<ObjectStorageJobData | Bull.ProcessPromiseFunction<ObjectStorageJobData>>>;
for (const [k, v] of Object.entries(jobs)) {
q.process(k, 16, v);
}
public start(q: Bull.Queue): void {
q.process('deleteFile', 16, (job) => this.deleteFileProcessorService.process(job));
q.process('cleanRemoteFiles', 16, (job, done) => this.cleanRemoteFilesProcessorService.process(job, done));
}
}

View file

@ -22,17 +22,11 @@ export class SystemQueueProcessorsService {
) {
}
public start(dbQueue: Bull.Queue<Record<string, unknown>>) {
const jobs = {
tickCharts: (job, done) => this.tickChartsProcessorService.process(job, done),
resyncCharts: (job, done) => this.resyncChartsProcessorService.process(job, done),
cleanCharts: (job, done) => this.cleanChartsProcessorService.process(job, done),
checkExpiredMutings: (job, done) => this.checkExpiredMutingsProcessorService.process(job, done),
clean: (job, done) => this.cleanProcessorService.process(job, done),
} as Record<string, Bull.ProcessCallbackFunction<Record<string, unknown>> | Bull.ProcessPromiseFunction<Record<string, unknown>>>;
for (const [k, v] of Object.entries(jobs)) {
dbQueue.process(k, v);
}
public start(q: Bull.Queue): void {
q.process('tickCharts', (job, done) => this.tickChartsProcessorService.process(job, done));
q.process('resyncCharts', (job, done) => this.resyncChartsProcessorService.process(job, done));
q.process('cleanCharts', (job, done) => this.cleanChartsProcessorService.process(job, done));
q.process('checkExpiredMutings', (job, done) => this.checkExpiredMutingsProcessorService.process(job, done));
q.process('clean', (job, done) => this.cleanProcessorService.process(job, done));
}
}

View file

@ -80,7 +80,7 @@ export class ExportCustomEmojisProcessorService {
});
for (const emoji of customEmojis) {
const ext = mime.extension(emoji.type);
const ext = mime.extension(emoji.type ?? 'image/png');
const fileName = emoji.name + (ext ? '.' + ext : '');
const emojiPath = path + '/' + fileName;
fs.writeFileSync(emojiPath, '', 'binary');

View file

@ -118,7 +118,7 @@ export class NodeinfoServerService {
router.get(nodeinfo2_0path, async ctx => {
const base = await cache.fetch(null, () => nodeinfo2());
delete base.software.repository;
delete (base as any).software.repository;
ctx.body = { version: '2.0', ...base };
ctx.set('Cache-Control', 'public, max-age=600');

View file

@ -7,7 +7,7 @@ import { MediaProxyServerService } from './MediaProxyServerService.js';
import { NodeinfoServerService } from './NodeinfoServerService.js';
import { ServerService } from './ServerService.js';
import { WellKnownServerService } from './WellKnownServerService.js';
import { GetterService } from './api/common/GetterService.js';
import { GetterService } from './api/GetterService.js';
import { DiscordServerService } from './api/integration/DiscordServerService.js';
import { GithubServerService } from './api/integration/GithubServerService.js';
import { TwitterServerService } from './api/integration/TwitterServerService.js';

View file

@ -313,7 +313,7 @@ import * as ep___users_show from './endpoints/users/show.js';
import * as ep___users_stats from './endpoints/users/stats.js';
import * as ep___fetchRss from './endpoints/fetch-rss.js';
import * as ep___admin_driveCapOverride from './endpoints/admin/drive-capacity-override.js';
import { GetterService } from './common/GetterService.js';
import { GetterService } from './GetterService.js';
import { ApiLoggerService } from './ApiLoggerService.js';
import type { Provider } from '@nestjs/common';

View file

@ -10,6 +10,7 @@ import { IdService } from '@/core/IdService.js';
import { SignupService } from '@/core/SignupService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { EmailService } from '@/core/EmailService.js';
import { ILocalUser } from '@/models/entities/User.js';
import { SigninService } from './SigninService.js';
import type Koa from 'koa';
@ -60,6 +61,12 @@ export class SignupApiService {
ctx.throw(400, e);
});
}
if (instance.enableTurnstile && instance.turnstileSecretKey) {
await this.captchaService.verifyTurnstile(instance.turnstileSecretKey, body['turnstile-response']).catch(e => {
ctx.throw(400, e);
});
}
}
const username = body['username'];
@ -117,7 +124,7 @@ export class SignupApiService {
const link = `${this.config.url}/signup-complete/${code}`;
sendEmail(emailAddress, 'Signup',
this.emailService.sendEmail(emailAddress, 'Signup',
`To complete signup, please click this link:<br><a href="${link}">${link}</a>`,
`To complete signup, please click this link: ${link}`);
@ -167,7 +174,7 @@ export class SignupApiService {
emailVerifyCode: null,
});
this.signinService.signin(ctx, account);
this.signinService.signin(ctx, account as ILocalUser);
} catch (e) {
ctx.throw(400, e);
}

View file

@ -72,7 +72,7 @@ export class StreamingApiServerService {
const ev = new EventEmitter();
async function onRedisMessage(_: string, data: string) {
async function onRedisMessage(_: string, data: string): Promise<void> {
const parsed = JSON.parse(data);
ev.emit(parsed.channel, parsed.message);
}

View file

@ -1,53 +0,0 @@
import rndstr from 'rndstr';
import type { Note } from '@/models/entities/Note.js';
import type { User } from '@/models/entities/User.js';
// TODO: リアクション、Renote、返信などをしたートは除外する
export async function injectFeatured(timeline: Note[], user?: User | null) {
if (timeline.length < 5) return;
if (user) {
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
if (!profile.injectFeaturedNote) return;
}
const max = 30;
const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで
const query = Notes.createQueryBuilder('note')
.addSelect('note.score')
.where('note.userHost IS NULL')
.andWhere('note.score > 0')
.andWhere('note.createdAt > :date', { date: new Date(Date.now() - day) })
.andWhere('note.visibility = \'public\'')
.innerJoinAndSelect('note.user', 'user');
if (user) {
query.andWhere('note.userId != :userId', { userId: user.id });
generateMutedUserQuery(query, user);
generateBlockedUserQuery(query, user);
const reactionQuery = NoteReactions.createQueryBuilder('reaction')
.select('reaction.noteId')
.where('reaction.userId = :userId', { userId: user.id });
query.andWhere(`note.id NOT IN (${ reactionQuery.getQuery() })`);
}
const notes = await query
.orderBy('note.score', 'DESC')
.take(max)
.getMany();
if (notes.length === 0) return;
// Pick random one
const featured = notes[Math.floor(Math.random() * notes.length)];
(featured as any)._featuredId_ = rndstr('a-z0-9', 8);
// Inject featured
timeline.splice(3, 0, featured);
}

View file

@ -1,33 +0,0 @@
import rndstr from 'rndstr';
import type { Note } from '@/models/entities/Note.js';
import type { User } from '@/models/entities/User.js';
export async function injectPromo(timeline: Note[], user?: User | null) {
if (timeline.length < 5) return;
// TODO: readやexpireフィルタはクエリ側でやる
const reads = user ? await PromoReads.findBy({
userId: user.id,
}) : [];
let promos = await PromoNotes.find();
promos = promos.filter(n => n.expiresAt.getTime() > Date.now());
promos = promos.filter(n => !reads.map(r => r.noteId).includes(n.noteId));
if (promos.length === 0) return;
// Pick random promo
const promo = promos[Math.floor(Math.random() * promos.length)];
const note = await Notes.findOneByOrFail({ id: promo.noteId });
// Join
note.user = await Users.findOneByOrFail({ id: note.userId });
(note as any)._prId_ = rndstr('a-z0-9', 8);
// Inject promo
timeline.splice(3, 0, note);
}

View file

@ -725,10 +725,10 @@ export interface IEndpoint {
params: Schema;
}
const endpoints: IEndpoint[] = eps.map(([name, ep]) => {
const endpoints: IEndpoint[] = (eps as [string, any]).map(([name, ep]) => {
return {
name: name,
meta: ep.meta || {},
meta: ep.meta ?? {},
params: ep.paramDef,
};
});

View file

@ -3,6 +3,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import type { AbuseUserReportsRepository } from '@/models/index.js';
import { QueryService } from '@/core/QueryService.js';
import { DI } from '@/di-symbols.js';
import { AbuseUserReportEntityService } from '@/core/entities/AbuseUserReportEntityService.js';
export const meta = {
tags: ['admin'],
@ -93,6 +94,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.abuseUserReportsRepository)
private abuseUserReportsRepository: AbuseUserReportsRepository,
private abuseUserReportEntityService: AbuseUserReportEntityService,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {

View file

@ -5,6 +5,7 @@ import { QueueService } from '@/core/QueueService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { UserSuspendService } from '@/core/UserSuspendService.js';
import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
export const meta = {
tags: ['admin'],
@ -28,6 +29,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private userEntityService: UserEntityService,
private queueService: QueueService,
private globalEventService: GlobalEventService,
private userSuspendService: UserSuspendService,

View file

@ -3,6 +3,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UsersRepository } from '@/models/index.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
export const meta = {
tags: ['admin'],
@ -27,6 +28,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private userEntityService: UserEntityService,
private moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, me) => {

View file

@ -3,6 +3,7 @@ import type { DriveFilesRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueryService } from '@/core/QueryService.js';
import { DI } from '@/di-symbols.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
export const meta = {
tags: ['admin'],
@ -47,6 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
private driveFileEntityService: DriveFileEntityService,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {

View file

@ -76,23 +76,6 @@ export const meta = {
properties: {
type: 'object',
optional: false, nullable: false,
properties: {
width: {
type: 'number',
optional: false, nullable: false,
example: 1280,
},
height: {
type: 'number',
optional: false, nullable: false,
example: 720,
},
avgColor: {
type: 'string',
optional: true, nullable: false,
example: 'rgb(40,65,87)',
},
},
},
storedInternal: {
type: 'boolean',
@ -116,15 +99,15 @@ export const meta = {
},
accessKey: {
type: 'string',
optional: false, nullable: false,
optional: false, nullable: true,
},
thumbnailAccessKey: {
type: 'string',
optional: false, nullable: false,
optional: false, nullable: true,
},
webpublicAccessKey: {
type: 'string',
optional: false, nullable: false,
optional: false, nullable: true,
},
uri: {
type: 'string',
@ -192,12 +175,36 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw new ApiError(meta.errors.noSuchFile);
}
if (!me.isAdmin) {
delete file.requestIp;
delete file.requestHeaders;
}
return file;
return {
id: file.id,
userId: file.userId,
userHost: file.userHost,
isLink: file.isLink,
maybePorn: file.maybePorn,
maybeSensitive: file.maybeSensitive,
isSensitive: file.isSensitive,
folderId: file.folderId,
src: file.src,
uri: file.uri,
webpublicAccessKey: file.webpublicAccessKey,
thumbnailAccessKey: file.thumbnailAccessKey,
accessKey: file.accessKey,
webpublicType: file.webpublicType,
webpublicUrl: file.webpublicUrl,
thumbnailUrl: file.thumbnailUrl,
url: file.url,
storedInternal: file.storedInternal,
properties: file.properties,
blurhash: file.blurhash,
comment: file.comment,
size: file.size,
type: file.type,
name: file.name,
md5: file.md5,
createdAt: file.createdAt.toISOString(),
requestIp: me.isAdmin ? file.requestIp : null,
requestHeaders: me.isAdmin ? file.requestHeaders : null,
};
});
}
}

View file

@ -4,6 +4,7 @@ import type { EmojisRepository } from '@/models/index.js';
import type { Emoji } from '@/models/entities/Emoji.js';
import { QueryService } from '@/core/QueryService.js';
import { DI } from '@/di-symbols.js';
import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
export const meta = {
tags: ['admin'],
@ -40,8 +41,8 @@ export const meta = {
optional: false, nullable: true,
},
host: {
type: 'null',
optional: false,
type: 'string',
optional: false, nullable: true,
description: 'The local host is represented with `null`. The field exists for compatibility with other API endpoints that return files.',
},
url: {
@ -71,6 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.emojisRepository)
private emojisRepository: EmojisRepository,
private emojiEntityService: EmojiEntityService,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {

View file

@ -47,6 +47,14 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
enableTurnstile: {
type: 'boolean',
optional: false, nullable: false,
},
turnstileSiteKey: {
type: 'string',
optional: false, nullable: true,
},
swPublickey: {
type: 'string',
optional: false, nullable: true,
@ -197,6 +205,10 @@ export const meta = {
type: 'string',
optional: true, nullable: true,
},
turnstileSecretKey: {
type: 'string',
optional: true, nullable: true,
}
sensitiveMediaDetection: {
type: 'string',
optional: true, nullable: false,
@ -374,6 +386,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
hcaptchaSiteKey: instance.hcaptchaSiteKey,
enableRecaptcha: instance.enableRecaptcha,
recaptchaSiteKey: instance.recaptchaSiteKey,
enableTurnstile: instance.enableTurnstile,
turnstileSiteKey: instance.turnstileSiteKey,
swPublickey: instance.swPublicKey,
themeColor: instance.themeColor,
mascotImageUrl: instance.mascotImageUrl,
@ -400,6 +414,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
blockedHosts: instance.blockedHosts,
hcaptchaSecretKey: instance.hcaptchaSecretKey,
recaptchaSecretKey: instance.recaptchaSecretKey,
turnstileSecretKey: instance.turnstileSecretKey,
sensitiveMediaDetection: instance.sensitiveMediaDetection,
sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity,
setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically,

View file

@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { PromoNotesRepository } from '@/models/index.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';

View file

@ -1,7 +1,7 @@
import { URL } from 'node:url';
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DeliverQueue } from '@/core/queue/QueueModule.js';
import type { DeliverQueue } from '@/core/queue/QueueModule.js';
export const meta = {
tags: ['admin'],

View file

@ -1,7 +1,7 @@
import { URL } from 'node:url';
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { InboxQueue } from '@/core/queue/QueueModule.js';
import type { InboxQueue } from '@/core/queue/QueueModule.js';
export const meta = {
tags: ['admin'],

View file

@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, WebhookDeliverQueue } from '@/core/queue/QueueModule.js';
import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, WebhookDeliverQueue } from '@/core/queue/QueueModule.js';
export const meta = {
tags: ['admin'],

View file

@ -3,6 +3,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import type { ModerationLogsRepository } from '@/models/index.js';
import { QueryService } from '@/core/QueryService.js';
import { DI } from '@/di-symbols.js';
import { ModerationLogEntityService } from '@/core/entities/ModerationLogEntityService.js';
export const meta = {
tags: ['admin'],
@ -67,6 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.moderationLogsRepository)
private moderationLogsRepository: ModerationLogsRepository,
private moderationLogEntityService: ModerationLogEntityService,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {

View file

@ -7,6 +7,7 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
import { UserSuspendService } from '@/core/UserSuspendService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
export const meta = {
tags: ['admin'],
@ -36,6 +37,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.notificationsRepository)
private notificationsRepository: NotificationsRepository,
private userEntityService: UserEntityService,
private userFollowingService: UserFollowingService,
private userSuspendService: UserSuspendService,
private moderationLogService: ModerationLogService,

View file

@ -52,6 +52,9 @@ export const paramDef = {
enableRecaptcha: { type: 'boolean' },
recaptchaSiteKey: { type: 'string', nullable: true },
recaptchaSecretKey: { type: 'string', nullable: true },
enableTurnstile: { type: 'boolean' },
turnstileSiteKey: { type: 'string', nullable: true },
turnstileSecretKey: { type: 'string', nullable: true },
sensitiveMediaDetection: { type: 'string', enum: ['none', 'all', 'local', 'remote'] },
sensitiveMediaDetectionSensitivity: { type: 'string', enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'] },
setSensitiveFlagAutomatically: { type: 'boolean' },
@ -231,6 +234,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
set.recaptchaSecretKey = ps.recaptchaSecretKey;
}
if (ps.enableTurnstile !== undefined) {
set.enableTurnstile = ps.enableTurnstile;
}
if (ps.turnstileSiteKey !== undefined) {
set.turnstileSiteKey = ps.turnstileSiteKey;
}
if (ps.turnstileSecretKey !== undefined) {
set.turnstileSecretKey = ps.turnstileSecretKey;
}
if (ps.sensitiveMediaDetection !== undefined) {
set.sensitiveMediaDetection = ps.sensitiveMediaDetection;
}

View file

@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { NotesRepository, AntennaNotesRepository } from '@/models/index.js';
import type { NotesRepository, AntennaNotesRepository, AntennasRepository } from '@/models/index.js';
import { QueryService } from '@/core/QueryService.js';
import { NoteReadService } from '@/core/NoteReadService.js';
import { DI } from '@/di-symbols.js';

View file

@ -6,7 +6,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserBlockingService } from '@/core/UserBlockingService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['account'],

View file

@ -6,7 +6,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserBlockingService } from '@/core/UserBlockingService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['account'],

View file

@ -44,7 +44,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private globalEventService: GlobalEventService,
) {
super(meta, paramDef, async (ps, me) => {
const channel = await Channels.findOneBy({
const channel = await this.channelsRepository.findOneBy({
id: ps.channelId,
});

View file

@ -4,7 +4,7 @@ import { IdService } from '@/core/IdService.js';
import { DI } from '@/di-symbols.js';
import type { ClipNotesRepository, ClipsRepository } from '@/models/index.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['account', 'notes', 'clips'],

View file

@ -3,7 +3,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import type { ClipNotesRepository, ClipsRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['account', 'notes', 'clips'],

View file

@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ApPersonService } from '@/core/remote/activitypub/models/ApPersonService.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['federation'],

View file

@ -7,7 +7,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['following', 'users'],

View file

@ -6,7 +6,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['following', 'users'],

View file

@ -6,7 +6,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['following', 'users'],

View file

@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { ApiError } from '../../../error.js';

View file

@ -1,10 +1,9 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { FollowingsRepository } from '@/models/index.js';
import type { UsersRepository } from '@/models/index.js';
import type { FollowingsRepository, UsersRepository } from '@/models/index.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';

View file

@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { ApiError } from '../../../error.js';

View file

@ -1,4 +1,5 @@
import { Inject, Injectable } from '@nestjs/common';
import { IsNull, Not } from 'typeorm';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { AccessTokensRepository } from '@/models/index.js';
import { AppEntityService } from '@/core/entities/AppEntityService.js';
@ -34,6 +35,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const tokens = await this.accessTokensRepository.find({
where: {
userId: me.id,
appId: Not(IsNull()),
},
take: ps.limit,
skip: ps.offset,
@ -42,7 +44,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
},
});
return await Promise.all(tokens.map(token => this.appEntityService.pack(token.appId, me, {
return await Promise.all(tokens.map(token => this.appEntityService.pack(token.appId!, me, {
detail: true,
})));
});

View file

@ -78,7 +78,7 @@ export const paramDef = {
description: { ...descriptionSchema, nullable: true },
location: { ...locationSchema, nullable: true },
birthday: { ...birthdaySchema, nullable: true },
lang: { type: 'string', enum: [null, ...Object.keys(langmap)], nullable: true },
lang: { type: 'string', enum: [null, ...Object.keys(langmap)] as string[], nullable: true },
avatarId: { type: 'string', format: 'misskey:id', nullable: true },
bannerId: { type: 'string', format: 'misskey:id', nullable: true },
fields: {
@ -109,9 +109,7 @@ export const paramDef = {
alwaysMarkNsfw: { type: 'boolean' },
autoSensitive: { type: 'boolean' },
ffVisibility: { type: 'string', enum: ['public', 'followers', 'private'] },
pinnedPageId: { type: 'array', items: {
type: 'string', format: 'misskey:id',
} },
pinnedPageId: { type: 'string', format: 'misskey:id' },
mutedWords: { type: 'array' },
mutedInstances: { type: 'array', items: {
type: 'string',
@ -266,7 +264,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
// Publish meUpdated event
this.globalEventService.publishMainStream(user.id, 'meUpdated', iObj);
this.globalEventService.publishUserEvent(user.id, 'updateUserProfile', await this.userProfilesRepository.findOneBy({ userId: user.id }));
this.globalEventService.publishUserEvent(user.id, 'updateUserProfile', await this.userProfilesRepository.findOneByOrFail({ userId: user.id }));
// 鍵垢を解除したとき、溜まっていたフォローリクエストがあるならすべて承認
if (user.isLocked && ps.isLocked === false) {

View file

@ -1,15 +1,14 @@
import { Inject, Injectable } from '@nestjs/common';
import { Brackets } from 'typeorm';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UsersRepository } from '@/models/index.js';
import type { UserGroupsRepository, MessagingMessagesRepository, UserGroupJoiningsRepository } from '@/models/index.js';
import type { UsersRepository, UserGroupsRepository, MessagingMessagesRepository, UserGroupJoiningsRepository } from '@/models/index.js';
import { QueryService } from '@/core/QueryService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { MessagingMessageEntityService } from '@/core/entities/MessagingMessageEntityService.js';
import { MessagingService } from '@/core/MessagingService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['messaging'],

View file

@ -3,7 +3,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import type { BlockingsRepository, UserGroupJoiningsRepository, DriveFilesRepository, UserGroupsRepository } from '@/models/index.js';
import type { User } from '@/models/entities/User.js';
import type { UserGroup } from '@/models/entities/UserGroup.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { MessagingService } from '@/core/MessagingService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';

View file

@ -119,6 +119,14 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
enableTurnstile: {
type: 'boolean',
optional: false, nullable: false,
},
turnstileSiteKey: {
type: 'string',
optional: false, nullable: true,
},
swPublickey: {
type: 'string',
optional: false, nullable: true,
@ -372,6 +380,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
hcaptchaSiteKey: instance.hcaptchaSiteKey,
enableRecaptcha: instance.enableRecaptcha,
recaptchaSiteKey: instance.recaptchaSiteKey,
enableTurnstile: instance.enableTurnstile,
turnstileSiteKey: instance.turnstileSiteKey,
swPublickey: instance.swPublicKey,
themeColor: instance.themeColor,
mascotImageUrl: instance.mascotImageUrl,
@ -423,6 +433,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
elasticsearch: this.config.elasticsearch ? true : false,
hcaptcha: instance.enableHcaptcha,
recaptcha: instance.enableRecaptcha,
turnstile: instance.enableTurnstile,
objectStorage: instance.useObjectStorage,
twitter: instance.enableTwitterIntegration,
github: instance.enableGithubIntegration,

View file

@ -6,7 +6,7 @@ import type { Muting } from '@/models/entities/Muting.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['account'],

View file

@ -4,7 +4,7 @@ import type { MutingsRepository } from '@/models/index.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['account'],

View file

@ -5,7 +5,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['clips', 'notes'],

View file

@ -5,7 +5,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['notes'],

View file

@ -5,7 +5,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteDeleteService } from '@/core/NoteDeleteService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['notes'],

View file

@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import type { NoteFavoritesRepository } from '@/models/index.js';
import { IdService } from '@/core/IdService.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';

View file

@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { DI } from '@/di-symbols.js';
import type { NoteFavoritesRepository } from '@/models/index.js';
import { ApiError } from '../../../error.js';

View file

@ -4,7 +4,7 @@ import type { UsersRepository, BlockingsRepository, PollsRepository, PollVotesRe
import type { IRemoteUser } from '@/models/entities/User.js';
import { IdService } from '@/core/IdService.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { QueueService } from '@/core/QueueService.js';
import { PollService } from '@/core/PollService.js';
import { ApRendererService } from '@/core/remote/activitypub/ApRendererService.js';

View file

@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { ReactionService } from '@/core/ReactionService.js';
import { ApiError } from '../../../error.js';

View file

@ -1,7 +1,7 @@
import ms from 'ms';
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { ReactionService } from '@/core/ReactionService.js';
import { ApiError } from '../../../error.js';

View file

@ -5,7 +5,7 @@ import { QueryService } from '@/core/QueryService.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['notes'],

View file

@ -4,7 +4,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['notes'],

View file

@ -16,10 +16,6 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
isWatching: {
type: 'boolean',
optional: false, nullable: false,
},
isMutedThread: {
type: 'boolean',
optional: false, nullable: false,

View file

@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import type { NotesRepository, NoteThreadMutingsRepository } from '@/models/index.js';
import { IdService } from '@/core/IdService.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { NoteReadService } from '@/core/NoteReadService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';

View file

@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import type { NoteThreadMutingsRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';

View file

@ -9,7 +9,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { MetaService } from '@/core/MetaService.js';
import { HttpRequestService } from '@/core/HttpRequestService.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['notes'],

View file

@ -5,7 +5,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteDeleteService } from '@/core/NoteDeleteService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['notes'],

View file

@ -4,7 +4,7 @@ import { IdService } from '@/core/IdService.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['notes'],

View file

@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { IsNull } from 'typeorm';
import type { InstancesRepository, NotesRepository, UsersRepository } from '@/models/index.js';
import type { InstancesRepository, NoteReactionsRepository, NotesRepository, UsersRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';

View file

@ -6,7 +6,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '../../common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
export const meta = {
tags: ['users'],

View file

@ -3,7 +3,7 @@ import type { UserGroupsRepository, UserGroupJoiningsRepository, UserGroupInvita
import { IdService } from '@/core/IdService.js';
import type { UserGroupInvitation } from '@/models/entities/UserGroupInvitation.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { CreateNotificationService } from '@/core/CreateNotificationService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';

View file

@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import type { UserGroupsRepository, UserGroupJoiningsRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';

View file

@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import type { UserGroupsRepository, UserGroupJoiningsRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { UserGroupEntityService } from '@/core/entities/UserGroupEntityService.js';
import { GetterService } from '@/server/api/common/GetterService.js';
import { GetterService } from '@/server/api/GetterService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';

Some files were not shown because too many files have changed in this diff Show more