forked from mozilla/srihash.org
-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.js
162 lines (133 loc) · 5.35 KB
/
app.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/* global copyText */
"use strict";
function getErrorText(url) {
const printableURL = encodeURI(url);
if (url.startsWith("http://") || url.startsWith("https://")) {
return `
Could not fetch from URL <em><a href="${printableURL}">${printableURL}</a></em>.<br>
Your issue could be one of the following:
<ul>
<li>The URL does not exist.
<li>The URL does not support <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">Cross-Origin Resource Sharing (CORS)</a>,
when it should send a response header like <code>Access-Control-Allow-Origin: *</code>
</ul>
Please see your <a href="https://developer.mozilla.org/en-US/docs/Tools">Browser Developer Tools</a> for additional details.
`;
}
return `Could not fetch from <em>${printableURL}</em>, which doesn't look like a valid URL.`;
}
function resetInterface() {
console.log(
"Please ignore SRI warnings above this line, as they are part of the SRI support check (badge at the bottom of the page)."
);
document.getElementById("sri-snippet").innerText = "";
document.getElementById("sri-error").innerText = "";
if (document.getElementById("sri-copy")) {
document.getElementById("sri-copy").remove();
}
document.getElementById("sri-snippet").classList.remove('is-active');
}
function digestName(hashAlgorithm) {
switch (hashAlgorithm) {
case "sha256": return "SHA-256";
case "sha384": return "SHA-384";
case "sha512": return "SHA-512";
default: return "SHA-384";
}
}
async function hashText(buffer, algorithm) {
const digest = await crypto.subtle.digest(digestName(algorithm), buffer);
return digest;
}
function parseContentType(type) {
if (!type) {
return "script";
}
const fileType = type.split(";");
const REGEX = /^text\/css$/;
const isStylesheet = REGEX.test(fileType[0]);
if (isStylesheet) {
return 'style';
}
return 'script';
}
async function integrityMetadata(buffer, algorithm) {
const hashBuffer = await hashText(buffer, algorithm);
const base64string = btoa(
String.fromCharCode(...new Uint8Array(hashBuffer))
);
return `${algorithm}-${base64string}`;
}
function checkBrowserDependency(url) {
const URL_LIST = [
'fonts.googleapis.com'
];
const u = new URL(url);
const hostName = u.hostname;
if (URL_LIST.includes(hostName)) {
return [true, hostName];
}
return [false, hostName];
}
function displayResult(resultDiv, url, contentType, integrity) {
resultDiv.classList.add("is-active");
if (contentType === "script") {
const scriptEl = `<span style="color: #ffa07a"><script src=</span><span style="color:#abe338">"${encodeURI(
url
)}"</span> <span style="color: #ffa07a">integrity=</span><span style="color:#abe338">"${integrity}"</span> <span style="color: #ffa07a">crossorigin=</span><span style="color:#abe338">"anonymous"</span><span style="color: #ffa07a">></script></span>`;
resultDiv.innerHTML = scriptEl;
} else {
const linkEl = `<span style="color: #ffa07a"><link rel=<span style="color:#abe338">"stylesheet"</span> href=</span><span style="color:#abe338">"${encodeURI(
url
)}"</span> <span style="color: #ffa07a">integrity=</span><span style="color:#abe338">"${integrity}"</span> <span style="color: #ffa07a">crossorigin=</span><span style="color:#abe338">"anonymous"</span><span style="color: #ffa07a">></span>`;
resultDiv.innerHTML = linkEl;
}
const copyButton = `<button id="sri-copy">Copy</button>`;
console.log("It's working");
resultDiv.insertAdjacentHTML('afterend', copyButton);
const sriCopy = document.getElementById("sri-copy");
sriCopy.addEventListener("click", () => {
copyText(resultDiv.innerText);
});
const [isBrowserDependent, domain] = checkBrowserDependency(url);
const warningElement = document.getElementById("warning");
if (warningElement) {
warningElement.remove();
}
if (!isBrowserDependent) {
return;
}
const warning = `<div id="warning">This integrity hash might not work on browsers other than the one you are currently using since ${domain} serves different contents depending on browsers.</div>`;
sriCopy.insertAdjacentHTML('afterend', warning);
}
async function formSubmit(event) {
event.preventDefault();
resetInterface();
const inputEl = document.getElementById("url");
const hashEl = document.getElementById("sriHash");
const url = inputEl.value;
const resultDiv = document.getElementById("sri-snippet");
const errorDiv = document.getElementById("sri-error");
console.info("Trying", url);
try {
const response = await fetch(url);
console.info("Response", response);
if (response.status === 200) {
const type = response.headers.get("content-type");
const contentType = parseContentType(type);
const buffer = await response.arrayBuffer();
const hashAlgorithm = hashEl.value;
const integrity = await integrityMetadata(buffer, hashAlgorithm);
displayResult(resultDiv, url, contentType, integrity);
} else {
console.error("Non-OK HTTP response status. Error.");
errorDiv.innerHTML = getErrorText(url);
}
} catch (e) {
console.error("Fetch Error: ", e);
errorDiv.innerHTML = getErrorText(url);
}
}
addEventListener("DOMContentLoaded", () => {
document.getElementById("sri-form").addEventListener("submit", formSubmit);
});