<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.2.2">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" hreflang="en" /><updated>2024-09-28T01:11:33+00:00</updated><id>/feed.xml</id><title type="html">resilient.is</title><subtitle>Resilient web without gatekeepers.</subtitle><entry><title type="html">More funding, new milestones</title><link href="/blog/more-funding-new-milestones/" rel="alternate" type="text/html" title="More funding, new milestones" /><published>2023-04-12T00:00:00+00:00</published><updated>2023-04-12T00:00:00+00:00</updated><id>/blog/more-funding-new-milestones</id><content type="html" xml:base="/blog/more-funding-new-milestones/"><![CDATA[<p>Good news: <a href="https://resilient.is/docs/plugins/dnslink-fetch/">NLnet Foundation</a> decided to extend their <a href="https://nlnet.nl/project/libresilient/">small grant for LibResilient</a>! That grant funded bulk of the work over the last year and a half. It will now continue to do so for the next year or so.</p>

<p>The grant extension also helped to define the milestones for 2023. Here they are, in no particular order — the order they get implemented depends on many factors, including some non-obvious interplay between them. Some of these milestones are pretty simple, some will require substantial re-writes. Exciting times ahead!</p>

<h2 id="improved-user-experience"><a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/8">Improved user experience</a></h2>

<p>LibResilient needs a “still loading” screen to be displayed when loading HTML resources over
slow transports. For example, retrieving content from <code class="language-plaintext highlighter-rouge">IPFS</code> can take upwards of 20s to load
sometimes. Currently the user experience here is lacking: depending on browser timeout defaults,
the page fails to load, showing an obscure error, and then suddenly loads and displays content.</p>

<p>Also, LibResilient currently kicks-in on the second request to a site that uses it, as that’s when
the ServiceWorker gets actually loaded. This could be improved by using <a href="https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim"><code class="language-plaintext highlighter-rouge">Clients.claim()</code></a>.</p>

<h3 id="plan">Plan</h3>

<ul>
  <li>implement a “still loading” screen; research questions:
    <ul>
      <li>will the return temporary HTML content need to explicitly redirect?</li>
      <li>or will the browser redirect by itself?</li>
      <li>which HTTP codes to use?</li>
    </ul>
  </li>
  <li>test <code class="language-plaintext highlighter-rouge">Clients.claim()</code> use and implement if makes sense</li>
</ul>

<h2 id="mime-type-deduction"><a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/9">MIME-type deduction</a></h2>

<p>When retrieving content using certain transports (for example <code class="language-plaintext highlighter-rouge">IPFS</code>), MIME-type information is not
available. Currently, plugins that face this issue naïvely try to guess the MIME-type based on file
extension. What is needed is a facility to reliably establish MIME-types of requested content,
made available by the ServiceWorker itself to all plugins that need it.</p>

<h3 id="plan-1">Plan</h3>

<ul>
  <li>implement MIME-type deduction directly in the ServiceWorker code
    <ul>
      <li>research if it would be possible to achieve this by looking at actual content, using some MIME-sniffing JS library</li>
    </ul>
  </li>
  <li>define an internal API for plugins to use when they need it</li>
  <li>update plugins which currently use the naïve approach to use the new internal API</li>
  <li>document all of this properly</li>
</ul>

<h2 id="corbcorscsp-related-testing-and-documentation"><a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/10">CORB/CORS/CSP-related testing and documentation</a></h2>

<p>The interplay between LibResilient, <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy"><code class="language-plaintext highlighter-rouge">CORB</code></a>, <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"><code class="language-plaintext highlighter-rouge">CORS</code></a>, and <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP"><code class="language-plaintext highlighter-rouge">CSP</code></a> is not well documented.</p>

<p>Documenting it well requires substantial testing on small but purpose-built infrastructure.</p>

<h3 id="plan-2">Plan</h3>

<ul>
  <li>design and deploy infrastructure for testing <code class="language-plaintext highlighter-rouge">CORB</code>/<code class="language-plaintext highlighter-rouge">CORS</code>/<code class="language-plaintext highlighter-rouge">CSP</code> in the context of LibResilient</li>
  <li>test different settings and edge-cases</li>
  <li>document best practices and potential pitfalls</li>
</ul>

<h2 id="cookiescredentials-related-testing-and-documentation"><a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/11">Cookies/credentials-related testing and documentation</a></h2>

<p>The assumption is that cookies and other credentials should not be exposed to alternative
transports (for example), but this needs strict testing and documentation. Perhaps this should also
be configurable.</p>

<h3 id="plan-3">Plan</h3>

<ul>
  <li>design and deploy infrastructure for testing this</li>
  <li>test settings, assumptions, and edge-cases</li>
  <li>document best practices and potential pitfalls</li>
  <li>potentially (if deemed useful) implement configuration options for sending cookies/credentials when retrieving content via alternative transports</li>
</ul>

<h2 id="rewriting-tests-for-deno"><a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/12">Rewriting tests for Deno</a></h2>

<p>Currently LibResilient uses <a href="https://jestjs.io/">Jest</a> and Node.js for tests of the browser-side code, and <a href="https://deno.land/">Deno</a> for the CLI
and CLI-related tests. This makes maintenance difficult. Deno is a much better choice as it <a href="https://deno.land/manual@v1.32.4/runtime/web_platform_apis">implements WebAPIs natively</a>. So, browser-side code tests should be re-written for Deno, and Node.js dependency completely removed from te project.</p>

<h3 id="plan-4">Plan</h3>

<ul>
  <li>rewrite browser-side code tests for Deno</li>
  <li>make sure all integrations with CI/CD set-up work</li>
</ul>

<h2 id="improved-error-handling"><a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/13">Improved error handling</a></h2>

<p>LibResilient has to handle request errors better. It needs to be smart about displaying the original
<code class="language-plaintext highlighter-rouge">404</code> page from the original domain, and otherwise needs to show some form of a plugin call stack
or other explanation if a request failed. Perhaps a “development” mode should be implemented.
Currently when a request fails (for example, due to <code class="language-plaintext highlighter-rouge">404</code> error, or because integrity check fails,
or…), a browser-internal “request failed” page is displayed to the user. This is not very helpful
when debugging issues, and at the same time this is confusing to users.</p>

<p>From the developer (and user) perspective, it’s difficult to figure out what went wrong when a
resource is not successfully fetched, and if the failure is related to LibResilient or not. This is
especially problematic when fetching resources that are protected by subresource integrity.</p>

<p>This will require substantial rewrites of crucial pieces of the ServiceWorker and plugins.</p>

<h3 id="plan-5">Plan</h3>

<ul>
  <li>design the error handling system for LibResilient
    <ul>
      <li>plugins throw standardized JS errors or otherwise return standardized error responses</li>
      <li>ServiceWorker handles them and potentially translates them to HTML error pages to display to the user</li>
    </ul>
  </li>
  <li>implement it in ServiceWorker</li>
  <li>implement it in plugins</li>
  <li>consider implementing “developer mode”</li>
  <li>document the error handling system for LibResilient</li>
  <li>document: best practices regarding when what kind of errors should be thrown by plugins</li>
  <li>document: how the ServiceWorker handles those errors</li>
</ul>

<h2 id="improved-configjson-handling-when-fetched-via-alternative-channels"><a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/14">Improved <code class="language-plaintext highlighter-rouge">config.json</code> handling when fetched via alternative channels</a></h2>

<p>When <a href="https://resilient.is/docs/UPDATING_DURING_DISRUPTION/">loading <code class="language-plaintext highlighter-rouge">config.json</code> via alternative transports</a>, if <code class="language-plaintext highlighter-rouge">config.json</code> is broken but the original website is not available, a LibResilient-enabled site might end up in a broken state</p>

<p>LibResilient should verify that a newly loaded config is valid broken (say, by deploying the new
configuration and attempting to load the <code class="language-plaintext highlighter-rouge">config.json</code> file it just loaded), and reverting to the
previous, clearly working config otherwise.</p>

<h3 id="plan-6">Plan</h3>

<ul>
  <li>test possible failure modes of <code class="language-plaintext highlighter-rouge">config.json</code> loaded via alternative transports</li>
  <li>improve handling of broken/problematic <code class="language-plaintext highlighter-rouge">config.json</code>
    <ul>
      <li>consider implementing deep plugin check</li>
    </ul>
  </li>
  <li>update documentation</li>
</ul>

<h2 id="improving-experience-for-site-administrators"><a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/15">Improving experience for site administrators</a></h2>

<p>There are several “papercut” issues in LibResilient and its plugins that are too small to be
considered a separate project plan items, but are nonetheless important to fix.</p>

<h3 id="plan-7">Plan</h3>

<ul>
  <li><a href="https://resilient.is/docs/plugins/basic-integrity/"><code class="language-plaintext highlighter-rouge">basic-integrity</code> plugin</a>: how to treat URIs without domain name?</li>
  <li>ServiceWorker: deterministically sorting query parameters</li>
  <li>create and test code to remove the service worker</li>
</ul>

<h2 id="dnslink-based-plugins-dns-over-https-without-json"><a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/16">DNSlink-based plugins: DNS-over-HTTPS without JSON</a></h2>

<p><a href="https://dnslink.dev/">DNSlink</a>-based plugins as currently implemented can only use <a href="https://en.wikipedia.org/wiki/DNS_over_HTTPS">DNS-over-HTTPS</a> servers that offer
JSON endpoints. Implementing pure DNS-over-HTTPS would greatly (several orders of magnitude) improve the number of DoH servers DNSlink-based plugins can use.</p>

<h3 id="plan-8">Plan</h3>

<ul>
  <li>implement pure DoH in DNSlink-based plugins
    <ul>
      <li><a href="https://resilient.is/docs/plugins/dnslink-ipfs/"><code class="language-plaintext highlighter-rouge">dnslink-ipfs</code></a></li>
      <li><a href="https://resilient.is/docs/plugins/dnslink-fetch/"><code class="language-plaintext highlighter-rouge">dnslink-fetch</code></a></li>
    </ul>
  </li>
  <li>update documentation</li>
</ul>]]></content><author><name>rysiek</name></author><category term="blog" /><summary type="html"><![CDATA[Good news: NLnet Foundation decided to extend their small grant for LibResilient! That grant funded bulk of the work over the last year and a half. It will now continue to do so for the next year or so. The grant extension also helped to define the milestones for 2023. Here they are, in no particular order — the order they get implemented depends on many factors, including some non-obvious interplay between them. Some of these milestones are pretty simple, some will require substantial re-writes. Exciting times ahead!]]></summary></entry><entry><title type="html">Documentation is now more usable</title><link href="/blog/better-exposed-documentation/" rel="alternate" type="text/html" title="Documentation is now more usable" /><published>2023-01-28T00:00:00+00:00</published><updated>2023-01-28T00:00:00+00:00</updated><id>/blog/better-exposed-documentation</id><content type="html" xml:base="/blog/better-exposed-documentation/"><![CDATA[<p>LibResilient’s documentation used to be just a bunch of Markdown files spread across the repository, available through the <a href="https://gitlab.com/rysiekpl/libresilient/">Gitlab-hosted project</a>. That was fine as the first jab at making it available, but it was far from perfect: for example, it was kind of difficult to discover and browse plugin documentation.</p>

<p>Now, documentation (both general docs, and per-plugin documentaion) is available <a href="../../docs/">directly on the website</a>. Still not perfect, but considerably better nonetheless. Importantly, plugins documentation is <a href="../../docs/plugins/">also gathered in a single place</a>.</p>

<h2 id="whats-in-the-docs">What’s in the docs</h2>

<p>Documentation is divided into two parts:</p>
<ul>
  <li><a href="../../docs/">general documentation</a></li>
  <li><a href="../../docs/plugins/">plugins documentation</a></li>
</ul>

<p>This should make the information there more easily available and discoverable. There is no search (yet?), as the size of project’s documentation is still small and arguably manageable with the help of a decent index pages.</p>

<h3 id="general-documentation">General documentation</h3>

<p>These are documentation resources discussing LibResilient generally, or providing step-by-step guides on deployment.</p>

<p>This includes a high-level overview of the <strong><a href="../../docs/PHILOSOPHY/">philosophy guiding the project</a></strong>, and an (still not entirely complete) <strong><a href="../../docs/ARCHITECTURE/">description of its architecture</a></strong>. There is also an extensive <strong><a href="../../docs/FAQ/">Frequently Asked Questions</a></strong> section, diving into things like interactions with web analytics systems and admin panels, how does LibResilient handle interactivity on a website, and a deep-dive into Service Workers as used by LibResilient.</p>

<p>The technical, step-by-step guides include the <strong><a href="../../docs/QUICKSTART/">Quickstart guide</a></strong> and the <strong><a href="../../docs/EXAMPLE_DEPLOYMENT/">example deployment</a></strong> document. There are also technical write-ups focusing on specific features of LibResilient: its ability to <strong><a href="../../docs/UPDATING_DURING_DISRUPTION/">update configuration even during disruption</a></strong> and on ensuring <strong><a href="../../docs/CONTENT_INTEGRITY/">security and content integrity</a></strong> — a topic particularly important when using third-party-run alternative endpoints.</p>

<div class="home-nav">
    <a href="../../docs/">Docs</a>
</div>

<h3 id="plugins-documentation">Plugins documentation</h3>

<p>This section contains documentation of every plugin available in LibResilient’s main code tree.</p>

<p>How extensively a plugin is documented differs between plugins. Some, like <a href="../../docs/plugins/dnslink-fetch/"><code class="language-plaintext highlighter-rouge">dnslink-fetch</code></a> offer a reasonably good write-up. Others, like <a href="../../docs/plugins/gun-ipfs/"><code class="language-plaintext highlighter-rouge">gun-ipfs</code></a>. Some plugins are considered stable or late <code class="language-plaintext highlighter-rouge">beta</code>, some are broken and need to be re-written. This is clearly expressed on the plugin overview page:</p>

<div class="home-nav">
    <a href="../../docs/plugins/">Plugins</a>
</div>

<h2 id="improving-the-documentation">Improving the documentation</h2>

<p>It’s important to recognize that good documentation is crucial to adoption. Quite a lot of work went into improving LibResilient’s documentation situation, but by no means is it done and perfect. If you’d like to get involved in helping out with this — or with any other aspect of LibResilient — check <a href="https://gitlab.com/rysiekpl/libresilient/">out the code in GitLab</a>.</p>

<p>General documentation available on this website is built from the content in the <a href="https://gitlab.com/rysiekpl/libresilient/-/tree/master/docs"><code class="language-plaintext highlighter-rouge">/docs/</code> directory in the repository</a>. Plugin documentation is built from <code class="language-plaintext highlighter-rouge">README.md</code> files in <a href="https://gitlab.com/rysiekpl/libresilient/-/tree/master/plugins">each individual plugin’s directory</a>. And if you’re wondering how that’s achieved, the <a href="https://gitlab.com/rysiekpl/resilient.is/-/blob/main/.gitlab-ci.yml">absolutely horrendously ugly code for that is here</a>. Actual LibResilient code is <a href="https://gitlab.com/rysiekpl/libresilient/-/blob/master/service-worker.js">much cleaner</a>, pinky promise!</p>]]></content><author><name>rysiek</name></author><category term="blog" /><summary type="html"><![CDATA[LibResilient’s documentation used to be just a bunch of Markdown files spread across the repository, available through the Gitlab-hosted project. That was fine as the first jab at making it available, but it was far from perfect: for example, it was kind of difficult to discover and browse plugin documentation. Now, documentation (both general docs, and per-plugin documentaion) is available directly on the website. Still not perfect, but considerably better nonetheless. Importantly, plugins documentation is also gathered in a single place.]]></summary></entry><entry><title type="html">LibResilient CLI</title><link href="/blog/libresilient-cli/" rel="alternate" type="text/html" title="LibResilient CLI" /><published>2023-01-15T00:00:00+00:00</published><updated>2023-01-15T00:00:00+00:00</updated><id>/blog/libresilient-cli</id><content type="html" xml:base="/blog/libresilient-cli/"><![CDATA[<p>LibResilient now has a large number of <a href="../docs/ARCHITECTURE/#transport-plugins">transport plugins</a>, offering a lot of flexibility for website administrators. Some of these plugins rely on more than one way of making information available — for example <a href="../docs/plugins/dnslink-ipfs/"><code class="language-plaintext highlighter-rouge">dnslink-ipfs</code></a> expects content to be published on IPFS, and the latest IPFS address to then be pushed to DNS.</p>

<p>How to push this information and data out was so far left to website administrators, creating a relatively large obstacle to LibResilient adoption. Now this might gradually start getting solved, thanks to <a href="https://gitlab.com/rysiekpl/libresilient/-/tree/master/cli"><code class="language-plaintext highlighter-rouge">lrcli</code></a>, the LibResilient CLI.</p>

<h2 id="the-problem">The Problem</h2>

<p>The big problem with creating a consistent CLI for a tool like LibResilient is that basically all relevant functionality is related to specific LibResilient plugins. Additionally, at least in case of some plugins there is more than one way to push the information where it needs to be for LibResilient to be able to make use of it.</p>

<p>Consider the <a href="../docs/plugins/alt-fetch/"><code class="language-plaintext highlighter-rouge">alt-fetch</code></a> plugin, which allows LibResilient to fetch content from alternative HTTPS endpoints. Can the <code class="language-plaintext highlighter-rouge">lrcli</code> make assumptions regarding <em>how</em> content should be pushed to them? Should FTP or SFTP be used? Or maybe some REST API needs to be used instead and <code class="language-plaintext highlighter-rouge">PUT</code> HTTPS requests need to be issued? Or perhaps it’s some kind of proprietary service that requires a specific proprietary protocol?</p>

<p>There is a growing number of plugins that might need some CLI functionality to make Libresilient easy to deploy when using them. And in case of many if not most of these plugins there are simply too many possible ways of pushing the information out for there to be a general CLI that implements all of them.</p>

<h2 id="the-approach">The Approach</h2>

<p>The plugin-based approach seems to work well for LibResilient itself. It might work well for the CLI itself, then, as well. After all, the author of a plugin probably knows best what kind of tools might a website administrator need to properly push the content and any necessary additional information out for the plugin to be able to make use of it.</p>

<p>LibResilient CLI is built around a simple plugin architecture. It assumes a <code class="language-plaintext highlighter-rouge">cli.js</code> file in plugin’s main directory. The file should be a valid <a href="https://deno.land/">Deno</a> module (<code class="language-plaintext highlighter-rouge">lrcli</code> is written for Deno JS runtime), and export an object that defines the name, description, version, and actions implemented by the plugin. Based on that, CLI knows how to run specific actions and interpret relevant command line arguments.</p>

<p><a href="https://gitlab.com/rysiekpl/libresilient/-/blob/master/plugins/basic-integrity/cli.js">Here</a> is a simple example for the <code class="language-plaintext highlighter-rouge">basic-integrity</code> plugin.</p>

<h2 id="the-plan">The Plan</h2>

<p>With time, more plugins will gain a CLI component. For some of them — like the <code class="language-plaintext highlighter-rouge">basic-integrity</code> or <a href="../docs/plugins/signed-integrity/"><code class="language-plaintext highlighter-rouge">signed-integrity</code></a>, which already have it — CLI’s role is going to be limited to generate data locally, for use with other tools in the publishing pipeline. For other plugins — for example, IPFS-based transport plugins — it makes sense to implement actions that push content out, actually publishing it.</p>

<p>And in some cases, this will remain somewhat complicated. There are simply too many ways to push out content to a simple HTTPS endpoint, that are often also very specific to a given website, for them to all be implementable in a single LibResilient CLI plugin. Same is probably true for pushing out DNS updates required for DNSLink-based plugins. In such cases, most broadly used mechanisms will probably be implemented (FTP/SFTP for <code class="language-plaintext highlighter-rouge">fetch</code>-based plugins? <a href="https://datatracker.ietf.org/doc/html/rfc2136"><code class="language-plaintext highlighter-rouge">DNS UPDATE</code></a> for DNSLink-based plugins?), but anything fancier than that will have to be left to the website admin, who knows their infrastructure and how to distribute content on it.</p>

<h2 id="example-usage">Example Usage</h2>

<p>When run, <code class="language-plaintext highlighter-rouge">lrcli</code> expects the name of the plugin to load, and tries to be helpful in guiding the user in how its usage:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>cli/lrcli.js 

Command-line interface <span class="k">for </span>LibResilient.

This script creates a common interface to CLI actions implemented by LibResilient plugins.

Usage:
    lrcli.js <span class="o">[</span>options] <span class="o">[</span>plugin-name <span class="o">[</span>plugin-options]]

Options:

    <span class="nt">-h</span>, <span class="nt">--help</span> <span class="o">[</span>plugin-name]
        Print this message, <span class="k">if </span>no plugin-name is given.
        If plugin-name is provided, print usage information of that plugin.
</code></pre></div></div>

<p>Plugin names are assumed to be sub-directories under <code class="language-plaintext highlighter-rouge">plugins/</code> directory in LibResilient’s code directory:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>cli/lrcli.js no-such-plugin

<span class="k">***</span> TypeError: Module not found <span class="s2">"file:///home/user/Projects/libresilient/plugins/no-such-plugin/cli.js"</span><span class="nb">.</span> <span class="k">***</span>
</code></pre></div></div>

<p>If plugin exists, usage information can be printed, based on data exported by the plugin’s <code class="language-plaintext highlighter-rouge">cli.js</code> module:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>cli/lrcli.js basic-integrity

<span class="k">***</span> No action specified <span class="k">for </span>plugin <span class="k">***</span>

CLI plugin:
    basic-integrity

Plugin Description:
    Verifying subresource integrity <span class="k">for </span>resources fetched by other plugins.
    CLI used to generate subresource integrity hashes <span class="k">for </span>provided files.
    
Usage:
    lrcli.js <span class="o">[</span>general-options] basic-integrity <span class="o">[</span>plugin-action <span class="o">[</span>action-options]]

General Options:

    <span class="nt">-h</span>, <span class="nt">--help</span> <span class="o">[</span>plugin-name]
        Print this message, <span class="k">if </span>no plugin-name is given.
        If plugin-name is provided, print usage information of that plugin.

Actions and Action Options:

    get-integrity <span class="o">[</span>options...] &lt;file...&gt;
        calculate subresource integrity hashes <span class="k">for </span>provided files

         &lt;file...&gt;
            paths of files to be processed

        <span class="nt">--algorithm</span> <span class="o">(</span>default: SHA-256<span class="o">)</span>
            SubtleCrypto.digest-compatible algorithm names to use when calculating digests <span class="o">(</span>default: <span class="s2">"SHA-256"</span><span class="o">)</span>

        <span class="nt">--output</span> <span class="o">(</span>default: json<span class="o">)</span>
            a string, defining output mode <span class="o">(</span><span class="s1">'json'</span> or <span class="s1">'text'</span><span class="p">;</span> <span class="s1">'json'</span> is default<span class="o">)</span>

</code></pre></div></div>

<p>The plugin controls its output, but a good practice is to provide support at least for <code class="language-plaintext highlighter-rouge">json</code> and <code class="language-plaintext highlighter-rouge">text</code> when useful data is returned, to simplify integration into any other tools the website admin chooses to use in their deployment pipeline:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>cli/lrcli.js basic-integrity get-integrity libresilient.js 
<span class="o">{</span><span class="s2">"libresilient.js"</span>:[<span class="s2">"sha256-UrkUn2KwKBQ93jS/pSd3Kt0/+9XkDT6Rj93jec/lOZY="</span><span class="o">]}</span>

<span class="nv">$ </span>cli/lrcli.js basic-integrity get-integrity libresilient.js <span class="nt">--output</span> text
libresilient.js: sha256-UrkUn2KwKBQ93jS/pSd3Kt0/+9XkDT6Rj93jec/lOZY<span class="o">=</span>
</code></pre></div></div>]]></content><author><name>rysiek</name></author><category term="blog" /><summary type="html"><![CDATA[LibResilient now has a large number of transport plugins, offering a lot of flexibility for website administrators. Some of these plugins rely on more than one way of making information available — for example dnslink-ipfs expects content to be published on IPFS, and the latest IPFS address to then be pushed to DNS. How to push this information and data out was so far left to website administrators, creating a relatively large obstacle to LibResilient adoption. Now this might gradually start getting solved, thanks to lrcli, the LibResilient CLI.]]></summary></entry><entry><title type="html">New DNSLink-based transport plugins</title><link href="/blog/new-dnslink-based-transport-plugins/" rel="alternate" type="text/html" title="New DNSLink-based transport plugins" /><published>2023-01-08T00:00:00+00:00</published><updated>2023-01-08T00:00:00+00:00</updated><id>/blog/new-dnslink-based-transport-plugins</id><content type="html" xml:base="/blog/new-dnslink-based-transport-plugins/"><![CDATA[<p>After a long break (perhaps a bit too long, in fact), LibResilient is back in active development. As part of that, a two new <a href="../docs/ARCHITECTURE/#transport-plugins">transport plugins</a> got implemented:</p>

<ul>
  <li><a href="../docs/plugins/dnslink-fetch/"><code class="language-plaintext highlighter-rouge">dnslink-fetch</code></a></li>
  <li><a href="../docs/plugins/dnslink-ipfs/"><code class="language-plaintext highlighter-rouge">dnslink-ipfs</code></a></li>
</ul>

<p>They fetch content using means that have been employed by LibResilient plugins before, but use <a href="https://dnslink.org/">DNSLink</a> to figure out where to fetch content from.</p>

<h2 id="what-is-dnslink">What is DNSLink</h2>

<p>DNSLink is a standard for storing information on where a content related to a given domain can be found directly in DNS, using <code class="language-plaintext highlighter-rouge">TXT</code> records.</p>

<p>Let’s say you are running a website at <code class="language-plaintext highlighter-rouge">https://example.org</code> and want to provide information on where relevant content can be found in case, for example, the main site goes down. You could put this in some place on the site itself, but this creates a chicken-and-egg problem: information on where to get content if the site is not available is only accessible as long as the site is available.</p>

<p>Instead, you could use DNSLink and put that information directly in DNS. To do that you would create <code class="language-plaintext highlighter-rouge">TXT</code> records for <code class="language-plaintext highlighter-rouge">_dnslink.example.org</code> label, like so:</p>

<pre><code class="language-dns">_dnslink.example.org.  60      IN      TXT     "dnslink=/ipfs/Qm..."
_dnslink.example.org.  60      IN      TXT     "dnslink=/https/gateway.ipfs.io/ipfs/Qm..."
_dnslink.example.org.  60      IN      TXT     "dnslink=/https/example.com/"
</code></pre>

<p>Software that understands DNSLink would take this to mean that content for <code class="language-plaintext highlighter-rouge">example.org</code> is also available directly on IPFS, or via HTTPS on specific IPFS gateways, or via HTTPS on an alternative endpoint (in this case, <code class="language-plaintext highlighter-rouge">example.com</code>). As long as DNS remains available, if client software understands DNSLink and supports the relevant transport protocols, the content could be retrieved even if <code class="language-plaintext highlighter-rouge">https://example.com</code> site itself is down.</p>

<p>This is where the new LibResilient plugins come in.</p>

<h2 id="new-plugins">New plugins</h2>

<p>With the new plugins, LibResilient turns any modern browser into client software that understands DNSLink and can retrieve content related to a website that happens to be down (as long as that particular visitor had visited that site once before and Service Worker got loaded).</p>

<p>The first of the two, <code class="language-plaintext highlighter-rouge">dnslink-fetch</code>, is very similar to the <a href="../docs/plugins/alt-fetch/"><code class="language-plaintext highlighter-rouge">alt-fetch</code></a> plugin: given alternative endpoints, it performs <a href="https://developer.mozilla.org/en-US/docs/Web/API/fetch">HTTP <code class="language-plaintext highlighter-rouge">fetch()</code></a> requests to them to pull relevant content. But instead of requiring the endpoints to be configured explicitly in the <code class="language-plaintext highlighter-rouge">config.json</code> configuration file (and thus be somewhat inflexible), it pulls the endpoints from DNS, in accordance to the DNSLink standard.</p>

<p>The second plugin, <code class="language-plaintext highlighter-rouge">dnslink-ipfs</code>, uses DNSLink to figure out which IPFS <a href="https://docs.ipfs.tech/concepts/content-addressing/"><code class="language-plaintext highlighter-rouge">CID</code></a> to use when fetching the content from IPFS. This is necessary because IPFS uses content-addressing: when content itself changes, the address will change too. When using IPFS for content retrieval, the address of the <em>current</em>, <em>up-to-date</em> version of content must first be known. DNSLink provides a good way of making that information available, and the plugin leans on that.</p>

<h2 id="updating-dns">Updating DNS…</h2>

<p>…is not, however, LibResilient’s responsibility. So, if you want to use these DNSLink-based plugins, you will need to separately implement some way of updating relevant <code class="language-plaintext highlighter-rouge">TXT</code> records when content gets modified or new content gets published. This can be done via your DNS hosting provider’s APIs, using the <a href="https://datatracker.ietf.org/doc/html/rfc2136"><code class="language-plaintext highlighter-rouge">DNS UPDATE</code></a> query if your DNS nameservers support that, or some other means.</p>

<p>At least for now.</p>

<p>Some work has started on implementing a command-line tool that would simplify deployment of websites that use LibResilient, so perhaps one day this will be handled by the LibResilient CLI. Stay tuned!</p>]]></content><author><name>rysiek</name></author><category term="blog" /><summary type="html"><![CDATA[After a long break (perhaps a bit too long, in fact), LibResilient is back in active development. As part of that, a two new transport plugins got implemented: dnslink-fetch dnslink-ipfs They fetch content using means that have been employed by LibResilient plugins before, but use DNSLink to figure out where to fetch content from.]]></summary></entry><entry><title type="html">Configuration updates during disruption and outage</title><link href="/blog/configuration-updates-during-disruption-and-outage/" rel="alternate" type="text/html" title="Configuration updates during disruption and outage" /><published>2022-02-09T00:00:00+00:00</published><updated>2022-02-09T00:00:00+00:00</updated><id>/blog/configuration-updates-during-disruption-and-outage</id><content type="html" xml:base="/blog/configuration-updates-during-disruption-and-outage/"><![CDATA[<p>Imagine this: you’re running a reasonably important site, and you decided to deploy LibResilient to make it, well, resilient.</p>

<p>Your config sets up the <code class="language-plaintext highlighter-rouge">fetch</code> plugin, then local <code class="language-plaintext highlighter-rouge">cache</code>, and then <a href="https://gitlab.com/rysiekpl/libresilient/-/blob/7a8105573acea7f78eb20f6f655e62565f3b8f57/plugins/alt-fetch/"><code class="language-plaintext highlighter-rouge">alt-fetch</code></a> with some nice independent endpoints (say, an <a href="https://docs.ipfs.io/concepts/ipfs-gateway/">IPFS gateway</a> here, an <a href="https://www.tor2web.org/">Tor Onion gateway</a> there). Perhaps with some <a href="/blog/content-integrity-in-libresilient/">content integrity checking</a> deployed too, for a peace of mind (no need to completely trust those third party gateway operators, after all).</p>

<p>Obviously you run your own IPFS node and a Tor Hidden Service for these to work correctly, but your website visitors do not need any special software, extensions, or configuration — they just visit your site in their regular browser; LibResilient handles everything else behind the scenes.</p>

<h2 id="then-you-experience-an-outage">Then you experience an outage</h2>

<p>Maybe your server keeled over, or maybe it’s a DDoS.</p>

<p>Good news is: for all visitors who had visited your site before, everything seems to work just fine (if perhaps a tiny bit slower than normally). Your website content is cached on IPFS nodes, and IPFS gateways are happily serving the requests LibResilient is sending their way. Local cache makes the experience quite seamless for content those visitors had viewed before, and the IPFS-related slowdown for content they have not is still small.</p>

<p>For whatever reason, however, you figure out the outage will last a bit longer, and you’d like to swap out the <code class="language-plaintext highlighter-rouge">fetch</code> pluging completely (no reason for visitors to wait for something that isn’t going to work anyway for the time being). You’d perhaps also want to remove the Tor Onion gateways from the <code class="language-plaintext highlighter-rouge">alt-fetch</code> endpoints — after all your Tor Hidden Service is down as well.</p>

<p>Bad news is: LibResilient’s config is a JavaScript file imported directly in the Service Worker, you have no way to update it until your site comes back up.</p>

<h2 id="but-now-you-actually-do">But now you actually do!</h2>

<p>This is what this milestone (third one supported by a small grant from <a href="https://nlnet.nl/project/libresilient/">NGI Assure</a>) was all about.</p>

<p>To make config updates possible during disruption and outage, the config format needed to be changed (JSON was the obvious choice), and then the whole machinery of verifying, loading, and caching it needed to be implemented.</p>

<p>And so now, the config file (<code class="language-plaintext highlighter-rouge">config.json</code>) is just a regular file that can be retrieved via any configured plugins. You don’t have to do anything special for this to work.</p>

<p>Let’s dive deeper into what exactly has been done this month.</p>

<h3 id="1-switching-to-a-json-config-file-instead-of-js">1. Switching to a JSON config file (instead of JS)</h3>

<ul>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/32">https://gitlab.com/rysiekpl/libresilient/-/issues/32</a></li>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/31">https://gitlab.com/rysiekpl/libresilient/-/issues/31</a></li>
</ul>

<p>This was done because the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">ServiceWorkers API</a> does not provide a way to update 
JavaScript scripts that were imported into the Service Worker via <a href="https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/importScripts"><code class="language-plaintext highlighter-rouge">importScripts()</code></a> call, 
in any other way that via a direct HTTPS fetch() to the original website.</p>

<p>For obvious reasons that’s unworkable for updating the config during disruption/outage.</p>

<p>A bunch of research was required, as expected. In the end, LibResilient needed 
to have a roughly full implementation of what the browser does to scripts 
imported via importScripts(): fetching <code class="language-plaintext highlighter-rouge">config.json</code>, caching it, and 
establishing it as stale so that it can be re-fetched.</p>

<p>Additional benefit of this is that the config file is now not code, it’s an 
“inert” format (JSON). It is no longer possible to include running code directly in the configuration file.
This is important for <a href="http://langsec.org/occupy/">various reasons that the LANGSEC community explores at length</a>.</p>

<p>This work also included implementing validity checks on 
the config file — something that was not really possible when config was written 
in directly-loaded JavaScript.</p>

<p>Implementing this change required me finally diving deep into the <a href="https://felixgerschau.com/service-worker-lifecycle-update/">ServiceWorker lifecycle</a>,
especially the parts of it that are mostly glossed over or not mentioned at all in most documentation: what <em>exactly</em> happens when a ServiceWorker has 
been registered and installed, but is now stopped, and is being restarted?</p>

<p>This research was crucial to implementing the JSON config change correctly, and 
provided important insight that will potentially be very useful for 
implementing future improvements.</p>

<h3 id="2-implementing-a-way-for-config-to-be-updated-and-applied-during-disruption">2. Implementing a way for config to be updated and applied during disruption</h3>

<ul>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/30">https://gitlab.com/rysiekpl/libresilient/-/issues/30</a></li>
</ul>

<p>Once the JSON config change was implemented, it was possible to implement 
background fetching of the updated <code class="language-plaintext highlighter-rouge">config.json</code> file.</p>

<p>This required cleaning up and refactoring code implementing JSON config 
support, and deciding what criteria to use when establishing if a cached 
<code class="language-plaintext highlighter-rouge">config.json</code> is “stale” (currently: over 24 hours old, based on the <code class="language-plaintext highlighter-rouge">Date:</code> header 
on the cached response).</p>

<p>The biggest issue was figuring out what should happen if the freshly retrieved
config file configures plugins that have not been loaded upon Service Worker 
installation. Because an updated <code class="language-plaintext highlighter-rouge">config.json</code> file is processed after Service Worker restart 
(so, <em>not during installation</em>), <code class="language-plaintext highlighter-rouge">importScripts()</code> is not available.</p>

<p>A decision was made to test for such such config changes and <em>reject</em> such a 
config file outright, falling back to the already cached, if stale, 
<code class="language-plaintext highlighter-rouge">config.json</code>, if the updated file was <em>not</em> retrieved using a regular <code class="language-plaintext highlighter-rouge">fetch</code>.</p>

<p>The rationale for this is that in such circumstances:</p>

<ol>
  <li>the original website cannot be assumed to be working correctly, as the 
<code class="language-plaintext highlighter-rouge">config.json</code> file was retrieved using an alternative transport;</li>
  <li>the currently deployed (if stale) <code class="language-plaintext highlighter-rouge">config.json</code> is functional, as we were, 
in fact, able to retrieve the updated <code class="language-plaintext highlighter-rouge">config.json</code>.</li>
</ol>

<p>Ideas for potential further improvements to this are listed <a href="https://gitlab.com/rysiekpl/libresilient/-/issues/40">here</a>.</p>

<h3 id="3-documentation">3. Documentation</h3>

<ul>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/blob/master/docs/UPDATING_DURING_DISRUPTION.md">https://gitlab.com/rysiekpl/libresilient/-/blob/master/docs/UPDATING_DURING_DISRUPTION.md</a></li>
</ul>

<p>Documentation was written on how JSON config loading and updating works, and 
how the config can be updated during disruption or outage. It explains the 
rationale behind implementation decisions and their technological context.</p>

<p>There is obviously more work needed to make this documentation more useful and readable. But it’s a start.</p>

<h3 id="maintaining-quality-of-code">Maintaining quality of code</h3>

<p>Code written for this milestone is of course covered by tests; overall <a href="https://gitlab.com/rysiekpl/libresilient">test coverage went up to ~62%</a>.</p>

<p>As before, I have avoided any external dependencies what-so-ever. LibResilient remains easily deployable by simply copying a few JS files (and now, a single JSON file) and adding a single line to your HTML.</p>

<h2 id="and-the-next-milestone-is">And the next milestone is…</h2>

<p>There are <a href="https://gitlab.com/rysiekpl/libresilient/-/milestones">four milestones</a> on the todo list. Unclear which one I will focus on next, but that should be resolved soon. Keep an eye on the issues assigned to those milestones if you want to be the first to know!</p>]]></content><author><name>rysiek</name></author><category term="blog" /><summary type="html"><![CDATA[Imagine this: you’re running a reasonably important site, and you decided to deploy LibResilient to make it, well, resilient. Your config sets up the fetch plugin, then local cache, and then alt-fetch with some nice independent endpoints (say, an IPFS gateway here, an Tor Onion gateway there). Perhaps with some content integrity checking deployed too, for a peace of mind (no need to completely trust those third party gateway operators, after all).]]></summary></entry><entry><title type="html">Content integrity in LibResilient</title><link href="/blog/content-integrity-in-libresilient/" rel="alternate" type="text/html" title="Content integrity in LibResilient" /><published>2022-01-18T00:00:00+00:00</published><updated>2022-01-18T00:00:00+00:00</updated><id>/blog/content-integrity-in-libresilient</id><content type="html" xml:base="/blog/content-integrity-in-libresilient/"><![CDATA[<p>So far most of LibResilient development was focused on proving the concept and implementing different content fetching plugins. After <a href="https://nlnet.nl/project/libresilient/">the project got a small NGI Assure grant</a>, the focus for the previous milestone was instead <a href="/blog/libresilient-reaches-a-milestone/">making the project itself more, well, resilient</a>.</p>

<p>Today another milestone was completed, focusing on integrity of content fetched via LibResilient, and thus on the security of websites deploying it.</p>

<h2 id="the-problem">The problem</h2>

<p>On a very basic level, LibResilient’s job is fetching website content from places other than the original domain of that website.</p>

<p>This can mean alternative endpoints controlled by the website owners (say, on secondary domains, or just IP addresses), or it can mean third-party endpoints like <a href="https://ipfs.github.io/public-gateway-checker/">IPFS gateways</a>, <a href="https://www.tor2web.org/">Tor2web proxies</a>, or any location where the website’s operator can upload website content, and from which that content can then be fetched.</p>

<p>This, however, creates a problem — operators of such third party services effectively get the ability to modify the content (accidentally, or… maliciously).</p>

<h2 id="ensuring-content-integrity">Ensuring content integrity</h2>

<p>The solution is to verify content integrity. We can leverage the <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity">Subresource Integrity</a> (SRI) feature of modern browsers — but that has several downsides:</p>
<ul>
  <li>it works only when integrity data is available at the time of a request;</li>
  <li>setting it in HTML is quite unwieldy and effectively impractical if we want to use it for all content and assets;</li>
  <li>the <code class="language-plaintext highlighter-rouge">integrity</code> attribute is only defined for <code class="language-plaintext highlighter-rouge">&lt;script&gt;</code> and <code class="language-plaintext highlighter-rouge">&lt;link&gt;</code> elements.</li>
</ul>

<p>Thankfully, it turns out integrity data <em>can</em> be provided for <code class="language-plaintext highlighter-rouge">fetch</code> requests in JavaScript for any content type, and once provided the browser will do the heavy lifting of verifying it!</p>

<p>That also means we can have plugins that provide that integrity data: for example, <a href="https://gitlab.com/rysiekpl/libresilient/-/blob/master/plugins/basic-integrity/">directly from the config</a>, or through an somewhat elaborate but considerably more flexible process of <a href="https://gitlab.com/rysiekpl/libresilient/-/blob/master/plugins/signed-integrity/">fetching a signed file with the relevant integrity data</a> for each request separately.</p>

<p>Finally, for transport plugins that do not rely on the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>, and thus do not benefit from the browser checking if integrity data matches fetched content, we now have a wrapper plugin that <a href="https://gitlab.com/rysiekpl/libresilient/-/blob/master/plugins/integrity-check/">explicitly checks integrity of any resource</a>, using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto">SubtleCrypto API</a>.</p>

<h2 id="work-done-in-this-milestone">Work done in this milestone</h2>

<p>Let’s break down specific work done in this latest milestone.</p>

<h3 id="1-making-sure-libresilient-supports-subresource-integrity-sri-fully">1. Making sure LibResilient supports Subresource Integrity (SRI) fully:</h3>

<ul>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/1">https://gitlab.com/rysiekpl/libresilient/-/issues/1</a></li>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/18">https://gitlab.com/rysiekpl/libresilient/-/issues/18</a></li>
</ul>

<p>This meant, first and foremost, identifying <em>how</em> SRI should be supported in 
LibResilient. Options included supporting it directly in the service worker 
code, or bubbling it down to the plugins. In the end, the latter approach was 
elected as more flexible.</p>

<p>Then, identifying places in <code class="language-plaintext highlighter-rouge">service-worker.js</code> and plugin code where SRI was 
not being correctly handled, and fixing that.</p>

<p>Some research was also necessary to establish if SRI can be set (and if it is 
enforced by the JS Fetch API) for resources other than scripts and CSS.</p>

<h3 id="2-writing-sri-related-plugins">2. Writing SRI-related plugins</h3>

<ul>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/19">https://gitlab.com/rysiekpl/libresilient/-/issues/19</a></li>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/20">https://gitlab.com/rysiekpl/libresilient/-/issues/20</a></li>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/28">https://gitlab.com/rysiekpl/libresilient/-/issues/28</a></li>
</ul>

<p>Once we had the basic SRI compatibility ensured, it was possible to write SRI-
related wrapper plugins.</p>

<p>The first, <a href="https://gitlab.com/rysiekpl/libresilient/-/blob/master/plugins/basic-integrity/"><code class="language-plaintext highlighter-rouge">basic-integrity</code></a>,
makes it possible to statically configure integrity data for specific URLs.</p>

<p>It doesn’t check the integrity itself, just makes sure that integrity data
configured for a given URL is added to the request data when the URL is being
fetched by LibResilient. Actual verification is assumed to be done by any
plugin wrapped by it.</p>

<p>Secondly, <a href="https://gitlab.com/rysiekpl/libresilient/-/blob/master/plugins/integrity-check/"><code class="language-plaintext highlighter-rouge">integrity-check</code></a>
wrapper plugin uses the SubtleCrypto API to implement integrity check directly in JS.</p>

<p>This makes it possible to check integrity (if present in the request being 
handled) of content fetched by transport plugins that do not guarantee 
integrity will be checked by the browser — such as any plugin not using the 
Fetch API.</p>

<p>Finally, the <a href="https://gitlab.com/rysiekpl/libresilient/-/blob/master/plugins/signed-integrity/"><code class="language-plaintext highlighter-rouge">signed-integrity</code></a> plugin is a proof-of-concept demonstrating how 
SRI could be used in LibResilient for sites that are not completely static. 
For each content URL being fetched it first fetches integrity data from an URL 
built by appending <code class="language-plaintext highlighter-rouge">.integrity</code> to the content URL, expecting a <a href="https://en.wikipedia.org/wiki/JSON_Web_Token">JSON Web Token</a>.</p>

<p>That JWT’s signature is verified using a pre-configured public key (assumption 
being that it was signed with a related private key on the server). JWT’s 
payload should contain an “integrity” field, which is then used to set the SRI 
data on the request being handled.</p>

<p>The plugin itself does not check integrity, it is assumed that the wrapped 
plugin will do that check.</p>

<p>By combining these plugins (for example, <code class="language-plaintext highlighter-rouge">signed-integrity</code> to retrieve 
integrity data for content, wrapping the <code class="language-plaintext highlighter-rouge">integrity-check</code> plugin that 
actually verifies integrity of content fetched by a transport plugin wrapped by 
it in turn) it is possible to provide SRI for transport plugins not built 
around the Fetch API.</p>

<h3 id="3-documentation">3. Documentation</h3>

<ul>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/blob/master/docs/CONTENT_INTEGRITY.md">https://gitlab.com/rysiekpl/libresilient/-/blob/master/docs/CONTENT_INTEGRITY.md</a></li>
</ul>

<p>A document on content integrity in the context of LibResilient was also 
created. It discusses SRI, different available plugins, pros and cons of 
different approaches to content integrity when using LibResilient, and 
mentions possible future developments.</p>

<h3 id="code-quality-and-such">Code quality and such</h3>

<p>Code written for this milestone is of course covered by tests, and so overall 
test coverage for the project <a href="https://gitlab.com/rysiekpl/libresilient">went up to ~60%</a>.</p>

<p>All of the functionality in this milestone was implemented without <em>any</em>
external dependencies (npm and <code class="language-plaintext highlighter-rouge">package.json</code> are only used for running
the unit tests, and have nothing to do with LibResilient’s browser-side code).
The aim remains for LibResilient to be deployable by simply copying a few JS
files over to the directory from which a website is served. No dependency hell,
no bundling, no stress.</p>

<h2 id="next-steps">Next steps</h2>

<p>Work has already started on the next milestone, focusing on being able to deploy
LibResilient configuration changes <a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/3">even when the original website is not available</a>.</p>]]></content><author><name>rysiek</name></author><category term="blog" /><summary type="html"><![CDATA[So far most of LibResilient development was focused on proving the concept and implementing different content fetching plugins. After the project got a small NGI Assure grant, the focus for the previous milestone was instead making the project itself more, well, resilient. Today another milestone was completed, focusing on integrity of content fetched via LibResilient, and thus on the security of websites deploying it.]]></summary></entry><entry><title type="html">LibResilient reaches a milestone!</title><link href="/blog/libresilient-reaches-a-milestone/" rel="alternate" type="text/html" title="LibResilient reaches a milestone!" /><published>2021-09-19T00:00:00+00:00</published><updated>2021-09-19T00:00:00+00:00</updated><id>/blog/libresilient-reaches-a-milestone</id><content type="html" xml:base="/blog/libresilient-reaches-a-milestone/"><![CDATA[<p>Took a while (summer holidays got in the way), but LibResilient finally reached a milestone: <a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/4">“Improved resilience of libresilient”</a>. It’s a reasonably big deal, for a number of reasons.</p>

<p>First, that means that development is actually happening again. Second, one of the goals of this milestone was to create a decent testing harness, so that any errors or breakage caused by code changes can be caught early and fixed.</p>

<p>Third, this is the first milestone covered by the <a href="https://nlnet.nl/project/libresilient/">NLnet grant for LibResilient</a>. You read that right: LibResilient development is now supported as part of the <a href="https://www.ngi.eu/ngi-projects/ngi-assure/">NGI Assure</a> project. There are <a href="https://gitlab.com/rysiekpl/libresilient/-/milestones/">six more milestones defined as part of that grant</a>.</p>

<p>Biggest specific pieces of work done for this milestone focused on:</p>

<h2 id="1-setting-up-a-testing-system-for-the-project-and-writing-the-tests">1. Setting up a testing system for the project, and writing the tests</h2>

<ul>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/5">https://gitlab.com/rysiekpl/libresilient/-/issues/5</a></li>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/6">https://gitlab.com/rysiekpl/libresilient/-/issues/6</a></li>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/8">https://gitlab.com/rysiekpl/libresilient/-/issues/8</a></li>
</ul>

<p>Currently test coverage is <a href="https://gitlab.com/rysiekpl/libresilient/-/jobs/1602926785#L1790">at ~53% overall</a>. This might not sound like a lot, until one considers that for all mature plugins (<code class="language-plaintext highlighter-rouge">fetch</code>, <code class="language-plaintext highlighter-rouge">cache</code>, <code class="language-plaintext highlighter-rouge">any-of</code>, <code class="language-plaintext highlighter-rouge">alt-fetch</code>) it’s at 100%, and for <code class="language-plaintext highlighter-rouge">service-worker.js</code> – the most important and complicated piece of the project – it’s at ~95%.</p>

<p>This means development can go ahead with reasonable confidence, as most bugs get caught early.</p>

<p>Less stable plugins (<code class="language-plaintext highlighter-rouge">gun-ipfs</code>, <code class="language-plaintext highlighter-rouge">ipns-ipfs</code>), and user-facing <code class="language-plaintext highlighter-rouge">libresilient.js</code> do not have a lot of test coverage currently, as they will require substantial rewrites in near future.</p>

<p>Security testing infrastructure was also set-up, which led to code quality improvements:</p>
<ul>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/13">https://gitlab.com/rysiekpl/libresilient/-/issues/13</a></li>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/12">https://gitlab.com/rysiekpl/libresilient/-/issues/12</a></li>
</ul>

<h2 id="2-re-thinking-and-re-writing-plugin-architecture">2. Re-thinking and re-writing plugin architecture.</h2>

<ul>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/issues/15">https://gitlab.com/rysiekpl/libresilient/-/issues/15</a></li>
</ul>

<p>This was a rather hairy piece of work, as it required refactoring of a lot of tightly-coupled code which was also handling core functionality of libresilient, and used to have certain old assumptions (like: <em>“a plugin can only be used once in the config”</em>) baked-in.</p>

<p>Having a testing harness helped a lot in making those changes without worrying if LibResilient remains functional, limiting the chance serious bugs were introduced.</p>

<p>This also laid down the groundwork for future work on other milestones, for example by making the config-handling code cleaner and easier to reason about.</p>

<h2 id="3-random-fixes-and-improvements">3. Random fixes and improvements</h2>

<p>Along the way some old code was re-written and random issues fixed; importantly, more error handling code was added to service-worker.js, for example:</p>
<ul>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/blame/736675fa0673f50700a199cb3f21119c3b493f52/service-worker.js#L106">https://gitlab.com/rysiekpl/libresilient/-/blame/736675fa0673f50700a199cb3f21119c3b493f52/service-worker.js#L106</a></li>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/blame/736675fa0673f50700a199cb3f21119c3b493f52/service-worker.js#L235">https://gitlab.com/rysiekpl/libresilient/-/blame/736675fa0673f50700a199cb3f21119c3b493f52/service-worker.js#L235</a></li>
  <li><a href="https://gitlab.com/rysiekpl/libresilient/-/blame/736675fa0673f50700a199cb3f21119c3b493f52/service-worker.js#L535">https://gitlab.com/rysiekpl/libresilient/-/blame/736675fa0673f50700a199cb3f21119c3b493f52/service-worker.js#L535</a></li>
</ul>

<p>Improved error handling means LibResilient should work better in Safari now (Safari implementing some new web APIs in the meantime also helped, of course).</p>

<h2 id="whats-next">What’s next?</h2>

<p>I’m going to continue to work on LibResilient in a rather organic way – without a very strict plan. There’s plenty to be done, and basically all planned improvements are intertwined with one another. Setting up a proper website for the project, with some demos and examples, is high on the list though.</p>]]></content><author><name>rysiek</name></author><category term="blog" /><summary type="html"><![CDATA[Took a while (summer holidays got in the way), but LibResilient finally reached a milestone: “Improved resilience of libresilient”. It’s a reasonably big deal, for a number of reasons. First, that means that development is actually happening again. Second, one of the goals of this milestone was to create a decent testing harness, so that any errors or breakage caused by code changes can be caught early and fixed. Third, this is the first milestone covered by the NLnet grant for LibResilient. You read that right: LibResilient development is now supported as part of the NGI Assure project. There are six more milestones defined as part of that grant.]]></summary></entry></feed>