From cfde3248df2c46d427e9b2a1b83df471b04b115b Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 4 Oct 2024 19:07:25 +0900 Subject: [PATCH 01/11] =?UTF-8?q?fix:=20signin=20=E3=81=AE=E8=B3=87?= =?UTF-8?q?=E6=A0=BC=E6=83=85=E5=A0=B1=E3=81=8C=E8=B6=B3=E3=82=8A=E3=81=AA?= =?UTF-8?q?=E3=81=84=E3=81=A0=E3=81=91=E3=81=AE=E5=A0=B4=E5=90=88=E3=81=AF?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E3=81=AB=E3=81=9B=E3=81=9A200?= =?UTF-8?q?=E3=82=92=E8=BF=94=E3=81=99=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/server/api/SigninApiService.ts | 66 ++---- .../backend/src/server/api/SigninService.ts | 6 +- packages/frontend/src/components/MkSignin.vue | 216 +++++++++--------- .../src/components/MkSignupDialog.form.vue | 7 +- packages/misskey-js/src/entities.ts | 12 +- 5 files changed, 148 insertions(+), 159 deletions(-) diff --git a/packages/backend/src/server/api/SigninApiService.ts b/packages/backend/src/server/api/SigninApiService.ts index 81684beb3c67..327076cd9cbf 100644 --- a/packages/backend/src/server/api/SigninApiService.ts +++ b/packages/backend/src/server/api/SigninApiService.ts @@ -5,8 +5,8 @@ import { Inject, Injectable } from '@nestjs/common'; import bcrypt from 'bcryptjs'; -import * as OTPAuth from 'otpauth'; import { IsNull } from 'typeorm'; +import * as Misskey from 'misskey-js'; import { DI } from '@/di-symbols.js'; import type { MiMeta, @@ -26,27 +26,9 @@ import { CaptchaService } from '@/core/CaptchaService.js'; import { FastifyReplyError } from '@/misc/fastify-reply-error.js'; import { RateLimiterService } from './RateLimiterService.js'; import { SigninService } from './SigninService.js'; -import type { AuthenticationResponseJSON, PublicKeyCredentialRequestOptionsJSON } from '@simplewebauthn/types'; +import type { AuthenticationResponseJSON } from '@simplewebauthn/types'; import type { FastifyReply, FastifyRequest } from 'fastify'; -/** - * next を指定すると、次にクライアント側で行うべき処理を指定できる。 - * - * - `captcha`: パスワードと、(有効になっている場合は)CAPTCHAを求める - * - `password`: パスワードを求める - * - `totp`: ワンタイムパスワードを求める - * - `passkey`: WebAuthn認証を求める(WebAuthnに対応していないブラウザの場合はワンタイムパスワード) - */ - -type SigninErrorResponse = { - id: string; - next?: 'captcha' | 'password' | 'totp'; -} | { - id: string; - next: 'passkey'; - authRequest: PublicKeyCredentialRequestOptionsJSON; -}; - @Injectable() export class SigninApiService { constructor( @@ -101,7 +83,7 @@ export class SigninApiService { const password = body['password']; const token = body['token']; - function error(status: number, error: SigninErrorResponse) { + function error(status: number, error: { id: string }) { reply.code(status); return { error }; } @@ -152,21 +134,17 @@ export class SigninApiService { const securityKeysAvailable = await this.userSecurityKeysRepository.countBy({ userId: user.id }).then(result => result >= 1); if (password == null) { - reply.code(403); + reply.code(200); if (profile.twoFactorEnabled) { return { - error: { - id: '144ff4f8-bd6c-41bc-82c3-b672eb09efbf', - next: 'password', - }, - } satisfies { error: SigninErrorResponse }; + finished: false, + next: 'password', + } satisfies Misskey.entities.SigninResponse; } else { return { - error: { - id: '144ff4f8-bd6c-41bc-82c3-b672eb09efbf', - next: 'captcha', - }, - } satisfies { error: SigninErrorResponse }; + finished: false, + next: 'captcha', + } satisfies Misskey.entities.SigninResponse; } } @@ -178,7 +156,7 @@ export class SigninApiService { // Compare password const same = await bcrypt.compare(password, profile.password!); - const fail = async (status?: number, failure?: SigninErrorResponse) => { + const fail = async (status?: number, failure?: { id: string; }) => { // Append signin history await this.signinsRepository.insert({ id: this.idService.gen(), @@ -268,27 +246,23 @@ export class SigninApiService { const authRequest = await this.webAuthnService.initiateAuthentication(user.id); - reply.code(403); + reply.code(200); return { - error: { - id: '06e661b9-8146-4ae3-bde5-47138c0ae0c4', - next: 'passkey', - authRequest, - }, - } satisfies { error: SigninErrorResponse }; + finished: false, + next: 'passkey', + authRequest, + } satisfies Misskey.entities.SigninResponse; } else { if (!same || !profile.twoFactorEnabled) { return await fail(403, { id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c', }); } else { - reply.code(403); + reply.code(200); return { - error: { - id: '144ff4f8-bd6c-41bc-82c3-b672eb09efbf', - next: 'totp', - }, - } satisfies { error: SigninErrorResponse }; + finished: false, + next: 'totp', + } satisfies Misskey.entities.SigninResponse; } } // never get here diff --git a/packages/backend/src/server/api/SigninService.ts b/packages/backend/src/server/api/SigninService.ts index 4b041f373f89..82d3ca154601 100644 --- a/packages/backend/src/server/api/SigninService.ts +++ b/packages/backend/src/server/api/SigninService.ts @@ -4,6 +4,7 @@ */ import { Inject, Injectable } from '@nestjs/common'; +import * as Misskey from 'misskey-js'; import { DI } from '@/di-symbols.js'; import type { SigninsRepository, UserProfilesRepository } from '@/models/_.js'; import { IdService } from '@/core/IdService.js'; @@ -57,9 +58,10 @@ export class SigninService { reply.code(200); return { + finished: true, id: user.id, - i: user.token, - }; + i: user.token!, + } satisfies Misskey.entities.SigninResponse; } } diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index 03dd61f6c609..2e8169ec0b86 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -227,8 +227,38 @@ async function tryLogin(req: Partial): Promise { - emit('login', res); - await onLoginSucceeded(res); + if (res.finished) { + emit('login', res); + await onLoginSucceeded(res); + } else { + switch (res.next) { + case 'captcha': { + needCaptcha.value = true; + page.value = 'password'; + break; + } + case 'password': { + needCaptcha.value = false; + page.value = 'password'; + break; + } + case 'totp': { + page.value = 'totp'; + break; + } + case 'passkey': { + if (webAuthnSupported()) { + credentialRequest.value = parseRequestOptionsFromJSON({ + publicKey: res.authRequest, + }); + page.value = 'passkey'; + } else { + page.value = 'totp'; + } + break; + } + } + } return res; }).catch((err) => { onSigninApiError(err); @@ -236,7 +266,7 @@ async function tryLogin(req: Partial): Promise { }); emit('signup', res); - if (props.autoSet) { + if (props.autoSet && res.finished) { return login(res.i); + } else { + os.alert({ + type: 'error', + text: i18n.ts.somethingHappened, + }); } } } catch { diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 98ac50e5a1e4..e19ec5b32ac8 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -293,8 +293,16 @@ export type SigninWithPasskeyResponse = { }; export type SigninResponse = { - id: User['id'], - i: string, + finished: true; + id: User['id']; + i: string; +} | { + finished: false; + next: 'captcha' | 'password' | 'totp'; +} | { + finished: false; + next: 'passkey'; + authRequest: PublicKeyCredentialRequestOptionsJSON; }; type Values> = T[keyof T]; From 463ab17c8ff04a063bab978a8b810f7bb786b807 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 4 Oct 2024 19:10:20 +0900 Subject: [PATCH 02/11] run api extractor --- packages/misskey-js/etc/misskey-js.api.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 9ad784c29641..33c1998851b6 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -3051,8 +3051,16 @@ type SigninRequest = { // @public (undocumented) type SigninResponse = { + finished: true; id: User['id']; i: string; +} | { + finished: false; + next: 'captcha' | 'password' | 'totp'; +} | { + finished: false; + next: 'passkey'; + authRequest: PublicKeyCredentialRequestOptionsJSON; }; // @public (undocumented) From 754a0940d88e30ce36bc4be5b862d3f7d2ce1e1c Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 4 Oct 2024 19:14:09 +0900 Subject: [PATCH 03/11] fix --- packages/frontend/src/components/MkSignin.vue | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index 2e8169ec0b86..21aa999da8a6 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -263,6 +263,16 @@ async function tryLogin(req: Partial): Promise { onSigninApiError(err); return Promise.reject(err); + }).finally(() => { + if (doingPasskeyFromInputPage.value === true) { + doingPasskeyFromInputPage.value = false; + page.value = 'input'; + password.value = ''; + } + passwordPageEl.value?.resetCaptcha(); + nextTick(() => { + waiting.value = false; + }); }); } @@ -353,16 +363,6 @@ function onSigninApiError(err?: any): void { }); } } - - if (doingPasskeyFromInputPage.value === true) { - doingPasskeyFromInputPage.value = false; - page.value = 'input'; - password.value = ''; - } - passwordPageEl.value?.resetCaptcha(); - nextTick(() => { - waiting.value = false; - }); } onBeforeUnmount(() => { From 5b757837a9762cec9ae016957c810b8d9c125537 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 4 Oct 2024 19:16:57 +0900 Subject: [PATCH 04/11] fix --- packages/frontend/src/components/MkSignin.vue | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index 21aa999da8a6..de4b6e6775f4 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -258,21 +258,21 @@ async function tryLogin(req: Partial): Promise { + waiting.value = false; + }); } return res; }).catch((err) => { onSigninApiError(err); return Promise.reject(err); - }).finally(() => { - if (doingPasskeyFromInputPage.value === true) { - doingPasskeyFromInputPage.value = false; - page.value = 'input'; - password.value = ''; - } - passwordPageEl.value?.resetCaptcha(); - nextTick(() => { - waiting.value = false; - }); }); } @@ -363,6 +363,16 @@ function onSigninApiError(err?: any): void { }); } } + + if (doingPasskeyFromInputPage.value === true) { + doingPasskeyFromInputPage.value = false; + page.value = 'input'; + password.value = ''; + } + passwordPageEl.value?.resetCaptcha(); + nextTick(() => { + waiting.value = false; + }); } onBeforeUnmount(() => { From b190ff7742107a5354cd51970b173cef86fa1ca1 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 4 Oct 2024 19:34:59 +0900 Subject: [PATCH 05/11] fix test --- packages/backend/test/e2e/2fa.ts | 53 +++++++++++++------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts index 88c32b434692..92758d59b800 100644 --- a/packages/backend/test/e2e/2fa.ts +++ b/packages/backend/test/e2e/2fa.ts @@ -199,12 +199,10 @@ describe('2要素認証', () => { const signinWithoutTokenResponse = await api('signin', { ...signinParam(), }); - assert.strictEqual(signinWithoutTokenResponse.status, 403); + assert.strictEqual(signinWithoutTokenResponse.status, 200); assert.deepStrictEqual(signinWithoutTokenResponse.body, { - error: { - id: '144ff4f8-bd6c-41bc-82c3-b672eb09efbf', - next: 'totp', - }, + finished: false, + next: 'totp', }); const signinResponse = await api('signin', { @@ -212,6 +210,7 @@ describe('2要素認証', () => { token: otpToken(registerResponse.body.secret), }); assert.strictEqual(signinResponse.status, 200); + assert.strictEqual(signinResponse.body.finished, true); assert.notEqual(signinResponse.body.i, undefined); // 後片付け @@ -255,26 +254,20 @@ describe('2要素認証', () => { const signinResponse = await api('signin', { ...signinParam(), }); - const signinResponseBody = signinResponse.body as unknown as { - error: { - id: string; - next: 'passkey'; - authRequest: PublicKeyCredentialRequestOptionsJSON; - }; - }; - assert.strictEqual(signinResponse.status, 403); - assert.strictEqual(signinResponseBody.error.id, '06e661b9-8146-4ae3-bde5-47138c0ae0c4'); - assert.strictEqual(signinResponseBody.error.next, 'passkey'); - assert.notEqual(signinResponseBody.error.authRequest.challenge, undefined); - assert.notEqual(signinResponseBody.error.authRequest.allowCredentials, undefined); - assert.strictEqual(signinResponseBody.error.authRequest.allowCredentials && signinResponseBody.error.authRequest.allowCredentials[0]?.id, credentialId.toString('base64url')); + assert.strictEqual(signinResponse.status, 200); + assert.strictEqual(signinResponse.body.finished, false); + assert.strictEqual(signinResponse.body.next, 'passkey'); + assert.notEqual(signinResponse.body.authRequest.challenge, undefined); + assert.notEqual(signinResponse.body.authRequest.allowCredentials, undefined); + assert.strictEqual(signinResponse.body.authRequest.allowCredentials && signinResponse.body.authRequest.allowCredentials[0]?.id, credentialId.toString('base64url')); const signinResponse2 = await api('signin', signinWithSecurityKeyParam({ keyName, credentialId, - requestOptions: signinResponseBody.error.authRequest, + requestOptions: signinResponse.body.authRequest, })); assert.strictEqual(signinResponse2.status, 200); + assert.strictEqual(signinResponse2.body.finished, true); assert.notEqual(signinResponse2.body.i, undefined); // 後片付け @@ -324,28 +317,22 @@ describe('2要素認証', () => { ...signinParam(), password: '', }); - const signinResponseBody = signinResponse.body as unknown as { - error: { - id: string; - next: 'passkey'; - authRequest: PublicKeyCredentialRequestOptionsJSON; - }; - }; - assert.strictEqual(signinResponse.status, 403); - assert.strictEqual(signinResponseBody.error.id, '06e661b9-8146-4ae3-bde5-47138c0ae0c4'); - assert.strictEqual(signinResponseBody.error.next, 'passkey'); - assert.notEqual(signinResponseBody.error.authRequest.challenge, undefined); - assert.notEqual(signinResponseBody.error.authRequest.allowCredentials, undefined); + assert.strictEqual(signinResponse.status, 200); + assert.strictEqual(signinResponse.body.finished, false); + assert.strictEqual(signinResponse.body.next, 'passkey'); + assert.notEqual(signinResponse.body.authRequest.challenge, undefined); + assert.notEqual(signinResponse.body.authRequest.allowCredentials, undefined); const signinResponse2 = await api('signin', { ...signinWithSecurityKeyParam({ keyName, credentialId, - requestOptions: signinResponseBody.error.authRequest, + requestOptions: signinResponse.body.authRequest, } as any), password: '', }); assert.strictEqual(signinResponse2.status, 200); + assert.strictEqual(signinResponse2.body.finished, true); assert.notEqual(signinResponse2.body.i, undefined); // 後片付け @@ -455,6 +442,7 @@ describe('2要素認証', () => { token: otpToken(registerResponse.body.secret), }); assert.strictEqual(signinResponse.status, 200); + assert.strictEqual(signinResponse.body.finished, true); assert.notEqual(signinResponse.body.i, undefined); // 後片付け @@ -489,6 +477,7 @@ describe('2要素認証', () => { ...signinParam(), }); assert.strictEqual(signinResponse.status, 200); + assert.strictEqual(signinResponse.body.finished, true); assert.notEqual(signinResponse.body.i, undefined); // 後片付け From 73e063bcb75add5df938a833a1e4e0bb90bc7197 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 4 Oct 2024 20:10:11 +0900 Subject: [PATCH 06/11] /signin -> /signin-flow --- cypress/e2e/basic.cy.ts | 2 +- cypress/support/commands.ts | 2 +- packages/backend/src/server/ServerModule.ts | 4 +-- .../src/server/api/ApiServerService.ts | 6 ++-- ...nApiService.ts => SigninFlowApiService.ts} | 2 +- packages/backend/test/e2e/2fa.ts | 16 +++++----- packages/backend/test/e2e/endpoints.ts | 8 ++--- packages/frontend/src/components/MkSignin.vue | 2 +- .../src/components/MkSignupDialog.form.vue | 2 +- packages/misskey-js/etc/misskey-js.api.md | 16 +++++----- packages/misskey-js/src/api.types.ts | 10 +++---- packages/misskey-js/src/entities.ts | 30 +++++++++---------- 12 files changed, 50 insertions(+), 50 deletions(-) rename packages/backend/src/server/api/{SigninApiService.ts => SigninFlowApiService.ts} (99%) diff --git a/cypress/e2e/basic.cy.ts b/cypress/e2e/basic.cy.ts index c9d7e0a24a4d..d2efbf709c88 100644 --- a/cypress/e2e/basic.cy.ts +++ b/cypress/e2e/basic.cy.ts @@ -120,7 +120,7 @@ describe('After user signup', () => { it('signin', () => { cy.visitHome(); - cy.intercept('POST', '/api/signin').as('signin'); + cy.intercept('POST', '/api/signin-flow').as('signin'); cy.get('[data-cy-signin]').click(); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index ed5cda31b001..197ff963acff 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -55,7 +55,7 @@ Cypress.Commands.add('registerUser', (username, password, isAdmin = false) => { Cypress.Commands.add('login', (username, password) => { cy.visitHome(); - cy.intercept('POST', '/api/signin').as('signin'); + cy.intercept('POST', '/api/signin-flow').as('signin'); cy.get('[data-cy-signin]').click(); cy.get('[data-cy-signin-page-input]').should('be.visible', { timeout: 1000 }); diff --git a/packages/backend/src/server/ServerModule.ts b/packages/backend/src/server/ServerModule.ts index 3ab0b815f232..381f4f9ef509 100644 --- a/packages/backend/src/server/ServerModule.ts +++ b/packages/backend/src/server/ServerModule.ts @@ -19,7 +19,7 @@ import { ApiLoggerService } from './api/ApiLoggerService.js'; import { ApiServerService } from './api/ApiServerService.js'; import { AuthenticateService } from './api/AuthenticateService.js'; import { RateLimiterService } from './api/RateLimiterService.js'; -import { SigninApiService } from './api/SigninApiService.js'; +import { SigninFlowApiService } from './api/SigninFlowApiService.js'; import { SigninService } from './api/SigninService.js'; import { SignupApiService } from './api/SignupApiService.js'; import { StreamingApiServerService } from './api/StreamingApiServerService.js'; @@ -71,7 +71,7 @@ import { SigninWithPasskeyApiService } from './api/SigninWithPasskeyApiService.j ApiServerService, AuthenticateService, RateLimiterService, - SigninApiService, + SigninFlowApiService, SigninWithPasskeyApiService, SigninService, SignupApiService, diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts index 356e14568120..6467c0099d2c 100644 --- a/packages/backend/src/server/api/ApiServerService.ts +++ b/packages/backend/src/server/api/ApiServerService.ts @@ -17,7 +17,7 @@ import { bindThis } from '@/decorators.js'; import endpoints from './endpoints.js'; import { ApiCallService } from './ApiCallService.js'; import { SignupApiService } from './SignupApiService.js'; -import { SigninApiService } from './SigninApiService.js'; +import { SigninFlowApiService } from './SigninFlowApiService.js'; import { SigninWithPasskeyApiService } from './SigninWithPasskeyApiService.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; @@ -38,7 +38,7 @@ export class ApiServerService { private userEntityService: UserEntityService, private apiCallService: ApiCallService, private signupApiService: SignupApiService, - private signinApiService: SigninApiService, + private signinFlowApiService: SigninFlowApiService, private signinWithPasskeyApiService: SigninWithPasskeyApiService, ) { //this.createServer = this.createServer.bind(this); @@ -133,7 +133,7 @@ export class ApiServerService { 'turnstile-response'?: string; 'm-captcha-response'?: string; }; - }>('/signin', (request, reply) => this.signinApiService.signin(request, reply)); + }>('/signin-flow', (request, reply) => this.signinFlowApiService.signin(request, reply)); fastify.post<{ Body: { diff --git a/packages/backend/src/server/api/SigninApiService.ts b/packages/backend/src/server/api/SigninFlowApiService.ts similarity index 99% rename from packages/backend/src/server/api/SigninApiService.ts rename to packages/backend/src/server/api/SigninFlowApiService.ts index 327076cd9cbf..84a31df10be3 100644 --- a/packages/backend/src/server/api/SigninApiService.ts +++ b/packages/backend/src/server/api/SigninFlowApiService.ts @@ -30,7 +30,7 @@ import type { AuthenticationResponseJSON } from '@simplewebauthn/types'; import type { FastifyReply, FastifyRequest } from 'fastify'; @Injectable() -export class SigninApiService { +export class SigninFlowApiService { constructor( @Inject(DI.config) private config: Config, diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts index 92758d59b800..63430c2e3e47 100644 --- a/packages/backend/test/e2e/2fa.ts +++ b/packages/backend/test/e2e/2fa.ts @@ -196,7 +196,7 @@ describe('2要素認証', () => { }, alice); assert.strictEqual(doneResponse.status, 200); - const signinWithoutTokenResponse = await api('signin', { + const signinWithoutTokenResponse = await api('signin-flow', { ...signinParam(), }); assert.strictEqual(signinWithoutTokenResponse.status, 200); @@ -205,7 +205,7 @@ describe('2要素認証', () => { next: 'totp', }); - const signinResponse = await api('signin', { + const signinResponse = await api('signin-flow', { ...signinParam(), token: otpToken(registerResponse.body.secret), }); @@ -251,7 +251,7 @@ describe('2要素認証', () => { assert.strictEqual(keyDoneResponse.body.id, credentialId.toString('base64url')); assert.strictEqual(keyDoneResponse.body.name, keyName); - const signinResponse = await api('signin', { + const signinResponse = await api('signin-flow', { ...signinParam(), }); assert.strictEqual(signinResponse.status, 200); @@ -261,7 +261,7 @@ describe('2要素認証', () => { assert.notEqual(signinResponse.body.authRequest.allowCredentials, undefined); assert.strictEqual(signinResponse.body.authRequest.allowCredentials && signinResponse.body.authRequest.allowCredentials[0]?.id, credentialId.toString('base64url')); - const signinResponse2 = await api('signin', signinWithSecurityKeyParam({ + const signinResponse2 = await api('signin-flow', signinWithSecurityKeyParam({ keyName, credentialId, requestOptions: signinResponse.body.authRequest, @@ -313,7 +313,7 @@ describe('2要素認証', () => { assert.strictEqual(iResponse.status, 200); assert.strictEqual(iResponse.body.usePasswordLessLogin, true); - const signinResponse = await api('signin', { + const signinResponse = await api('signin-flow', { ...signinParam(), password: '', }); @@ -323,7 +323,7 @@ describe('2要素認証', () => { assert.notEqual(signinResponse.body.authRequest.challenge, undefined); assert.notEqual(signinResponse.body.authRequest.allowCredentials, undefined); - const signinResponse2 = await api('signin', { + const signinResponse2 = await api('signin-flow', { ...signinWithSecurityKeyParam({ keyName, credentialId, @@ -437,7 +437,7 @@ describe('2要素認証', () => { assert.strictEqual(afterIResponse.status, 200); assert.strictEqual(afterIResponse.body.securityKeys, false); - const signinResponse = await api('signin', { + const signinResponse = await api('signin-flow', { ...signinParam(), token: otpToken(registerResponse.body.secret), }); @@ -473,7 +473,7 @@ describe('2要素認証', () => { }, alice); assert.strictEqual(unregisterResponse.status, 204); - const signinResponse = await api('signin', { + const signinResponse = await api('signin-flow', { ...signinParam(), }); assert.strictEqual(signinResponse.status, 200); diff --git a/packages/backend/test/e2e/endpoints.ts b/packages/backend/test/e2e/endpoints.ts index 5aaec7f6f9d0..b91d77c398c8 100644 --- a/packages/backend/test/e2e/endpoints.ts +++ b/packages/backend/test/e2e/endpoints.ts @@ -66,9 +66,9 @@ describe('Endpoints', () => { }); }); - describe('signin', () => { + describe('signin-flow', () => { test('間違ったパスワードでサインインできない', async () => { - const res = await api('signin', { + const res = await api('signin-flow', { username: 'test1', password: 'bar', }); @@ -77,7 +77,7 @@ describe('Endpoints', () => { }); test('クエリをインジェクションできない', async () => { - const res = await api('signin', { + const res = await api('signin-flow', { username: 'test1', // @ts-expect-error password must be string password: { @@ -89,7 +89,7 @@ describe('Endpoints', () => { }); test('正しい情報でサインインできる', async () => { - const res = await api('signin', { + const res = await api('signin-flow', { username: 'test1', password: 'test1', }); diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index de4b6e6775f4..0f2812c18693 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -226,7 +226,7 @@ async function tryLogin(req: Partial): Promise { + return await misskeyApi('signin-flow', _req).then(async (res) => { if (res.finished) { emit('login', res); await onLoginSucceeded(res); diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue index b97e25693a52..85b59bcb0cec 100644 --- a/packages/frontend/src/components/MkSignupDialog.form.vue +++ b/packages/frontend/src/components/MkSignupDialog.form.vue @@ -269,7 +269,7 @@ async function onSubmit(): Promise { }); emit('signupEmailPending'); } else { - const res = await misskeyApi('signin', { + const res = await misskeyApi('signin-flow', { username: username.value, password: password.value, }); diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 33c1998851b6..732352abd898 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1158,9 +1158,9 @@ export type Endpoints = Overwrite> = T[keyof T]; From 35dd85762de4cef91492da7cba9f973b97fe2e5e Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 4 Oct 2024 20:17:02 +0900 Subject: [PATCH 07/11] fix --- packages/backend/src/server/api/SigninFlowApiService.ts | 8 ++++---- packages/backend/src/server/api/SigninService.ts | 2 +- packages/frontend/src/components/MkSignin.vue | 6 +++--- packages/frontend/src/components/MkSignupDialog.form.vue | 2 +- packages/frontend/src/components/MkSignupDialog.vue | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/backend/src/server/api/SigninFlowApiService.ts b/packages/backend/src/server/api/SigninFlowApiService.ts index 84a31df10be3..377c4b4adf61 100644 --- a/packages/backend/src/server/api/SigninFlowApiService.ts +++ b/packages/backend/src/server/api/SigninFlowApiService.ts @@ -139,12 +139,12 @@ export class SigninFlowApiService { return { finished: false, next: 'password', - } satisfies Misskey.entities.SigninResponse; + } satisfies Misskey.entities.SigninFlowResponse; } else { return { finished: false, next: 'captcha', - } satisfies Misskey.entities.SigninResponse; + } satisfies Misskey.entities.SigninFlowResponse; } } @@ -251,7 +251,7 @@ export class SigninFlowApiService { finished: false, next: 'passkey', authRequest, - } satisfies Misskey.entities.SigninResponse; + } satisfies Misskey.entities.SigninFlowResponse; } else { if (!same || !profile.twoFactorEnabled) { return await fail(403, { @@ -262,7 +262,7 @@ export class SigninFlowApiService { return { finished: false, next: 'totp', - } satisfies Misskey.entities.SigninResponse; + } satisfies Misskey.entities.SigninFlowResponse; } } // never get here diff --git a/packages/backend/src/server/api/SigninService.ts b/packages/backend/src/server/api/SigninService.ts index 82d3ca154601..640356b50c63 100644 --- a/packages/backend/src/server/api/SigninService.ts +++ b/packages/backend/src/server/api/SigninService.ts @@ -61,7 +61,7 @@ export class SigninService { finished: true, id: user.id, i: user.token!, - } satisfies Misskey.entities.SigninResponse; + } satisfies Misskey.entities.SigninFlowResponse; } } diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index 0f2812c18693..f41722dbc520 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -83,7 +83,7 @@ import type { AuthenticationPublicKeyCredential } from '@github/webauthn-json/br import type { OpenOnRemoteOptions } from '@/scripts/please-login.js'; const emit = defineEmits<{ - (ev: 'login', v: Misskey.entities.SigninResponse): void; + (ev: 'login', v: Misskey.entities.SigninFlowResponse): void; }>(); const props = withDefaults(defineProps<{ @@ -212,7 +212,7 @@ async function onTotpSubmitted(token: string) { } } -async function tryLogin(req: Partial): Promise { +async function tryLogin(req: Partial): Promise { const _req = { username: req.username ?? userInfo.value?.username, ...req, @@ -276,7 +276,7 @@ async function tryLogin(req: Partial): Promise(); diff --git a/packages/frontend/src/components/MkSignupDialog.vue b/packages/frontend/src/components/MkSignupDialog.vue index 97310d32a64e..4cccd99492da 100644 --- a/packages/frontend/src/components/MkSignupDialog.vue +++ b/packages/frontend/src/components/MkSignupDialog.vue @@ -47,7 +47,7 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'done', res: Misskey.entities.SigninResponse): void; + (ev: 'done', res: Misskey.entities.SigninFlowResponse): void; (ev: 'closed'): void; }>(); @@ -55,7 +55,7 @@ const dialog = shallowRef>(); const isAcceptedServerRule = ref(false); -function onSignup(res: Misskey.entities.SigninResponse) { +function onSignup(res: Misskey.entities.SigninFlowResponse) { emit('done', res); dialog.value?.close(); } From c81bdd066068b2416a9ea9cef4042f56d2abaa9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 4 Oct 2024 21:00:58 +0900 Subject: [PATCH 08/11] fix lint --- packages/backend/test/e2e/2fa.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts index 63430c2e3e47..48e1bababb7e 100644 --- a/packages/backend/test/e2e/2fa.ts +++ b/packages/backend/test/e2e/2fa.ts @@ -136,7 +136,7 @@ describe('2要素認証', () => { keyName: string, credentialId: Buffer, requestOptions: PublicKeyCredentialRequestOptionsJSON, - }): misskey.entities.SigninRequest => { + }): misskey.entities.SigninFlowRequest => { // AuthenticatorAssertionResponse.authenticatorData // https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorAssertionResponse/authenticatorData const authenticatorData = Buffer.concat([ From 1ae44234e355345a38fbe1df666ff20211c80ca1 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 4 Oct 2024 23:57:26 +0900 Subject: [PATCH 09/11] rename --- packages/backend/src/server/ServerModule.ts | 4 ++-- packages/backend/src/server/api/ApiServerService.ts | 4 ++-- .../api/{SigninFlowApiService.ts => SigninApiService.ts} | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename packages/backend/src/server/api/{SigninFlowApiService.ts => SigninApiService.ts} (99%) diff --git a/packages/backend/src/server/ServerModule.ts b/packages/backend/src/server/ServerModule.ts index 381f4f9ef509..3ab0b815f232 100644 --- a/packages/backend/src/server/ServerModule.ts +++ b/packages/backend/src/server/ServerModule.ts @@ -19,7 +19,7 @@ import { ApiLoggerService } from './api/ApiLoggerService.js'; import { ApiServerService } from './api/ApiServerService.js'; import { AuthenticateService } from './api/AuthenticateService.js'; import { RateLimiterService } from './api/RateLimiterService.js'; -import { SigninFlowApiService } from './api/SigninFlowApiService.js'; +import { SigninApiService } from './api/SigninApiService.js'; import { SigninService } from './api/SigninService.js'; import { SignupApiService } from './api/SignupApiService.js'; import { StreamingApiServerService } from './api/StreamingApiServerService.js'; @@ -71,7 +71,7 @@ import { SigninWithPasskeyApiService } from './api/SigninWithPasskeyApiService.j ApiServerService, AuthenticateService, RateLimiterService, - SigninFlowApiService, + SigninApiService, SigninWithPasskeyApiService, SigninService, SignupApiService, diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts index 6467c0099d2c..9093fddac788 100644 --- a/packages/backend/src/server/api/ApiServerService.ts +++ b/packages/backend/src/server/api/ApiServerService.ts @@ -17,7 +17,7 @@ import { bindThis } from '@/decorators.js'; import endpoints from './endpoints.js'; import { ApiCallService } from './ApiCallService.js'; import { SignupApiService } from './SignupApiService.js'; -import { SigninFlowApiService } from './SigninFlowApiService.js'; +import { SigninApiService } from './SigninApiService.js'; import { SigninWithPasskeyApiService } from './SigninWithPasskeyApiService.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; @@ -38,7 +38,7 @@ export class ApiServerService { private userEntityService: UserEntityService, private apiCallService: ApiCallService, private signupApiService: SignupApiService, - private signinFlowApiService: SigninFlowApiService, + private signinFlowApiService: SigninApiService, private signinWithPasskeyApiService: SigninWithPasskeyApiService, ) { //this.createServer = this.createServer.bind(this); diff --git a/packages/backend/src/server/api/SigninFlowApiService.ts b/packages/backend/src/server/api/SigninApiService.ts similarity index 99% rename from packages/backend/src/server/api/SigninFlowApiService.ts rename to packages/backend/src/server/api/SigninApiService.ts index 377c4b4adf61..0d24ffa56acc 100644 --- a/packages/backend/src/server/api/SigninFlowApiService.ts +++ b/packages/backend/src/server/api/SigninApiService.ts @@ -30,7 +30,7 @@ import type { AuthenticationResponseJSON } from '@simplewebauthn/types'; import type { FastifyReply, FastifyRequest } from 'fastify'; @Injectable() -export class SigninFlowApiService { +export class SigninApiService { constructor( @Inject(DI.config) private config: Config, From b6307b5ce2b3451250e1dfcb53f03a0709b4b2c4 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 5 Oct 2024 00:08:50 +0900 Subject: [PATCH 10/11] fix --- packages/backend/src/server/api/ApiServerService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts index 9093fddac788..6b760c258b1c 100644 --- a/packages/backend/src/server/api/ApiServerService.ts +++ b/packages/backend/src/server/api/ApiServerService.ts @@ -38,7 +38,7 @@ export class ApiServerService { private userEntityService: UserEntityService, private apiCallService: ApiCallService, private signupApiService: SignupApiService, - private signinFlowApiService: SigninApiService, + private signinApiService: SigninApiService, private signinWithPasskeyApiService: SigninWithPasskeyApiService, ) { //this.createServer = this.createServer.bind(this); @@ -133,7 +133,7 @@ export class ApiServerService { 'turnstile-response'?: string; 'm-captcha-response'?: string; }; - }>('/signin-flow', (request, reply) => this.signinFlowApiService.signin(request, reply)); + }>('/signin-flow', (request, reply) => this.signinApiService.signin(request, reply)); fastify.post<{ Body: { From cb426bc20be33a6aa798cb2f6c96e5d62284137d Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 5 Oct 2024 02:07:47 +0900 Subject: [PATCH 11/11] fix --- packages/frontend/src/components/MkSignin.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index f41722dbc520..26e1ac516c6c 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -212,17 +212,17 @@ async function onTotpSubmitted(token: string) { } } -async function tryLogin(req: Partial): Promise { +async function tryLogin(req: Partial): Promise { const _req = { username: req.username ?? userInfo.value?.username, ...req, }; - function assertIsSigninRequest(x: Partial): x is Misskey.entities.SigninRequest { + function assertIsSigninFlowRequest(x: Partial): x is Misskey.entities.SigninFlowRequest { return x.username != null; } - if (!assertIsSigninRequest(_req)) { + if (!assertIsSigninFlowRequest(_req)) { throw new Error('Invalid request'); }