Issue 1:
If not I would like to request this feature.

Given the fact that npm modules have been hacked before and that I/we will use modules from the registry it would be nice if we could reduce the threat of these modules and only give permissions to each module if necessary.

If this is possible I would suggest a new parameter like --block-external which would deny all given permissions from cached/external modules and than each permission could be extended by a list that would come after it.

I don't really know if this is feasible.

Btw good job on Deno! Its pretty cool so far.

Issue 2:
So I love the concept of privileged vs. unprivileged. During the talk at JSConf, Ryan recognizes that a linter should not be allowed to, for example, make network requests. I think this is a powerful concept, but I also think it's not quite powerful enough.

JS and in particular node/npm gets a bad rep these days for security. First of all, I think this is unwarranted generally speaking, as the kinds of things people point out are equally accurate in most package managers/languages/runtimes, if not more so. However, if deno is going to consider permissions to be a language/runtime level concern, I think it should go a step further.

For some context, I want to point to the article I've seen most on this topic. The concern in this particular article is a little different than the one I'm proposing deno attempt to solve because deno is backend and the article proposes a frontend security issue, but it's certainly related and if deno is going to end up with similar usecases to node, of course we will be using it on the front end as well. The issue is that a node module N dependencies deep can do arbitrary things like read files, read environment variables, make requests to servers, etc., and the end user won't necessarily ever know about it (and the middle package maintainers very well might not either).

Sandboxing on an application-level is a start, but I just don't think it goes far enough for practical needs. I think an amazing module/dependency system (which I think deno is trying to create) should be able to "sandbox" individual module/dependencies, and that this should even be the default behavior.

Unfortunately, barring switching back to require, all of the ideas I have either rely on using some kind of manifest such as package.json, a language-level change, some kind of string-related kludge, or mandatory dependency injection. In my opinion, the first two are the most reasonable (knowing absolutely nothing about deno internals).

The manifest solution is, of course, quite simple. You can just add permissions to modules that would cascade down. An example given using typical package.json structure:

{
"dependencies": {
"https://unpkg.com/somepackage@0.0.1/somepackage.min.js": {
"permissions": {
"http": true,
"fs": true
}
},
"https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js": {
"permissions": {
"*": true
}
}
}
}

A language level solution might include a tweak to import such as import a from 'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js' permit(http, fs) or a more Rusty solution which I kind of like better:

import a from 'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js';

await a.initializeSafely();

// ...

%permit(http, fs) {
await a.doSomethingDangerous();
}

The reason I like this solution better is because it now makes it even harder for package writers to hijack permissions just because they happen to be using them elsewhere. That is to say, now only doSomethingDangerous can make http requests, while initializeSafely remains safe. So the package writers can't use the permissions you give them just because you import them.

I think this is harder to enforce at runtime in general but especially in-browser, but I'd leave that to ebwckpa or whomever.

Arguably, this is also similar to what Haskell might do, or just similar to how async/await works with the implicit "pre-emption" permission; you need to yield power to it for it to use that power. If arbitrary commands could allow pre-emption, that would be inherently insecure as much of our code is written with the understanding that it will be executed synchronously.

A string related kludge is very similar to modifying import:

import a from 'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js permit(http, fs)';

I don't love it but it would be relatively easy to implement on the surface level, I believe, as it's just a matter of resolution middleware.

Mandatory dependency injection would essentially disallow libraries from importing system APIs. This is kind of nice for all the reasons dependency injection is nice, and annoying for all the reasons dependency injection is annoying.

import makeA from 'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js';
import fs from 'fs';
import http from 'http';

const a = makeA({ fs, http });

await a.doSomethingDangerous();

I could also see this being combined with an import modification:

import makeA from 'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js' with fs=fs, http=http;

wherein the inner package would not be allowed to import 'fs' without the place where it's imported having explicitly defined this behavior. The issue here is a lack of flexibility (such as a lower ability to mock-in-place).

In an ideal world (and I do actually think this would be the best solution possible), deno would disallow importing system libraries from inside modules and allow grand overrides of inner module dependencies, with additional configuration allowed at runtime. This would enable the following usecases, almost all of which are more ergonomic if it's allowed at runtime:

Allowing inner modules to easily and ergonomically offer custom replacements

Bluebird instead of native promises, for example

Mocking during testing (think Jest, but available all the time as a first-class citizen)

Initialization parameters (no need to separately call mod.initialize({ /* ... */ }))

Very curious to hear what everyone's thoughts are.