Firebase emulator hitting DB via the REST feature - firebase

I’m trying to setup the emulator so I can develop the firebase functions safely before deploying them. I just noticed that some REST calls I’m doing now fails - anybody know if it is not possible to use the REST feature of the RealTime DB https://firebase.google.com/docs/reference/rest/database
I'm trying to hit it with this URL
http://localhost:9000/?ns=<PROJECT ID>-default-rtdb/development/DISHES.json
because this is what I set the firebaseConfig.databaseURL to (suggested here by Google)
Bonus info: If I try to do a GET to the URL via postman it creates another database called fake-server (http://localhost:4000/database/fake-server: null) 🤔

According to RFC 3986, the path must come before the query parameters in URLs. Your URL should be instead written as:
http://localhost:9000/development/DISHES.json?ns=<PROJECT ID>-default-rtdb
Note how the corrected URL has the query parameter appended to the very end. (The URL you've provided in the question will be parsed as having one query parameter ns with the value of <PROJECT ID>-default-rtdb/development/DISHES.json, which is not a valid namespace name. That explains the errors you've seen.)
FYI, it looks like you're constructing the URL by concatenating the string databaseURL with the path -- this may lead to surprising results as you've seen above. Considering using a URL parser / formatter in your language / framework of choice instead, which handles URL parts correctly. For example, in JavaScript you can use the snippet below:
const url = new URL(databaseURL); // Parse URL (including query params, if any)
url.pathname = '/development/DISHES.json';
yourFetchingLogic(url.toString()); // Reconstruct the URL with path replaced

Related

Firebase Realtime Database - how to manage database rules using REST API

I would like to get/set realtime database rules using Rest API however no tutorial is working for me. I try to do it like that:
I copied the url to my realtime database which is in Europe https://my-project-database.europe-west1.firebasedatabase.app/
I copied the java code from this tutorial: https://firebase.google.com/docs/database/rest/auth which was supposed to give me the access token
val googleCred = GoogleCredential.fromStream(File("/path/to/my/key.json").inputStream())
val scoped = googleCred.createScoped(
Arrays.asList( // or use firebase.database.readonly for read-only access
"https://www.googleapis.com/auth/firebase.database",
"https://www.googleapis.com/auth/userinfo.email"
)
)
scoped.refreshToken()
val token = scoped.accessToken
println(token)
However the token looks very strange with a long string of dots at the end like (it's related to: Why am I getting a JWT with a bunch of periods/dots back from Google OAuth?)
ya29.c.Kp8BCgi0lxWtUt-_[Normal JWT stuff, redacted for
security]yVvGk...............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
I did HTTP GET to address like https://my-project-database.europe-west1.firebasedatabase.app/.settings/rules.json?access_token=$token and I got 401 UNAUTHORIZED
I assume it's due to the fact that I use the whole of this strange token full of dots as the access_token variable. So now I have questions how to transform it and use as the access_token to make it work
EDIT:
I created this gist although it's in python it has exactly the same problem. How to make it work ?
https://gist.github.com/solveretur/86d53a9c0221f096c38c3ef8f70a8dbd
It works I used wrong database key

Send firebase storage authorization as url parameter from a flutter web app

I would like to know how to make an authorized request to firebase storage using the user Id Token as a parameter in the url. Right now with a firebase rule of 'request.auth != null' I receive a 403 network error (Failed to load video: You do not have permission to access the requested resource). Here is my GET request url:
https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<folder_name>%2F<video_name>.mp4?alt=media&auth=eyJh...<ID TOKEN>...Ll2un8ng
-WITHOUT the firebase rule in place I'm able to successfully get the asset with this request url https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<folder_name>%2F<video_name>.mp4?alt=media
-also tried token=, token_id=, tokenId=
-the reason for not using the firebase SDK to fetch the file is so that I can use the flutter video_player (https://pub.dev/packages/video_player#-example-tab-) package and use this with files in firebase, I mention this in case theres a better way to use the video_player library in flutter web right now:
_controller = VideoPlayerController.network(
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
closedCaptionFile: _loadCaptions(),
);
[EDIT] It appears that it's not possible to pass the auth in as a query parameter. After some exploring, I found an acceptable way to still use the video_player with your firebase assets that are protected (If you're not using rules to protect them, you can directly use the firebase url). I will post some general steps here and some sample code:
Use the Storage Firebase SDK package to get the Uint8List, the uri given by getDownloadURL has the correct header auth, for example
import 'package:firebase/firebase.dart';
final url = await storagePath.getDownloadURL();
final response = await http.get(url);
if (response.statusCode == 200) {
return response.bodyBytes;
}
use the Uint8List buffer to init a Blob object which you'll use to then create an ObjectURL which basically gives you the same interface as a file url to use as the network url for your video player
final blob = html.Blob([data.buffer], 'video/mp4');
final videoUrl = html.Url.createObjectUrl(blob);
videoPlayerController = VideoPlayerController.network(
videoUrl)
..initialize().then((_) {...
That's it.
Firebase Storage REST does not (rightly) support authorization from GET query string as you are trying to do. Instead, it uses the standard Authorization header (see here).
Firebase cloud storage internally uses Google Cloud Storage. Mentioned here
If the library you use doesn't support HTTP headers yet, you must consider an alternative. The issue you mentioned in the comment shows that the feature is still under development, so you can also wait for the library to come out with the support for headers.
Internally all this package does for flutter-web is create an HtmlElementView widget here for which it passes a VideoElement (ref here) from the package dart:html with the provided URL which translates to a <Video> tag inside a shadow dom element in your web page. The error 403 could also mean you are trying to access it from a different origin.
I would suggest following approach.
Check your console for any CORS related errors. If yes, then you will have to whitelist your ip/domain in the firebase storage. Check this post for possible approach and more details here.
Check if you are able to access the URL directly with the authorization token as a query parameter as you suggested. If not then, it is not the correct way to access the object and should be corrected. You could update the question with the exact error details.

cosmos db, generate authentication key on client for Azure Table endpoint

Cosmos DB, API Azure Tables, gives you 2 endpoints in the Overview blade
Document Endpoint
Azure Table Endpoint
An example of (1) is
https://myname.documents.azure.com/dbs/tempdb/colls
An example of (2) is
https://myname.table.cosmosdb.azure.com/FirstTestTable?$filter=PartitionKey%20eq%20'car'%20and%20RowKey%20eq%20'124'
You can create the authorization code for (1) on the client using the prerequest code from this Postman script: https://github.com/MicrosoftCSA/documentdb-postman-collection/blob/master/DocumentDB.postman_collection.json
Which will give you a code like this:
Authorization: type%3Dmaster%26ver%3D1.0%26sig%3DavFQkBscU...
This is useful for playing with the rest urls
For (2) the only code I could find to generate a code that works was on the server side and gives you a code like this:
Authorization: SharedKey myname:JXkSGZlcB1gX8Mjuu...
I had to get this out of Fiddler
My questions
(i) Can you generate a code for case (2) above on the client like you can for case (1)
(ii) Can you securely use Cosmos DB from the client?
If you go to the Azure Portal for a GA Table API account you won't see the document endpoint anymore. Instead only the Azure Table Endpoint is advertised (e.g. X.table.cosmosdb.azure.com). So we'll focus on that.
When using anything but direct mode with the .NET SDK, our existing SDKs when talking to X.table.cosmosdb.azure.com endpoint are using the SharedKey authentication scheme. There is also a SharedKeyLight scheme which should also work. Both are documented in https://learn.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services. Make sure you read the sections specifically on the Table Service. The thing to notice is that a SharedKey header is directly tied to the request it is associated with. So basically every request needs a unique header. This is useful for security because it means that a leaked header can only be used for a limited time to replay a specific request. It can't be used to authorize other requests. But of course that is exactly what you are trying to do.
An alternative is the SharedKeyLight header which is a bit easier to implement as it just requires a date and the a URL.
But we don't have externalized code libraries to really help with either.
But there is another solution that is much friendly to things like Fiddler or Postman, which is to use a SAS URL as defined in https://blogs.msdn.microsoft.com/windowsazurestorage/2012/06/12/introducing-table-sas-shared-access-signature-queue-sas-and-update-to-blob-sas/.
There are at least two ways to get a SAS token. One way is to generate one yourself. Here is some sample code to do that:
var connectionString = "DefaultEndpointsProtocol=https;AccountName=tableaccount;AccountKey=X;TableEndpoint=https://tableaccount.table.cosmosdb.azure.com:443/;";
var tableName = "ATable";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference(tableName);
await table.CreateIfNotExistsAsync();
SharedAccessTablePolicy policy = new SharedAccessTablePolicy()
{
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(1000),
Permissions = SharedAccessTablePermissions.Add
| SharedAccessTablePermissions.Query
| SharedAccessTablePermissions.Update
| SharedAccessTablePermissions.Delete
};
string sasToken = table.GetSharedAccessSignature(
policy, null, null, null, null, null);
This returns the query portion of the URL you will need to create a SAS URL.
Another, code free way, to get a SAS URL is to go to https://azure.microsoft.com/en-us/features/storage-explorer/ and download the Azure Storage Explorer. When you start it up it will show you the "Connect to Azure Storage" dialog. In that case:
Select "Use a connection string or a shared access signature URI" and click next
Select "Use a connection string" and paste in your connection string from the Azure Portal for your Azure Cosmos DB Table API account and click Next and then click Connect in the next dialog
In the Explorer pane on the left look for your account under "Storage Accounts" (NOT Cosmos DB Accounts (Preview)) and then click on Tables and then right click on the specific table you want to explore. In the right click dialog you will see an entry for "Get Shared Access Signature", click on that.
A new dialog titled "Generate Shared Access Signature" will show up. Unfortunately so will an error dialog complaining about "NotImplemented", you can ignore that. Just click OK on the error dialog.
Now you can choose how to configure your SAS, I usually just take the defaults since that gives the widest access permission. Now click Create.
The result will be a dialog with both a complete URL and a query string.
So now we can take that URL (or create it ourselves using the query output from the code) and create a fiddler request:
GET https://tableaccount.table.cosmosdb.azure.com/ATable?se=2018-01-12T05%3A22%3A00Z&sp=raud&sv=2017-04-17&tn=atable&sig=X&$filter=PartitionKey%20eq%20'Foo'%20and%20RowKey%20eq%20'bar' HTTP/1.1
User-Agent: Fiddler
Host: tableaccount.table.cosmosdb.azure.com
Accept: application/json;odata=nometadata
DataServiceVersion: 3.0
To make the request more interesting I added a $filter operation. This is an OData filter that lets us explore the content. Note, btw, to make filter work both the Accept and DataServiceVersion headers are needed. But you can use the base URL (e.g. without the filter parameter) to make any of the REST API calls on a specific table.
Do be aware that the SAS token is scoped to an individual table. So higher level operations won't work with this SAS token.

Updating Evernote note with Evernote php sdk

I can get notes(real contents, not just metadata) from the evernote API. However, calling notestore->update() always gives me a EDAMUserException.
My php code is below, the arguments are self-explanatory:
//add text to note
//if append=true then the text will be appended to the end, else it will be appended to the start
public function addToNote($new_content, $access_token, $note_store, $note_guid, $append = true){
$note = $note_store->getNote($access_token, $note_guid, true, false, false, false);
$note->content +="<en-note>Note updated</en-note>";
$note_store->updateNote($access_token, $note);
}
I've already did a lot of searching before I asked here, and here are the things I know:
According to: https://dev.evernote.com/doc/articles/permissions.php it says that there are two types of api keys, one is the basic access and one is for full access, I have full access, this is proved by no exception was thrown during $note_store->getNote() call, and I did output the data from that call, I can actually get the contents of the note.
In the same page as 1: "Certain API functions are only available to official Evernote applications and services. These functions are described as such in the API Reference and will throw an EDAMUserException with the error code PERMISSION_DENIED if called by a third-party application." I read the API documentation here: https://dev.evernote.com/doc/reference/NoteStore.html#Fn_NoteStore_updateNote
It does not mention that it is blocked by default.
I think I figured out what was wrong. Evernote actually has its own DTD document format, if the "content" section of the note is not a valid document, then the request is denied. In my case it was not denied because my API key's access level, but because the "content" I gave was not a proper evernote format.
if I set:
$note->content='<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div>testing complete!!!</div></en-note>';
Then the note will be successfully updated.
However, for other users that are getting this exception and using the right format, it is most likely:
1.your api key does not have full access, choose the full access option while you request an api key.
2.usually you would start testing on the "sandboxed"(https://sandbox.evernote.com) version of their site, you need to register another account on the sandboxed site(you real evernote account doesn't carry over) and test with that account. If you do not do this, your account will not exist on the sandboxed account and anything you do will not work.

Paw Extensions : Dynamic Value based on URI

I have an API that includes an account ID as part of the url (e.g. /account/7319310/report) where 7319310 is then account ID.
There are different credentials for each account, stored in MySQL although they could be stored in another manner if it made it easier.
I'd like Paw to automatically use the correct credentials based on the account parameter in the URI (it's always the second element) - is this possible?
In paw you can use a regex Dynamic to extract the data you need from the url:
Paw does not have a direct connection to MySQL, you can make http request from a custom value but you would need a server running to push these request to the server. A better option would be to save the credentials into a flat json file.
{
"1234334": {
"key1": 123456,
"key2": 345211
}
}
With this saved you can load this json file in a Custom Dynamic Value:
Here you can embed the extracted user id by using the regex dynamic value. inline in the code. Paw will reload the file on every request so you could set up a cron job to dump your database to this JSON file.

Resources