mirror of https://github.com/nocodb/nocodb
nith2001
2 years ago
committed by
GitHub
197 changed files with 16300 additions and 9042 deletions
@ -1,19 +0,0 @@ |
|||||||
import { Test } from '@nestjs/testing'; |
|
||||||
import { Connection } from './knex'; |
|
||||||
import type { TestingModule } from '@nestjs/testing'; |
|
||||||
|
|
||||||
describe('Knex', () => { |
|
||||||
let provider: Connection; |
|
||||||
|
|
||||||
beforeEach(async () => { |
|
||||||
const module: TestingModule = await Test.createTestingModule({ |
|
||||||
providers: [Connection], |
|
||||||
}).compile(); |
|
||||||
|
|
||||||
provider = module.get<Connection>(Connection); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should be defined', () => { |
|
||||||
expect(provider).toBeDefined(); |
|
||||||
}); |
|
||||||
}); |
|
@ -1,37 +0,0 @@ |
|||||||
import { Global, Injectable, Scope } from '@nestjs/common'; |
|
||||||
|
|
||||||
import { XKnex } from '../db/CustomKnex'; |
|
||||||
import NcConfigFactory from '../utils/NcConfigFactory'; |
|
||||||
import type * as knex from 'knex'; |
|
||||||
|
|
||||||
@Injectable({ |
|
||||||
scope: Scope.DEFAULT, |
|
||||||
}) |
|
||||||
export class Connection { |
|
||||||
public static knex: knex.Knex; |
|
||||||
public static _config: any; |
|
||||||
|
|
||||||
get knexInstance(): knex.Knex { |
|
||||||
return Connection.knex; |
|
||||||
} |
|
||||||
|
|
||||||
get config(): knex.Knex { |
|
||||||
return Connection._config; |
|
||||||
} |
|
||||||
|
|
||||||
// init metadb connection
|
|
||||||
static async init(): Promise<void> { |
|
||||||
Connection._config = await NcConfigFactory.make(); |
|
||||||
if (!Connection.knex) { |
|
||||||
Connection.knex = XKnex({ |
|
||||||
...this._config.meta.db, |
|
||||||
useNullAsDefault: true, |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// init metadb connection
|
|
||||||
async init(): Promise<void> { |
|
||||||
return await Connection.init(); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,281 @@ |
|||||||
|
import { promisify } from 'util'; |
||||||
|
import { v4 as uuidv4 } from 'uuid'; |
||||||
|
import bcrypt from 'bcryptjs'; |
||||||
|
import { validatePassword } from 'nocodb-sdk'; |
||||||
|
import boxen from 'boxen'; |
||||||
|
import { T } from 'nc-help'; |
||||||
|
import { isEmail } from 'validator'; |
||||||
|
import NocoCache from '../cache/NocoCache'; |
||||||
|
import { ProjectUser, User } from '../models'; |
||||||
|
import Noco from '../Noco'; |
||||||
|
import { CacheScope, MetaTable } from '../utils/globals'; |
||||||
|
|
||||||
|
const rolesLevel = { owner: 0, creator: 1, editor: 2, commenter: 3, viewer: 4 }; |
||||||
|
|
||||||
|
export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) { |
||||||
|
if (process.env.NC_ADMIN_EMAIL && process.env.NC_ADMIN_PASSWORD) { |
||||||
|
if (!isEmail(process.env.NC_ADMIN_EMAIL?.trim())) { |
||||||
|
console.log( |
||||||
|
'\n', |
||||||
|
boxen( |
||||||
|
`Provided admin email '${process.env.NC_ADMIN_EMAIL}' is not valid`, |
||||||
|
{ |
||||||
|
title: 'Invalid admin email', |
||||||
|
padding: 1, |
||||||
|
borderStyle: 'double', |
||||||
|
titleAlignment: 'center', |
||||||
|
borderColor: 'red', |
||||||
|
}, |
||||||
|
), |
||||||
|
'\n', |
||||||
|
); |
||||||
|
process.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
const { valid, error, hint } = validatePassword( |
||||||
|
process.env.NC_ADMIN_PASSWORD, |
||||||
|
); |
||||||
|
if (!valid) { |
||||||
|
console.log( |
||||||
|
'\n', |
||||||
|
boxen(`${error}${hint ? `\n\n${hint}` : ''}`, { |
||||||
|
title: 'Invalid admin password', |
||||||
|
padding: 1, |
||||||
|
borderStyle: 'double', |
||||||
|
titleAlignment: 'center', |
||||||
|
borderColor: 'red', |
||||||
|
}), |
||||||
|
'\n', |
||||||
|
); |
||||||
|
process.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
let ncMeta; |
||||||
|
try { |
||||||
|
ncMeta = await _ncMeta.startTransaction(); |
||||||
|
const email = process.env.NC_ADMIN_EMAIL.toLowerCase().trim(); |
||||||
|
|
||||||
|
const salt = await promisify(bcrypt.genSalt)(10); |
||||||
|
const password = await promisify(bcrypt.hash)( |
||||||
|
process.env.NC_ADMIN_PASSWORD, |
||||||
|
salt, |
||||||
|
); |
||||||
|
const email_verification_token = uuidv4(); |
||||||
|
const roles = 'user,super'; |
||||||
|
|
||||||
|
// if super admin not present
|
||||||
|
if (await User.isFirst(ncMeta)) { |
||||||
|
// roles = 'owner,creator,editor'
|
||||||
|
T.emit('evt', { |
||||||
|
evt_type: 'project:invite', |
||||||
|
count: 1, |
||||||
|
}); |
||||||
|
|
||||||
|
await User.insert( |
||||||
|
{ |
||||||
|
firstname: '', |
||||||
|
lastname: '', |
||||||
|
email, |
||||||
|
salt, |
||||||
|
password, |
||||||
|
email_verification_token, |
||||||
|
roles, |
||||||
|
}, |
||||||
|
ncMeta, |
||||||
|
); |
||||||
|
} else { |
||||||
|
const salt = await promisify(bcrypt.genSalt)(10); |
||||||
|
const password = await promisify(bcrypt.hash)( |
||||||
|
process.env.NC_ADMIN_PASSWORD, |
||||||
|
salt, |
||||||
|
); |
||||||
|
const email_verification_token = uuidv4(); |
||||||
|
const superUser = await ncMeta.metaGet2(null, null, MetaTable.USERS, { |
||||||
|
roles: 'user,super', |
||||||
|
}); |
||||||
|
|
||||||
|
if (!superUser?.id) { |
||||||
|
const existingUserWithNewEmail = await User.getByEmail(email, ncMeta); |
||||||
|
if (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
|
||||||
|
await User.update( |
||||||
|
existingUserWithNewEmail.id, |
||||||
|
{ |
||||||
|
salt, |
||||||
|
email, |
||||||
|
password, |
||||||
|
email_verification_token, |
||||||
|
token_version: null, |
||||||
|
refresh_token: null, |
||||||
|
roles, |
||||||
|
}, |
||||||
|
ncMeta, |
||||||
|
); |
||||||
|
} else { |
||||||
|
T.emit('evt', { |
||||||
|
evt_type: 'project:invite', |
||||||
|
count: 1, |
||||||
|
}); |
||||||
|
|
||||||
|
await User.insert( |
||||||
|
{ |
||||||
|
firstname: '', |
||||||
|
lastname: '', |
||||||
|
email, |
||||||
|
salt, |
||||||
|
password, |
||||||
|
email_verification_token, |
||||||
|
roles, |
||||||
|
}, |
||||||
|
ncMeta, |
||||||
|
); |
||||||
|
} |
||||||
|
} else if (email !== superUser.email) { |
||||||
|
// update admin email and password and migrate projects
|
||||||
|
// if user already present and associated with some project
|
||||||
|
|
||||||
|
// check user account already present with the new admin email
|
||||||
|
const existingUserWithNewEmail = await User.getByEmail(email, ncMeta); |
||||||
|
|
||||||
|
if (existingUserWithNewEmail?.id) { |
||||||
|
// get all project access belongs to the existing account
|
||||||
|
// and migrate to the admin account
|
||||||
|
const existingUserProjects = await ncMeta.metaList2( |
||||||
|
null, |
||||||
|
null, |
||||||
|
MetaTable.PROJECT_USERS, |
||||||
|
{ |
||||||
|
condition: { fk_user_id: existingUserWithNewEmail.id }, |
||||||
|
}, |
||||||
|
); |
||||||
|
|
||||||
|
for (const existingUserProject of existingUserProjects) { |
||||||
|
const userProject = await ProjectUser.get( |
||||||
|
existingUserProject.project_id, |
||||||
|
superUser.id, |
||||||
|
ncMeta, |
||||||
|
); |
||||||
|
|
||||||
|
// if admin user already have access to the project
|
||||||
|
// then update role based on the highest access level
|
||||||
|
if (userProject) { |
||||||
|
if ( |
||||||
|
rolesLevel[userProject.roles] > |
||||||
|
rolesLevel[existingUserProject.roles] |
||||||
|
) { |
||||||
|
await ProjectUser.update( |
||||||
|
userProject.project_id, |
||||||
|
superUser.id, |
||||||
|
existingUserProject.roles, |
||||||
|
ncMeta, |
||||||
|
); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// if super doesn't have access then add the access
|
||||||
|
await ProjectUser.insert( |
||||||
|
{ |
||||||
|
...existingUserProject, |
||||||
|
fk_user_id: superUser.id, |
||||||
|
}, |
||||||
|
ncMeta, |
||||||
|
); |
||||||
|
} |
||||||
|
// delete the old project access entry from DB
|
||||||
|
await ProjectUser.delete( |
||||||
|
existingUserProject.project_id, |
||||||
|
existingUserProject.fk_user_id, |
||||||
|
ncMeta, |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// delete existing user
|
||||||
|
await ncMeta.metaDelete( |
||||||
|
null, |
||||||
|
null, |
||||||
|
MetaTable.USERS, |
||||||
|
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
|
||||||
|
await User.update( |
||||||
|
superUser.id, |
||||||
|
{ |
||||||
|
salt, |
||||||
|
email, |
||||||
|
password, |
||||||
|
email_verification_token, |
||||||
|
token_version: null, |
||||||
|
refresh_token: null, |
||||||
|
}, |
||||||
|
ncMeta, |
||||||
|
); |
||||||
|
} else { |
||||||
|
// if email's are not different update the password and hash
|
||||||
|
await User.update( |
||||||
|
superUser.id, |
||||||
|
{ |
||||||
|
salt, |
||||||
|
email, |
||||||
|
password, |
||||||
|
email_verification_token, |
||||||
|
token_version: null, |
||||||
|
refresh_token: null, |
||||||
|
}, |
||||||
|
ncMeta, |
||||||
|
); |
||||||
|
} |
||||||
|
} else { |
||||||
|
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( |
||||||
|
superUser.id, |
||||||
|
{ |
||||||
|
salt, |
||||||
|
password, |
||||||
|
email_verification_token, |
||||||
|
token_version: null, |
||||||
|
refresh_token: null, |
||||||
|
}, |
||||||
|
ncMeta, |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
await ncMeta.commit(); |
||||||
|
} catch (e) { |
||||||
|
console.log('Error occurred while updating/creating admin user'); |
||||||
|
console.log(e); |
||||||
|
await ncMeta.rollback(e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,6 +1,5 @@ |
|||||||
import Noco from './Noco'; |
import Noco from './Noco'; |
||||||
import NcConfigFactory from './utils/NcConfigFactory'; |
|
||||||
|
|
||||||
export default Noco; |
export default Noco; |
||||||
|
|
||||||
export { Noco, NcConfigFactory }; |
export { Noco }; |
||||||
|
@ -1,12 +1,12 @@ |
|||||||
import { Connection } from './connection/connection'; |
|
||||||
import { MetaService } from './meta/meta.service'; |
import { MetaService } from './meta/meta.service'; |
||||||
|
import { NcConfig } from './utils/nc-config'; |
||||||
import Noco from './Noco'; |
import Noco from './Noco'; |
||||||
|
|
||||||
// run upgrader
|
// run upgrader
|
||||||
import NcUpgrader from './version-upgrader/NcUpgrader'; |
import NcUpgrader from './version-upgrader/NcUpgrader'; |
||||||
|
|
||||||
export default async () => { |
export default async () => { |
||||||
await Connection.init(); |
const config = await NcConfig.createByEnv(); |
||||||
Noco._ncMeta = new MetaService(new Connection()); |
Noco._ncMeta = new MetaService(config); |
||||||
await NcUpgrader.upgrade({ ncMeta: Noco._ncMeta }); |
await NcUpgrader.upgrade({ ncMeta: Noco._ncMeta }); |
||||||
}; |
}; |
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue