src/libs/identity.ts (60 lines of code) (raw):
import { getSsmValue } from '../utils/ssm';
interface IdAPIUserConsent {
status: string;
user: {
consents: [
{
id: string;
consented: boolean;
},
];
};
}
export async function fetchIdentityAPIToken(stage: string) {
console.log(`fetch identity api token for stage: ${stage}`);
return await getSsmValue(stage, 'IdAPI-BearerToken');
}
async function queryUserDetailsFromIdAPI(
identityId: string,
identityAPIBearerToken: string,
): Promise<IdAPIUserConsent> {
//console.log(
// `Querying IdAPI for identityId ${identityId} with token ${identityAPIBearerToken}`,
//);
console.log(`Querying IdAPI for identityId ${identityId}`);
const url = `https://idapi.theguardian.com/user/${identityId}`;
//console.log(`url: ${url}`);
const response = await fetch(url, {
method: 'GET',
headers: {
Authorization: `Bearer ${identityAPIBearerToken}`,
},
});
/*
response.data is a
{
"status": "ok",
"user": {
"primaryEmailAddress": "[REMOVED]",
"id": "[REMOVED]",
"publicFields": {
"displayName": "user"
},
"dates": {
"accountCreatedDate": "2018-12-03T10:22:45Z"
},
"consents": [
[....],
{
"actor": "user",
"id": "phone_optout",
"version": 0,
"consented": false,
"timestamp": "2018-12-03T10:22:45Z",
"privacyPolicyVersion": 1
}
],
"hasPassword": true
}
}
*/
return (await response.json()) as IdAPIUserConsent;
}
export async function validateIdentityIdForPhoneNumberInclusion(
stage: string,
identityId: string,
identityAPIBearerToken: string,
): Promise<boolean> {
if (stage === 'CODE') {
return true; // The ids in Saleforce CODE might not validate against idAPI PROD, but we want the phone numbers in CODE
}
let userDetailsFromIdAPI;
try {
userDetailsFromIdAPI = await queryUserDetailsFromIdAPI(
identityId,
identityAPIBearerToken,
);
if (userDetailsFromIdAPI.status !== 'ok') {
return false;
}
const consent = userDetailsFromIdAPI.user.consents.find(
(consent) => consent.id == 'phone_optout',
);
/*
consent is now either underfined or
{
"actor": "user",
"id": "phone_optout",
"version": 0,
"consented": false,
"timestamp": "2018-12-03T10:22:45Z",
"privacyPolicyVersion": 1
}
*/
if (consent !== undefined) {
return consent.consented === false; // `false` is the value that we are looking for
// Means that the user has not consented out of the phone use
} else {
return false;
}
} catch (err) {
console.error(err);
return false; // We isolate any caller from any failure of connecting to the identityAPI, by returning a proper boolean, `false` in this case
}
}