<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Brian Morearty</title>
    <description>The latest articles on DEV Community by Brian Morearty (@bmorearty).</description>
    <link>https://dev.to/bmorearty</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F392920%2Fd13f6e1f-4f82-4868-8380-15056140ff3f.jpeg</url>
      <title>DEV Community: Brian Morearty</title>
      <link>https://dev.to/bmorearty</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bmorearty"/>
    <language>en</language>
    <item>
      <title>Using RequestStore with asynchronous I/O in Rails apps</title>
      <dc:creator>Brian Morearty</dc:creator>
      <pubDate>Mon, 22 Nov 2021 19:37:29 +0000</pubDate>
      <link>https://dev.to/bmorearty/using-requeststore-with-asynchronous-io-in-rails-apps-3ma5</link>
      <guid>https://dev.to/bmorearty/using-requeststore-with-asynchronous-io-in-rails-apps-3ma5</guid>
      <description>&lt;p&gt;Did you know it’s possible to write Rails apps using non-blocking, asynchronous I/O, the way Node apps work? Your app handles each web request in a fiber. Whenever that fiber fires off a blocking operation like a network call, it can yield the current fiber and allow another fiber to use the CPU. In fact it’s more convenient than Node because your methods are &lt;a href="https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/"&gt;colorless&lt;/a&gt;—there are no issues with synchronous methods calling async methods.&lt;/p&gt;

&lt;p&gt;Writing a Rails app with fibers has two advantages over threads: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No worrying about race conditions. This is a big deal.&lt;/li&gt;
&lt;li&gt;More scalable. Fibers use much less memory than threads. You can create hundreds of thousands of fibers without problems.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can use the &lt;a href="https://github.com/socketry/async"&gt;Async&lt;/a&gt; gem and the &lt;a href="https://github.com/socketry/falcon"&gt;Falcon&lt;/a&gt; web server to take advantage of this capability. And starting in Ruby 3.0, async I/O is even more automatic because inside the Ruby runtime, &lt;a href="https://www.wjwh.eu/posts/2020-12-28-ruby-fiber-scheduler-c-extension.html"&gt;all socket operations will automatically yield the current fiber by default&lt;/a&gt;. It’s fully transparent to the developer. Your I/O calls appear to be blocking so they are easy to understand, consistent with Ruby’s “programmer happiness” philosophy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Problem
&lt;/h1&gt;

&lt;p&gt;As people start using this technique more and more, some problems will come up. One I’ve noticed is the inability to use the &lt;code&gt;request_store&lt;/code&gt; gem. This is a gem that helps you make per-request “global” storage that doesn’t accidentally leak from one request to the next. For example you could use it to store information about the current user without having to pass it down to every method but without worrying that it will leak into the next request. Globals aren’t exactly the best thing ever, but sometimes they’re practical and you do what you gotta do.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;request_store&lt;/code&gt; was written to handle web servers that handle each request in its own thread so it stores the per-request data in thread-local storage in &lt;code&gt;Thread.current[:request_store]&lt;/code&gt;. But the problem is, despite its name, &lt;code&gt;Thread.current&lt;/code&gt; is actually &lt;em&gt;fiber-local&lt;/em&gt;, not thread-local. So your request handler could store the current user info in the request store, then fire off a new fiber to make an I/O call concurrently, and that fiber won’t have access to the request store.&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;To fix this I wrote a new &lt;a href="https://github.com/BMorearty/request_store-fibers"&gt;&lt;code&gt;request_store-fibers&lt;/code&gt;&lt;/a&gt; gem that detects whenever a new fiber is created by hooking into &lt;code&gt;Fiber.new&lt;/code&gt;. Before the fiber is executed, I copy the current request_store data into a variable. Then as soon as the fiber is resumed the very first time, I copy that data into the fiber's request_store.&lt;/p&gt;

&lt;p&gt;Presto! Thanks to Ruby’s ability to hook into core APIs, now you can use &lt;code&gt;request_store&lt;/code&gt; with a Rails app that has fibers.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;request_store-fibers&lt;/code&gt; is actually a thin layer on top of another more generic gem I wrote, &lt;a href="https://github.com/BMorearty/fiber_hook"&gt;&lt;code&gt;fiber_hook&lt;/code&gt;&lt;/a&gt;, which does all the magic. It lets you hook into fiber creation and do anything you want right after any fiber is created and before it executes.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Better Deno Security: Ask for Permission at Runtime</title>
      <dc:creator>Brian Morearty</dc:creator>
      <pubDate>Thu, 28 May 2020 13:46:00 +0000</pubDate>
      <link>https://dev.to/bmorearty/better-deno-security-ask-for-permission-at-runtime-1fnm</link>
      <guid>https://dev.to/bmorearty/better-deno-security-ask-for-permission-at-runtime-1fnm</guid>
      <description>&lt;p&gt;Deno, the new kid on the block in server-side TypeScript and JavaScript, is secure by default. You kind of can’t miss it. They’ve been hammering that point all over their documentation and conference talks just to make sure you know. It’s on &lt;a href="https://deno.land/" rel="noopener noreferrer"&gt;their homepage&lt;/a&gt; too, repeated in the first &lt;strong&gt;three&lt;/strong&gt; sentences.&lt;/p&gt;

&lt;p&gt;I'm glad they chose secure by default. But I'm not crazy about the samples they use to demonstrate security. The samples promote the idea that you should &lt;strong&gt;specify in advance what an app’s permissions are going to be&lt;/strong&gt;. This reminds me of the old Android model, where you had to grant all permissions to an app when installing it. Eventually Android fixed it to be like the better model that iOS and browsers use: &lt;strong&gt;let the program request the necessary permissions at runtime&lt;/strong&gt; so the user can respond to the request in context.&lt;/p&gt;

&lt;p&gt;Let's look at sample code from the &lt;a href="https://deno.land/v1" rel="noopener noreferrer"&gt;Deno v1 announcement&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;serve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/std@0.50.0/http/server.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’ve copied this sample to a GitHub repo so you can run it directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ deno run https://raw.githubusercontent.com/BMorearty/deno-permissions-samples/master/serve-original.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you’ll see that it fails, as it should, because it doesn’t have network permission. The v1 page explains this: "The above example will fail unless the &lt;code&gt;--allow-net&lt;/code&gt; command-line flag is provided."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8i0yept66z5lk1aiahw2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8i0yept66z5lk1aiahw2.png" alt="Deno network permission error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fix by running with &lt;code&gt;--allow-net&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ deno run --allow-net https://raw.githubusercontent.com/BMorearty/deno-permissions-samples/master/serve-original.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(You won’t see any output because it’s silently waiting on a port.)&lt;/p&gt;

&lt;p&gt;Sounds nice and secure. But when a user downloads a script and runs it, or runs it directly off the Internet as in the examples above, they don’t have advance knowledge of why the program needs network permission—or worse, file permission. So they’ll blindly grant it &lt;strong&gt;all&lt;/strong&gt; the permissions it says it needs before they even run it.&lt;/p&gt;

&lt;p&gt;This is similar to what &lt;a href="https://developer.android.com/guide/topics/permissions/overview#install-time_requests_android_511_and_below" rel="noopener noreferrer"&gt;used to be required when installing an Android app&lt;/a&gt;. When I had an Android phone I found it vexing. Sometimes I wanted an app but didn’t want to grant it access to, for example my contacts. The slight improvement with Deno is that at least with Deno, permissions aren’t all-or-nothing, chosen by the developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  A better option: ask for permission at runtime
&lt;/h2&gt;

&lt;p&gt;Thankfully, Deno already provides a better security model than this. It’s just not heavily promoted. The program can ask for permission at the point of need, rather than requiring the user to grant it up front on the command line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// serve-request.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;serve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/std@0.50.0/http/server.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;netPermission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;net&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;netPermission&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;granted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Can’t serve pages without net permission.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the time of this writing, &lt;code&gt;Deno.permissions&lt;/code&gt; is not yet part of the stable API so you need to run this with &lt;code&gt;--unstable&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deno run --unstable https://raw.githubusercontent.com/BMorearty/deno-permissions-samples/master/serve-request.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s how this looks when granting permission (I typed &lt;code&gt;g&lt;/code&gt; and hit &lt;code&gt;Enter&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3ie228vzxgu95x1qluk7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3ie228vzxgu95x1qluk7.png" alt="Ask for permissions at runtime"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here’s how it looks when denying:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw0fzlf7wm3vx3teuqpjx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw0fzlf7wm3vx3teuqpjx.png" alt="Denying permissions at runtime"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The "Deno requests" line is part of Deno itself, not controlled by the app. As you can see from the code above, the “Can’t serve pages without net permission” line is the app’s custom response. An app can respond any way it likes to the user’s choice not to grant permission.&lt;/p&gt;

&lt;p&gt;Don’t worry about Deno asking for permissions that are already granted. If the user runs the app with &lt;code&gt;--allow-net&lt;/code&gt;, the &lt;code&gt;Deno.permissions.request&lt;/code&gt; call won’t redundantly ask for permission. It will just return &lt;code&gt;{ "state": "granted" }&lt;/code&gt; immediately.&lt;/p&gt;

&lt;p&gt;The same is true if an app requests the same permission multiple times at runtime. If it’s already been granted or denied once during runtime, the response is remembered in all subsequent permission requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// request-twice.ts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;netPermission1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;net&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`The first permission request returned &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;netPermission1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;netPermission2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;net&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`The second permission request returned &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;netPermission2&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ deno run --unstable https://raw.githubusercontent.com/BMorearty/deno-permissions-samples/master/request-twice.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, it only asks for permissions once:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F76w4dvddci2zo9d5p6yh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F76w4dvddci2zo9d5p6yh.png" alt="Request permission twice"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Give context when asking for permission
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://developer.apple.com/design/human-interface-guidelines/ios/app-architecture/requesting-permission/#:~:text=Explain%20why%20your%20app%20needs%20the%20information." rel="noopener noreferrer"&gt;iOS Human Interface Guidelines on permissions&lt;/a&gt; state: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Explain why your app needs the information. Provide custom text (known as a purpose string or usage description string) for display in the system's permission request alert, and include an example. Keep the text short and specific, use sentence case, and be polite so people don't feel pressured. There’s no need to include your app name—the system already identifies your app.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is good advice for Deno apps as well. If you give the user context about why you need permission, they’re more likely to grant it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// serve-context.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;serve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/std@0.50.0/http/server.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;netPermission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;net&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;netPermission&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prompt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Net permission needed to serve web pages.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;netPermission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;net&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;netPermission&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;granted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Can’t serve pages without net permission.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This version prints the reason for the request right before making the request. The gives the user enough context to understand why Deno is requesting permission. &lt;/p&gt;

&lt;p&gt;But what’s this call to &lt;code&gt;Deno.permissions.query&lt;/code&gt;? Now that we’re displaying some context before the permission prompt is shown, it’s necessary to first check if the app already has permission. Otherwise you’ll display the permission context for no reason.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Deno.permissions.query&lt;/code&gt; can return three possible states:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;{ "state": "granted" }&lt;/code&gt; means you already have permission.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{ "state": "denied" }&lt;/code&gt; means you have already been denied permission. There’s no point in requesting it because it will return "denied" immediately without showing a prompt.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{ "state": "prompt" }&lt;/code&gt; means if you call &lt;code&gt;request&lt;/code&gt;, a prompt will be shown to the user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deno run --unstable https://raw.githubusercontent.com/BMorearty/deno-permissions-samples/master/serve-context.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you’ll see the prompt:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fycz7ua85gcau7fqq6zay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fycz7ua85gcau7fqq6zay.png" alt="Give context before requesting permission"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you run with &lt;code&gt;--allow-net&lt;/code&gt;, you can see that it doesn’t display the context because the call to &lt;code&gt;Deno.permissions.query&lt;/code&gt; indicated that the call to &lt;code&gt;Deno.permissions.request&lt;/code&gt; would return success.&lt;/p&gt;

&lt;p&gt;In my opinion this is the best way to deal with permissions in your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wish list: store permissions persistently for installed scripts
&lt;/h2&gt;

&lt;p&gt;Deno has a &lt;code&gt;deno install&lt;/code&gt; command that lets you add a Deno script to your machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ deno install --unstable https://raw.githubusercontent.com/BMorearty/deno-permissions-samples/master/serve-context.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This downloads, compiles, and caches the script and its dependencies. It also creates an executable script. On a Mac it’s stored in &lt;code&gt;~/.deno/bin/serve-context&lt;/code&gt; (you can add &lt;code&gt;~/.deno/bin&lt;/code&gt; to your PATH) and looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c"&gt;# generated by deno install&lt;/span&gt;
deno &lt;span class="s2"&gt;"run"&lt;/span&gt; &lt;span class="s2"&gt;"--unstable"&lt;/span&gt; &lt;span class="s2"&gt;"https://raw.githubusercontent.com/BMorearty/deno-permissions-samples/master/serve-context.ts"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that parameters you pass to &lt;code&gt;deno install&lt;/code&gt;, such as &lt;code&gt;--unstable&lt;/code&gt;, get passed on to &lt;code&gt;deno run&lt;/code&gt;. You could &lt;code&gt;deno install --allow-net https://my/script&lt;/code&gt; and it would store the &lt;code&gt;--allow-net&lt;/code&gt; permission in the executable.&lt;/p&gt;

&lt;p&gt;Again, it’s not ideal to require your users to decide up front what all the permissions are. But Deno doesn’t store the permissions persistently. After installing &lt;code&gt;serve-context&lt;/code&gt; without &lt;code&gt;--allow-net&lt;/code&gt;, every time I run it, it asks for net permission.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I’d love to see an improvement to Deno that allows it to locally cache the user’s answers to permission questions per app.&lt;/strong&gt; This is what browsers do when a domain requests permission, such as camera or geolocation. Of course you’d also need a way to revoke or grant permissions after the fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wish list: let the script pass the reason into the &lt;code&gt;request&lt;/code&gt; call
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;serve-context&lt;/code&gt; example we had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call &lt;code&gt;Deno.permissions.query&lt;/code&gt; to see if a permission has been granted.&lt;/li&gt;
&lt;li&gt;If not:

&lt;ol&gt;
&lt;li&gt;Display a reason that the script needs the permission&lt;/li&gt;
&lt;li&gt;Request it with &lt;code&gt;Deno.permissions.request&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;It’d be a lot simpler if you could do all this in a single call to &lt;code&gt;Deno.permissions.request&lt;/code&gt;. &lt;strong&gt;I think Deno should let the script pass in a short &lt;code&gt;reason&lt;/code&gt; string to the permission request. If the script doesn’t already have permission, the reason would be displayed before the user is asked to grant permission&lt;/strong&gt;. If the script already has permission, the reason won’t be displayed.&lt;/p&gt;

&lt;p&gt;If Deno supported this, the steps would be shortened to just:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Request permission with &lt;code&gt;Deno.permissions.request&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is what the code would look like (not runnable because &lt;code&gt;reason&lt;/code&gt; is not currently a valid key to pass in to &lt;code&gt;request&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// serve-reason.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;serve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/std@0.50.0/http/server.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;netPermission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;net&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Net permission needed to serve web pages.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;netPermission&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;granted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Can’t serve pages without net permission.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://deno.land/typedoc/classes/deno.permissions.html" rel="noopener noreferrer"&gt;Deno permissions documentation&lt;/a&gt;. The list of permission types is in the &lt;code&gt;PermissionDescriptor&lt;/code&gt; type, but as of this writing, Deno doesn't seem to have docs for this type.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/denoland/deno/blob/f6e58b076ca430c29f164b65678bbf6bc64a39b7/cli/js/lib.deno.unstable.d.ts#L1122-L1184" rel="noopener noreferrer"&gt;Current list of &lt;code&gt;PermissionDescriptor&lt;/code&gt; values, currently in unstable.ts&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can &lt;a href="https://twitter.com/BMorearty" rel="noopener noreferrer"&gt;follow me on Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>deno</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
