Skip to content

Instantly share code, notes, and snippets.

@wiomoc
Created February 8, 2022 14:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wiomoc/94345d372d42e57ff95cc44957429eda to your computer and use it in GitHub Desktop.
Save wiomoc/94345d372d42e57ff95cc44957429eda to your computer and use it in GitHub Desktop.
AWS CloudFront Function for embedded Shopify Admin App
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;
}
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