how to download a publicly shared file from google drive in a browser using fetch and without using google authentication - fetch

I would like to fetch a file using javascript from a browser client for a file stored in google drive.
Assumptions:
User has set full access to the file.
The file is just a stored file like a json etc. not a google docs or google sheet file.
In my use-case, the user specifies the url in an input box and the javascript program should retrieve it.
The program is not just for google drive but for any internet accessible public storage (say S3 too).
Hence I wished to use fetch(url).
When the download url is entered on a browser window (https://drive.google.com/uc?export=download&id=<FILE_ID>) it downloads the file. But when set inside fetch it gives a Access to Fetch has been blocked due to CORS. When I try to use the `{"mode": "no-cors"} in the fetch command it gives a response with type opaque.
Is there a generic way to download a file?
Thanks

Related

Get a permanent URL from Google Cloud Storage?

I have a scenario where a user can upload images to Firebase Storage, however I do not want them to be able to get a URL for these images (Copy Image Address). Instead I want to provide them with a blob.
When a user uploads the image client side, I get the download URL and store that in Firestore. When the user wants to see the image, I have a cloud function that downloads that image, and sends it to the user as a blob.
This works great for images the user uploads, however I also have a cloud function that is triggered automatically when an image is uploaded and generates a thumbnail.
How do I go about getting a permanent download URL from a Cloud Function/Node server for this generated image? I can get a signed one, but it's not what I need
You can't directly with Google Cloud Storage. The signed URL can't live more than 7 days
The longest expiration value is 604800 seconds (7days).
You can keep the link of the generated thumbnail image, but you have to either download it and serve it each time, or generate a signed url for using and displaying it, each time also. This second solution reduces the processing time and thus the cost.
If you want a permanent URL to access your data, you could make them public according to this documentation[1].
Just keep in mind that when accessing public data through the Google Cloud Platform Console, you must authenticate with Google. It can be accessed with any Google account, the account does not have to be associated with the project that contains the public data, nor must it be registered in the Cloud Storage service [2].
[1] https://cloud.google.com/storage/docs/access-control/making-data-public
[2] https://cloud.google.com/storage/docs/access-public-data
If you are using Django and django-storages[google] lib
Make the bucket public(not advisable for production)
Disable ACL and URL signing
Add these to the settings.py
GS_DEFAULT_ACL = None
GS_QUERYSTRING_AUTH = False

How to hide Google Storage bucket path and image name from URL

I'm using Google Storage to store profile pictures of my users. I have couple of thousands pictures.
Now the pictures are being saved in a bucket like so:
data/images/profiles/USER_ID.jpg
So the URL to an image:
https://storage.cloud.google.com/data/images/profiles/USER_ID.jpg
I don't want users being able to see someone else picture by just knowing their USER_ID, and still, It has to be the USER_ID for easier search from a developer's side.
I can't use Signed URL as my users do not have a google account, and the pictures from the storage are fetched from a Mobile Application.
Is there a way to keep the file names as they are in the storage, but simple hide the path+filename from the URL?
https://storage.cloud.google.com/fc720d5c05411b03e5e2a6692f8d7d61.jpg -> points to https://storage.cloud.google.com/data/images/profiles/USER_ID.jpg
Thank You
You have several options. Here are a few:
Have users request the URL for another user from the server, then have the server decide whether or not the user is allowed to see the image. If so, have the server (which does have a service account) generate a signed URL and pass it back to the user (or redirect to it). This way, although the user may know the user ID of another user and the URL of their image, they still can't see the image unless the server agrees that this is okay.
Use Firebase Storage to manage the images, which will still store them in GCS but will give you Firebase's auth support.
Proxy the images through your app, either an app engine app or something running in GCE or GKE. This lets you hide everything about the source of the image, including the user ID, but has the downside of requiring all of the data to pass through your service.
Reexamine your requirements. "Easier search on the developer's side" may not be as important as you think, and you need to way the benefit of that vs the cost of working around it.
Another option is Google Images API available on AppEngine. You can link your Cloud Storage objects with Google Images API and use benefits of this API - secure URLs, transform and resize images using URL parameters.
You only need to prepare servingURL for every image stored in GCS and persist this serving URL (for example in Google Datastore)
ImagesService imagesService = ImagesServiceFactory.getImagesService();
ServingUrlOptions suo = ServingUrlOptions.Builder
.withGoogleStorageFileName(gcsImageObjectPath)
.secureUrl(true);
String servingUrl = imagesService.getServingUrl(suo);

How to hide the Firebase Storage download URL from the network tab of browsers?

I'm leveraging Firebase Authentication for downloading images from firebase storage. I'm also leveraging google API HTTP referrers for blockage by domain so that my image from firebase storage is only accessed from my website. But when I go to the network tab of my browser I can see the download URL of the image. By this, anyone can download my image and use it. What should I do so that my images are secured?
P.S: I'm using the firebase storage SDK and by following the documentation when I execute this code below
storageRef.child('images/stars.jpg').getDownloadURL().then(function(url) {
// `url` is the download URL for 'images/stars.jpg'
var img = document.getElementById('myimg');
img.src = url;
}).catch(function(error) {
// Handle any errors
});
I can see the download URL in the network tab of my browser.
You can't. When you give up access to a Cloud Storage download URL to any one, in any way, you are implicitly trusting that user to its access. They are free to share it with anyone they want. If you don't trust that user, then don't give them the URL.
If you don't like the way this works, then don't use download URLs, and allow only secure downloads via the Firebase SDK. At that point, you are trusting the user they will not take the content and upload it elsewhere and generate a URL to it.
You seem to have two options as far as I can tell. Unfortunately, they are basically one in the same effectively as you will probably have to implement both.
The first option is to revoke the access token on individual files you don't want to be allowed to download. Unfortunately, this also means that you can't display them anywhere you currently do via the URL as it breaks that link. See this answer for why that is a pain to do.
The second option is to use storage references to download them client side, but this only works if you are using Firebase SDK's in a web app and not a simple static website. I think this shouldn't expose the URL on the network tab of the browser if the app is set up correctly.
You can implement the second option without the first and the URL shouldn't be exposed, but you can't use the url anymore and have to use both options if you implement the first one... :/ meh... firebase is great, but nothing is perfect
This seems to work, I'll update if it doesn't
Edit: "However, the CORS configuration applies only to XML API requests," which one can just go to the file still.. https://cloud.google.com/storage/docs/cross-origin
GCP console >_
pencil icon > create cors.json [{"origin":["https://yourorigin1.com"],"method":["GET"],"maxAgeSeconds":3600}]
go back to shell and enter gsutil cors set cors.json gs://yourproject1.appspot.com
https://stackoverflow.com/a/58613527/11711280
Workaround:
I will make all rules resource.data.authorId, resource.data.members, etc. I need to match the request.auth.uid (or control calls in client code to non-anonymous uid's), and sign-in every user anonymously, at first. Then, uid will not be null when using a firebase initialized from our domain

Firebase Storage – getting static link based on filename

I have a situation where in Firebase Storage users store their avatar to /users/{uid}.jpg
If I then use the Storage API to get the download URL and display the image, it ends up being very slow to make the first request because the download URL is not cached anywhere.
So my solution is to get the DownloadURL when the user uploads the image and store that in Firebase allowing the client image provider to automatically cache the image which speeds up loads considerably.
However, there is one problem with this solution.
If a user replaces their avatar, the old link becomes broken instead of updated. I believe this is because a new token is generated each time something is uploaded for security reasons but these are of no benefit to me.
So my question is twofold:
1) How can I allow a user to upload an avatar to a path that is dedicated to them such as /users/{uid}.jpg, get a bare download URL that can be cached by the client, and have that URL remain the same even when the file changes at /users/{uid}.jpg
2) If this is not possible, what is the normal way to solve this issue?
Download URLs are opaque. The contents of the actual URL itself is an implementation detail of the system, and it's not supported to dig around in its contents. The URLs can't be dissected or composed.
You can use a storage trigger with Cloud Functions to automatically generate a signed URL whenever something changes in your storage bucket.
So instead of serving from a hard-coded URL, simply retrieve the URL from an updated value in the datastore (or any data storage system). Every time the user updates the avatar, simply store the new URL in the datastore and you can query for it when you need it.

Hiding API Key on Xively Image

I'm interested in using Xively's image embed code in a website I'm working on, but I need to either:
Make the Xively feed public in order to access the image
Include the API key in the get request
Now I do not want to expose our private information or open up the datastreams to being modified without my permission using my API key, what options do we have? In other words, how can I conceal the API key in the image URL that your can easily find by viewing the source? I'm not particularly keen on saving the image locally, renaming it, and then serving it from our server with a different name.
Xively API keys have very fine-grain permissions. You probably want to generate a key that has:
read-only access to just that specific feed
referrer set to the domain of your website
You will find an "Add Key" button on your develop workbench, see screenshot below.
This should protect your data, but still keep your device's feed private.

Resources