<?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: Jesse Ditson</title>
    <description>The latest articles on DEV Community by Jesse Ditson (@jesseditson).</description>
    <link>https://dev.to/jesseditson</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%2F19727%2Ffe8b205c-76b9-49fc-96a0-b9280ba665be.jpeg</url>
      <title>DEV Community: Jesse Ditson</title>
      <link>https://dev.to/jesseditson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jesseditson"/>
    <language>en</language>
    <item>
      <title>cf-doh: look up DNS records from your frontend javascript</title>
      <dc:creator>Jesse Ditson</dc:creator>
      <pubDate>Mon, 07 Oct 2024 22:52:46 +0000</pubDate>
      <link>https://dev.to/jesseditson/cf-doh-look-up-dns-records-from-your-frontend-javascript-418k</link>
      <guid>https://dev.to/jesseditson/cf-doh-look-up-dns-records-from-your-frontend-javascript-418k</guid>
      <description>&lt;p&gt;Recently when working on &lt;a href="//archival.dev"&gt;Archival&lt;/a&gt;, I found myself needing to check the DNS records of a domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Archival Pro allows users to point custom domains at Archival sites. To enable https for these sites, we use a TXT-record based domain verifier to verify ownership before issuing an SSL. To make this process simpler, I needed to query the records to check if the CNAME and TXT records are configured correctly and show some helpful messages if not.&lt;/p&gt;

&lt;p&gt;In a node.js or C-like environment this is quite simple, as each OS has a local DNS cache and lookup tools. However, I was running this in a cloudflare worker, which is actually a v8 isolate and therefore doesn't have access to the OS's dns system. In fact, even with &lt;code&gt;nodejs_compat&lt;/code&gt; turned on, the &lt;code&gt;dns&lt;/code&gt; library from node's stdlib will just return an empty object.&lt;/p&gt;

&lt;h2&gt;
  
  
  DNS-over-HTTPS
&lt;/h2&gt;

&lt;p&gt;After doing a bit of research, I realized that the modern DNS-over-HTTPS would be a good fit for this problem, and has uses outside of my narrow case. However I didn't love any of the libraries on npm for this use case - what I wanted was something more similar to node's DNS library, which abstracts away the lookup servers.&lt;/p&gt;

&lt;p&gt;Cloudflare offers a DNS-over-HTTPs solution, which you can read about here: &lt;a href="https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/" rel="noopener noreferrer"&gt;https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The primary downside to this API is that it can be a bit opaque to average users - the status codes are returned as numbers that map to a spec, and the response format is in Question and Answer format and includes granular data that, while useful, is overkill for most casual use.&lt;/p&gt;

&lt;h3&gt;
  
  
  A simple package
&lt;/h3&gt;

&lt;p&gt;To make this easy for myself and others, I published &lt;a href="https://www.npmjs.com/package/cf-doh" rel="noopener noreferrer"&gt;cf-doh&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a simple library that makes it super simple to query records from the browser, cloudflare workers, or anywhere else that javascript runs. It depends on a native &lt;code&gt;fetch&lt;/code&gt; implementation, and allows setting one if you don't already have one, so if you desire you can even run in node with a polyfilled whatwg fetch implementation - however if you're in node, you'll also have &lt;code&gt;node:dns&lt;/code&gt; which is likely what you want.&lt;/p&gt;

&lt;p&gt;In addition to wrapping the fetch calls, this library provides full types for the entire spec, handles quoted string responses, and converts http errors and status responses into exceptions.&lt;/p&gt;

&lt;p&gt;Usage is simple:&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;queryDNS&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;cf-doh&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;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;queryDNS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_verification.jesseditson.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TXT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you prefer a typed value, you can even import all valid record types and use them instead of strings:&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;queryDNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DNSRecordType&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;cf-doh&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;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;queryDNS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_verification.jesseditson.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DNSRecordType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TXT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to handle statuses other than &lt;code&gt;NoError&lt;/code&gt;, you can instead use a lower level API:&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;queryDNSRecords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DNSRecordType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DOHStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DOHStatusMessage&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;cf-doh&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;queryDNSRecords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_verification.jesseditson.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DNSRecordType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TXT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;DOHStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NoError&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;This record exists!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;DOHStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NXDomain&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;Domain wasn't found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;default&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="nx"&gt;DOHStatusMessage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;break&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;To add this to your project, just run &lt;code&gt;npm install --save cf-doh&lt;/code&gt;. If you're curious about the source or full API surface, check out the repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jesseditson/cf-doh" rel="noopener noreferrer"&gt;https://github.com/jesseditson/cf-doh&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cloudflare</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Quip 2020 Diversity Scholarship</title>
      <dc:creator>Jesse Ditson</dc:creator>
      <pubDate>Wed, 20 May 2020 19:37:42 +0000</pubDate>
      <link>https://dev.to/jesseditson/quip-2020-diversity-scholarship-3hpm</link>
      <guid>https://dev.to/jesseditson/quip-2020-diversity-scholarship-3hpm</guid>
      <description>&lt;p&gt;Hey there! I work for Quip, a Salesforce company - every year for the last 5 years we've run a program where we offer a small scholarship for diverse tech students, and I'd love to see some applicants come from this community. Obviously with the pandemic making everyone nervous, we're also seeing our responses lower than normal, which is a bit disappointing. I've worked on prior years directly and can vouch for the impact it can have, and I absolutely love hearing about the applicants every year, it's incredibly inspiring.&lt;/p&gt;

&lt;p&gt;If you fit the description please apply (and reach out if you have questions), and if not, please share with your network! Things are crazy, and I'm hoping this could help motivate someone to continue their journey.&lt;/p&gt;

&lt;p&gt;Here's the company blurb:&lt;/p&gt;

&lt;p&gt;Applications for 2020 Quip Diversity Scholarship are now being accepted. Winners will be invited to a full day of learning and mentorship. Each winner will also receive $5,000 toward their education. For details and eligibility, see our blog post: &lt;a href="https://quip.com/blog/2020-quip-diversity-scholarship" rel="noopener noreferrer"&gt;https://quip.com/blog/2020-quip-diversity-scholarship&lt;/a&gt;&lt;/p&gt;

</description>
      <category>scholarship</category>
      <category>internship</category>
      <category>inclusion</category>
      <category>tech</category>
    </item>
  </channel>
</rss>
