Created
February 8, 2022 14:46
-
-
Save wiomoc/94345d372d42e57ff95cc44957429eda to your computer and use it in GitHub Desktop.
AWS CloudFront Function for embedded Shopify Admin App
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function handler(event) { | |
const { request } = event; | |
const { headers, querystring } = request; | |
const clientId = process.env.SHOPIFY_API_KEY; | |
const clientSecret = process.env.SHOPIFY_API_SECRET; | |
const scopes = process.env.SCOPES; | |
const shop = querystring["shop"]; | |
if (!shop || !shop.value) { | |
return { | |
statusCode: 404, | |
statusDescription: 'Not Found', | |
} | |
} | |
if (!querystring["host"]) { | |
const redirectUri = process.env.BASE_URL; | |
return { | |
statusCode: 302, | |
statusDescription: 'Found', | |
headers: { | |
"location": { | |
"value": `https://${shop.value}/admin/oauth/authorize?client_id=${clientId}&scope=${scopes}&redirect_uri=${redirectUri}` | |
} | |
} | |
}; | |
} | |
function objectToQueryString(obj, hmac) { | |
const str = []; | |
for (const param in obj) | |
if (obj[param].multiValue) { | |
const { multiValue } = obj[param]; | |
if (hmac) { | |
str.push(`${param.substring(0, param.length - 2)}=[${multiValue.map(({ value }) => `"${value}"`).join(', ')}]`); | |
} else { | |
for (const i in multiValue) { | |
str.push(`${param}=${multiValue[i].value}`); | |
} | |
} | |
} | |
else if (obj[param].value === '') | |
str.push(param); | |
else | |
str.push(param + "=" + obj[param].value); | |
return str.join("&"); | |
} | |
//checkHmac | |
let hmac = null | |
const filteredQuerystringParams = [] | |
for (const param in querystring) { | |
if (param !== "hmac") | |
filteredQuerystringParams.push(param) | |
else | |
hmac = querystring[param].value | |
} | |
if (!hmac) { | |
return { | |
statusCode: 401, | |
statusDescription: 'hmac missing', | |
} | |
} | |
filteredQuerystringParams.sort() | |
const filteredQuerystring = {} | |
for (const param of filteredQuerystringParams) { | |
filteredQuerystring[param] = querystring[param] | |
} | |
const generatedHash = require('crypto') | |
.createHmac('sha256', clientSecret) | |
.update(objectToQueryString(filteredQuerystring, true)) | |
.digest('hex'); | |
if (hmac !== generatedHash) { | |
return { | |
statusCode: 403, | |
statusDescription: 'hmac mismatch', | |
} | |
} | |
const timestamp = querystring["timestamp"] | |
if (timestamp && parseInt(timestamp.value) + 24 * 60 * 60 < new Date().valueOf() / 1000) { | |
return { | |
statusCode: 403, | |
statusDescription: 'timestamp too old', | |
} | |
} | |
if (headers["sec-fetch-dest"] && headers["sec-fetch-dest"].value === "document") { | |
return { | |
statusCode: 302, | |
statusDescription: 'Found', | |
headers: { | |
"location": { | |
"value": `https://${shop.value}/admin/apps/${clientId}/?${objectToQueryString(querystring)}` | |
} | |
} | |
}; | |
} | |
request.uri = "/index.html"; | |
return request; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function handler(event) { | |
var shop = event.request.querystring["shop"]; | |
var response = event.response; | |
response.headers["content-security-policy"] = {value: `frame-ancestors https://${shop.value} https://admin.shopify.com;`}; | |
return response; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment