diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2021-11-12 02:02:25 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2021-11-12 02:02:25 +0900 |
| commit | 0e4a111f81cceed275d9bec2695f6e401fb654d8 (patch) | |
| tree | 40874799472fa07416f17b50a398ac33b7771905 /packages/backend/src/server/api/common/signup.ts | |
| parent | update deps (diff) | |
| download | misskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.gz misskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.bz2 misskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.zip | |
refactoring
Resolve #7779
Diffstat (limited to 'packages/backend/src/server/api/common/signup.ts')
| -rw-r--r-- | packages/backend/src/server/api/common/signup.ts | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/packages/backend/src/server/api/common/signup.ts b/packages/backend/src/server/api/common/signup.ts new file mode 100644 index 0000000000..2ba0d8e479 --- /dev/null +++ b/packages/backend/src/server/api/common/signup.ts @@ -0,0 +1,113 @@ +import * as bcrypt from 'bcryptjs'; +import { generateKeyPair } from 'crypto'; +import generateUserToken from './generate-native-user-token'; +import { User } from '@/models/entities/user'; +import { Users, UsedUsernames } from '@/models/index'; +import { UserProfile } from '@/models/entities/user-profile'; +import { getConnection } from 'typeorm'; +import { genId } from '@/misc/gen-id'; +import { toPunyNullable } from '@/misc/convert-host'; +import { UserKeypair } from '@/models/entities/user-keypair'; +import { usersChart } from '@/services/chart/index'; +import { UsedUsername } from '@/models/entities/used-username'; + +export async function signup(opts: { + username: User['username']; + password?: string | null; + passwordHash?: UserProfile['password'] | null; + host?: string | null; +}) { + const { username, password, passwordHash, host } = opts; + let hash = passwordHash; + + // Validate username + if (!Users.validateLocalUsername.ok(username)) { + throw new Error('INVALID_USERNAME'); + } + + if (password != null && passwordHash == null) { + // Validate password + if (!Users.validatePassword.ok(password)) { + throw new Error('INVALID_PASSWORD'); + } + + // Generate hash of password + const salt = await bcrypt.genSalt(8); + hash = await bcrypt.hash(password, salt); + } + + // Generate secret + const secret = generateUserToken(); + + // Check username duplication + if (await Users.findOne({ usernameLower: username.toLowerCase(), host: null })) { + throw new Error('DUPLICATED_USERNAME'); + } + + // Check deleted username duplication + if (await UsedUsernames.findOne({ username: username.toLowerCase() })) { + throw new Error('USED_USERNAME'); + } + + const keyPair = await new Promise<string[]>((res, rej) => + generateKeyPair('rsa', { + modulusLength: 4096, + publicKeyEncoding: { + type: 'spki', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem', + cipher: undefined, + passphrase: undefined + } + } as any, (err, publicKey, privateKey) => + err ? rej(err) : res([publicKey, privateKey]) + )); + + let account!: User; + + // Start transaction + await getConnection().transaction(async transactionalEntityManager => { + const exist = await transactionalEntityManager.findOne(User, { + usernameLower: username.toLowerCase(), + host: null + }); + + if (exist) throw new Error(' the username is already used'); + + account = await transactionalEntityManager.save(new User({ + id: genId(), + createdAt: new Date(), + username: username, + usernameLower: username.toLowerCase(), + host: toPunyNullable(host), + token: secret, + isAdmin: (await Users.count({ + host: null, + })) === 0, + })); + + await transactionalEntityManager.save(new UserKeypair({ + publicKey: keyPair[0], + privateKey: keyPair[1], + userId: account.id + })); + + await transactionalEntityManager.save(new UserProfile({ + userId: account.id, + autoAcceptFollowed: true, + password: hash, + })); + + await transactionalEntityManager.save(new UsedUsername({ + createdAt: new Date(), + username: username.toLowerCase(), + })); + }); + + usersChart.update(account, true); + + return { account, secret }; +} |