summaryrefslogtreecommitdiff
path: root/src/server/api/private
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2021-11-12 02:02:25 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2021-11-12 02:02:25 +0900
commit0e4a111f81cceed275d9bec2695f6e401fb654d8 (patch)
tree40874799472fa07416f17b50a398ac33b7771905 /src/server/api/private
parentupdate deps (diff)
downloadsharkey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.gz
sharkey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.bz2
sharkey-0e4a111f81cceed275d9bec2695f6e401fb654d8.zip
refactoring
Resolve #7779
Diffstat (limited to 'src/server/api/private')
-rw-r--r--src/server/api/private/signin.ts232
-rw-r--r--src/server/api/private/signup-pending.ts35
-rw-r--r--src/server/api/private/signup.ts112
3 files changed, 0 insertions, 379 deletions
diff --git a/src/server/api/private/signin.ts b/src/server/api/private/signin.ts
deleted file mode 100644
index 83c3dfee94..0000000000
--- a/src/server/api/private/signin.ts
+++ /dev/null
@@ -1,232 +0,0 @@
-import * as Koa from 'koa';
-import * as bcrypt from 'bcryptjs';
-import * as speakeasy from 'speakeasy';
-import signin from '../common/signin';
-import config from '@/config/index';
-import { Users, Signins, UserProfiles, UserSecurityKeys, AttestationChallenges } from '@/models/index';
-import { ILocalUser } from '@/models/entities/user';
-import { genId } from '@/misc/gen-id';
-import { verifyLogin, hash } from '../2fa';
-import { randomBytes } from 'crypto';
-
-export default async (ctx: Koa.Context) => {
- ctx.set('Access-Control-Allow-Origin', config.url);
- ctx.set('Access-Control-Allow-Credentials', 'true');
-
- const body = ctx.request.body as any;
- const username = body['username'];
- const password = body['password'];
- const token = body['token'];
-
- function error(status: number, error: { id: string }) {
- ctx.status = status;
- ctx.body = { error };
- }
-
- if (typeof username != 'string') {
- ctx.status = 400;
- return;
- }
-
- if (typeof password != 'string') {
- ctx.status = 400;
- return;
- }
-
- if (token != null && typeof token != 'string') {
- ctx.status = 400;
- return;
- }
-
- // Fetch user
- const user = await Users.findOne({
- usernameLower: username.toLowerCase(),
- host: null
- }) as ILocalUser;
-
- if (user == null) {
- error(404, {
- id: '6cc579cc-885d-43d8-95c2-b8c7fc963280',
- });
- return;
- }
-
- if (user.isSuspended) {
- error(403, {
- id: 'e03a5f46-d309-4865-9b69-56282d94e1eb',
- });
- return;
- }
-
- const profile = await UserProfiles.findOneOrFail(user.id);
-
- // Compare password
- const same = await bcrypt.compare(password, profile.password!);
-
- async function fail(status?: number, failure?: { id: string }) {
- // Append signin history
- await Signins.insert({
- id: genId(),
- createdAt: new Date(),
- userId: user.id,
- ip: ctx.ip,
- headers: ctx.headers,
- success: false
- });
-
- error(status || 500, failure || { id: '4e30e80c-e338-45a0-8c8f-44455efa3b76' });
- }
-
- if (!profile.twoFactorEnabled) {
- if (same) {
- signin(ctx, user);
- return;
- } else {
- await fail(403, {
- id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c'
- });
- return;
- }
- }
-
- if (token) {
- if (!same) {
- await fail(403, {
- id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c'
- });
- return;
- }
-
- const verified = (speakeasy as any).totp.verify({
- secret: profile.twoFactorSecret,
- encoding: 'base32',
- token: token,
- window: 2
- });
-
- if (verified) {
- signin(ctx, user);
- return;
- } else {
- await fail(403, {
- id: 'cdf1235b-ac71-46d4-a3a6-84ccce48df6f'
- });
- return;
- }
- } else if (body.credentialId) {
- if (!same && !profile.usePasswordLessLogin) {
- await fail(403, {
- id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c'
- });
- return;
- }
-
- const clientDataJSON = Buffer.from(body.clientDataJSON, 'hex');
- const clientData = JSON.parse(clientDataJSON.toString('utf-8'));
- const challenge = await AttestationChallenges.findOne({
- userId: user.id,
- id: body.challengeId,
- registrationChallenge: false,
- challenge: hash(clientData.challenge).toString('hex')
- });
-
- if (!challenge) {
- await fail(403, {
- id: '2715a88a-2125-4013-932f-aa6fe72792da'
- });
- return;
- }
-
- await AttestationChallenges.delete({
- userId: user.id,
- id: body.challengeId
- });
-
- if (new Date().getTime() - challenge.createdAt.getTime() >= 5 * 60 * 1000) {
- await fail(403, {
- id: '2715a88a-2125-4013-932f-aa6fe72792da'
- });
- return;
- }
-
- const securityKey = await UserSecurityKeys.findOne({
- id: Buffer.from(
- body.credentialId
- .replace(/-/g, '+')
- .replace(/_/g, '/'),
- 'base64'
- ).toString('hex')
- });
-
- if (!securityKey) {
- await fail(403, {
- id: '66269679-aeaf-4474-862b-eb761197e046'
- });
- return;
- }
-
- const isValid = verifyLogin({
- publicKey: Buffer.from(securityKey.publicKey, 'hex'),
- authenticatorData: Buffer.from(body.authenticatorData, 'hex'),
- clientDataJSON,
- clientData,
- signature: Buffer.from(body.signature, 'hex'),
- challenge: challenge.challenge
- });
-
- if (isValid) {
- signin(ctx, user);
- return;
- } else {
- await fail(403, {
- id: '93b86c4b-72f9-40eb-9815-798928603d1e'
- });
- return;
- }
- } else {
- if (!same && !profile.usePasswordLessLogin) {
- await fail(403, {
- id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c'
- });
- return;
- }
-
- const keys = await UserSecurityKeys.find({
- userId: user.id
- });
-
- if (keys.length === 0) {
- await fail(403, {
- id: 'f27fd449-9af4-4841-9249-1f989b9fa4a4'
- });
- return;
- }
-
- // 32 byte challenge
- const challenge = randomBytes(32).toString('base64')
- .replace(/=/g, '')
- .replace(/\+/g, '-')
- .replace(/\//g, '_');
-
- const challengeId = genId();
-
- await AttestationChallenges.insert({
- userId: user.id,
- id: challengeId,
- challenge: hash(Buffer.from(challenge, 'utf-8')).toString('hex'),
- createdAt: new Date(),
- registrationChallenge: false
- });
-
- ctx.body = {
- challenge,
- challengeId,
- securityKeys: keys.map(key => ({
- id: key.id
- }))
- };
- ctx.status = 200;
- return;
- }
- // never get here
-};
diff --git a/src/server/api/private/signup-pending.ts b/src/server/api/private/signup-pending.ts
deleted file mode 100644
index c0638a1cda..0000000000
--- a/src/server/api/private/signup-pending.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import * as Koa from 'koa';
-import { Users, UserPendings, UserProfiles } from '@/models/index';
-import { signup } from '../common/signup';
-import signin from '../common/signin';
-
-export default async (ctx: Koa.Context) => {
- const body = ctx.request.body;
-
- const code = body['code'];
-
- try {
- const pendingUser = await UserPendings.findOneOrFail({ code });
-
- const { account, secret } = await signup({
- username: pendingUser.username,
- passwordHash: pendingUser.password,
- });
-
- UserPendings.delete({
- id: pendingUser.id,
- });
-
- const profile = await UserProfiles.findOneOrFail(account.id);
-
- await UserProfiles.update({ userId: profile.userId }, {
- email: pendingUser.email,
- emailVerified: true,
- emailVerifyCode: null,
- });
-
- signin(ctx, account);
- } catch (e) {
- ctx.throw(400, e);
- }
-};
diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts
deleted file mode 100644
index 2b6a3eb00c..0000000000
--- a/src/server/api/private/signup.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-import * as Koa from 'koa';
-import rndstr from 'rndstr';
-import * as bcrypt from 'bcryptjs';
-import { fetchMeta } from '@/misc/fetch-meta';
-import { verifyHcaptcha, verifyRecaptcha } from '@/misc/captcha';
-import { Users, RegistrationTickets, UserPendings } from '@/models/index';
-import { signup } from '../common/signup';
-import config from '@/config';
-import { sendEmail } from '@/services/send-email';
-import { genId } from '@/misc/gen-id';
-import { validateEmailForAccount } from '@/services/validate-email-for-account';
-
-export default async (ctx: Koa.Context) => {
- const body = ctx.request.body;
-
- const instance = await fetchMeta(true);
-
- // Verify *Captcha
- // ただしテスト時はこの機構は障害となるため無効にする
- if (process.env.NODE_ENV !== 'test') {
- if (instance.enableHcaptcha && instance.hcaptchaSecretKey) {
- await verifyHcaptcha(instance.hcaptchaSecretKey, body['hcaptcha-response']).catch(e => {
- ctx.throw(400, e);
- });
- }
-
- if (instance.enableRecaptcha && instance.recaptchaSecretKey) {
- await verifyRecaptcha(instance.recaptchaSecretKey, body['g-recaptcha-response']).catch(e => {
- ctx.throw(400, e);
- });
- }
- }
-
- const username = body['username'];
- const password = body['password'];
- const host: string | null = process.env.NODE_ENV === 'test' ? (body['host'] || null) : null;
- const invitationCode = body['invitationCode'];
- const emailAddress = body['emailAddress'];
-
- if (instance.emailRequiredForSignup) {
- if (emailAddress == null || typeof emailAddress != 'string') {
- ctx.status = 400;
- return;
- }
-
- const available = await validateEmailForAccount(emailAddress);
- if (!available) {
- ctx.status = 400;
- return;
- }
- }
-
- if (instance.disableRegistration) {
- if (invitationCode == null || typeof invitationCode != 'string') {
- ctx.status = 400;
- return;
- }
-
- const ticket = await RegistrationTickets.findOne({
- code: invitationCode
- });
-
- if (ticket == null) {
- ctx.status = 400;
- return;
- }
-
- RegistrationTickets.delete(ticket.id);
- }
-
- if (instance.emailRequiredForSignup) {
- const code = rndstr('a-z0-9', 16);
-
- // Generate hash of password
- const salt = await bcrypt.genSalt(8);
- const hash = await bcrypt.hash(password, salt);
-
- await UserPendings.insert({
- id: genId(),
- createdAt: new Date(),
- code,
- email: emailAddress,
- username: username,
- password: hash,
- });
-
- const link = `${config.url}/signup-complete/${code}`;
-
- sendEmail(emailAddress, 'Signup',
- `To complete signup, please click this link:<br><a href="${link}">${link}</a>`,
- `To complete signup, please click this link: ${link}`);
-
- ctx.status = 204;
- } else {
- try {
- const { account, secret } = await signup({
- username, password, host
- });
-
- const res = await Users.pack(account, account, {
- detail: true,
- includeSecrets: true
- });
-
- (res as any).token = secret;
-
- ctx.body = res;
- } catch (e) {
- ctx.throw(400, e);
- }
- }
-};