diff --git a/packages/nocodb/src/lib/meta/api/userApi/initStrategies.ts b/packages/nocodb/src/lib/meta/api/userApi/initStrategies.ts index 1ffe03e98c..5eceff3190 100644 --- a/packages/nocodb/src/lib/meta/api/userApi/initStrategies.ts +++ b/packages/nocodb/src/lib/meta/api/userApi/initStrategies.ts @@ -53,7 +53,8 @@ export function initStrategies(router): void { firstname, lastname, isAuthorized, - isPublicBase + isPublicBase, + token_version }, done ) { @@ -72,7 +73,8 @@ export function initStrategies(router): void { provider, firstname, lastname, - roles + roles, + token_version }); }); @@ -100,11 +102,17 @@ export function initStrategies(router): void { ); if (cachedVal) { + if (cachedVal.token_version !== jwtPayload.token_version) { + return done(new Error('Token Expired. Please login again.')); + } return done(null, cachedVal); } User.getByEmail(jwtPayload?.email) .then(async user => { + if (user.token_version !== jwtPayload.token_version) { + return done(new Error('Token Expired. Please login again.')); + } if (req.ncProjectId) { // this.xcMeta // .metaGet(req.ncProjectId, null, 'nc_projects_users', { diff --git a/packages/nocodb/src/lib/meta/api/userApi/userApis.ts b/packages/nocodb/src/lib/meta/api/userApi/userApis.ts index a3c7500960..2b8384a9c6 100644 --- a/packages/nocodb/src/lib/meta/api/userApi/userApis.ts +++ b/packages/nocodb/src/lib/meta/api/userApi/userApis.ts @@ -96,6 +96,8 @@ export async function signup(req: Request, res: Response) { } } + const token_version = randomTokenString(); + await User.insert({ firstname, lastname, @@ -104,7 +106,7 @@ export async function signup(req: Request, res: Response) { password, email_verification_token, roles, - token_expired: false + token_version }); } user = await User.getByEmail(email); @@ -151,7 +153,8 @@ export async function signup(req: Request, res: Response) { firstname: user.firstname, lastname: user.lastname, id: user.id, - roles: user.roles + roles: user.roles, + token_version: user.token_version }, Noco.getConfig().auth.jwt.secret, Noco.getConfig().auth.jwt.options @@ -181,10 +184,15 @@ async function successfulSignIn({ await promisify((req as any).login.bind(req))(user); const refreshToken = randomTokenString(); + let token_version = user.token_version; + if (!token_version) { + token_version = randomTokenString(); + } + await User.update(user.id, { refresh_token: refreshToken, email: user.email, - token_expired: false + token_version }); setTokenCookie(res, refreshToken); @@ -203,7 +211,8 @@ async function successfulSignIn({ firstname: user.firstname, lastname: user.lastname, id: user.id, - roles: user.roles + roles: user.roles, + token_version }, Noco.getConfig().auth.jwt.secret, @@ -292,7 +301,7 @@ async function passwordChange(req: Request, res): Promise { salt, password, email: user.email, - token_expired: true + token_version: null }); Audit.insert({ @@ -320,7 +329,8 @@ async function passwordForgot(req: Request, res): Promise { await User.update(user.id, { email: user.email, reset_password_token: token, - reset_password_expires: new Date(Date.now() + 60 * 60 * 1000) + reset_password_expires: new Date(Date.now() + 60 * 60 * 1000), + token_version: null }); try { const template = (await import('./ui/emailTemplates/forgotPassword')) @@ -371,7 +381,7 @@ async function tokenValidate(req, res): Promise { if (user.reset_password_expires < new Date()) { NcError.badRequest('Password reset url expired'); } - if (user.token_expired) { + if (!user.token_version) { NcError.badRequest('Token Expired. Please login again.'); } res.json(true); @@ -403,7 +413,7 @@ async function passwordReset(req, res): Promise { email: user.email, reset_password_expires: null, reset_password_token: '', - token_expired: true + token_version: null }); Audit.insert({ @@ -461,8 +471,7 @@ async function refreshToken(req, res): Promise { await User.update(user.id, { email: user.email, - refresh_token: refreshToken, - token_expired: false + refresh_token: refreshToken }); setTokenCookie(res, refreshToken); diff --git a/packages/nocodb/src/lib/meta/helpers/ncMetaAclMw.ts b/packages/nocodb/src/lib/meta/helpers/ncMetaAclMw.ts index b2bbad271b..944ab25de0 100644 --- a/packages/nocodb/src/lib/meta/helpers/ncMetaAclMw.ts +++ b/packages/nocodb/src/lib/meta/helpers/ncMetaAclMw.ts @@ -2,9 +2,6 @@ import projectAcl from '../../utils/projectAcl'; import { NextFunction, Request, Response } from 'express'; import catchError, { NcError } from './catchError'; import extractProjectIdAndAuthenticate from './extractProjectIdAndAuthenticate'; -import NocoCache from '../../cache/NocoCache'; -import Noco from '../../Noco'; -import { CacheGetType, CacheScope, MetaTable } from '../../utils/globals'; export default function(handlerFn, permissionName) { return [ @@ -24,25 +21,6 @@ export default function(handlerFn, permissionName) { ) { NcError.unauthorized('Unauthorized access'); } - - // check if the token is still valid for non-public base - if (!req?.session?.passport?.user?.isPublicBase) { - const email = req?.session?.passport?.user?.email; - let user = - email && - (await NocoCache.get( - `${CacheScope.USER}:${email}`, - CacheGetType.TYPE_OBJECT - )); - if (!user) { - user = await Noco.ncMeta.metaGet2(null, null, MetaTable.USERS, { - email - }); - } - if (user.token_expired) { - NcError.unauthorized('Token Expired. Please login again.'); - } - } next(); }), // @ts-ignore diff --git a/packages/nocodb/src/lib/migrations/XcMigrationSourcev2.ts b/packages/nocodb/src/lib/migrations/XcMigrationSourcev2.ts index 8b303131f4..dbcd223c7b 100644 --- a/packages/nocodb/src/lib/migrations/XcMigrationSourcev2.ts +++ b/packages/nocodb/src/lib/migrations/XcMigrationSourcev2.ts @@ -4,7 +4,7 @@ import * as nc_013_sync_source from './v2/nc_013_sync_source'; import * as nc_014_alter_column_data_types from './v2/nc_014_alter_column_data_types'; import * as nc_015_add_meta_col_in_column_table from './v2/nc_015_add_meta_col_in_column_table'; import * as nc_016_alter_hooklog_payload_types from './v2/nc_016_alter_hooklog_payload_types'; -import * as nc_017_add_user_token_exp_column from './v2/nc_017_add_user_token_exp_column'; +import * as nc_017_add_user_token_version_column from './v2/nc_017_add_user_token_version_column'; // Create a custom migration source class export default class XcMigrationSourcev2 { @@ -20,7 +20,7 @@ export default class XcMigrationSourcev2 { 'nc_014_alter_column_data_types', 'nc_015_add_meta_col_in_column_table', 'nc_016_alter_hooklog_payload_types', - 'nc_017_add_user_token_exp_column' + 'nc_017_add_user_token_version_column' ]); } @@ -42,8 +42,8 @@ export default class XcMigrationSourcev2 { return nc_015_add_meta_col_in_column_table; case 'nc_016_alter_hooklog_payload_types': return nc_016_alter_hooklog_payload_types; - case 'nc_017_add_user_token_exp_column': - return nc_017_add_user_token_exp_column; + case 'nc_017_add_user_token_version_column': + return nc_017_add_user_token_version_column; } } } diff --git a/packages/nocodb/src/lib/migrations/v2/nc_017_add_user_token_exp_column.ts b/packages/nocodb/src/lib/migrations/v2/nc_017_add_user_token_version_column.ts similarity index 92% rename from packages/nocodb/src/lib/migrations/v2/nc_017_add_user_token_exp_column.ts rename to packages/nocodb/src/lib/migrations/v2/nc_017_add_user_token_version_column.ts index 9e4c2e9ae9..083bcb353d 100644 --- a/packages/nocodb/src/lib/migrations/v2/nc_017_add_user_token_exp_column.ts +++ b/packages/nocodb/src/lib/migrations/v2/nc_017_add_user_token_version_column.ts @@ -2,13 +2,13 @@ import Knex from 'knex'; const up = async (knex: Knex) => { await knex.schema.alterTable('nc_users_v2', table => { - table.boolean('token_expired').defaultTo(false); + table.string('token_version'); }); }; const down = async knex => { await knex.schema.alterTable('nc_users_v2', table => { - table.dropColumns('token_expired'); + table.dropColumns('token_version'); }); }; diff --git a/packages/nocodb/src/lib/models/User.ts b/packages/nocodb/src/lib/models/User.ts index a9d046fac3..3b383dc88c 100644 --- a/packages/nocodb/src/lib/models/User.ts +++ b/packages/nocodb/src/lib/models/User.ts @@ -22,7 +22,7 @@ export default class User implements UserType { email_verification_token?: string; email_verified: boolean; roles?: string; - token_expired?: boolean; + token_version?: string; constructor(data: User) { Object.assign(this, data); @@ -45,7 +45,7 @@ export default class User implements UserType { 'email_verification_token', 'email_verified', 'roles', - 'token_expired' + 'token_version' ]); const { id } = await ncMeta.metaInsert2( null, @@ -74,7 +74,7 @@ export default class User implements UserType { 'email_verification_token', 'email_verified', 'roles', - 'token_expired' + 'token_version' ]); // get existing cache const keys = [ diff --git a/packages/nocodb/src/lib/v1-legacy/rest/RestAuthCtrl.ts b/packages/nocodb/src/lib/v1-legacy/rest/RestAuthCtrl.ts index f7c0a2fc7e..a7ac48db87 100644 --- a/packages/nocodb/src/lib/v1-legacy/rest/RestAuthCtrl.ts +++ b/packages/nocodb/src/lib/v1-legacy/rest/RestAuthCtrl.ts @@ -42,7 +42,8 @@ passport.serializeUser(function( firstname, lastname, isAuthorized, - isPublicBase + isPublicBase, + token_version }, done ) { @@ -61,7 +62,8 @@ passport.serializeUser(function( provider, firstname, lastname, - roles + roles, + token_version }); });