Browse Source

fix(nocohub): Moved auth related api from user controller to auth controller

pull/6376/head
Muhammed Mustafa 1 year ago
parent
commit
22b9d0efe3
  1. 2
      packages/nocodb/src/app.module.ts
  2. 2
      packages/nocodb/src/controllers/auth.controller.spec.ts
  3. 46
      packages/nocodb/src/controllers/auth.controller.ts
  4. 266
      packages/nocodb/src/controllers/auth/auth.controller.ts
  5. 0
      packages/nocodb/src/controllers/auth/ui/auth/emailVerify.ts
  6. 0
      packages/nocodb/src/controllers/auth/ui/auth/resetPassword.ts
  7. 0
      packages/nocodb/src/controllers/auth/ui/emailTemplates/forgotPassword.ts
  8. 0
      packages/nocodb/src/controllers/auth/ui/emailTemplates/invite.ts
  9. 0
      packages/nocodb/src/controllers/auth/ui/emailTemplates/verify.ts
  10. 236
      packages/nocodb/src/controllers/users/users.controller.ts
  11. 21
      packages/nocodb/src/modules/auth/auth.module.ts
  12. 3
      packages/nocodb/src/modules/users/users.module.ts
  13. 2
      packages/nocodb/src/services/auth.service.ts
  14. 4
      packages/nocodb/src/services/users/users.service.ts

2
packages/nocodb/src/app.module.ts

@ -24,11 +24,13 @@ import { ExtractIdsMiddleware } from '~/middlewares/extract-ids/extract-ids.midd
import { HookHandlerService } from '~/services/hook-handler.service'; import { HookHandlerService } from '~/services/hook-handler.service';
import { BasicStrategy } from '~/strategies/basic.strategy/basic.strategy'; import { BasicStrategy } from '~/strategies/basic.strategy/basic.strategy';
import { UsersModule } from '~/modules/users/users.module'; import { UsersModule } from '~/modules/users/users.module';
import { AuthModule } from '~/modules/auth/auth.module';
export const ceModuleConfig = { export const ceModuleConfig = {
imports: [ imports: [
GlobalModule, GlobalModule,
UsersModule, UsersModule,
AuthModule,
...(process.env['PLAYWRIGHT_TEST'] === 'true' ? [TestModule] : []), ...(process.env['PLAYWRIGHT_TEST'] === 'true' ? [TestModule] : []),
MetasModule, MetasModule,
DatasModule, DatasModule,

2
packages/nocodb/src/controllers/auth.controller.spec.ts

@ -1,6 +1,6 @@
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { AuthService } from '../services/auth.service'; import { AuthService } from '../services/auth.service';
import { AuthController } from './auth.controller'; import { AuthController } from './auth/auth.controller';
import type { TestingModule } from '@nestjs/testing'; import type { TestingModule } from '@nestjs/testing';
describe('AuthController', () => { describe('AuthController', () => {

46
packages/nocodb/src/controllers/auth.controller.ts

@ -1,46 +0,0 @@
import {
Body,
Controller,
HttpCode,
Post,
Request,
UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ConfigService } from '@nestjs/config';
import type { AppConfig } from '~/interface/config';
import { AuthService } from '~/services/auth.service';
import { NcError } from '~/helpers/catchError';
export class CreateUserDto {
readonly username: string;
readonly email: string;
readonly password: string;
}
@Controller()
export class AuthController {
constructor(
private readonly authService: AuthService,
private readonly config: ConfigService<AppConfig>,
) {}
@UseGuards(AuthGuard('local'))
@Post('/api/v1/auth/user/signin')
@HttpCode(200)
async signin(@Request() req) {
if (this.config.get('auth', { infer: true }).disableEmailAuth) {
NcError.forbidden('Email authentication is disabled');
}
return await this.authService.login(req.user);
}
@Post('/api/v1/auth/user/signup')
@HttpCode(200)
async signup(@Body() createUserDto: CreateUserDto) {
if (this.config.get('auth', { infer: true }).disableEmailAuth) {
NcError.forbidden('Email authentication is disabled');
}
return await this.authService.signup(createUserDto);
}
}

266
packages/nocodb/src/controllers/auth/auth.controller.ts

@ -0,0 +1,266 @@
import {
Body,
Controller,
Get,
HttpCode,
Param,
Post,
Request,
Response,
UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ConfigService } from '@nestjs/config';
import { extractRolesObj } from 'nocodb-sdk';
import * as ejs from 'ejs';
import type { AppConfig } from '~/interface/config';
import { UsersService } from '~/services/users/users.service';
import { AppHooksService } from '~/services/app-hooks/app-hooks.service';
import { randomTokenString, setTokenCookie } from '~/services/users/helpers';
import { GlobalGuard } from '~/guards/global/global.guard';
import { NcError } from '~/helpers/catchError';
import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware';
import { User } from '~/models';
export class CreateUserDto {
readonly username: string;
readonly email: string;
readonly password: string;
}
@Controller()
export class AuthController {
constructor(
protected readonly usersService: UsersService,
protected readonly appHooksService: AppHooksService,
protected readonly config: ConfigService<AppConfig>,
) {}
@Post([
'/auth/user/signup',
'/api/v1/db/auth/user/signup',
'/api/v1/auth/user/signup',
])
@HttpCode(200)
async signup(@Request() req: any, @Response() res: any): Promise<any> {
if (this.config.get('auth', { infer: true }).disableEmailAuth) {
NcError.forbidden('Email authentication is disabled');
}
res.json(
await this.usersService.signup({
body: req.body,
req,
res,
}),
);
}
@Post([
'/auth/token/refresh',
'/api/v1/db/auth/token/refresh',
'/api/v1/auth/token/refresh',
])
@HttpCode(200)
async refreshToken(@Request() req: any, @Response() res: any): Promise<any> {
res.json(
await this.usersService.refreshToken({
body: req.body,
req,
res,
}),
);
}
@Post([
'/auth/user/signin',
'/api/v1/db/auth/user/signin',
'/api/v1/auth/user/signin',
])
@UseGuards(AuthGuard('local'))
@HttpCode(200)
async signin(@Request() req, @Response() res) {
if (this.config.get('auth', { infer: true }).disableEmailAuth) {
NcError.forbidden('Email authentication is disabled');
}
await this.setRefreshToken({ req, res });
res.json(await this.usersService.login(req.user));
}
@UseGuards(GlobalGuard)
@Post('/api/v1/auth/user/signout')
@HttpCode(200)
async signOut(@Request() req, @Response() res): Promise<any> {
if (!(req as any).isAuthenticated()) {
NcError.forbidden('Not allowed');
}
res.json(
await this.usersService.signOut({
req,
res,
}),
);
}
@Post(`/auth/google/genTokenByCode`)
@HttpCode(200)
@UseGuards(AuthGuard('google'))
async googleSignin(@Request() req, @Response() res) {
await this.setRefreshToken({ req, res });
res.json(await this.usersService.login(req.user));
}
@Get('/auth/google')
@UseGuards(AuthGuard('google'))
googleAuthenticate() {
// google strategy will take care the request
}
@Get(['/auth/user/me', '/api/v1/db/auth/user/me', '/api/v1/auth/user/me'])
@UseGuards(GlobalGuard)
async me(@Request() req) {
const user = {
...req.user,
roles: extractRolesObj(req.user.roles),
workspace_roles: extractRolesObj(req.user.workspace_roles),
project_roles: extractRolesObj(req.user.project_roles),
};
return user;
}
@Post([
'/user/password/change',
'/api/v1/db/auth/password/change',
'/api/v1/auth/password/change',
])
@UseGuards(GlobalGuard)
@Acl('passwordChange', {
scope: 'org',
})
@HttpCode(200)
async passwordChange(@Request() req: any): Promise<any> {
if (!(req as any).isAuthenticated()) {
NcError.forbidden('Not allowed');
}
await this.usersService.passwordChange({
user: req['user'],
req,
body: req.body,
});
return { msg: 'Password has been updated successfully' };
}
@Post([
'/auth/password/forgot',
'/api/v1/db/auth/password/forgot',
'/api/v1/auth/password/forgot',
])
@HttpCode(200)
async passwordForgot(@Request() req: any): Promise<any> {
await this.usersService.passwordForgot({
siteUrl: (req as any).ncSiteUrl,
body: req.body,
req,
});
return { msg: 'Please check your email to reset the password' };
}
@Post([
'/auth/token/validate/:tokenId',
'/api/v1/db/auth/token/validate/:tokenId',
'/api/v1/auth/token/validate/:tokenId',
])
@HttpCode(200)
async tokenValidate(@Param('tokenId') tokenId: string): Promise<any> {
await this.usersService.tokenValidate({
token: tokenId,
});
return { msg: 'Token has been validated successfully' };
}
@Post([
'/auth/password/reset/:tokenId',
'/api/v1/db/auth/password/reset/:tokenId',
'/api/v1/auth/password/reset/:tokenId',
])
@HttpCode(200)
async passwordReset(
@Request() req: any,
@Param('tokenId') tokenId: string,
@Body() body: any,
): Promise<any> {
await this.usersService.passwordReset({
token: tokenId,
body: body,
req,
});
return { msg: 'Password has been reset successfully' };
}
@Post([
'/api/v1/db/auth/email/validate/:tokenId',
'/api/v1/auth/email/validate/:tokenId',
])
@HttpCode(200)
async emailVerification(
@Request() req: any,
@Param('tokenId') tokenId: string,
): Promise<any> {
await this.usersService.emailVerification({
token: tokenId,
req,
});
return { msg: 'Email has been verified successfully' };
}
@Get([
'/api/v1/db/auth/password/reset/:tokenId',
'/auth/password/reset/:tokenId',
])
async renderPasswordReset(
@Request() req: any,
@Response() res: any,
@Param('tokenId') tokenId: string,
): Promise<any> {
try {
res.send(
ejs.render((await import('./ui/auth/resetPassword')).default, {
ncPublicUrl: process.env.NC_PUBLIC_URL || '',
token: JSON.stringify(tokenId),
baseUrl: `/`,
}),
);
} catch (e) {
return res.status(400).json({ msg: e.message });
}
}
async setRefreshToken({ res, req }) {
const userId = req.user?.id;
if (!userId) return;
const user = await User.get(userId);
if (!user) return;
const refreshToken = randomTokenString();
if (!user['token_version']) {
user['token_version'] = randomTokenString();
}
await User.update(user.id, {
refresh_token: refreshToken,
email: user.email,
token_version: user['token_version'],
});
setTokenCookie(res, refreshToken);
}
}

0
packages/nocodb/src/controllers/users/ui/auth/emailVerify.ts → packages/nocodb/src/controllers/auth/ui/auth/emailVerify.ts

0
packages/nocodb/src/controllers/users/ui/auth/resetPassword.ts → packages/nocodb/src/controllers/auth/ui/auth/resetPassword.ts

0
packages/nocodb/src/controllers/users/ui/emailTemplates/forgotPassword.ts → packages/nocodb/src/controllers/auth/ui/emailTemplates/forgotPassword.ts

0
packages/nocodb/src/controllers/users/ui/emailTemplates/invite.ts → packages/nocodb/src/controllers/auth/ui/emailTemplates/invite.ts

0
packages/nocodb/src/controllers/users/ui/emailTemplates/verify.ts → packages/nocodb/src/controllers/auth/ui/emailTemplates/verify.ts

236
packages/nocodb/src/controllers/users/users.controller.ts

@ -9,17 +9,11 @@ import {
Response, Response,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import * as ejs from 'ejs';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { extractRolesObj } from 'nocodb-sdk';
import type { AppConfig } from '~/interface/config'; import type { AppConfig } from '~/interface/config';
import { GlobalGuard } from '~/guards/global/global.guard';
import { NcError } from '~/helpers/catchError';
import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware';
import { User } from '~/models';
import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service';
import { randomTokenString, setTokenCookie } from '~/services/users/helpers';
import { UsersService } from '~/services/users/users.service'; import { UsersService } from '~/services/users/users.service';
@Controller() @Controller()
@ -29,230 +23,4 @@ export class UsersController {
protected readonly appHooksService: AppHooksService, protected readonly appHooksService: AppHooksService,
protected readonly config: ConfigService<AppConfig>, protected readonly config: ConfigService<AppConfig>,
) {} ) {}
@Post([
'/auth/user/signup',
'/api/v1/db/auth/user/signup',
'/api/v1/auth/user/signup',
])
@HttpCode(200)
async signup(@Request() req: any, @Response() res: any): Promise<any> {
if (this.config.get('auth', { infer: true }).disableEmailAuth) {
NcError.forbidden('Email authentication is disabled');
}
res.json(
await this.usersService.signup({
body: req.body,
req,
res,
}),
);
}
@Post([
'/auth/token/refresh',
'/api/v1/db/auth/token/refresh',
'/api/v1/auth/token/refresh',
])
@HttpCode(200)
async refreshToken(@Request() req: any, @Response() res: any): Promise<any> {
res.json(
await this.usersService.refreshToken({
body: req.body,
req,
res,
}),
);
}
@Post([
'/auth/user/signin',
'/api/v1/db/auth/user/signin',
'/api/v1/auth/user/signin',
])
@UseGuards(AuthGuard('local'))
@HttpCode(200)
async signin(@Request() req, @Response() res) {
if (this.config.get('auth', { infer: true }).disableEmailAuth) {
NcError.forbidden('Email authentication is disabled');
}
await this.setRefreshToken({ req, res });
res.json(await this.usersService.login(req.user));
}
@UseGuards(GlobalGuard)
@Post('/api/v1/auth/user/signout')
@HttpCode(200)
async signOut(@Request() req, @Response() res): Promise<any> {
if (!(req as any).isAuthenticated()) {
NcError.forbidden('Not allowed');
}
res.json(
await this.usersService.signOut({
req,
res,
}),
);
}
@Post(`/auth/google/genTokenByCode`)
@HttpCode(200)
@UseGuards(AuthGuard('google'))
async googleSignin(@Request() req, @Response() res) {
await this.setRefreshToken({ req, res });
res.json(await this.usersService.login(req.user));
}
@Get('/auth/google')
@UseGuards(AuthGuard('google'))
googleAuthenticate() {
// google strategy will take care the request
}
@Get(['/auth/user/me', '/api/v1/db/auth/user/me', '/api/v1/auth/user/me'])
@UseGuards(GlobalGuard)
async me(@Request() req) {
const user = {
...req.user,
roles: extractRolesObj(req.user.roles),
workspace_roles: extractRolesObj(req.user.workspace_roles),
project_roles: extractRolesObj(req.user.project_roles),
};
return user;
}
@Post([
'/user/password/change',
'/api/v1/db/auth/password/change',
'/api/v1/auth/password/change',
])
@UseGuards(GlobalGuard)
@Acl('passwordChange', {
scope: 'org',
})
@HttpCode(200)
async passwordChange(@Request() req: any): Promise<any> {
if (!(req as any).isAuthenticated()) {
NcError.forbidden('Not allowed');
}
await this.usersService.passwordChange({
user: req['user'],
req,
body: req.body,
});
return { msg: 'Password has been updated successfully' };
}
@Post([
'/auth/password/forgot',
'/api/v1/db/auth/password/forgot',
'/api/v1/auth/password/forgot',
])
@HttpCode(200)
async passwordForgot(@Request() req: any): Promise<any> {
await this.usersService.passwordForgot({
siteUrl: (req as any).ncSiteUrl,
body: req.body,
req,
});
return { msg: 'Please check your email to reset the password' };
}
@Post([
'/auth/token/validate/:tokenId',
'/api/v1/db/auth/token/validate/:tokenId',
'/api/v1/auth/token/validate/:tokenId',
])
@HttpCode(200)
async tokenValidate(@Param('tokenId') tokenId: string): Promise<any> {
await this.usersService.tokenValidate({
token: tokenId,
});
return { msg: 'Token has been validated successfully' };
}
@Post([
'/auth/password/reset/:tokenId',
'/api/v1/db/auth/password/reset/:tokenId',
'/api/v1/auth/password/reset/:tokenId',
])
@HttpCode(200)
async passwordReset(
@Request() req: any,
@Param('tokenId') tokenId: string,
@Body() body: any,
): Promise<any> {
await this.usersService.passwordReset({
token: tokenId,
body: body,
req,
});
return { msg: 'Password has been reset successfully' };
}
@Post([
'/api/v1/db/auth/email/validate/:tokenId',
'/api/v1/auth/email/validate/:tokenId',
])
@HttpCode(200)
async emailVerification(
@Request() req: any,
@Param('tokenId') tokenId: string,
): Promise<any> {
await this.usersService.emailVerification({
token: tokenId,
req,
});
return { msg: 'Email has been verified successfully' };
}
@Get([
'/api/v1/db/auth/password/reset/:tokenId',
'/auth/password/reset/:tokenId',
])
async renderPasswordReset(
@Request() req: any,
@Response() res: any,
@Param('tokenId') tokenId: string,
): Promise<any> {
try {
res.send(
ejs.render((await import('./ui/auth/resetPassword')).default, {
ncPublicUrl: process.env.NC_PUBLIC_URL || '',
token: JSON.stringify(tokenId),
baseUrl: `/`,
}),
);
} catch (e) {
return res.status(400).json({ msg: e.message });
}
}
async setRefreshToken({ res, req }) {
const userId = req.user?.id;
if (!userId) return;
const user = await User.get(userId);
if (!user) return;
const refreshToken = randomTokenString();
if (!user['token_version']) {
user['token_version'] = randomTokenString();
}
await User.update(user.id, {
refresh_token: refreshToken,
email: user.email,
token_version: user['token_version'],
});
setTokenCookie(res, refreshToken);
}
} }

21
packages/nocodb/src/modules/auth/auth.module.ts

@ -0,0 +1,21 @@
import { forwardRef, Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { GoogleStrategyProvider } from '~/strategies/google.strategy/google.strategy';
import { GlobalModule } from '~/modules/global/global.module';
import { UsersService } from '~/services/users/users.service';
import { AuthController } from '~/controllers/auth/auth.controller';
import { MetasModule } from '~/modules/metas/metas.module';
@Module({
imports: [
forwardRef(() => GlobalModule),
PassportModule,
forwardRef(() => MetasModule),
],
controllers: [
...(process.env.NC_WORKER_CONTAINER !== 'true' ? [AuthController] : []),
],
providers: [UsersService, GoogleStrategyProvider],
exports: [UsersService],
})
export class AuthModule {}

3
packages/nocodb/src/modules/users/users.module.ts

@ -1,6 +1,5 @@
import { forwardRef, Module } from '@nestjs/common'; import { forwardRef, Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { GoogleStrategyProvider } from '~/strategies/google.strategy/google.strategy';
import { GlobalModule } from '~/modules/global/global.module'; import { GlobalModule } from '~/modules/global/global.module';
import { UsersService } from '~/services/users/users.service'; import { UsersService } from '~/services/users/users.service';
import { UsersController } from '~/controllers/users/users.controller'; import { UsersController } from '~/controllers/users/users.controller';
@ -15,7 +14,7 @@ import { MetasModule } from '~/modules/metas/metas.module';
controllers: [ controllers: [
...(process.env.NC_WORKER_CONTAINER !== 'true' ? [UsersController] : []), ...(process.env.NC_WORKER_CONTAINER !== 'true' ? [UsersController] : []),
], ],
providers: [UsersService, GoogleStrategyProvider], providers: [UsersService],
exports: [UsersService], exports: [UsersService],
}) })
export class UsersModule {} export class UsersModule {}

2
packages/nocodb/src/services/auth.service.ts

@ -4,7 +4,7 @@ import { Injectable } from '@nestjs/common';
import * as bcrypt from 'bcryptjs'; import * as bcrypt from 'bcryptjs';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import type { CreateUserDto } from '~/controllers/auth.controller'; import type { CreateUserDto } from 'src/controllers/auth/auth.controller';
import Noco from '~/Noco'; import Noco from '~/Noco';
import { genJwt } from '~/services/users/helpers'; import { genJwt } from '~/services/users/helpers';
import { UsersService } from '~/services/users/users.service'; import { UsersService } from '~/services/users/users.service';

4
packages/nocodb/src/services/users/users.service.ts

@ -209,7 +209,7 @@ export class UsersService {
}); });
try { try {
const template = ( const template = (
await import('~/controllers/users/ui/emailTemplates/forgotPassword') await import('~/controllers/auth/ui/emailTemplates/forgotPassword')
).default; ).default;
await NcPluginMgrv2.emailAdapter().then((adapter) => await NcPluginMgrv2.emailAdapter().then((adapter) =>
adapter.mailSend({ adapter.mailSend({
@ -451,7 +451,7 @@ export class UsersService {
try { try {
const template = ( const template = (
await import('~/controllers/users/ui/emailTemplates/verify') await import('~/controllers/auth/ui/emailTemplates/verify')
).default; ).default;
await ( await (
await NcPluginMgrv2.emailAdapter() await NcPluginMgrv2.emailAdapter()

Loading…
Cancel
Save