I'm running a simple web application that creates a JSON out of some data the user manipulates in a web UI. The page is served as a GitHub Pages hosted site. What I'm trying to do is to create a download link on that page which I pass through JavaScript's Blob API's to create a download URL that is programmatically clicked. The action, as shown below, is initiated by a user initiated click.
While doing this, I am intermittently seeing Chrome (Version 135.0.7049.115 (Official Build) (arm64)) and certain versions of Safari indicate 'sandbox' errors when clicking the button. I am not able to reproduce this on the Safari on my machine, but I do know that some folks had issues (ironically, some folks had older versions of Safari so it seems that newer versions are fine).
Error (Chrome):
Download is disallowed. The frame initiating or instantiating the download is sandboxed, but the flag ‘allow-downloads’ is not set. See https://www.chromestatus.com/feature/5706745674465280 for more details.*emphasized text*
As I understand this error, it is detecting that the download is being blocked because Chrome maybe does not think this is user initiated? Not quite sure what I could do to make this work since the event is very much user-triggered?
To try it out, paste into https://playcode.io/vue:
<script setup>
import {ref} from 'vue'
function generateRandomData() {
return {
id: Math.floor(Math.random() * 10000),
name: "User" + Math.floor(Math.random() * 1000),
email: "user" + Math.floor(Math.random() * 1000) + "@example.com",
timestamp: new Date().toISOString()
};
}
async function downloadBtn() {
console.log('VUE');
const data = generateRandomData();
const jsonStr = JSON.stringify(data, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'data.json';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
</script>
<template>
<h1>Hello Vue 3</h1>
<button @click="downloadBtn">DO NOT PRESS ME VUE</button>
</template>
<style scoped>
button {
font-weight: bold;
}
</style>
The code above works in the context of the playground, however, it fails when I try it on my hosted site. Note also that I am not using any iFrame's in this context either. I'm not sure why this is being flagged as a sandbox violation? It's 100% user initiated && not inside an iframe either. Not sure if the CSP (Content Security Policy) for my GitHub Pages site has anything to do with it.
Update: It turns out the host (privately hosted GitHub) is setting sandbox policy for its CSP which does not explicitly set 'allow-downloads'. As a result of this, we cannot use 'meta' tags in the HTML headers to override it. The only real options are to either workaround (force use to right click and save the Blob URL link) or to change the actual CSP policy on the server side.
Hope this helps someone who runs into this down the line.