html-over-dns/index.html
Jacob Kiers 4b117a4743 Add support for longer records
This makes it possible to handle more content in a single round.

Signed-off-by: Jacob Kiers <jacob@jacobkiers.net>
2021-08-21 11:17:50 +02:00

147 lines
3.7 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Blog over DNS</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.2.0/build/styles/default.min.css">
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.2.0/build/highlight.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
class Content {
content = "";
type = "";
metaData = {}
constructor(content, type, metaData = {})
{
this.content = content;
this.type = type;
this.metaData = metaData;
}
}
class Index
{
mimeType = "";
chunks = 0;
hash = "";
metaData = {};
constructor(mimeType, chunks, hash, metaData = {})
{
this.mimeType = mimeType;
this.chunks = chunks;
this.hash = hash;
this.metaData = metaData
}
}
const dohServer = "https://cloudflare-dns.com/dns-query?ct=application/dns-json&type=TXT&name=";
const baseDomain = "hod.experiments.jacobkiers.net";
async function readUrl(domain) {
var index = await fetchIndex(`${domain}.${baseDomain}`);
var chunk_promises = [];
for(i = 0; i < index.chunks; i++)
{
chunk_promises[i] = fetchChunk(i, index.hash);
}
const chunks = await Promise.all(chunk_promises);
const base64 = chunks.reduce((built, current) => built += current);
return handleContent(new Content(atob(content), index.mimeType, index.metaData));
}
async function fetchChunk(id, hash)
{
const domain = `${id}.${hash}.${baseDomain}`;
return await fetchData(domain);
}
async function fetchData(domain)
{
const json = await fetch(`${dohServer}${domain}`)
.then(response => response.json());
const raw_data = json.Answer[0].data;
const data = raw_data.replaceAll(/[\s\"]/g, '');
return data;
}
async function fetchIndex(domain)
{
const index = await fetchData(domain);
let ret = {};
let items = index.split(';');
items.forEach(item => {
let md = item.split('=');
let key = md[0];
let value = md[1];
ret[key] = value;
});
const metadata = JSON.parse(atob(ret["m"]));
return new Index(ret["t"], ret["c"], ret["h"], metadata);
}
function handleContent(content)
{
if (!content instanceof Content) {
console.log("Not valid content in handleContent.")
return;
}
switch(content.type)
{
case "text/javascript":
return handleJavascript(content);
case "text/markdown":
return handleMarkdown(content);
default:
console.log(`handleContent() does not know how to parse ${content.type}`);
break;
}
}
function handleJavascript(content)
{
console.log("Got some javascript!", content.content);
}
async function handleMarkdown(content)
{
console.log("Got me some markdown!");
marked.setOptions({
highlight: function(code, lang) {
return hljs.highlight(lang, code).value;
},
// langPrefix: ''
});
if (content.metaData.title != undefined) document.title = content.metaData.title;
document.getElementById("post").innerHTML = marked(content.content);
let title = document.createElement("h1");
title.innerHTML = content.metaData.title;
document.getElementById("post").prepend(title)
document.getElementById("nojs").style.visibility = "hidden";
}
</script>
</head>
<body>
<script>
readUrl("posts-2021-08-17-serving-blog-content-over-dns-md");
</script>
<div id="post"></div>
<div id="nojs">
<h1>HTML over DNS</h1>
<p>The content of this page is fetched using DNS over HTTP. Since that requires Javascript, please enable that to see the content.</p>
</div>
</body>
</html>