Preventing global installations of an NPM package - node.js

I have a library and want to encourage/force users to use the locally installed version only. I could do this the hard way or the easy way.
The easy way would be if NPM had a mechanism to prevent using the --global switch with the npm install command, for any library.
The hard way would be to add code in my NPM packaged that returned early if the code determined it was globally installed not locally installed.
Does anyone know if you can prevent global installations of an NPM package? What might be the most user friendly way to approach this?

The best way to prevent users from installing your module globally would be to describe your preference in the documentation.
There is nothing you can do to force your users to never install it globally if they can install it locally. They will always be able to move the files manually if they want.
In the npm community the assumption is that the user has control over the modules he/she uses, not the other way around. Forcing people to use your module in certain ways will only make them unhappy.
So the only good answer to your question is to document the way your code should be used. You can ask them to use your module a certain way - but they are the ones who can choose to listen to you or not. You can state that using your module installed globally is unsupported, unwise, discouraged, dangerous, but you will not be able to force users to use the module as you want, and that's a good thing.
Now, for some bad answers, you can always test if the parent of your module's root directory is named node_modules or not and fail if it isn't but I'm sure it can cause some trouble if someone happens to install your module locally as you want but under a different directory. You can see if your module is run from one of the default paths that node uses to search for modules but those paths are not always the same, and you'd have to take the NODE_PATH environment variable into account as well.
You can do few tricks like that but they can only annoy users who know what they are doing because they will have to change the source code of your module to do what they want, and they will always be able to do that, no matter how hard you try to make their life harder.
In summary, my recommendation would be to document your module well and respect your users and their needs, and trust them to know what they're doing.
Update
For a working example of a Bash function that prevents global npm installation of a certain module, see this answer - section Working example of preventing global install.

Related

NodeJS sub-projects installation

I have a large project that contains multiple sub-modules, many of which are optional. And I have each sub-module sitting in its own folder with local package.json.
I'm trying to figure out the best way to create an integral package.json that would be able to run npm install on a specific subset of those modules.
Question
Is there a more civilized approach these days than just running npm install from every sub-module folder? I want to be able to halt the integral installation when it fails for one module, and hopefully do it on a declarative level within package.json, rather than implementing such logic myself. Plus, I want postinstall-s run on each package (if present), and then one of the integration package.
Other than that, maybe there is a better way today to manage such projects? I'm open to any suggestions!

Use different node module depending on environment?

I have a npm package that we use for multiple projects. Currently when I want to make a change to something on these projects that requires a change on the npm package I need to make a change to the npm package, submit a pr, wait for someone to merge it for me and then I can actually test the changes I made on the other projects (no testing is set up currently sadly).
What I want to do is on the other projects have a way to install / use the local module instead of the global one so I can test the full flow before I submit any prs. Im using config package and ideally I can set it up so if I use a specific config file it defaults to local npm package instead of global.
Is this possible?
Based on what you are describing, take look at the link command offered by package managers to help solve this:
https://classic.yarnpkg.com/en/docs/cli/link#search
https://docs.npmjs.com/cli/v8/commands/npm-link

What are the risks of installing (running) foreign npm modules? Can we limit the risks?

According to this post, malicious npm modules are real. And it seems the only real approach is to "be aware of what you're installing."
When I npm install and require() a module,
Could it access my entire file system?
Can I limit the file system access to a specific directory? Either with a package.json setting, or maybe with the OS's native user/groups file permission system?
Could it execute any commands? Download anything, execute anything, upload anything?
Can I restrict this?
An npm package (like any library/software) has the full access to whatever environment you put it in. If you can do it in Node.js, an npm package can do it.
As a package manager, npm can effectively put a file anywhere (ex. an malicious executable) and when a function is called it can do whatever it was programmed to (ex. execute the malware).
Software auditing is real, and a major push is being done by various Open Source groups to help make sure that software doesn't have any critical flaws (intentional or otherwise). Before you install, find the package.json file and give it a read, if something seems suspicious you might have to dig deeper (ask a dev or community member for help). If the software is open source look for audits (or audit yourself).
There are some suggestions listed in this Medium article: https://medium.com/#nodepractices/were-under-attack-23-node-js-security-best-practices-e33c146cb87d
Recommendation: Try to be a white hat hacker. Check out the technology and try to infect your own machine with some malicious code you made, then see if there's a way you could have avoided it.
Source:
https://docs.npmjs.com/files/package.json
https://docs.npmjs.com/cli/install
As you said, the only way to prevent this is to "be aware of what you're installing."
Short answer: When you require a module, it becomes your code
Could it access my entire file system ?: YES it can ! fs-extra and chokidar require native fs module
Can I limit the file system access to a specific directory?: No you can't ! As I said above, it becomes your code once you require it. You can't or don't want to limit access to yourself...
Could it execute any commands? : Yes it can ! shelljs can do it
Can I restrict this? : Yes you can: Don't be lazy ! Do not install any module for small tasks like set environment, set CORS setup etc... ! Try to achieve it yourself with natives Nodejs's elements.
The essential modules of are generally audited and used by millions of senior developers around the world.

How to create a custom rule to copy folder and perform npm install

I'm just starting with Bazel, I want to create a rule that copies my nodejs application (folder) inside the sandbox, copies other local packages (referenced in package.json using the file:// annotation) and perform a npm install action.
The output directory should then be a distributable nodejs application with the node_modules/ already set and working (or this is what I want to get).
I've tried by starting over this rule but I can't seem to perform any modification over it and I don't know where to go from there since the logic is pretty hard to follow.
I also tried to start with an easier action but I cannot get it right, especially regarding the local libraries, because it won't allow me declare as glob any file containing "..".
Can you please give some advice to get started?
If possible I'd also like to know how could I dynamically generate a JSON file, so I'd be able to declare my node dependencies in bazel itself (being able to track them down and centralize their version).
this won't be an easy exercise :) It's perfectly doable, and at the end you'll be perfectly comfortable understanding what that rule does :)
I suggest you to read the documentation on writing extensions and custom Skylark rules to start. Be sure to start small and iterate.
It's quite cumbersome to work with directories, you might want to create a tar first. You can also perform npm install if you really want to, but it will have caching and remote execution implications.
And of course, you can generate json in Skylark.

How to deal with local package dependencies in nodejs with npm

How should we deal with local packages that are a dependency in other local packages?
For simplicities sake, say we have the follow packages
api - express application
people - a package to deal with people
data-access - a package that deals with data access
And then the dependencies are
api depends on people
people depends on data-access
Currently we have these dependencies setup as file dependencies.
I.e. api package.json would have
"dependencies": {
"people": "file:../people"
}
Trouble with this is that we're finding it a PITA when we make updates to one package and want those changes in the other packages that depend on it.
The options we have thought of are:
npm install - but this won't overwrite previously installed packages if changes are made, so we have to delete the old one from the node_modules directory and re-run npm install... which can be niggly if the package dependency is deep.
npm link - we're not sold on the idea because it doesn't survive version control... Just thinking about it now, maybe we have some kind of local build script that would run the npm link commands for us... this way it could survive version control. Would that be a grunt job?
grunt - we haven't dived too deep into this one yet, but it feels like a good direction. A little bit of googling we came accross this: https://github.com/ahutchings/grunt-install-dependencies
So, what option would work best for our situation?
Are there other options that we haven't thought of yet?
Ps. we're a .NET shop doing a PoC in node, so assume we know nothing!
Pps. if you strongly believe we're setting up our project incorrectly and we shouldn't have smaller individual packages, let me know in the comments with a link to some reading on the subject.
So, I agree that going with 'many small packages' is usually a good idea. Check out 12factor.net if you haven't already.
That said, in specific answer to your question I'd say your best bet is to consider mainly how you want to maintain them.
If the 'subcomponents' are all just parts of your app (as, for example, data-access implies), then I'd keep them in the same folder structure, not map them in package.json at all, and just require them where you need them. In this case, everything versions together and is part of the same git repository.
If you really want to or need to keep them all in separate git repositories, then you can do npm link, but to be honest I've found it more useful to just use the URL syntax in package.json:
dependencies: {
"people" : "git://path.to.git:repo#version.number"
}
Then, when you want to explicitly update one of your dependencies, you just have to bump the version number in your package.json and run npm install again.

Resources