diff --git a/.env.example b/.env.example index 35725f4..70f2cb5 100644 --- a/.env.example +++ b/.env.example @@ -6,4 +6,6 @@ SCOPES="openid myinfo.name myinfo.passport_expiry_date myinfo.nric_number" DEV_AND_STAGING_SCOPES="openid sgidthirdpartymock.work_email sgidthirdpartymock.is_public_officer myinfo.nric_number myinfo.name myinfo.email myinfo.mobile_number" PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----woot woot-----END RSA PRIVATE KEY-----" OVERRIDE_DEV="http://localhost:3000" +RULES_ENGINE_DEV_ENDPOINT="http://localhost:3001/api/rules/eval" +SGID_RULE_IDS="ISOGPOFFICER-53270fce ISOGPOFFICER-aed06721" diff --git a/config/index.ts b/config/index.ts index d4751ed..4709ee8 100644 --- a/config/index.ts +++ b/config/index.ts @@ -10,3 +10,4 @@ export const PORT = process.env.PORT || 10000 export const SCOPES = process.env.SCOPES || 'openid' export const DEV_AND_STAGING_SCOPES = process.env.DEV_AND_STAGING_SCOPES || 'openid' +export const SGID_RULE_IDS = process.env.SGID_RULE_IDS || '' diff --git a/routes/callback.ts b/routes/callback.ts index 406bb03..dd059e3 100644 --- a/routes/callback.ts +++ b/routes/callback.ts @@ -1,9 +1,10 @@ import express from 'express' import { sgidService } from '../services/sgid-client.service' -import { formatData } from '../utils' +import { formatData, prettifyRuleName } from '../utils' import { nodeCache } from '../services/node-cache.service' import { SESSION_COOKIE_NAME } from '../constants' import { IAuthSession } from '../types' +import { SGID_RULE_IDS } from '../config' /** * Main controller function to generate the callback page @@ -21,11 +22,21 @@ export const callback = async (req: express.Request, res: express.Response) => { String(sessionData?.codeVerifier) ) - const { data } = await sgidService[String(state)].userinfo(accessToken, sub) - const formattedData = formatData(data) + const { data: userInfoData } = await sgidService[String(state)].userinfo( + accessToken, + sub + ) + const formattedUserInfoData = formatData(userInfoData) + + const rulesData = await sgidService[String(state)].rules({ + accessToken, + ruleIds: SGID_RULE_IDS, + userInfoData, + }) + const formattedRulesData = rulesData.map(data => [prettifyRuleName(data.ruleId), data.output]) res.render('callback', { - data: [['sgID', sub], ...formattedData], + data: [['sgID', sub], ...formattedUserInfoData, ...formattedRulesData], }) } catch (error) { console.error(error) diff --git a/services/sgid-client.service.ts b/services/sgid-client.service.ts index 27045c6..ff69108 100644 --- a/services/sgid-client.service.ts +++ b/services/sgid-client.service.ts @@ -1,4 +1,7 @@ -import SgidClient, { generatePkcePair } from '@opengovsg/sgid-client' +import SgidClient, { + RulesParams, + RulesReturn, +} from '@opengovsg/sgid-client' import { BASE_URLS } from '../config' interface SgidServiceOption { @@ -7,10 +10,12 @@ interface SgidServiceOption { privateKey: string redirectUri: string hostname: string + rulesEngineEndpoint: string | undefined } class SgidService { private sgidClient: SgidClient + clientId: string constructor({ clientId, @@ -18,6 +23,7 @@ class SgidService { privateKey, redirectUri, hostname, + rulesEngineEndpoint }: SgidServiceOption) { this.sgidClient = new SgidClient({ clientId: clientId, @@ -25,7 +31,9 @@ class SgidService { privateKey: privateKey, redirectUri: redirectUri, hostname: hostname, + rulesEngineEndpoint: rulesEngineEndpoint }) + this.clientId = clientId } /** @@ -80,6 +88,22 @@ class SgidService { throw new Error('Error retrieving user info via sgid-client') } } + + async rules(rulesParams: RulesParams): Promise { + const { accessToken, ruleIds, userInfoData } = rulesParams + + if (!accessToken) throw new Error(`accessToken cannot be empty`) + if (!ruleIds) throw new Error(`ruleIds cannot be empty`) + if (!userInfoData) throw new Error(`userInfoData cannot be empty`) + + try { + const data = await this.sgidClient.rules(rulesParams) + return data + } catch (e) { + console.error(e) + throw new Error('Error retrieving rule-based fields') + } + } } // Initialised the sgidService object with the different environments @@ -93,5 +117,6 @@ Object.keys(BASE_URLS).forEach((env) => { privateKey: process.env.PRIVATE_KEY as string, redirectUri: process.env.HOSTNAME + '/callback', hostname: BASE_URLS[env as keyof typeof BASE_URLS] as string, + rulesEngineEndpoint: env === 'dev' ? process.env.RULES_ENGINE_DEV_ENDPOINT : undefined }) }) diff --git a/utils/index.ts b/utils/index.ts index d5872e5..5ff2921 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -21,3 +21,7 @@ export const prettifyKey = (key: string): string => { prettified = prettified.replace(/_/g, ' ') return prettified.toUpperCase() } + +export const prettifyRuleName = (ruleName: string): string => { + return ruleName.replace(/_/g, ' ').toUpperCase() +} \ No newline at end of file