From 5b2e4d787563ef7318013389672da2efae6196b2 Mon Sep 17 00:00:00 2001 From: SIY1121 Date: Tue, 30 Mar 2021 15:32:03 +0000 Subject: [PATCH] add: logtou & redirect_url validation --- src/handlers/auth.ts | 40 ++++++++++++++++++++++++++++++++++++++-- src/index.ts | 3 ++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/handlers/auth.ts b/src/handlers/auth.ts index dd88dc8..6b6e2aa 100644 --- a/src/handlers/auth.ts +++ b/src/handlers/auth.ts @@ -4,6 +4,17 @@ import passport from 'passport'; import { sessionService } from '../services/sessionService'; import { userService } from '../services/userService'; +const cookieName = process.env.COOKIE_NAME ?? 'twinte_session'; + +/** + * twinteのドメインにしかリダイレクトを返さないようにする + */ +function validateRedirectUrl(url?: string) { + if (!url) return false; + else if (process.env.NODE_ENV === 'development') return true; + else return /^https:\/\/([a-zA-Z0-9-]+\.)*twinte\.net/.test(url); +} + export async function handleAuth(req: Request, res: Response) { const provider = req.params['provider']; if (provider !== 'google' && provider !== 'twitter' && provider !== 'apple') { @@ -11,7 +22,7 @@ export async function handleAuth(req: Request, res: Response) { return; } - const callbackUrl = req.query['redirect_url']; + const callbackUrl = req.query['redirect_url'] as string; if (!callbackUrl) { res.status(400); @@ -19,6 +30,12 @@ export async function handleAuth(req: Request, res: Response) { return; } + if (!validateRedirectUrl(callbackUrl)) { + res.status(400); + res.send('invalid redirect_url'); + return; + } + res.cookie('twinte_auth_callback', callbackUrl, { maxAge: 3 * 60 * 1000, httpOnly: true, @@ -58,7 +75,7 @@ export async function handleAuthCallback(req: Request, res: Response) { const callbackUrl = req.cookies['twinte_auth_callback'] || 'https://www.twinte.net'; - res.cookie(process.env.COOKIE_NAME!, session.sessionId, { + res.cookie(cookieName, session.sessionId, { expires: expiredDate, secure: cookieOptions.secure, httpOnly: true, @@ -73,3 +90,22 @@ export async function handleAuthCallback(req: Request, res: Response) { res.send(); }); } + +export async function handleLogout(req: Request, res: Response) { + const callbackUrl = req.query['redirect_url'] as string; + + if (!callbackUrl) { + res.status(400); + res.send('please specify redirect_url'); + return; + } + + if (!validateRedirectUrl(callbackUrl)) { + res.status(400); + res.send('invalid redirect_url'); + return; + } + + res.clearCookie(cookieName); + res.redirect(callbackUrl); +} diff --git a/src/index.ts b/src/index.ts index 45cd5fc..d237c14 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ dotenv.config(); import express from 'express'; import session from 'express-session'; -import { handleAuth, handleAuthCallback } from './handlers/auth'; +import { handleAuth, handleAuthCallback, handleLogout } from './handlers/auth'; import { configurePassport } from './passport'; import cookieParser from 'cookie-parser'; import passport from 'passport'; @@ -22,6 +22,7 @@ app.use( ); app.use(passport.initialize()); app.use(passport.session()); +app.get('/logout', handleLogout); app.get('/:provider', handleAuth); app.get('/:provider/callback', handleAuthCallback);