From 8e6a47d9d6500470a7c1fbfdf85236472c785653 Mon Sep 17 00:00:00 2001 From: Gavin Meredith Behr Date: Wed, 9 Oct 2024 16:29:49 +0100 Subject: [PATCH] Added Projects for direct Lambda Functions & Custom Authorizer --- .gitignore | 18 +-- UltimatePDFLambdaAuthorizer/Function.cs | 61 +++++++++ UltimatePDFLambdaAuthorizer/README.md | 15 +++ .../UltimatePDFLambdaAuthorizer.csproj | 16 +++ .../generate_upload_package.ps1 | 3 + UltimatePDFLambdaFunctions/Functions.cs | 117 ++++++++++++++++++ .../Inputs/PrintPDFInput.cs | 33 +++++ .../Inputs/PrintPDFToRestInput.cs | 33 +++++ .../Inputs/PrintPDFToS3Input.cs | 33 +++++ .../Inputs/ScreenshotPNGInput.cs | 35 ++++++ UltimatePDFLambdaFunctions/README.md | 6 + .../UltimatePDFLambdaFunctions.csproj | 20 +++ .../UltimatePDFLambdaFunctions.sln | 37 ++++++ .../generate_upload_package.ps1 | 3 + 14 files changed, 418 insertions(+), 12 deletions(-) create mode 100644 UltimatePDFLambdaAuthorizer/Function.cs create mode 100644 UltimatePDFLambdaAuthorizer/README.md create mode 100644 UltimatePDFLambdaAuthorizer/UltimatePDFLambdaAuthorizer.csproj create mode 100644 UltimatePDFLambdaAuthorizer/generate_upload_package.ps1 create mode 100644 UltimatePDFLambdaFunctions/Functions.cs create mode 100644 UltimatePDFLambdaFunctions/Inputs/PrintPDFInput.cs create mode 100644 UltimatePDFLambdaFunctions/Inputs/PrintPDFToRestInput.cs create mode 100644 UltimatePDFLambdaFunctions/Inputs/PrintPDFToS3Input.cs create mode 100644 UltimatePDFLambdaFunctions/Inputs/ScreenshotPNGInput.cs create mode 100644 UltimatePDFLambdaFunctions/README.md create mode 100644 UltimatePDFLambdaFunctions/UltimatePDFLambdaFunctions.csproj create mode 100644 UltimatePDFLambdaFunctions/UltimatePDFLambdaFunctions.sln create mode 100644 UltimatePDFLambdaFunctions/generate_upload_package.ps1 diff --git a/.gitignore b/.gitignore index 0e59184..434f0c1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,6 @@ -.vs/ -UltimatePDF_ExternalLogic/bin/ -UltimatePDF_ExternalLogic/obj/ -UltimatePDF_ExternalLogic.Tests/bin/ -UltimatePDF_ExternalLogic.Tests/obj/ - -TestLambda_UltimatePDF_ExternalLogic/.vs/ -TestLambda_UltimatePDF_ExternalLogic/src/TestLambda_UltimatePDF_ExternalLogic/.vs/ -TestLambda_UltimatePDF_ExternalLogic/src/TestLambda_UltimatePDF_ExternalLogic/bin/ -TestLambda_UltimatePDF_ExternalLogic/src/TestLambda_UltimatePDF_ExternalLogic/obj/ -TestLambda_UltimatePDF_ExternalLogic/src/TestLambda_UltimatePDF_ExternalLogic/Properties/launchSettings.json +.vs +bin +obj *.zip *.cache @@ -16,4 +8,6 @@ TestLambda_UltimatePDF_ExternalLogic/src/TestLambda_UltimatePDF_ExternalLogic/Pr *.dll *.br *.so -*.pdb \ No newline at end of file +*.pdb + +launchSettings.json \ No newline at end of file diff --git a/UltimatePDFLambdaAuthorizer/Function.cs b/UltimatePDFLambdaAuthorizer/Function.cs new file mode 100644 index 0000000..f0d96fb --- /dev/null +++ b/UltimatePDFLambdaAuthorizer/Function.cs @@ -0,0 +1,61 @@ +using Amazon.Lambda.APIGatewayEvents; +using Amazon.Lambda.Core; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace UltimatePDFLambdaAuthorizer +{ + public class Function + { + public APIGatewayCustomAuthorizerResponse FunctionHandler(APIGatewayCustomAuthorizerRequest request, ILambdaContext context) + { + var authorized = false; + + request.Headers.TryGetValue("Authorization", out string? authHeader); + + if (!string.IsNullOrWhiteSpace(authHeader)) { + var encodedCredentials = authHeader.Split(' ')[1]; + + byte[] data = Convert.FromBase64String(encodedCredentials); + var decodedCredentials = System.Text.Encoding.UTF8.GetString(data).Split(":"); + var username = decodedCredentials[0]; + var password = decodedCredentials[1]; + + // Sample credentials below for demostration purposes + // These details should be fetched from somewhere secure and configurable + if (username == "test" && password == "test") + { + authorized = true; + } + } + + APIGatewayCustomAuthorizerPolicy policy = new APIGatewayCustomAuthorizerPolicy + { + Version = "2012-10-17", + Statement = new List() + }; + + policy.Statement.Add(new APIGatewayCustomAuthorizerPolicy.IAMPolicyStatement + { + Action = new HashSet(new string[] { "execute-api:Invoke" }), + Effect = authorized ? "Allow" : "Deny", + Resource = new HashSet(new string[] { request.MethodArn }) + + }); + + APIGatewayCustomAuthorizerContextOutput contextOutput = new APIGatewayCustomAuthorizerContextOutput() + { + ["User"] = "User", + ["Path"] = request.MethodArn + }; + + return new APIGatewayCustomAuthorizerResponse + { + PrincipalID = "User", + Context = contextOutput, + PolicyDocument = policy + }; + } + } +} diff --git a/UltimatePDFLambdaAuthorizer/README.md b/UltimatePDFLambdaAuthorizer/README.md new file mode 100644 index 0000000..26d1186 --- /dev/null +++ b/UltimatePDFLambdaAuthorizer/README.md @@ -0,0 +1,15 @@ +This project is for illustration purposes only and provides a sample Custom Authorizer for use with AWS API Gateway endpoints using Basic Auth + +Step to execute the code: +1. Run .\generate_upload_package.ps1 +1. Create a AWS Lambda .net 6.0 runtime +1. Upload the zip UltimatePDFLambdaAuthorizer.zip as the lambda function code +1. Add the lambda function as a new request based custom authorizer on API gateway + + +To test the custom authorizer call an API Gateway endpoint that has the authorizer enabled using Basic Auth headers + +```text +// This header equates to Basic Auth with username: test | password: test +Authorization: Basic dGVzdDp0ZXM= +``` \ No newline at end of file diff --git a/UltimatePDFLambdaAuthorizer/UltimatePDFLambdaAuthorizer.csproj b/UltimatePDFLambdaAuthorizer/UltimatePDFLambdaAuthorizer.csproj new file mode 100644 index 0000000..d68170b --- /dev/null +++ b/UltimatePDFLambdaAuthorizer/UltimatePDFLambdaAuthorizer.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + true + true + + + + + + + + diff --git a/UltimatePDFLambdaAuthorizer/generate_upload_package.ps1 b/UltimatePDFLambdaAuthorizer/generate_upload_package.ps1 new file mode 100644 index 0000000..9ada0e7 --- /dev/null +++ b/UltimatePDFLambdaAuthorizer/generate_upload_package.ps1 @@ -0,0 +1,3 @@ +Set-ExecutionPolicy -Scope CurrentUser Unrestricted +dotnet publish -c Release -r linux-x64 --self-contained false +Compress-Archive -Path .\bin\Release\net6.0\linux-x64\publish\* -Update -DestinationPath UltimatePDFLambdaAuthorizer.zip -CompressionLevel Optimal \ No newline at end of file diff --git a/UltimatePDFLambdaFunctions/Functions.cs b/UltimatePDFLambdaFunctions/Functions.cs new file mode 100644 index 0000000..0df690e --- /dev/null +++ b/UltimatePDFLambdaFunctions/Functions.cs @@ -0,0 +1,117 @@ +using Amazon.Lambda.Core; +using UltimatePDFLambdaFunctions.Inputs; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace UltimatePDFLambdaFunctions +{ + /// + /// A class that will hold our AWS Function methods. + /// + public class Functions + { + /// + /// This function returns a base64 encoded string representation of the generated PDF + /// + /// + /// + /// Base64 encoded string representation of the generated PDF + public string PrintPDFFunctionHandler(PrintPDFInput input, ILambdaContext context) + { + var uri = new Uri(input.Url); + var ultimatePdfLib = new OutSystems.UltimatePDF_ExternalLogic.UltimatePDF_ExternalLogic(); + var environment = new OutSystems.UltimatePDF_ExternalLogic.Structures.Environment + { + BaseURL = uri.Host, + Locale = input.Environment.Locale, + Timezone = input.Environment.Timezone + }; + + var pdf = ultimatePdfLib.PrintPDF( + input.Url, + input.Viewport, + environment, + input.Cookies, + input.Paper, + input.TimeoutSeconds, + input.CollectLogs, + input.AttachFilesLogs, + out byte[] logsZipFile); + + return Convert.ToBase64String(pdf); + } + + public void PrintPDFToRestFunctionHandler(PrintPDFToRestInput input, ILambdaContext context) + { + var uri = new Uri(input.Url); + var ultimatePdfLib = new OutSystems.UltimatePDF_ExternalLogic.UltimatePDF_ExternalLogic(); + var environment = new OutSystems.UltimatePDF_ExternalLogic.Structures.Environment + { + BaseURL = uri.Host, + Locale = input.Environment.Locale, + Timezone = input.Environment.Timezone + }; + + ultimatePdfLib.PrintPDF_ToRest( + input.Url, + input.Viewport, + environment, + input.Cookies, + input.Paper, + input.TimeoutSeconds, + input.CollectLogs, + input.AttachFilesLogs, + input.RestCaller); + } + + public void PrintPDFToS3FunctionHandler(PrintPDFToS3Input input, ILambdaContext context) + { + var uri = new Uri(input.Url); + var ultimatePdfLib = new OutSystems.UltimatePDF_ExternalLogic.UltimatePDF_ExternalLogic(); + var environment = new OutSystems.UltimatePDF_ExternalLogic.Structures.Environment + { + BaseURL = uri.Host, + Locale = input.Environment.Locale, + Timezone = input.Environment.Timezone + }; + + ultimatePdfLib.PrintPDF_ToS3( + input.Url, + input.Viewport, + environment, + input.Cookies, + input.Paper, + input.TimeoutSeconds, + input.CollectLogs, + input.AttachFilesLogs, + input.S3Endpoints); + } + + public string ScreenshotPNGFunctionHandler(ScreenshotPNGInput input, ILambdaContext context) + { + var uri = new Uri(input.Url); + var ultimatePdfLib = new OutSystems.UltimatePDF_ExternalLogic.UltimatePDF_ExternalLogic(); + var environment = new OutSystems.UltimatePDF_ExternalLogic.Structures.Environment + { + BaseURL = uri.Host, + Locale = input.Environment.Locale, + Timezone = input.Environment.Timezone + }; + + var screenshot = ultimatePdfLib.ScreenshotPNG( + input.Url, + input.Viewport, + environment, + input.Cookies, + input.Paper, + input.ScreenshotOptions, + input.TimeoutSeconds, + input.CollectLogs, + input.AttachFilesLogs, + out byte[] logsZipFile); + + return Convert.ToBase64String(screenshot); + } + } +} diff --git a/UltimatePDFLambdaFunctions/Inputs/PrintPDFInput.cs b/UltimatePDFLambdaFunctions/Inputs/PrintPDFInput.cs new file mode 100644 index 0000000..0e8208f --- /dev/null +++ b/UltimatePDFLambdaFunctions/Inputs/PrintPDFInput.cs @@ -0,0 +1,33 @@ +using OutSystems.UltimatePDF_ExternalLogic.Structures; +using Environment = OutSystems.UltimatePDF_ExternalLogic.Structures.Environment; + +namespace UltimatePDFLambdaFunctions.Inputs +{ + public class PrintPDFInput + { + public string Url { get; init; } = String.Empty; + public Viewport Viewport { get; init; } = new Viewport { Width = 1366, Height = 768 }; + public Environment Environment { get; init; } = new Environment + { + BaseURL = "", + Locale = "en", + Timezone = "Europe/Lisbon" + }; + public IEnumerable Cookies { get; init; } = Array.Empty(); + public Paper Paper { get; init; } = new Paper + { + UseCustomPaper = false, + Width = 21, + Height = 29.7M, + UseCustomMargins = false, + MarginTop = 2.54M, + MarginRight = 2.54M, + MarginBottom = 2.54M, + MarginLeft = 2.54M + }; + public int TimeoutSeconds { get; init; } = 120; + public bool CollectLogs { get; init; } = false; + public bool AttachFilesLogs { get; init; } = false; + public byte[]? LogsZipFile { get; init; } = null; + } +} diff --git a/UltimatePDFLambdaFunctions/Inputs/PrintPDFToRestInput.cs b/UltimatePDFLambdaFunctions/Inputs/PrintPDFToRestInput.cs new file mode 100644 index 0000000..aef4aaa --- /dev/null +++ b/UltimatePDFLambdaFunctions/Inputs/PrintPDFToRestInput.cs @@ -0,0 +1,33 @@ +using OutSystems.UltimatePDF_ExternalLogic.Structures; +using Environment = OutSystems.UltimatePDF_ExternalLogic.Structures.Environment; + +namespace UltimatePDFLambdaFunctions.Inputs +{ + public class PrintPDFToRestInput + { + public string Url { get; init; } = String.Empty; + public Viewport Viewport { get; init; } = new Viewport { Width = 1366, Height = 768 }; + public Environment Environment { get; init; } = new Environment + { + BaseURL = "", + Locale = "en", + Timezone = "Europe/Lisbon" + }; + public IEnumerable Cookies { get; init; } = Array.Empty(); + public Paper Paper { get; init; } = new Paper + { + UseCustomPaper = false, + Width = 21, + Height = 29.7M, + UseCustomMargins = false, + MarginTop = 2.54M, + MarginRight = 2.54M, + MarginBottom = 2.54M, + MarginLeft = 2.54M + }; + public int TimeoutSeconds { get; init; } = 120; + public bool CollectLogs { get; init; } = false; + public bool AttachFilesLogs { get; init; } = false; + public RestCaller RestCaller { get; init; } = default; + } +} diff --git a/UltimatePDFLambdaFunctions/Inputs/PrintPDFToS3Input.cs b/UltimatePDFLambdaFunctions/Inputs/PrintPDFToS3Input.cs new file mode 100644 index 0000000..2b70f56 --- /dev/null +++ b/UltimatePDFLambdaFunctions/Inputs/PrintPDFToS3Input.cs @@ -0,0 +1,33 @@ +using OutSystems.UltimatePDF_ExternalLogic.Structures; +using Environment = OutSystems.UltimatePDF_ExternalLogic.Structures.Environment; + +namespace UltimatePDFLambdaFunctions.Inputs +{ + public class PrintPDFToS3Input + { + public string Url { get; init; } = String.Empty; + public Viewport Viewport { get; init; } = new Viewport { Width = 1366, Height = 768 }; + public Environment Environment { get; init; } = new Environment + { + BaseURL = "", + Locale = "en", + Timezone = "Europe/Lisbon" + }; + public IEnumerable Cookies { get; init; } = Array.Empty(); + public Paper Paper { get; init; } = new Paper + { + UseCustomPaper = false, + Width = 21, + Height = 29.7M, + UseCustomMargins = false, + MarginTop = 2.54M, + MarginRight = 2.54M, + MarginBottom = 2.54M, + MarginLeft = 2.54M + }; + public int TimeoutSeconds { get; init; } = 120; + public bool CollectLogs { get; init; } = false; + public bool AttachFilesLogs { get; init; } = false; + public S3Endpoints S3Endpoints { get; init; } = default; + } +} diff --git a/UltimatePDFLambdaFunctions/Inputs/ScreenshotPNGInput.cs b/UltimatePDFLambdaFunctions/Inputs/ScreenshotPNGInput.cs new file mode 100644 index 0000000..b6e6ae6 --- /dev/null +++ b/UltimatePDFLambdaFunctions/Inputs/ScreenshotPNGInput.cs @@ -0,0 +1,35 @@ +using OutSystems.UltimatePDF_ExternalLogic.Structures; +using Environment = OutSystems.UltimatePDF_ExternalLogic.Structures.Environment; + +namespace UltimatePDFLambdaFunctions.Inputs +{ + public class ScreenshotPNGInput + { + public string Url { get; init; } = String.Empty; + public Viewport Viewport { get; init; } = new Viewport { Width = 1366, Height = 768 }; + public Environment Environment { get; init; } = new Environment + { + BaseURL = "", + Locale = "en", + Timezone = "Europe/Lisbon" + }; + public IEnumerable Cookies { get; init; } = Array.Empty(); + public Paper Paper { get; init; } = new Paper + { + UseCustomPaper = false, + Width = 21, + Height = 29.7M, + UseCustomMargins = false, + MarginTop = 2.54M, + MarginRight = 2.54M, + MarginBottom = 2.54M, + MarginLeft = 2.54M + }; + public ScreenshotOptions ScreenshotOptions { get; init; } = new ScreenshotOptions { FullPage = true, TransparentBackground = true }; + public int TimeoutSeconds { get; init; } = 120; + public bool CollectLogs { get; init; } = false; + public bool AttachFilesLogs { get; init; } = false; + public byte[]? LogsZipFile { get; init; } = null; + + } +} diff --git a/UltimatePDFLambdaFunctions/README.md b/UltimatePDFLambdaFunctions/README.md new file mode 100644 index 0000000..9bef575 --- /dev/null +++ b/UltimatePDFLambdaFunctions/README.md @@ -0,0 +1,6 @@ +This project is for illustration purposes only and provides sample Lambda Function wrappers around UltimatePDF + +Step to execute the code: +1. Run .\generate_upload_package.ps1 +1. Create a AWS Lambda .net 6.0 runtime for each public method +1. Upload the zip UltimatePDFLambda.zip as the lambda function code \ No newline at end of file diff --git a/UltimatePDFLambdaFunctions/UltimatePDFLambdaFunctions.csproj b/UltimatePDFLambdaFunctions/UltimatePDFLambdaFunctions.csproj new file mode 100644 index 0000000..d2b2c6e --- /dev/null +++ b/UltimatePDFLambdaFunctions/UltimatePDFLambdaFunctions.csproj @@ -0,0 +1,20 @@ + + + + net6.0 + enable + enable + true + true + + + + + + + + + + + + diff --git a/UltimatePDFLambdaFunctions/UltimatePDFLambdaFunctions.sln b/UltimatePDFLambdaFunctions/UltimatePDFLambdaFunctions.sln new file mode 100644 index 0000000..7a6c8a8 --- /dev/null +++ b/UltimatePDFLambdaFunctions/UltimatePDFLambdaFunctions.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35201.131 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UltimatePDFLambdaFunctions", "UltimatePDFLambdaFunctions.csproj", "{73D0BB53-50D4-42FB-BA27-F74B937591CE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UltimatePDF_ExternalLogic", "..\UltimatePDF_ExternalLogic\UltimatePDF_ExternalLogic.csproj", "{5A58A2B0-B0C7-4B33-BB07-7250E8A0C21F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UltimatePDFLambdaAuthorizer", "..\UltimatePDFLambdaAuthorizer\UltimatePDFLambdaAuthorizer.csproj", "{D1F3C73A-DF2F-4FDB-9C6D-94189B60AFF9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {73D0BB53-50D4-42FB-BA27-F74B937591CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73D0BB53-50D4-42FB-BA27-F74B937591CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73D0BB53-50D4-42FB-BA27-F74B937591CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73D0BB53-50D4-42FB-BA27-F74B937591CE}.Release|Any CPU.Build.0 = Release|Any CPU + {5A58A2B0-B0C7-4B33-BB07-7250E8A0C21F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A58A2B0-B0C7-4B33-BB07-7250E8A0C21F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A58A2B0-B0C7-4B33-BB07-7250E8A0C21F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A58A2B0-B0C7-4B33-BB07-7250E8A0C21F}.Release|Any CPU.Build.0 = Release|Any CPU + {D1F3C73A-DF2F-4FDB-9C6D-94189B60AFF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D1F3C73A-DF2F-4FDB-9C6D-94189B60AFF9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D1F3C73A-DF2F-4FDB-9C6D-94189B60AFF9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D1F3C73A-DF2F-4FDB-9C6D-94189B60AFF9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C6C13398-6F14-4F23-8E61-4F0B09FC5484} + EndGlobalSection +EndGlobal diff --git a/UltimatePDFLambdaFunctions/generate_upload_package.ps1 b/UltimatePDFLambdaFunctions/generate_upload_package.ps1 new file mode 100644 index 0000000..4693e68 --- /dev/null +++ b/UltimatePDFLambdaFunctions/generate_upload_package.ps1 @@ -0,0 +1,3 @@ +Set-ExecutionPolicy -Scope CurrentUser Unrestricted +dotnet publish -c Release -r linux-x64 --self-contained false +Compress-Archive -Path .\bin\Release\net6.0\linux-x64\publish\* -Update -DestinationPath UltimatePDFLambda.zip -CompressionLevel Optimal \ No newline at end of file