upd: swap bcrypt to argon2, add misskey-js to dev, auto load replies
This commit is contained in:
		
							parent
							
								
									03b5acf17f
								
							
						
					
					
						commit
						7111c6c90b
					
				
					 20 changed files with 105 additions and 43 deletions
				
			
		| 
						 | 
					@ -58,7 +58,6 @@
 | 
				
			||||||
	"dependencies": {
 | 
						"dependencies": {
 | 
				
			||||||
		"@aws-sdk/client-s3": "3.412.0",
 | 
							"@aws-sdk/client-s3": "3.412.0",
 | 
				
			||||||
		"@aws-sdk/lib-storage": "3.412.0",
 | 
							"@aws-sdk/lib-storage": "3.412.0",
 | 
				
			||||||
		"@smithy/node-http-handler": "2.1.5",
 | 
					 | 
				
			||||||
		"@bull-board/api": "5.8.4",
 | 
							"@bull-board/api": "5.8.4",
 | 
				
			||||||
		"@bull-board/fastify": "5.8.4",
 | 
							"@bull-board/fastify": "5.8.4",
 | 
				
			||||||
		"@bull-board/ui": "5.8.4",
 | 
							"@bull-board/ui": "5.8.4",
 | 
				
			||||||
| 
						 | 
					@ -77,11 +76,13 @@
 | 
				
			||||||
		"@peertube/http-signature": "1.7.0",
 | 
							"@peertube/http-signature": "1.7.0",
 | 
				
			||||||
		"@simplewebauthn/server": "8.1.1",
 | 
							"@simplewebauthn/server": "8.1.1",
 | 
				
			||||||
		"@sinonjs/fake-timers": "11.1.0",
 | 
							"@sinonjs/fake-timers": "11.1.0",
 | 
				
			||||||
 | 
							"@smithy/node-http-handler": "2.1.5",
 | 
				
			||||||
		"@swc/cli": "0.1.62",
 | 
							"@swc/cli": "0.1.62",
 | 
				
			||||||
		"@swc/core": "1.3.86",
 | 
							"@swc/core": "1.3.86",
 | 
				
			||||||
		"accepts": "1.3.8",
 | 
							"accepts": "1.3.8",
 | 
				
			||||||
		"ajv": "8.12.0",
 | 
							"ajv": "8.12.0",
 | 
				
			||||||
		"archiver": "6.0.1",
 | 
							"archiver": "6.0.1",
 | 
				
			||||||
 | 
							"argon2": "^0.31.1",
 | 
				
			||||||
		"async-mutex": "0.4.0",
 | 
							"async-mutex": "0.4.0",
 | 
				
			||||||
		"bcryptjs": "2.4.3",
 | 
							"bcryptjs": "2.4.3",
 | 
				
			||||||
		"blurhash": "2.0.5",
 | 
							"blurhash": "2.0.5",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { randomUUID } from 'node:crypto';
 | 
					import { randomUUID } from 'node:crypto';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
import { IsNull, DataSource } from 'typeorm';
 | 
					import { IsNull, DataSource } from 'typeorm';
 | 
				
			||||||
import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
 | 
					import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
 | 
				
			||||||
import { MiUser } from '@/models/User.js';
 | 
					import { MiUser } from '@/models/User.js';
 | 
				
			||||||
| 
						 | 
					@ -32,8 +33,8 @@ export class CreateSystemUserService {
 | 
				
			||||||
		const password = randomUUID();
 | 
							const password = randomUUID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Generate hash of password
 | 
							// Generate hash of password
 | 
				
			||||||
		const salt = await bcrypt.genSalt(8);
 | 
							//const salt = await bcrypt.genSalt(8);
 | 
				
			||||||
		const hash = await bcrypt.hash(password, salt);
 | 
							const hash = await argon2.hash(password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Generate secret
 | 
							// Generate secret
 | 
				
			||||||
		const secret = generateNativeUserToken();
 | 
							const secret = generateNativeUserToken();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { generateKeyPair } from 'node:crypto';
 | 
					import { generateKeyPair } from 'node:crypto';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { DataSource, IsNull } from 'typeorm';
 | 
					import { DataSource, IsNull } from 'typeorm';
 | 
				
			||||||
import { DI } from '@/di-symbols.js';
 | 
					import { DI } from '@/di-symbols.js';
 | 
				
			||||||
import type { UsedUsernamesRepository, UsersRepository } from '@/models/_.js';
 | 
					import type { UsedUsernamesRepository, UsersRepository } from '@/models/_.js';
 | 
				
			||||||
| 
						 | 
					@ -64,8 +65,8 @@ export class SignupService {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Generate hash of password
 | 
								// Generate hash of password
 | 
				
			||||||
			const salt = await bcrypt.genSalt(8);
 | 
								//const salt = await bcrypt.genSalt(8);
 | 
				
			||||||
			hash = await bcrypt.hash(password, salt);
 | 
								hash = await argon2.hash(password);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Generate secret
 | 
							// Generate secret
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,8 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import * as OTPAuth from 'otpauth';
 | 
					import * as OTPAuth from 'otpauth';
 | 
				
			||||||
import { IsNull } from 'typeorm';
 | 
					import { IsNull } from 'typeorm';
 | 
				
			||||||
import { DI } from '@/di-symbols.js';
 | 
					import { DI } from '@/di-symbols.js';
 | 
				
			||||||
| 
						 | 
					@ -121,7 +122,7 @@ export class SigninApiService {
 | 
				
			||||||
		const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
 | 
							const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Compare password
 | 
							// Compare password
 | 
				
			||||||
		const same = await bcrypt.compare(password, profile.password!);
 | 
							const same = await argon2.verify(profile.password!, password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const fail = async (status?: number, failure?: { id: string }) => {
 | 
							const fail = async (status?: number, failure?: { id: string }) => {
 | 
				
			||||||
		// Append signin history
 | 
							// Append signin history
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,8 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { IsNull } from 'typeorm';
 | 
					import { IsNull } from 'typeorm';
 | 
				
			||||||
import { DI } from '@/di-symbols.js';
 | 
					import { DI } from '@/di-symbols.js';
 | 
				
			||||||
import type { RegistrationTicketsRepository, UsedUsernamesRepository, UserPendingsRepository, UserProfilesRepository, UsersRepository, MiRegistrationTicket } from '@/models/_.js';
 | 
					import type { RegistrationTicketsRepository, UsedUsernamesRepository, UserPendingsRepository, UserProfilesRepository, UsersRepository, MiRegistrationTicket } from '@/models/_.js';
 | 
				
			||||||
| 
						 | 
					@ -160,8 +161,8 @@ export class SignupApiService {
 | 
				
			||||||
			const code = secureRndstr(16, { chars: L_CHARS });
 | 
								const code = secureRndstr(16, { chars: L_CHARS });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Generate hash of password
 | 
								// Generate hash of password
 | 
				
			||||||
			const salt = await bcrypt.genSalt(8);
 | 
								//const salt = await bcrypt.genSalt(8);
 | 
				
			||||||
			const hash = await bcrypt.hash(password, salt);
 | 
								const hash = await argon2.hash(password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			const pendingUser = await this.userPendingsRepository.insert({
 | 
								const pendingUser = await this.userPendingsRepository.insert({
 | 
				
			||||||
				id: this.idService.genId(),
 | 
									id: this.idService.genId(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,8 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
import type { UsersRepository, UserProfilesRepository } from '@/models/_.js';
 | 
					import type { UsersRepository, UserProfilesRepository } from '@/models/_.js';
 | 
				
			||||||
import { DI } from '@/di-symbols.js';
 | 
					import { DI } from '@/di-symbols.js';
 | 
				
			||||||
| 
						 | 
					@ -61,7 +62,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			||||||
			const passwd = secureRndstr(8);
 | 
								const passwd = secureRndstr(8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Generate hash of password
 | 
								// Generate hash of password
 | 
				
			||||||
			const hash = bcrypt.hashSync(passwd);
 | 
								const hash = await argon2.hash(passwd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			await this.userProfilesRepository.update({
 | 
								await this.userProfilesRepository.update({
 | 
				
			||||||
				userId: user.id,
 | 
									userId: user.id,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,8 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
 | 
					import { UserEntityService } from '@/core/entities/UserEntityService.js';
 | 
				
			||||||
| 
						 | 
					@ -61,7 +62,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 | 
				
			||||||
			const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
								const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Compare password
 | 
								// Compare password
 | 
				
			||||||
			const same = await bcrypt.compare(ps.password, profile.password ?? '');
 | 
								const same = await argon2.verify(profile.password ?? '', ps.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!same) {
 | 
								if (!same) {
 | 
				
			||||||
				throw new ApiError(meta.errors.incorrectPassword);
 | 
									throw new ApiError(meta.errors.incorrectPassword);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,8 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
import type { UserProfilesRepository } from '@/models/_.js';
 | 
					import type { UserProfilesRepository } from '@/models/_.js';
 | 
				
			||||||
| 
						 | 
					@ -67,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Compare password
 | 
								// Compare password
 | 
				
			||||||
			const same = await bcrypt.compare(ps.password, profile.password ?? '');
 | 
								const same = await argon2.verify(profile.password ?? '', ps.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!same) {
 | 
								if (!same) {
 | 
				
			||||||
				throw new ApiError(meta.errors.incorrectPassword);
 | 
									throw new ApiError(meta.errors.incorrectPassword);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,8 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import * as OTPAuth from 'otpauth';
 | 
					import * as OTPAuth from 'otpauth';
 | 
				
			||||||
import * as QRCode from 'qrcode';
 | 
					import * as QRCode from 'qrcode';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
| 
						 | 
					@ -48,7 +49,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			||||||
			const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
								const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Compare password
 | 
								// Compare password
 | 
				
			||||||
			const same = await bcrypt.compare(ps.password, profile.password ?? '');
 | 
								const same = await argon2.verify(profile.password ?? '', ps.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!same) {
 | 
								if (!same) {
 | 
				
			||||||
				throw new ApiError(meta.errors.incorrectPassword);
 | 
									throw new ApiError(meta.errors.incorrectPassword);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,8 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
import type { UserProfilesRepository, UserSecurityKeysRepository } from '@/models/_.js';
 | 
					import type { UserProfilesRepository, UserSecurityKeysRepository } from '@/models/_.js';
 | 
				
			||||||
| 
						 | 
					@ -51,7 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			||||||
			const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
								const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Compare password
 | 
								// Compare password
 | 
				
			||||||
			const same = await bcrypt.compare(ps.password, profile.password ?? '');
 | 
								const same = await argon2.verify(profile.password ?? '', ps.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!same) {
 | 
								if (!same) {
 | 
				
			||||||
				throw new ApiError(meta.errors.incorrectPassword);
 | 
									throw new ApiError(meta.errors.incorrectPassword);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,8 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
 | 
					import { UserEntityService } from '@/core/entities/UserEntityService.js';
 | 
				
			||||||
| 
						 | 
					@ -47,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			||||||
			const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
								const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Compare password
 | 
								// Compare password
 | 
				
			||||||
			const same = await bcrypt.compare(ps.password, profile.password ?? '');
 | 
								const same = await argon2.verify(profile.password ?? '', ps.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!same) {
 | 
								if (!same) {
 | 
				
			||||||
				throw new ApiError(meta.errors.incorrectPassword);
 | 
									throw new ApiError(meta.errors.incorrectPassword);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
import type { UserSecurityKeysRepository } from '@/models/_.js';
 | 
					import type { UserSecurityKeysRepository } from '@/models/_.js';
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,8 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
import type { UserProfilesRepository } from '@/models/_.js';
 | 
					import type { UserProfilesRepository } from '@/models/_.js';
 | 
				
			||||||
| 
						 | 
					@ -34,15 +35,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			||||||
			const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
								const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Compare password
 | 
								// Compare password
 | 
				
			||||||
			const same = await bcrypt.compare(ps.currentPassword, profile.password!);
 | 
								const same = await argon2.verify(profile.password!, ps.currentPassword);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!same) {
 | 
								if (!same) {
 | 
				
			||||||
				throw new Error('incorrect password');
 | 
									throw new Error('incorrect password');
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Generate hash of password
 | 
								// Generate hash of password
 | 
				
			||||||
			const salt = await bcrypt.genSalt(8);
 | 
								//const salt = await bcrypt.genSalt(8);
 | 
				
			||||||
			const hash = await bcrypt.hash(ps.newPassword, salt);
 | 
								const hash = await argon2.hash(ps.newPassword);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			await this.userProfilesRepository.update(me.id, {
 | 
								await this.userProfilesRepository.update(me.id, {
 | 
				
			||||||
				password: hash,
 | 
									password: hash,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,8 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import type { UsersRepository, UserProfilesRepository } from '@/models/_.js';
 | 
					import type { UsersRepository, UserProfilesRepository } from '@/models/_.js';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
| 
						 | 
					@ -43,7 +44,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Compare password
 | 
								// Compare password
 | 
				
			||||||
			const same = await bcrypt.compare(ps.password, profile.password!);
 | 
								const same = await argon2.verify(profile.password!, ps.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!same) {
 | 
								if (!same) {
 | 
				
			||||||
				throw new Error('incorrect password');
 | 
									throw new Error('incorrect password');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,8 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
import type { UsersRepository, UserProfilesRepository } from '@/models/_.js';
 | 
					import type { UsersRepository, UserProfilesRepository } from '@/models/_.js';
 | 
				
			||||||
| 
						 | 
					@ -43,7 +44,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			||||||
			const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
								const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Compare password
 | 
								// Compare password
 | 
				
			||||||
			const same = await bcrypt.compare(ps.password, profile.password!);
 | 
								const same = await argon2.verify(profile.password!, ps.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!same) {
 | 
								if (!same) {
 | 
				
			||||||
				throw new Error('incorrect password');
 | 
									throw new Error('incorrect password');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import ms from 'ms';
 | 
					import ms from 'ms';
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
import type { UserProfilesRepository } from '@/models/_.js';
 | 
					import type { UserProfilesRepository } from '@/models/_.js';
 | 
				
			||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
 | 
					import { UserEntityService } from '@/core/entities/UserEntityService.js';
 | 
				
			||||||
| 
						 | 
					@ -67,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			||||||
			const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
								const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Compare password
 | 
								// Compare password
 | 
				
			||||||
			const same = await bcrypt.compare(ps.password, profile.password!);
 | 
								const same = await argon2.verify(profile.password!, ps.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!same) {
 | 
								if (!same) {
 | 
				
			||||||
				throw new ApiError(meta.errors.incorrectPassword);
 | 
									throw new ApiError(meta.errors.incorrectPassword);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,8 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt from 'bcryptjs';
 | 
					//import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import * as argon2 from 'argon2';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import { Inject, Injectable } from '@nestjs/common';
 | 
				
			||||||
import type { UserProfilesRepository, PasswordResetRequestsRepository } from '@/models/_.js';
 | 
					import type { UserProfilesRepository, PasswordResetRequestsRepository } from '@/models/_.js';
 | 
				
			||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
					import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
				
			||||||
| 
						 | 
					@ -50,8 +51,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Generate hash of password
 | 
								// Generate hash of password
 | 
				
			||||||
			const salt = await bcrypt.genSalt(8);
 | 
								//const salt = await bcrypt.genSalt(8);
 | 
				
			||||||
			const hash = await bcrypt.hash(ps.password, salt);
 | 
								const hash = await argon2.hash(ps.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			await this.userProfilesRepository.update(req.userId, {
 | 
								await this.userProfilesRepository.update(req.userId, {
 | 
				
			||||||
				password: hash,
 | 
									password: hash,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -501,6 +501,7 @@ function loadReplies() {
 | 
				
			||||||
		replies.value = res;
 | 
							replies.value = res;
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					loadReplies();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const conversationLoaded = ref(false);
 | 
					const conversationLoaded = ref(false);
 | 
				
			||||||
function loadConversation() {
 | 
					function loadConversation() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										49
									
								
								pnpm-lock.yaml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										49
									
								
								pnpm-lock.yaml
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -134,6 +134,9 @@ importers:
 | 
				
			||||||
      archiver:
 | 
					      archiver:
 | 
				
			||||||
        specifier: 6.0.1
 | 
					        specifier: 6.0.1
 | 
				
			||||||
        version: 6.0.1
 | 
					        version: 6.0.1
 | 
				
			||||||
 | 
					      argon2:
 | 
				
			||||||
 | 
					        specifier: ^0.31.1
 | 
				
			||||||
 | 
					        version: 0.31.1
 | 
				
			||||||
      async-mutex:
 | 
					      async-mutex:
 | 
				
			||||||
        specifier: 0.4.0
 | 
					        specifier: 0.4.0
 | 
				
			||||||
        version: 0.4.0
 | 
					        version: 0.4.0
 | 
				
			||||||
| 
						 | 
					@ -4317,6 +4320,24 @@ packages:
 | 
				
			||||||
    engines: {node: '>=8'}
 | 
					    engines: {node: '>=8'}
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /@mapbox/node-pre-gyp@1.0.11:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      detect-libc: 2.0.2
 | 
				
			||||||
 | 
					      https-proxy-agent: 5.0.1
 | 
				
			||||||
 | 
					      make-dir: 3.1.0
 | 
				
			||||||
 | 
					      node-fetch: 2.7.0
 | 
				
			||||||
 | 
					      nopt: 5.0.0
 | 
				
			||||||
 | 
					      npmlog: 5.0.1
 | 
				
			||||||
 | 
					      rimraf: 3.0.2
 | 
				
			||||||
 | 
					      semver: 7.5.4
 | 
				
			||||||
 | 
					      tar: 6.1.13
 | 
				
			||||||
 | 
					    transitivePeerDependencies:
 | 
				
			||||||
 | 
					      - encoding
 | 
				
			||||||
 | 
					      - supports-color
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /@mapbox/node-pre-gyp@1.0.9:
 | 
					  /@mapbox/node-pre-gyp@1.0.9:
 | 
				
			||||||
    resolution: {integrity: sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==}
 | 
					    resolution: {integrity: sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==}
 | 
				
			||||||
    hasBin: true
 | 
					    hasBin: true
 | 
				
			||||||
| 
						 | 
					@ -4670,6 +4691,11 @@ packages:
 | 
				
			||||||
      sshpk: 1.17.0
 | 
					      sshpk: 1.17.0
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /@phc/format@1.0.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==}
 | 
				
			||||||
 | 
					    engines: {node: '>=10'}
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /@pkgjs/parseargs@0.11.0:
 | 
					  /@pkgjs/parseargs@0.11.0:
 | 
				
			||||||
    resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
 | 
					    resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
 | 
				
			||||||
    engines: {node: '>=14'}
 | 
					    engines: {node: '>=14'}
 | 
				
			||||||
| 
						 | 
					@ -7046,7 +7072,7 @@ packages:
 | 
				
			||||||
    hasBin: true
 | 
					    hasBin: true
 | 
				
			||||||
    peerDependencies:
 | 
					    peerDependencies:
 | 
				
			||||||
      '@swc/core': ^1.2.66
 | 
					      '@swc/core': ^1.2.66
 | 
				
			||||||
      chokidar: 3.5.3
 | 
					      chokidar: ^3.5.1
 | 
				
			||||||
    peerDependenciesMeta:
 | 
					    peerDependenciesMeta:
 | 
				
			||||||
      chokidar:
 | 
					      chokidar:
 | 
				
			||||||
        optional: true
 | 
					        optional: true
 | 
				
			||||||
| 
						 | 
					@ -8825,7 +8851,6 @@ packages:
 | 
				
			||||||
      delegates: 1.0.0
 | 
					      delegates: 1.0.0
 | 
				
			||||||
      readable-stream: 3.6.0
 | 
					      readable-stream: 3.6.0
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
    optional: true
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /are-we-there-yet@3.0.1:
 | 
					  /are-we-there-yet@3.0.1:
 | 
				
			||||||
    resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==}
 | 
					    resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==}
 | 
				
			||||||
| 
						 | 
					@ -8839,6 +8864,19 @@ packages:
 | 
				
			||||||
    resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
 | 
					    resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
 | 
				
			||||||
    dev: true
 | 
					    dev: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /argon2@0.31.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-ik2xnJrLXazya7m4Nz1XfBSRjXj8Koq8qF9PsQC8059p20ifWc9zx/hgU3ItZh/3TnwXkv0RbhvjodPkmFf0bg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=14.0.0'}
 | 
				
			||||||
 | 
					    requiresBuild: true
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@mapbox/node-pre-gyp': 1.0.11
 | 
				
			||||||
 | 
					      '@phc/format': 1.0.0
 | 
				
			||||||
 | 
					      node-addon-api: 7.0.0
 | 
				
			||||||
 | 
					    transitivePeerDependencies:
 | 
				
			||||||
 | 
					      - encoding
 | 
				
			||||||
 | 
					      - supports-color
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /argparse@1.0.10:
 | 
					  /argparse@1.0.10:
 | 
				
			||||||
    resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
 | 
					    resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
| 
						 | 
					@ -12111,7 +12149,6 @@ packages:
 | 
				
			||||||
      strip-ansi: 6.0.1
 | 
					      strip-ansi: 6.0.1
 | 
				
			||||||
      wide-align: 1.1.5
 | 
					      wide-align: 1.1.5
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
    optional: true
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /gauge@4.0.4:
 | 
					  /gauge@4.0.4:
 | 
				
			||||||
    resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
 | 
					    resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
 | 
				
			||||||
| 
						 | 
					@ -15005,6 +15042,10 @@ packages:
 | 
				
			||||||
  /node-addon-api@6.1.0:
 | 
					  /node-addon-api@6.1.0:
 | 
				
			||||||
    resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
 | 
					    resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /node-addon-api@7.0.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==}
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /node-bitmap@0.0.1:
 | 
					  /node-bitmap@0.0.1:
 | 
				
			||||||
    resolution: {integrity: sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA==}
 | 
					    resolution: {integrity: sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA==}
 | 
				
			||||||
    engines: {node: '>=v0.6.5'}
 | 
					    engines: {node: '>=v0.6.5'}
 | 
				
			||||||
| 
						 | 
					@ -15155,7 +15196,6 @@ packages:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      abbrev: 1.1.1
 | 
					      abbrev: 1.1.1
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
    optional: true
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /nopt@6.0.0:
 | 
					  /nopt@6.0.0:
 | 
				
			||||||
    resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==}
 | 
					    resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==}
 | 
				
			||||||
| 
						 | 
					@ -15224,7 +15264,6 @@ packages:
 | 
				
			||||||
      gauge: 3.0.2
 | 
					      gauge: 3.0.2
 | 
				
			||||||
      set-blocking: 2.0.0
 | 
					      set-blocking: 2.0.0
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
    optional: true
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /npmlog@6.0.2:
 | 
					  /npmlog@6.0.2:
 | 
				
			||||||
    resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==}
 | 
					    resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,12 @@ await execa('pnpm', ['build-assets'], {
 | 
				
			||||||
	stderr: process.stderr,
 | 
						stderr: process.stderr,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					await execa('pnpm', ['--filter', 'misskey-js', 'build'], {
 | 
				
			||||||
 | 
						cwd: _dirname + '/../',
 | 
				
			||||||
 | 
						stdout: process.stdout,
 | 
				
			||||||
 | 
						stderr: process.stderr,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
execa('pnpm', ['build-assets', '--watch'], {
 | 
					execa('pnpm', ['build-assets', '--watch'], {
 | 
				
			||||||
	cwd: _dirname + '/../',
 | 
						cwd: _dirname + '/../',
 | 
				
			||||||
	stdout: process.stdout,
 | 
						stdout: process.stdout,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue