From 767a292dbdaedeb34de5476f0c23ca25a0395e90 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 23 Nov 2017 13:25:33 +0900 Subject: #939 --- src/api/common/signin.ts | 19 ++++++ src/api/private/signin.ts | 14 +---- src/api/service/twitter.ts | 78 +++++++++++++++++++++--- src/web/app/desktop/tags/pages/entrance.tag | 1 + src/web/app/mobile/tags/page/entrance/signin.tag | 1 + 5 files changed, 92 insertions(+), 21 deletions(-) create mode 100644 src/api/common/signin.ts (limited to 'src') diff --git a/src/api/common/signin.ts b/src/api/common/signin.ts new file mode 100644 index 0000000000..693e62f39f --- /dev/null +++ b/src/api/common/signin.ts @@ -0,0 +1,19 @@ +import config from '../../conf'; + +export default function(res, user, redirect: boolean) { + const expires = 1000 * 60 * 60 * 24 * 365; // One Year + res.cookie('i', user.token, { + path: '/', + domain: `.${config.host}`, + secure: config.url.substr(0, 5) === 'https', + httpOnly: false, + expires: new Date(Date.now() + expires), + maxAge: expires + }); + + if (redirect) { + res.redirect(config.url); + } else { + res.sendStatus(204); + } +} diff --git a/src/api/private/signin.ts b/src/api/private/signin.ts index 0689887925..0ebf8d6aa1 100644 --- a/src/api/private/signin.ts +++ b/src/api/private/signin.ts @@ -4,7 +4,7 @@ import { default as User, IUser } from '../models/user'; import Signin from '../models/signin'; import serialize from '../serializers/signin'; import event from '../event'; -import config from '../../conf'; +import signin from '../common/signin'; export default async (req: express.Request, res: express.Response) => { res.header('Access-Control-Allow-Credentials', 'true'); @@ -43,17 +43,7 @@ export default async (req: express.Request, res: express.Response) => { const same = await bcrypt.compare(password, user.password); if (same) { - const expires = 1000 * 60 * 60 * 24 * 365; // One Year - res.cookie('i', user.token, { - path: '/', - domain: `.${config.host}`, - secure: config.url.substr(0, 5) === 'https', - httpOnly: false, - expires: new Date(Date.now() + expires), - maxAge: expires - }); - - res.sendStatus(204); + signin(res, user, false); } else { res.status(400).send({ error: 'incorrect password' diff --git a/src/api/service/twitter.ts b/src/api/service/twitter.ts index 9fb274aacb..b5dfc2c99a 100644 --- a/src/api/service/twitter.ts +++ b/src/api/service/twitter.ts @@ -1,4 +1,6 @@ import * as express from 'express'; +import * as cookie from 'cookie'; +import * as uuid from 'uuid'; // import * as Twitter from 'twitter'; // const Twitter = require('twitter'); import autwh from 'autwh'; @@ -7,6 +9,7 @@ import User from '../models/user'; import serialize from '../serializers/user'; import event from '../event'; import config from '../../conf'; +import signin from '../common/signin'; module.exports = (app: express.Application) => { app.get('/disconnect/twitter', async (req, res): Promise => { @@ -30,8 +33,13 @@ module.exports = (app: express.Application) => { if (config.twitter == null) { app.get('/connect/twitter', (req, res) => { - res.send('現在Twitterへ接続できません'); + res.send('現在Twitterへ接続できません (このインスタンスではTwitterはサポートされていません)'); }); + + app.get('/signin/twitter', (req, res) => { + res.send('現在Twitterへ接続できません (このインスタンスではTwitterはサポートされていません)'); + }); + return; } @@ -41,6 +49,12 @@ module.exports = (app: express.Application) => { callbackUrl: `${config.api_url}/tw/cb` }); + const twAuthSignin = autwh({ + consumerKey: config.twitter.consumer_key, + consumerSecret: config.twitter.consumer_secret, + callbackUrl: `${config.api_url}/signin/twitter/cb` + }); + app.get('/connect/twitter', async (req, res): Promise => { if (res.locals.user == null) return res.send('plz signin'); const ctx = await twAuth.begin(); @@ -56,15 +70,15 @@ module.exports = (app: express.Application) => { const user = await User.findOneAndUpdate({ token: res.locals.user }, { - $set: { - twitter: { - access_token: result.accessToken, - access_token_secret: result.accessTokenSecret, - user_id: result.userId, - screen_name: result.screenName - } + $set: { + twitter: { + access_token: result.accessToken, + access_token_secret: result.accessTokenSecret, + user_id: result.userId, + screen_name: result.screenName } - }); + } + }); res.send(`Twitter: @${result.screenName} を、Misskey: @${user.username} に接続しました!`); @@ -75,4 +89,50 @@ module.exports = (app: express.Application) => { })); }); }); + + app.get('/signin/twitter', async (req, res): Promise => { + const ctx = await twAuthSignin.begin(); + + const sessid = uuid(); + + redis.set(sessid, JSON.stringify(ctx)); + + const expires = 1000 * 60 * 60; // 1h + res.cookie('signin_with_twitter_session_id', sessid, { + path: '/', + domain: `.${config.host}`, + secure: config.url.substr(0, 5) === 'https', + httpOnly: true, + expires: new Date(Date.now() + expires), + maxAge: expires + }); + + res.redirect(ctx.url); + }); + + app.get('/signin/twitter/cb', (req, res): any => { + // req.headers['cookie'] は常に string ですが、型定義の都合上 + // string | string[] になっているので string を明示しています + const cookies = cookie.parse((req.headers['cookie'] as string || '')); + + const sessid = cookies['signin_with_twitter_session_id']; + + if (sessid == undefined) { + res.status(400).send('invalid session'); + } + + redis.get(sessid, async (_, ctx) => { + const result = await twAuthSignin.done(JSON.parse(ctx), req.query.oauth_verifier); + + const user = await User.findOne({ + 'twitter.user_id': result.userId + }); + + if (user == null) { + res.status(404).send(`@${result.screenName}と連携しているMisskeyアカウントはありませんでした...`); + } + + signin(res, user, true); + }); + }); }; diff --git a/src/web/app/desktop/tags/pages/entrance.tag b/src/web/app/desktop/tags/pages/entrance.tag index 824847f516..02aeb922fe 100644 --- a/src/web/app/desktop/tags/pages/entrance.tag +++ b/src/web/app/desktop/tags/pages/entrance.tag @@ -157,6 +157,7 @@ + Twitterでサインイン
or
Misskeyについて