From 18c4d01feceec0cd2043fb766cafd875f6d74fed Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2017 15:23:16 +0900 Subject: [PATCH 01/19] WIP #23 Add services to .travis.yml --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index ee6cc0986..fb24086b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,9 @@ language: node_js node_js: - "7.3.0" +services: + - mongodb + - redis-server before_script: - "mkdir -p ./.config && cp ./.ci-files/config.yml ./.config" env: From 307d2b7a4106326413b4085e908e601c81041672 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2017 15:25:26 +0900 Subject: [PATCH 02/19] Clean up --- src/web/app/desktop/script.js | 5 -- src/web/app/desktop/tags.ls | 2 - src/web/app/desktop/tags/log-window.tag | 20 -------- src/web/app/desktop/tags/log.tag | 62 ------------------------- 4 files changed, 89 deletions(-) delete mode 100644 src/web/app/desktop/tags/log-window.tag delete mode 100644 src/web/app/desktop/tags/log.tag diff --git a/src/web/app/desktop/script.js b/src/web/app/desktop/script.js index 179cfa332..980ae9772 100644 --- a/src/web/app/desktop/script.js +++ b/src/web/app/desktop/script.js @@ -32,11 +32,6 @@ boot(me => { // Register mixins mixins(me); - // Debug - if (me != null && me.data.debug) { - riot.mount(document.body.appendChild(document.createElement('mk-log-window'))); - } - // Start routing route(me); }); diff --git a/src/web/app/desktop/tags.ls b/src/web/app/desktop/tags.ls index f78d36734..90e888ee9 100644 --- a/src/web/app/desktop/tags.ls +++ b/src/web/app/desktop/tags.ls @@ -99,5 +99,3 @@ require './tags/user-followers-window.tag' require './tags/list-user.tag' require './tags/ui-notification.tag' require './tags/signin-history.tag' -require './tags/log.tag' -require './tags/log-window.tag' diff --git a/src/web/app/desktop/tags/log-window.tag b/src/web/app/desktop/tags/log-window.tag deleted file mode 100644 index 6dabc4de3..000000000 --- a/src/web/app/desktop/tags/log-window.tag +++ /dev/null @@ -1,20 +0,0 @@ -mk-log-window - mk-window@window(width={ '600px' }, height={ '400px' }) - - i.fa.fa-terminal - | Log - - - mk-log - - -style. - > mk-window - [data-yield='header'] - > i - margin-right 4px - -script. - @on \mount ~> - @refs.window.on \closed ~> - @unmount! diff --git a/src/web/app/desktop/tags/log.tag b/src/web/app/desktop/tags/log.tag deleted file mode 100644 index 20e5f8f69..000000000 --- a/src/web/app/desktop/tags/log.tag +++ /dev/null @@ -1,62 +0,0 @@ -mk-log - header - button.follow(class={ following: following }, onclick={ follow }) Follow - div.logs@logs - code(each={ logs }) - span.date { date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds() } - span.message { message } - -style. - display block - height 100% - color #fff - background #000 - - > header - height 32px - background #343a42 - - > button - line-height 32px - - > .follow - position absolute - top 0 - right 0 - - &.following - color #ff0 - - > .logs - height calc(100% - 32px) - overflow auto - - > code - display block - padding 4px 8px - - &:hover - background rgba(#fff, 0.15) - - > .date - margin-right 8px - opacity 0.5 - -script. - @mixin \log - - @following = true - - @on \mount ~> - @log-event.on \log @on-log - - @on \unmount ~> - @log-event.off \log @on-log - - @follow = ~> - @following = true - - @on-log = ~> - @update! - if @following - @refs.logs.scroll-top = @refs.logs.scroll-height From da77aab7c4d7a9e4778f521f7333116efaaf8fc1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2017 15:26:40 +0900 Subject: [PATCH 03/19] Fix bug --- src/web/app/common/tags/time.tag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/app/common/tags/time.tag b/src/web/app/common/tags/time.tag index 56c3b8ecc..52ad89a44 100644 --- a/src/web/app/common/tags/time.tag +++ b/src/web/app/common/tags/time.tag @@ -11,7 +11,7 @@ script. @absolute = @time.get-full-year! + \年 + - @time.get-month! + \月 + + @time.get-month! + 1 + \月 + @time.get-date! + \日 + ' ' + @time.get-hours! + \時 + From 1de54209d022143b62f5fbd340edc8dd9c1b01ba Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2017 15:27:25 +0900 Subject: [PATCH 04/19] Update dependency :rocket: --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 13cf6dcaa..5c7503077 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "livescript": "1.5.0", "mime-types": "2.1.13", "mocha": "3.2.0", - "mongodb": "2.2.16", + "mongodb": "2.2.19", "ms": "0.7.2", "multer": "1.2.1", "nprogress": "0.2.0", From 39eabbd2c0413f14d5b5472e651f9c34abaff2b4 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2017 15:32:04 +0900 Subject: [PATCH 05/19] Use nyaize package for nya filter :package: --- gulpfile.ts | 1 + package.json | 1 + src/web/app/common/scripts/text-compiler.js | 6 ++---- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gulpfile.ts b/gulpfile.ts index 1c5516801..5ae2652c6 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -149,6 +149,7 @@ const aliasifyConfig = { 'chart.js': './node_modules/chart.js/src/chart.js', 'textarea-caret-position': './node_modules/textarea-caret/index.js', 'misskey-text': './src/common/text/index.js', + 'nyaize': './node_modules/nyaize/built/index.js', 'strength.js': './node_modules/syuilo-password-strength/strength.js', 'cropper': './node_modules/cropperjs/dist/cropper.js', 'Sortable': './node_modules/sortablejs/Sortable.js', diff --git a/package.json b/package.json index 5c7503077..360025749 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "ms": "0.7.2", "multer": "1.2.1", "nprogress": "0.2.0", + "nyaize": "0.0.2", "page": "1.7.1", "prominence": "0.2.0", "pug": "2.0.0-beta6", diff --git a/src/web/app/common/scripts/text-compiler.js b/src/web/app/common/scripts/text-compiler.js index f6c531c6c..8ea2361b8 100644 --- a/src/web/app/common/scripts/text-compiler.js +++ b/src/web/app/common/scripts/text-compiler.js @@ -1,4 +1,5 @@ const riot = require('riot'); +const nyaize = require('nyaize').default; module.exports = function(tokens, shouldBreak, escape) { if (shouldBreak == null) { @@ -34,10 +35,7 @@ module.exports = function(tokens, shouldBreak, escape) { }).join(''); if (me && me.data && me.data.nya) { - text = text.replace(/な/g, 'にゃ') - .replace(/ニャ/g, 'にゃ') - .replace(/にゃでにゃで/g, 'なでなで') - .replace(/ニャデニャデ/g, 'ナデナデ'); + text = nyaize(text); } return text; From 1232286158629e805093cd13ad6bc12ca337f015 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 4 Jan 2017 15:46:12 +0900 Subject: [PATCH 06/19] Fix bug --- src/web/app/common/scripts/date-stringify.ls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/app/common/scripts/date-stringify.ls b/src/web/app/common/scripts/date-stringify.ls index 9aa8b3e6c..7e85192ce 100644 --- a/src/web/app/common/scripts/date-stringify.ls +++ b/src/web/app/common/scripts/date-stringify.ls @@ -3,7 +3,7 @@ module.exports = (date) -> text = date.get-full-year! + \年 + - date.get-month! + \月 + + date.get-month! + 1 + \月 + date.get-date! + \日 + ' ' + date.get-hours! + \時 + From 257f1ecdcf66eebb3ac35bad8db3c3be110de475 Mon Sep 17 00:00:00 2001 From: Aya Morisawa Date: Thu, 5 Jan 2017 07:02:52 +0900 Subject: [PATCH 07/19] Update type definition --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 360025749..b60fb5123 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "@types/browserify": "12.0.30", "@types/chalk": "0.4.31", "@types/compression": "0.0.33", - "@types/cors": "0.0.33", + "@types/cors": "2.8.0", "@types/elasticsearch": "5.0.9", "@types/escape-html": "0.0.19", "@types/event-stream": "3.3.30", From 07834db0364d07f66e458fdcc1f5a93fdd8f5e9b Mon Sep 17 00:00:00 2001 From: Aya Morisawa Date: Thu, 5 Jan 2017 07:04:00 +0900 Subject: [PATCH 08/19] Update browserify --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b60fb5123..423103c75 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "babel-preset-stage-3": "6.17.0", "bcrypt": "1.0.2", "body-parser": "1.15.2", - "browserify": "13.1.1", + "browserify": "13.3.0", "browserify-livescript": "0.2.3", "chalk": "1.1.3", "chart.js": "2.4.0", From 56cb70ee847bd511c5a925dbad3e495f22126c7c Mon Sep 17 00:00:00 2001 From: ha-dai Date: Thu, 5 Jan 2017 21:58:02 +0900 Subject: [PATCH 09/19] Improve convenience. --- src/api/endpoints/users/posts.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/api/endpoints/users/posts.js b/src/api/endpoints/users/posts.js index 6d6f8a690..e1a59efa2 100644 --- a/src/api/endpoints/users/posts.js +++ b/src/api/endpoints/users/posts.js @@ -20,8 +20,18 @@ module.exports = (params, me) => { // Get 'user_id' parameter const userId = params.user_id; - if (userId === undefined || userId === null) { - return rej('user_id is required'); + if (userId === undefined || userId === null || userId === '') { + userId = null; + } + + // Get 'username' parameter + const username = params.username; + if (username === undefined || username === null || username === '') { + username = null; + } + + if (userId === null && username === null) { + return rej('user_id or username is required'); } // Get 'with_replies' parameter @@ -62,9 +72,9 @@ module.exports = (params, me) => } // Lookup user - const user = await User.findOne({ - _id: new mongo.ObjectID(userId) - }); + const user = userId !== null + ? await User.findOne({ _id: new mongo.ObjectID(userId) }) + : await User.findOne({ username_lower: username.toLowerCase() }); if (user === null) { return rej('user not found'); From a63de6d776d6f9f7840555a86fa0af05e173bc91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?syuilo=E2=AD=90=EF=B8=8F?= Date: Thu, 5 Jan 2017 22:15:53 +0900 Subject: [PATCH 10/19] Fix bug Use `let` instead of `const` --- src/api/endpoints/users/posts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/endpoints/users/posts.js b/src/api/endpoints/users/posts.js index e1a59efa2..1b8dfe031 100644 --- a/src/api/endpoints/users/posts.js +++ b/src/api/endpoints/users/posts.js @@ -19,13 +19,13 @@ module.exports = (params, me) => new Promise(async (res, rej) => { // Get 'user_id' parameter - const userId = params.user_id; + let userId = params.user_id; if (userId === undefined || userId === null || userId === '') { userId = null; } // Get 'username' parameter - const username = params.username; + let username = params.username; if (username === undefined || username === null || username === '') { username = null; } From fa591e5c9b27752bbe55c28cb3f7f798558104a6 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 6 Jan 2017 01:28:16 +0900 Subject: [PATCH 11/19] =?UTF-8?q?=E3=82=A2=E3=82=AF=E3=82=BB=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=83=BC=E3=82=AF=E3=83=B3=E3=81=AF=20i=20=E3=81=AB?= =?UTF-8?q?=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit トークンの先頭に ! がプリフィックスされているかどうかでユーザー固有のトークンかどうか判別する --- docs/api/getting-started.pug | 2 +- src/api/authenticate.ts | 21 ++++++++++----------- src/api/private/signup.ts | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/docs/api/getting-started.pug b/docs/api/getting-started.pug index 8e6e6b4f4..f56574523 100644 --- a/docs/api/getting-started.pug +++ b/docs/api/getting-started.pug @@ -71,4 +71,4 @@ block content br | 上手くいけば、認証したユーザーのアクセストークンがレスポンスとして取得できます。おめでとうございます! - p アクセストークンを取得できたら、あとは簡単です。REST APIなら、リクエストにアクセストークンを_userkey(「自分のアクセストークンを取得したい場合」の方法で取得したアクセストークンの場合はi)としてパラメータに含めるだけです。 + p アクセストークンを取得できたら、あとは簡単です。REST APIなら、リクエストにアクセストークンをiとしてパラメータに含めるだけです。 diff --git a/src/api/authenticate.ts b/src/api/authenticate.ts index 5798adb83..16a7ee1b4 100644 --- a/src/api/authenticate.ts +++ b/src/api/authenticate.ts @@ -20,10 +20,14 @@ export interface IAuthContext { isSecure: boolean; } -export default (req: express.Request) => - new Promise(async (resolve, reject) => { - const token = req.body['i']; - if (token) { +export default (req: express.Request) => new Promise(async (resolve, reject) => { + const token = req.body['i'] || req.body['_userkey']; // そのうち_userkeyは削除 + + if (token == null) { + return resolve({ app: null, user: null, isSecure: false }); + } + + if (token[0] == '!') { const user = await User .findOne({ token: token }); @@ -36,12 +40,9 @@ export default (req: express.Request) => user: user, isSecure: true }); - } - - const userkey = req.headers['userkey'] || req.body['_userkey']; - if (userkey) { + } else { const userkeyDoc = await Userkey.findOne({ - key: userkey + key: token }); if (userkeyDoc === null) { @@ -56,6 +57,4 @@ export default (req: express.Request) => return resolve({ app: app, user: user, isSecure: false }); } - - return resolve({ app: null, user: null, isSecure: false }); }); diff --git a/src/api/private/signup.ts b/src/api/private/signup.ts index c50b07005..592dfcceb 100644 --- a/src/api/private/signup.ts +++ b/src/api/private/signup.ts @@ -48,7 +48,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 = '!' + rndstr('a-zA-Z0-9', 32); // Create account const inserted = await User.insert({ From 2ded8ba8580f49741e0d5e436f65561c8dd9ef18 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 6 Jan 2017 01:45:02 +0900 Subject: [PATCH 12/19] Fix bug, Support thirdparty streaming access --- src/api/streaming.ts | 40 +++++++++++++------ src/web/app/boot.js | 2 +- .../app/common/scripts/messaging-stream.ls | 2 +- src/web/app/common/scripts/stream.ls | 5 +-- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 38068d1e3..93d5f217b 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -2,6 +2,7 @@ import * as http from 'http'; import * as websocket from 'websocket'; import * as redis from 'redis'; import User from './models/user'; +import Userkey from './models/userkey'; import homeStream from './stream/home'; import messagingStream from './stream/messaging'; @@ -17,7 +18,13 @@ module.exports = (server: http.Server) => { ws.on('request', async (request) => { const connection = request.accept(); - const user = await authenticate(connection); + const user = await authenticate(connection, request.resourceURL.query.i); + + if (user == null) { + connection.send('authentication-failed'); + connection.close(); + return; + } // Connect to Redis const subscriber = redis.createClient( @@ -41,29 +48,36 @@ module.exports = (server: http.Server) => { }); }; -function authenticate(connection: websocket.connection): Promise { - return new Promise((resolve, reject) => { - // Listen first message - connection.once('message', async (data) => { - const msg = JSON.parse(data.utf8Data); - +function authenticate(connection: websocket.connection, token: string): Promise { + return new Promise(async (resolve, reject) => { + if (token[0] == '!') { // Fetch user // SELECT _id const user = await User .findOne({ - token: msg.i + token: token }, { _id: true }); - if (user === null) { - connection.close(); - return; + resolve(user); + } else { + const userkey = await Userkey.findOne({ + key: token + }); + + if (userkey == null) { + return reject('invalid userkey'); } - connection.send('authenticated'); + // Fetch user + // SELECT _id + const user = await User + .findOne({ _id: userkey.user_id }, { + _id: true + }); resolve(user); - }); + } }); } diff --git a/src/web/app/boot.js b/src/web/app/boot.js index 5067600c6..e8e504c2b 100644 --- a/src/web/app/boot.js +++ b/src/web/app/boot.js @@ -39,7 +39,7 @@ try { checkForUpdate(); // Get token from cookie -const i = (document.cookie.match(/i=(\w+)/) || [null, null])[1]; +const i = (document.cookie.match(/i=(!\w+)/) || [null, null])[1]; // ユーザーをフェッチしてコールバックする module.exports = callback => { diff --git a/src/web/app/common/scripts/messaging-stream.ls b/src/web/app/common/scripts/messaging-stream.ls index 298285dc9..ac3e74f1f 100644 --- a/src/web/app/common/scripts/messaging-stream.ls +++ b/src/web/app/common/scripts/messaging-stream.ls @@ -9,7 +9,7 @@ class Connection @event = riot.observable! @me = me host = CONFIG.api.url.replace \http \ws - @socket = new ReconnectingWebSocket "#{host}/messaging?otherparty=#{otherparty}" + @socket = new ReconnectingWebSocket "#{host}/messaging?i=#{me.token}&otherparty=#{otherparty}" @socket.add-event-listener \open @on-open @socket.add-event-listener \message @on-message diff --git a/src/web/app/common/scripts/stream.ls b/src/web/app/common/scripts/stream.ls index 534048248..64ae03817 100644 --- a/src/web/app/common/scripts/stream.ls +++ b/src/web/app/common/scripts/stream.ls @@ -9,13 +9,12 @@ module.exports = (me) ~> state-ev = riot.observable! event = riot.observable! - socket = new ReconnectingWebSocket CONFIG.api.url.replace \http \ws + host = CONFIG.api.url.replace \http \ws + socket = new ReconnectingWebSocket "#{host}?i=#{me.token}" socket.onopen = ~> state := \connected state-ev.trigger \connected - socket.send JSON.stringify do - i: me.token socket.onclose = ~> state := \reconnecting From 733b3d81326c85127037ec572ddfd6054b65adfb Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 6 Jan 2017 02:04:00 +0900 Subject: [PATCH 13/19] Mobile: Fix design glitch :art: --- src/web/app/mobile/tags/user-preview.tag | 49 +++++++++--------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/src/web/app/mobile/tags/user-preview.tag b/src/web/app/mobile/tags/user-preview.tag index 4f5fbc152..56bd93825 100644 --- a/src/web/app/mobile/tags/user-preview.tag +++ b/src/web/app/mobile/tags/user-preview.tag @@ -3,11 +3,10 @@ mk-user-preview img.avatar(src={ user.avatar_url + '?thumbnail&size=64' }, alt='avatar') div.main header - div.left - a.name(href={ CONFIG.url + '/' + user.username }) - | { user.name } - span.username - | @{ user.username } + a.name(href={ CONFIG.url + '/' + user.username }) + | { user.name } + span.username + | @{ user.username } div.body div.bio { user.bio } @@ -57,36 +56,26 @@ style. width calc(100% - 74px) > header - white-space nowrap - @media (min-width 500px) margin-bottom 2px - &:after - content "" - display block - clear both + > .name + display inline + margin 0 + padding 0 + color #777 + font-size 1em + font-weight 700 + text-align left + text-decoration none - > .left - float left + &:hover + text-decoration underline - > .name - display inline - margin 0 - padding 0 - color #777 - font-size 1em - font-weight 700 - text-align left - text-decoration none - - &:hover - text-decoration underline - - > .username - text-align left - margin 0 0 0 8px - color #ccc + > .username + text-align left + margin 0 0 0 8px + color #ccc > .body From 86548f6468217f45d0b59a04e6283492a1eef0bf Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 6 Jan 2017 11:07:42 +0900 Subject: [PATCH 14/19] Refactor: Extract isNativeToken method --- src/api/authenticate.ts | 3 ++- src/api/common/is-native-token.ts | 1 + src/api/streaming.ts | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 src/api/common/is-native-token.ts diff --git a/src/api/authenticate.ts b/src/api/authenticate.ts index 16a7ee1b4..832517379 100644 --- a/src/api/authenticate.ts +++ b/src/api/authenticate.ts @@ -2,6 +2,7 @@ import * as express from 'express'; import App from './models/app'; import User from './models/user'; import Userkey from './models/userkey'; +import isNativeToken from './common/is-native-token'; export interface IAuthContext { /** @@ -27,7 +28,7 @@ export default (req: express.Request) => new Promise(async (resolv return resolve({ app: null, user: null, isSecure: false }); } - if (token[0] == '!') { + if (isNativeToken(token)) { const user = await User .findOne({ token: token }); diff --git a/src/api/common/is-native-token.ts b/src/api/common/is-native-token.ts new file mode 100644 index 000000000..0769a4812 --- /dev/null +++ b/src/api/common/is-native-token.ts @@ -0,0 +1 @@ +export default (token: string) => token[0] == '!'; diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 93d5f217b..84a0f9ddf 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -3,6 +3,7 @@ import * as websocket from 'websocket'; import * as redis from 'redis'; import User from './models/user'; import Userkey from './models/userkey'; +import isNativeToken from './common/is-native-token'; import homeStream from './stream/home'; import messagingStream from './stream/messaging'; @@ -50,7 +51,7 @@ module.exports = (server: http.Server) => { function authenticate(connection: websocket.connection, token: string): Promise { return new Promise(async (resolve, reject) => { - if (token[0] == '!') { + if (isNativeToken(token)) { // Fetch user // SELECT _id const user = await User From 94582453820655d11cb6dff8ad62148742591103 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 6 Jan 2017 11:50:46 +0900 Subject: [PATCH 15/19] [BREAKING CHANGE] Improve security --- docs/api/getting-started.pug | 2 ++ package.json | 1 + src/api/authenticate.ts | 2 +- src/api/endpoints/auth/accept.js | 15 ++++++++++++++- src/api/streaming.ts | 2 +- 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/api/getting-started.pug b/docs/api/getting-started.pug index f56574523..e255a5e93 100644 --- a/docs/api/getting-started.pug +++ b/docs/api/getting-started.pug @@ -70,5 +70,7 @@ block content | 次に、#{api_url}/auth/session/userkeyapp_secretとしてApp Secretを、tokenとしてセッションのトークンをパラメータとして付与したリクエストを送信してください。 br | 上手くいけば、認証したユーザーのアクセストークンがレスポンスとして取得できます。おめでとうございます! + p + | 以降アクセストークンは、ユーザーのアクセストークン+アプリのシークレットキーをsha512したものとして扱います。 p アクセストークンを取得できたら、あとは簡単です。REST APIなら、リクエストにアクセストークンをiとしてパラメータに含めるだけです。 diff --git a/package.json b/package.json index 423103c75..1debc8853 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "compression": "1.6.2", "cors": "2.8.1", "cropperjs": "1.0.0-beta", + "crypto": "0.0.3", "deepcopy": "0.6.3", "del": "2.2.2", "elasticsearch": "12.1.3", diff --git a/src/api/authenticate.ts b/src/api/authenticate.ts index 832517379..0a888e72d 100644 --- a/src/api/authenticate.ts +++ b/src/api/authenticate.ts @@ -43,7 +43,7 @@ export default (req: express.Request) => new Promise(async (resolv }); } else { const userkeyDoc = await Userkey.findOne({ - key: token + hash: token }); if (userkeyDoc === null) { diff --git a/src/api/endpoints/auth/accept.js b/src/api/endpoints/auth/accept.js index 7c45650c6..9eb5d2e7e 100644 --- a/src/api/endpoints/auth/accept.js +++ b/src/api/endpoints/auth/accept.js @@ -4,6 +4,8 @@ * Module dependencies */ import rndstr from 'rndstr'; +const crypto = require('crypto'); +import App from '../../models/app'; import AuthSess from '../../models/auth-session'; import Userkey from '../../models/userkey'; @@ -41,12 +43,23 @@ module.exports = (params, user) => }); if (exist === null) { + // Lookup app + const app = await App.findOne({ + app_id: session.app_id + }); + + // Generate Hash + const sha512 = crypto.createHash('sha512'); + sha512.update(key + app.secret); + const hash = sha512.digest('hex'); + // Insert userkey doc await Userkey.insert({ created_at: new Date(), app_id: session.app_id, user_id: user._id, - key: key + key: key, + hash: hash }); } diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 84a0f9ddf..dd28a0bc1 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -64,7 +64,7 @@ function authenticate(connection: websocket.connection, token: string): Promise< resolve(user); } else { const userkey = await Userkey.findOne({ - key: token + hash: token }); if (userkey == null) { From fef3d3f300c80bf26b0c6a203db5782f76463151 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 6 Jan 2017 12:09:57 +0900 Subject: [PATCH 16/19] Refactor: Rename userkey --> access-token --- src/api/authenticate.ts | 12 ++++++------ src/api/endpoints/auth/accept.js | 24 +++++++++++------------ src/api/endpoints/auth/session/userkey.js | 8 ++++---- src/api/models/access-token.ts | 6 ++++++ src/api/models/userkey.ts | 5 ----- src/api/serializers/app.ts | 4 ++-- src/api/streaming.ts | 10 +++++----- 7 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 src/api/models/access-token.ts delete mode 100644 src/api/models/userkey.ts diff --git a/src/api/authenticate.ts b/src/api/authenticate.ts index 0a888e72d..2304acff2 100644 --- a/src/api/authenticate.ts +++ b/src/api/authenticate.ts @@ -1,7 +1,7 @@ import * as express from 'express'; import App from './models/app'; import User from './models/user'; -import Userkey from './models/userkey'; +import AccessToken from './models/access-token'; import isNativeToken from './common/is-native-token'; export interface IAuthContext { @@ -42,19 +42,19 @@ export default (req: express.Request) => new Promise(async (resolv isSecure: true }); } else { - const userkeyDoc = await Userkey.findOne({ + const accessToken = await AccessToken.findOne({ hash: token }); - if (userkeyDoc === null) { - return reject('invalid userkey'); + if (accessToken === null) { + return reject('invalid token'); } const app = await App - .findOne({ _id: userkeyDoc.app_id }); + .findOne({ _id: accessToken.app_id }); const user = await User - .findOne({ _id: userkeyDoc.user_id }); + .findOne({ _id: accessToken.user_id }); return resolve({ app: app, user: user, isSecure: false }); } diff --git a/src/api/endpoints/auth/accept.js b/src/api/endpoints/auth/accept.js index 9eb5d2e7e..110a0897d 100644 --- a/src/api/endpoints/auth/accept.js +++ b/src/api/endpoints/auth/accept.js @@ -7,7 +7,7 @@ import rndstr from 'rndstr'; const crypto = require('crypto'); import App from '../../models/app'; import AuthSess from '../../models/auth-session'; -import Userkey from '../../models/userkey'; +import AccessToken from '../../models/access-token'; /** * Accept @@ -20,24 +20,24 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Get 'token' parameter - const token = params.token; - if (token == null) { + const sesstoken = params.token; + if (sesstoken == null) { return rej('token is required'); } // Fetch token const session = await AuthSess - .findOne({ token: token }); + .findOne({ token: sesstoken }); if (session === null) { return rej('session not found'); } - // Generate userkey - const key = rndstr('a-zA-Z0-9', 32); + // Generate access token + const token = rndstr('a-zA-Z0-9', 32); - // Fetch exist userkey - const exist = await Userkey.findOne({ + // Fetch exist access token + const exist = await AccessToken.findOne({ app_id: session.app_id, user_id: user._id, }); @@ -50,15 +50,15 @@ module.exports = (params, user) => // Generate Hash const sha512 = crypto.createHash('sha512'); - sha512.update(key + app.secret); + sha512.update(token + app.secret); const hash = sha512.digest('hex'); - // Insert userkey doc - await Userkey.insert({ + // Insert access token doc + await AccessToken.insert({ created_at: new Date(), app_id: session.app_id, user_id: user._id, - key: key, + token: token, hash: hash }); } diff --git a/src/api/endpoints/auth/session/userkey.js b/src/api/endpoints/auth/session/userkey.js index 2626e4ce3..f85a720ea 100644 --- a/src/api/endpoints/auth/session/userkey.js +++ b/src/api/endpoints/auth/session/userkey.js @@ -5,7 +5,7 @@ */ import App from '../../../models/app'; import AuthSess from '../../../models/auth-session'; -import Userkey from '../../../models/userkey'; +import AccessToken from '../../../models/access-token'; import serialize from '../../../serializers/user'; /** @@ -53,8 +53,8 @@ module.exports = (params) => return rej('this session is not allowed yet'); } - // Lookup userkey - const userkey = await Userkey.findOne({ + // Lookup access token + const accessToken = await AccessToken.findOne({ app_id: app._id, user_id: session.user_id }); @@ -66,7 +66,7 @@ module.exports = (params) => // Response res({ - userkey: userkey.key, + access_token: accessToken.token, user: await serialize(session.user_id, null, { detail: true }) diff --git a/src/api/models/access-token.ts b/src/api/models/access-token.ts new file mode 100644 index 000000000..f94df954d --- /dev/null +++ b/src/api/models/access-token.ts @@ -0,0 +1,6 @@ +const collection = global.db.collection('access_tokens'); + +collection.createIndex('token'); +collection.createIndex('hash'); + +export default collection; diff --git a/src/api/models/userkey.ts b/src/api/models/userkey.ts deleted file mode 100644 index 204f283a2..000000000 --- a/src/api/models/userkey.ts +++ /dev/null @@ -1,5 +0,0 @@ -const collection = global.db.collection('userkeys'); - -collection.createIndex('key'); - -export default collection; diff --git a/src/api/serializers/app.ts b/src/api/serializers/app.ts index 1c4b244a3..b60bcb97e 100644 --- a/src/api/serializers/app.ts +++ b/src/api/serializers/app.ts @@ -7,7 +7,7 @@ import * as mongo from 'mongodb'; import deepcopy = require('deepcopy'); import App from '../models/app'; import User from '../models/user'; -import Userkey from '../models/userkey'; +import AccessToken from '../models/access-token'; /** * Serialize an app @@ -71,7 +71,7 @@ export default ( if (me) { // 既に連携しているか - const exist = await Userkey.count({ + const exist = await AccessToken.count({ app_id: _app.id, user_id: me, }, { diff --git a/src/api/streaming.ts b/src/api/streaming.ts index dd28a0bc1..49269ac44 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -2,7 +2,7 @@ import * as http from 'http'; import * as websocket from 'websocket'; import * as redis from 'redis'; import User from './models/user'; -import Userkey from './models/userkey'; +import AccessToken from './models/access-token'; import isNativeToken from './common/is-native-token'; import homeStream from './stream/home'; @@ -63,18 +63,18 @@ function authenticate(connection: websocket.connection, token: string): Promise< resolve(user); } else { - const userkey = await Userkey.findOne({ + const accessToken = await AccessToken.findOne({ hash: token }); - if (userkey == null) { - return reject('invalid userkey'); + if (accessToken == null) { + return reject('invalid token'); } // Fetch user // SELECT _id const user = await User - .findOne({ _id: userkey.user_id }, { + .findOne({ _id: accessToken.user_id }, { _id: true }); From 89a3d6789cb1ed00b0082b6074fe59b3a8033464 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 6 Jan 2017 12:30:35 +0900 Subject: [PATCH 17/19] [API] Improve: Better error message --- src/api/authenticate.ts | 2 +- src/api/streaming.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/authenticate.ts b/src/api/authenticate.ts index 2304acff2..6b70b0bfa 100644 --- a/src/api/authenticate.ts +++ b/src/api/authenticate.ts @@ -47,7 +47,7 @@ export default (req: express.Request) => new Promise(async (resolv }); if (accessToken === null) { - return reject('invalid token'); + return reject('invalid signature'); } const app = await App diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 49269ac44..7a8d2d435 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -68,7 +68,7 @@ function authenticate(connection: websocket.connection, token: string): Promise< }); if (accessToken == null) { - return reject('invalid token'); + return reject('invalid signature'); } // Fetch user From a7e646e7c1fc2c9aea2078cfa299744898140c88 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 6 Jan 2017 12:32:55 +0900 Subject: [PATCH 18/19] [API] Clean up --- src/api/authenticate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/authenticate.ts b/src/api/authenticate.ts index 6b70b0bfa..50a55e51b 100644 --- a/src/api/authenticate.ts +++ b/src/api/authenticate.ts @@ -22,7 +22,7 @@ export interface IAuthContext { } export default (req: express.Request) => new Promise(async (resolve, reject) => { - const token = req.body['i'] || req.body['_userkey']; // そのうち_userkeyは削除 + const token = req.body['i']; if (token == null) { return resolve({ app: null, user: null, isSecure: false }); From 12ae14901cb468c34e4d3bf45ac41bf01712311a Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 6 Jan 2017 12:36:06 +0900 Subject: [PATCH 19/19] Update changelog --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4da46cf7..b97f12f2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,11 @@ -# 1 +# Server +## 1 +First version + +# API +## 2 +* パラメータ: _userkey --> i +* トークンは、アクセストークン + アプリのシークレットキーをsha512したものに + +## 1 First version