Browse Source

feat: middleware to authguard

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/5444/head
Pranav C 2 years ago
parent
commit
bf7e41db6b
  1. 24
      packages/nocodb-nest/src/app.module.ts
  2. 47
      packages/nocodb-nest/src/middlewares/extract-project-id/extract-project-id.middleware.ts
  3. 0
      packages/nocodb-nest/src/modules/auth/auth.controller.spec.ts
  4. 0
      packages/nocodb-nest/src/modules/auth/auth.controller.ts
  5. 2
      packages/nocodb-nest/src/modules/auth/auth.module.ts
  6. 0
      packages/nocodb-nest/src/modules/auth/auth.service.spec.ts
  7. 2
      packages/nocodb-nest/src/modules/auth/auth.service.ts
  8. 0
      packages/nocodb-nest/src/modules/auth/constants.ts
  9. 0
      packages/nocodb-nest/src/modules/projects/projects.controller.spec.ts
  10. 19
      packages/nocodb-nest/src/modules/projects/projects.controller.ts
  11. 2
      packages/nocodb-nest/src/modules/projects/projects.module.ts
  12. 0
      packages/nocodb-nest/src/modules/projects/projects.service.spec.ts
  13. 16
      packages/nocodb-nest/src/modules/projects/projects.service.ts
  14. 20
      packages/nocodb-nest/src/modules/tables/tables.controller.spec.ts
  15. 7
      packages/nocodb-nest/src/modules/tables/tables.controller.ts
  16. 9
      packages/nocodb-nest/src/modules/tables/tables.module.ts
  17. 18
      packages/nocodb-nest/src/modules/tables/tables.service.spec.ts
  18. 4
      packages/nocodb-nest/src/modules/tables/tables.service.ts
  19. 0
      packages/nocodb-nest/src/modules/users/user.spec.ts
  20. 0
      packages/nocodb-nest/src/modules/users/user.ts
  21. 0
      packages/nocodb-nest/src/modules/users/users.controller.spec.ts
  22. 15
      packages/nocodb-nest/src/modules/users/users.controller.ts
  23. 4
      packages/nocodb-nest/src/modules/users/users.module.ts
  24. 0
      packages/nocodb-nest/src/modules/users/users.service.spec.ts
  25. 2
      packages/nocodb-nest/src/modules/users/users.service.ts
  26. 0
      packages/nocodb-nest/src/modules/utils/utils.controller.spec.ts
  27. 0
      packages/nocodb-nest/src/modules/utils/utils.controller.ts
  28. 0
      packages/nocodb-nest/src/modules/utils/utils.module.ts
  29. 0
      packages/nocodb-nest/src/modules/utils/utils.service.spec.ts
  30. 10
      packages/nocodb-nest/src/modules/utils/utils.service.ts
  31. 95
      packages/nocodb-nest/src/strategies/jwt.strategy.ts
  32. 2
      packages/nocodb-nest/src/strategies/local.strategy.ts
  33. 13
      packages/nocodb-nest/src/users/users.controller.ts

24
packages/nocodb-nest/src/app.module.ts

@ -1,18 +1,26 @@
import { Module } from '@nestjs/common';
import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common'
import { Connection } from './connection/connection';
import { AuthModule } from './auth/auth.module';
import { ExtractProjectIdMiddleware } from './middlewares/extract-project-id/extract-project-id.middleware'
import { UsersModule } from './users/users.module';
import { AuthModule } from './modules/auth/auth.module';
import { ExtractProjectIdMiddleware } from './middlewares/extract-project-id/extract-project-id.middleware';
import { UsersModule } from './modules/users/users.module';
import { MetaService } from './meta/meta.service';
import { LocalStrategy } from './strategies/local.strategy';
import { UtilsModule } from './utils/utils.module';
import { ProjectsModule } from './projects/projects.module';
import { UtilsModule } from './modules/utils/utils.module';
import { ProjectsModule } from './modules/projects/projects.module';
import { JwtStrategy } from './strategies/jwt.strategy';
import { AuthGuard } from '@nestjs/passport';
import { TablesModule } from './modules/tables/tables.module';
@Module({
imports: [AuthModule, UsersModule, UtilsModule, ProjectsModule],
imports: [AuthModule, UsersModule, UtilsModule, ProjectsModule, TablesModule],
controllers: [],
providers: [Connection, MetaService, JwtStrategy, ExtractProjectIdMiddleware],
exports: [Connection, MetaService],
})
export class AppModule {}
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(ExtractProjectIdMiddleware)
.forRoutes({ path: '*', method: RequestMethod.ALL})
}
}

47
packages/nocodb-nest/src/middlewares/extract-project-id/extract-project-id.middleware.ts

@ -1,5 +1,6 @@
import {
CallHandler,
CanActivate,
ExecutionContext,
Injectable,
NestInterceptor,
@ -30,17 +31,10 @@ import catchError, { NcError } from '../catchError';
import extractProjectIdAndAuthenticate from '../extractProjectIdAndAuthenticate';
@Injectable()
export class ExtractProjectIdMiddleware implements NestInterceptor {
export class ExtractProjectIdMiddleware implements NestMiddleware, CanActivate {
constructor(private reflector: Reflector) {}
async intercept(
context: ExecutionContext,
next: CallHandler,
): Promise<Observable<any>> {
const req = context.switchToHttp().getRequest();
const res = context.switchToHttp().getResponse();
req.customProperty = 'This is a custom property';
async use(req, res, next): Promise<any> {
try {
const { params } = req;
@ -180,24 +174,26 @@ export class ExtractProjectIdMiddleware implements NestInterceptor {
// await promisify((req as any).login.bind(req))(user);
} catch (e) {
console.log(e);
return throwError(new Error('Internal error'));
// return throwError(new Error('Internal error'));
}
next();
// return next.handle().pipe(
// map((data) => {
// return data;
// }),
// );
}
return next.handle().pipe(
map((data) => {
return data;
}),
async canActivate(
context: ExecutionContext,
): Promise<boolean> {
await this.use(
context.switchToHttp().getRequest(),
context.switchToHttp().getResponse(),
() => {},
);
return true;
}
// async use(req: any, res: any, next: () => void) {
// const customValue = this.reflector.get<string>(
// 'customValue',
// req.route?.stack[0].handle,
// );
//
//
// }
}
@Injectable()
@ -279,7 +275,8 @@ export class AclMiddleware implements NestInterceptor {
}
}
export const UseProjectIdMiddleware = () => (target: any, key?: string, descriptor?: PropertyDescriptor) => {
export const UseProjectIdMiddleware =
() => (target: any, key?: string, descriptor?: PropertyDescriptor) => {
UseInterceptors(ExtractProjectIdMiddleware)(target, key, descriptor);
};
@ -301,6 +298,6 @@ export const UseAclMiddleware =
key,
descriptor,
);
UseInterceptors(ExtractProjectIdMiddleware)(target, key, descriptor);
// UseInterceptors(ExtractProjectIdMiddleware)(target, key, descriptor);
UseInterceptors(AclMiddleware)(target, key, descriptor);
};

0
packages/nocodb-nest/src/auth/auth.controller.spec.ts → packages/nocodb-nest/src/modules/auth/auth.controller.spec.ts

0
packages/nocodb-nest/src/auth/auth.controller.ts → packages/nocodb-nest/src/modules/auth/auth.controller.ts

2
packages/nocodb-nest/src/auth/auth.module.ts → packages/nocodb-nest/src/modules/auth/auth.module.ts

@ -1,5 +1,5 @@
import { Module } from '@nestjs/common';
import { LocalStrategy } from '../strategies/local.strategy';
import { LocalStrategy } from '../../strategies/local.strategy';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UsersModule } from '../users/users.module';

0
packages/nocodb-nest/src/auth/auth.service.spec.ts → packages/nocodb-nest/src/modules/auth/auth.service.spec.ts

2
packages/nocodb-nest/src/auth/auth.service.ts → packages/nocodb-nest/src/modules/auth/auth.service.ts

@ -7,7 +7,7 @@ import { JwtService } from '@nestjs/jwt';
import { CreateUserDto } from './auth.controller';
import { v4 as uuidv4 } from 'uuid';
import { Connection } from '../connection/connection';
import { Connection } from '../../connection/connection';
@Injectable()
export class AuthService {

0
packages/nocodb-nest/src/auth/constants.ts → packages/nocodb-nest/src/modules/auth/constants.ts

0
packages/nocodb-nest/src/projects/projects.controller.spec.ts → packages/nocodb-nest/src/modules/projects/projects.controller.spec.ts

19
packages/nocodb-nest/src/projects/projects.controller.ts → packages/nocodb-nest/src/modules/projects/projects.controller.ts

@ -14,22 +14,23 @@ import { AuthGuard } from '@nestjs/passport';
import isDocker from 'is-docker';
import { ProjectReqType } from 'nocodb-sdk';
import { PagedResponseImpl } from 'src/helpers/PagedResponse';
import { ProjectType } from '../../../nocodb-sdk'
import { ProjectType } from '../../../../nocodb-sdk';
import {
ExtractProjectIdMiddleware,
UseAclMiddleware,
UseProjectIdMiddleware,
} from '../middlewares/extract-project-id/extract-project-id.middleware'
import Noco from '../Noco';
import { packageVersion } from '../utils/packageVersion';
} from '../../middlewares/extract-project-id/extract-project-id.middleware';
import Noco from '../../Noco';
import { packageVersion } from '../../utils/packageVersion';
import { ProjectsService } from './projects.service';
@UseGuards(AuthGuard('jwt'))
@UseGuards(ExtractProjectIdMiddleware, AuthGuard('jwt'))
@Controller()
export class ProjectsController {
constructor(private readonly projectsService: ProjectsService) {}
@UseAclMiddleware({
permissionName: 'projectList'
permissionName: 'projectList',
})
@Get('/api/v1/db/meta/projects/')
async list(@Query() queryParams: Record<string, any>, @Request() req) {
@ -38,9 +39,9 @@ export class ProjectsController {
query: queryParams,
});
return new PagedResponseImpl(projects as ProjectType[], {
count: projects.length,
limit: projects.length,
})
count: projects.length,
limit: projects.length,
});
}
@Get('/api/v1/db/meta/projects/:projectId/info')

2
packages/nocodb-nest/src/projects/projects.module.ts → packages/nocodb-nest/src/modules/projects/projects.module.ts

@ -1,5 +1,5 @@
import { Module } from '@nestjs/common';
import { ExtractProjectIdMiddleware } from '../middlewares/extract-project-id/extract-project-id.middleware'
import { ExtractProjectIdMiddleware } from '../../middlewares/extract-project-id/extract-project-id.middleware'
import { ProjectsService } from './projects.service';
import { ProjectsController } from './projects.controller';

0
packages/nocodb-nest/src/projects/projects.service.spec.ts → packages/nocodb-nest/src/modules/projects/projects.service.spec.ts

16
packages/nocodb-nest/src/projects/projects.service.ts → packages/nocodb-nest/src/modules/projects/projects.service.ts

@ -3,15 +3,15 @@ import * as DOMPurify from 'isomorphic-dompurify';
import { customAlphabet } from 'nanoid';
import { ProjectReqType } from 'nocodb-sdk';
import { promisify } from 'util';
import { OrgUserRoles, ProjectUpdateReqType } from '../../../nocodb-sdk';
import { populateMeta, validatePayload } from '../helpers';
import { NcError } from '../helpers/catchError';
import { extractPropsAndSanitize } from '../helpers/extractProps';
import syncMigration from '../helpers/syncMigration';
import { Project, ProjectUser } from '../models';
import { OrgUserRoles, ProjectUpdateReqType } from '../../../../nocodb-sdk';
import { populateMeta, validatePayload } from '../../helpers';
import { NcError } from '../../helpers/catchError';
import { extractPropsAndSanitize } from '../../helpers/extractProps';
import syncMigration from '../../helpers/syncMigration';
import { Project, ProjectUser } from '../../models';
import { T } from 'nc-help';
import Noco from '../Noco';
import NcConfigFactory from '../utils/NcConfigFactory';
import Noco from '../../Noco';
import NcConfigFactory from '../../utils/NcConfigFactory';
const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 4);

20
packages/nocodb-nest/src/modules/tables/tables.controller.spec.ts

@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TablesController } from './tables.controller';
import { TablesService } from './tables.service';
describe('TablesController', () => {
let controller: TablesController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [TablesController],
providers: [TablesService],
}).compile();
controller = module.get<TablesController>(TablesController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

7
packages/nocodb-nest/src/modules/tables/tables.controller.ts

@ -0,0 +1,7 @@
import { Controller } from '@nestjs/common';
import { TablesService } from './tables.service';
@Controller('tables')
export class TablesController {
constructor(private readonly tablesService: TablesService) {}
}

9
packages/nocodb-nest/src/modules/tables/tables.module.ts

@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { TablesService } from './tables.service';
import { TablesController } from './tables.controller';
@Module({
controllers: [TablesController],
providers: [TablesService]
})
export class TablesModule {}

18
packages/nocodb-nest/src/modules/tables/tables.service.spec.ts

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TablesService } from './tables.service';
describe('TablesService', () => {
let service: TablesService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [TablesService],
}).compile();
service = module.get<TablesService>(TablesService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

4
packages/nocodb-nest/src/modules/tables/tables.service.ts

@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class TablesService {}

0
packages/nocodb-nest/src/users/user.spec.ts → packages/nocodb-nest/src/modules/users/user.spec.ts

0
packages/nocodb-nest/src/users/user.ts → packages/nocodb-nest/src/modules/users/user.ts

0
packages/nocodb-nest/src/users/users.controller.spec.ts → packages/nocodb-nest/src/modules/users/users.controller.spec.ts

15
packages/nocodb-nest/src/modules/users/users.controller.ts

@ -0,0 +1,15 @@
import { Controller, Get, Request, UseGuards } from '@nestjs/common'
import { AuthGuard } from '@nestjs/passport'
import { UsersService } from './users.service'
@Controller()
export class UsersController {
constructor(private readonly usersService: UsersService) {
}
@UseGuards(AuthGuard('jwt'))
@Get('/api/v1/auth/user/me')
async me(@Request() req) {
return req.user
}
}

4
packages/nocodb-nest/src/users/users.module.ts → packages/nocodb-nest/src/modules/users/users.module.ts

@ -1,6 +1,6 @@
import { Module } from '@nestjs/common';
import { Connection } from '../connection/connection'
import { MetaService } from '../meta/meta.service'
import { Connection } from '../../connection/connection'
import { MetaService } from '../../meta/meta.service'
import { UsersService } from './users.service';
import { UsersController } from './users.controller';

0
packages/nocodb-nest/src/users/users.service.spec.ts → packages/nocodb-nest/src/modules/users/users.service.spec.ts

2
packages/nocodb-nest/src/users/users.service.ts → packages/nocodb-nest/src/modules/users/users.service.ts

@ -1,5 +1,5 @@
import { Injectable } from '@nestjs/common';
import { MetaService, MetaTable } from '../meta/meta.service'
import { MetaService, MetaTable } from '../../meta/meta.service'
@Injectable()
export class UsersService {

0
packages/nocodb-nest/src/utils/utils.controller.spec.ts → packages/nocodb-nest/src/modules/utils/utils.controller.spec.ts

0
packages/nocodb-nest/src/utils/utils.controller.ts → packages/nocodb-nest/src/modules/utils/utils.controller.ts

0
packages/nocodb-nest/src/utils/utils.module.ts → packages/nocodb-nest/src/modules/utils/utils.module.ts

0
packages/nocodb-nest/src/utils/utils.service.spec.ts → packages/nocodb-nest/src/modules/utils/utils.service.spec.ts

10
packages/nocodb-nest/src/utils/utils.service.ts → packages/nocodb-nest/src/modules/utils/utils.service.ts

@ -1,11 +1,11 @@
import { Injectable } from '@nestjs/common';
import axios from 'axios';
import { compareVersions, validate } from 'compare-versions';
import { NC_ATTACHMENT_FIELD_SIZE } from '../constants';
import { NcError } from '../helpers/catchError'
import { User } from '../models'
import NcConfigFactory from './NcConfigFactory';
import { packageVersion } from './packageVersion';
import { NC_ATTACHMENT_FIELD_SIZE } from '../../constants';
import { NcError } from '../../helpers/catchError';
import { User } from '../../models';
import NcConfigFactory from '../../utils/NcConfigFactory';
import { packageVersion } from '../../utils/packageVersion';
// import { packageVersion } from '../packageVersion';
const versionCache = {

95
packages/nocodb-nest/src/strategies/jwt.strategy.ts

@ -1,8 +1,15 @@
import { Injectable, UnauthorizedException } from '@nestjs/common'
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from 'passport-jwt';
import { jwtConstants } from '../auth/constants'
import { UsersService } from '../users/users.service'
import { OrgUserRoles } from '../../../nocodb-sdk';
import NocoCache from '../cache/NocoCache';
import { ProjectUser, User } from '../models';
import {
CacheGetType,
CacheScope,
} from '../utils/globals';
import { jwtConstants } from '../modules/auth/constants';
import { UsersService } from '../modules/users/users.service';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
@ -11,15 +18,83 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
// ignoreExpiration: false,
jwtFromRequest: ExtractJwt.fromHeader('xc-auth'),
secretOrKey: jwtConstants.secret,
expiresIn: '10h'
})
expiresIn: '10h',
passReqToCallback: true,
});
}
async validate(payload: any) {
const user = await this.userService.findOne(payload?.email);
if (!user) {
throw new UnauthorizedException();
async validate(req:any,jwtPayload: any,) {
// todo: improve this
if (
req.ncProjectId &&
jwtPayload.roles?.split(',').includes(OrgUserRoles.SUPER_ADMIN)
) {
return User.getByEmail(jwtPayload?.email).then(async (user) => {
return {
...user,
roles: `owner,creator,${OrgUserRoles.SUPER_ADMIN}`,
};
});
}
const keyVals = [jwtPayload?.email];
if (req.ncProjectId) {
keyVals.push(req.ncProjectId);
}
const key = keyVals.join('___');
const cachedVal = await NocoCache.get(
`${CacheScope.USER}:${key}`,
CacheGetType.TYPE_OBJECT,
);
if (cachedVal) {
/*todo: tobe fixed
if (
!cachedVal.token_version ||
!jwtPayload.token_version ||
cachedVal.token_version !== jwtPayload.token_version
) {
throw new Error('Token Expired. Please login again.');
}*/
return cachedVal;
}
return user;
return User.getByEmail(jwtPayload?.email).then(async (user: User) => {
/*
todo: tobe fixed
if (
// !user.token_version ||
// !jwtPayload.token_version ||
user.token_version !== jwtPayload.token_version
) {
throw new Er ror('Token Expired. Please login again.');
}*/
if (req.ncProjectId) {
// this.xcMeta
// .metaGet(req.ncProjectId, null, 'nc_projects_users', {
// user_id: user?.id
// })
return ProjectUser.get(req.ncProjectId, user.id).then(
async (projectUser) => {
user.roles = projectUser?.roles || user.roles;
user.roles = user.roles === 'owner' ? 'owner,creator' : user.roles;
// + (user.roles ? `,${user.roles}` : '');
await NocoCache.set(`${CacheScope.USER}:${key}`, user);
return user;
},
);
} else {
// const roles = projectUser?.roles ? JSON.parse(projectUser.roles) : {guest: true};
if (user) {
await NocoCache.set(`${CacheScope.USER}:${key}`, user);
return user;
} else {
throw new Error('User not found');
}
}
});
}
}

2
packages/nocodb-nest/src/strategies/local.strategy.ts

@ -1,7 +1,7 @@
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from '../auth/auth.service';
import { AuthService } from '../modules/auth/auth.service';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {

13
packages/nocodb-nest/src/users/users.controller.ts

@ -1,13 +0,0 @@
import { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller()
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get('/api/v1/auth/user/me')
async me() {
// return this.usersService.me();
}
}
Loading…
Cancel
Save