Skip to content

Commit

Permalink
OLH-1828 - Upgrade the frontend to AWS SDK v3
Browse files Browse the repository at this point in the history
  • Loading branch information
peterfajemisincabinetoffice committed Jun 26, 2024
1 parent ad5d25d commit dc0c934
Show file tree
Hide file tree
Showing 12 changed files with 822 additions and 3,528 deletions.
4,115 changes: 686 additions & 3,429 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,15 @@
},
"dependencies": {
"@aws-crypto/client-node": "^4.0.0",
"@aws-sdk/client-dynamodb": "^3.602.0",
"@aws-sdk/client-dynamodb": "^3.600.0",
"@aws-sdk/lib-dynamodb": "^3.600.0",
"@aws-sdk/client-sqs": "^3.600.0",
"@aws-sdk/util-dynamodb": "^3.602.0",
"@aws-sdk/util-dynamodb": "^3.600.0",
"@aws-sdk/client-kms": "^3.600.0",
"@aws-sdk/client-sns": "^3.600.0",
"@aws-sdk/util-base64-browser": "^3.209.0",
"@govuk-one-login/frontend-analytics": "1.0.3",
"@govuk-one-login/frontend-language-toggle": "^1.1.0",
"aws-sdk": "2.1647.0",
"axios": "^1.7.2",
"base64url": "3.0.1",
"body-parser": "^1.20.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Request, Response, NextFunction } from "express";
import { PATH_DATA } from "../../app.constants";
// import { formatEvent } from "../../utils/activityHistory";
import {
getAppEnv,
getDynamoActivityLogStoreTableName,
getOIDCClientId,
} from "../../config";
import { DynamoDB } from "aws-sdk";
import { QueryCommand } from "@aws-sdk/client-dynamodb";
import { dynamoDBService } from "../../utils/dynamo";
import { getSNSSuspicousActivityTopic } from "../../config";
import { ActivityLogEntry, FormattedActivityLog } from "../../utils/types";
Expand All @@ -15,18 +14,22 @@ import { formatActivityLogs } from "../../utils/activityHistory";
import { decryptData } from "../../utils/decrypt-data";
import { snsService } from "../../utils/sns";
import { getTxmaHeader } from "../../utils/txma-header";
import { unmarshall } from "@aws-sdk/util-dynamodb";

const activityLogDynamoDBRequest = (
subjectId: string,
eventId: string
): DynamoDB.Types.QueryInput => ({
TableName: getDynamoActivityLogStoreTableName(),
KeyConditionExpression: "user_id = :user_id AND event_id = :event_id ",
ExpressionAttributeValues: {
":user_id": { S: subjectId },
":event_id": { S: eventId },
},
});
): QueryCommand => {
const params = {
TableName: getDynamoActivityLogStoreTableName(),
KeyConditionExpression: "user_id = :user_id AND event_id = :event_id ",
ExpressionAttributeValues: {
":user_id": { S: subjectId },
":event_id": { S: eventId },
},
};
return new QueryCommand(params);
};

interface ReportSuspiciousActivityParams {
user_id: string;
Expand Down Expand Up @@ -91,9 +94,7 @@ export async function reportSuspiciousActivityGet(
);
return next();
}
activityLog = DynamoDB.Converter.unmarshall(
response.Items[0]
) as ActivityLogEntry;
activityLog = unmarshall(response.Items[0]) as ActivityLogEntry;
} catch (err) {
req.log.error(err.message);
return next(err);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import { expect } from "chai";
import * as dynamo from "../../../utils/dynamo";
import * as sns from "../../../utils/sns";
import { DynamoDBService } from "../../../utils/types";
import { DynamoDB } from "aws-sdk";
import {
GetItemCommandOutput,
QueryCommandOutput,
} from "@aws-sdk/client-dynamodb";
import { logger } from "../../../utils/logger";
import { AwsConfig } from "../../../config/aws";

Expand All @@ -18,7 +21,7 @@ describe("report suspicious activity controller", () => {
let req: Partial<Request>;
let res: Partial<Response>;
let next: any;
let dynamodbQueryOutput: DynamoDB.Types.QueryOutput;
let dynamodbQueryOutput: QueryCommandOutput;
let loggerSpy: sinon.SinonSpy;
let errorLoggerSpy: sinon.SinonSpy;
let mockDynamoDBService: DynamoDBService;
Expand Down Expand Up @@ -60,6 +63,7 @@ describe("report suspicious activity controller", () => {
};
next = sandbox.fake(() => {});
dynamodbQueryOutput = {
$metadata: undefined,
Items: [
{
event_id: { S: "event-id" },
Expand All @@ -72,10 +76,10 @@ describe("report suspicious activity controller", () => {
],
};
mockDynamoDBService = {
getItem(): Promise<DynamoDB.GetItemOutput> {
getItem(): Promise<GetItemCommandOutput> {
return Promise.resolve(undefined);
},
queryItem(): Promise<DynamoDB.Types.QueryOutput> {
queryItem(): Promise<QueryCommandOutput> {
return Promise.resolve(dynamodbQueryOutput);
},
};
Expand Down Expand Up @@ -108,6 +112,7 @@ describe("report suspicious activity controller", () => {
// Arrange
req.query = { event: "event-id", reported: "true" };
dynamodbQueryOutput = {
$metadata: undefined,
Items: [
{
event_id: { S: "event-id" },
Expand Down Expand Up @@ -150,7 +155,7 @@ describe("report suspicious activity controller", () => {
describe("Sorry, there is a problem with the service", () => {
it("event param can't be found for this user", async () => {
// Arrange
dynamodbQueryOutput = { Items: [] };
dynamodbQueryOutput = { $metadata: undefined, Items: [] };
req.query = { event: "event-id", reported: "false" };

// Act
Expand All @@ -163,10 +168,10 @@ describe("report suspicious activity controller", () => {
it("activity log can't be retrieved for this user", async () => {
// Arrange
mockDynamoDBService = {
getItem(): Promise<DynamoDB.GetItemOutput> {
getItem(): Promise<GetItemCommandOutput> {
throw new Error("DynamoDB error");
},
queryItem(): Promise<DynamoDB.Types.QueryOutput> {
queryItem(): Promise<QueryCommandOutput> {
throw new Error("DynamoDB error");
},
};
Expand Down
25 changes: 15 additions & 10 deletions src/config/aws.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Endpoint } from "aws-sdk";
import { DynamoDBClientConfig } from "@aws-sdk/client-dynamodb";
import {
isLocalEnv,
Expand All @@ -21,10 +20,14 @@ export interface SnsConfig {
awsConfig: AwsConfig;
}

export interface AwsConfig {
endpoint?: Endpoint;
export interface Credentials {
accessKeyId?: string;
secretAccessKey?: string;
}

export interface AwsConfig {
endpoint?: string;
credentials?: Credentials;
region: string;
}

Expand All @@ -37,9 +40,11 @@ function getLocalStackKmsConfig() {

function getLocalStackAWSConfig(): AwsConfig {
return {
endpoint: new Endpoint(getLocalStackBaseUrl()),
accessKeyId: "na",
secretAccessKey: "na",
endpoint: getLocalStackBaseUrl(),
credentials: {
accessKeyId: "na",
secretAccessKey: "na",
},
region: getAwsRegion(),
};
}
Expand Down Expand Up @@ -131,15 +136,15 @@ export function getDBConfig(
): DynamoDBClientConfig {
const dbConfig: any = {};

if (config.accessKeyId || config.secretAccessKey) {
if (config.credentials?.accessKeyId || config.credentials?.secretAccessKey) {
dbConfig.credentials = {
accessKeyId: config.accessKeyId || "",
secretAccessKey: config.secretAccessKey || "",
accessKeyId: config.credentials.accessKeyId || "",
secretAccessKey: config.credentials.secretAccessKey || "",
};
}

if (config.endpoint) {
dbConfig.endpoint = `${config.endpoint.protocol}//${config.endpoint.host}`;
dbConfig.endpoint = config.endpoint;
}

if (config.region) {
Expand Down
28 changes: 15 additions & 13 deletions src/utils/activityHistory.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DynamoDB } from "aws-sdk";
import { QueryCommand } from "@aws-sdk/client-dynamodb";
import { unmarshall } from "@aws-sdk/util-dynamodb";
import {
activityLogItemsPerPage,
getDynamoActivityLogStoreTableName,
Expand Down Expand Up @@ -194,16 +195,17 @@ export const formatActivityLogs = (
return formattedData;
};

const activityLogDynamoDBRequest = (
user_id: string
): DynamoDB.Types.QueryInput => ({
TableName: getDynamoActivityLogStoreTableName(),
KeyConditionExpression: "user_id = :user_id",
ExpressionAttributeValues: {
":user_id": { S: user_id },
},
ScanIndexForward: false, // Set to 'true' for ascending order
});
const activityLogDynamoDBRequest = (user_id: string): QueryCommand => {
const param = {
TableName: getDynamoActivityLogStoreTableName(),
KeyConditionExpression: "user_id = :user_id",
ExpressionAttributeValues: {
":user_id": { S: user_id },
},
ScanIndexForward: false, // Set to 'true' for ascending order
};
return new QueryCommand(param);
};

export const getActivityLogEntry = async (
user_id: string,
Expand All @@ -213,8 +215,8 @@ export const getActivityLogEntry = async (
const response = await dynamoDBService().queryItem(
activityLogDynamoDBRequest(user_id)
);
const unmarshalledItems = response.Items?.map((item) =>
DynamoDB.Converter.unmarshall(item)
const unmarshalledItems = response.Items?.map((item: any) =>
unmarshall(item)
) as ActivityLogEntry[];
return unmarshalledItems;
} catch (err) {
Expand Down
26 changes: 15 additions & 11 deletions src/utils/dynamo.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
import { DynamoDB } from "aws-sdk";
import {
DynamoDBClient,
GetItemCommand,
QueryCommand,
QueryCommandOutput,
} from "@aws-sdk/client-dynamodb";
import { DynamoDBService } from "./types";
import { getAWSConfig, AwsConfig } from "../config/aws";
import { GetCommandOutput } from "@aws-sdk/lib-dynamodb";

export function dynamoDBService(
awsConfig: AwsConfig = getAWSConfig()
): DynamoDBService {
const getItem = async function (
request: DynamoDB.Types.GetItemInput
): Promise<DynamoDB.Types.GetItemOutput> {
const dynamoDb = new DynamoDB(awsConfig);

return await dynamoDb.getItem(request).promise();
request: GetItemCommand
): Promise<GetCommandOutput> {
const dynamoClient = new DynamoDBClient(awsConfig as any);
return await dynamoClient.send(request);
};

const queryItem = async function (
request: DynamoDB.Types.QueryInput
): Promise<DynamoDB.Types.QueryOutput> {
const dynamoDb = new DynamoDB(awsConfig);

return await dynamoDb.query(request).promise();
request: QueryCommand
): Promise<QueryCommandOutput> {
const dynamoClient = new DynamoDBClient(awsConfig as any);
return await dynamoClient.send(request);
};

return {
Expand Down
26 changes: 15 additions & 11 deletions src/utils/kms.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import { KMS } from "aws-sdk";
import {
KMSClient,
MessageType,
SignCommand,
SignCommandOutput,
SigningAlgorithmSpec,
} from "@aws-sdk/client-kms";
import { KmsService } from "./types";
import { getKMSConfig, KmsConfig } from "../config/aws";

export function kmsService(config: KmsConfig = getKMSConfig()): KmsService {
const sign = async function (
payload: string
): Promise<KMS.Types.SignResponse> {
const kms = new KMS(config.awsConfig);
const sign = async function (payload: string): Promise<SignCommandOutput> {
const client = new KMSClient(config.awsConfig as any);

const request: KMS.SignRequest = {
const params = {
KeyId: config.kmsKeyId,
Message: payload,
SigningAlgorithm: "RSASSA_PKCS1_V1_5_SHA_512",
MessageType: "RAW",
Message: Buffer.from(payload),
MessageType: MessageType.RAW,
SigningAlgorithm: SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_512,
};

return await kms.sign(request).promise();
const request: SignCommand = new SignCommand(params);
return await client.send(request);
};

return {
Expand Down
9 changes: 5 additions & 4 deletions src/utils/oidc.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Issuer, Client, custom, generators } from "openid-client";
import { Client, custom, generators, Issuer } from "openid-client";
import { OIDCConfig } from "../types";
import memoize from "fast-memoize";
import { ClientAssertionServiceInterface, KmsService } from "./types";
import { kmsService } from "./kms";
import base64url from "base64url";
import { createRemoteJWKSet, decodeJwt } from "jose";
import random = generators.random;
import { decodeJwt, createRemoteJWKSet } from "jose";

const { toBase64 } = require("@aws-sdk/util-base64-browser");

custom.setHttpOptionsDefaults({
timeout: 20000,
Expand Down Expand Up @@ -61,7 +63,6 @@ function clientAssertionGenerator(
alg: "RS512",
typ: "JWT",
};

const payload = {
iss: clientId,
sub: clientId,
Expand All @@ -87,7 +88,7 @@ function clientAssertionGenerator(
"." +
token_components.payload +
"." +
sig.Signature.toString("base64")
toBase64(sig.Signature.toString())
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "")
Expand Down
16 changes: 10 additions & 6 deletions src/utils/sns.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import { SNS } from "aws-sdk";
import {
PublishCommand,
PublishCommandOutput,
SNSClient,
} from "@aws-sdk/client-sns";
import { SnsService } from "./types";
import { getSNSConfig, SnsConfig } from "../config/aws";

export function snsService(config: SnsConfig = getSNSConfig()): SnsService {
const publish = async function (
topic_arn: string,
message: string
): Promise<SNS.Types.PublishResponse> {
const sns = new SNS(config.awsConfig);
): Promise<PublishCommandOutput> {
const client = new SNSClient(config.awsConfig as any);

const request: SNS.PublishInput = {
const params = {
TopicArn: topic_arn,
Message: message,
};

return await sns.publish(request).promise();
const request: PublishCommand = new PublishCommand(params);
return await client.send(request);
};
return {
publish,
Expand Down
Loading

0 comments on commit dc0c934

Please sign in to comment.