Skip to content

Commit

Permalink
Sentry integration done in api module (#81)
Browse files Browse the repository at this point in the history
* Sentry integration done in `api` module

* Dockerfile: bumped node version to 16

* Logging user details in Sentry events

* ApiService: fixed redundant double encryption bug in login API
  • Loading branch information
choxx authored Jul 17, 2023
1 parent b9ce44c commit 5623bf0
Show file tree
Hide file tree
Showing 11 changed files with 404 additions and 27 deletions.
5 changes: 4 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ FLAGSMITH_ENVIRONMENT_KEY=
#Testing
ALLOW_DEFAULT_OTP="false"
DEFAULT_OTP="1234"
DEFAULT_OTP_USERS=["9999999999"] # JSON array of mobile numbers
DEFAULT_OTP_USERS=["9999999999"] # JSON array of mobile numbers

# Sentry
SENTRY_DSN=
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:12 AS builder
FROM node:16 AS builder

# Create app directory
WORKDIR /app
Expand All @@ -17,7 +17,7 @@ COPY . .

RUN yarn run build

FROM node:12
FROM node:16

COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
"@nestjs/terminus": "9.2.1",
"@nestjs/throttler": "^2.0.1",
"@prisma/client": "2.28.0",
"@sentry/minimal": "^6.19.7",
"@sentry/node": "^7.57.0",
"ajv": "^8.12.0",
"crypto-js": "^4.1.1",
"flagsmith-nodejs": "^2.5.2",
Expand Down
4 changes: 3 additions & 1 deletion src/api/api.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Param,
Patch,
Post,
Query, UnprocessableEntityException,
Query, UnprocessableEntityException, UseInterceptors,
} from '@nestjs/common';
import {
SignupResponse,
Expand All @@ -22,12 +22,14 @@ import { SMSResponse } from './sms/sms.interface';
import { RefreshRequest } from '@fusionauth/typescript-client/build/src/FusionAuthClient';
import { ChangePasswordDTO } from '../user/dto/changePassword.dto';
import { LoginDto } from '../user/dto/login.dto';
import { SentryInterceptor } from '../interceptors/sentry.interceptor';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const CryptoJS = require('crypto-js');

CryptoJS.lib.WordArray.words;

@Controller('api')
@UseInterceptors(SentryInterceptor)
export class ApiController {
constructor(
private readonly fusionAuthService: FusionauthService,
Expand Down
16 changes: 1 addition & 15 deletions src/api/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,6 @@ export class ApiService {
) {}

login(user: any, authHeader: string): Promise<SignupResponse> {
const encStatus = this.configResolverService.getEncryptionStatus(
user.applicationId,
);
if (encStatus) {
this.encodedBase64Key = this.configResolverService.getEncryptionKey(
user.applicationId,
);
this.parsedBase64Key =
this.encodedBase64Key === undefined
? CryptoJS.enc.Base64.parse('bla')
: CryptoJS.enc.Base64.parse(this.encodedBase64Key);
user.loginId = this.encrypt(user.loginId, this.parsedBase64Key);
user.password = this.encrypt(user.password, this.parsedBase64Key);
}
return this.fusionAuthService
.login(user, authHeader)
.then(async (resp: ClientResponse<LoginResponse>) => {
Expand Down Expand Up @@ -121,7 +107,7 @@ export class ApiService {
return response;
})
.catch((errorResponse: ClientResponse<LoginResponse>): SignupResponse => {
console.log(errorResponse);
// console.log(errorResponse);
const response: SignupResponse = new SignupResponse().init(uuidv4());
if (errorResponse.statusCode === 404) {
response.responseCode = ResponseCode.FAILURE;
Expand Down
75 changes: 72 additions & 3 deletions src/api/fusionauth/fusionauth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ConfigResolverService } from '../config.resolver.service';
import { RefreshRequest } from '@fusionauth/typescript-client/build/src/FusionAuthClient';
import { RefreshTokenResult } from '../api.interface';
import { FusionAuthUserRegistration } from '../../admin/admin.interface';
import * as Sentry from '@sentry/node';

export enum FAStatus {
SUCCESS = 'SUCCESS',
Expand Down Expand Up @@ -86,6 +87,12 @@ export class FusionauthService {
},
)
.catch((e): { statusFA: FAStatus; userId: UUID; user: User } => {
Sentry.captureException(e, {
user: {
username: username,
applicationId: applicationId,
}
});
console.log(
`Could not fetch user with username ${username}`,
JSON.stringify(e),
Expand Down Expand Up @@ -138,6 +145,11 @@ export class FusionauthService {
},
)
.catch((e): { total: number; users: Array<User> } => {
Sentry.captureException(e, {
user: {
applicationId: applicationId
}
});
console.log(
`Could not fetch users for applicationId ${applicationId}`,
JSON.stringify(e),
Expand Down Expand Up @@ -193,6 +205,11 @@ export class FusionauthService {
},
)
.catch((e): { total: number; users: Array<User> } => {
Sentry.captureException(e, {
user: {
applicationId: applicationId
}
});
console.log(`Could not fetch users`, JSON.stringify(e));
return {
total: 0,
Expand All @@ -205,13 +222,10 @@ export class FusionauthService {
user: LoginRequest,
authHeader: string,
): Promise<ClientResponse<LoginResponse>> {
console.log(user);
let apiKey = this.configResolverService.getApiKey(user.applicationId);
console.log('here', apiKey);
if (authHeader != null) {
apiKey = authHeader;
}
console.log({ apiKey });
const host = this.configResolverService.getHost(user.applicationId);
const fusionauthClient = this.getClient(apiKey, host);
return fusionauthClient
Expand Down Expand Up @@ -250,6 +264,12 @@ export class FusionauthService {
},
)
.catch((e): { userId: UUID; user: User; err: Error } => {
Sentry.captureException(e, {
user: {
applicationId: applicationId,
user: user
}
});
console.log(`Could not create user ${user}`, JSON.stringify(e));
return {
userId: null,
Expand Down Expand Up @@ -286,6 +306,13 @@ export class FusionauthService {
},
)
.catch((e): { _userId: UUID; user: User; err: Error } => {
Sentry.captureException(e, {
user: {
id: userId,
applicationId: applicationId,
user: user
}
});
console.log(`Could not update user ${user.user.id}`, JSON.stringify(e));
return {
_userId: null,
Expand Down Expand Up @@ -361,6 +388,11 @@ export class FusionauthService {
};
})
.catch((e): RefreshTokenResult => {
Sentry.captureException(e, {
user: {
applicationId: applicationId
}
});
console.log(`Could not update token`, JSON.stringify(e));
return {
user: {
Expand Down Expand Up @@ -398,6 +430,12 @@ export class FusionauthService {
},
)
.catch((e): { statusFA: FAStatus; userId: UUID; user: User } => {
Sentry.captureException(e, {
user: {
id: userId,
applicationId: applicationId
}
});
this.logger.error(
`Could not fetch user with user id ${userId}`,
JSON.stringify(e),
Expand Down Expand Up @@ -432,6 +470,12 @@ export class FusionauthService {
},
)
.catch((e): { userId: UUID; err: Error } => {
Sentry.captureException(e, {
user: {
id: userId,
applicationId: applicationId
}
});
this.logger.error(
`Could not update user ${userId}`,
JSON.stringify(e),
Expand All @@ -449,6 +493,12 @@ export class FusionauthService {
return { userId: userId, err: null };
})
.catch((e): { userId: UUID; err: Error } => {
Sentry.captureException(e, {
user: {
id: userId,
applicationId: applicationId
}
});
this.logger.error(`Could not update user ${userId}`, JSON.stringify(e));
return {
userId: null,
Expand Down Expand Up @@ -479,6 +529,12 @@ export class FusionauthService {
},
)
.catch((e): { userId: UUID; err: Error } => {
Sentry.captureException(e, {
user: {
id: userId,
applicationId: applicationId
}
});
this.logger.error(`Could not update user ${userId}`, JSON.stringify(e));
return {
userId: null,
Expand Down Expand Up @@ -506,6 +562,12 @@ export class FusionauthService {
};
})
.catch((response) => {
Sentry.captureException(response, {
user: {
id: userId,
applicationId: applicationId
}
});
console.log(JSON.stringify(response));
return {
statusFA: FAStatus.ERROR,
Expand Down Expand Up @@ -557,6 +619,13 @@ export class FusionauthService {
registration: FusionAuthUserRegistration;
err: Error;
} => {
Sentry.captureException(e, {
user: {
id: userId,
applicationId: applicationId,
registration: registration
}
});
this.logger.error(
`Could not update user ${userId}`,
JSON.stringify(e),
Expand Down
13 changes: 12 additions & 1 deletion src/api/sms/cdac/cdac.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { SmsService } from '../sms.service';
import { ConfigService } from '@nestjs/config';
import got, {Got} from 'got';
import * as speakeasy from 'speakeasy';
import * as Sentry from '@sentry/node';

@Injectable()
export class CdacService extends SmsService implements SMS {
Expand Down Expand Up @@ -62,7 +63,11 @@ export class CdacService extends SmsService implements SMS {
step: this.configService.get<string>('SMS_TOTP_EXPIRY'),
});
} catch (error) {
console.log(error);
Sentry.captureException(error, {
user: {
phone: data.phone
}
});
throw new HttpException('TOTP generation failed!', 500);
}

Expand Down Expand Up @@ -94,6 +99,11 @@ export class CdacService extends SmsService implements SMS {
return status;
})
.catch((e: Error): OTPResponse => {
Sentry.captureException(e, {
user: {
phone: data.phone
}
});
const error: SMSError = {
errorText: `Uncaught Exception :: ${e.message}`,
errorCode: 'CUSTOM ERROR',
Expand Down Expand Up @@ -137,6 +147,7 @@ export class CdacService extends SmsService implements SMS {
};
}
} catch (e) {
Sentry.captureException(e);
const error: SMSError = {
errorText: `CDAC response could not be parsed :: ${e.message}; Provider Response - ${response}`,
errorCode: 'CUSTOM ERROR',
Expand Down
26 changes: 26 additions & 0 deletions src/api/sms/gupshup/gupshup.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { Injectable } from '@nestjs/common';
import { SmsService } from '../sms.service';
import { Got } from 'got/dist/source';
import * as Sentry from '@sentry/node';

@Injectable()
export class GupshupService extends SmsService implements SMS {
Expand Down Expand Up @@ -92,6 +93,13 @@ export class GupshupService extends SmsService implements SMS {
.then((response): OTPResponse => {
status.networkResponseCode = 200;
const r = this.parseResponse(response.body);
if (r.error) {
Sentry.captureMessage(JSON.stringify(r), {
user: {
phone: data.phone
}
});
}
status.messageID = r.messageID;
status.error = r.error;
status.providerResponseCode = r.providerResponseCode;
Expand All @@ -100,6 +108,11 @@ export class GupshupService extends SmsService implements SMS {
return status;
})
.catch((e: Error): OTPResponse => {
Sentry.captureException(e, {
user: {
phone: data.phone
}
});
const error: SMSError = {
errorText: `Uncaught Exception :: ${e.message}`,
errorCode: 'CUSTOM ERROR',
Expand Down Expand Up @@ -136,6 +149,13 @@ export class GupshupService extends SmsService implements SMS {
.then((response): OTPResponse => {
status.networkResponseCode = 200;
const r = this.parseResponse(response.body);
if (r.error) {
Sentry.captureMessage(JSON.stringify(r), {
user: {
phone: data.phone
}
});
}
status.messageID = r.messageID;
status.error = r.error;
status.providerResponseCode = r.providerResponseCode;
Expand All @@ -144,6 +164,11 @@ export class GupshupService extends SmsService implements SMS {
return status;
})
.catch((e: Error): OTPResponse => {
Sentry.captureException(e, {
user: {
phone: data.phone
}
});
const error: SMSError = {
errorText: `Uncaught Exception :: ${e.message}`,
errorCode: 'CUSTOM ERROR',
Expand Down Expand Up @@ -188,6 +213,7 @@ export class GupshupService extends SmsService implements SMS {
};
}
} catch (e) {
Sentry.captureException(e);
const error: SMSError = {
errorText: `Gupshup response could not be parsed :: ${e.message}; Provider Response - ${response}`,
errorCode: 'CUSTOM ERROR',
Expand Down
Loading

0 comments on commit 5623bf0

Please sign in to comment.