From 5ae6b0058ff4e5be19d4561713fc37e49be5ae1d Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 6 Jul 2019 00:46:00 +0900 Subject: やった (#5110) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/views/components/games/reversi/reversi.game.vue | 6 +++--- src/client/app/common/views/components/mfm.ts | 12 ++++++------ .../common/views/components/misskey-flavored-markdown.vue | 4 ++-- src/client/app/common/views/components/poll.vue | 2 +- src/client/app/common/views/components/user-list.vue | 2 +- src/client/app/common/views/components/user-name.vue | 2 +- src/client/app/common/views/deck/deck.notification.vue | 6 +++--- src/client/app/common/views/deck/deck.user-column.vue | 2 +- src/client/app/common/views/pages/follow.vue | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/client/app/common') diff --git a/src/client/app/common/views/components/games/reversi/reversi.game.vue b/src/client/app/common/views/components/games/reversi/reversi.game.vue index 3f481e8eb5..a7c918aa71 100644 --- a/src/client/app/common/views/components/games/reversi/reversi.game.vue +++ b/src/client/app/common/views/components/games/reversi/reversi.game.vue @@ -5,17 +5,17 @@

- +

- +

{{ $t('@.reversi.opponent-turn') }}

{{ $t('@.reversi.my-turn') }}

diff --git a/src/client/app/common/views/components/mfm.ts b/src/client/app/common/views/components/mfm.ts index fa798504c7..561c3d8e30 100644 --- a/src/client/app/common/views/components/mfm.ts +++ b/src/client/app/common/views/components/mfm.ts @@ -22,11 +22,11 @@ export default Vue.component('misskey-flavored-markdown', { type: String, required: true }, - shouldBreak: { + plain: { type: Boolean, - default: true + default: false }, - plainText: { + nowrap: { type: Boolean, default: false }, @@ -50,7 +50,7 @@ export default Vue.component('misskey-flavored-markdown', { render(createElement) { if (this.text == null || this.text == '') return; - const ast = (this.plainText ? parsePlain : parse)(this.text); + const ast = (this.plain ? parsePlain : parse)(this.text); let bigCount = 0; let motionCount = 0; @@ -60,7 +60,7 @@ export default Vue.component('misskey-flavored-markdown', { case 'text': { const text = token.node.props.text.replace(/(\r\n|\n|\r)/g, '\n'); - if (this.shouldBreak) { + if (!this.plain) { const x = text.split('\n') .map(t => t == '' ? [createElement('br')] : [createElement('span', t), createElement('br')]); x[x.length - 1].pop(); @@ -270,7 +270,7 @@ export default Vue.component('misskey-flavored-markdown', { }, props: { customEmojis: this.customEmojis || customEmojis, - normal: this.plainText + normal: this.plain } })]; } diff --git a/src/client/app/common/views/components/misskey-flavored-markdown.vue b/src/client/app/common/views/components/misskey-flavored-markdown.vue index a0ecbecbb2..64496f9c84 100644 --- a/src/client/app/common/views/components/misskey-flavored-markdown.vue +++ b/src/client/app/common/views/components/misskey-flavored-markdown.vue @@ -1,5 +1,5 @@ diff --git a/src/client/app/common/views/pages/page/page.button.vue b/src/client/app/common/views/pages/page/page.button.vue index 3747be96ce..9f760bf48c 100644 --- a/src/client/app/common/views/pages/page/page.button.vue +++ b/src/client/app/common/views/pages/page/page.button.vue @@ -27,6 +27,16 @@ export default Vue.extend({ } else if (this.value.action === 'resetRandom') { this.script.aiScript.updateRandomSeed(Math.random()); this.script.eval(); + } else if (this.value.action === 'pushEvent') { + this.$root.api('page-push', { + pageId: this.script.page.id, + event: this.value.event + }); + + this.$root.dialog({ + type: 'success', + text: this.script.interpolate(this.value.message) + }); } } } diff --git a/src/client/app/common/views/pages/page/page.vue b/src/client/app/common/views/pages/page/page.vue index 96a2cfafb7..a93d5316d5 100644 --- a/src/client/app/common/views/pages/page/page.vue +++ b/src/client/app/common/views/pages/page/page.vue @@ -35,8 +35,10 @@ class Script { public aiScript: ASEvaluator; private onError: any; public vars: Record; + public page: Record; - constructor(aiScript, onError) { + constructor(page, aiScript, onError) { + this.page = page; this.aiScript = aiScript; this.onError = onError; this.eval(); @@ -113,7 +115,7 @@ export default Vue.extend({ icon: faStickyNote }); const pageVars = this.getPageVars(); - this.script = new Script(new ASEvaluator(this.page.variables, pageVars, { + this.script = new Script(this.page, new ASEvaluator(this.page.variables, pageVars, { randomSeed: Math.random(), user: page.user, visitor: this.$store.state.i, diff --git a/src/server/api/endpoints/page-push.ts b/src/server/api/endpoints/page-push.ts new file mode 100644 index 0000000000..300df7c250 --- /dev/null +++ b/src/server/api/endpoints/page-push.ts @@ -0,0 +1,44 @@ +import $ from 'cafy'; +import define from '../define'; +import { ID } from '../../../misc/cafy-id'; +import { publishMainStream } from '../../../services/stream'; +import { Users, Pages } from '../../../models'; +import { ApiError } from '../error'; + +export const meta = { + requireCredential: true, + secure: true, + + params: { + pageId: { + validator: $.type(ID) + }, + + event: { + validator: $.str + } + }, + + errors: { + noSuchPage: { + message: 'No such page.', + code: 'NO_SUCH_PAGE', + id: '4a13ad31-6729-46b4-b9af-e86b265c2e74' + } + } +}; + +export default define(meta, async (ps, user) => { + const page = await Pages.findOne(ps.pageId); + if (page == null) { + throw new ApiError(meta.errors.noSuchPage); + } + + publishMainStream(user.id, 'pageEvent', { + pageId: ps.pageId, + event: ps.event, + user: await Users.pack(user, page.userId, { + detail: true + }) + }); +}); -- cgit v1.2.3-freya From 067e9ec6f4ca6f6741456f7d46bf8b237edffa77 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 6 Jul 2019 22:53:15 +0900 Subject: Fix bug --- src/client/app/common/views/components/url-preview.vue | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/app/common') diff --git a/src/client/app/common/views/components/url-preview.vue b/src/client/app/common/views/components/url-preview.vue index 20fbcbb046..476c671e77 100644 --- a/src/client/app/common/views/components/url-preview.vue +++ b/src/client/app/common/views/components/url-preview.vue @@ -63,6 +63,7 @@ export default Vue.extend({ data() { const isSelf = this.url.startsWith(local); const hasRoute = + (this.url.substr(local.length) === '/') || this.url.substr(local.length).startsWith('/@') || this.url.substr(local.length).startsWith('/notes/') || this.url.substr(local.length).startsWith('/pages/'); -- cgit v1.2.3-freya From e97dd13e815b277b1aafab4b217ebdeeaa5fb347 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 6 Jul 2019 23:11:16 +0900 Subject: Pages: ボタンを色付き表示できるように MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/ja-JP.yml | 1 + .../app/common/views/pages/page-editor/els/page-editor.el.button.vue | 2 ++ src/client/app/common/views/pages/page/page.button.vue | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/client/app/common') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 9726d49c25..6666e630a3 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2024,6 +2024,7 @@ pages: _button: text: "タイトル" + colored: "色付き" action: "ボタンを押したときの動作" _action: dialog: "ダイアログを表示する" diff --git a/src/client/app/common/views/pages/page-editor/els/page-editor.el.button.vue b/src/client/app/common/views/pages/page-editor/els/page-editor.el.button.vue index 579de6a8fc..04001d8560 100644 --- a/src/client/app/common/views/pages/page-editor/els/page-editor.el.button.vue +++ b/src/client/app/common/views/pages/page-editor/els/page-editor.el.button.vue @@ -4,6 +4,7 @@

{{ $t('blocks._button.text') }} + {{ $t('blocks._button.colored') }} @@ -52,6 +53,7 @@ export default Vue.extend({ if (this.value.content == null) Vue.set(this.value, 'content', null); if (this.value.event == null) Vue.set(this.value, 'event', null); if (this.value.message == null) Vue.set(this.value, 'message', null); + if (this.value.message == null) Vue.set(this.value, 'primary', false); }, }); diff --git a/src/client/app/common/views/pages/page/page.button.vue b/src/client/app/common/views/pages/page/page.button.vue index 9f760bf48c..d3f0307625 100644 --- a/src/client/app/common/views/pages/page/page.button.vue +++ b/src/client/app/common/views/pages/page/page.button.vue @@ -1,6 +1,6 @@ -- cgit v1.2.3-freya From 047a46d96689a97bee4c843fcd86e63b816846f1 Mon Sep 17 00:00:00 2001 From: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com> Date: Sun, 7 Jul 2019 01:38:36 +0900 Subject: Support password-less login with WebAuthn (#5112) * Support password-less login with WebAuthn * Fix initial value of usePasswordLessLogin --- locales/ja-JP.yml | 1 + migration/1562422242907-PasswordLessLogin.ts | 13 ++++++++ .../app/common/views/components/settings/2fa.vue | 16 ++++++++++ src/client/app/common/views/components/signin.vue | 6 +++- src/models/entities/user-profile.ts | 5 +++ src/models/repositories/user.ts | 2 +- src/server/api/endpoints/i/2fa/password-less.ts | 21 +++++++++++++ src/server/api/private/signin.ts | 36 +++++++++++++++++----- 8 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 migration/1562422242907-PasswordLessLogin.ts create mode 100644 src/server/api/endpoints/i/2fa/password-less.ts (limited to 'src/client/app/common') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 6666e630a3..5daf7e7e3a 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1112,6 +1112,7 @@ desktop/views/components/settings.2fa.vue: register-security-key: "キーの登録を完了" something-went-wrong: "わー! キーを登録する際に問題が発生しました:" key-unregistered: "キーが削除されました" + use-password-less-login: "パスワードなしのログインを使用" common/views/components/media-image.vue: sensitive: "閲覧注意" diff --git a/migration/1562422242907-PasswordLessLogin.ts b/migration/1562422242907-PasswordLessLogin.ts new file mode 100644 index 0000000000..e789a34334 --- /dev/null +++ b/migration/1562422242907-PasswordLessLogin.ts @@ -0,0 +1,13 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class PasswordLessLogin1562422242907 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_profile" ADD COLUMN "usePasswordLessLogin" boolean DEFAULT false NOT NULL`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "usePasswordLessLogin"`); + } + +} diff --git a/src/client/app/common/views/components/settings/2fa.vue b/src/client/app/common/views/components/settings/2fa.vue index eb645898e2..813a91b5c0 100644 --- a/src/client/app/common/views/components/settings/2fa.vue +++ b/src/client/app/common/views/components/settings/2fa.vue @@ -28,6 +28,10 @@
+ + {{ $t('use-password-less-login') }} + + {{ $t('something-went-wrong') }} {{ registration.error }} {{ $t('register') }} @@ -80,6 +84,7 @@ export default Vue.extend({ return { data: null, supportsCredentials: !!navigator.credentials, + usePasswordLessLogin: this.$store.state.i.usePasswordLessLogin, registration: null, keyName: '', token: null @@ -112,6 +117,9 @@ export default Vue.extend({ if (canceled) return; this.$root.api('i/2fa/unregister', { password: password + }).then(() => { + this.usePasswordLessLogin = false; + this.updatePasswordLessLogin(); }).then(() => { this.$notify(this.$t('unregistered')); this.$store.state.i.twoFactorEnabled = false; @@ -157,6 +165,9 @@ export default Vue.extend({ return this.$root.api('i/2fa/remove-key', { password, credentialId: key.id + }).then(() => { + this.usePasswordLessLogin = false; + this.updatePasswordLessLogin(); }).then(() => { this.$notify(this.$t('key-unregistered')); }); @@ -213,6 +224,11 @@ export default Vue.extend({ this.registration.stage = -1; }); }); + }, + updatePasswordLessLogin() { + this.$root.api('i/2fa/password-less', { + value: !!this.usePasswordLessLogin + }); } } }); diff --git a/src/client/app/common/views/components/signin.vue b/src/client/app/common/views/components/signin.vue index 8498a1dc3e..f76f989d6d 100644 --- a/src/client/app/common/views/components/signin.vue +++ b/src/client/app/common/views/components/signin.vue @@ -7,7 +7,7 @@ - + {{ $t('password') }} @@ -28,6 +28,10 @@

{{ $t('enter-2fa-code') }}

+ + {{ $t('password') }} + + {{ $t('@.2fa') }} diff --git a/src/models/entities/user-profile.ts b/src/models/entities/user-profile.ts index 6f960f1b7b..4a588ebfbf 100644 --- a/src/models/entities/user-profile.ts +++ b/src/models/entities/user-profile.ts @@ -81,6 +81,11 @@ export class UserProfile { }) public securityKeysAvailable: boolean; + @Column('boolean', { + default: false, + }) + public usePasswordLessLogin: boolean; + @Column('varchar', { length: 128, nullable: true, comment: 'The password hash of the User. It will be null if the origin of the user is local.' diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts index cc89b674c5..06da74197f 100644 --- a/src/models/repositories/user.ts +++ b/src/models/repositories/user.ts @@ -156,6 +156,7 @@ export class UserRepository extends Repository { detail: true }), twoFactorEnabled: profile!.twoFactorEnabled, + usePasswordLessLogin: profile!.usePasswordLessLogin, securityKeys: profile!.twoFactorEnabled ? UserSecurityKeys.count({ userId: user.id @@ -208,7 +209,6 @@ export class UserRepository extends Repository { select: ['id', 'name', 'lastUsed'] }) : [] - } : {}), ...(relation ? { diff --git a/src/server/api/endpoints/i/2fa/password-less.ts b/src/server/api/endpoints/i/2fa/password-less.ts new file mode 100644 index 0000000000..19e75ca1c5 --- /dev/null +++ b/src/server/api/endpoints/i/2fa/password-less.ts @@ -0,0 +1,21 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { UserProfiles } from '../../../../../models'; + +export const meta = { + requireCredential: true, + + secure: true, + + params: { + value: { + validator: $.boolean + } + } +}; + +export default define(meta, async (ps, user) => { + await UserProfiles.update(user.id, { + usePasswordLessLogin: ps.value + }); +}); diff --git a/src/server/api/private/signin.ts b/src/server/api/private/signin.ts index bc9346d088..67afed760b 100644 --- a/src/server/api/private/signin.ts +++ b/src/server/api/private/signin.ts @@ -72,19 +72,25 @@ export default async (ctx: Koa.BaseContext) => { } } - if (!same) { - await fail(403, { - error: 'incorrect password' - }); - return; - } - if (!profile.twoFactorEnabled) { - signin(ctx, user); + if (same) { + signin(ctx, user); + } else { + await fail(403, { + error: 'incorrect password' + }); + } return; } if (token) { + if (!same) { + await fail(403, { + error: 'incorrect password' + }); + return; + } + const verified = (speakeasy as any).totp.verify({ secret: profile.twoFactorSecret, encoding: 'base32', @@ -101,6 +107,13 @@ export default async (ctx: Koa.BaseContext) => { return; } } else if (body.credentialId) { + if (!same && !profile.usePasswordLessLogin) { + await fail(403, { + error: 'incorrect password' + }); + return; + } + const clientDataJSON = Buffer.from(body.clientDataJSON, 'hex'); const clientData = JSON.parse(clientDataJSON.toString('utf-8')); const challenge = await AttestationChallenges.findOne({ @@ -163,6 +176,13 @@ export default async (ctx: Koa.BaseContext) => { return; } } else { + if (!same && !profile.usePasswordLessLogin) { + await fail(403, { + error: 'incorrect password' + }); + return; + } + const keys = await UserSecurityKeys.find({ userId: user.id }); -- cgit v1.2.3-freya From 2afcdda0587b8f63b5bfd8c28348ede41b5f12ee Mon Sep 17 00:00:00 2001 From: tamaina Date: Fri, 19 Apr 2019 11:07:54 +0900 Subject: wip --- locales/ja-JP.yml | 13 +++++++ src/client/app/boot.js | 16 ++++----- .../common/views/components/settings/app-type.vue | 40 ++++++++++++++++++++++ .../common/views/components/settings/settings.vue | 3 ++ src/client/app/store.ts | 1 + 5 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 src/client/app/common/views/components/settings/app-type.vue (limited to 'src/client/app/common') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 5daf7e7e3a..c5325d2fab 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -460,6 +460,8 @@ common/views/components/connect-failed.troubleshooter.vue: flush: "キャッシュの削除" set-version: "バージョン指定" + + common/views/components/media-banner.vue: sensitive: "閲覧注意" click-to-show: "クリックして表示" @@ -637,6 +639,17 @@ common/views/components/emoji-picker.vue: symbols: "記号" flags: "旗" +common/views/components/settings/client-mode.vue: + title: "クライアント" + select-app-type: "利用するクライアントのモード" + choices: + auto: "自動で選択" + desktop: "デスクトップ版に固定" + mobile: "モバイル版に固定" + desktop: "デスクトップ" + mobile: "モバイル" + info: "変更はページの再度読み込み後に反映されます。" + common/views/components/signin.vue: username: "ユーザー名" password: "パスワード" diff --git a/src/client/app/boot.js b/src/client/app/boot.js index 01104bf715..56eb59e21e 100644 --- a/src/client/app/boot.js +++ b/src/client/app/boot.js @@ -35,12 +35,12 @@ const url = new URL(location.href); //#region Detect app name - let app = null; + var appType = null; - if (`${url.pathname}/`.startsWith('/docs/')) app = 'docs'; - if (`${url.pathname}/`.startsWith('/dev/')) app = 'dev'; - if (`${url.pathname}/`.startsWith('/auth/')) app = 'auth'; - if (`${url.pathname}/`.startsWith('/admin/')) app = 'admin'; + if (`${url.pathname}/`.startsWith('/docs/')) appType = 'docs'; + if (`${url.pathname}/`.startsWith('/dev/')) appType = 'dev'; + if (`${url.pathname}/`.startsWith('/auth/')) appType = 'auth'; + if (`${url.pathname}/`.startsWith('/admin/')) appType = 'admin'; //#endregion // Script version @@ -103,15 +103,15 @@ } // Switch desktop or mobile version - if (app == null) { - app = isMobile ? 'mobile' : 'desktop'; + if (appType == null) { + appType = isMobile ? 'mobile' : 'desktop'; } // Load an app script // Note: 'async' make it possible to load the script asyncly. // 'defer' make it possible to run the script when the dom loaded. const script = document.createElement('script'); - script.setAttribute('src', `/assets/${app}.${ver}.js`); + script.setAttribute('src', `/assets/${appType}.${ver}.js`); script.setAttribute('async', 'true'); script.setAttribute('defer', 'true'); head.appendChild(script); diff --git a/src/client/app/common/views/components/settings/app-type.vue b/src/client/app/common/views/components/settings/app-type.vue new file mode 100644 index 0000000000..533fd51517 --- /dev/null +++ b/src/client/app/common/views/components/settings/app-type.vue @@ -0,0 +1,40 @@ + + + diff --git a/src/client/app/common/views/components/settings/settings.vue b/src/client/app/common/views/components/settings/settings.vue index 1254eb5e5e..5f370c8be7 100644 --- a/src/client/app/common/views/components/settings/settings.vue +++ b/src/client/app/common/views/components/settings/settings.vue @@ -163,6 +163,7 @@ +