Android Question Howto get a Firebase Storage's file public https:-URL?

fredo

Well-Known Member
Licensed User
Longtime User
@Erel 's Firebase Storage library is easy to setup and easy to use.
A Testproject is working well with and without authentication.
abc.png
The "UploadCompleted" event delivers the Serverpath (1), which is fine so far and can be used with the gs:\\ protocol (2) by authenticated users.

In order to download the file from unauthenticated users a https:\\-URL (3) is needed.
12-08-_2017_17-18-02.png

So, this is the question:
How to get the Firebase Storage public https://-URL from the storage object? (4)
12-08-_2017_17-54-28.png

I could find this valuable information in SO here but was not able to get a grip on a solution:
"Luckily Firebase Storage gives both URLs that we can use to represent files."

// "Private" internal URL, only accessible through Firebase Storage API
// This is protected by Firebase Storage Security Rules & Firebase Auth
gs://bucket/object

// "Public" unguessable URL, accessible by anyone with the link
// This is secured because that token is *very* hard for someone to guess
https://firebasestorage.googleapis.com/v0/bucket/object?alt=media&token=<token>

The first option requires that you use the reference.getDownloadURL() method to convert the internal gs:// URL into a public https:// URL.

The second option allows you to share this public but unguessable URL with trusted individuals, and allows them to access content without authentication to Firebase or using your app--think sharing family photos with Google Photos. Likely this behavior will be good enough, unless you desire public sharing with clean URLs. You can use this URL in a browser, or use any other HTTP library to download it. We provide the ability to download these files as well (off a reference), so you don't need to get a third party library, you can just use us.

The Firebase documentation gives some explanations, but in a language with "curly brackets" ...

I saw this post from @alwaysbusy 's wonderful "ABMaterial"-world, but it's B4J.
12-08-_2017_17-05-32.png




___
Please ignore the attached file. I can't remove it since the normal "Edit"-"More options" produces a "ERR_BLOCKED_BY_XSS_AUDITOR"
 

Attachments

  • 12-08-_2017_17-05-32.png
    12-08-_2017_17-05-32.png
    35.2 KB · Views: 281
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
Note that it is better to post code as text with code tags.

In order to download the file from unauthenticated users a https:\\-URL (3) is needed.
That's not correct. The https link allows users to download it without the firebase SDK.

Do you want to allow users to download the resource outside of your app?
 
Upvote 0

fredo

Well-Known Member
Licensed User
Longtime User
...without the firebase SDK.
I wasn't aware of that. Thank you.

...allow users to download the resource outside of your app?
Yes.
Some files (small datapacks in json format) shall be shared with trusted individuals via an ungeuessable URL outside our app.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Here:
B4X:
Sub btnDownloadPublic_Click
   Wait For (GetDownloadUrl("/public/Untitled.png")) Complete (Url As String)
   If Url <> "" Then
     Log(Url)
   End If
End Sub

Sub GetDownloadUrl(ServerPath As String) As ResumableSub
   Dim fs As JavaObject = Starter.storage
   fs = fs.GetField("fs")
   Dim ref As JavaObject = fs.RunMethod("getReferenceFromUrl", Array(Starter.bucket & ServerPath))
   Dim task As JavaObject = ref.RunMethod("getDownloadUrl", Null)
   Do While task.RunMethod("isComplete", Null) = False
     Sleep(100)
   Loop
   If task.RunMethod("isSuccessful", Null) Then
     Dim s As String = task.RunMethod("getResult", Null)
     Return s
   Else
     Log("Error")
     Return ""
   End If
End Sub
This code uses the new feature added in v7.30 that allows resumable subs to return values.
 
Upvote 0

fredo

Well-Known Member
Licensed User
Longtime User
Thank you Erel! The support from Anywhere Software is superb as always.

Since we wanted a "nontalking" URL I added an URL shortener inspired by Erel here.
Although I'm not sure if I used the new ResumableSub feature correct, it delivers the expected results.

B4X:
...
      wait for (GetDownloadUrl(ServerPath)) complete (strDownloadUrlHttps As String)
      If strDownloadUrlHttps.Length > 0 Then

          wait for(ShortenUrl(strDownloadUrlHttps)) complete (strUrlShort As String)
          Log( strUrlShort )

      End If
...

Sub ShortenUrl(url As String) As ResumableSub
    Dim j As HttpJob
    j.Initialize("shortenurl", Me)
    Dim jg As JSONGenerator
    jg.Initialize(CreateMap("longUrl": url))
    ' Google API key is awailable here --> https://console.developers.google.com/apis/api/urlshortener.googleapis.com/overview?project=yyyyyyyyyyyyyyyyyyyyyyyyyy
    '  (don't forget to ENABLE)
    j.PostBytes($"https://www.googleapis.com/urlshortener/v1/url?key=${Starter.apikey}"$, jg.ToString.GetBytes("UTF8"))
    j.GetRequest.SetContentType("application/json")
    wait for JobDone(job As HttpJob)
    Dim shortUrl As String = ""
    If job.JobName = "shortenurl" Then
        If job.Success Then
            Dim jp As JSONParser
            jp.Initialize(job.GetString)
            shortUrl = jp.NextObject.Get("id")
        Else
            Log("Error: " & job.ErrorMessage)
        End If
    End If
    job.Release
    Return shortUrl
End Sub

Info: The shortened URL is easy to unshort, so it's only a weak obfuscation measure
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
The code is mostly correct. It can be improved with:

1. Don't set the job name.
2. Set the sender filter parameter when waiting for JobDone:

B4X:
Sub ShortenUrl(url As String) As ResumableSub
    Dim j As HttpJob
    j.Initialize("", Me)
    Dim jg As JSONGenerator
    jg.Initialize(CreateMap("longUrl": url))
    ' Google API key is awailable here --> https://console.developers.google.com/apis/api/urlshortener.googleapis.com/overview?project=yyyyyyyyyyyyyyyyyyyyyyyyyy
    '  (don't forget to ENABLE)
    j.PostBytes($"https://www.googleapis.com/urlshortener/v1/url?key=${Starter.apikey}"$, jg.ToString.GetBytes("UTF8"))
    j.GetRequest.SetContentType("application/json")
    wait for (j) JobDone(job As HttpJob)
    Dim shortUrl As String = ""
        If job.Success Then
            Dim jp As JSONParser
            jp.Initialize(job.GetString)
            shortUrl = jp.NextObject.Get("id")
        Else
            Log("Error: " & job.ErrorMessage)
        End If
    job.Release
    Return shortUrl
End Sub

There could be any number of concurrent HttpJob requests. By setting the sender filter parameter you make sure that only the one created locally will be intercepted by the relevant Wait For call.
 
Upvote 0
Top