Possibility for only currently connected (not authenticated) and admin user to read and write on certain location - firebase

Is there any way to write a security rule or is there any other approach that would make possible only for currently connected (not authenticated) user to write/read certain location - admin should also be able to write/read?
Can a rule be written that disallows users to read of complete list of entries and let them read only entry that matches some identifier that was passed from client?
I'm trying to exchange some data between user and Node.js application through Firebase and that data shouldn't be able to read or write by anyone else other than user and/or admin.
I know that one solution would be that user requests auth token on my server and uses it to authenticate on Firebase and that would make it possible to write rule which prevents reads and writes. However, I'm trying to avoid user connecting to my server so this solution is not first option.
This is in a way session based scenario which is not available in Firebase but I have
some ideas that could solve this kind of problem - if implemented before session management:
maybe letting admin write into /.info/ location which is observed by client for every change and can be read only by active connection - if I understood correctly how .info works
maybe creating .temp location for that purpose
maybe letting admin and connected client could have more access to connection information which would contain some connection unique id, that can be used to create location with that name and use it inside rule to prevent reading and listing to other users
Thanks

This seems like a classic XY problem (i.e. trying to solve the attempted solution instead of the actual problem).
If I understand your constraints correctly, the underlying issue is that you do not wish to have direct connections to your server. This is currently the model we're using with Firebase and I can think of two simple patterns to accomplish this.
1) Store the data in an non-guessable path
Create a UUID or GID or, assuming we're not talking bank level security here, just a plain Firebase ID ( firebaseRef.push().name() ). Then have the server and client communicate via this path.
This avoids the need for security rules since the URLs are unguessable, or close enough to it, in the case of the Firebase ID, for normal uses.
Client example:
var fb = new Firebase(MY_INSTANCE_URL+'/connect');
var uniquePath = fb.push();
var myId = uniquePath.name();
// send a message to the server
uniquePath.push('hello world');
From the server, simply monitor connect, each one that connects is a new client:
var fb = new Firebase(MY_INSTANCE_URL+'/connect');
fb.on('child_added', newClientConnected);
function newClientConnected(snapshot) {
snapshot.ref().on('child_added', function(ss) {
// when the client sends me a message, log it and then return "goodbye"
console.log('new message', ss.val());
ss.ref().set('goodbye');
});
};
In your security rules:
{
"rules": {
// read/write are false by default
"connect": {
// contents cannot be listed, no way to find out ids other than guessing
"$client": {
".read": true,
".write": true
}
}
}
}
2) Use Firebase authentication
Instead of expending so much effort to avoid authentication, just use a third party service, like Firebase's built-in auth, or Singly (which supports Firebase). This is the best of both worlds, and the model I use for most cases.
Your client can authenticate directly with one of these services, never touching your server, and then authenticate to Firebase with the token, allowing security rules to take effect.

Related

Check if a user is currently online to meteor server

I'd like to determine if a user is currently "online" or connected to the Meteor server.
I need this information before I send the user message, If the user is not connected I'd like to send the message via email.
I know that for traditional web applications that are totally state-less the definition of "online" use is a bit not clear but since modern web frameworks rely on websocket, a user is supposed to be online if a websocket is open.
The question is does Meteor include a method to determine if a user is connected or not?
Summarized: yes, there is such a mechanism.
There are for example package, that store the active login connections of the users with the meteor server and make them available either via an own collection or as part of the user profile.
See: https://github.com/dburles/meteor-presence
(Creates a new collection, called Presences)
or https://github.com/dan335/meteor-user-presence/
(Creates a user's profile entry, called presence. However, has also a collection to store and update the information in the background)
or https://github.com/mizzao/meteor-user-status
(Thanks to blueren in the comments)
Code example (from the first listed package)
Meteor.onConnection(function(connection) {
// console.log('connectionId: ' + connection.id);
Presences.insert({ _id: connection.id });
connections[connection.id] = {};
tick(connection.id);
connection.onClose(function() {
// console.log('connection closed: ' + connection.id);
expire(connection.id);
});
});
If you don't want to rely on the packages you may make use of that mechanism yourself.
See: https://docs.meteor.com/api/connections.html#Meteor-onConnection

Is there a way to increment a count in Firebase without exposing current count to the client?

I would like to increment a count in Firebase, but without exposing the the current count to client.
I have read numerous helpful answers about using transactions to increment counters in Firebase, but all of these assume that the client has "read" access to the counter element. What if the client shouldn't have read access to the count, but I want to increment the value based on the user's actions?
Example:
Suppose I want to track views or impressions (or some other user action) on a specific piece of content. The counts are for internal eyes only, and perhaps to be shared privately with advertisers and partners -- but not shown to the users themselves, and we don't want to share that data with competitors by exposing it to the browser.
For cases like this, I could route things through a server process, in which the server process fetches the count and increments it, but that kinda defeats the purpose of using Firebase in the first place. Are there any other options to increment a "private" counter from the browser?
I'm not sure why you're getting downvoted, as it seems like a valid question to me.
There is no server-side way to increment a counter in Firebase. With that knowledge, the only way to currently increment a counter is to have the client perform the increment. While you can secure that with rules to ensure that each user can only increment once, that each increment is a single step and many other things, the client-app will have to be able to read the current value.
The common solution to your problem would be to introduce a tally server. Each client can write it's "I've viewed this content" record into the database and then you have a server that listens to this queue and updates the count.
viewQueue
$pushId
uid: <uid>
itemId: <itemId>
viewCounts
$itemId: <totalViewCount>
You could secure this so that users can only write to the view queue and only the server (which likely will run under a service account can access the view counts:
{
"rules": {
"viewQueue": {
".read": false, // only the server can read this
"$pushid": {
".write": "newData.exists() && !data.exists()"
}
},
"viewCounts": {
// only the server can access this
".read": false,
".write": false
}
}
}

Creating an Asterisk "application" to send GET requests from an endpoint via Phone Prompt

To start off, I'd like to state that this is my first dive into Asterisk related applications, and that I'm mostly a web developer.
My workplace uses an MSP that installed Asterisk/FreePBX to manage our phone systems. The GUI is pretty intuitive and after reading and getting a bit lost I figured I'd come here and see how to go about setting this up.
I was tasked with building a simple application to reset user passwords through both a web interface (completed) and a phone interface - by dialing a number, dialing their ID card #, and then having their password reset. I'm a Systems Administrator and have access to all necessary applications, servers, etc. I can pick things up fairly easy and I was told I'd have enough time to figure this out and get it done.
This is what I need in terms of pseudocode when the user calls a specific extension:
recording('pwResetCardID'); // Play a "Please enter your ID # to reset PW" greeting.
function getCardID() {
cardID = input(); // Input 4-5 digits using the dialpad and save it to a var.
verify = get('http://some.site/endpoint/cardid/'.$cardid); // Send a GET request.
if verify { // If we got a successful response (200)
recording('pwChanged'); // Tell the user their password has changed
} else { //
recording('errorCardID'); // Otherwise tell them to try again
getCardID(); // Recur the function.
}
}
getCardID();
If the cardID is valid, their PW is changed on the other end of my node.js application, and I simply need the GET request to be sent out and the user notified of the success (or failure)
You can start from doc describing asterisk dialplan
Probably need use func_CURL, Read application, Playbavk and Goto
You need put new dialplan in extensions_custom.conf and setup use it via custom apps module

Unable to delete information from my firebase

I was testing some changes to my firebase and accidently submitted 100's of updates to a reference. Now when I try and delete the reference it then creates a new reference with different data.
I have tried deleting everything in the firebase but it will just keep creating a new reference.
In this specific example I used set() to add 5 random values to a user name Michael. The 5 random values were called 100's of times and now when I delete the Michael user to test again it already has a value queued up and recreates itself immediately. I looked at my upload usage and it showed a huge amount of data being uploaded at one point that coincides with this error.
Any idea how to remove these queued up changes?
Make sure to disconnect the client that is writing this data. I suspect somewhere you have a process running that is generating these writes.
If you can't stop the offending process for some reason, you could always modify your security rules to deny access to the client that's doing the writes (or if it's a server using a Firebase Secret to authenticate, you could revoke its secret).
I've had a similar issue - think it has to do with your session / caching.
Try logging out of firebase and back in - if the records are still there, make a backup of your security rules, then use:
{
"rules": {
".read": false,
".write": false
}
}
and delete them.

How do you secure the client side MongoDB API?

I don't want just all of my users being able to insert/destroy data.
While there is no documented way to do this yet, here's some code that should do what you want:
Foo = new Meteor.Collection("foo");
...
if (Meteor.is_server) {
Meteor.startup(function () {
Meteor.default_server.method_handlers['/foo/insert'] = function () {};
Meteor.default_server.method_handlers['/foo/update'] = function () {};
Meteor.default_server.method_handlers['/foo/remove'] = function () {};
});
}
This will disable the default insert/update/remove methods. Clients can try to insert into the database, but the server will do nothing, and the client will notice and remove the locally created item when the server responds.
insert/update/remove will still work on the server. You'll need to make methods with Meteor.methods that run on the server to accomplish any database writes.
All of this will change when the authentication branch lands. Once that happens, you'll be able to provide validators to inspect and authorize database writes on the server. Here's a little more detail: http://news.ycombinator.com/item?id=3825063
[UPDATE] There is now an official and documented Auth Package which provides different solutions to secure a collection.
On a CRUD level :
[Server] collection.allow(options) and collection.deny(options). Restricts default write methods on this collection. Once either of these are called on a collection, all write methods on that collection are restricted regardless of the insecure package.
And there is also insecureto remove full write access from the client.
source : Getting Started with Auth (thanks to #dan-dascalescu)
[OLD ANSWER]
Apparently there are working on Auth Package(?) that should avoid any users taking full control on the db as it is now. There is also someone suggesting that there is an existing solution (workaround) by defining your own mutations (methods) and make them failed if they attempts to perform an unauthorized action. I didn't get it much better but I think this will often be necessary since I doubt the Auth Package will let you implement the usual auth logic on a row level but probably only on the CRUD methods. Will have to see what the devs have to say.
[EDIT]
Found something that seems to confirm my thoughts :
Currently the client is given full write access to the collection. They can execute arbitrary Mongo update commands. Once we build authentication, you will be able to limit the client's direct access to insert, update, and remove. We are also considering validators and other ORM-like functionality.
Sources of this answer :
Accessing to DB at client side as in server side with meteor
https://stackoverflow.com/questions/10100813/data-validation-and-security-in-meteor/10101516#10101516
A more succinct way:
_.each(['collection1', 'collection2'], function(collection){
_.each(['insert','update', 'remove'], function(method){
Meteor.default_server.method_handlers['/' + collection + '/' + method] = function(){}
});
});
or to make it more idiomatic:
extend meteor:
_.extend(Meteor.Collection.prototype, {
remove_client_access: function(methods){
var self = this;
if(!methods) methods = ['insert','update','remove'];
if(typeof methods === 'String') methods = [methods];
_.each(methods, function(method){
Meteor.default_server.method_handlers[self._prefix + method] = function(){}
});
}
});
Calls are simpler:
List.remove_client_access() // restrict all
List.remove_client_access('remove') //restrict one
List.remove_client_access(['remove','update']) //restrict more than one
I am new to Meteor, but what I have come across so far are these two points
You can limit what a client can access in the database by adding parameters to the find command in the server-side publish command. Then when the client calls Collection.find({}), the results that are returned correspond to what on the server side would be, for example, Collection.find({user: this.userId}) (see also Publish certain information for Meteor.users and more information for Meteor.user and http://docs.meteor.com/#meteor_publish)
One thing that is built in (I have meteor 0.5.9) is that the client can only update items by id, not using selectors. An error is logged to console on the client if there is an attempt that doesn't comply. 403: "Not permitted. Untrusted code may only update documents by ID." (see Understanding "Not permitted. Untrusted code may only update documents by ID." Meteor error).
In view of number 2, you need to use Meteor.methods on the server side to make remote procedure calls available to the client with Meteor.call.

Resources