diff --git a/package.json b/package.json index 367bcf9b..cf0398f7 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@react-spring/web": "^9.7.3", "@tanstack/react-query": "^4.33.0", "@umami/prisma-client": "^0.5.0", - "@umami/redis-client": "^0.17.0", + "@umami/redis-client": "^0.18.0", "chalk": "^4.1.1", "chart.js": "^4.2.1", "chartjs-adapter-date-fns": "^3.0.0", diff --git a/src/declaration.d.ts b/src/declaration.d.ts index 42a5eeed..3523e9fa 100644 --- a/src/declaration.d.ts +++ b/src/declaration.d.ts @@ -1 +1,2 @@ +declare module 'cors'; declare module 'debug'; diff --git a/src/lib/auth.ts b/src/lib/auth.ts index c218cef9..1757f05e 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,6 +1,6 @@ import { Report } from '@prisma/client'; -import redis from '@umami/redis-client'; import debug from 'debug'; +import redis from '@umami/redis-client'; import { PERMISSIONS, ROLE_PERMISSIONS, SHARE_TOKEN_HEADER } from 'lib/constants'; import { secret } from 'lib/crypto'; import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next-basics'; @@ -12,13 +12,13 @@ import { NextApiRequest } from 'next'; const log = debug('umami:auth'); const cloudMode = process.env.CLOUD_MODE; -export async function setAuthKey(data: any, expire = 0) { +export async function saveAuth(data: any, expire = 0) { const authKey = `auth:${getRandomChars(32)}`; - await redis.set(authKey, data); + await redis.client.set(authKey, data); if (expire) { - await redis.expire(authKey, expire); + await redis.client.expire(authKey, expire); } return createSecureToken({ authKey }, secret()); @@ -61,11 +61,7 @@ export async function canViewWebsite({ user, shareToken }: Auth, websiteId: stri export async function canCreateWebsite({ user, grant }: Auth) { if (cloudMode) { - if (grant?.find(a => a === PERMISSIONS.websiteCreate)) { - return true; - } - - return false; + return !!grant?.find(a => a === PERMISSIONS.websiteCreate); } if (user.isAdmin) { @@ -121,11 +117,7 @@ export async function canDeleteReport(auth: Auth, report: Report) { export async function canCreateTeam({ user, grant }: Auth) { if (cloudMode) { - if (grant?.find(a => a === PERMISSIONS.teamCreate)) { - return true; - } - - return false; + return !!grant?.find(a => a === PERMISSIONS.teamCreate); } if (user.isAdmin) { diff --git a/src/lib/cache.ts b/src/lib/cache.ts index 2b577bf2..11fd9f5c 100644 --- a/src/lib/cache.ts +++ b/src/lib/cache.ts @@ -3,67 +3,71 @@ import redis from '@umami/redis-client'; import { getSession, getUserById, getWebsiteById } from '../queries'; async function fetchWebsite(id): Promise { - return redis.getCache(`website:${id}`, () => getWebsiteById(id), 86400); + return redis.client.getCache(`website:${id}`, () => getWebsiteById(id), 86400); } async function storeWebsite(data) { const { id } = data; const key = `website:${id}`; - const obj = await redis.setCache(key, data); - await redis.expire(key, 86400); + const obj = await redis.client.setCache(key, data); + await redis.client.expire(key, 86400); return obj; } async function deleteWebsite(id) { - return redis.deleteCache(`website:${id}`); + return redis.client.deleteCache(`website:${id}`); } async function fetchUser(id): Promise { - return redis.getCache(`user:${id}`, () => getUserById(id, { includePassword: true }), 86400); + return redis.client.getCache( + `user:${id}`, + () => getUserById(id, { includePassword: true }), + 86400, + ); } async function storeUser(data) { const { id } = data; const key = `user:${id}`; - const obj = await redis.setCache(key, data); - await redis.expire(key, 86400); + const obj = await redis.client.setCache(key, data); + await redis.client.expire(key, 86400); return obj; } async function deleteUser(id) { - return redis.deleteCache(`user:${id}`); + return redis.client.deleteCache(`user:${id}`); } async function fetchSession(id) { - return redis.getCache(`session:${id}`, () => getSession(id), 86400); + return redis.client.getCache(`session:${id}`, () => getSession(id), 86400); } async function storeSession(data) { const { id } = data; const key = `session:${id}`; - const obj = await redis.setCache(key, data); - await redis.expire(key, 86400); + const obj = await redis.client.setCache(key, data); + await redis.client.expire(key, 86400); return obj; } async function deleteSession(id) { - return redis.deleteCache(`session:${id}`); + return redis.client.deleteCache(`session:${id}`); } async function fetchUserBlock(userId: string) { const key = `user:block:${userId}`; - return redis.get(key); + return redis.client.get(key); } async function incrementUserBlock(userId: string) { const key = `user:block:${userId}`; - return redis.incr(key); + return redis.client.incr(key); } export default { diff --git a/src/lib/middleware.ts b/src/lib/middleware.ts index 5a12eb6a..b54f6d3a 100644 --- a/src/lib/middleware.ts +++ b/src/lib/middleware.ts @@ -1,6 +1,6 @@ -import redis from '@umami/redis-client'; import cors from 'cors'; import debug from 'debug'; +import redis from '@umami/redis-client'; import { getAuthToken, parseShareToken } from 'lib/auth'; import { ROLES } from 'lib/constants'; import { isUuid, secret } from 'lib/crypto'; @@ -47,15 +47,17 @@ export const useSession = createMiddleware(async (req, res, next) => { export const useAuth = createMiddleware(async (req, res, next) => { const token = getAuthToken(req); const payload = parseSecureToken(token, secret()); - const shareToken = await parseShareToken(req); + const shareToken = await parseShareToken(req as any); let user = null; const { userId, authKey, grant } = payload || {}; if (isUuid(userId)) { user = await getUserById(userId); - } else if (redis && authKey) { - user = await redis.get(authKey); + } else if (redis.enabled && authKey) { + const key = await redis.client.get(authKey); + + user = await getUserById(key.userId); } if (process.env.NODE_ENV === 'development') { diff --git a/src/pages/api/auth/login.ts b/src/pages/api/auth/login.ts index 0946ae75..e1007b3c 100644 --- a/src/pages/api/auth/login.ts +++ b/src/pages/api/auth/login.ts @@ -1,6 +1,6 @@ import redis from '@umami/redis-client'; import debug from 'debug'; -import { setAuthKey } from 'lib/auth'; +import { saveAuth } from 'lib/auth'; import { secret } from 'lib/crypto'; import { useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, User } from 'lib/types'; @@ -52,8 +52,8 @@ export default async ( const user = await getUserByUsername(username, { includePassword: true }); if (user && checkPassword(password, user.password)) { - if (redis) { - const token = await setAuthKey(user); + if (redis.enabled) { + const token = await saveAuth({ userId: user.id }); return ok(res, { token, user }); } diff --git a/src/pages/api/auth/logout.ts b/src/pages/api/auth/logout.ts index e6222e49..715fda62 100644 --- a/src/pages/api/auth/logout.ts +++ b/src/pages/api/auth/logout.ts @@ -8,8 +8,8 @@ export default async (req: NextApiRequest, res: NextApiResponse) => { await useAuth(req, res); if (req.method === 'POST') { - if (redis) { - await redis.del(getAuthToken(req)); + if (redis.enabled) { + await redis.client.del(getAuthToken(req)); } return ok(res); diff --git a/src/pages/api/auth/sso.ts b/src/pages/api/auth/sso.ts index a7992666..7b1eef60 100644 --- a/src/pages/api/auth/sso.ts +++ b/src/pages/api/auth/sso.ts @@ -3,13 +3,13 @@ import { useAuth } from 'lib/middleware'; import { NextApiResponse } from 'next'; import { badRequest, ok } from 'next-basics'; import redis from '@umami/redis-client'; -import { setAuthKey } from 'lib/auth'; +import { saveAuth } from 'lib/auth'; export default async (req: NextApiRequestAuth, res: NextApiResponse) => { await useAuth(req, res); - if (redis && req.auth.user) { - const token = await setAuthKey(req.auth.user, 86400); + if (redis.enabled && req.auth.user) { + const token = await saveAuth({ userId: req.auth.user.id }, 86400); return ok(res, { user: req.auth.user, token }); } diff --git a/yarn.lock b/yarn.lock index 9927b8ca..2c95f0d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2609,10 +2609,10 @@ chalk "^4.1.2" debug "^4.3.4" -"@umami/redis-client@^0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@umami/redis-client/-/redis-client-0.17.0.tgz#a24db0cb561a9c18b0ecaf6a3342c28525abe1e5" - integrity sha512-rX0xB+QkhMoHnKcj8jzbp1CUMKB/qk2HaYWpNP0Stztkvw7wjFYXsLTLidW3t1a06H5qApx6mJvUjxefLUsX7w== +"@umami/redis-client@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@umami/redis-client/-/redis-client-0.18.0.tgz#6a2315a878f2688dae162d93e88dfc4e097fc48e" + integrity sha512-uDuX5w7ydlOZWrq0h6fADG3XWOhto9fAqrUVu85FUhdijWoGlv5f8adaL8FAah5jD+/Byw2VyGQaZO4VhboEZw== dependencies: debug "^4.3.4" redis "^4.5.1"