From e3122a683da4f83e7dc347e2a52e94d8b79d50a7 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 22 Jan 2021 23:38:29 +0800 Subject: [PATCH] server: move auth utilities to authUtil --- server/routes/api/auth.test.ts | 2 +- server/routes/api/auth.ts | 26 +++----------------- server/routes/api/client.test.ts | 2 +- server/routes/api/feed-monitor.test.ts | 2 +- server/routes/api/index.test.ts | 2 +- server/routes/api/torrents.test.ts | 2 +- server/util/authUtil.ts | 34 ++++++++++++++++++++++++++ 7 files changed, 42 insertions(+), 28 deletions(-) create mode 100644 server/util/authUtil.ts diff --git a/server/routes/api/auth.test.ts b/server/routes/api/auth.test.ts index 3ed23c6b..629d0e0c 100644 --- a/server/routes/api/auth.test.ts +++ b/server/routes/api/auth.test.ts @@ -4,7 +4,7 @@ import supertest from 'supertest'; import {AccessLevel} from '../../../shared/schema/constants/Auth'; import app from '../../app'; -import {getAuthToken} from './auth'; +import {getAuthToken} from '../../util/authUtil'; import type { AuthRegistrationOptions, diff --git a/server/routes/api/auth.ts b/server/routes/api/auth.ts index 83937505..8d8e3a85 100644 --- a/server/routes/api/auth.ts +++ b/server/routes/api/auth.ts @@ -1,5 +1,4 @@ import express from 'express'; -import jwt from 'jsonwebtoken'; import passport from 'passport'; import rateLimit from 'express-rate-limit'; @@ -12,6 +11,7 @@ import { AuthVerificationPreloadConfigs, } from '../../../shared/schema/api/auth'; import config from '../../../config'; +import {getAuthToken, getCookieOptions} from '../../util/authUtil'; import {getResponseFn, validationError} from '../../util/ajaxUtil'; import requireAdmin from '../../middleware/requireAdmin'; import services from '../../services'; @@ -40,33 +40,13 @@ router.use( }), ); -export const getAuthToken = (username: string, res?: Response): string => { - const expirationSeconds = 60 * 60 * 24 * 7; // one week - const cookieExpiration = Date.now() + expirationSeconds * 1000; - - // Create token if the password matched and no error was thrown. - const token = jwt.sign({username}, config.secret, { - expiresIn: expirationSeconds, - }); - - if (res != null) { - res.cookie('jwt', token, { - expires: new Date(cookieExpiration), - httpOnly: true, - sameSite: 'strict', - }); - } - - return token; -}; - const sendAuthenticationResponse = ( res: Response, credentials: Required>, ): void => { const {username, level} = credentials; - getAuthToken(username, res); + res.cookie('jwt', getAuthToken(username), getCookieOptions()); const response: AuthAuthenticationResponse = { success: true, @@ -200,7 +180,7 @@ router.use('/verify', (req, res, next) => { if (config.authMethod === 'none') { const {username, level} = Users.getConfigUser(); - getAuthToken(username, res); + res.cookie('jwt', getAuthToken(username), getCookieOptions()); const response: AuthVerificationResponse = { initialUser: false, diff --git a/server/routes/api/client.test.ts b/server/routes/api/client.test.ts index df966388..7db29583 100644 --- a/server/routes/api/client.test.ts +++ b/server/routes/api/client.test.ts @@ -1,7 +1,7 @@ import supertest from 'supertest'; import app from '../../app'; -import {getAuthToken} from './auth'; +import {getAuthToken} from '../../util/authUtil'; import type {ClientSettings} from '../../../shared/types/ClientSettings'; diff --git a/server/routes/api/feed-monitor.test.ts b/server/routes/api/feed-monitor.test.ts index 0dd10ff0..a133871d 100644 --- a/server/routes/api/feed-monitor.test.ts +++ b/server/routes/api/feed-monitor.test.ts @@ -2,7 +2,7 @@ import fs from 'fs'; import supertest from 'supertest'; import app from '../../app'; -import {getAuthToken} from './auth'; +import {getAuthToken} from '../../util/authUtil'; import {getTempPath} from '../../models/TemporaryStorage'; import type {AddFeedOptions, AddRuleOptions, ModifyFeedOptions} from '../../../shared/types/api/feed-monitor'; diff --git a/server/routes/api/index.test.ts b/server/routes/api/index.test.ts index b4d990e2..360f265e 100644 --- a/server/routes/api/index.test.ts +++ b/server/routes/api/index.test.ts @@ -1,7 +1,7 @@ import supertest from 'supertest'; import app from '../../app'; -import {getAuthToken} from './auth'; +import {getAuthToken} from '../../util/authUtil'; import type {FloodSettings} from '../../../shared/types/FloodSettings'; diff --git a/server/routes/api/torrents.test.ts b/server/routes/api/torrents.test.ts index b3a55eef..cc377079 100644 --- a/server/routes/api/torrents.test.ts +++ b/server/routes/api/torrents.test.ts @@ -7,7 +7,7 @@ import stream from 'stream'; import supertest from 'supertest'; import app from '../../app'; -import {getAuthToken} from './auth'; +import {getAuthToken} from '../../util/authUtil'; import {getTempPath} from '../../models/TemporaryStorage'; import paths from '../../../shared/config/paths'; diff --git a/server/util/authUtil.ts b/server/util/authUtil.ts new file mode 100644 index 00000000..0f77de82 --- /dev/null +++ b/server/util/authUtil.ts @@ -0,0 +1,34 @@ +import {CookieOptions} from 'express'; +import jwt from 'jsonwebtoken'; + +import config from '../../config'; + +const EXPIRATION_SECONDS = 60 * 60 * 24 * 7; // one week + +export const getCookieOptions = (): CookieOptions => ({ + expires: new Date(Date.now() + EXPIRATION_SECONDS * 1000), + httpOnly: true, + sameSite: 'strict', +}); + +export const getAuthToken = (username: string): string => + jwt.sign({username}, config.secret, { + expiresIn: EXPIRATION_SECONDS, + }); + +export const getToken = (payload: Record) => + jwt.sign(payload, config.secret, { + expiresIn: EXPIRATION_SECONDS, + }); + +export const verifyToken = async (token: string): Promise> => + new Promise((resolve, reject) => { + jwt.verify(token, config.secret, (err, decoded) => { + if (err !== null || decoded == null) { + reject(err); + return; + } + + resolve(decoded as Record); + }); + });