From 80cb9d5bd2ee33580e7510f7eecc1ea1c87e72be Mon Sep 17 00:00:00 2001 From: Gowri Date: Wed, 27 Sep 2023 13:28:01 +0930 Subject: [PATCH] DO-1535: upgrade geoip redirect construct --- package-lock.json | 23 ++++++++ packages/geoip-redirect/.gitignore | 58 +++++++++++++++++++ packages/geoip-redirect/.npmignore | 11 ++++ packages/geoip-redirect/README.md | 4 ++ packages/geoip-redirect/index.ts | 3 + .../geoip-redirect/lib/handlers/redirect.ts | 43 ++++++++++++++ .../geoip-redirect/lib/redirect-construct.ts | 57 ++++++++++++++++++ packages/geoip-redirect/package.json | 34 +++++++++++ packages/geoip-redirect/tsconfig.json | 3 + 9 files changed, 236 insertions(+) create mode 100644 packages/geoip-redirect/.gitignore create mode 100644 packages/geoip-redirect/.npmignore create mode 100644 packages/geoip-redirect/README.md create mode 100644 packages/geoip-redirect/index.ts create mode 100644 packages/geoip-redirect/lib/handlers/redirect.ts create mode 100644 packages/geoip-redirect/lib/redirect-construct.ts create mode 100644 packages/geoip-redirect/package.json create mode 100644 packages/geoip-redirect/tsconfig.json diff --git a/package-lock.json b/package-lock.json index b8d3bc82..d00d4897 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,10 @@ "resolved": "packages/cloudfront-security-headers", "link": true }, + "node_modules/@aligent/cdk-geoip-redirect": { + "resolved": "packages/geoip-redirect", + "link": true + }, "node_modules/@aligent/cdk-rabbitmq": { "resolved": "packages/rabbitmq", "link": true @@ -5855,6 +5859,25 @@ "typescript": "~5.2.2" } }, + "packages/geoip-redirect": { + "version": "0.1.0", + "license": "GPL-3.0-only", + "dependencies": { + "@types/aws-lambda": "^8.10.122", + "aws-cdk-lib": "2.97.0", + "constructs": "^10.0.0", + "source-map-support": "^0.5.21" + }, + "devDependencies": { + "@types/jest": "^29.5.5", + "@types/node": "20.6.3", + "aws-cdk": "2.97.0", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.1", + "typescript": "~5.2.2" + } + }, "packages/rabbitmq": { "name": "@aligent/cdk-rabbitmq", "version": "2.0.0", diff --git a/packages/geoip-redirect/.gitignore b/packages/geoip-redirect/.gitignore new file mode 100644 index 00000000..8f77f768 --- /dev/null +++ b/packages/geoip-redirect/.gitignore @@ -0,0 +1,58 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Maven +target/ +dist/ + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +!jest.config.js + +# CDK asset staging directory +.cdk.staging +cdk.out + +*.d.ts +*.js diff --git a/packages/geoip-redirect/.npmignore b/packages/geoip-redirect/.npmignore new file mode 100644 index 00000000..bfd115ba --- /dev/null +++ b/packages/geoip-redirect/.npmignore @@ -0,0 +1,11 @@ +*.ts +!lib/handlers/*.ts +!*.d.ts +!*.js + +# CDK asset staging directory +.cdk.staging +cdk.out + +# Samples +sample/ diff --git a/packages/geoip-redirect/README.md b/packages/geoip-redirect/README.md new file mode 100644 index 00000000..40b83a8d --- /dev/null +++ b/packages/geoip-redirect/README.md @@ -0,0 +1,4 @@ +# Geo-IP Redirect +This library provides a construct which creates a Lambda@Edge functions to perform GeoIP redirects. + +These functions are intended to be added to an existing Cloudfront distribution diff --git a/packages/geoip-redirect/index.ts b/packages/geoip-redirect/index.ts new file mode 100644 index 00000000..807b044b --- /dev/null +++ b/packages/geoip-redirect/index.ts @@ -0,0 +1,3 @@ +import { RedirectFunction } from "./lib/redirect-construct"; + +export { RedirectFunction }; diff --git a/packages/geoip-redirect/lib/handlers/redirect.ts b/packages/geoip-redirect/lib/handlers/redirect.ts new file mode 100644 index 00000000..7a762f24 --- /dev/null +++ b/packages/geoip-redirect/lib/handlers/redirect.ts @@ -0,0 +1,43 @@ +import "source-map-support/register"; +import { + CloudFrontRequestEvent, + CloudFrontResponse, + CloudFrontRequest, +} from "aws-lambda"; + +const REDIRECT_HOST = process.env.REDIRECT_HOST; +const SUPPORTED_REGIONS = new RegExp(process.env.SUPPORTED_REGIONS); +const DEFAULT_REGION = process.env.DEFAULT_REGION; + +export const handler = async ( + event: CloudFrontRequestEvent +): Promise => { + const request = event.Records[0].cf.request; + + let redirectURL = `https://${REDIRECT_HOST}/`; + if (request.headers["cloudfront-viewer-country"]) { + const countryCode = request.headers["cloudfront-viewer-country"][0].value; + if (SUPPORTED_REGIONS.test(countryCode)) { + redirectURL = `${redirectURL}${countryCode.toLowerCase()}${request.uri}`; + } else { + redirectURL = `${redirectURL}${DEFAULT_REGION.toLowerCase()}${ + request.uri + }`; + } + + return { + status: "302", + statusDescription: "Found", + headers: { + location: [ + { + key: "Location", + value: redirectURL, + }, + ], + }, + }; + } + + return request; +}; diff --git a/packages/geoip-redirect/lib/redirect-construct.ts b/packages/geoip-redirect/lib/redirect-construct.ts new file mode 100644 index 00000000..0cf65aea --- /dev/null +++ b/packages/geoip-redirect/lib/redirect-construct.ts @@ -0,0 +1,57 @@ +import { AssetHashType, DockerImage } from "aws-cdk-lib"; +import { EdgeFunction } from "aws-cdk-lib/aws-cloudfront/lib/experimental"; +import { Code, IVersion, Runtime, Version } from "aws-cdk-lib/aws-lambda"; +import { Construct } from "constructs"; +import { join } from "path"; +import { Esbuild } from "@aligent/esbuild"; + +export interface RedirectFunctionOptions { + redirectHost: string; + // Case-sensitive regular expression matching cloudfront-viewer-country + supportedRegionsExpression: string; + // default region code to use when not matched + defaultRegion: string; +} + +export class RedirectFunction extends Construct { + readonly edgeFunction: EdgeFunction; + + constructor(scope: Construct, id: string, options: RedirectFunctionOptions) { + super(scope, id); + + const command = [ + "sh", + "-c", + 'echo "Docker build not supported. Please install esbuild."', + ]; + + this.edgeFunction = new EdgeFunction(this, `${id}-redirect-fn`, { + code: Code.fromAsset(join(__dirname, "handlers"), { + assetHashType: AssetHashType.OUTPUT, + bundling: { + command, + image: DockerImage.fromRegistry("busybox"), + local: new Esbuild({ + entryPoints: [join(__dirname, "handlers/redirect.ts")], + define: { + "process.env.REDIRECT_HOST": options.redirectHost, + "process.env.SUPPORTED_REGIONS": + options.supportedRegionsExpression, + "process.env.DEFAULT_REGION": options.defaultRegion, + }, + }), + }, + }), + runtime: Runtime.NODEJS_18_X, + handler: "redirect.handler", + }); + } + + public getFunctionVersion(): IVersion { + return Version.fromVersionArn( + this, + "redirect-fn-version", + this.edgeFunction.currentVersion.edgeArn + ); + } +} diff --git a/packages/geoip-redirect/package.json b/packages/geoip-redirect/package.json new file mode 100644 index 00000000..532c5543 --- /dev/null +++ b/packages/geoip-redirect/package.json @@ -0,0 +1,34 @@ +{ + "name": "@aligent/cdk-geoip-redirect", + "version": "0.1.0", + "description": "A Cloudfront Lambda@Edge stack for performing redirection based on CloudFront-Viewer-Country", + "main": "index.js", + "scripts": { + "build": "tsc && cd ./lib/handlers && npm ci", + "prepublish": "tsc && cd ./lib/handlers && npm ci" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/aligent/aws-cdk-prerender-proxy-stack.git" + }, + "license": "GPL-3.0-only", + "bugs": { + "url": "https://github.com/aligent/aws-cdk-prerender-proxy-stack/issues" + }, + "homepage": "https://github.com/aligent/aws-cdk-prerender-proxy-stack#readme", + "devDependencies": { + "@types/jest": "^29.5.5", + "@types/node": "20.6.3", + "aws-cdk": "2.97.0", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.1", + "typescript": "~5.2.2" + }, + "dependencies": { + "@types/aws-lambda": "^8.10.122", + "aws-cdk-lib": "2.97.0", + "constructs": "^10.0.0", + "source-map-support": "^0.5.21" + } +} diff --git a/packages/geoip-redirect/tsconfig.json b/packages/geoip-redirect/tsconfig.json new file mode 100644 index 00000000..4082f16a --- /dev/null +++ b/packages/geoip-redirect/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +}