Skip to content

Commit

Permalink
Merge tag '2024.3.1-io.4b' into host
Browse files Browse the repository at this point in the history
  • Loading branch information
u1-liquid committed Mar 30, 2024
2 parents 1f209d0 + 70538fd commit 1c111ae
Show file tree
Hide file tree
Showing 19 changed files with 1,155 additions and 1,160 deletions.
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "misskey",
"version": "2024.3.1-host.4a",
"version": "2024.3.1-host.4b",
"codename": "nasubi",
"repository": {
"type": "git",
"url": "https://github.com/MisskeyIO/misskey.git"
},
"packageManager": "[email protected].4",
"packageManager": "[email protected].5",
"workspaces": [
"packages/frontend",
"packages/backend",
Expand Down Expand Up @@ -49,20 +49,20 @@
"@tensorflow/tfjs-core": "4.17.0",
"chokidar": "3.6.0",
"lodash": "4.17.21",
"sharp": "0.33.2"
"sharp": "0.33.3"
},
"dependencies": {
"cssnano": "6.1.1",
"cssnano": "6.1.2",
"execa": "8.0.1",
"js-yaml": "4.1.0",
"postcss": "8.4.38",
"terser": "5.29.2",
"terser": "5.30.0",
"typescript": "5.4.3"
},
"devDependencies": {
"@types/node": "20.11.30",
"@typescript-eslint/eslint-plugin": "7.3.1",
"@typescript-eslint/parser": "7.3.1",
"@types/node": "20.12.2",
"@typescript-eslint/eslint-plugin": "7.4.0",
"@typescript-eslint/parser": "7.4.0",
"cross-env": "7.0.3",
"cypress": "13.7.1",
"eslint": "8.57.0",
Expand Down
40 changes: 20 additions & 20 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,41 +66,41 @@
},
"dependencies": {
"@authenio/samlify-node-xmllint": "2.0.0",
"@aws-sdk/client-s3": "3.537.0",
"@aws-sdk/lib-storage": "3.537.0",
"@bull-board/api": "5.15.1",
"@bull-board/fastify": "5.15.1",
"@bull-board/ui": "5.15.1",
"@discordapp/twemoji": "15.0.2",
"@aws-sdk/client-s3": "3.540.0",
"@aws-sdk/lib-storage": "3.540.0",
"@bull-board/api": "5.15.3",
"@bull-board/fastify": "5.15.3",
"@bull-board/ui": "5.15.3",
"@discordapp/twemoji": "15.0.3",
"@fastify/accepts": "4.3.0",
"@fastify/cookie": "9.3.1",
"@fastify/cors": "9.0.1",
"@fastify/express": "2.3.0",
"@fastify/formbody": "7.4.0",
"@fastify/http-proxy": "9.5.0",
"@fastify/multipart": "8.2.0",
"@fastify/static": "7.0.1",
"@fastify/static": "7.0.2",
"@fastify/view": "9.0.0",
"@misskey-dev/sharp-read-bmp": "1.2.0",
"@misskey-dev/summaly": "5.1.0",
"@nestjs/common": "10.3.4",
"@nestjs/core": "10.3.4",
"@nestjs/testing": "10.3.4",
"@nestjs/common": "10.3.7",
"@nestjs/core": "10.3.7",
"@nestjs/testing": "10.3.7",
"@peertube/http-signature": "1.7.0",
"@simplewebauthn/server": "9.0.3",
"@sinonjs/fake-timers": "11.2.2",
"@smithy/node-http-handler": "2.5.0",
"@swc/cli": "0.1.65",
"@swc/core": "1.3.107",
"@twemoji/parser": "15.0.0",
"@twemoji/parser": "15.1.0",
"accepts": "1.3.8",
"ajv": "8.12.0",
"archiver": "6.0.1",
"async-mutex": "0.4.1",
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
"body-parser": "1.20.2",
"bullmq": "5.4.4",
"bullmq": "5.4.6",
"cacheable-lookup": "7.0.0",
"cbor": "9.0.2",
"chalk": "5.3.0",
Expand Down Expand Up @@ -166,14 +166,14 @@
"ratelimiter": "3.4.1",
"re2": "1.20.10",
"redis-lock": "0.1.4",
"reflect-metadata": "0.2.1",
"reflect-metadata": "0.2.2",
"rename": "1.0.4",
"rss-parser": "3.13.0",
"rxjs": "7.8.1",
"samlify": "2.8.11",
"sanitize-html": "2.13.0",
"secure-json-parse": "2.7.0",
"sharp": "0.33.2",
"sharp": "0.33.3",
"slacc": "0.0.10",
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
Expand All @@ -194,7 +194,7 @@
"devDependencies": {
"@jest/globals": "29.7.0",
"@misskey-dev/eslint-plugin": "1.0.0",
"@nestjs/platform-express": "10.3.4",
"@nestjs/platform-express": "10.3.7",
"@simplewebauthn/types": "9.0.1",
"@swc/jest": "0.2.36",
"@types/accepts": "1.3.7",
Expand All @@ -213,11 +213,11 @@
"@types/jsrsasign": "10.5.13",
"@types/mime-types": "2.1.4",
"@types/ms": "0.7.34",
"@types/node": "20.11.30",
"@types/node": "20.12.2",
"@types/node-forge": "1.3.11",
"@types/nodemailer": "6.4.14",
"@types/oauth": "0.9.4",
"@types/oauth2orize": "1.11.4",
"@types/oauth2orize": "1.11.5",
"@types/oauth2orize-pkce": "0.1.2",
"@types/pg": "8.11.4",
"@types/pug": "2.0.10",
Expand All @@ -235,9 +235,9 @@
"@types/vary": "1.1.3",
"@types/web-push": "3.6.3",
"@types/ws": "8.5.10",
"@typescript-eslint/eslint-plugin": "7.3.1",
"@typescript-eslint/parser": "7.3.1",
"aws-sdk-client-mock": "3.0.1",
"@typescript-eslint/eslint-plugin": "7.4.0",
"@typescript-eslint/parser": "7.4.0",
"aws-sdk-client-mock": "4.0.0",
"cross-env": "7.0.3",
"eslint": "8.57.0",
"eslint-plugin-import": "2.29.1",
Expand Down
44 changes: 33 additions & 11 deletions packages/backend/src/core/DeleteAccountService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { Inject, Injectable } from '@nestjs/common';
import * as Redis from 'ioredis';
import { bindThis } from '@/decorators.js';
import { DI } from '@/di-symbols.js';
import type Logger from '@/logger.js';
Expand All @@ -20,6 +21,8 @@ export class DeleteAccountService {
public logger: Logger;

constructor(
@Inject(DI.redis)
private redisClient: Redis.Redis,
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,

Expand All @@ -29,7 +32,7 @@ export class DeleteAccountService {
private globalEventService: GlobalEventService,
private loggerService: LoggerService,
) {
this.logger = this.loggerService.getLogger('delete-account');
this.logger = this.loggerService.getLogger('account:delete');
}

@bindThis
Expand All @@ -39,19 +42,38 @@ export class DeleteAccountService {
const _user = await this.usersRepository.findOneByOrFail({ id: user.id });
if (_user.isRoot) throw new Error('cannot delete a root account');

// 物理削除する前にDelete activityを送信する
await this.userSuspendService.doPostSuspend(user).catch(err => this.logger.error(err));
// 5分間の間に同じアカウントに対して削除リクエストが複数回来た場合、最初のリクエストのみを処理する
const lock = await this.redisClient.set(`account:delete:lock:${user.id}`, Date.now(), 'EX', 60 * 5, 'NX');
if (lock === null) {
this.logger.warn(`Delete account is already in progress for ${user.id}`);
return;
}

this.queueService.createDeleteAccountJob(user, {
force: me ? await this.roleService.isModerator(me) : false,
soft: soft,
});
// noinspection ES6MissingAwait APIで呼び出される際にタイムアウトされないように
(async () => {
try {
// 物理削除する前にDelete activityを送信する
await this.userSuspendService.doPostSuspend(user).catch(err => this.logger.error(err));

await this.usersRepository.update(user.id, {
isDeleted: true,
});
// noinspection ES6MissingAwait
this.queueService.createDeleteAccountJob(user, {
force: me ? await this.roleService.isModerator(me) : false,
soft: soft,
});

await this.usersRepository.update(user.id, {
isDeleted: true,
});

this.globalEventService.publishInternalEvent('userChangeDeletedState', { id: user.id, isDeleted: true });
this.globalEventService.publishInternalEvent('userChangeDeletedState', { id: user.id, isDeleted: true });
} catch (err) {
this.logger.error(`Failed to delete account ${user.id}, request by ${me ? me.id : 'remote'} (soft: ${soft})`, { error: err });
// すでにcallstackから離れてるので、ここでエラーをthrowしても意味がない
} finally {
// 成功・失敗に関わらずロックを解除
await this.redisClient.unlink(`account:delete:lock:${user.id}`);
}
})();
}

@bindThis
Expand Down
5 changes: 3 additions & 2 deletions packages/backend/src/core/FetchInstanceMetadataService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ export class FetchInstanceMetadataService {
private logger: Logger;

constructor(
@Inject(DI.redis)
private redisClient: Redis.Redis,

private httpRequestService: HttpRequestService,
private loggerService: LoggerService,
private federatedInstanceService: FederatedInstanceService,
@Inject(DI.redis)
private redisClient: Redis.Redis,
) {
this.logger = this.loggerService.getLogger('metadata', 'cyan');
}
Expand Down
115 changes: 69 additions & 46 deletions packages/backend/src/core/SignupService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,50 @@
import { generateKeyPair } from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common';
import bcrypt from 'bcryptjs';
import * as Redis from 'ioredis';
import { DataSource, IsNull } from 'typeorm';
import { bindThis } from '@/decorators.js';
import { DI } from '@/di-symbols.js';
import type Logger from '@/logger.js';
import generateUserToken from '@/misc/generate-native-user-token.js';
import type { UsedUsernamesRepository, UsersRepository } from '@/models/_.js';
import { MiUser } from '@/models/User.js';
import { MiUserProfile } from '@/models/UserProfile.js';
import { IdService } from '@/core/IdService.js';
import { MiUserKeypair } from '@/models/UserKeypair.js';
import { MiUsedUsername } from '@/models/UsedUsername.js';
import generateUserToken from '@/misc/generate-native-user-token.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { IdService } from '@/core/IdService.js';
import { MetaService } from '@/core/MetaService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { LoggerService } from '@/core/LoggerService.js';
import { InstanceActorService } from '@/core/InstanceActorService.js';
import { bindThis } from '@/decorators.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import UsersChart from '@/core/chart/charts/users.js';
import { UtilityService } from '@/core/UtilityService.js';
import { MetaService } from '@/core/MetaService.js';

@Injectable()
export class SignupService {
public logger: Logger;

constructor(
@Inject(DI.db)
private db: DataSource,
@Inject(DI.redis)
private redisClient: Redis.Redis,

@Inject(DI.usersRepository)
private usersRepository: UsersRepository,

@Inject(DI.usedUsernamesRepository)
private usedUsernamesRepository: UsedUsernamesRepository,

private utilityService: UtilityService,
private userEntityService: UserEntityService,
private idService: IdService,
private metaService: MetaService,
private utilityService: UtilityService,
private loggerService: LoggerService,
private instanceActorService: InstanceActorService,
private userEntityService: UserEntityService,
private usersChart: UsersChart,
) {
this.logger = this.loggerService.getLogger('account:create');
}

@bindThis
Expand Down Expand Up @@ -110,47 +119,61 @@ export class SignupService {
err ? rej(err) : res([publicKey, privateKey]),
));

let account!: MiUser;
// 5分間のロックを取得
const lock = await this.redisClient.set(`account:create:lock:${username.toLowerCase()}`, Date.now(), 'EX', 60 * 5, 'NX');
if (lock === null) {
throw new Error('ALREADY_IN_PROGRESS');
}

// Start transaction
await this.db.transaction(async transactionalEntityManager => {
const exist = await transactionalEntityManager.findOneBy(MiUser, {
usernameLower: username.toLowerCase(),
host: IsNull(),
try {
let account!: MiUser;

// Start transaction
await this.db.transaction(async transactionalEntityManager => {
const exist = await transactionalEntityManager.findOneBy(MiUser, {
usernameLower: username.toLowerCase(),
host: IsNull(),
});

if (exist) throw new Error(' the username is already used');

account = await transactionalEntityManager.save(new MiUser({
id: this.idService.gen(),
username: username,
usernameLower: username.toLowerCase(),
host: this.utilityService.toPunyNullable(host),
token: secret,
isRoot: isTheFirstUser,
}));

await transactionalEntityManager.save(new MiUserKeypair({
publicKey: keyPair[0],
privateKey: keyPair[1],
userId: account.id,
}));

await transactionalEntityManager.save(new MiUserProfile({
userId: account.id,
autoAcceptFollowed: true,
password: hash,
}));

await transactionalEntityManager.save(new MiUsedUsername({
createdAt: new Date(),
username: username.toLowerCase(),
}));
});

if (exist) throw new Error(' the username is already used');

account = await transactionalEntityManager.save(new MiUser({
id: this.idService.gen(),
username: username,
usernameLower: username.toLowerCase(),
host: this.utilityService.toPunyNullable(host),
token: secret,
isRoot: isTheFirstUser,
}));

await transactionalEntityManager.save(new MiUserKeypair({
publicKey: keyPair[0],
privateKey: keyPair[1],
userId: account.id,
}));

await transactionalEntityManager.save(new MiUserProfile({
userId: account.id,
autoAcceptFollowed: true,
password: hash,
}));

await transactionalEntityManager.save(new MiUsedUsername({
createdAt: new Date(),
username: username.toLowerCase(),
}));
});

this.usersChart.update(account, true);

return { account, secret };
this.usersChart.update(account, true);

return { account, secret };
} catch (err) {
this.logger.error(`Failed to create account ${username}`, { error: err });
throw err;
} finally {
// 成功・失敗に関わらずロックを解除
await this.redisClient.unlink(`account:create:lock:${username.toLowerCase()}`);
}
}
}

Loading

0 comments on commit 1c111ae

Please sign in to comment.