How to hide server code when using pub/sub

Hello, i’m facing a serious issue but don’t how to solve it.
My structure code:
server/main.js
imports/api/payments.js
imports/ui/Payments.js
main.js:

...
import '../imports/api/payments';
...

payments.js:

...
export const Payments = new Mongo.Collection('payments');

if ( Meteor.isServer ){
Meteor.publish('payments', function (){
	if ( !this.userId )
		return this.stop();
	if(Roles.userIsInRole(this.userId, 'admin',  Roles.GLOBAL_GROUP)) {	
		 	return apiPayments.find({});	
	} else {
		return apiPayments.find({userId: this.userId});
	}
 });
Meteor.methods({
'payments.build'(amount, options){
//my secret code;
}
});

}

...

Payments.js:

...
import { Payments } from '../../api/payments.js';
Meteor.subscribe('payments');
let payments = Payments.find({}).fetch();
...

I’m able to list all of user’s payment on client but all the code in Meteor.isServer block was exposed to the client. I tried to declare a Payments on Payments.js like this:

//import { Payments } from '../../api/payments.js';

const Payments = new Mongo.Collection('payments');

Meteor.subscribe('payments');
let payments = Payments.find({}).fetch();

Then i met this error: collection.js:269 Uncaught Error: There is already a collection named “payments”

How could i avoid this? I don’t know how to fix this issue, thank for any help!

I think it’s best if you peruse the documentation. Meteor.isServer indeed won’t prevent your code from being delivered to the front-end.

For that, you need to structure your application into server and client modules. More info here: https://guide.meteor.com/structure.html#javascript-structure

1 Like

I thought Meteor.isServer only work on server, where should i put the server only code if there are some functions i don’t want to show in the client?

Hi,
You can have a look at this section in Meteor guide about security.
I think it’s specific to methods but I guess you can apply the same thing for publications.

1 Like

No, Meteor.isServer and Meteor.isClient are blocks that you put in a file common to both server and client, but instructing Meteor to execute some code within the common file on the server, and maybe other block when on the client.

A good example of that are the files where you declare your collections, but you can set indexes only inside an isServer block. You should read about the concept of isomorphism in Meteor.

However, from your question I gather you’ve only just skimmed through the documentation and tutorials :). Not sure you’re going to get much more help without at least learning the basics.

I promise you, all this is explained very well in the docs.

1 Like

Have you removed the insecure and autopublish packages?

You can examine the installed packages by typing

meteor list

at the command line in your meteor app directory. If they are present, remove them by typing

meteor remove insecure
meteor remove autopublish

These two packages are enabled by default to help make development easier. But they don’t enforce tight separation of client and server.

Let me know if that helps.

1 Like

the best way is split server and client code. using DDP.

https://medium.com/@imhazige/custom-build-meteor-via-docker-and-deploy-to-heroku-27ccf943d5a9

1 Like

Nice info, but you’ll get the OP even more confused with this, as it is more pertinent to deployment. All the OP needed to know was how to separate server code from the client one.

This is helpful information but it does not address the OP’s question in any way.

I don’t understand why no one’s answering the question.

In your package.json, you have something like

  "meteor": {
    "mainModule": {
      "client": "client/main.js",
      "server": "server/main.js"
    },
    "testModule": "tests/main.js"
  },

Everything in server/main.js, including all its imports, will not be sent to the client. Everything imported from client/main.js will be sent to the client. In addition, nothing in the server directory will be sent the client.

server
Any directory named server/ is not loaded on the client. Similar to wrapping your code in if (Meteor.isServer) { ... } , except the client never even receives the code. Any sensitive code that you don’t want served to the client, such as code containing passwords or authentication mechanisms, should be kept in the server/ directory.
Meteor gathers all your JavaScript files, excluding anything under the client , public , and private subdirectories, and loads them into a Node.js server instance. In Meteor, your server code runs in a single thread per request, not in the asynchronous callback style typical of Node.
Therefor, if you don’t want something sent to the client, you should either put it in server/main.js, or in a file that server/main.js imports.

3 Likes

Thank you all because helpful information guys, i have solved my problem by stop use pub/sub mechanism.

You don’t need to stop using pub-sub because of this.

The summary, as pointed out above, is that code within an isServer block is sent to the client, but not run on the client. Code within a server file/directory is not sent to the client.

So, all your publications should be within a server only directory.

For methods where you are using a server side secret (e.g. as alluded to by your payments.js), you can create a function on a server file, and then import and call the function within an isServer block - the import itself will need to be within the isServer block to prevent any of that code from being sent to the client.

2 Likes