Browse Source

Merge pull request #2393 from nocodb/fix/admin-env-variables

Fix: invalidate token if admin email or password changed
pull/2492/head
navi 2 years ago committed by GitHub
parent
commit
073749f494
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 41
      packages/nocodb/src/lib/meta/api/userApi/initAdminFromEnv.ts
  2. 8
      packages/nocodb/src/lib/meta/api/userApi/initStrategies.ts
  3. 7
      packages/nocodb/src/lib/meta/api/userApi/userApis.ts
  4. 3
      packages/nocodb/src/lib/models/User.ts

41
packages/nocodb/src/lib/meta/api/userApi/initAdminFromEnv.ts

@ -5,10 +5,11 @@ import { Tele } from 'nc-help';
import bcrypt from 'bcryptjs'; import bcrypt from 'bcryptjs';
import Noco from '../../../Noco'; import Noco from '../../../Noco';
import { MetaTable } from '../../../utils/globals'; import { CacheScope, MetaTable } from '../../../utils/globals';
import ProjectUser from '../../../models/ProjectUser'; import ProjectUser from '../../../models/ProjectUser';
import { validatePassword } from 'nocodb-sdk'; import { validatePassword } from 'nocodb-sdk';
import boxen from 'boxen'; import boxen from 'boxen';
import NocoCache from '../../../cache/NocoCache';
const { isEmail } = require('validator'); const { isEmail } = require('validator');
const rolesLevel = { owner: 0, creator: 1, editor: 2, commenter: 3, viewer: 4 }; const rolesLevel = { owner: 0, creator: 1, editor: 2, commenter: 3, viewer: 4 };
@ -103,7 +104,7 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
// check user account already present with the new admin email // check user account already present with the new admin email
const existingUserWithNewEmail = await User.getByEmail(email, ncMeta); const existingUserWithNewEmail = await User.getByEmail(email, ncMeta);
if (existingUserWithNewEmail) { if (existingUserWithNewEmail?.id) {
// get all project access belongs to the existing account // get all project access belongs to the existing account
// and migrate to the admin account // and migrate to the admin account
const existingUserProjects = await ncMeta.metaList2( const existingUserProjects = await ncMeta.metaList2(
@ -155,13 +156,25 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
} }
// delete existing user // delete existing user
ncMeta.metaDelete( await ncMeta.metaDelete(
null, null,
null, null,
MetaTable.USERS, MetaTable.USERS,
existingUserWithNewEmail.id existingUserWithNewEmail.id
); );
// clear cache
await NocoCache.delAll(
CacheScope.USER,
`${existingUserWithNewEmail.email}___*`
);
await NocoCache.del(
`${CacheScope.USER}:${existingUserWithNewEmail.id}`
);
await NocoCache.del(
`${CacheScope.USER}:${existingUserWithNewEmail.email}`
);
// Update email and password of super admin account // Update email and password of super admin account
await User.update( await User.update(
superUser.id, superUser.id,
@ -169,7 +182,9 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
salt, salt,
email, email,
password, password,
email_verification_token email_verification_token,
token_version: null,
refresh_token: null
}, },
ncMeta ncMeta
); );
@ -181,24 +196,36 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
salt, salt,
email, email,
password, password,
email_verification_token email_verification_token,
token_version: null,
refresh_token: null
}, },
ncMeta ncMeta
); );
} }
} else { } else {
// if email's are not different update the password and hash const newPasswordHash = await promisify(bcrypt.hash)(
process.env.NC_ADMIN_PASSWORD,
superUser.salt
);
if (newPasswordHash !== superUser.password) {
// if email's are same and passwords are different
// then update the password and token version
await User.update( await User.update(
superUser.id, superUser.id,
{ {
salt, salt,
password, password,
email_verification_token email_verification_token,
token_version: null,
refresh_token: null
}, },
ncMeta ncMeta
); );
} }
} }
}
await ncMeta.commit(); await ncMeta.commit();
} catch (e) { } catch (e) {
console.log('Error occurred while updating/creating admin user'); console.log('Error occurred while updating/creating admin user');

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

@ -103,8 +103,8 @@ export function initStrategies(router): void {
if (cachedVal) { if (cachedVal) {
if ( if (
cachedVal.token_version && !cachedVal.token_version ||
jwtPayload.token_version && !jwtPayload.token_version ||
cachedVal.token_version !== jwtPayload.token_version cachedVal.token_version !== jwtPayload.token_version
) { ) {
return done(new Error('Token Expired. Please login again.')); return done(new Error('Token Expired. Please login again.'));
@ -115,8 +115,8 @@ export function initStrategies(router): void {
User.getByEmail(jwtPayload?.email) User.getByEmail(jwtPayload?.email)
.then(async user => { .then(async user => {
if ( if (
user.token_version && !user.token_version ||
jwtPayload.token_version && !jwtPayload.token_version ||
user.token_version !== jwtPayload.token_version user.token_version !== jwtPayload.token_version
) { ) {
return done(new Error('Token Expired. Please login again.')); return done(new Error('Token Expired. Please login again.'));

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

@ -179,15 +179,14 @@ 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 (!user.token_version) {
if (!token_version) { user.token_version = randomTokenString();
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_version token_version: user.token_version
}); });
setTokenCookie(res, refreshToken); setTokenCookie(res, refreshToken);

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

@ -84,6 +84,9 @@ export default class User implements UserType {
if (updateObj.email) { if (updateObj.email) {
updateObj.email = updateObj.email.toLowerCase(); updateObj.email = updateObj.email.toLowerCase();
} else {
// set email prop to avoid generation of invalid cache key
updateObj.email = (await this.get(id, ncMeta))?.email?.toLowerCase();
} }
// get existing cache // get existing cache
const keys = [ const keys = [

Loading…
Cancel
Save