diff --git a/CHANGELOG.md b/CHANGELOG.md index bdbfdbe73..2d18b1b7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ChangeLog ========= 主に notable な changes を書いていきます +unlereased +---------- +* New: トークンを再生成できるように (#497) + 2461 (2017/08/28) ----------------- * Fix: モバイル版からアバターとバナーの設定を行えなかった問題を修正 @@ -11,8 +15,8 @@ ChangeLog ----------------- * New: モバイル版からプロフィールを設定できるように * New: モバイル版からサインアウトを行えるように -* Improve: 投稿ページに次の投稿/前の投稿リンクを作成 (#734) -* Improve: タイムラインの投稿をダブルクリックすることで詳細な情報が見れるように +* New: 投稿ページに次の投稿/前の投稿リンクを作成 (#734) +* New: タイムラインの投稿をダブルクリックすることで詳細な情報が見れるように * Fix: モバイル版でおすすめユーザーをフォローしてもタイムラインが更新されない (#736) * Fix: モバイル版で設定にアクセスできない * デザインの調整 diff --git a/locales/en.yml b/locales/en.yml index bfec7ebb5..950180278 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -28,6 +28,7 @@ common: loading: "Loading" ok: "OK" update-available: "New version of Misskey is now available({newer}, current is {current}). Reload page to apply update." + my-token-regenerated: "Your token is just regenerated, so you will signout." tags: mk-messaging-form: @@ -129,6 +130,9 @@ common: desktop: tags: + mk-api-info: + regenerate-token: "Please enter the password" + mk-drive-browser-base-contextmenu: create-folder: "Create a folder" upload: "Upload a file" diff --git a/locales/ja.yml b/locales/ja.yml index e2c537fc4..2655eb484 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -28,6 +28,7 @@ common: loading: "読み込み中" ok: "わかった" update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。" + my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" tags: mk-messaging-form: @@ -129,6 +130,9 @@ common: desktop: tags: + mk-api-info: + regenerate-token: "パスワードを入力してください" + mk-drive-browser-base-contextmenu: create-folder: "フォルダーを作成" upload: "ファイルをアップロード" diff --git a/src/api/common/generate-native-user-token.ts b/src/api/common/generate-native-user-token.ts new file mode 100644 index 000000000..2082b89a5 --- /dev/null +++ b/src/api/common/generate-native-user-token.ts @@ -0,0 +1,3 @@ +import rndstr from 'rndstr'; + +export default () => `!${rndstr('a-zA-Z0-9', 32)}`; diff --git a/src/api/endpoints.ts b/src/api/endpoints.ts index 5bbc480a8..a658c9a42 100644 --- a/src/api/endpoints.ts +++ b/src/api/endpoints.ts @@ -159,6 +159,10 @@ const endpoints: Endpoint[] = [ }, kind: 'account-write' }, + { + name: 'i/regenerate_token', + withCredential: true + }, { name: 'i/appdata/get', withCredential: true diff --git a/src/api/endpoints/i/regenerate_token.ts b/src/api/endpoints/i/regenerate_token.ts new file mode 100644 index 000000000..ccebbc810 --- /dev/null +++ b/src/api/endpoints/i/regenerate_token.ts @@ -0,0 +1,42 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import * as bcrypt from 'bcryptjs'; +import User from '../../models/user'; +import event from '../../event'; +import generateUserToken from '../../common/generate-native-user-token'; + +/** + * Regenerate native token + * + * @param {any} params + * @param {any} user + * @return {Promise} + */ +module.exports = async (params, user) => new Promise(async (res, rej) => { + // Get 'password' parameter + const [password, passwordErr] = $(params.password).string().$; + if (passwordErr) return rej('invalid password param'); + + // Compare password + const same = bcrypt.compareSync(password, user.password); + + if (!same) { + return rej('incorrect password'); + } + + // Generate secret + const secret = generateUserToken(); + + await User.update(user._id, { + $set: { + token: secret + } + }); + + res(); + + // Publish i updated event + event(user._id, 'my_token_regenerated'); +}); diff --git a/src/api/private/signup.ts b/src/api/private/signup.ts index 2375c2284..899fa8847 100644 --- a/src/api/private/signup.ts +++ b/src/api/private/signup.ts @@ -1,10 +1,10 @@ import * as express from 'express'; import * as bcrypt from 'bcryptjs'; -import rndstr from 'rndstr'; import recaptcha = require('recaptcha-promise'); import User from '../models/user'; import { validateUsername, validatePassword } from '../models/user'; import serialize from '../serializers/user'; +import generateUserToken from '../common/generate-native-user-token'; import config from '../../conf'; recaptcha.init({ @@ -58,7 +58,7 @@ export default async (req: express.Request, res: express.Response) => { const hash = bcrypt.hashSync(password, salt); // Generate secret - const secret = `!${rndstr('a-zA-Z0-9', 32)}`; + const secret = generateUserToken(); // Create account const account = await User.insert({ diff --git a/src/web/app/common/scripts/home-stream.js b/src/web/app/common/scripts/home-stream.js index 24f13cd29..c54cbd7f1 100644 --- a/src/web/app/common/scripts/home-stream.js +++ b/src/web/app/common/scripts/home-stream.js @@ -1,6 +1,7 @@ 'use strict'; import Stream from './stream'; +import signout from './signout'; /** * Home stream connection @@ -12,6 +13,11 @@ class Connection extends Stream { }); this.on('i_updated', me.update); + + this.on('my_token_regenerated', () => { + alert('%i18n:common.my-token-regenerated%'); + signout(); + }); } } diff --git a/src/web/app/common/tags/api-info.tag b/src/web/app/common/tags/api-info.tag deleted file mode 100644 index 612f20a7a..000000000 --- a/src/web/app/common/tags/api-info.tag +++ /dev/null @@ -1,27 +0,0 @@ - -

Token:{ I.token }

-

APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。

-

アカウントを乗っ取られてしまう可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。

-

万が一このトークンが漏れたりその可能性がある場合は - できます。(副作用として、ログインしているすべてのデバイスでログアウトが発生します) -

- - -
diff --git a/src/web/app/common/tags/index.js b/src/web/app/common/tags/index.js index 5dc4ef454..1ee8dab42 100644 --- a/src/web/app/common/tags/index.js +++ b/src/web/app/common/tags/index.js @@ -14,7 +14,6 @@ require('./forkit.tag'); require('./introduction.tag'); require('./copyright.tag'); require('./signin-history.tag'); -require('./api-info.tag'); require('./twitter-setting.tag'); require('./authorized-apps.tag'); require('./poll.tag'); diff --git a/src/web/app/desktop/scripts/password-dialog.js b/src/web/app/desktop/scripts/password-dialog.js new file mode 100644 index 000000000..2bdc93e42 --- /dev/null +++ b/src/web/app/desktop/scripts/password-dialog.js @@ -0,0 +1,11 @@ +import * as riot from 'riot'; + +export default (title, onOk, onCancel) => { + const dialog = document.body.appendChild(document.createElement('mk-input-dialog')); + return riot.mount(dialog, { + title: title, + type: 'password', + onOk: onOk, + onCancel: onCancel + }); +}; diff --git a/src/web/app/desktop/tags/input-dialog.tag b/src/web/app/desktop/tags/input-dialog.tag index f343c4625..78fd62ee8 100644 --- a/src/web/app/desktop/tags/input-dialog.tag +++ b/src/web/app/desktop/tags/input-dialog.tag @@ -5,7 +5,7 @@
- +
@@ -126,6 +126,7 @@ this.placeholder = this.opts.placeholder; this.default = this.opts.default; this.allowEmpty = this.opts.allowEmpty != null ? this.opts.allowEmpty : true; + this.type = this.opts.type ? this.opts.type : 'text'; this.on('mount', () => { this.text = this.refs.window.refs.text; @@ -156,6 +157,10 @@ this.refs.window.close(); }; + this.onInput = () => { + this.update(); + }; + this.onKeydown = e => { if (e.which == 13) { // Enter e.preventDefault(); diff --git a/src/web/app/desktop/tags/settings.tag b/src/web/app/desktop/tags/settings.tag index a89cfda0e..7fc6acb4a 100644 --- a/src/web/app/desktop/tags/settings.tag +++ b/src/web/app/desktop/tags/settings.tag @@ -211,3 +211,33 @@ }; + + +

Token:{ I.token }

+

APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。

+

アカウントを乗っ取られてしまう可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。

+

万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。(副作用として、ログインしているすべてのデバイスでログアウトが発生します)

+ + +
diff --git a/src/web/app/mobile/tags/page/settings/api.tag b/src/web/app/mobile/tags/page/settings/api.tag index 46419eb3d..25413e2d8 100644 --- a/src/web/app/mobile/tags/page/settings/api.tag +++ b/src/web/app/mobile/tags/page/settings/api.tag @@ -15,3 +15,22 @@ }); + + +

Token:{ I.token }

+

APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。

+

アカウントを乗っ取られてしまう可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。

+

万が一このトークンが漏れたりその可能性がある場合はデスクトップ版Misskeyから再生成できます。

+ + +