Browse Source

Merge branch 'develop' into feat/pnpm

pull/5903/head
Wing-Kam Wong 1 year ago
parent
commit
6c740e8de4
  1. 4
      packages/nc-gui/middleware/auth.global.ts
  2. 2
      packages/nc-lib-gui/package.json
  3. 2
      packages/nocodb-sdk/package.json
  4. 4
      packages/nocodb/package.json
  5. 137
      packages/nocodb/src/helpers/initAdminFromEnv.ts
  6. 11
      packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts
  7. 2
      packages/nocodb/src/models/User.ts
  8. 1
      packages/nocodb/src/services/api-docs/swagger/getSwaggerColumnMetas.ts
  9. 6
      packages/nocodb/src/services/api-docs/swagger/templates/paths.ts
  10. 17
      packages/nocodb/src/strategies/authtoken.strategy/authtoken.strategy.ts

4
packages/nc-gui/middleware/auth.global.ts

@ -85,7 +85,7 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
} }
} else { } else {
/** If page is limited to certain users verify the user have the roles */ /** If page is limited to certain users verify the user have the roles */
if (to.meta.allowedRoles && to.meta.allowedRoles.every((role) => !allRoles.value[role])) { if (to.meta.allowedRoles && to.meta.allowedRoles.every((role) => !allRoles.value?.[role])) {
message.error("You don't have enough permission to access the page.") message.error("You don't have enough permission to access the page.")
return navigateTo('/') return navigateTo('/')
} }
@ -94,7 +94,7 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
if (to.params.projectId && from.params.projectId !== to.params.projectId) { if (to.params.projectId && from.params.projectId !== to.params.projectId) {
const user = await api.auth.me({ project_id: to.params.projectId as string }) const user = await api.auth.me({ project_id: to.params.projectId as string })
if (user?.roles?.user) { if (user?.roles?.guest) {
message.error("You don't have enough permission to access the project.") message.error("You don't have enough permission to access the project.")
return navigateTo('/') return navigateTo('/')

2
packages/nc-lib-gui/package.json

@ -1,6 +1,6 @@
{ {
"name": "nc-lib-gui", "name": "nc-lib-gui",
"version": "0.111.2", "version": "0.111.3",
"description": "NocoDB GUI", "description": "NocoDB GUI",
"author": { "author": {
"name": "NocoDB", "name": "NocoDB",

2
packages/nocodb-sdk/package.json

@ -1,6 +1,6 @@
{ {
"name": "nocodb-sdk", "name": "nocodb-sdk",
"version": "0.111.2", "version": "0.111.3",
"description": "NocoDB SDK", "description": "NocoDB SDK",
"main": "build/main/index.js", "main": "build/main/index.js",
"typings": "build/main/index.d.ts", "typings": "build/main/index.d.ts",

4
packages/nocodb/package.json

@ -1,6 +1,6 @@
{ {
"name": "nocodb", "name": "nocodb",
"version": "0.111.2", "version": "0.111.3",
"description": "NocoDB Backend", "description": "NocoDB Backend",
"main": "dist/bundle.js", "main": "dist/bundle.js",
"author": { "author": {
@ -129,7 +129,7 @@
"mysql2": "^3.2.0", "mysql2": "^3.2.0",
"nanoid": "^3.1.20", "nanoid": "^3.1.20",
"nc-help": "^0.2.88", "nc-help": "^0.2.88",
"nc-lib-gui": "0.111.2", "nc-lib-gui": "0.111.3",
"nc-plugin": "^0.1.3", "nc-plugin": "^0.1.3",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"nestjs-kafka": "^1.0.6", "nestjs-kafka": "^1.0.6",

137
packages/nocodb/src/helpers/initAdminFromEnv.ts

@ -62,7 +62,7 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
salt, salt,
); );
const email_verification_token = uuidv4(); const email_verification_token = uuidv4();
const roles = 'user,super'; const roles = 'org-level-creator,super';
// if super admin not present // if super admin not present
if (await User.isFirst(ncMeta)) { if (await User.isFirst(ncMeta)) {
@ -78,6 +78,7 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
salt, salt,
password, password,
email_verification_token, email_verification_token,
token_version: randomTokenString(),
roles, roles,
}, },
ncMeta, ncMeta,
@ -89,62 +90,25 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
salt, salt,
); );
const email_verification_token = uuidv4(); const email_verification_token = uuidv4();
const superUser = await ncMeta.metaGet2(null, null, MetaTable.USERS, { // TODO improve this
roles: 'user,super', const superUsers = await ncMeta.metaList2(null, null, MetaTable.USERS);
});
if (!superUser?.id) { let superUserPresent = false;
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 for (const user of superUsers) {
await User.update( if (!user.roles?.includes('super')) continue;
existingUserWithNewEmail.id,
{
salt,
email,
password,
email_verification_token,
token_version: randomTokenString(),
refresh_token: null,
roles,
},
ncMeta,
);
} else {
T.emit('evt', {
evt_type: 'project:invite',
count: 1,
});
await User.insert( superUserPresent = true;
{
email, if (email !== user.email) {
salt,
password,
email_verification_token,
roles,
},
ncMeta,
);
}
} else if (email !== superUser.email) {
// update admin email and password and migrate projects // update admin email and password and migrate projects
// if user already present and associated with some project // if user already present and associated with some project
// 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?.id) { if (existingUserWithNewEmail?.id) {
// get all project access belongs to the existing account // get all project access belongs to the existing account
@ -161,7 +125,7 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
for (const existingUserProject of existingUserProjects) { for (const existingUserProject of existingUserProjects) {
const userProject = await ProjectUser.get( const userProject = await ProjectUser.get(
existingUserProject.project_id, existingUserProject.project_id,
superUser.id, user.id,
ncMeta, ncMeta,
); );
@ -174,7 +138,7 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
) { ) {
await ProjectUser.update( await ProjectUser.update(
userProject.project_id, userProject.project_id,
superUser.id, user.id,
existingUserProject.roles, existingUserProject.roles,
ncMeta, ncMeta,
); );
@ -184,7 +148,7 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
await ProjectUser.insert( await ProjectUser.insert(
{ {
...existingUserProject, ...existingUserProject,
fk_user_id: superUser.id, fk_user_id: user.id,
}, },
ncMeta, ncMeta,
); );
@ -219,7 +183,7 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
// Update email and password of super admin account // Update email and password of super admin account
await User.update( await User.update(
superUser.id, user.id,
{ {
salt, salt,
email, email,
@ -231,9 +195,9 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
ncMeta, ncMeta,
); );
} else { } else {
// if email's are not different update the password and hash // if no user present with the new admin email update the email and password
await User.update( await User.update(
superUser.id, user.id,
{ {
salt, salt,
email, email,
@ -248,14 +212,14 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
} else { } else {
const newPasswordHash = await promisify(bcrypt.hash)( const newPasswordHash = await promisify(bcrypt.hash)(
process.env.NC_ADMIN_PASSWORD, process.env.NC_ADMIN_PASSWORD,
superUser.salt, user.salt,
); );
if (newPasswordHash !== superUser.password) { if (newPasswordHash !== user.password) {
// if email's are same and passwords are different // if email's are same and passwords are different
// then update the password and token version // then update the password and token version
await User.update( await User.update(
superUser.id, user.id,
{ {
salt, salt,
password, password,
@ -268,11 +232,64 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
} }
} }
} }
if (!superUserPresent) {
// check user account already present with the new admin email
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 password and roles of existing user
await User.update(
existingUserWithNewEmail.id,
{
salt,
email,
password,
email_verification_token,
token_version: randomTokenString(),
refresh_token: null,
roles,
},
ncMeta,
);
} else {
// no super user present and no user present with the new admin email
T.emit('evt', {
evt_type: 'project:invite',
count: 1,
});
await User.insert(
{
email,
salt,
password,
email_verification_token,
token_version: randomTokenString(),
roles,
},
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');
console.log(e);
await ncMeta.rollback(e); await ncMeta.rollback(e);
throw e;
} }
} }
} }

11
packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts

@ -180,8 +180,8 @@ export class ExtractIdsMiddleware implements NestMiddleware, CanActivate {
} }
function getUserRoleForScope(user: any, scope: string) { function getUserRoleForScope(user: any, scope: string) {
if (scope === 'project' || scope === 'workspace') { if (scope === 'project') {
return user?.project_roles || user?.workspace_roles; return user?.project_roles;
} else if (scope === 'org') { } else if (scope === 'org') {
return user?.roles; return user?.roles;
} }
@ -220,6 +220,13 @@ export class AclMiddleware implements NestInterceptor {
NcError.forbidden('Unauthorized access'); NcError.forbidden('Unauthorized access');
} }
// assign owner role to super admin for all projects
if (userScopeRole === OrgUserRoles.SUPER_ADMIN) {
req.user.project_roles = {
[ProjectRoles.OWNER]: true,
};
}
const roles: Record<string, boolean> = extractRolesObj(userScopeRole); const roles: Record<string, boolean> = extractRolesObj(userScopeRole);
if (req?.user?.is_api_token && blockApiTokenAccess) { if (req?.user?.is_api_token && blockApiTokenAccess) {

2
packages/nocodb/src/models/User.ts

@ -87,7 +87,7 @@ export default class User implements UserType {
// check if the target email addr is in use or not // check if the target email addr is in use or not
const targetUser = await this.getByEmail(updateObj.email, ncMeta); const targetUser = await this.getByEmail(updateObj.email, ncMeta);
if (targetUser.id !== id) { if (targetUser && targetUser.id !== id) {
NcError.badRequest('email is in use'); NcError.badRequest('email is in use');
} }
} else { } else {

1
packages/nocodb/src/services/api-docs/swagger/getSwaggerColumnMetas.ts

@ -36,6 +36,7 @@ export default async (
field.type = 'object'; field.type = 'object';
break; break;
case UITypes.Rollup: case UITypes.Rollup:
case UITypes.Links:
field.type = 'number'; field.type = 'number';
break; break;
case UITypes.Attachment: case UITypes.Attachment:

6
packages/nocodb/src/services/api-docs/swagger/templates/paths.ts

@ -1,4 +1,4 @@
import { ModelTypes, UITypes } from 'nocodb-sdk'; import { isLinksOrLTAR, ModelTypes, UITypes } from 'nocodb-sdk';
import { import {
columnNameParam, columnNameParam,
columnNameQueryParam, columnNameQueryParam,
@ -670,7 +670,5 @@ function getPaginatedResponseType(type: string) {
}; };
} }
function isRelationExist(columns: SwaggerColumn[]) { function isRelationExist(columns: SwaggerColumn[]) {
return columns.some( return columns.some((c) => isLinksOrLTAR(c.column) && !c.column.system);
(c) => c.column.uidt === UITypes.LinkToAnotherRecord && !c.column.system,
);
} }

17
packages/nocodb/src/strategies/authtoken.strategy/authtoken.strategy.ts

@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport'; import { PassportStrategy } from '@nestjs/passport';
import { extractRolesObj, ProjectRoles } from 'nocodb-sdk';
import { Strategy } from 'passport-custom'; import { Strategy } from 'passport-custom';
import { ApiToken, ProjectUser, User } from '~/models'; import { ApiToken, ProjectUser, User } from '~/models';
import { sanitiseUserObj } from '~/utils'; import { sanitiseUserObj } from '~/utils';
@ -16,9 +17,12 @@ export class AuthTokenStrategy extends PassportStrategy(Strategy, 'authtoken') {
return callback({ msg: 'Invalid token' }); return callback({ msg: 'Invalid token' });
} }
user = {}; user = {
is_api_token: true,
};
if (!apiToken.fk_user_id) { if (!apiToken.fk_user_id) {
user.roles = 'editor'; user.project_roles = extractRolesObj(ProjectRoles.EDITOR);
return callback(null, user); return callback(null, user);
} }
@ -29,17 +33,18 @@ export class AuthTokenStrategy extends PassportStrategy(Strategy, 'authtoken') {
Object.assign(user, { Object.assign(user, {
id: dbUser.id, id: dbUser.id,
roles: dbUser.roles, roles: extractRolesObj(dbUser.roles),
}); });
dbUser.is_api_token = true;
if (req['ncProjectId']) { if (req['ncProjectId']) {
const projectUser = await ProjectUser.get( const projectUser = await ProjectUser.get(
req['ncProjectId'], req['ncProjectId'],
dbUser.id, dbUser.id,
); );
user.roles = projectUser?.roles || dbUser.roles; user.project_roles = extractRolesObj(projectUser?.roles);
user.roles = user.roles === 'owner' ? 'owner,creator' : user.roles; if (user.project_roles.owner) {
user.project_roles.creator = true;
}
return callback(null, sanitiseUserObj(user)); return callback(null, sanitiseUserObj(user));
} }
} }

Loading…
Cancel
Save