forked from mnapoli/serverless-pdf-generator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhandler.js
133 lines (116 loc) · 3.33 KB
/
handler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
'use strict';
const chromium = require('chrome-aws-lambda');
const puppeteer = chromium.puppeteer;
const crypto = require('crypto');
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const bucketName = process.env.STORAGE_BUCKET;
if (!bucketName) {
throw 'The STORAGE_BUCKET environment variable is not defined';
}
const domainWhitelistString = process.env.DOMAIN_WHITELIST;
if (!domainWhitelistString) {
throw 'The DOMAIN_WHITELIST environment variable is not defined';
}
const domainWhitelist = domainWhitelistString.split(',');
console.log('Whitelisted domains: ' + domainWhitelist.join(', '));
module.exports.index = async (event, context) => {
if (!event.queryStringParameters || !event.queryStringParameters.url) {
return {
statusCode: 400,
body: JSON.stringify('A URL must be provided: /?url=<url to export to pdf>'),
}
}
const url = event.queryStringParameters.url;
const force = event.queryStringParameters.force;
// Check that the URL is in the whitelist
if (!isWhitelisted(url)) {
return {
statusCode: 400,
body: JSON.stringify(`The URL ${url} is not a whitelisted URL`),
}
}
// The file name will be a hash of the URL
const s3Key = sha1(url) + '.pdf';
let pdf = null;
if (!force) {
try {
// Fetch the PDF file
const s3Response = await s3.getObject({
Bucket: bucketName,
Key: s3Key,
}).promise();
pdf = s3Response.Body;
} catch (e) {
// If not found, the `pdf` variable will be null
if (e.code !== 'NoSuchKey') throw e;
}
}
if (!pdf) {
pdf = await createPdf(url);
await s3.putObject({
Bucket: bucketName,
Key: s3Key,
Body: pdf,
ContentType: 'application/pdf',
}).promise();
}
let s3pdfurl = s3.getSignedUrl('getObject',{
Bucket: bucketName,
Key: s3Key,
})
return {
statusCode: 302,
headers: {
Location: s3pdfurl
}
};
};
/**
* @param url
* @returns {Promise<Buffer>}
*/
async function createPdf(url) {
let browser = null;
try {
browser = await puppeteer.launch({
args: chromium.args,
executablePath: await chromium.executablePath,
headless: chromium.headless,
defaultViewport: {width: 1280, height: 800, deviceScaleFactor: 2},
});
const page = await browser.newPage();
await page.goto(url, {
waitUntil: ['domcontentloaded', 'networkidle0'],
});
return await page.pdf({
displayHeaderFooter: true,
format: 'A4',
printBackground: false,
});
} finally {
if (browser) {
await browser.close();
}
}
}
/**
* @param string
* @returns {string}
*/
function sha1(string) {
return crypto.createHash('sha1').update(string).digest('hex');
}
function isWhitelisted(url) {
const urlDomain = (new URL(url)).hostname;
if (domainWhitelist.includes(urlDomain)) {
return true;
}
// support subdomains
for (let domain of domainWhitelist) {
if (urlDomain.endsWith('.' + domain)) {
return true;
}
}
return false;
}