diff --git a/src/fetcher.js b/src/fetcher.js
index b6e2918..783f5c9 100644
--- a/src/fetcher.js
+++ b/src/fetcher.js
@@ -64,32 +64,55 @@ function not_found_response() {
)
}
+function forbidden_response() {
+ return response(
+ 403, 'Forbidden',
+ Buffer.from('
404 Not Found403 Forbidden
Intergalactic'),
+ {'Content-Type': 'text/html; charset=utf-8'}
+ )
+}
+
self.addEventListener('fetch', (event) => {
if (!event.request.url.startsWith(self.location.origin)) {
- return console.log('Fetch not in scope:', event.request.url)
+ return console.log('fetch not in scope:', event.request.url)
}
console.log('handling fetch event:', event.request.url)
- const url = new URL(event.request.url)
- const multihash = url.pathname
+ const request_path = (new URL(event.request.url)).pathname
// If this isn't an IPFS URL, bail.
- if (!multihash.startsWith('/ipfs/')) {
- console.log('not a valid IPFS hash:', multihash)
- if (multihash != '/bundle.js' && multihash != '/fetcher.js') {
+ if (!request_path.startsWith('/ipfs/')) {
+ console.log('not a valid IPFS hash:', request_path)
+ if (request_path != '/bundle.js' && request_path != '/fetcher.js') {
event.respondWith(not_found_response())
}
return
}
+ // If this is a same-origin or CORS request, and it's not to a URL within the same base IPFS
+ // hash, then block it as forbidden. This in effect gives each base IPFS hash its own origin.
+ if (event.request.mode == 'same-origin' || event.request.mode == 'cors') {
+ let matches = /^(\/ipfs\/\w*)/.exec((new URL(event.request.referrer)).pathname)
+ let referrer_base_path = matches[1]
+ if (referrer_base_path && !request_path.startsWith(referrer_base_path)) {
+ console.log(
+ 'denying ' + event.request.mode + ' request from referrer with different base hash:',
+ event.request.referrer
+ )
+ event.respondWith(forbidden_response())
+ return
+ }
+ }
+
+
if (!ipfs_initialized) {
ipfs_initialized = initialize_ipfs()
}
event.respondWith(
ipfs_initialized.then(() => {
- return node.files.get(multihash)
+ return node.files.get(request_path)
}).then((files) => {
// If there's just one result, return it.
if (files.length == 1 && files[0].content) {