Skip to content

Instantly share code, notes, and snippets.

@tyte
Created April 30, 2022 14:28
Show Gist options
  • Save tyte/293a93d3bdd3cbd6bbba83142e252385 to your computer and use it in GitHub Desktop.
Save tyte/293a93d3bdd3cbd6bbba83142e252385 to your computer and use it in GitHub Desktop.
JS encode third party code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Dragon Trainer Monthly - Author Data</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style type="text/css">
body {
margin: 0 auto;
max-width: 40em;
width: 88%;
}
article {
margin-bottom: 3em;
}
</style>
</head>
<body>
<h1>Dragon Trainer Monthly - Author Data</h1>
<div id="app"></div>
<script>
// Get the app element
let app = document.querySelector('#app');
/**
* Find the first matching author
* @param {String} name The author name
* @param {Array} authors The author details
* @return {Array} The author
*/
function getAuthor (name, authors) {
return authors.find(function (author) {
return author.author === name;
});
}
/**
* Render an error message if fetch fails
*/
function renderFail () {
app.innerHTML = '<p>The dragons burned all the copies. Unable to get new articles at this time. Sorry!</p>';
}
/**
* Render articles into the DOM
* @param {Array} articles The articles to render
* @param {Array} authors The author details
*/
function render (articles, authors) {
// If there are no articles to show
if (!articles || articles.length < 1) {
renderFail();
return;
}
// Create a new array of markup strings with array.map(), then
// Combine them into one string with array.join(), then
// Insert them into the DOM with innerHTML
app.innerHTML = articles.map(function (article) {
let author = getAuthor(article.author, authors);
return `
<article>
<h2><a href="${encodeHTML(article.url)}">${encodeHTML(article.title)}</a></h2>
<p><em>By ${author ? `${encodeHTML(author.author)} - ${encodeHTML(author.bio)}` : encodeHTML(article.author)}</em></p>
<p>${article.article}</p>
</article>`;
}).join('');
}
// Get articles
Promise.all([
fetch('https://vanillajsacademy.com/api/dragons.json'),
fetch('https://vanillajsacademy.com/api/dragons-authors.json'),
]).then(function (responses) {
return Promise.all(responses.map(function (response) {
return response.json();
}));
}).then(function (data) {
// Render them into the DOM
render(data[0].articles, data[1].authors);
}).catch(function (error) {
console.warn(error);
renderFail();
});
/**
* Encode the HTML in a user-submitted string
* https://portswigger.net/web-security/cross-site-scripting/preventing
* @param {String} str The user-submitted string
* @return {String} str The sanitized string
*/
function encodeHTML (str) {
return str.replace(/data:/gi, '').replace(/javascript:/gi, '').replace(/[^\w-_. ]/gi, function (c) {
return `&#${c.charCodeAt(0)};`;
});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment