Refactor auth logic.

This commit is contained in:
Mike Cao 2022-10-11 21:48:33 -07:00
parent edd1751b81
commit 5e2d23f18f
10 changed files with 40 additions and 30 deletions

View File

@ -17,8 +17,8 @@ export default function WebsiteHeader({ websiteId, title, domain, showLink = fal
<Favicon domain={domain} /> <Favicon domain={domain} />
<Link <Link
className={styles.titleLink} className={styles.titleLink}
href="/website/[...id]" href="/websites/[...id]"
as={`/website/${websiteId}/${title}`} as={`/websites/${websiteId}/${title}`}
> >
<OverflowText tooltipId={`${websiteId}-title`}>{title}</OverflowText> <OverflowText tooltipId={`${websiteId}-title`}>{title}</OverflowText>
</Link> </Link>
@ -41,8 +41,8 @@ export default function WebsiteHeader({ websiteId, title, domain, showLink = fal
<RefreshButton websiteId={websiteId} /> <RefreshButton websiteId={websiteId} />
{showLink && ( {showLink && (
<Link <Link
href="/website/[...id]" href="/websites/[...id]"
as={`/website/${websiteId}/${title}`} as={`/websites/${websiteId}/${title}`}
className={styles.link} className={styles.link}
icon={<Arrow />} icon={<Arrow />}
size="small" size="small"

View File

@ -55,7 +55,7 @@ export default function TestConsole() {
<PageHeader> <PageHeader>
<div>Test Console</div> <div>Test Console</div>
<DropDown <DropDown
value={selectedValue || 'Select websites'} value={selectedValue || 'Select website'}
options={options} options={options}
onChange={handleSelect} onChange={handleSelect}
/> />

View File

@ -84,7 +84,7 @@ export default function WebsiteSettings() {
); );
const DetailsLink = ({ id, name, domain }) => ( const DetailsLink = ({ id, name, domain }) => (
<Link className={styles.detailLink} href="/website/[...id]" as={`/website/${id}/${name}`}> <Link className={styles.detailLink} href="/websites/[...id]" as={`/websites/${id}/${name}`}>
<Favicon domain={domain} /> <Favicon domain={domain} />
<OverflowText tooltipId={`${id}-name`}>{name}</OverflowText> <OverflowText tooltipId={`${id}-name`}>{name}</OverflowText>
</Link> </Link>

View File

@ -1,10 +1,10 @@
import { validate } from 'uuid'; import { validate } from 'uuid';
import { parseSecureToken, parseToken, getItem } from 'next-basics'; import { parseSecureToken, parseToken } from 'next-basics';
import { AUTH_TOKEN, SHARE_TOKEN_HEADER } from './constants';
import { getWebsite } from 'queries'; import { getWebsite } from 'queries';
import { secret } from './crypto'; import { SHARE_TOKEN_HEADER } from 'lib/constants';
import { secret } from 'lib/crypto';
export async function getAuthToken(req) { export function getAuthToken(req) {
try { try {
const token = req.headers.authorization; const token = req.headers.authorization;
@ -14,13 +14,15 @@ export async function getAuthToken(req) {
} }
} }
export function getAuthHeader() { export function getShareToken(req) {
const token = getItem(AUTH_TOKEN); try {
return parseSecureToken(req.headers[SHARE_TOKEN_HEADER], secret());
return token ? { authorization: `Bearer ${token}` } : {}; } catch {
return null;
}
} }
export async function isValidToken(token, validation) { export function isValidToken(token, validation) {
try { try {
const result = parseToken(token, secret()); const result = parseToken(token, secret());

View File

@ -1,7 +1,7 @@
import { createMiddleware, unauthorized, badRequest, serverError } from 'next-basics'; import { createMiddleware, unauthorized, badRequest, serverError } from 'next-basics';
import cors from 'cors'; import cors from 'cors';
import { getSession } from './session'; import { getSession } from './session';
import { getAuthToken } from './auth'; import { getAuthToken, getShareToken } from './auth';
export const useCors = createMiddleware(cors()); export const useCors = createMiddleware(cors());
@ -27,11 +27,12 @@ export const useSession = createMiddleware(async (req, res, next) => {
export const useAuth = createMiddleware(async (req, res, next) => { export const useAuth = createMiddleware(async (req, res, next) => {
const token = await getAuthToken(req); const token = await getAuthToken(req);
const shareToken = await getShareToken(req);
if (!token) { if (!token) {
return unauthorized(res); return unauthorized(res);
} }
req.auth = token; req.auth = { ...token, shareToken };
next(); next();
}); });

View File

@ -31,7 +31,7 @@ export async function getSession(req) {
let websiteId = null; let websiteId = null;
// Check if websites exists // Check if website exists
if (redis.enabled) { if (redis.enabled) {
websiteId = Number(await redis.get(`website:${websiteUuid}`)); websiteId = Number(await redis.get(`website:${websiteUuid}`));
} }

View File

@ -84,7 +84,7 @@
"maxmind": "^4.3.6", "maxmind": "^4.3.6",
"moment-timezone": "^0.5.35", "moment-timezone": "^0.5.35",
"next": "^12.2.5", "next": "^12.2.5",
"next-basics": "^0.12.0", "next-basics": "^0.17.0",
"node-fetch": "^3.2.8", "node-fetch": "^3.2.8",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",

View File

@ -9,10 +9,10 @@ export default async (req, res) => {
const website = await getWebsiteByShareId(id); const website = await getWebsiteByShareId(id);
if (website) { if (website) {
const websiteId = website.websiteId; const { websiteId, websiteUuid } = website;
const token = createToken({ websiteId: websiteId }, secret()); const token = createToken({ websiteId, websiteUuid }, secret());
return ok(res, { websiteId, token }); return ok(res, { websiteId, websiteUuid, token });
} }
return notFound(res); return notFound(res);

View File

@ -5,6 +5,10 @@ import { useAuth, useCors } from 'lib/middleware';
import { validate } from 'uuid'; import { validate } from 'uuid';
export default async (req, res) => { export default async (req, res) => {
await useAuth(req, res);
const { isAdmin, userId, accountUuid } = req.auth;
const { id } = req.query; const { id } = req.query;
const websiteId = +id; const websiteId = +id;
@ -23,9 +27,6 @@ export default async (req, res) => {
} }
if (req.method === 'POST') { if (req.method === 'POST') {
await useAuth(req, res);
const { isAdmin: currentUserIsAdmin, userId: currentUserId, accountUuid } = req.auth;
const { name, domain, owner, enable_share_url } = req.body; const { name, domain, owner, enable_share_url } = req.body;
let account; let account;
@ -37,7 +38,7 @@ export default async (req, res) => {
const shareId = enable_share_url ? website.shareId || getRandomChars(8) : null; const shareId = enable_share_url ? website.shareId || getRandomChars(8) : null;
if (website.userId !== currentUserId && !currentUserIsAdmin) { if (website.userId !== userId && !isAdmin) {
return unauthorized(res); return unauthorized(res);
} }

View File

@ -2273,6 +2273,11 @@ balanced-match@^2.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9"
integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==
base-x@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a"
integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==
bcrypt-pbkdf@^1.0.0: bcrypt-pbkdf@^1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
@ -4731,11 +4736,12 @@ natural-compare@^1.4.0:
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
next-basics@^0.12.0: next-basics@^0.17.0:
version "0.12.0" version "0.17.0"
resolved "https://registry.yarnpkg.com/next-basics/-/next-basics-0.12.0.tgz#e946cdb3f32d5d84f67e7c35b6e2e96750763c62" resolved "https://registry.yarnpkg.com/next-basics/-/next-basics-0.17.0.tgz#567c7b7a05f02bf6e4a073090954c1b6de4e7045"
integrity sha512-3meED1Z9m8QvOsG4bz5OAuyjROdV9Cf75Wq2t+cHiGBh+y8qhTluJduqIXuoY5x0S72/5XvY1mwthW+Og47H9A== integrity sha512-NXYfbdBCdbn/a6x4F+7zZGmJ8llHtZcUYp3BMwoYXRSPsa1Y4wmJgIgtGBu542IMfTkQ2YClBy3Z1gOoMbzgaQ==
dependencies: dependencies:
base-x "^4.0.0"
bcryptjs "^2.4.3" bcryptjs "^2.4.3"
jsonwebtoken "^8.5.1" jsonwebtoken "^8.5.1"