Browse Source

fix: session across broswers

pull/2338/head
Wing-Kam Wong 2 years ago
parent
commit
5f08ecbf67
  1. 12
      packages/nocodb/src/lib/meta/api/userApi/initStrategies.ts
  2. 29
      packages/nocodb/src/lib/meta/api/userApi/userApis.ts
  3. 22
      packages/nocodb/src/lib/meta/helpers/ncMetaAclMw.ts
  4. 8
      packages/nocodb/src/lib/migrations/XcMigrationSourcev2.ts
  5. 4
      packages/nocodb/src/lib/migrations/v2/nc_017_add_user_token_version_column.ts
  6. 6
      packages/nocodb/src/lib/models/User.ts
  7. 6
      packages/nocodb/src/lib/v1-legacy/rest/RestAuthCtrl.ts

12
packages/nocodb/src/lib/meta/api/userApi/initStrategies.ts

@ -53,7 +53,8 @@ export function initStrategies(router): void {
firstname, firstname,
lastname, lastname,
isAuthorized, isAuthorized,
isPublicBase isPublicBase,
token_version
}, },
done done
) { ) {
@ -72,7 +73,8 @@ export function initStrategies(router): void {
provider, provider,
firstname, firstname,
lastname, lastname,
roles roles,
token_version
}); });
}); });
@ -100,11 +102,17 @@ export function initStrategies(router): void {
); );
if (cachedVal) { if (cachedVal) {
if (cachedVal.token_version !== jwtPayload.token_version) {
return done(new Error('Token Expired. Please login again.'));
}
return done(null, cachedVal); return done(null, cachedVal);
} }
User.getByEmail(jwtPayload?.email) User.getByEmail(jwtPayload?.email)
.then(async user => { .then(async user => {
if (user.token_version !== jwtPayload.token_version) {
return done(new Error('Token Expired. Please login again.'));
}
if (req.ncProjectId) { if (req.ncProjectId) {
// this.xcMeta // this.xcMeta
// .metaGet(req.ncProjectId, null, 'nc_projects_users', { // .metaGet(req.ncProjectId, null, 'nc_projects_users', {

29
packages/nocodb/src/lib/meta/api/userApi/userApis.ts

@ -96,6 +96,8 @@ export async function signup(req: Request, res: Response<TableType>) {
} }
} }
const token_version = randomTokenString();
await User.insert({ await User.insert({
firstname, firstname,
lastname, lastname,
@ -104,7 +106,7 @@ export async function signup(req: Request, res: Response<TableType>) {
password, password,
email_verification_token, email_verification_token,
roles, roles,
token_expired: false token_version
}); });
} }
user = await User.getByEmail(email); user = await User.getByEmail(email);
@ -151,7 +153,8 @@ export async function signup(req: Request, res: Response<TableType>) {
firstname: user.firstname, firstname: user.firstname,
lastname: user.lastname, lastname: user.lastname,
id: user.id, id: user.id,
roles: user.roles roles: user.roles,
token_version: user.token_version
}, },
Noco.getConfig().auth.jwt.secret, Noco.getConfig().auth.jwt.secret,
Noco.getConfig().auth.jwt.options Noco.getConfig().auth.jwt.options
@ -181,10 +184,15 @@ async function successfulSignIn({
await promisify((req as any).login.bind(req))(user); await promisify((req as any).login.bind(req))(user);
const refreshToken = randomTokenString(); const refreshToken = randomTokenString();
let token_version = user.token_version;
if (!token_version) {
token_version = randomTokenString();
}
await User.update(user.id, { await User.update(user.id, {
refresh_token: refreshToken, refresh_token: refreshToken,
email: user.email, email: user.email,
token_expired: false token_version
}); });
setTokenCookie(res, refreshToken); setTokenCookie(res, refreshToken);
@ -203,7 +211,8 @@ async function successfulSignIn({
firstname: user.firstname, firstname: user.firstname,
lastname: user.lastname, lastname: user.lastname,
id: user.id, id: user.id,
roles: user.roles roles: user.roles,
token_version
}, },
Noco.getConfig().auth.jwt.secret, Noco.getConfig().auth.jwt.secret,
@ -292,7 +301,7 @@ async function passwordChange(req: Request<any, any>, res): Promise<any> {
salt, salt,
password, password,
email: user.email, email: user.email,
token_expired: true token_version: null
}); });
Audit.insert({ Audit.insert({
@ -320,7 +329,8 @@ async function passwordForgot(req: Request<any, any>, res): Promise<any> {
await User.update(user.id, { await User.update(user.id, {
email: user.email, email: user.email,
reset_password_token: token, 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 { try {
const template = (await import('./ui/emailTemplates/forgotPassword')) const template = (await import('./ui/emailTemplates/forgotPassword'))
@ -371,7 +381,7 @@ async function tokenValidate(req, res): Promise<any> {
if (user.reset_password_expires < new Date()) { if (user.reset_password_expires < new Date()) {
NcError.badRequest('Password reset url expired'); NcError.badRequest('Password reset url expired');
} }
if (user.token_expired) { if (!user.token_version) {
NcError.badRequest('Token Expired. Please login again.'); NcError.badRequest('Token Expired. Please login again.');
} }
res.json(true); res.json(true);
@ -403,7 +413,7 @@ async function passwordReset(req, res): Promise<any> {
email: user.email, email: user.email,
reset_password_expires: null, reset_password_expires: null,
reset_password_token: '', reset_password_token: '',
token_expired: true token_version: null
}); });
Audit.insert({ Audit.insert({
@ -461,8 +471,7 @@ async function refreshToken(req, res): Promise<any> {
await User.update(user.id, { await User.update(user.id, {
email: user.email, email: user.email,
refresh_token: refreshToken, refresh_token: refreshToken
token_expired: false
}); });
setTokenCookie(res, refreshToken); setTokenCookie(res, refreshToken);

22
packages/nocodb/src/lib/meta/helpers/ncMetaAclMw.ts

@ -2,9 +2,6 @@ import projectAcl from '../../utils/projectAcl';
import { NextFunction, Request, Response } from 'express'; import { NextFunction, Request, Response } from 'express';
import catchError, { NcError } from './catchError'; import catchError, { NcError } from './catchError';
import extractProjectIdAndAuthenticate from './extractProjectIdAndAuthenticate'; 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) { export default function(handlerFn, permissionName) {
return [ return [
@ -24,25 +21,6 @@ export default function(handlerFn, permissionName) {
) { ) {
NcError.unauthorized('Unauthorized access'); 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(); next();
}), }),
// @ts-ignore // @ts-ignore

8
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_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_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_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 // Create a custom migration source class
export default class XcMigrationSourcev2 { export default class XcMigrationSourcev2 {
@ -20,7 +20,7 @@ export default class XcMigrationSourcev2 {
'nc_014_alter_column_data_types', 'nc_014_alter_column_data_types',
'nc_015_add_meta_col_in_column_table', 'nc_015_add_meta_col_in_column_table',
'nc_016_alter_hooklog_payload_types', '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; return nc_015_add_meta_col_in_column_table;
case 'nc_016_alter_hooklog_payload_types': case 'nc_016_alter_hooklog_payload_types':
return nc_016_alter_hooklog_payload_types; return nc_016_alter_hooklog_payload_types;
case 'nc_017_add_user_token_exp_column': case 'nc_017_add_user_token_version_column':
return nc_017_add_user_token_exp_column; return nc_017_add_user_token_version_column;
} }
} }
} }

4
packages/nocodb/src/lib/migrations/v2/nc_017_add_user_token_exp_column.ts → 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) => { const up = async (knex: Knex) => {
await knex.schema.alterTable('nc_users_v2', table => { await knex.schema.alterTable('nc_users_v2', table => {
table.boolean('token_expired').defaultTo(false); table.string('token_version');
}); });
}; };
const down = async knex => { const down = async knex => {
await knex.schema.alterTable('nc_users_v2', table => { await knex.schema.alterTable('nc_users_v2', table => {
table.dropColumns('token_expired'); table.dropColumns('token_version');
}); });
}; };

6
packages/nocodb/src/lib/models/User.ts

@ -22,7 +22,7 @@ export default class User implements UserType {
email_verification_token?: string; email_verification_token?: string;
email_verified: boolean; email_verified: boolean;
roles?: string; roles?: string;
token_expired?: boolean; token_version?: string;
constructor(data: User) { constructor(data: User) {
Object.assign(this, data); Object.assign(this, data);
@ -45,7 +45,7 @@ export default class User implements UserType {
'email_verification_token', 'email_verification_token',
'email_verified', 'email_verified',
'roles', 'roles',
'token_expired' 'token_version'
]); ]);
const { id } = await ncMeta.metaInsert2( const { id } = await ncMeta.metaInsert2(
null, null,
@ -74,7 +74,7 @@ export default class User implements UserType {
'email_verification_token', 'email_verification_token',
'email_verified', 'email_verified',
'roles', 'roles',
'token_expired' 'token_version'
]); ]);
// get existing cache // get existing cache
const keys = [ const keys = [

6
packages/nocodb/src/lib/v1-legacy/rest/RestAuthCtrl.ts

@ -42,7 +42,8 @@ passport.serializeUser(function(
firstname, firstname,
lastname, lastname,
isAuthorized, isAuthorized,
isPublicBase isPublicBase,
token_version
}, },
done done
) { ) {
@ -61,7 +62,8 @@ passport.serializeUser(function(
provider, provider,
firstname, firstname,
lastname, lastname,
roles roles,
token_version
}); });
}); });

Loading…
Cancel
Save