diff --git a/src/api/api.controller.ts b/src/api/api.controller.ts index 4773816..11d2fba 100644 --- a/src/api/api.controller.ts +++ b/src/api/api.controller.ts @@ -17,6 +17,8 @@ import { SignupResponse, UserRegistration, UsersResponse, + ResponseCode, + ResponseStatus } from './api.interface'; import { ApiService } from './api.service'; import { ConfigResolverService } from './config.resolver.service'; @@ -27,10 +29,12 @@ import { RefreshRequest } from '@fusionauth/typescript-client/build/src/FusionAu import { ChangePasswordDTO } from './dto/changePassword.dto'; import { SentryInterceptor } from '../interceptors/sentry.interceptor'; import * as Sentry from '@sentry/node'; -import { LoginDto } from './dto/login.dto'; +import { LoginDto, LoginWithUniqueIdDto } from './dto/login.dto'; import { SendOtpDto } from './dto/send-otp.dto'; import { VerifyOtpDto } from './dto/verify-otp.dto'; import { Throttle, SkipThrottle} from '@nestjs/throttler'; +import { ConfigService } from '@nestjs/config'; +import { v4 as uuidv4 } from 'uuid'; // eslint-disable-next-line @typescript-eslint/no-var-requires const CryptoJS = require('crypto-js'); @@ -40,6 +44,7 @@ CryptoJS.lib.WordArray.words; @UseInterceptors(SentryInterceptor) export class ApiController { constructor( + private configService: ConfigService, private readonly fusionAuthService: FusionauthService, private readonly otpService: OtpService, private readonly apiService: ApiService, @@ -358,4 +363,22 @@ export class ApiController { ): Promise { return await this.apiService.loginWithOtp(user, authHeader); } + + @Post('login-with-unique-id') + @UsePipes(new ValidationPipe({ transform: true })) + async loginWithUniqueId( + @Body() user: LoginWithUniqueIdDto, + @Headers('authorization') authHeader, + @Headers('ADMIN-API-KEY') adminApiKey + ): Promise { + if(adminApiKey!=this.configService.get('ADMIN_API_KEY')){ + const response: SignupResponse = new SignupResponse().init(uuidv4()); + response.responseCode = ResponseCode.FAILURE; + response.params.err = 'UNAUTHORIZED'; + response.params.errMsg = 'Invalid admin api key'; + response.params.status = ResponseStatus.failure; + return response; + } + return await this.apiService.loginWithUniqueId(user, authHeader); + } } diff --git a/src/api/api.service.ts b/src/api/api.service.ts index c4fbdac..7ae5ba0 100644 --- a/src/api/api.service.ts +++ b/src/api/api.service.ts @@ -30,6 +30,7 @@ const CryptoJS = require('crypto-js'); // eslint-disable-next-line @typescript-eslint/no-var-requires const AES = require('crypto-js/aes'); import Flagsmith from 'flagsmith-nodejs'; +import { LoginWithUniqueIdDto } from './dto/login.dto'; CryptoJS.lib.WordArray.words; @@ -637,6 +638,56 @@ export class ApiService { } } + async loginWithUniqueId(loginDto: LoginWithUniqueIdDto, authHeader: null | string): Promise { + /* Execution flow + 1. Check if user exists for the given applicationId and loginId. + 3.1. If existing user, login user with default password. + 3.2. If new user, register to this application. + 4. Send login response with the token + */ + const salt = this.configResolverService.getSalt(loginDto.applicationId); + let password = salt + this.configService.get("DEFAULT_USER_PASSWORD"); // mix OTP with salt + console.log(password) + + const { + statusFA + }: { statusFA: FAStatus} = + await this.fusionAuthService.getUser( + loginDto.loginId, + loginDto.applicationId, + authHeader, + ); + if (statusFA === FAStatus.USER_EXISTS) { + return this.login({...loginDto,password}, authHeader); + } else { + // create a new user + const createUserPayload: UserRegistration = { + user: { + timezone: "Asia/Kolkata", + username: loginDto.loginId, + password: password + }, + registration: { + applicationId: loginDto.applicationId, + preferredLanguages: [ + "en" + ], + roles: [], + } + } + const { userId, user, err }: { userId: UUID; user: User; err: Error } = + await this.fusionAuthService.createAndRegisterUser( + createUserPayload, + loginDto.applicationId, + authHeader, + ); + if (userId == null || user == null) { + throw new HttpException(err, HttpStatus.BAD_REQUEST); + } + return this.login({...loginDto,password}, authHeader); + } + } + async updateUserRegistration( applicationId: UUID, authHeader: null | string, diff --git a/src/api/dto/login.dto.ts b/src/api/dto/login.dto.ts index ea279ef..348b9b9 100644 --- a/src/api/dto/login.dto.ts +++ b/src/api/dto/login.dto.ts @@ -17,3 +17,15 @@ export class LoginDto { @IsNotEmpty() applicationId: string; } + + +export class LoginWithUniqueIdDto { + @IsString() + @IsNotEmpty() + @MaxLength(80) + loginId: string; + + @IsUUID() + @IsNotEmpty() + applicationId: string; +}