<p dir="auto">If not I would like to request this feature.</p>
<p dir="auto">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.</p>
<p dir="auto">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.</p>
<p dir="auto">I don't really know if this is feasible.<br>
Btw good job on Deno! Its pretty cool so far.</p>
<p dir="auto">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.</p>
<p dir="auto">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.</p>
<p dir="auto">For some context, I want to point to <a href="https://hackernoon.com/im-harvesting-credit-card-numbers-and-passwords-from-your-site-here-s-how-9a8cb347c5b5" rel="nofollow">the article I've seen most on this topic</a>. 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).</p>
<p dir="auto">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.</p>
<p dir="auto">Unfortunately, barring switching back to <code class="notranslate">require</code>, 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).</p>
<hr>
<p dir="auto">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:</p>
<div class="highlight highlight-source-json notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
  &quot;dependencies&quot;: {
    &quot;https://unpkg.com/somepackage@0.0.1/somepackage.min.js&quot;: {
      &quot;permissions&quot;: {
         &quot;http&quot;: true,
         &quot;fs&quot;: true
       }
    },
    &quot;https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js&quot;: {
      &quot;permissions&quot;: {
          &quot;*&quot;: true
       }
    }
  }
}"><pre class="notranslate">{
  <span class="pl-ent">"dependencies"</span>: {
    <span class="pl-ent">"https://unpkg.com/somepackage@0.0.1/somepackage.min.js"</span>: {
      <span class="pl-ent">"permissions"</span>: {
         <span class="pl-ent">"http"</span>: <span class="pl-c1">true</span>,
         <span class="pl-ent">"fs"</span>: <span class="pl-c1">true</span>
       }
    },
    <span class="pl-ent">"https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js"</span>: {
      <span class="pl-ent">"permissions"</span>: {
          <span class="pl-ent">"*"</span>: <span class="pl-c1">true</span>
       }
    }
  }
}</pre></div>
<hr>
<p dir="auto">A language level solution might include a tweak to <code class="notranslate">import</code> such as <code class="notranslate">import a from 'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js' permit(http, fs)</code> or a more Rusty solution which I kind of like better:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import a from 'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js';

await a.initializeSafely();

// ...

%permit(http, fs) {
  await a.doSomethingDangerous();
}"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">a</span> <span class="pl-k">from</span> <span class="pl-s">'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js'</span><span class="pl-kos">;</span>

<span class="pl-k">await</span> <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-en">initializeSafely</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-c">// ...</span>

<span class="pl-c1">%</span><span class="pl-en">permit</span><span class="pl-kos">(</span><span class="pl-s1">http</span><span class="pl-kos">,</span> <span class="pl-s1">fs</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-k">await</span> <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-en">doSomethingDangerous</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">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 <em>only</em> <code class="notranslate">doSomethingDangerous</code> can make http requests, while <code class="notranslate">initializeSafely</code> remains safe. So the package writers can't use the permissions you give them just because you import them.</p>
<p dir="auto">I think this is harder to enforce at runtime in general but especially in-browser, but I'd leave that to ebwckpa or whomever.</p>
<p dir="auto">Arguably, this is also similar to what Haskell might do, or just similar to how <code class="notranslate">async/await</code> 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.</p>
<hr>
<p dir="auto">A string related kludge is very similar to modifying <code class="notranslate">import</code>:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import a from 'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js permit(http, fs)';"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">a</span> <span class="pl-k">from</span> <span class="pl-s">'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js permit(http, fs)'</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">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.</p>
<hr>
<p dir="auto">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.</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="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();"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">makeA</span> <span class="pl-k">from</span> <span class="pl-s">'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js'</span><span class="pl-kos">;</span>
<span class="pl-k">import</span> <span class="pl-s1">fs</span> <span class="pl-k">from</span> <span class="pl-s">'fs'</span><span class="pl-kos">;</span>
<span class="pl-k">import</span> <span class="pl-s1">http</span> <span class="pl-k">from</span> <span class="pl-s">'http'</span><span class="pl-kos">;</span>

<span class="pl-k">const</span> <span class="pl-s1">a</span> <span class="pl-c1">=</span> <span class="pl-en">makeA</span><span class="pl-kos">(</span><span class="pl-kos">{</span> fs<span class="pl-kos">,</span> http <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-k">await</span> <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-en">doSomethingDangerous</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">I could also see this being combined with an import modification:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import makeA from 'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js' with fs=fs, http=http;"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">makeA</span> <span class="pl-k">from</span> <span class="pl-s">'https://unpkg.com/highlytrustedpackage@1.2.3/ok.min.js'</span> <span class="pl-s1">with</span> <span class="pl-s1">fs</span><span class="pl-c1">=</span><span class="pl-s1">fs</span><span class="pl-kos">,</span> <span class="pl-s1">http</span><span class="pl-c1">=</span><span class="pl-s1">http</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">wherein the inner package would not be allowed to <code class="notranslate">import 'fs'</code> 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).</p>
<p dir="auto">In an ideal world (and I do actually think this would be the best solution possible), deno would disallow <code class="notranslate">import</code>ing 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:</p>
<ul dir="auto">
<li>Allowing inner modules to easily and ergonomically offer custom replacements
<ul dir="auto">
<li>Bluebird instead of native promises, for example</li>
</ul>
</li>
<li>Mocking during testing (think Jest, but available all the time as a first-class citizen)</li>
<li>Initialization parameters (no need to separately call <code class="notranslate">mod.initialize({ /* ... */ })</code>)</li>
</ul>
<hr>
<p dir="auto">Very curious to hear what everyone's thoughts are.</p>