From f9fd938863572066d9480e1c56b6abbfc148c254 Mon Sep 17 00:00:00 2001 From: Brian Cao Date: Fri, 12 Aug 2022 11:59:05 -0700 Subject: [PATCH] add auth-code --- components/pages/DashboardEdit.js | 2 -- components/pages/WebsiteList.js | 2 -- lib/crypto.js | 24 ++++++++++------- lib/filters.js | 2 -- pages/api/auth/token.js | 36 ++++++++++++++++++++++++++ pages/auth.js | 43 +++++++++++++++++++++++++++++++ 6 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 pages/api/auth/token.js create mode 100644 pages/auth.js diff --git a/components/pages/DashboardEdit.js b/components/pages/DashboardEdit.js index d06f32f9..d231a8fb 100644 --- a/components/pages/DashboardEdit.js +++ b/components/pages/DashboardEdit.js @@ -23,8 +23,6 @@ export default function DashboardEdit({ websites }) { const ordered = useMemo(() => sortArrayByMap(websites, order, 'website_id'), [websites, order]); - console.log({ order, ordered }); - function handleWebsiteDrag({ destination, source }) { if (!destination || destination.index === source.index) return; diff --git a/components/pages/WebsiteList.js b/components/pages/WebsiteList.js index 4de8d05d..2c19c167 100644 --- a/components/pages/WebsiteList.js +++ b/components/pages/WebsiteList.js @@ -24,8 +24,6 @@ export default function WebsiteList({ websites, showCharts, limit }) { const { websiteOrder } = useDashboard(); const { formatMessage } = useIntl(); - console.log({ websiteOrder }); - const ordered = useMemo( () => sortArrayByMap(websites, websiteOrder, 'website_id'), [websites, websiteOrder], diff --git a/lib/crypto.js b/lib/crypto.js index e59b0193..a83dbbe9 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -5,16 +5,20 @@ import { JWT, JWE, JWK } from 'jose'; import { startOfMonth } from 'date-fns'; const SALT_ROUNDS = 10; -const KEY = JWK.asKey(Buffer.from(secret())); +const KEY = key(); const ROTATING_SALT = hash(startOfMonth(new Date()).toUTCString()); const CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; +export function key(value) { + return JWK.asKey(Buffer.from(secret(value))); +} + export function hash(...args) { return crypto.createHash('sha512').update(args.join('')).digest('hex'); } -export function secret() { - return hash(process.env.HASH_SALT || process.env.DATABASE_URL); +export function secret(secret = process.env.HASH_SALT || process.env.DATABASE_URL) { + return hash(secret); } export function salt() { @@ -51,23 +55,23 @@ export async function createToken(payload) { return JWT.sign(payload, KEY); } -export async function parseToken(token) { +export async function parseToken(token, key = KEY) { try { - return JWT.verify(token, KEY); + return JWT.verify(token, key); } catch { return null; } } -export async function createSecureToken(payload) { - return JWE.encrypt(await createToken(payload), KEY); +export async function createSecureToken(payload, key = KEY) { + return JWE.encrypt(await createToken(payload), key); } -export async function parseSecureToken(token) { +export async function parseSecureToken(token, key = KEY) { try { - const result = await JWE.decrypt(token, KEY); + const result = await JWE.decrypt(token, key); - return parseToken(result.toString()); + return parseToken(result.toString(), key); } catch { return null; } diff --git a/lib/filters.js b/lib/filters.js index 27b88e20..fd5c312e 100644 --- a/lib/filters.js +++ b/lib/filters.js @@ -98,7 +98,5 @@ export const paramFilter = data => { Object.keys(map[key]).map(n => ({ x: `${key}=${n}`, p: key, v: n, y: map[key][n] })), ); - console.log({ map, d }); - return d; }; diff --git a/pages/api/auth/token.js b/pages/api/auth/token.js new file mode 100644 index 00000000..5b438b04 --- /dev/null +++ b/pages/api/auth/token.js @@ -0,0 +1,36 @@ +import { ok, unauthorized, methodNotAllowed } from 'lib/response'; +import { post } from 'lib/web'; +import { parseSecureToken, key, createSecureToken } from 'lib/crypto'; +import { getAccountByUsername } from 'queries'; + +export default async (req, res) => { + var { authCode } = req.body; + + if (req.method === 'POST') { + const params = { + authorizationCode: authCode, + clientId: process.env.CLIENT_ID, + clientSecret: process.env.CLIENT_SECRET, + }; + + var { ok: authOk, data } = await post(process.env.OAUTH_URL, params); + + if (authOk) { + const { username } = await parseSecureToken(data.token, key(process.env.CLIENT_SECRET)); + + const account = await getAccountByUsername(username); + + if (account) { + const { user_id, username, is_admin } = account; + const user = { user_id, username, is_admin }; + const token = await createSecureToken(user); + + return ok(res, { token, user }); + } + } + + return unauthorized(res); + } + + return methodNotAllowed(res); +}; diff --git a/pages/auth.js b/pages/auth.js new file mode 100644 index 00000000..425bc540 --- /dev/null +++ b/pages/auth.js @@ -0,0 +1,43 @@ +import React from 'react'; +import Layout from 'components/layout/Layout'; +import useApi from 'hooks/useApi'; +import { useRouter } from 'next/router'; +import { useEffect } from 'react'; +import { setItem } from 'lib/web'; +import { setUser } from 'store/app'; +import { AUTH_TOKEN } from 'lib/constants'; + +export default function AuthPage({ loginDisabled }) { + const { post } = useApi(); + const router = useRouter(); + + useEffect(() => { + const { auth_code } = router.query; + const verifyyData = async () => { + const { ok, data } = await post('/auth/token', { authCode: auth_code }); + + if (ok) { + setItem(AUTH_TOKEN, data.token); + setUser(data.user); + + await router.push('/'); + + return null; + } + }; + + verifyyData().catch(async () => await router.push('/')); + }, [post, router]); + + if (loginDisabled) { + return null; + } + + return ; +} + +export async function getServerSideProps() { + return { + props: { loginDisabled: !!process.env.DISABLE_LOGIN }, + }; +}