From 39eb86f5af5d1d24e471abf0596bc6bec82e95a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 27 Aug 2023 09:21:07 +0900 Subject: [PATCH 01/52] build(deps): bump actions/checkout from 3.5.3 to 3.6.0 (#11762) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.3 to 3.6.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3.5.3...v3.6.0) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-misskey-js.yml | 2 +- .github/workflows/check_copyright_year.yml | 2 +- .github/workflows/docker-develop.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/dockle.yml | 2 +- .github/workflows/lint.yml | 6 +++--- .github/workflows/pr-preview-deploy.yml | 2 +- .github/workflows/reviewer_lottery.yml | 2 +- .github/workflows/storybook.yml | 4 ++-- .github/workflows/test-backend.yml | 2 +- .github/workflows/test-frontend.yml | 4 ++-- .github/workflows/test-misskey-js.yml | 2 +- .github/workflows/test-production.yml | 2 +- 13 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml index d0018ffcf9..7b8a1ce128 100644 --- a/.github/workflows/api-misskey-js.yml +++ b/.github/workflows/api-misskey-js.yml @@ -9,7 +9,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v3.6.0 - run: corepack enable diff --git a/.github/workflows/check_copyright_year.yml b/.github/workflows/check_copyright_year.yml index 174b6ab256..e06e33b397 100644 --- a/.github/workflows/check_copyright_year.yml +++ b/.github/workflows/check_copyright_year.yml @@ -10,7 +10,7 @@ jobs: check_copyright_year: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 - run: | if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then echo "Please change copyright year!" diff --git a/.github/workflows/docker-develop.yml b/.github/workflows/docker-develop.yml index c839c64a72..4e817b0f22 100644 --- a/.github/workflows/docker-develop.yml +++ b/.github/workflows/docker-develop.yml @@ -13,7 +13,7 @@ jobs: if: github.repository == 'misskey-dev/misskey' steps: - name: Check out the repo - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v3.6.0 - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v2.9.1 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index da05f0cabe..84f74389b9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Check out the repo - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v3.6.0 - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v2.9.1 diff --git a/.github/workflows/dockle.yml b/.github/workflows/dockle.yml index 02dbef35df..4e90b4fc3d 100644 --- a/.github/workflows/dockle.yml +++ b/.github/workflows/dockle.yml @@ -14,7 +14,7 @@ jobs: env: DOCKER_CONTENT_TRUST: 1 steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 - run: | curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v0.4.10/dockle_0.4.10_Linux-64bit.deb" sudo dpkg -i dockle.deb diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d3ea13c120..ae40a274a9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -11,7 +11,7 @@ jobs: pnpm_install: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 with: fetch-depth: 0 submodules: true @@ -38,7 +38,7 @@ jobs: - sw - misskey-js steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 with: fetch-depth: 0 submodules: true @@ -64,7 +64,7 @@ jobs: - backend - misskey-js steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 with: fetch-depth: 0 submodules: true diff --git a/.github/workflows/pr-preview-deploy.yml b/.github/workflows/pr-preview-deploy.yml index fd1417b65b..7980b7383c 100644 --- a/.github/workflows/pr-preview-deploy.yml +++ b/.github/workflows/pr-preview-deploy.yml @@ -53,7 +53,7 @@ jobs: # Check out merge commit - name: Fork based /deploy checkout - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v3.6.0 with: ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge' diff --git a/.github/workflows/reviewer_lottery.yml b/.github/workflows/reviewer_lottery.yml index f8f7d22532..f281e6c3a1 100644 --- a/.github/workflows/reviewer_lottery.yml +++ b/.github/workflows/reviewer_lottery.yml @@ -7,7 +7,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 - uses: uesteibar/reviewer-lottery@v3 with: repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index b068041f3c..8ab6d204bf 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -15,12 +15,12 @@ jobs: NODE_OPTIONS: "--max_old_space_size=7168" steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 if: github.event_name != 'pull_request_target' with: fetch-depth: 0 submodules: true - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 if: github.event_name == 'pull_request_target' with: fetch-depth: 0 diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index f0a152731a..1d9e613433 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -29,7 +29,7 @@ jobs: - 56312:6379 steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 with: submodules: true - name: Install pnpm diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index 46a35ed848..0a7f954fde 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -16,7 +16,7 @@ jobs: node-version: [20.x] steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 with: submodules: true - name: Install pnpm @@ -68,7 +68,7 @@ jobs: - 56312:6379 steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 with: submodules: true # https://github.com/cypress-io/cypress-docker-images/issues/150 diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml index bd9c21f5e0..a3be6216e1 100644 --- a/.github/workflows/test-misskey-js.yml +++ b/.github/workflows/test-misskey-js.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v3.6.0 - run: corepack enable diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml index 5be24f83ec..07a33ac357 100644 --- a/.github/workflows/test-production.yml +++ b/.github/workflows/test-production.yml @@ -19,7 +19,7 @@ jobs: node-version: [20.x] steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v3.6.0 with: submodules: true - name: Install pnpm From f5a5d591557eeed9f163cda8baf2538e142379a9 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 27 Aug 2023 09:45:23 +0900 Subject: [PATCH 02/52] Update CONTRIBUTING.md --- CONTRIBUTING.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 62bc11cd99..e81fecf357 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -301,6 +301,12 @@ export const handlers = [ Don't forget to re-run the `.storybook/generate.js` script after adding, editing, or removing the above files. ## Notes + +### Misskeyのドメイン固有の概念は`Mi`をprefixする +例えばGoogleが自社サービスをMap、Earth、DriveではなくGoogle Map、Google Earth、Google Driveのように命名するのと同じ +コード上でMisskeyのドメイン固有の概念には`Mi`をprefixすることで、他のドメインの同様の概念と区別できるほか、名前の衝突を防ぐ。 +ただし、文脈上Misskeyのものを指すことが明らかであり、名前の衝突の恐れがない場合は、一時的なローカル変数に限って`Mi`を省略してもよい。 + ### How to resolve conflictions occurred at pnpm-lock.yaml? Just execute `pnpm` to fix it. From 257c4fccf1193f111686f039e06cc4d00b9dce37 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 28 Aug 2023 18:25:31 +0900 Subject: [PATCH 03/52] feat: Refine 2fa (#11766) * wip * Update 2fa.qrdialog.vue * Update 2fa.vue * Update CHANGELOG.md * tweak * :v: --- CHANGELOG.md | 1 + locales/index.d.ts | 9 +- locales/ja-JP.yml | 15 +- .../1690569881926-user-2fa-backup-codes.js | 11 ++ .../src/core/entities/UserEntityService.ts | 1 + .../src/models/entities/UserProfile.ts | 5 + .../backend/src/models/json-schema/user.ts | 5 + .../src/server/api/SigninApiService.ts | 7 + .../src/server/api/endpoints/i/2fa/done.ts | 7 + .../server/api/endpoints/i/2fa/unregister.ts | 1 + packages/backend/test/e2e/2fa.ts | 12 +- packages/backend/test/e2e/users.ts | 2 + packages/frontend/.storybook/changes.ts | 5 + packages/frontend/.storybook/fakes.ts | 6 + packages/frontend/.storybook/generate.tsx | 5 + packages/frontend/.storybook/main.ts | 5 + packages/frontend/.storybook/manager.ts | 5 + packages/frontend/.storybook/mocks.ts | 5 + .../frontend/.storybook/preload-locale.ts | 5 + packages/frontend/.storybook/preload-theme.ts | 5 + packages/frontend/.storybook/preview.ts | 5 + packages/frontend/src/components/MkSignin.vue | 2 +- packages/frontend/src/pages/scratchpad.vue | 10 +- .../src/pages/settings/2fa.qrdialog.vue | 178 +++++++++++++----- packages/frontend/src/pages/settings/2fa.vue | 43 ++--- packages/frontend/src/style.scss | 9 - packages/misskey-js/etc/misskey-js.api.md | 1 + packages/misskey-js/src/entities.ts | 1 + 28 files changed, 267 insertions(+), 99 deletions(-) create mode 100644 packages/backend/migration/1690569881926-user-2fa-backup-codes.js diff --git a/CHANGELOG.md b/CHANGELOG.md index e57a2c4fd3..a2f5d086cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - お知らせのバナー表示やダイアログ表示が可能に - お知らせのアイコンを設定可能に - チャンネルをセンシティブ指定できるようになりました +- 二要素認証のバックアップコードが生成されるようになりました ### Client - プロフィールにその人が作ったPlayの一覧出せるように diff --git a/locales/index.d.ts b/locales/index.d.ts index 1f25edd0ef..1d756a14d8 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -414,6 +414,7 @@ export interface Locale { "administrator": string; "token": string; "2fa": string; + "setupOf2fa": string; "totp": string; "totpDescription": string; "moderator": string; @@ -1811,9 +1812,10 @@ export interface Locale { "step1": string; "step2": string; "step2Click": string; - "step2Url": string; + "step2Uri": string; "step3Title": string; "step3": string; + "setupCompleted": string; "step4": string; "securityKeyNotSupported": string; "registerTOTPBeforeKey": string; @@ -1829,6 +1831,11 @@ export interface Locale { "renewTOTPConfirm": string; "renewTOTPOk": string; "renewTOTPCancel": string; + "checkBackupCodesBeforeCloseThisWizard": string; + "backupCodes": string; + "backupCodesDescription": string; + "backupCodeUsedWarning": string; + "backupCodesExhaustedWarning": string; }; "_permissions": { "read:account": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 2e0e64bbef..3396a3a832 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -411,6 +411,7 @@ aboutMisskey: "Misskeyについて" administrator: "管理者" token: "確認コード" 2fa: "二要素認証" +setupOf2fa: "二要素認証のセットアップ" totp: "認証アプリ" totpDescription: "認証アプリを使ってワンタイムパスワードを入力" moderator: "モデレーター" @@ -1729,10 +1730,11 @@ _2fa: step1: "まず、{a}や{b}などの認証アプリをお使いのデバイスにインストールします。" step2: "次に、表示されているQRコードをアプリでスキャンします。" step2Click: "QRコードをクリックすると、お使いの端末にインストールされている認証アプリやキーリングに登録できます。" - step2Url: "デスクトップアプリでは次のURIを入力します:" + step2Uri: "デスクトップアプリを使用する場合は次のURIを入力します" step3Title: "確認コードを入力" - step3: "アプリに表示されている確認コード(トークン)を入力して完了です。" - step4: "これからログインするときも、同じように確認コードを入力します。" + step3: "アプリに表示されている確認コード(トークン)を入力します。" + setupCompleted: "設定が完了しました" + step4: "これからログインするときも、同じようにコードを入力します。" securityKeyNotSupported: "お使いのブラウザはセキュリティキーに対応していません。" registerTOTPBeforeKey: "セキュリティキー・パスキーを登録するには、まず認証アプリの設定を行なってください。" securityKeyInfo: "FIDO2をサポートするハードウェアセキュリティキー、端末の生体認証やPINロック、パスキーといった、WebAuthn由来の鍵を登録します。" @@ -1744,9 +1746,14 @@ _2fa: removeKeyConfirm: "{name}を削除しますか?" whyTOTPOnlyRenew: "セキュリティキーが登録されている場合、認証アプリの設定は解除できません。" renewTOTP: "認証アプリを再設定" - renewTOTPConfirm: "今までの認証アプリの確認コードは使用できなくなります" + renewTOTPConfirm: "今までの認証アプリの確認コードおよびバックアップコードは使用できなくなります" renewTOTPOk: "再設定する" renewTOTPCancel: "やめておく" + checkBackupCodesBeforeCloseThisWizard: "このウィザードを閉じる前に、以下のバックアップコードを確認してください。" + backupCodes: "バックアップコード" + backupCodesDescription: "認証アプリが使用できなくなった場合、以下のバックアップコードを使ってアカウントにアクセスできます。これらのコードは必ず安全な場所に保管してください。各コードは一回だけ使用できます。" + backupCodeUsedWarning: "バックアップコードが使用されました。認証アプリが使えなくなっている場合、なるべく早く認証アプリを再設定してください。" + backupCodesExhaustedWarning: "バックアップコードが全て使用されました。認証アプリを利用できない場合、これ以上アカウントにアクセスできなくなります。認証アプリを再登録してください。" _permissions: "read:account": "アカウントの情報を見る" diff --git a/packages/backend/migration/1690569881926-user-2fa-backup-codes.js b/packages/backend/migration/1690569881926-user-2fa-backup-codes.js new file mode 100644 index 0000000000..2049df8ea2 --- /dev/null +++ b/packages/backend/migration/1690569881926-user-2fa-backup-codes.js @@ -0,0 +1,11 @@ +export class User2faBackupCodes1690569881926 { + name = 'User2faBackupCodes1690569881926' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_profile" ADD "twoFactorBackupSecret" character varying array`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "twoFactorBackupSecret"`); + } +} diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 236ee9f0b4..d12fd1b620 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -434,6 +434,7 @@ export class UserEntityService implements OnModuleInit { preventAiLearning: profile!.preventAiLearning, isExplorable: user.isExplorable, isDeleted: user.isDeleted, + twoFactorBackupCodesStock: profile?.twoFactorBackupSecret?.length === 5 ? 'full' : (profile?.twoFactorBackupSecret?.length ?? 0) > 0 ? 'partial' : 'none', hideOnlineStatus: user.hideOnlineStatus, hasUnreadSpecifiedNotes: this.noteUnreadsRepository.count({ where: { userId: user.id, isSpecified: true }, diff --git a/packages/backend/src/models/entities/UserProfile.ts b/packages/backend/src/models/entities/UserProfile.ts index 54144cb429..0fd26f4d63 100644 --- a/packages/backend/src/models/entities/UserProfile.ts +++ b/packages/backend/src/models/entities/UserProfile.ts @@ -101,6 +101,11 @@ export class MiUserProfile { }) public twoFactorSecret: string | null; + @Column('varchar', { + nullable: true, array: true, + }) + public twoFactorBackupSecret: string[] | null; + @Column('boolean', { default: false, }) diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 0c205654eb..3314464c31 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -321,6 +321,11 @@ export const packedMeDetailedOnlySchema = { type: 'boolean', nullable: false, optional: false, }, + twoFactorBackupCodesStock: { + type: 'string', + enum: ['full', 'partial', 'none'], + nullable: false, optional: false, + }, hideOnlineStatus: { type: 'boolean', nullable: false, optional: false, diff --git a/packages/backend/src/server/api/SigninApiService.ts b/packages/backend/src/server/api/SigninApiService.ts index d68b2617e3..58a5cca4fc 100644 --- a/packages/backend/src/server/api/SigninApiService.ts +++ b/packages/backend/src/server/api/SigninApiService.ts @@ -160,6 +160,13 @@ export class SigninApiService { }); } + if (profile.twoFactorBackupSecret?.includes(token)) { + await this.userProfilesRepository.update({ userId: profile.userId }, { + twoFactorBackupSecret: profile.twoFactorBackupSecret.filter((secret) => secret !== token), + }); + return this.signinService.signin(request, reply, user); + } + const delta = OTPAuth.TOTP.validate({ secret: OTPAuth.Secret.fromBase32(profile.twoFactorSecret!), digits: 6, diff --git a/packages/backend/src/server/api/endpoints/i/2fa/done.ts b/packages/backend/src/server/api/endpoints/i/2fa/done.ts index e508a28cc0..2d1457b9b5 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/done.ts @@ -54,8 +54,11 @@ export default class extends Endpoint { // eslint- throw new Error('not verified'); } + const backupCodes = Array.from({ length: 5 }, () => new OTPAuth.Secret().base32); + await this.userProfilesRepository.update(me.id, { twoFactorSecret: profile.twoFactorTempSecret, + twoFactorBackupSecret: backupCodes, twoFactorEnabled: true, }); @@ -64,6 +67,10 @@ export default class extends Endpoint { // eslint- detail: true, includeSecrets: true, })); + + return { + backupCodes: backupCodes, + }; }); } } diff --git a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts index ee58fb2af4..e017e2ef53 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts @@ -46,6 +46,7 @@ export default class extends Endpoint { // eslint- await this.userProfilesRepository.update(me.id, { twoFactorSecret: null, + twoFactorBackupSecret: null, twoFactorEnabled: false, usePasswordLessLogin: false, }); diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts index 387249871e..0aa7427da8 100644 --- a/packages/backend/test/e2e/2fa.ts +++ b/packages/backend/test/e2e/2fa.ts @@ -191,7 +191,7 @@ describe('2要素認証', () => { const doneResponse = await api('/i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); - assert.strictEqual(doneResponse.status, 204); + assert.strictEqual(doneResponse.status, 200); const usersShowResponse = await api('/users/show', { username, @@ -216,7 +216,7 @@ describe('2要素認証', () => { const doneResponse = await api('/i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); - assert.strictEqual(doneResponse.status, 204); + assert.strictEqual(doneResponse.status, 200); const registerKeyResponse = await api('/i/2fa/register-key', { password, @@ -272,7 +272,7 @@ describe('2要素認証', () => { const doneResponse = await api('/i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); - assert.strictEqual(doneResponse.status, 204); + assert.strictEqual(doneResponse.status, 200); const registerKeyResponse = await api('/i/2fa/register-key', { password, @@ -329,7 +329,7 @@ describe('2要素認証', () => { const doneResponse = await api('/i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); - assert.strictEqual(doneResponse.status, 204); + assert.strictEqual(doneResponse.status, 200); const registerKeyResponse = await api('/i/2fa/register-key', { password, @@ -371,7 +371,7 @@ describe('2要素認証', () => { const doneResponse = await api('/i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); - assert.strictEqual(doneResponse.status, 204); + assert.strictEqual(doneResponse.status, 200); const registerKeyResponse = await api('/i/2fa/register-key', { password, @@ -423,7 +423,7 @@ describe('2要素認証', () => { const doneResponse = await api('/i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); - assert.strictEqual(doneResponse.status, 204); + assert.strictEqual(doneResponse.status, 200); const usersShowResponse = await api('/users/show', { username, diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index 8afbcbe322..2c396813ff 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -152,6 +152,7 @@ describe('ユーザー', () => { preventAiLearning: user.preventAiLearning, isExplorable: user.isExplorable, isDeleted: user.isDeleted, + twoFactorBackupCodesStock: user.twoFactorBackupCodesStock, hideOnlineStatus: user.hideOnlineStatus, hasUnreadSpecifiedNotes: user.hasUnreadSpecifiedNotes, hasUnreadMentions: user.hasUnreadMentions, @@ -398,6 +399,7 @@ describe('ユーザー', () => { assert.strictEqual(response.preventAiLearning, true); assert.strictEqual(response.isExplorable, true); assert.strictEqual(response.isDeleted, false); + assert.strictEqual(response.twoFactorBackupCodesStock, 'none'); assert.strictEqual(response.hideOnlineStatus, false); assert.strictEqual(response.hasUnreadSpecifiedNotes, false); assert.strictEqual(response.hasUnreadMentions, false); diff --git a/packages/frontend/.storybook/changes.ts b/packages/frontend/.storybook/changes.ts index a1275132be..0cc648fbae 100644 --- a/packages/frontend/.storybook/changes.ts +++ b/packages/frontend/.storybook/changes.ts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + import fs from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; import path from 'node:path'; diff --git a/packages/frontend/.storybook/fakes.ts b/packages/frontend/.storybook/fakes.ts index a4289cff7d..14481deeea 100644 --- a/packages/frontend/.storybook/fakes.ts +++ b/packages/frontend/.storybook/fakes.ts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + import type { entities } from 'misskey-js' export function abuseUserReport() { @@ -110,6 +115,7 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi publicReactions: false, securityKeys: false, twoFactorEnabled: false, + twoFactorBackupCodesStock: 'none', updatedAt: null, uri: null, url: null, diff --git a/packages/frontend/.storybook/generate.tsx b/packages/frontend/.storybook/generate.tsx index d47d8672c7..d61df9e7be 100644 --- a/packages/frontend/.storybook/generate.tsx +++ b/packages/frontend/.storybook/generate.tsx @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + import { existsSync, readFileSync } from 'node:fs'; import { writeFile } from 'node:fs/promises'; import { basename, dirname } from 'node:path/posix'; diff --git a/packages/frontend/.storybook/main.ts b/packages/frontend/.storybook/main.ts index b64979980a..a450f8b46b 100644 --- a/packages/frontend/.storybook/main.ts +++ b/packages/frontend/.storybook/main.ts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + import { resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import type { StorybookConfig } from '@storybook/vue3-vite'; diff --git a/packages/frontend/.storybook/manager.ts b/packages/frontend/.storybook/manager.ts index 5653deee84..8f501111d0 100644 --- a/packages/frontend/.storybook/manager.ts +++ b/packages/frontend/.storybook/manager.ts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + import { addons } from '@storybook/manager-api'; import { create } from '@storybook/theming/create'; diff --git a/packages/frontend/.storybook/mocks.ts b/packages/frontend/.storybook/mocks.ts index 4091e39686..b60755feea 100644 --- a/packages/frontend/.storybook/mocks.ts +++ b/packages/frontend/.storybook/mocks.ts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + import { type SharedOptions, rest } from 'msw'; export const onUnhandledRequest = ((req, print) => { diff --git a/packages/frontend/.storybook/preload-locale.ts b/packages/frontend/.storybook/preload-locale.ts index 2b7362b88d..349cc13508 100644 --- a/packages/frontend/.storybook/preload-locale.ts +++ b/packages/frontend/.storybook/preload-locale.ts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + import { writeFile } from 'node:fs/promises'; import locales from '../../../locales/index.js'; diff --git a/packages/frontend/.storybook/preload-theme.ts b/packages/frontend/.storybook/preload-theme.ts index 42fbeff738..ad2cf18a35 100644 --- a/packages/frontend/.storybook/preload-theme.ts +++ b/packages/frontend/.storybook/preload-theme.ts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + import { readFile, writeFile } from 'node:fs/promises'; import JSON5 from 'json5'; diff --git a/packages/frontend/.storybook/preview.ts b/packages/frontend/.storybook/preview.ts index 67c81c666b..9860b60c67 100644 --- a/packages/frontend/.storybook/preview.ts +++ b/packages/frontend/.storybook/preview.ts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + import { addons } from '@storybook/addons'; import { FORCE_REMOUNT } from '@storybook/core-events'; import { type Preview, setup } from '@storybook/vue3'; diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index 2f1130d992..19f418b48d 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only - + diff --git a/packages/frontend/src/pages/scratchpad.vue b/packages/frontend/src/pages/scratchpad.vue index ec251c6640..6d68a26c3c 100644 --- a/packages/frontend/src/pages/scratchpad.vue +++ b/packages/frontend/src/pages/scratchpad.vue @@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- +
@@ -175,6 +175,14 @@ definePageMetadata({ position: relative; } +.code { + background: #2d2d2d; + color: #ccc; + font-size: 14px; + line-height: 1.5; + padding: 5px; +} + .ui { padding: 32px; } diff --git a/packages/frontend/src/pages/settings/2fa.qrdialog.vue b/packages/frontend/src/pages/settings/2fa.qrdialog.vue index 245d3e79e8..cf6b0227fd 100644 --- a/packages/frontend/src/pages/settings/2fa.qrdialog.vue +++ b/packages/frontend/src/pages/settings/2fa.qrdialog.vue @@ -4,45 +4,110 @@ SPDX-License-Identifier: AGPL-3.0-only -->