From 53d7dfdcc23d90dba85a681f39ebc724b7fbdcc2 Mon Sep 17 00:00:00 2001 From: DaevMithran <61043607+DaevMithran@users.noreply.github.com> Date: Thu, 11 Jan 2024 18:28:36 +0530 Subject: [PATCH 1/4] fix: Fix error handling on tracking operations [DEV-3527] (#461) * fix: Fix error handling on tracking operations * Silently log tracking errors * Remove duplicate return statements --------- Co-authored-by: Andrew Nikitin --- src/controllers/account.ts | 53 +++++++++++----------------- src/controllers/credential-status.ts | 45 ++++++++++++----------- src/controllers/credentials.ts | 30 +++++++++------- src/controllers/resource.ts | 10 +++--- 4 files changed, 68 insertions(+), 70 deletions(-) diff --git a/src/controllers/account.ts b/src/controllers/account.ts index 1b0e8b95..0d21f9e7 100644 --- a/src/controllers/account.ts +++ b/src/controllers/account.ts @@ -95,41 +95,28 @@ export class AccountController { } const identityStrategySetup = new IdentityServiceStrategySetup(response.locals.customer.customerId); - let apiKey = await identityStrategySetup.agent.getAPIKey(response.locals.customer, response.locals.user); - // If there is no API key for the customer - create it - if (!apiKey) { - apiKey = await identityStrategySetup.agent.setAPIKey( - request.session.idToken, - response.locals.customer, - response.locals.user - ); - } else if (apiKey.isExpired()) { - // If API key is expired - update it - apiKey = await identityStrategySetup.agent.updateAPIKey(apiKey, request.session.idToken); - } - return response.status(StatusCodes.OK).json({ - idToken: apiKey?.apiKey, - }); - } - - public async setupDefaultRole(request: Request, response: Response) { - if (request.body) { - const { body } = request; - if (!body.user.isSuspended) { - const logToHelper = new LogToHelper(); - const _r = await logToHelper.setup(); - if (_r.status !== StatusCodes.OK) { - return response.status(StatusCodes.BAD_GATEWAY).json({ - error: _r.error, - }); - } - const resp = await logToHelper.setDefaultRoleForUser(body.user.id as string); - return response.status(resp.status).json({ - error: resp.error, - }); + try { + // Get the API key for the customer + let apiKey = await identityStrategySetup.agent.getAPIKey(response.locals.customer, response.locals.user); + // If there is no API key for the customer - create it + if (!apiKey) { + apiKey = await identityStrategySetup.agent.setAPIKey( + request.session.idToken, + response.locals.customer, + response.locals.user + ); + } else if (apiKey.isExpired()) { + // If API key is expired - update it + apiKey = await identityStrategySetup.agent.updateAPIKey(apiKey, request.session.idToken); } + return response.status(StatusCodes.OK).json({ + idToken: apiKey?.apiKey, + }); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + }); } - return response.status(StatusCodes.BAD_REQUEST).json({}); } public async bootstrap(request: Request, response: Response) { diff --git a/src/controllers/credential-status.ts b/src/controllers/credential-status.ts index c22c067b..9e3c410f 100644 --- a/src/controllers/credential-status.ts +++ b/src/controllers/credential-status.ts @@ -562,13 +562,14 @@ export class CredentialStatusController { }, } as ITrackOperation; - const trackResult = await identityServiceStrategySetup.agent.trackOperation(trackResourceInfo); + const trackResult = await identityServiceStrategySetup.agent + .trackOperation(trackResourceInfo) + .catch((error) => { + return { error }; + }); if (trackResult.error) { - return response - .status(StatusCodes.INTERNAL_SERVER_ERROR) - .json(trackResult as CreateEncryptedStatusListUnsuccessfulResponseBody); + console.error(`Tracking Error: ${trackResult.error}`); } - // return result return response.status(StatusCodes.OK).json({ ...result, encrypted: undefined }); } catch (error) { @@ -695,14 +696,14 @@ export class CredentialStatusController { feePaymentNetwork: CheqdNetwork.Testnet, }, } as ITrackOperation; - const trackResult = await identityServiceStrategySetup.agent.trackOperation(trackResourceInfo); - + const trackResult = await identityServiceStrategySetup.agent + .trackOperation(trackResourceInfo) + .catch((error) => { + return { error }; + }); if (trackResult.error) { - return response - .status(StatusCodes.INTERNAL_SERVER_ERROR) - .json(trackResult as CreateEncryptedStatusListUnsuccessfulResponseBody); + console.error(`Tracking Error: ${trackResult.error}`); } - // return result return response.status(StatusCodes.OK).json({ ...result, encrypted: undefined }); } catch (error) { @@ -873,12 +874,13 @@ export class CredentialStatusController { symmetricKey: '', }, } as ITrackOperation; - const trackResult = await identityServiceStrategySetup.agent.trackOperation(trackResourceInfo); + const trackResult = await identityServiceStrategySetup.agent + .trackOperation(trackResourceInfo) + .catch((error) => { + return { error }; + }); if (trackResult.error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - updated: false, - error: trackResult.error, - } as UpdateUnencryptedStatusListUnsuccessfulResponseBody); + console.error(`Tracking Error: ${trackResult.error}`); } } @@ -1072,12 +1074,13 @@ export class CredentialStatusController { feePaymentNetwork: CheqdNetwork.Testnet, }, } as ITrackOperation; - const trackResult = await identityServiceStrategySetup.agent.trackOperation(trackResourceInfo); + const trackResult = await identityServiceStrategySetup.agent + .trackOperation(trackResourceInfo) + .catch((error) => { + return { error }; + }); if (trackResult.error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - updated: false, - error: trackResult.error, - } as UpdateUnencryptedStatusListUnsuccessfulResponseBody); + console.error(`Tracking Error: ${trackResult.error}`); } } diff --git a/src/controllers/credentials.ts b/src/controllers/credentials.ts index 83a0221e..852879f9 100644 --- a/src/controllers/credentials.ts +++ b/src/controllers/credentials.ts @@ -331,11 +331,13 @@ export class CredentialController { } as ITrackOperation; // Track operation - const trackResult = await identityServiceStrategySetup.agent.trackOperation(trackInfo); - if (trackResult.error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: trackResult.error, + const trackResult = await identityServiceStrategySetup.agent + .trackOperation(trackInfo) + .catch((error) => { + return { error }; }); + if (trackResult.error) { + console.error(`Tracking Error: ${trackResult.error}`); } } // Return Ok response @@ -435,11 +437,13 @@ export class CredentialController { } as ITrackOperation; // Track operation - const trackResult = await identityServiceStrategySetup.agent.trackOperation(trackInfo); - if (trackResult.error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: trackResult.error, + const trackResult = await identityServiceStrategySetup.agent + .trackOperation(trackInfo) + .catch((error) => { + return { error }; }); + if (trackResult.error) { + console.error(`Tracking Error: ${trackResult.error}`); } } @@ -537,11 +541,13 @@ export class CredentialController { } as ITrackOperation; // Track operation - const trackResult = await identityServiceStrategySetup.agent.trackOperation(trackInfo); - if (trackResult.error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: trackResult.error, + const trackResult = await identityServiceStrategySetup.agent + .trackOperation(trackInfo) + .catch((error) => { + return { error }; }); + if (trackResult.error) { + console.error(`Tracking Error: ${trackResult.error}`); } } // Return Ok response diff --git a/src/controllers/resource.ts b/src/controllers/resource.ts index efeb22e1..4f06862a 100644 --- a/src/controllers/resource.ts +++ b/src/controllers/resource.ts @@ -190,11 +190,13 @@ export class ResourceController { }, } as ITrackOperation; - const trackResult = await identityServiceStrategySetup.agent.trackOperation(trackResourceInfo); - if (trackResult.error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: `${trackResult.error}`, + const trackResult = await identityServiceStrategySetup.agent + .trackOperation(trackResourceInfo) + .catch((error) => { + return { error }; }); + if (trackResult.error) { + console.error(`Tracking Error: ${trackResult.error}`); } return response.status(StatusCodes.CREATED).json({ From b6b97542a0480c36260798aa8ffb73e04bd171b0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 11 Jan 2024 13:09:10 +0000 Subject: [PATCH 2/4] chore(release): 2.15.1-develop.1 [skip ci] ## [2.15.1-develop.1](https://github.com/cheqd/credential-service/compare/2.15.0...2.15.1-develop.1) (2024-01-11) ### Bug Fixes * Fix error handling on tracking operations [DEV-3527] ([#461](https://github.com/cheqd/credential-service/issues/461)) ([53d7dfd](https://github.com/cheqd/credential-service/commit/53d7dfdcc23d90dba85a681f39ebc724b7fbdcc2)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d25bb36..7d67a8c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [2.15.1-develop.1](https://github.com/cheqd/credential-service/compare/2.15.0...2.15.1-develop.1) (2024-01-11) + + +### Bug Fixes + +* Fix error handling on tracking operations [DEV-3527] ([#461](https://github.com/cheqd/credential-service/issues/461)) ([53d7dfd](https://github.com/cheqd/credential-service/commit/53d7dfdcc23d90dba85a681f39ebc724b7fbdcc2)) + ## [2.15.0](https://github.com/cheqd/credential-service/compare/2.14.0...2.15.0) (2024-01-05) diff --git a/package.json b/package.json index 01d0b575..3d9e6ea3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cheqd/credential-service", - "version": "2.15.0", + "version": "2.15.1-develop.1", "description": "cheqd Credential Service Backend", "source": "src/index.ts", "main": "dist/index.js", From ddeeaa30b5e1f4c4498901ec5e571da8f228325b Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Thu, 11 Jan 2024 14:26:55 +0100 Subject: [PATCH 3/4] Simplyfing setting up user or customer from fetcher --- src/middleware/auth/base-auth-handler.ts | 2 -- .../auth/user-info-fetcher/m2m-token.ts | 4 +++ src/middleware/authentication.ts | 25 ++++++++++++------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/middleware/auth/base-auth-handler.ts b/src/middleware/auth/base-auth-handler.ts index 629c9e43..c479bb25 100644 --- a/src/middleware/auth/base-auth-handler.ts +++ b/src/middleware/auth/base-auth-handler.ts @@ -136,8 +136,6 @@ export class BaseAuthHandler extends BaseAPIGuard implements IAuthHandler { this.setUserInfoStrategy(new APITokenUserInfoFetcher(token)); } else { this.setUserInfoStrategy(new M2MTokenUserInfoFetcher(token)); - const customerId = request.headers['customer-id']; - if (typeof customerId === 'string') this.setCustomerId(customerId); } } else { this.setUserInfoStrategy(new SwaggerUserInfoFetcher()); diff --git a/src/middleware/auth/user-info-fetcher/m2m-token.ts b/src/middleware/auth/user-info-fetcher/m2m-token.ts index ef66ab07..4c6df508 100644 --- a/src/middleware/auth/user-info-fetcher/m2m-token.ts +++ b/src/middleware/auth/user-info-fetcher/m2m-token.ts @@ -18,6 +18,10 @@ export class M2MTokenUserInfoFetcher extends AuthReturn implements IUserInfoFetc } async fetchUserInfo(request: Request, oauthProvider: IOAuthProvider): Promise { + // Get customerId from header + const customerId = request.headers['customer-id']; + if (typeof customerId === 'string') this.setCustomerId(customerId); + // Verify M2M token return this.verifyJWTToken(this.token as string, oauthProvider); } diff --git a/src/middleware/authentication.ts b/src/middleware/authentication.ts index 8981a986..9172aa0d 100644 --- a/src/middleware/authentication.ts +++ b/src/middleware/authentication.ts @@ -135,10 +135,12 @@ export class Authentication { }); } // Only for rules when it's not allowed for unauthorized users - // we need to find customer and assign it to the response.locals + // we need to find customer or user and assign them to the response.locals if (!_resp.data.isAllowedUnauthorized) { + let customer; + let user; if (_resp.data.userId !== '') { - const user = await UserService.instance.get(_resp.data.userId); + user = await UserService.instance.get(_resp.data.userId); if (!user) { return response.status(StatusCodes.NOT_FOUND).json({ error: `Looks like user with logToId ${_resp.data.userId} is not found`, @@ -149,18 +151,23 @@ export class Authentication { error: `Looks like user with logToId ${_resp.data.userId} is not assigned to any CredentialService customer`, }); } - response.locals.customer = user.customer; - response.locals.user = user; - } else if (!(['/account/create'].includes(request.path) && _resp.data.customerId == '')) { - // allow bootstrap apis to create a customer if there is not customerId - const customer = await CustomerService.instance.get(_resp.data.customerId); + customer = user.customer; + } + if (_resp.data.customerId !== '' && !customer) { + customer = await CustomerService.instance.get(_resp.data.customerId); if (!customer) { return response.status(StatusCodes.NOT_FOUND).json({ - error: `Looks like user with logToId ${_resp.data.customerId} is not found`, + error: `Looks like customer with id ${_resp.data.customerId} is not found`, }); } - response.locals.customer = customer; } + if (!customer && !user) { + return response.status(StatusCodes.UNAUTHORIZED).json({ + error: `Looks like customer and user are not found in the system or they are not registered yet. Please contact administrator.`, + }) + } + response.locals.customer = customer; + response.locals.user = user; } next(); } catch (err) { From 46ce17709dc1c8fdb9d5d0d29cb78695cee88e5c Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Thu, 11 Jan 2024 14:48:31 +0100 Subject: [PATCH 4/4] Fix it for account creating --- src/controllers/account.ts | 2 +- src/middleware/authentication.ts | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/controllers/account.ts b/src/controllers/account.ts index d1277bf2..8948f055 100644 --- a/src/controllers/account.ts +++ b/src/controllers/account.ts @@ -411,7 +411,7 @@ export class AccountController { } } } - return response.status(StatusCodes.OK).json(customer); + return response.status(StatusCodes.CREATED).json(customer); } catch (error) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: `Internal Error: ${(error as Error)?.message || error}`, diff --git a/src/middleware/authentication.ts b/src/middleware/authentication.ts index 9172aa0d..d48f62f6 100644 --- a/src/middleware/authentication.ts +++ b/src/middleware/authentication.ts @@ -122,6 +122,11 @@ export class Authentication { } } + // ToDo: refactor it or keep for the moment of setting up the admin panel + private isBootstrapping(request: Request) { + return ['/account/create'].includes(request.path); + } + public async guard(request: Request, response: Response, next: NextFunction) { const { provider } = request.body as { claim: string; provider: string }; if (this.authHandler.skipPath(request.path)) return next(); @@ -161,7 +166,7 @@ export class Authentication { }); } } - if (!customer && !user) { + if (!customer && !user && !this.isBootstrapping(request)) { return response.status(StatusCodes.UNAUTHORIZED).json({ error: `Looks like customer and user are not found in the system or they are not registered yet. Please contact administrator.`, })