I've been experimenting with Firebase code to upload/download files between my Windows 11 PC and my Firebase storage bucket. Once I'd got it working I realised that the code didn't include a login. Since I was using default Cloud Storage rules I would have expected my upload/download calls to have been bounced.
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
I cleared my browser cache and logged out of Google and the Firebase console to see if that made the problem go away. It didn't, and neither did a reboot. But then I was greatly relieved to find that the code errored as expected when it was run on an entirely separate machine. Running my code (now deployed onto the web) in this case produced the expected error:
"Oops - upload failed : error = FirebaseError: Firebase Storage: User does not have permission to access 'some-child'. (storage/unauthorized)".
But the problem persists on my development PC, so my question is, what could possibly be putting Firebase there into a state where Cloud storage rules are bypassed, allowing bucket access even though there's not a login?
Here's the (firebase v9) code I'm using (it allows me to upload a selected file on my PC to a file called 'some-child' in my storage bucket, and then download it to a file called demo.txt in my download folder). :
import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.4.0/firebase-app.js';
import { getAuth, GoogleAuthProvider, signInWithPopup } from 'https://www.gstatic.com/firebasejs/9.4.0/firebase-auth.js';
import { getStorage, ref, uploadBytes, getDownloadURL } from 'https://www.gstatic.com/firebasejs/9.4.0/firebase-storage.js';
const firebaseConfig = {
...
};
const firebaseApp = initializeApp(firebaseConfig);
const provider = new GoogleAuthProvider();
const auth = getAuth();
const storage = getStorage();
const storageRef = ref(storage, 'some-child');
window.onload = function () {
document.getElementById('fileitem').onchange = function () { uploadFile() };
document.getElementById('downloadbutton').onclick = function () { downloadFile() };
}
function uploadFile() {
var file = document.getElementById('fileitem').files[0];
uploadBytes(storageRef, file)
.then((snapshot) => {
alert('Successful upload');
})
.catch((error) => {
alert('Oops - upload failed : error = ' error);
});
}
function downloadFile() {
var file = getDownloadURL(ref(storage, 'some-child'))
.then((url) => {
// `url` is the download URL for 'some-child' and can be downloaded directly:
const xhr = new XMLHttpRequest();
xhr.responseType = 'text';
xhr.onload = (event) => {
const blob = xhr.response;
const a = document.getElementById('downloadanchor');
a.href = window.URL.createObjectURL(new Blob([blob], { type: "text/plain" }));
a.download = "demo.txt";
a.click();
alert('Successful download');
};
xhr.open('GET', url);
xhr.send();
})
.catch((error) => {
alert('Oops - download failed : error = ' error);
});
}
There's an html front-end for this of course. The guts of this are as follows:
<input id="fileitem" type="file"><br></br>
<button id="downloadbutton">Download</button>
<a id="downloadanchor" href="" download></a>
CodePudding user response:
It sounds like you signed a user in once, and never signed them out. Firebase persists the user credentials and restores them when the page is reloaded, and then sends it along with the calls to the database. This is usually exactly what you'd want, but here it seems to be getting in your way.
If you don't want to use authentication you can sign the user out by a one-time call to signOut`:
import { getAuth, ... } from "firebase/auth";
const auth = getAuth();
signOut(auth).then(() => {
// Sign-out successful.
}).catch((error) => {
// An error happened.
});