/
redirect.js
90 lines (84 loc) · 2.93 KB
/
redirect.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
require('dotenv').config()
const fs = require('fs')
const defaultRedirectURL = getEnv('DEFAULT_REDIRECT_URL')
exports.handler = async event => {
const {host} = event.headers
const {code} = event.queryStringParameters
if (!code) {
console.log(`no code query param provided`)
return getResponse()
}
const codeLength = code.length
if (codeLength > 20) {
console.log(
`short code "${code}" is ${codeLength} characters long. Sounds fishy.`,
)
return getResponse()
}
try {
const apiKey = getEnv('AIRTABLE_KEY')
const base = getEnv('AIRTABLE_BASE')
const table = getEnv('AIRTABLE_TABLE', 'URLs')
const shortCodeField = getEnv('AIRTABLE_SHORT_CODE_FIELD', 'Short Code')
const longLinkField = getEnv('AIRTABLE_LONG_LINK_FIELD', 'Long Link')
const Airtable = require('airtable')
console.log(`Attempting to get long link for code "${code}"`)
const result = await new Airtable({apiKey})
.base(base)(table)
.select({
maxRecords: 1,
fields: [longLinkField],
filterByFormula: `{${shortCodeField}} = "${code}"`,
})
.firstPage()
const longLink = result[0].get(longLinkField)
if (longLink) {
return getResponse({longLink, statusCode: 301})
} else {
console.log(`There was no Long Link associated with "${code}".`)
return getResponse()
}
} catch (error) {
if (error.stack) {
console.log(error.stack)
} else {
console.log(error)
}
console.log('!! there was an error and we are ignoring it... !!')
}
return getResponse()
function getResponse({longLink = defaultRedirectURL, statusCode = 302} = {}) {
console.log(`> redirecting to ${longLink}`)
const title = `${host}/${code || ''}`
const body = `<html><head><title>${title}</title></head><body><a href="${longLink}">moved here</a></body>`
const cacheHeaders = JSON.parse(getEnv('ENABLE_CACHE', 'false'))
? {
// entirely disable the cache for now until I can find a way
// for the cache to take the query paremeter into consideration
'Cache-Control': 'public, max-age=10080', // 10080 seconds is 1 week
// this is set by the redirect logic because the query string
// is not taken into account by the caching mechanism for some reason
Vary: 'X-Short-Code',
'X-Short-Code': code, // may as well return it just in case I guess?
}
: null
return {
statusCode,
body,
headers: {
Location: longLink,
...cacheHeaders,
// these headers I got by curling a bit.ly URL
// and just doing what they do.
'Content-Length': String(body.length),
'Content-Type': 'text/html; charset=utf-8',
Connection: 'close',
'Content-Security-Policy': 'referrer always',
'Referrer-Policy': 'unsafe-url',
},
}
}
}
function getEnv(name, defaultValue) {
return process.env[name] || defaultValue
}