-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
102 lines (89 loc) · 3.32 KB
/
index.js
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
101
102
function error(text) {
document.querySelector(".error").style.display = "inherit";
document.querySelector("#errortext").innerText = `Error: ${text}`;
}
// Run when the <body> loads
async function main() {
if (window.location.hash) {
// Fail if the b64 library or API was not loaded
if (!("b64" in window)) {
error("Base64 library not loaded.");
return;
}
if (!("apiVersions" in window)) {
error("API library not loaded.");
return;
}
// Try to get page data from the URL if possible
const hash = window.location.hash.slice(1);
let params;
try {
params = JSON.parse(b64.decode(hash));
} catch {
error("The link appears corrupted.");
return;
}
// Check that all required parameters encoded in the URL are present
if (!("v" in params && "e" in params)) {
error("The link appears corrupted. The encoded URL is missing necessary parameters.");
return;
}
// Check that the version in the parameters is valid
if (!(params["v"] in apiVersions)) {
error("Unsupported API version. The link may be corrupted.");
return;
}
const api = apiVersions[params["v"]];
// Get values for decryption
const encrypted = b64.base64ToBinary(params["e"]);
const salt = "s" in params ? b64.base64ToBinary(params["s"]) : null;
const iv = "i" in params ? b64.base64ToBinary(params["i"]) : null;
let hint, password;
if ("h" in params) {
hint = params["h"];
password = prompt(`Please enter the password to unlock the link.\n\nHint: ${hint}`);
} else {
password = prompt("Please enter the password to unlock the link.");
}
// Decrypt and redirect if possible
let url;
try {
url = await api.decrypt(encrypted, password, salt, iv);
} catch {
// Password is incorrect.
error("Password is incorrect.");
// Set the "decrypt without redirect" URL appropriately
document.querySelector("#no-redirect").href =
`https://wahyu9kdl.github.io/link-lock/decrypt/#${hash}`;
// Set the "create hidden bookmark" URL appropriately
document.querySelector("#hidden").href =
`https://wahyu9kdl.github.io/link-lock/hidden/#${hash}`;
return;
}
try {
// Extra check to make sure the URL is valid. Probably shouldn't fail.
let urlObj = new URL(url);
// Prevent XSS by making sure only HTTP URLs are used. Also allow magnet
// links for password-protected torrents.
if (!(urlObj.protocol == "http:"
|| urlObj.protocol == "https:"
|| urlObj.protocol == "magnet:")) {
error(`The link uses a non-hypertext protocol, which is not allowed. `
+ `The URL begins with "${urlObj.protocol}" and may be malicious.`);
return;
}
// IMPORTANT NOTE: must use window.location.href instead of the (in my
// opinion more proper) window.location.replace. If you use replace, it
// causes Chrome to change the icon of a bookmarked link to update it to
// the unlocked destination. This is dangerous information leakage.
window.location.href = url;
} catch {
error("A corrupted URL was encrypted. Cannot redirect.");
console.log(url);
return;
}
} else {
// Otherwise redirect to the creator
window.location.replace("./create");
}
}