Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/webforms' into silky
Browse files Browse the repository at this point in the history
  • Loading branch information
jdinh8124 committed Nov 3, 2023
2 parents d0cc80f + 469690d commit a0eb009
Show file tree
Hide file tree
Showing 52 changed files with 1,374 additions and 186 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/destroy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ jobs:
if: |
(
github.event.ref_type == 'branch' &&
!startsWith(github.event.ref, 'skipci') &&
!contains(fromJson('["master", "staging", "production"]'), github.event.ref)
(!startsWith(github.event.ref, 'skipci')) &&
(!contains(fromJson('["master", "staging", "production"]'), github.event.ref))
) ||
(
inputs.environment != '' &&
!contains(fromJson('["master", "staging", "production"]'), inputs.environment)
(!contains(fromJson('["master", "staging", "production"]'), inputs.environment))
)
runs-on: ubuntu-20.04
environment:
Expand Down Expand Up @@ -51,7 +51,7 @@ jobs:
SLACK_COLOR: ${{job.status}}
SLACK_ICON: https://github.com/Enterprise-CMCS.png?size=48
SLACK_TITLE: Failure
SLACK_USERNAME: ${{ github.repository }} ${{job.status}}
SLACK_USERNAME: ${{ github.repository }} - ${{job.status}}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

delete_environment:
Expand Down
6 changes: 6 additions & 0 deletions serverless-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ services:
path: src/services/data
params:
ECSFailureTopicArn: ${alerts.ECSFailureTopicArn}
uploads:
path: src/services/uploads
ui-infra:
path: src/services/ui-infra
api:
Expand All @@ -17,6 +19,10 @@ services:
ECSFailureTopicArn: ${alerts.ECSFailureTopicArn}
osDomainArn: ${data.OpenSearchDomainArn}
osDomain: ${data.OpenSearchDomainEndpoint}
topicName: ${data.TopicName}
attachmentsBucketName: ${uploads.AttachmentsBucketName}
attachmentsBucketRegion: ${uploads.AttachmentsBucketRegion}
attachmentsBucketArn: ${uploads.AttachmentsBucketArn}
auth:
path: src/services/auth
params:
Expand Down
3 changes: 3 additions & 0 deletions src/packages/shared-types/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum Action {
ENABLE_RAI_WITHDRAW = "enable-rai-withdraw",
}
1 change: 1 addition & 0 deletions src/packages/shared-types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from "./errors";
export * from "./seatool";
export * from "./onemac";
export * from "./opensearch";
export * from "./actions";
4 changes: 4 additions & 0 deletions src/packages/shared-types/opensearch.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { SeaToolTransform } from "./seatool";
import { OneMacTransform } from "./onemac";
import { Action } from "./actions";

export type OsHit<T> = {
_index: string;
Expand Down Expand Up @@ -34,6 +35,9 @@ export type OsResponse<T> = {
export type OsMainSourceItem = OneMacTransform & SeaToolTransform;
export type OsMainSearchResponse = OsResponse<OsMainSourceItem>;
export type SearchData = OsHits<OsMainSourceItem>;
export type ItemResult = OsHit<OsMainSourceItem> & {
found: boolean;
};

export type OsFilterType =
| "term"
Expand Down
32 changes: 12 additions & 20 deletions src/services/api/handlers/forms.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,44 @@
import { response } from "../libs/handler";

import * as fs from "fs";
import { APIGatewayEvent } from "aws-lambda";

export const forms = async (event: APIGatewayEvent) => {
try {
const body = event.body ? JSON.parse(event.body) : {};
const formId = body.formId;
const formVersion = body.formVersion;
const formId = event.queryStringParameters.formId;
const formVersion = event.queryStringParameters.formVersion;

if (!formId) {
return {
return response({
statusCode: 400,
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ error: "File ID was not provided" }),
};
});
}

const filePath = getFilepathForIdAndVersion(formId, formVersion);
const jsonData = await fs.promises.readFile(filePath, "utf-8");

if (!jsonData) {
return {
return response({
statusCode: 404,
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
error: "No file was found with provided formId and formVersion",
}),
};
});
}
console.log(jsonData);
return {
return response({
statusCode: 200,
headers: {
"Content-Type": "application/json",
},
body: jsonData,
};
});
} catch (error) {
console.error("Error:", error);
return {
return response({
statusCode: 500,
body: JSON.stringify({
error: error.message ? error.message : "Internal server error",
}),
};
});
}
};

Expand Down
61 changes: 33 additions & 28 deletions src/services/api/handlers/getAttachmentUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const handler = async (event: APIGatewayEvent) => {
}

// Now we can generate the presigned url
const url = await generatePresignedS3Url(body.bucket, body.key, 60);
const url = await generateLegacyPresignedS3Url(body.bucket, body.key, 60);

return response<unknown>({
statusCode: 200,
Expand All @@ -84,32 +84,37 @@ export const handler = async (event: APIGatewayEvent) => {
}
};

async function generatePresignedS3Url(bucket, key, expirationInSeconds) {
// Create an S3 client
const roleToAssumeArn = process.env.onemacLegacyS3AccessRoleArn;

// Create an STS client to make the AssumeRole API call
const stsClient = new STSClient({});

// Assume the role
const assumedRoleResponse = await stsClient.send(
new AssumeRoleCommand({
RoleArn: roleToAssumeArn,
RoleSessionName: "AssumedRoleSession",
})
);

// Extract the assumed role credentials
const assumedCredentials = assumedRoleResponse.Credentials;

// Create S3 client using the assumed role's credentials
const assumedS3Client = new S3Client({
credentials: {
accessKeyId: assumedCredentials.AccessKeyId,
secretAccessKey: assumedCredentials.SecretAccessKey,
sessionToken: assumedCredentials.SessionToken,
},
});
async function getClient(bucket) {
if (bucket.startsWith("uploads")) {
const stsClient = new STSClient({});

// Assume the role
const assumedRoleResponse = await stsClient.send(
new AssumeRoleCommand({
RoleArn: process.env.onemacLegacyS3AccessRoleArn,
RoleSessionName: "AssumedRoleSession",
})
);

// Extract the assumed role credentials
const assumedCredentials = assumedRoleResponse.Credentials;

// Create S3 client using the assumed role's credentials
return new S3Client({
credentials: {
accessKeyId: assumedCredentials.AccessKeyId,
secretAccessKey: assumedCredentials.SecretAccessKey,
sessionToken: assumedCredentials.SessionToken,
},
});
} else {
return new S3Client({});
}
}

async function generateLegacyPresignedS3Url(bucket, key, expirationInSeconds) {
// Get an S3 client
const client = await getClient(bucket);

// Create a command to get the object (you can adjust this according to your use case)
const getObjectCommand = new GetObjectCommand({
Expand All @@ -118,7 +123,7 @@ async function generatePresignedS3Url(bucket, key, expirationInSeconds) {
});

// Generate a presigned URL
const presignedUrl = await getSignedUrl(assumedS3Client, getObjectCommand, {
const presignedUrl = await getSignedUrl(client, getObjectCommand, {
expiresIn: expirationInSeconds,
});

Expand Down
66 changes: 66 additions & 0 deletions src/services/api/handlers/getPackageActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { APIGatewayEvent } from "aws-lambda";
import { Action, CognitoUserAttributes, ItemResult } from "shared-types";
import { isCmsUser } from "shared-utils";
import { getPackage } from "../libs/package/getPackage";
import {
getAuthDetails,
isAuthorized,
lookupUserAttributes,
} from "../libs/auth/user";
import { response } from "../libs/handler";

type GetPackageActionsBody = {
id: string;
};

/** Generates an array of allowed actions from a combination of user attributes
* and OS result data */
const packageActionsForResult = (
user: CognitoUserAttributes,
result: ItemResult
): Action[] => {
const actions = [];
if (isCmsUser(user)) {
actions.push(Action.ENABLE_RAI_WITHDRAW);
}
return actions;
};
export const getPackageActions = async (event: APIGatewayEvent) => {
const body = JSON.parse(event.body) as GetPackageActionsBody;
try {
console.log(body);
const result = await getPackage(body.id);
const passedStateAuth = await isAuthorized(event, result._source.state);
if (!passedStateAuth)
return response({
statusCode: 401,
body: { message: "Not authorized to view resources from this state" },
});
if (!result.found)
return response({
statusCode: 404,
body: { message: "No record found for the given id" },
});

const authDetails = getAuthDetails(event);
const userAttr = await lookupUserAttributes(
authDetails.userId,
authDetails.poolId
);

return response({
statusCode: 200,
body: {
actions: packageActionsForResult(userAttr, result),
},
});
} catch (err) {
console.error({ err });
return response({
statusCode: 500,
body: { message: "Internal server error" },
});
}
};

export const handler = getPackageActions;
50 changes: 50 additions & 0 deletions src/services/api/handlers/getUploadUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { response } from "../libs/handler";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { v4 as uuidv4 } from "uuid";

checkEnvVariables(["attachmentsBucketName", "attachmentsBucketRegion"]);

const s3 = new S3Client({
region: process.env.attachmentsBucketRegion,
});

export const handler = async () => {
try {
const bucket = process.env.attachmentsBucketName;
const key = uuidv4();
const url = await getSignedUrl(
s3,
new PutObjectCommand({
Bucket: bucket,
Key: key,
}),
{
expiresIn: 60,
}
);

return response<unknown>({
statusCode: 200,
body: { url, bucket, key },
});
} catch (error) {
console.error({ error });
return response({
statusCode: 500,
body: { message: "Internal server error" },
});
}
};

function checkEnvVariables(requiredEnvVariables) {
const missingVariables = requiredEnvVariables.filter(
(envVar) => !process.env[envVar]
);

if (missingVariables.length > 0) {
throw new Error(
`Missing required environment variables: ${missingVariables.join(", ")}`
);
}
}
11 changes: 2 additions & 9 deletions src/services/api/handlers/item.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { response } from "../libs/handler";
import { APIGatewayEvent } from "aws-lambda";
import * as os from "../../../libs/opensearch-lib";
import { getStateFilter } from "../libs/auth/user";
import { OsHit, OsMainSourceItem } from "shared-types";
import { getPackage } from "../libs/package/getPackage";

if (!process.env.osDomain) {
throw "ERROR: osDomain env variable is required,";
Expand All @@ -11,14 +10,8 @@ if (!process.env.osDomain) {
export const getItemData = async (event: APIGatewayEvent) => {
try {
const body = JSON.parse(event.body);

const stateFilter = await getStateFilter(event);

const result = (await os.getItem(
process.env.osDomain,
"main",
body.id
)) as OsHit<OsMainSourceItem> & { found: boolean };
const result = await getPackage(body.id);

if (
stateFilter &&
Expand Down
5 changes: 5 additions & 0 deletions src/services/api/libs/package/getPackage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as os from "../../../../libs/opensearch-lib";
import { ItemResult } from "shared-types";

export const getPackage = async (id: string) =>
(await os.getItem(process.env.osDomain, "main", id)) as ItemResult;
Loading

0 comments on commit a0eb009

Please sign in to comment.