We can define methods on Meteor server and call them from clients, is there any way to call client defined methods from server?
As per official Docs there is no direct way to call client side methods from server but you can achieve that by using a smart package called anti:methods
You need to set the clientId which will be used to communicate to this particular client.
Tracker.autorun(function() {
Meteor.ClientCall.setClientId(Meteor.userId());
});
Defining a method
Meteor.ClientCall.methods({
'chatMessage': function(username, message) {
...
},
});
Calling a method
Meteor.ClientCall.apply(clientId, method, arguments, callback)
Note: This package is not fully functional. Check the readme for more information.
Alternatively if you just want to re-use some code in both server and client, you can create a global function in common folder and call it from anywhere you want. Just make sure it does not contain any browser specific code and it loads before the function where you calling it.
Related
I use Flutter/Firestore/Cloud Functions.
Say I want to update a users balance via a transaction. I will call my Firebase function from the client with the help of Googles cloud_functions package:
Future updateBalance(amount)async{
dynamic resp = await balanceUpdate.call(<String, dynamic>{
'amount': amount
});
return resp.data;
}
Is it possible for a attacker to middle man the function call and change the parameters? amount in this case. (ex: the attacker submits a $5 transaction and edits the call to the function changing it to $500).
If it isn't possible, should encryption be used anyways just to be safe, or it that not necessary?
Callable functions are just public HTTP functions that anyone can invoke using the documented HTTP protocol. Anyone can invoke them and pass any parameters they want.
Additional encryption will not help here. The API of the function is effectively public and easy to reverse engineer from the app's own code and behavior. If you don't want someone invoking your function using arbitrary values, your function should have some code that validates the user and the parameters being passed.
Is there anyway to determine if the Rocket.chat app is running in desktop or browser?
Thank you in advance. :)
You can look at server environment variables using a line like this:
console.log(process.env.TZ);
If you need to access that from the client, you can do this in your client code:
console.log("TZ = "+Meteor.call("getEnv","TZ"));
and in your meteor methods (in the server folder)
Meteor.methods({
getEnv: function(varname) {
return process.env[varname];
},
Obviously use this with care. It is a generic method that may present a security hole. If you want to make it more secure, just write a specific method where you don't pass the environment variable name, to prevent any kind of malicious attack.
Meteor has special directories: server and client for serving files only to server or only to client.
Is it possible to make similar behaviour, but using not client and server folder names but file names which end with either .client.js or .server.js?
For example collections.client.js would be available only on client and collections.server.js would be available only on server?
UPD
Maybe it is possible to create smart package which will take control of files serving?
This is not possible, what you can do however, is the following :
lib/collections/collection.js
Declare the collection and common client/server behavior such as Meteor.methods.
client/collections/collection.js
Declare client specific helpers regarding the collection.
server/collections/collection.js
Declare publications and other server-side helpers.
You could alternatively declare everything in lib/collections/collection.js and use Meteor.isClient and Meteor.isServer blocks.
This might be OK for very small files but it can quickly become a mess for larger projects.
I'm not sure if the Meteor build tool is smart enough to strip Meteor.isServer from the bundle served to the client.
You can also use a modular approach and use packages instead, with the Package API you can control precisely the context where a file is supposed to be executed.
Package.describe({
name: "my-app-module",
description: "Handles some feature in My App",
version: "1.0.0"
});
Package.onUse(function(api){
api.addFiles({
"my-module/shared.js"
},["client","server"]);
//
api.addFiles({
"my-module/client.js"
},"client");
//
api.addFiles({
"my-module/server.js"
},"server");
//
api.export("MyModule",["client","server"]);
});
Hmmm, for now you can't do this, but you can put your code in
if (Meteor.isServer) {
// your server code
};
if (Meteor.isClient) {
// your client code
};
This screencast shows how to retrieve additional user profile attributes from external authentication. But I don't understand how can I update the user account every time user logs in with possibly updated profile attributes? Is onCreateUser called every time user authenticates or just the first time? From what I understand it is just the first time. So how can I hook into login process to update attributes?
You need to hook into when someone logs in and then update the attributes manually.
Firstly you need something that tells when the user is logged in. At the moment you could use a client based solution (where a call is made to the server a second time on a successful login) using something like meteor-prescence or by editing the core packages and placing them in your /packages directory.
Alter the accounts-base package with the file accounts-server.js to create a 'hook' when the user logs in at
Meteor.methods({
login: function(options) {
.....
if (result !== null)
//Run here
this.setUserId(result.id);
return result;
},
});
Then at the //Run Here add a function that connects to facebook and gets the data you need. Or in the Meteor.call method that you would call from the client if you decide to use meteor-prescence or a similar library or method. It would be something similar to this:
if(Meteor.user().services.facebook.accessToken) {
var graph = Npm.require('fbgraph');
graph.setAccessToken(Meteor.user().services.facebook.accessToken);
graph.get('/me',{},function(err,result) {
//Update your user (you could also alter services.facebook instead
Meteor.users.update(Meteor.userId, {$set: {profile:result}});
}
}
In the above the example is for facebook using the fbgraph node module (which you would need to install) - or use the method described here to use Npm modules without a seperate package. You could to the same in principle for other providers too. Note you don't have to use a synchronous type call here to your provider as it is ok the data could be updated shortly after they log in.
Another place you could hook into is also in the _setUserId method in the livedata package.
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.