Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Readme

Shortlinks for the decentralised web

This is a script to allow API-based updating of the shortlinks/redirects in an IPFS-based shortlink repo (using val.town). I've written up how all this works on my blog at https://byjp.me/posts/link-shortener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { shortlink_domain } from "https://esm.town/v/byjp/shortlink_domain";
import { shortlink_repo } from "https://esm.town/v/byjp/shortlink_repo";
import { fetch } from "https://esm.town/v/std/fetch";
import { Buffer } from "node:buffer";
export const addShortlink = async (
req: express.Request,
res: express.Response,
) => {
const { to } = req.query;
const shortlink = req.path;
if (!/^Bearer github_pat_/.test(req.get("Authorization"))) {
res.status(401).send("Github PAT authentication required");
return;
}
if (!/^\/[a-zA-Z0-9][a-zA-Z0-9-]*$/.test(shortlink)) {
res.status(400).send("Invalid shortlink code, must be alphanumeric");
return;
}
const check = await fetch(
`https://${shortlink_domain}${shortlink}`,
{
method: "HEAD",
},
);
switch (check.status) {
case 200:
res.status(409).send(`The '${shortlink}' shortlink already exists`);
return;
case 404:
// This is as expected
break;
default:
res.status(500).send(
`The shortlink service isn't responding as expected (${check.status}): ${check.statusText}`,
);
return;
}
try {
const dest = new URL(to);
if (dest.hostname === shortlink_domain) {
res.status(400).send("Self-referencing shortlinks aren't allowed");
return;
}
}
catch (err) {
res.status(400).send(`Invalid destination URL: ${err.message}}`);
return;
}
const headers = {
Accept: "application/vnd.github+json",
Authorization: req.get("Authorization"),
"X-GitHub-Api-Version": "2022-11-28",
};
const path = `https://api.github.com/repos/${shortlink_repo}/contents/public/_redirects`;
const getRes = await fetch(path, {
method: "GET",
headers,
});
switch (getRes.status) {
case 200:
// All is well
break;
case 403:
res.status(500).send(
`Github is reporting a 403; public/_redirects from ${shortlink_repo} isn't accessible by the access token you're using`,
);
case 404:
res.status(500).send(
`Github is reporting a 404; public/_redirects doesn't exist in ${shortlink_repo}, or the access token you're using doesn't have read/write permissions.`,
);
default:
res.status(500).send(
`Github unavailable at ${path} (${getRes.status}): ${getRes.statusText}`,
);
return;
}
const ghJson = await getRes.json();
const sha = ghJson.sha;
let redirects = atob(ghJson.content);
redirects = `${shortlink} ${to} 302\n${redirects}`;
const putRes = await fetch(path, {
method: "PUT",
headers,
body: JSON.stringify({
message: `Adding '${shortlink}' shortlink via API`,
content: Buffer.from(redirects).toString("base64"),
sha,
}),
});
switch (putRes.status) {
case 200:
res.status(200).send(
`Shortlink added: https://${shortlink_domain}${shortlink}${to}\nTry it in a few mintes, when the change has deployed.`,
);
return;
case 404:
res.status(401).send(
`Github is reporting a 404 when trying to update, this probably means your access token doesn't have permission to edit public/_redirects in ${shortlink_repo}`,
);
anonymous-untitled_roseoctopus.express.val.run
December 9, 2023