summaryrefslogtreecommitdiff
path: root/static/src
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2021-08-03 15:20:32 -0600
committerBrian Picciano <mediocregopher@gmail.com>2021-08-03 15:20:32 -0600
commitec4aac24abc35fcf192c13a3fc9b2b65875c3444 (patch)
tree47fc25a28925459c2f4df9affea24559ca9b7a91 /static/src
parent20b92130106007585cbdde73f6622428d9cf68c8 (diff)
got pow working on the subscribe endpoint
Diffstat (limited to 'static/src')
-rw-r--r--static/src/assets/solvePow.js28
-rw-r--r--static/src/follow.md123
2 files changed, 144 insertions, 7 deletions
diff --git a/static/src/assets/solvePow.js b/static/src/assets/solvePow.js
new file mode 100644
index 0000000..900400c
--- /dev/null
+++ b/static/src/assets/solvePow.js
@@ -0,0 +1,28 @@
+const fromHexString = hexString =>
+ new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
+
+const toHexString = bytes =>
+ bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
+
+onmessage = async (e) => {
+ const seed = fromHexString(e.data.seedHex);
+ const target = e.data.target;
+
+ const fullBuf = new ArrayBuffer(seed.byteLength*2);
+
+ const fullBufSeed = new Uint8Array(fullBuf, 0, seed.byteLength);
+ seed.forEach((v, i) => fullBufSeed[i] = v);
+
+ const randBuf = new Uint8Array(fullBuf, seed.byteLength);
+
+ while (true) {
+ crypto.getRandomValues(randBuf);
+ const digest = await crypto.subtle.digest('SHA-512', fullBuf);
+ const digestView = new DataView(digest);
+ if (digestView.getUint32(0) < target) {
+ postMessage(toHexString(randBuf));
+ return;
+ }
+ }
+
+};
diff --git a/static/src/follow.md b/static/src/follow.md
index 8093267..4e949dd 100644
--- a/static/src/follow.md
+++ b/static/src/follow.md
@@ -6,7 +6,121 @@ nofollow: true
Here's your options for receiving updates about new blog posts:
-## Option 1: RSS
+## Option 1: Email
+
+Email is by far my preferred option for notifying followers of new posts.
+
+The entire email list system for this blog, from storing subscriber email
+addresses to the email server which sends the notifications out, has been
+designed from scratch and is completely self-hosted in my living room.
+
+I solemnly swear that:
+
+* You will never receive an email from this blog except to notify of a new post.
+
+* Your email will never be provided or sold to anyone else for any reason.
+
+With all that said, if you'd like to receive an email everytime a new blog post
+is published then input your email below and smash that subscribe button!
+
+<style>
+
+#emailStatus.success {
+ color: green;
+}
+
+#emailStatus.fail {
+ color: red;
+}
+
+</style>
+
+<input type="email" placeholder="name@host.com" id="emailAddress" />
+<input class="button-primary" type="submit" value="Subscribe" id="emailSubscribe" />
+<span id="emailStatus"></span>
+
+<script>
+const emailAddress = document.getElementById("emailAddress");
+const emailSubscribe = document.getElementById("emailSubscribe");
+const emailSubscribeOrigValue = emailSubscribe.value;
+const emailStatus = document.getElementById("emailStatus");
+
+const solvePow = async (seedHex, target) => {
+
+ const worker = new Worker('/assets/solvePow.js');
+
+ const p = new Promise((resolve, reject) => {
+ worker.postMessage({seedHex, target});
+ worker.onmessage = resolve;
+ });
+
+ const solutionHex = (await p).data;
+ worker.terminate();
+
+ return solutionHex;
+}
+
+emailSubscribe.onclick = async () => {
+
+ emailSubscribe.disabled = true;
+ emailSubscribe.className = "";
+ emailSubscribe.value = "Please hold...";
+
+ await (async () => {
+
+ setErr = (errStr, retry) => {
+ emailStatus.className = "fail";
+ emailStatus.innerHTML = errStr
+ if (retry) emailStatus.innerHTML += " (please try again)";
+ };
+
+ if (!window.isSecureContext) {
+ setErr("The browser environment is not secure.", false);
+ return;
+ }
+
+ const getPowReq = new Request('/api/pow/challenge');
+ const res = await fetch(getPowReq)
+ .then(response => response.json())
+
+ if (res.error) {
+ setErr(res.error, true);
+ return;
+ }
+
+ const powSol = await solvePow(res.seed, res.target);
+
+ const subscribeForm = new FormData();
+ subscribeForm.append('powSeed', res.seed);
+ subscribeForm.append('powSolution', powSol);
+ subscribeForm.append('email', emailAddress.value);
+
+ const subscribeReq = new Request('/api/mailinglist/subscribe', {
+ method: 'POST',
+ body: subscribeForm,
+ });
+
+ const subRes = await fetch(subscribeReq)
+ .then(response => response.json());
+
+ if (subRes.error) {
+ setErr(subRes.error, true);
+ return;
+ }
+
+ emailStatus.className = "success";
+ emailStatus.innerHTML = "Verification email sent (check your spam folder)";
+
+ })();
+
+ emailSubscribe.disabled = false;
+ emailSubscribe.className = "button-primary";
+ emailSubscribe.value = emailSubscribeOrigValue;
+};
+
+</script>
+
+## Option 2: RSS
RSS is the classic way to follow any blog. It comes from a time before
aggregators like reddit and twitter stole the show, when people felt capable to
@@ -31,14 +145,9 @@ recommendations:
iPhone/iPad/Mac devices, so I'm told. Their homepage description makes a much
better sales pitch for RSS than I ever could.
-## Option 2: Twitter
+## Option 3: Twitter
New posts are automatically published to [my Twitter](https://twitter.com/{{
site.twitter_username }}). Simply follow me there and pray the algorithm smiles
upon my tweets enough to show them to you! :pray: :pray: :pray:
-## Option 3: Email?
-
-I tried setting up an RSS-to-Email list thing on Mailchimp but it doesn't seem
-to like my RSS feed. If anyone knows a better alternative please [email
-me.](mailto:mediocregopher@gmail.com)