Are there 'private' server methods in Meteor? - meteor

Is there a way to stop a Client calling a Server Method from the browser console?
I gather from the Unofficial Meteor FAQ that there isn't. I just wanted to check if that's definitely the case - the FAQ isn't really specific. I mean are there no 'private' methods?

In meteor the 'methods' described by Meteor.methods can all be called from the client. In this sense there aren't private methods because the purpose of the RPC call is for the client to make the call.
If you want a 'private' method you could use an ordinary JavaScript method. If you define the method with var, it would only be accessible within the file, and cannot be called from the client.
var yourmethod = function() {
...
}
which is equivalent to:
function yourmethod() {
...
}
Or you can define it so any of your server script can use it:
yourmethod = function() {
....
}
If you mean you want a RPC method call that is accessible only from the javascript code, but not from the javascript console in chrome this isn't possible. This is because the idea behind meteor is all RPCs from the client are not trusted & there is no way to distinguish whether it came from the console or not. You can use meteor user authentication or Collection.allow or Collection.deny methods to prevent any unauthorized changes this way.

I made a private method by checking this.connection to be null.
Ref: http://docs.meteor.com/#/full/method_connection
Ex.
Meteor.methods({
'serverCallOnlyFunc': function() {
if (this.connection === null) {
//do something
} else {
throw(new Meteor.Error(500, 'Permission denied!'));
}
}
});

Related

Is it possible to stub meteor methods and publications in cypress tests?

Is it possible to stub meteor methods and publications in cypress tests?
In the docs (https://docs.cypress.io/guides/getting-started/testing-your-app#Stubbing-the-server) it says:
This means that instead of resetting the database, or seeding it with
the state we want, you can force the server to respond with whatever
you want it to. (...) and even test all of the edge cases, without needing a server.
But I do not find more details about that. All I can find is, that when not using the virtual user in the tests to fill the database, it is possible to call API calls on the app, like so:
cy.request('POST', '/test/seed/user', { username: 'jane.lane' })
.its('body')
.as('currentUser')
In my opinion that is not a "stub". It is a method to "seed" the database.
Is it possible to tell cypress to answer a meteor method in the client code like
Meteor.call('getUser', { username: 'jane.lane' }, callbackFunction);
with some data, it would give back in production?
I can only show an example using sinon to stub Meteor method calls:
const stub = sinon.stub(Meteor, 'call')
stub.callsFake(function (name, obj, callback) {
if (name === 'getUser' && obj.username === 'jane.lane') {
setTimeout(function () {
callback(/* your fake data here */)
})
}
})
That would be of corse a client-side stub. You could also simply override your Meteor method for this one test.

Insert new collection after function runs on server

When I return the geocode from googles API I'm trying to save it into my database. I've been trying to use the code below, to just insert a Test document with no luck. I think it has something to do with meteor being asynchronous. If I run the insert function before the googleMapsClient.geocode function it works fine. Can someone show me what I'm doing wrong.
Meteor.methods({
'myTestFunction'() {
googleMapsClient.geocode({
address: 'test address'
}, function(err, response) {
if (!err) {
Test.insert({test: 'test name'});
}
});
}
});
I see now where you got the idea to run the NPM library on the client side, but this is not what you really want here. You should be getting some errors on the server side of your meteor instance when you run the initial piece of code you gave us here. The problem is that the google npm library runs in it's own thread, this prevents us from using Meteor's methods. The easiest thing you could do is wrap the function with Meteor.wrapAsync so it would look something like this.
try {
var wrappedGeocode = Meteor.wrapAsync(googleMapsClient.geocode);
var results = wrappedGeocode({ address : "testAddress" });
console.log("results ", results);
Test.insert({ test : results });
} catch (err) {
throw new Meteor.Error('error code', 'error message');
}
You can find more info by looking at this thread, there are others dealing with the same issue as well
You should run the googleMapsClient.geocode() function on the client side, and the Test.insert() function on the server side (via a method). Try this:
Server side
Meteor.methods({
'insertIntoTest'(json) {
Test.insert({results: json.results});
}
});
Client side
googleMapsClient.geocode({
address: 'test address'
}, function(err, response) {
if (!err) {
Meteor.call('insertIntoTest', response.json);
}
});
Meteor Methods should be available on the both the server and client sides. Therefore make sure that your method is accessible by server; via proper importing on /server/main.js or proper folder structuring.
(If a method contains a secret logic run on the server, it should be isolated from the method runs on both server & client, though)

meteor.call does not call method from meteor.method

i have an issue with callback method.
i have created on methods.js in server folder
and one callback.js file in client/test/mytest folder.
my callback.js contains following code
Template.testHello.events({
"click #testHello": function(e) {
Meteor.call("testmethod",function(error, id) {
if (error) {
Errors.throwError(error.reason);
}
return false;
});
return false;
}
});
and methods.js file code is
Meteor.methods({
testmethod: function(att) {
alert("hello testmethod..");
}
});
but when i clicked on button "testHello" then it gives me error like "internal server error 500".
can anyone have idea about this?
Thanks,
It makes no sense to have client-only method calls because Meteor methods are intended to perform RMI (remote method invokation) on the server.
Move your methods.js to either server/methods.js or lib/methods.js if you want your method to have a simulation counterpart on the client.
EDIT :
As hinted by #user728291, the alert method is defined on the window object which is a browser related object thus only available on client environment, you can use console.log instead to print something on the server.

Signalr (1.0.0-alpha2) Hubs - Can you add client functions after connection has been started?

Using Signalr (1.0.0-alpha2), I want to know if it is possible to add client functions after a connection has been started.
Say I create my connection and grab the proxy. Then I add some Server Fired client functions to the hub to do a few things. Then I start my connection. I then want to add some more Server Fired functions to my hub object. Is this possible?
var myHub= $.connection.myHub;
myHub.SomeClientFunction = function() {
alert("serverside called 'Clients.SomeClientFunction()'");
};
$.connection.hub.start()
.done(function() {
myHub.SomeNewClientFunction = function() {
alert("serverside called 'Clients.SomeNewClientFunction()'");
}
})
This example is not realistic, but I basically want to send my 'myHub' variable to a different object after the hub is started to subscribe to new events that the original code did not care for.
Real Life Example: A dashboard with a number of different hub events (new site visits, chat message, site error). I 'subscribe' after the connection has started and then pass my hub proxy to all of my different UI components to handle their specific 'message types'. Should I create separate Hubs for these or should I be able to add more Server Fired client functions on the fly?
Yes you can. Use the .on method.
Example:
myHub.on('somethingNew', function() {
alert("This was called after the connection started!");
});
If you want to remove it later on use the .off method.
I have the exact same situation. You might want to consider adding another layout of abstraction if you're trying to call it from multiple places.
Here's a preliminary version of what I've come up with (typescript).
I'll start with the usage. SignalRManager is my 'manager' class that abstracts my debuggingHub hub. I have a client method fooChanged that is triggered on the server.
Somewhere in the module that is using SignalR I just call the start method, which is not re-started if already started.
// ensure signalR is started
SignalRManager.start().done(() =>
{
$.connection.debuggingHub.server.init();
});
Your 'module' simply registers its callback through the manager class and whenever the SignalR client method is triggered your handler is called.
// handler for foo changed
SignalRManager.onFooChanged((guid: string) =>
{
if (this.currentSession().guid == guid)
{
alert('changed');
}
});
This is a simple version of SignalRManager that uses jQuery $.Callbacks to pass on the request to as many modules as you have. Of course you could use any mechanism you wanted, but this seems to be the simplest.
module RR
{
export class SignalRManager
{
// the original promise returned when calling hub.Start
static _start: JQueryPromise<any>;
private static _fooChangedCallback = $.Callbacks();
// add callback for 'fooChanged' callback
static onfooChanged(callback: (guid: string) => any)
{
SignalRManager._fooChangedCallback.add(callback);
}
static start(): JQueryPromise<any>
{
if (!SignalRManager._start)
{
// callback for fooChanged
$.connection.debuggingHub.client.fooChanged = (guid: string) =>
{
console.log('foo Changed ' + guid);
SignalRManager._fooChangedCallback.fire.apply(arguments);
};
// start hub and save the promise returned
SignalRManager._start = $.connection.hub.start().done(() =>
{
console.log('Signal R initialized');
});
}
return SignalRManager._start;
}
}
}
Note: there may be extra work involved to handle disconnections or connections lost.

Meteor.http.call gives not allowed by Access-Control-Allow-Origin

When I try to call an external server for JSON queries in Meteor with the Meteor.http.call("GET") method I get the error message "not allowed by Access-Control-Allow-Origin".
How do I allow my meteor app to make HTTP calls to other servers?
Right now I run it on localhost.
The code I run is this:
Meteor.http.call("GET",
"http://api.vasttrafik.se/bin/rest.exe/v1/location.name?authKey=XXXX&format=json&jsonpCallback=processJSON&input=kungsportsplatsen",
function(error, result) {
console.log("test");
}
);
There are other questions similar to this on StackOverflow.
You're restricted by the server you're trying to connect to when you do this from the client side (AJAX).
One way to solve it is if you have access to the external server, you can modify the header file to allow some, or all origins by:
Access-Control-Allow-Origin: *
However, if you place the call on the server side and not provide a callback function, the call will be made synchronously, thus not with AJAX, and it should succeed.
Here's
Meteor.methods({checkTwitter: function (userId) {
this.unblock();
var result = Meteor.http.call("GET", "http://api.twitter.com/xyz", {params: {user: userId}});
if (result.statusCode === 200) return true
return false;
}});

Resources