<?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: Mathieu Kerjouan</title>
    <description>The latest articles on DEV Community by Mathieu Kerjouan (@niamtokik).</description>
    <link>https://dev.to/niamtokik</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1302415%2Ff02d4ee9-14d9-45ec-966a-6bb53e0e3240.jpeg</url>
      <title>DEV Community: Mathieu Kerjouan</title>
      <link>https://dev.to/niamtokik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/niamtokik"/>
    <language>en</language>
    <item>
      <title>rdomain, wireguard, packet filter and OpenBSD</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Tue, 03 Nov 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/rdomain-wireguard-packet-filter-and-openbsd-42lm</link>
      <guid>https://dev.to/niamtokik/rdomain-wireguard-packet-filter-and-openbsd-42lm</guid>
      <description>&lt;p&gt;&lt;code&gt;rdomain&lt;/code&gt; is an interesting feature present on OpenBSD to create isolated routing domain. I rarely used this one - except for testing - but it was never deployed in production. In fact, it was pretty rare to have an OpenBSD router/firewall running outside of my own lab. A previous post was showing how to isolate a pool of workers and forward all their traffic through using onion routing using proxies. In this post, the workers traffic will be routed to a remote server using a wireguard tunnel. Both the firewall and the remote server are running on OpenBSD.&lt;/p&gt;

&lt;p&gt;A picture is worse thousand of words, then, the infrastructure schema below should give you an idea of the network structure and the connections between the different devices. Not everything is presented though, because my network is a bit more complex than that, but this is a big picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fidewl20h0mxgs3i8uakw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fidewl20h0mxgs3i8uakw.png" alt="Infrastructure Schema for Wireguard and rdomain on OpenBSD" width="800" height="1030"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before doing anything, we should probably start to learn what is an &lt;code&gt;rdomain&lt;/code&gt; and how to use it properly.&lt;/p&gt;

&lt;h1&gt;
  
  
  It's All About Isolation and Routing
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;rdomain&lt;/code&gt; appeared for the first time in OpenBSD 4.9. This goal was to offer a way to have isolated routing tables. By default, all routes are put in the &lt;code&gt;rdomain 0&lt;/code&gt;, and it can lead to some issues when dealing with complex network. With an &lt;code&gt;rdomain&lt;/code&gt;, an operator is able to create dynamically a new routing table isolated from the rest of the system, even if it is limited to 255 &lt;code&gt;rdomain&lt;/code&gt;, it shold be enough for most of the use case.&lt;/p&gt;

&lt;p&gt;Processes can be started in their own &lt;code&gt;rdomain&lt;/code&gt; with the help of the &lt;a href="https://man.openbsd.org/route" rel="noopener noreferrer"&gt;&lt;code&gt;route&lt;/code&gt;&lt;/a&gt; command and its &lt;code&gt;exec&lt;/code&gt; subcommand without forgetting the &lt;a href="https://man.openbsd.org/route#T" rel="noopener noreferrer"&gt;&lt;code&gt;-T&lt;/code&gt;&lt;/a&gt; flag. A way to check in which domain a process is in, is to use &lt;a href="https://man.openbsd.org/ps" rel="noopener noreferrer"&gt;&lt;code&gt;ps&lt;/code&gt;&lt;/a&gt; command with the &lt;a href="https://man.openbsd.org/ps#rtable" rel="noopener noreferrer"&gt;&lt;code&gt;rtable&lt;/code&gt;&lt;/a&gt; option. Let first checks the output of the &lt;code&gt;ps&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ps &lt;span class="nt"&gt;-o&lt;/span&gt; rtable,pid,ppid,%cpu,%mem,command
&lt;span class="go"&gt;RTABLE   PID  PPID %CPU %MEM COMMAND
     0 59603 14917  0.0  0.0 -ksh (ksh)
     0 13501 59603  0.0  0.2 tmux: client (/tmp/tmux-1000/default) (tmux)
     0 68852 66599  0.0  0.0 -ksh (ksh)
     0 73792 66599  0.0  0.0 -ksh (ksh)
     0 75757 66599  0.0  0.0 -ksh (ksh)
     0 85484 75757  0.0  0.1 ps -o rtable
     0 47120 66599  0.0  0.0 -ksh (ksh)
     0 86889 66599  0.0  0.0 -ksh (ksh)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AS you can see, all processes are currently running in the default &lt;code&gt;rdomain 0&lt;/code&gt;. To use another &lt;code&gt;rdomain&lt;/code&gt;, the &lt;code&gt;route&lt;/code&gt; command can be used, like it has been seen previously. Let check that by spawning a &lt;a href="https://man.openbsd.org/man1/sleep.1" rel="noopener noreferrer"&gt;&lt;code&gt;sleep&lt;/code&gt;&lt;/a&gt; in the background for 10 seconds in the &lt;code&gt;rdomain 1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-T1&lt;/span&gt; &lt;span class="nb"&gt;exec sleep &lt;/span&gt;10 &amp;amp;
&lt;span class="go"&gt;[1] 96416

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ps &lt;span class="nt"&gt;-o&lt;/span&gt; rtable,pid,ppid,%cpu,%mem,command
&lt;span class="go"&gt;RTABLE   PID  PPID %CPU %MEM COMMAND
     0 59603 14917  0.0  0.0 -ksh (ksh)
     0 13501 59603  0.0  0.2 tmux: client (/tmp/tmux-1000/default) (tmux)
     0 68852 66599  0.0  0.0 -ksh (ksh)
     0 73792 66599  0.0  0.0 -ksh (ksh)
     0 46155 73792  0.0  0.0 sleep 1
     0 75757 66599  0.0  0.0 -ksh (ksh)
     1 96416 75757  0.0  0.0 sleep 10
     0 26428 75757  0.0  0.1 ps -o rtable
     0 47120 66599  0.0  0.0 -ksh (ksh)
     0 86889 66599  0.0  0.0 -ksh (ksh)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;sleep&lt;/code&gt; process is correctly using the &lt;code&gt;rtable 1&lt;/code&gt;, but what kind of differences are existing between all of those routing tables? Well, the default routing table is initialized during the startup of the system, but all other &lt;code&gt;rdomain&lt;/code&gt; should be empty. Again, the &lt;code&gt;route&lt;/code&gt; command can be used to show that or the &lt;a href="https://man.openbsd.org/netstat.1" rel="noopener noreferrer"&gt;&lt;code&gt;netstat&lt;/code&gt;&lt;/a&gt; command can be used instead, it is offering more filtering options.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;netstat &lt;span class="nt"&gt;-rnT0&lt;/span&gt; &lt;span class="nt"&gt;-finet&lt;/span&gt;
&lt;span class="go"&gt;Routing tables

Internet:
Destination        Gateway            Flags   Refs      Use   Mtu  Prio Iface
default            192.168.123.254      UGS        9 10038979     -     8 re0
224/4              127.0.0.1          URS        0        0 32768     8 lo0
10.255.255.240/28  10.255.255.253     UCn        1        0     -     
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An existing &lt;code&gt;rdomain 1&lt;/code&gt; is currently present on my test example. As you can see, the output returned by &lt;code&gt;netstat&lt;/code&gt; is totally different than the one from the &lt;code&gt;rdomain 1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;netstat &lt;span class="nt"&gt;-rnT1&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; inet
&lt;span class="go"&gt;Routing tables

Internet:
Destination        Gateway            Flags   Refs      Use   Mtu  Prio Iface
default            172.17.0.1         UGS        0    17202     -     8 wg0
10.255.255.240/28  10.255.255.254     UCn        1        0     -     4 pair1
10.255.255.253     fe:e1:ba:d5:62:48  UHLch      1        6     -     3 pair1
10.255.255.254     fe:e1:ba:d6:4a:44  UHLl       0        4     -     1 pair1
10.255.255.255     10.255.255.254     UHb        0        0     -     1 pair1
127.0.0.1          127.0.0.1          UHl        0      315 32768     1 lo1
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;rdomain 2&lt;/code&gt; does not exist though, and when trying to show its content, an error is returned by &lt;code&gt;netstat&lt;/code&gt;. The same error is returned to any unitialized &lt;code&gt;rdomains&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;netstat &lt;span class="nt"&gt;-rnT2&lt;/span&gt;
&lt;span class="go"&gt;netstat: routing table 2: No such file or directory
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;netstat &lt;span class="nt"&gt;-rnT3&lt;/span&gt;
&lt;span class="go"&gt;netstat: routing table 3: No such file or directory
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;rdomain&lt;/code&gt;s can be created when dealing with network interfaces and pseudo devices. For example, let created &lt;code&gt;rdomain 2&lt;/code&gt; and &lt;code&gt;rdomain 3&lt;/code&gt; by defining &lt;code&gt;lo2&lt;/code&gt; and &lt;code&gt;lo3&lt;/code&gt; loopback interfaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig lo2 create rdomain 2 &lt;span class="nb"&gt;alias &lt;/span&gt;127.0.0.1 up
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig lo2
&lt;span class="gp"&gt;lo2: flags=2008049&amp;lt;UP,LOOPBACK,RUNNING,MULTICAST,LRO&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rdomain 2 mtu 32768
&lt;span class="go"&gt;        index 26 priority 0 llprio 3
        groups: lo
        inet6 ::1 prefixlen 128
        inet6 fe80::1%lo2 prefixlen 64 scopeid 0x1a
        inet 127.0.0.1 netmask 0xff000000
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig lo3 create rdomain 3 &lt;span class="nb"&gt;alias &lt;/span&gt;127.0.0.1 up
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig lo3
&lt;span class="gp"&gt;lo3: flags=2008049&amp;lt;UP,LOOPBACK,RUNNING,MULTICAST,LRO&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rdomain 3 mtu 32768
&lt;span class="go"&gt;        index 27 priority 0 llprio 3
        groups: lo
        inet6 ::1 prefixlen 128
        inet6 fe80::1%lo3 prefixlen 64 scopeid 0x1b
        inet 127.0.0.1 netmask 0xff000000
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both interfaces are totally isolated in their own address space, with its own routing table, this is why the same IP address (here &lt;code&gt;127.0.0.1&lt;/code&gt;) can be set. To extend the example, 2 &lt;code&gt;vether&lt;/code&gt; interfaces can be created as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig vether2 create &lt;span class="nb"&gt;alias &lt;/span&gt;10.0.0.1/24 rdomain 2 up
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ifconfig vether2
&lt;span class="gp"&gt;vether2: flags=8843&amp;lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rdomain 2 mtu 1500
&lt;span class="go"&gt;        lladdr fe:e1:ba:d9:1b:6c
        index 30 priority 0 llprio 3
        groups: vether
        media: Ethernet autoselect
        status: active
        inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig vether3 create &lt;span class="nb"&gt;alias &lt;/span&gt;10.0.1.1/24 rdomain 3 up
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ifconfig vether3
&lt;span class="gp"&gt;vether3: flags=8843&amp;lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rdomain 3 mtu 1500
&lt;span class="go"&gt;        lladdr fe:e1:ba:da:b5:73
        index 31 priority 0 llprio 3
        groups: vether
        media: Ethernet autoselect
        status: active
        inet 10.0.1.1 netmask 0xffffff00 broadcast 10.0.1.255
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To interconnect those networks 2 &lt;code&gt;pair&lt;/code&gt; interfaces can be created. A  small subnet will be create to route the packets between both networks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig pair2 create &lt;span class="nb"&gt;alias &lt;/span&gt;172.31.255.253/30 rdomain 2 up
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ifconfig pair2
&lt;span class="gp"&gt;pair2: flags=8843&amp;lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rdomain 2 mtu 1500
&lt;span class="go"&gt;        lladdr fe:e1:ba:de:a4:28
        index 35 priority 0 llprio 3
        groups: pair
        media: Ethernet autoselect
        inet 172.31.255.253 netmask 0xfffffffc broadcast 172.31.255.255
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig pair3 create &lt;span class="nb"&gt;alias &lt;/span&gt;172.31.255.254/30 rdomain 3 up 
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ifconfig pair3
&lt;span class="gp"&gt;pair3: flags=8843&amp;lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rdomain 3 mtu 1500
&lt;span class="go"&gt;        lladdr fe:e1:ba:df:34:e5
        index 36 priority 0 llprio 3
        groups: pair
        media: Ethernet autoselect
        inet 172.31.255.254 netmask 0xfffffffc broadcast 172.31.255.255
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;pair&lt;/code&gt; interfaces must be patched together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig pair2 patch pair3
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ifconfig pair2
&lt;span class="gp"&gt;pair2: flags=8843&amp;lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rdomain 2 mtu 1500
&lt;span class="go"&gt;        lladdr fe:e1:ba:de:a4:28
        index 35 priority 0 llprio 3
        patch: pair3
        groups: pair
        media: Ethernet autoselect
        status: active
        inet 172.31.255.253 netmask 0xfffffffc broadcast 172.31.255.255

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ifconfig pair3
&lt;span class="gp"&gt;pair3: flags=8843&amp;lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rdomain 3 mtu 1500
&lt;span class="go"&gt;        lladdr fe:e1:ba:df:34:e5
        index 36 priority 0 llprio 3
        patch: pair2
        groups: pair
        media: Ethernet autoselect
        status: active
        inet 172.31.255.254 netmask 0xfffffffc broadcast 172.31.255.25
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should now be possible to reach &lt;code&gt;pair2&lt;/code&gt; network from &lt;code&gt;pair3&lt;/code&gt; and vice versa. The best way to check that is to use the &lt;code&gt;route exec&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT2&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;ping &lt;span class="nt"&gt;-c&lt;/span&gt; 3 172.31.255.254
&lt;span class="go"&gt;PING 172.31.255.254 (172.31.255.254): 56 data bytes
64 bytes from 172.31.255.254: icmp_seq=0 ttl=255 time=0.615 ms
64 bytes from 172.31.255.254: icmp_seq=1 ttl=255 time=0.369 ms
64 bytes from 172.31.255.254: icmp_seq=2 ttl=255 time=0.382 ms

--- 172.31.255.254 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 0.369/0.455/0.615/0.113 ms

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT3&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;ping &lt;span class="nt"&gt;-c3&lt;/span&gt; 172.31.255.253
&lt;span class="go"&gt;PING 172.31.255.253 (172.31.255.253): 56 data bytes
64 bytes from 172.31.255.253: icmp_seq=0 ttl=255 time=0.352 ms
64 bytes from 172.31.255.253: icmp_seq=1 ttl=255 time=0.364 ms
64 bytes from 172.31.255.253: icmp_seq=2 ttl=255 time=0.378 ms

--- 172.31.255.253 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 0.352/0.364/0.378/0.011 ms

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT3&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;ping &lt;span class="nt"&gt;-c1&lt;/span&gt; 10.0.0.1
&lt;span class="go"&gt;PING 10.0.0.1 (10.0.0.1): 56 data bytes
ping: sendmsg: Can't assign requested address
ping: wrote 10.0.0.1 64 chars, ret=-1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;10.0.0.1/24&lt;/code&gt; and &lt;code&gt;10.0.1.0/24&lt;/code&gt; networks are not reachable yet, because no routes have been configured. Let fix that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas route &lt;span class="nt"&gt;-nT2&lt;/span&gt; add 10.0.1.0/24 172.31.255.254
&lt;span class="go"&gt;add net 10.0.1.0/24: gateway 172.31.255.254

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;netstat &lt;span class="nt"&gt;-rnfinet&lt;/span&gt; &lt;span class="nt"&gt;-T2&lt;/span&gt;
&lt;span class="go"&gt;Routing tables

Internet:
Destination        Gateway            Flags   Refs      Use   Mtu  Prio Iface
10.0.0/24          10.0.0.1           UCn        0        0     -     4 vether2
10.0.0.1           fe:e1:ba:d9:1b:6c  UHLl       0        8     -     1 vether2
10.0.0.255         10.0.0.1           UHb        0        0     -     1 vether2
10.0.1/24          172.31.255.254     UGS        0        0     -     8 pair2
127.0.0.1          127.0.0.1          UHl        0        0 32768     1 lo2
172.31.255.252/30  172.31.255.253     UCn        1        0     -     4 pair2
172.31.255.253     fe:e1:ba:de:a4:28  UHLl       0       10     -     1 pair2
172.31.255.254     fe:e1:ba:df:34:e5  UHLch      1       13     -     3 pair2
172.31.255.255     172.31.255.253     UHb        0        0     -     1 pair2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas route &lt;span class="nt"&gt;-nT3&lt;/span&gt; add 10.0.0.0/24 172.31.255.253
&lt;span class="go"&gt;add net 10.0.0.0/24: gateway 172.31.255.253

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;netstat &lt;span class="nt"&gt;-rnfinet&lt;/span&gt; &lt;span class="nt"&gt;-T3&lt;/span&gt;
&lt;span class="go"&gt;Routing tables

Internet:
Destination        Gateway            Flags   Refs      Use   Mtu  Prio Iface
10.0.0/24          172.31.255.253     UGS        0        2     -     8 pair3
10.0.1/24          10.0.1.1           UCn        0        0     -     4 vether3
10.0.1.1           fe:e1:ba:da:b5:73  UHLl       0        0     -     1 vether3
10.0.1.255         10.0.1.1           UHb        0        0     -     1 vether3
127.0.0.1          127.0.0.1          UHl        0        0 32768     1 lo3
172.31.255.252/30  172.31.255.254     UCn        1        0     -     4 pair3
172.31.255.253     fe:e1:ba:de:a4:28  UHLch      1        7     -     3 pair3
172.31.255.254     fe:e1:ba:df:34:e5  UHLl       0       14     -     1 pair3
172.31.255.255     172.31.255.254     UHb        0        0     -     1 pair3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After having added these routes, both network are available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT3&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;ping &lt;span class="nt"&gt;-c3&lt;/span&gt; 10.0.0.1
&lt;span class="go"&gt;PING 10.0.0.1 (10.0.0.1): 56 data bytes
64 bytes from 10.0.0.1: icmp_seq=0 ttl=255 time=0.476 ms
64 bytes from 10.0.0.1: icmp_seq=1 ttl=255 time=0.371 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=255 time=0.272 ms

--- 10.0.0.1 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 0.272/0.373/0.476/0.083 ms

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT2&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;ping &lt;span class="nt"&gt;-c3&lt;/span&gt; 10.0.1.1
&lt;span class="go"&gt;PING 10.0.1.1 (10.0.1.1): 56 data bytes
64 bytes from 10.0.1.1: icmp_seq=0 ttl=255 time=0.477 ms
64 bytes from 10.0.1.1: icmp_seq=1 ttl=255 time=0.355 ms
64 bytes from 10.0.1.1: icmp_seq=2 ttl=255 time=0.271 ms

--- 10.0.1.1 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 0.271/0.368/0.477/0.085 ms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Managing one or two &lt;code&gt;rdomain&lt;/code&gt; can easily be done with packet-filter, but if you have more than that, it could become rapidly a complex task. While looking for more examples and use cases from the *BSD users, many authors were recommending using &lt;a href="https://man.openbsd.org/pf.conf#ANCHORS" rel="noopener noreferrer"&gt;packet-filter anchors&lt;/a&gt; to make the configuration easier to understand and to control. Let check that, if you don't know, packet-filter configuration file is located in &lt;code&gt;/etc/pf.conf&lt;/code&gt;, but before editing this file, two new &lt;code&gt;pflog&lt;/code&gt; interfaces will be required to log the packets from these domains.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig pflog2 create up
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig pflog3 create up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;rdomain 2&lt;/code&gt; ruleset will be managed by the &lt;code&gt;rd2&lt;/code&gt; anchor and the &lt;code&gt;rdomain 3&lt;/code&gt; will be managed by the &lt;code&gt;rd3&lt;/code&gt; anchor. Both of them will only have one rule for now, to log all packets in transit respectively to &lt;code&gt;pflog2&lt;/code&gt; and &lt;code&gt;pflog3&lt;/code&gt; pseudo interfaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="s2"&gt;"rd2"&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; {
  &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; (&lt;span class="n"&gt;all&lt;/span&gt;, &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pflog2&lt;/span&gt;)
}

&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="s2"&gt;"rd3"&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; {
  &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; (&lt;span class="n"&gt;all&lt;/span&gt;, &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pflog3&lt;/span&gt;)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas pfctl &lt;span class="nt"&gt;-f&lt;/span&gt; /etc/pf.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is another great feature available by default with packet-filter, instead of having text logs output, the typical logs messages when using &lt;a href="https://manpages.debian.org/trixie/iptables/iptables.8.en.html" rel="noopener noreferrer"&gt;&lt;code&gt;iptables&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://manpages.debian.org/trixie/nftables/nftables.8.en.html" rel="noopener noreferrer"&gt;&lt;code&gt;nftables&lt;/code&gt;&lt;/a&gt; on Linux systems, the packets are directly duplicated to a dedicated interfaces, compatible with &lt;a href="https://man.openbsd.org/tcpdump" rel="noopener noreferrer"&gt;&lt;code&gt;tcpdump&lt;/code&gt;&lt;/a&gt; and giving us the possibility to export them in PCAP format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas tcpdump &lt;span class="nt"&gt;-i&lt;/span&gt; pflog2
&lt;span class="go"&gt;tcpdump: listening on pflog2, link-type PFLOG
&lt;/span&gt;&lt;span class="gp"&gt;13:49:03.419153 172.31.255.253 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;10.0.1.1: icmp: &lt;span class="nb"&gt;echo &lt;/span&gt;request
&lt;span class="gp"&gt;13:49:03.419380 10.0.1.1 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;172.31.255.253: icmp: &lt;span class="nb"&gt;echo &lt;/span&gt;reply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas tcpdump &lt;span class="nt"&gt;-i&lt;/span&gt; pflog3
&lt;span class="go"&gt;tcpdump: listening on pflog3, link-type PFLOG
&lt;/span&gt;&lt;span class="gp"&gt;13:49:03.419267 172.31.255.253 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;10.0.1.1: icmp: &lt;span class="nb"&gt;echo &lt;/span&gt;request
&lt;span class="gp"&gt;13:49:03.419330 10.0.1.1 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;172.31.255.253: icmp: &lt;span class="nb"&gt;echo &lt;/span&gt;reply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The packets displayed in the &lt;code&gt;tcpdump&lt;/code&gt; output have been generated by a simple &lt;code&gt;ping&lt;/code&gt; command. As you can see, we have know a way to understand more deeply what can happen on each &lt;code&gt;rdomain&lt;/code&gt; previously created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT2&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;ping &lt;span class="nt"&gt;-c1&lt;/span&gt; 10.0.1.1
&lt;span class="go"&gt;PING 10.0.1.1 (10.0.1.1): 56 data bytes
64 bytes from 10.0.1.1: icmp_seq=0 ttl=255 time=0.479 ms

--- 10.0.1.1 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 0.479/0.479/0.479/0.000 ms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One question to ask is if it is possible to forward packets from one &lt;code&gt;rdomain&lt;/code&gt; to another via packet-filter. Indeed, the configuration support &lt;code&gt;on rdomain NUMBER&lt;/code&gt; and &lt;code&gt;rtable NUMBER&lt;/code&gt; parameters, so, it should be possible to achieve. To test this the &lt;code&gt;pair&lt;/code&gt; interfaces previously created must be destroyed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig pair2 destroy
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig pair3 destroy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be sure the loopback interfaces (&lt;code&gt;lo2&lt;/code&gt; and &lt;code&gt;lo3&lt;/code&gt; in this example) are not skipped, the firewall must have the control on all traffic on these &lt;code&gt;rdomain&lt;/code&gt;s. When an ICMP packet is sent on &lt;code&gt;rdomain 2&lt;/code&gt;, it will be redirected to &lt;code&gt;rdomain 3&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="s2"&gt;"rd2"&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; {
  &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; (&lt;span class="n"&gt;all&lt;/span&gt;, &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pflog2&lt;/span&gt;)
  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt; \
    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt; \
    &lt;span class="n"&gt;rtable&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; \
    &lt;span class="n"&gt;rdr&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;
}

&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="s2"&gt;"rd3"&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; {
  &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; (&lt;span class="n"&gt;all&lt;/span&gt;, &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pflog3&lt;/span&gt;)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas pfctl &lt;span class="nt"&gt;-f&lt;/span&gt; /etc/pf.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT2&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;ping &lt;span class="nt"&gt;-c&lt;/span&gt; 1 10.0.0.1
&lt;span class="go"&gt;PING 10.0.0.1 (10.0.0.1): 56 data bytes
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas tcpdump &lt;span class="nt"&gt;-i&lt;/span&gt; pflog2
&lt;span class="gp"&gt;14:17:19.787826 10.0.0.1 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;10.0.0.1: icmp: &lt;span class="nb"&gt;echo &lt;/span&gt;request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas tcpdump &lt;span class="nt"&gt;-i&lt;/span&gt; pflog3
&lt;span class="gp"&gt;14:17:19.788009 10.0.0.1 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;10.0.1.1: icmp: &lt;span class="nb"&gt;echo &lt;/span&gt;request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without a route to &lt;code&gt;10.0.1.1/24&lt;/code&gt;, previously removed alongside the &lt;code&gt;pair&lt;/code&gt; interfaces, it fails. Packet-filter will do the redirection anyway because it can switch from different routing tables and domains. It means the packet from &lt;code&gt;10.0.0.1&lt;/code&gt; is correctly forwarded to the &lt;code&gt;10.0.1.1&lt;/code&gt; address. Unfortunately, &lt;code&gt;10.0.1.1&lt;/code&gt; can't reply to &lt;code&gt;10.0.0.1&lt;/code&gt; because it does not have it in its own table. ICMP is perhaps not the best protocol to do those kind of redirection because it is stateless, and it can become very complex to manage the redirection. It is possible to generate an ICMP reply quite easily though, even without a correct routing table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="s2"&gt;"rd2"&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; {
  &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; (&lt;span class="n"&gt;all&lt;/span&gt;, &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pflog2&lt;/span&gt;)
  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt; \
    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt; \
    &lt;span class="n"&gt;icmp&lt;/span&gt;-&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;echoreq&lt;/span&gt; \
    &lt;span class="n"&gt;rtable&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; \
    &lt;span class="n"&gt;rdr&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;
}

&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="s2"&gt;"rd3"&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; {
  &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; (&lt;span class="n"&gt;all&lt;/span&gt;, &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pflog3&lt;/span&gt;)
  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt; \
    &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt; \
    &lt;span class="n"&gt;icmp&lt;/span&gt;-&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;echoreq&lt;/span&gt; \
    &lt;span class="n"&gt;rtable&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; \
    &lt;span class="n"&gt;rdr&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT2&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;ping &lt;span class="nt"&gt;-c&lt;/span&gt; 1 10.0.0.1
&lt;span class="go"&gt;PING 10.0.0.1 (10.0.0.1): 56 data bytes
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas tcpdump &lt;span class="nt"&gt;-i&lt;/span&gt; pflog2
&lt;span class="gp"&gt;14:55:06.725461 10.0.0.1 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;10.0.0.1: icmp: &lt;span class="nb"&gt;echo &lt;/span&gt;request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas tcpdump &lt;span class="nt"&gt;-i&lt;/span&gt; pflog3
&lt;span class="gp"&gt;14:55:06.725640 10.0.0.1 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;10.0.1.1: icmp: &lt;span class="nb"&gt;echo &lt;/span&gt;request
&lt;span class="gp"&gt;14:55:06.725780 10.0.1.1 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;10.0.0.1: icmp: &lt;span class="nb"&gt;echo &lt;/span&gt;reply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this last example, it is possible to redirect a packet from one &lt;code&gt;rdomain&lt;/code&gt; to another, but it is probably not the best idea to that in this way, because the rules will become quickly hard to understand. Regarding the anchors, one can also use another alternative syntax by passing the &lt;code&gt;rdomain&lt;/code&gt; to each rules, like the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; (&lt;span class="n"&gt;all&lt;/span&gt;, &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pflog2&lt;/span&gt;) &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt; \
  &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt; \
  &lt;span class="n"&gt;icmp&lt;/span&gt;-&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;echoreq&lt;/span&gt; \
  &lt;span class="n"&gt;rtable&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; \
  &lt;span class="n"&gt;rdr&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  VPN Server Configuration
&lt;/h1&gt;

&lt;p&gt;The VPN server will act as the default router for the workers present behind the firewall they are connected to. This server is already quite busy, many services like OpenVPN, Tinc, and few others are already present and running. The private network attributed to all those services were taken randomly, and it's a small mess. To avoid confusion, only the rules for the VPN using Wireguard will be presented, in their own &lt;code&gt;rdomain&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig lo1 create rdomain 1 &lt;span class="nb"&gt;alias &lt;/span&gt;127.0.0.1 up
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.lo1 &amp;lt; EOF
&lt;span class="go"&gt;rdomain 1
alias 127.0.0.1
up
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;rdomain 1&lt;/code&gt; is totally isolated from &lt;code&gt;rdomain 0&lt;/code&gt; where the &lt;code&gt;vio0&lt;/code&gt; interface is present, it is necessary to create an interconnection network between them. The best way is to create 2 &lt;code&gt;pair&lt;/code&gt; interfaces. The subnet will be set to &lt;code&gt;10.255.255.250/30&lt;/code&gt;. &lt;code&gt;pair0&lt;/code&gt; will stay in &lt;code&gt;rdomain 0&lt;/code&gt;, and will give knowledge to the routes available on &lt;code&gt;rdomain 1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig pair0 create rdomain 0 up
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.pair0 &amp;lt; EOF
&lt;span class="go"&gt;inet 10.255.255.253/30
patch pair1
up
!route add 172.17.0.0/24 10.255.255.254
!route add 172.16.0.0/24 10.255.255.254
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pair1&lt;/code&gt; will be pushed in &lt;code&gt;rdomain 1&lt;/code&gt; and like &lt;code&gt;pair0&lt;/code&gt;, it will announce the route available on its side.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig pair1 create rdomain 1 up
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.pair1 &amp;lt; EOF
&lt;span class="go"&gt;rdomain 1
inet 10.255.255.254/30
up
!route -T1 add default 10.255.255.253
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this pseudo interface configured, it is now possible to reach the network(s) present in &lt;code&gt;rdomain 1&lt;/code&gt;. Let configures the VPN with a wireguard pseudo interface. The following snippet hides the private information to avoid leaks, but the idea is quite simple.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;generate a private key using &lt;code&gt;openssl&lt;/code&gt; from a random integer encoded in base64;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;use a new random port (let say it will be 12345 for the rest of the configuration) using &lt;code&gt;openssl&lt;/code&gt; as well;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;add the public key from the firewall (it will be shown in the next part)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;configure the end-point, in our case, it will be the public address of my firewall, let say 1.2.3.4 for now;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;creates the &lt;code&gt;wg0&lt;/code&gt; interface using &lt;code&gt;ifconfig&lt;/code&gt; containing the previously created parameters. Set also the &lt;code&gt;wgaip&lt;/code&gt; to explicitly allow the IP address from the firewall;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;finally, create the &lt;code&gt;/etc/hostname.wg0&lt;/code&gt; file containing the very same information to recreate automatically the VPN after a reboot.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;server_wgkey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-base64&lt;/span&gt; 32&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;server_wgport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"0x&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 2&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;server_wgpeer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;firewall_public_key&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;server_wgendpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;firewall_ip_address&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig wg0 create wgport &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;server_wgport&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="gp"&gt;  wgkey $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;server_wgkey&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="gp"&gt;  wgpeer $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;server_wgpeer&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="go"&gt;  wgaip 172.17.0.2/32 \
  wgaip 172.16.0.0/24 \
&lt;/span&gt;&lt;span class="gp"&gt;  wgendpoint $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;server_wgendpoint&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="go"&gt;  172.17.0.1/24 \
  rdomain 1 \
  up

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.wg0 &amp;lt; EOF
&lt;span class="gp"&gt;wgport $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;server_wgport&lt;span class="o"&gt;}&lt;/span&gt; wgkey &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;server_wgkey&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;wgpeer $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;server_wgpeer&lt;span class="o"&gt;}&lt;/span&gt; wgaip 172.17.0.2/32 wgaip 172.16.0.0/24
&lt;span class="gp"&gt;wgendpoint $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;server_wgendpoint&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;172.17.0.1/24
rdomain 1
up
!route -T1 add 172.16.0.0/24 172.17.0.2
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having a dedicated &lt;code&gt;pflog&lt;/code&gt; interface for this &lt;code&gt;rdomain&lt;/code&gt; can also be helpful, so, one can create the &lt;code&gt;pflog1&lt;/code&gt; interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ifconfig pflog1 create up
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.pflog1 &amp;lt; EOF
&lt;span class="go"&gt;up
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The configuration is practically over, packet-filter configuration will be the last step. The first part of this configuration will ensure the packets from the VPN are correctly translated to the public address set on the &lt;code&gt;vio0&lt;/code&gt; interface. In short, addresses from the worker network will use the public address of this server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; \
  &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.&lt;span class="m"&gt;255&lt;/span&gt;.&lt;span class="m"&gt;255&lt;/span&gt;.&lt;span class="m"&gt;253&lt;/span&gt;/&lt;span class="m"&gt;28&lt;/span&gt; \
  &lt;span class="n"&gt;nat&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt; (&lt;span class="n"&gt;vio0&lt;/span&gt;) &lt;span class="n"&gt;static&lt;/span&gt;-&lt;span class="n"&gt;port&lt;/span&gt;

&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; \
  &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="m"&gt;172&lt;/span&gt;.&lt;span class="m"&gt;17&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;/&lt;span class="m"&gt;24&lt;/span&gt; \
  &lt;span class="n"&gt;rtable&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; \
  &lt;span class="n"&gt;nat&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt; (&lt;span class="n"&gt;vio0&lt;/span&gt;) &lt;span class="n"&gt;static&lt;/span&gt;-&lt;span class="n"&gt;port&lt;/span&gt;

&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; \
  &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="m"&gt;172&lt;/span&gt;.&lt;span class="m"&gt;16&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;/&lt;span class="m"&gt;24&lt;/span&gt; \
  &lt;span class="n"&gt;rtable&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; \
  &lt;span class="n"&gt;nat&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt; (&lt;span class="n"&gt;vio0&lt;/span&gt;) &lt;span class="n"&gt;static&lt;/span&gt;-&lt;span class="n"&gt;port&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DNS resolution can be a problem, and to avoid DNS leaks, all packets from the worker network will be redirected to a local &lt;code&gt;unbound&lt;/code&gt; instance, in charge of doing the domain resolution. It will also be easier to see what kind of queries are sent to domain servers and to filter them in one place.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; (&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pflog1&lt;/span&gt;) &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; \
  &lt;span class="n"&gt;proto&lt;/span&gt; {&lt;span class="n"&gt;tcp&lt;/span&gt;, &lt;span class="n"&gt;udp&lt;/span&gt;} \
  &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="m"&gt;53&lt;/span&gt; \
  &lt;span class="n"&gt;rtable&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; \
  &lt;span class="n"&gt;rdr&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;127&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Packet-filter is blocking all traffic by default. Wireguard needs to have its port accessible to other nodes though, then, the port previously create will be opened.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;vio0&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;udp&lt;/span&gt; \
  &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="m"&gt;12345&lt;/span&gt; \
  &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="s2"&gt;"wireguard vpn"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the last rules are only for &lt;code&gt;rdomain 1&lt;/code&gt;. All packets are blocked and logged by default in this &lt;code&gt;rdomain&lt;/code&gt;. ICMP and few TCP ports are allowed though, for SSH, HTTP and HTTPS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="s2"&gt;"workers"&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; {
  &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; (&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pflog1&lt;/span&gt;)
  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt;
  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;tcp&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; {&lt;span class="m"&gt;22&lt;/span&gt;, &lt;span class="m"&gt;80&lt;/span&gt;, &lt;span class="m"&gt;443&lt;/span&gt;} &lt;span class="n"&gt;keep&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Packet-filter configuration can be reloaded or restarted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas pfctl &lt;span class="nt"&gt;-nf&lt;/span&gt; /etc/pf.conf
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas pfctl &lt;span class="nt"&gt;-f&lt;/span&gt; /etc/pf.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this configuration, any nodes connected to wireguard will use the IP address of the server instead of their own (or the IP address of their routers). Especially useful if your workers are running in private place and you don't want to share your real IP address to Gitlab (or any other provider).&lt;/p&gt;

&lt;p&gt;Fixing the right access to the hostname.if files can also be a good idea.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas &lt;span class="nb"&gt;chmod &lt;/span&gt;600 /etc/hostname.&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Firewall Configuration
&lt;/h1&gt;

&lt;p&gt;The firewall will be way easier to configure, the process will be similar than the one for the server. At first, creating a loopback interface for &lt;code&gt;rdomain 1&lt;/code&gt; can help.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.lo1 &amp;lt; EOF
&lt;span class="go"&gt;rdomain 1
alias 127.0.0.1
up
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main physical interface called &lt;code&gt;re1&lt;/code&gt; will be put in &lt;code&gt;rdomain 1&lt;/code&gt;, and will not be configured. The IP address will be set on a &lt;code&gt;vether&lt;/code&gt; pseudo interface created during the next step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.re1 &amp;lt; EOF
&lt;span class="go"&gt;rdomain 1
up
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;vether0&lt;/code&gt; is the main interface for &lt;code&gt;rdomain 1&lt;/code&gt;. It is the gateway for the workers' network and will be put in &lt;code&gt;rdomain 1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.vether0 &amp;lt; EOF
&lt;span class="go"&gt;rdomain 1
inet 172.16.0.1/24
up
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bridge called &lt;code&gt;bridge0&lt;/code&gt; will be used to interconnect &lt;code&gt;vether0&lt;/code&gt; and &lt;code&gt;re1&lt;/code&gt;, and will be put also in &lt;code&gt;rdomain 1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.bridge0 &amp;lt; EOF
&lt;span class="go"&gt;add vether0
add re1
rdomain 1
up
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My private network should have access to the workers' network, for monitoring and maintenance purpose. The workers will not be allowed to pass there though, this rule will be enforced in packet filter. Anyway, a small interconnection network will be created and set on &lt;code&gt;pair0&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.pair0 &amp;lt; EOF
&lt;span class="go"&gt;inet 10.255.255.253/30
rdomain 0
patch pair1
up
!route add 172.16.0/24 10.255.255.254
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pair1&lt;/code&gt; will also be created and connected to &lt;code&gt;pair0&lt;/code&gt;. This time, &lt;code&gt;pair1&lt;/code&gt; will be put in &lt;code&gt;rdomain 1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.pair1 &amp;lt; EOF
&lt;span class="go"&gt;inet 10.255.255.254/30
rdomain 1
up
&lt;/span&gt;&lt;span class="gp"&gt;!route -T1 add $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;local_private_network&lt;span class="o"&gt;}&lt;/span&gt; 10.255.255.253
&lt;span class="go"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A wireguard &lt;code&gt;wg0&lt;/code&gt; speudo interface is also required to connect the firewall to the VPN. The procedure is the very same than before, except the information are created for the firewall this time, and not for the server. &lt;code&gt;wgaip&lt;/code&gt; parameter is also set to &lt;code&gt;0.0.0.0/0&lt;/code&gt; to allow any network to pass through the VPN, very useful if the VPN will be set as default gateway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;fw_wgkey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-base64&lt;/span&gt; 32&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;fw_wgport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"0x&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 2&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;fw_wgpeer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;server_public_key&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;fw_wgendpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;server_ip_address&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/hostname.wg0 &amp;lt; EOF
&lt;span class="gp"&gt;wgport $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;fw_wgport&lt;span class="o"&gt;}&lt;/span&gt; wgkey &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;server_wgkey&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;wgpeer $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;fw_wgpeer&lt;span class="o"&gt;}&lt;/span&gt; wgaip 0.0.0.0/0
&lt;span class="gp"&gt;wgendpoint $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;server_wgendpoint&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;172.17.0.2/24
rdomain 1
up
!route -T1 add default 172.17.0.1
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the packet-filter configuration present in &lt;code&gt;/etc/pf.conf&lt;/code&gt;. The first part defines the macros. Classic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;worker_if&lt;/span&gt; = &lt;span class="s2"&gt;"{ re1, bridge0, vether0 }"&lt;/span&gt;
&lt;span class="n"&gt;worker_network&lt;/span&gt; = &lt;span class="s2"&gt;"172.16.0.0/24"&lt;/span&gt;
&lt;span class="n"&gt;worker_gateway&lt;/span&gt; = &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="m"&gt;172&lt;/span&gt;.&lt;span class="m"&gt;16&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To avoid leaks, all packets from the workers' network will be dropped and not allowed to pass through the outgoing interface &lt;code&gt;re0&lt;/code&gt;. This is probably not necessary here, because in the full configuration a &lt;code&gt;block log&lt;/code&gt; is also present, and should block these connections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; \
  &lt;span class="n"&gt;on&lt;/span&gt; $&lt;span class="n"&gt;worker_if&lt;/span&gt; \
  &lt;span class="n"&gt;from&lt;/span&gt; $&lt;span class="n"&gt;worker_network&lt;/span&gt; \
  &lt;span class="n"&gt;to&lt;/span&gt; (&lt;span class="n"&gt;re0&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The connections from the private network (here set to &lt;code&gt;! $worker_network&lt;/code&gt; but it could be set with a network) are allowed to reach the workers' network with a small subset of protocols, including ICMP, SSH, HTTP and HTTPS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt; \
  &lt;span class="n"&gt;from&lt;/span&gt; ! $&lt;span class="n"&gt;worker_network&lt;/span&gt; \
  &lt;span class="n"&gt;to&lt;/span&gt; $&lt;span class="n"&gt;worker_network&lt;/span&gt;

&lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;tcp&lt;/span&gt; \
  &lt;span class="n"&gt;from&lt;/span&gt; ! $&lt;span class="n"&gt;worker_network&lt;/span&gt; \
  &lt;span class="n"&gt;to&lt;/span&gt; $&lt;span class="n"&gt;worker_network&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; {&lt;span class="m"&gt;22&lt;/span&gt;, &lt;span class="m"&gt;80&lt;/span&gt;, &lt;span class="m"&gt;443&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the core configuration for &lt;code&gt;rdomain 1&lt;/code&gt; contains the rules filter the connections for the workers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;an explicit &lt;code&gt;block&lt;/code&gt; is redefined, so, by default, everything is blocked;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the private network is allowed to use SSH, HTTP and HTTPS in the workers' network;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the workers are allowed to use ICMP&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the workers are allowed to use SSH, HTTP and HTTPS;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;only worker nodes are allowed to use &lt;code&gt;bridge0&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;only worker nodes are allowed to use &lt;code&gt;wg0&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;workers nodes have the right to connect to the gateway via HTTP;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;all DNS queries are forwarded automatically to the VPN via the VPN gateway (&lt;code&gt;172.17.0.1&lt;/code&gt;);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NTP connections are locally forwarded to an instance of &lt;code&gt;ntpd&lt;/code&gt; running on the firewall.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="s2"&gt;"workers"&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;rdomain&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; {
  &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; (&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pflog1&lt;/span&gt;)

  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;tcp&lt;/span&gt; \
    &lt;span class="n"&gt;from&lt;/span&gt; ! $&lt;span class="n"&gt;worker_network&lt;/span&gt; \
    &lt;span class="n"&gt;to&lt;/span&gt; $&lt;span class="n"&gt;worker_network&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; {&lt;span class="m"&gt;22&lt;/span&gt;, &lt;span class="m"&gt;80&lt;/span&gt;, &lt;span class="m"&gt;443&lt;/span&gt;}

  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt;

  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;tcp&lt;/span&gt; \
    &lt;span class="n"&gt;from&lt;/span&gt; $&lt;span class="n"&gt;worker_network&lt;/span&gt; \
    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; {&lt;span class="m"&gt;22&lt;/span&gt;, &lt;span class="m"&gt;80&lt;/span&gt;, &lt;span class="m"&gt;443&lt;/span&gt;} \
    &lt;span class="n"&gt;keep&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;

  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;bridge0&lt;/span&gt; \
    &lt;span class="n"&gt;from&lt;/span&gt; $&lt;span class="n"&gt;worker_network&lt;/span&gt;

  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;wg0&lt;/span&gt; \
    &lt;span class="n"&gt;from&lt;/span&gt; $&lt;span class="n"&gt;worker_network&lt;/span&gt;

  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;tcp&lt;/span&gt; \
    &lt;span class="n"&gt;from&lt;/span&gt; $&lt;span class="n"&gt;worker_network&lt;/span&gt; \
    &lt;span class="n"&gt;to&lt;/span&gt; $&lt;span class="n"&gt;worker_gateway&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;

  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; {&lt;span class="n"&gt;tcp&lt;/span&gt;, &lt;span class="n"&gt;udp&lt;/span&gt;} \
    &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="m"&gt;172&lt;/span&gt;.&lt;span class="m"&gt;16&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;/&lt;span class="m"&gt;24&lt;/span&gt; \
    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="n"&gt;rdr&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;172&lt;/span&gt;.&lt;span class="m"&gt;17&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;

  &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;inet&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="n"&gt;udp&lt;/span&gt; \
    &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="m"&gt;172&lt;/span&gt;.&lt;span class="m"&gt;16&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;/&lt;span class="m"&gt;24&lt;/span&gt; \
    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="n"&gt;ntp&lt;/span&gt; \
    &lt;span class="n"&gt;rtable&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; \
    &lt;span class="n"&gt;rdr&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;127&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let fix the access rights on the files previously created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas &lt;span class="nb"&gt;chmod &lt;/span&gt;600 /etc/hostname.&lt;span class="k"&gt;*&lt;/span&gt; /etc/pf.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The network can be started or restarted. If other interfaces are configured, it is also possible to start them one by one or by giving a list of them as parameters for the &lt;code&gt;netstart&lt;/code&gt; script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas sh /etc/netstart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything looks good... Packet filter can be restarted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas pfctl &lt;span class="nt"&gt;-nf&lt;/span&gt; /etc/pf.conf
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas pfctl &lt;span class="nt"&gt;-f&lt;/span&gt; /etc/pf.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The firewall should now be connected to the server using wireguard. Let check that with a simple ping to &lt;code&gt;openbsd.org&lt;/code&gt;. Unfortunately, because &lt;code&gt;lo1&lt;/code&gt; has been created and set with &lt;code&gt;127.0.0.1&lt;/code&gt;, it is not possible to resolve a domain name locally on this firewall, but, it is still possible to use any other ip addresses. Indeed, a redirection is done on the VPN side, and any connections to DNS are forwarded on a local &lt;code&gt;unbound&lt;/code&gt; instance. Let's try that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT1&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;dig @1.2.3.4 google.fr +short
&lt;span class="go"&gt;142.251.142.195

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT1&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;ping &lt;span class="nt"&gt;-c3&lt;/span&gt; 142.251.142.195
&lt;span class="go"&gt;PING 142.251.142.195 (142.251.142.195): 56 data bytes
64 bytes from 142.251.142.195: icmp_seq=0 ttl=118 time=24.746 ms
64 bytes from 142.251.142.195: icmp_seq=1 ttl=118 time=25.723 ms
64 bytes from 142.251.142.195: icmp_seq=2 ttl=118 time=25.193 ms

--- 142.251.142.195 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 24.746/25.221/25.723/0.399 ms

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT1&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;nc &lt;span class="nt"&gt;-zv&lt;/span&gt; 142.251.142.195 80
&lt;span class="go"&gt;Connection to 142.251.142.195 80 port [tcp/www] succeeded!

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;route &lt;span class="nt"&gt;-nT1&lt;/span&gt; &lt;span class="nb"&gt;exec &lt;/span&gt;nc &lt;span class="nt"&gt;-zv&lt;/span&gt; 142.251.142.195 443
&lt;span class="go"&gt;Connection to 142.251.142.195 443 port [tcp/https] succeeded!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It seems the firewall is correctly using the VPN and the packets are correctly routed to some public IP addresses. To be sure, one can also use &lt;code&gt;tcpdump&lt;/code&gt; to see what's happening on &lt;code&gt;wg0&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tcpdump &lt;span class="nt"&gt;-ni&lt;/span&gt; wg0
&lt;span class="go"&gt;tcpdump: listening on wg0, link-type LOOP
&lt;/span&gt;&lt;span class="gp"&gt;14:51:40.154762 172.17.0.2.31538 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;142.251.142.195.443: SWE 4156193580:4156193580&lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt; win 16384 &amp;lt;mss 1452,nop,nop,sackOK,nop,wscale 6,nop,nop,timestamp 2865047363 0&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;DF&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;14:51:40.180844 142.251.142.195.443 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;172.17.0.2.31538: S 1448631416:1448631416&lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt; ack 4156193581 win 65535 &amp;lt;mss 1412,sackOK,timestamp 728224899 2865047363,nop,wscale 8&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;DF&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;tos 0x80]
&lt;span class="gp"&gt;14:51:40.180995 172.17.0.2.31538 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;142.251.142.195.443: &lt;span class="nb"&gt;.&lt;/span&gt; ack 1 win 256 &amp;lt;nop,nop,timestamp 2865047383 728224899&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;DF&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;14:51:40.182406 172.17.0.2.31538 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;142.251.142.195.443: F 1:1&lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt; ack 1 win 256 &amp;lt;nop,nop,timestamp 2865047383 728224899&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;DF&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;14:51:40.206851 142.251.142.195.443 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;172.17.0.2.31538: F 1:1&lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt; ack 2 win 1050 &amp;lt;nop,nop,timestamp 728224925 2865047383&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;tos 0x80]
&lt;span class="gp"&gt;14:51:40.207024 172.17.0.2.31538 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;142.251.142.195.443: &lt;span class="nb"&gt;.&lt;/span&gt; ack 2 win 256 &amp;lt;nop,nop,timestamp 2865047413 728224925&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;DF&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;14:51:40.987301 172.16.0.2.48148 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;172.65.251.78.443: &lt;span class="nb"&gt;.&lt;/span&gt; ack 2499027552 win 78 &amp;lt;nop,nop,timestamp 674758452 2705939126&amp;gt;
&lt;span class="gp"&gt;14:51:41.013134 172.65.251.78.443 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;172.16.0.2.48148: &lt;span class="nb"&gt;.&lt;/span&gt; ack 1 win 19 &amp;lt;nop,nop,timestamp 2705969587 674743439&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;DF&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;14:51:41.333030 172.65.251.78.443 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;172.16.0.2.48148: &lt;span class="nb"&gt;.&lt;/span&gt; ack 1 win 19 &amp;lt;nop,nop,timestamp 2705969908 674743439&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;DF&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;14:51:41.334165 172.16.0.2.48148 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;172.65.251.78.443: &lt;span class="nb"&gt;.&lt;/span&gt; ack 1 win 78 &amp;lt;nop,nop,timestamp 674758799 2705969587&amp;gt;
&lt;span class="gp"&gt;14:51:42.840018 172.65.251.78.443 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;172.16.0.3.40668: &lt;span class="nb"&gt;.&lt;/span&gt; ack 1758166881 win 16 &amp;lt;nop,nop,timestamp 2453064192 1968171036&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;DF&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;14:51:42.840607 172.16.0.3.40668 &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;172.65.251.78.443: &lt;span class="nb"&gt;.&lt;/span&gt; ack 1 win 78 &amp;lt;nop,nop,timestamp 1968186512 2453048737&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is now confirmed, the traffic is going into the VPN!&lt;/p&gt;

&lt;h1&gt;
  
  
  Workers Configuration
&lt;/h1&gt;

&lt;p&gt;The last part of this infrastructure is directly related to the "workers". Those workers will host gitlab-runners and probably other services like &lt;code&gt;podman&lt;/code&gt; or even &lt;code&gt;k3s&lt;/code&gt; to build, test and release my own private application locally. Those servers are old laptops, and other small devices connected in their dedicated switch, behind the firewall. Most of them will use Alpine Linux. So, first, the network configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/network/interfaces &amp;lt; EOF
&lt;span class="go"&gt;auto lo
iface lo inet loopback

auto eth0
        address 172.16.0.2/24
        network 172.16.0.0
        broadcast 172.16.0.255
        gateway 172.16.0.1
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To apply the configuration, simple invoke the &lt;code&gt;service&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas service networking restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the &lt;code&gt;dnsmasq&lt;/code&gt; configuration, in the previous article, it was used to worked the domain name requests to the Tor DNS service. In this case, it will be used to forward the requests to the gateway, then the gateway will forward them to the VPN.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/dnsmasq.conf &amp;lt; EOF
&lt;span class="go"&gt;no-resolv
server=172.16.0.1
local-service
listen-address=127.0.0.1
conf-dir=/etc/dnsmasq.d/,*.conf
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be sure &lt;code&gt;dnsmasq&lt;/code&gt; is started during boot and start the service if it's not already done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas rc-update add dnsmasq default
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas service dnsmasq start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure &lt;code&gt;/etc/resolv.conf&lt;/code&gt; is correctly configured to ask &lt;code&gt;dnsmasq&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/resolv.conf &amp;lt; EOF
&lt;span class="go"&gt;nameserver 127.0.0.1
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voilà. A worker is configured! The idea was to have something really simple on this side to deploy many workers when needed. The &lt;code&gt;dnsmasq&lt;/code&gt; is a bonus, because simply configuring the &lt;code&gt;/etc/resolv.conf&lt;/code&gt; would have been way enough.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing
&lt;/h1&gt;

&lt;p&gt;One of the most important section of this article... Testing the configuration from the workers point of view. First, the DNS resolution is mandatory and must work. Checked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;dig +short openbsd.org
&lt;span class="go"&gt;199.185.178.80
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All packets must be forwarded through the VPN and not locally. As one can see, the packets are passing to the gateway, then, to the VPN and go out from the server (the IP addresse(s) have been replaced by &lt;code&gt;x.x.x.x&lt;/code&gt;). Checked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;traceroute openbsd.org &lt;span class="nt"&gt;-nI&lt;/span&gt;
&lt;span class="go"&gt;traceroute to openbsd.org (199.185.178.80), 30 hops max, 46 byte packets
 1  172.16.0.1  0.591 ms  0.179 ms  0.434 ms
 2  172.17.0.1  24.231 ms  25.197 ms  24.946 ms
 3  x.x.x.x  25.732 ms  26.328 ms  28.007 ms
 4  x.x.x.y  24.522 ms  26.557 ms  25.837 ms
 5  x.x.y.z  25.012 ms  24.913 ms  25.359 ms
 6  80.249.213.240  26.202 ms  26.065 ms  31.208 ms
 7  64.125.20.28  145.869 ms  *  146.492 ms
 8  64.125.29.184  145.833 ms  145.111 ms  146.056 ms
 9  *  64.125.31.110  146.041 ms  *
10  *  *  *
11  *  *  *
12  64.125.30.199  147.083 ms  145.227 ms  145.968 ms
13  64.125.31.158  145.922 ms  146.089 ms  146.342 ms
14  64.125.18.179  145.466 ms  145.984 ms  145.082 ms
15  64.125.18.180  148.951 ms  147.816 ms  146.111 ms
16  64.125.18.210  145.243 ms  146.458 ms  146.015 ms
17  208.185.75.98  146.226 ms  146.872 ms  146.485 ms
18  204.209.252.4  146.952 ms  148.495 ms  147.707 ms
19  199.185.230.2  147.111 ms  147.041 ms  147.363 ms
20  199.185.178.80  145.313 ms  144.660 ms  145.852 m
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTTP connections should work. It can be verified with &lt;code&gt;nc&lt;/code&gt;. Checked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nc &lt;span class="nt"&gt;-zv&lt;/span&gt; openbsd.org 80
&lt;span class="go"&gt;Connection to openbsd.org (199.185.178.80) 80 port [tcp/http] succeeded!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTTPS connections must work. This one is important because some repository will be cloned using HTTPS. Checked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nc &lt;span class="nt"&gt;-zv&lt;/span&gt; openbsd.org 443
&lt;span class="go"&gt;Connection to openbsd.org (199.185.178.80) 443 port [tcp/https] succeeded!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another important service to check is SSH. Most of the repositories are using Git over SSH, usually listening on port TCP/22 by default. The workers must have access to that as well. Checked!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nc &lt;span class="nt"&gt;-zv&lt;/span&gt; ftp.eu.openbsd.org 22
&lt;span class="go"&gt;Connection to ftp.eu.openbsd.org (193.156.13.178) 22 port [tcp/ssh] succeeded!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let check if Alpine Linux can be updated and upgraded... Checked!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas apk update
&lt;span class="go"&gt;v3.23.7-30-g7a9ffafb21a [https://mirror.leaseweb.com/alpine/v3.23/main]
v3.23.7-29-gecf474a05c5 [https://mirror.leaseweb.com/alpine/v3.23/community]
OK: 27586 distinct packages available

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas apk upgrade
&lt;span class="go"&gt;OK: 1146.9 MiB in 302 packages
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My own local workers/builders infrastructure is now running behind a firewall and a VPN. The IP address seen by gitlab is not the one from my place, but from another server.&lt;/p&gt;

&lt;h1&gt;
  
  
  Troubleshooting and Improvements
&lt;/h1&gt;

&lt;p&gt;Managing &lt;code&gt;rdomain&lt;/code&gt; can become very complex, and one must be disciplined to manage packet-filter rules but also the pseudo devices created. &lt;code&gt;tcpdump&lt;/code&gt; will be the best tool to investigate a routing issue and will quickly give an idea of the root cause. &lt;code&gt;route&lt;/code&gt; and &lt;code&gt;netstat&lt;/code&gt; commands will also be really useful to inspect the state of the network stack. Finally, creating &lt;code&gt;pflog&lt;/code&gt; interfaces to log and follow the packet flow will also be of a great help.&lt;/p&gt;

&lt;p&gt;Another point to improve in this design is about trusting the traffic. The workers will use gitlab-runners, and based on the news, supply-chain attacks or 0days are kinda dangerous. The previous configuration using Tor was interesting because a proxy was required. In the current situation an HTTP proxy would have been a good idea to deploy, to filter and log all outgoing connections. A bastion for ssh (or an ssh proxy) would have been great as well. Indeed, to avoid an attack, restricting the access to a small subset of allowed IP addresses or domains is the bare minimum.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Coming back to my roots was pretty great. Configuring VPN, routes and other kind of network stuff on OpenBSD is always a fun experience. &lt;code&gt;rdomain&lt;/code&gt; is a furtive technology mostly known by some OpenBSD wizards and other hardcore system/network administrators. The number of publications on this topic is pretty low, but the OpenBSD documentation is here to save our life.&lt;/p&gt;

&lt;p&gt;Anyway, &lt;code&gt;rdomain&lt;/code&gt; is a great tool to isolate networks and avoid leaks. Configuring it correctly can be challenging though, and testing it is also another layer of complexity, but the result is - as usual with OpenBSD - rock solid. This article is already huge, and having a list of resources/references can also probably help you to deal with all of that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/rdomain.4" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;rdomain(4)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; man page, explaining how &lt;code&gt;rdomain&lt;/code&gt; is working with few examples;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/pfctl" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;pfctl(8)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; command man page, where you will find how to use &lt;code&gt;pfctl&lt;/code&gt;, mainly to reload the firewall rules;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/pf.conf" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;pf.conf(5)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; configuration page man page, where you will find more about &lt;code&gt;rdomain&lt;/code&gt; and &lt;code&gt;rtable&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/route" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;route(8)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; command mange page, where you will learn how to use the &lt;code&gt;route&lt;/code&gt; command to switch between &lt;code&gt;rdomain&lt;/code&gt;s;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/netstart" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;netstart(8)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; script man page, to restart/reload interfaces;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/hostname.if" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;hostname.if(5)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; configuration file man page, where the configuration of the interfaces will be stored;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/wg" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;wg(4)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; pseudo device man page, where you will find more information about how to create, configure and maintain a wireguard interface;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/pair" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;pair(4)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; pseudo device man page, where you will understand how to use &lt;code&gt;pair&lt;/code&gt; to connect different &lt;code&gt;rdomain&lt;/code&gt; together;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/vether.4" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;vether(4)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; pseudo device man page, where you will learn how to use the virtual ethernet interface;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/bridge.4" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;bridge(4)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; pseudo device man page, useful to link many interfaces together;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/ifconfig" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;ifconfig(8)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; command man page, to deal with the pseudo devices and network interfaces;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://man.openbsd.org/pflog" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;pflog(4)&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; pseudo interface man page to see what kind of data one can collect and how to use it with &lt;a href="https://man.openbsd.org/tcpdump" rel="noopener noreferrer"&gt;&lt;code&gt;tcpdump&lt;/code&gt;&lt;/a&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://indico.bsdcan.org/event/1/contributions/31/attachments/7/7/wg.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Implementing Routing Domains on an OpenBSD workstation for use with WireGuard&lt;/strong&gt;&lt;/a&gt; talk presented in 2024, with the recording available on &lt;a href="https://www.youtube.com/watch?v=ipbPcNXeDj4&amp;amp;pp=ygVNSW1wbGVtZW50aW5nIFJvdXRpbmcgRG9tYWlucyBvbiBhbiBPcGVuQlNEIHdvcmtzdGF0aW9uIGZvciB1c2Ugd2l0aCBXaXJlR3VhcmQ%3D" rel="noopener noreferrer"&gt;youtube&lt;/a&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://thelongcon.ca/slides/2024/Robert%20Keizer%20-%20Introduction%20to%20global%20anycast%20using%20OpenBSD%20(on%20a%20budget)%20-%20The%20Long%20Con%202024.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Introduction to global anycast using OpenBSD (on a budget)&lt;/strong&gt;&lt;/a&gt; live streaming talk presented in 2024, with the recording available on &lt;a href="https://www.youtube.com/watch?v=JpxpjzUfQpg&amp;amp;pp=ygU6SW50cm9kdWN0aW9uIHRvIGdsb2JhbCBhbnljYXN0IHVzaW5nIE9wZW5CU0QgKG9uIGEgYnVkZ2V0KQ%3D%3D" rel="noopener noreferrer"&gt;youtube&lt;/a&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.openbsd.org/papers/eurobsdcon2023-matthieu-pf-rdomain.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Practical use of OpenBSD routing domains with redundant&lt;br&gt;
firewalls&lt;/strong&gt;&lt;/a&gt; talk presented in 2023, with the recorded session available on &lt;a href="https://www.youtube.com/watch?v=c81bS9u1A6Q&amp;amp;pp=ygVBUHJhY3RpY2FsIHVzZSBvZiBPcGVuQlNEIHJvdXRpbmcgZG9tYWlucyB3aXRoIHJlZHVuZGFudCBmaXJld2FsbHM%3D" rel="noopener noreferrer"&gt;youtube&lt;/a&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.openbsd.org/papers/jres2021-matthieu-tuto-pf.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Installation de pare-feux redondants avec OpenBSD&lt;/strong&gt;&lt;/a&gt; talk slides presented in 2021 (but in French);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.openbsd.org/papers/asiabsdcon2018-mininet-slides.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Mininet on OpenBSD Using rdomains for Interactive SDN Testing and Development&lt;/strong&gt;&lt;/a&gt; talk presented in 2018, with the &lt;a href="https://www.youtube.com/watch?v=Vg9Czjm9aV8&amp;amp;pp=ygVNTWluaW5ldCBvbiBPcGVuQlNEIFVzaW5nIHJkb21haW5zIGZvciBJbnRlcmFjdGl2ZSBTRE4gVGVzdGluZyBhbmQgRGV2ZWxvcG1lbnTSBwkJMgwBhyohjO8%3D" rel="noopener noreferrer"&gt;youtube video&lt;/a&gt; and its &lt;a href="https://www.openbsd.org/papers/asiabsdcon2018-mininet-paper.pdf" rel="noopener noreferrer"&gt;paper&lt;/a&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.bsdcan.org/2017/schedule/attachments/415_bsdcan2017-talk.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;pf+rdomains create splendid multi-tenancy firewalls&lt;/strong&gt;&lt;/a&gt; talk presented in 2017, with the &lt;a href="https://www.youtube.com/watch?v=5Cni50vnlto&amp;amp;pp=ygUzcGYrcmRvbWFpbnMgY3JlYXRlIHNwbGVuZGlkIG11bHRpLXRlbmFuY3kgZmlyZXdhbGxz0gcJCTIMAYcqIYzv" rel="noopener noreferrer"&gt;youtube video&lt;/a&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://undeadly.org/features/2018/02/eurobsdcon2017-branch-vpn.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Branch VPN Solution with OpenBSD&lt;/strong&gt;&lt;/a&gt; talk slides presented in 2017;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.openbsd.org/papers/bsdcan2015-rdomains.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;using routing domains/routing tables in a production network&lt;/strong&gt;&lt;/a&gt; talk slides presented in 2015;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.unfriendlygrinch.info/posts/openbsd-routing-tables-and-routing-domains/" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenBSD Routing Tables and Routing Domains&lt;/strong&gt;&lt;/a&gt; by the Unfriendly Grinch, offering a great &lt;code&gt;rdomain&lt;/code&gt; usage example;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://insec.sh/secure-torrenting-with-openbsd-rdomains/" rel="noopener noreferrer"&gt;&lt;strong&gt;Secure torrenting with OpenBSD rdomains&lt;/strong&gt;&lt;/a&gt;, a post showing us how to isolate/secure torrenting using &lt;code&gt;rdomain&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dataswamp.org/~solene/2021-12-16-openbsd-openvpn-exit.html" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenVPN on OpenBSD in its own rdomain to prevent data leak&lt;/strong&gt;&lt;/a&gt;, another post where &lt;code&gt;rdomain&lt;/code&gt; is used with OpenVPN;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dataswamp.org/~solene/2021-10-09-openbsd-wireguard-exit.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Full WireGuard setup with OpenBSD&lt;/strong&gt;&lt;/a&gt;, probably one of the first post available on the web about wireguard and &lt;code&gt;rdomain&lt;/code&gt; on OpenBSD;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serverfault.com/questions/821306/configuring-pf-to-route-between-routing-domains" rel="noopener noreferrer"&gt;&lt;strong&gt;Configuring PF to route between routing domains&lt;/strong&gt;&lt;/a&gt; on ServerFault;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.linuxquestions.org/questions/%2Absd-17/openbsd-pf-rdr-to-across-rdomains-4175657966/" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenBSD PF rdr-to across rdomains&lt;/strong&gt;&lt;/a&gt; on Linux Questions;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy hacking and have fun!&lt;/p&gt;

&lt;p&gt;EDIT(20261103): adding a missing route in &lt;code&gt;/etc/hostname.wg0&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;Cover Image by &lt;a href="https://unsplash.com/@rafaelpeier?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Rafael Peier&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-dead-pufferfish-lies-on-the-sandy-beach-FoVu-YEHj2Y?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>openbsd</category>
      <category>network</category>
      <category>security</category>
      <category>systems</category>
    </item>
    <item>
      <title>WeeklyReview#202644</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Mon, 02 Nov 2026 10:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/weeklyreview202644-2d6o</link>
      <guid>https://dev.to/niamtokik/weeklyreview202644-2d6o</guid>
      <description>&lt;p&gt;This week was mostly dedicated to clean up and fix my CI/CD local infrastructure. The first version of this one was undocumented and using Tor as relay to hide my private IP address. Unfortunately, most of the tor exit nodes were blocked by Google, and following the recent news regarding the 333 rogue exit nodes, forwarding this traffic through my own servers is probably a better idea. Both configuration have been configured - even if it's not yet finished but it works.&lt;/p&gt;

&lt;p&gt;In the end, it was great to do some old-school sysadmin/netadmin tasks on OpenBSD. This system is still my favorite after all these years. Yes, it is not fast as a Linux-like distribution, it does not have all fancy hardware support from other operating system, but damn... In few hours, one is able to deploy a crazy stable and secure infrastructure.&lt;/p&gt;




&lt;p&gt;On my Dart/Flutter application side, the database management was - and still is - a problem. &lt;code&gt;sqflite&lt;/code&gt; and other interface to it are unpleasant to use. One of my target is to use &lt;code&gt;ribs_sqlite&lt;/code&gt; over &lt;code&gt;sqlite&lt;/code&gt; or &lt;code&gt;sqflite&lt;/code&gt;, but designing it this way requires to change some of my first design.&lt;/p&gt;

&lt;p&gt;Another thing, the front-end part was my main target because it was my weak point. By doing that, a big part of my time was dedicated to learn more about UI/UX and mobile design. A post is planned to be released - one day - on that.&lt;/p&gt;




&lt;h1&gt;
  
  
  Coding
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/mbrock/filnix/tree/main/nanofil" rel="noopener noreferrer"&gt;&lt;strong&gt;nanofil&lt;/strong&gt;&lt;/a&gt;: A C compiler written in Prolog that emits x86-64 assembly in the Fil-C ABI. Its object files link with clang-built Fil-C code, and they keep Fil-C's guarantees&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://learnerlang.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Learn Erlang Step-By-Step&lt;/strong&gt;&lt;/a&gt;: a new initiative to learn Erlang based on a real-world project! I like the concept and how it has been done.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.benjoffe.com/fast-floordiv" rel="noopener noreferrer"&gt;&lt;strong&gt;A faster way to compute signed 64-bit floor division by constants&lt;/strong&gt;&lt;/a&gt;: a way to optimize floor division when the divisor is known during compile time.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://tartanllama.xyz/posts/writing-a-linux-debugger/setup/" rel="noopener noreferrer"&gt;&lt;strong&gt;Writing a Linux Debugger Part 1: Setup&lt;/strong&gt;&lt;/a&gt;: a serie of article on developing its own linux debugger in C++.&lt;/p&gt;

&lt;h1&gt;
  
  
  System
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/henrygd/beszel" rel="noopener noreferrer"&gt;&lt;strong&gt;Beszel&lt;/strong&gt;&lt;/a&gt;: a lightweight server monitoring platform that includes Docker statistics, historical data, and alert functions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Database
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/darold/pgcluu" rel="noopener noreferrer"&gt;&lt;strong&gt;pgCluu&lt;/strong&gt;&lt;/a&gt;:  a Perl program used to perform a full audit of a PostgreSQL Cluster and System performance.&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://safegrd.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;SafeGrd&lt;/strong&gt;&lt;/a&gt;: SafeGrd backs up your databases, files and mail, encrypts and locks each copy, and restores it on a schedule to prove it works. An agent with your production keys can drop the database, but not the backups.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/Muzzammil242/pgrecon" rel="noopener noreferrer"&gt;&lt;strong&gt;pgrecon&lt;/strong&gt;&lt;/a&gt;: an open-source Oracle to PostgreSQL migration assessment and schema conversion tool. It inventories an Oracle database from an offline dump and runs a deterministic rule engine over it.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://postgresql-anonymizer.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;&lt;strong&gt;PostgreSQL Anonymizer&lt;/strong&gt;&lt;/a&gt;: an extension to mask or replace personally identifiable information (PII) or commercially sensitive data from a Postgres database.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/nalgeon/sqlean" rel="noopener noreferrer"&gt;&lt;strong&gt;sqlean&lt;/strong&gt;&lt;/a&gt;: There are a lot of SQLite extensions out there, but they are incomplete, inconsistent and scattered across the internet. Sqlean brings them together, neatly packaged into domain modules, documented, tested, and built for Linux, Windows and macOS.&lt;/p&gt;

&lt;h1&gt;
  
  
  Security
&lt;/h1&gt;

&lt;p&gt;🌐 &lt;a href="https://tailworm.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Tailworm, we have zero-trust in our infrastructure&lt;/strong&gt;&lt;/a&gt;: a report audit of the tailscale project, containing a lot of security issues.&lt;/p&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/KeystoneWallet/status/2114719318722404578" rel="noopener noreferrer"&gt;&lt;strong&gt;Keystone: Statement Regarding the Security Incident on Our Official Website and Customer Guidance&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://satcom.sysnet.ucsd.edu/docs/dontlookup_ccs25_fullpaper.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Don’t Look Up: There Are Sensitive Internal Links in the Clear on&lt;br&gt;
GEO Satellites&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://projectzero.google/2026/10/fuzzing-v-AI.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Fuzzers vs. AI: Comparing Fuzzilli and BigSleep on JavaScript Engines&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://tpbreak.afflicted.sh/" rel="noopener noreferrer"&gt;&lt;strong&gt;tpbreak&lt;/strong&gt;&lt;/a&gt;: TP-Link firmware decryption at scale — 52,609 images. The verification public key is also the decryption key: the AES key/IV fall out of the RSA-PSS salt. No private key required.&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://smsofdeath.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;SMS of Death&lt;/strong&gt;&lt;/a&gt;: an unchecked cast on an array can cause a denial of service for a long period of time on Android. It can lead to SQLite database corruption and also impact the phone to boot. It can brick the phone. If I understand correctly, it will not be fixed... Crazy.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://alpinelinux.org/posts/GitLab-security-incident-CVE-2026-97229.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Alpine Linux GitLab security incident: attempted exploitation of CVE-2026-97229&lt;/strong&gt;&lt;/a&gt;: a gitlab upgrade where the main fix was not applied because of Ruby. It confirms me Alpine Linux team is great, instead of ignoring this attack, they are redeploying/rebuilding everything. Great project.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.rtl-sdr.com/specter-leaking-data-from-air-gapped-computers-by-toggling-usb-power-states/" rel="noopener noreferrer"&gt;&lt;strong&gt;SPECTER: Leaking Data from Air-Gapped Computers by Toggling USB Power States&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.rtl-sdr.com/thermal-noise-communication-sending-data-without-a-carrier-signal-with-an-rtl-sdr-as-the-receiver/" rel="noopener noreferrer"&gt;&lt;strong&gt;Thermal Noise Communication: Sending Data Without a Carrier Signal, with an RTL-SDR as the Receiver&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://thehackernews.com/2026/10/official-claude-code-vs-code-extension.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Official Claude Code VS Code Extension Compromised to Install Persistent SSH Backdoor&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://freenode.net/article/when-intermediate-cas-fail-language-stacks-discover-they-own-the-blast-radius" rel="noopener noreferrer"&gt;&lt;strong&gt;When intermediate CAs fail, language stacks discover they own the blast radius&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://raelize.com/upload/research/2016/2016_BlackHat-EU_Bypassing-Secure-Boot-Using-Fault-Injection_NT-AS.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Bypassing Secure Boot using Fault Injection&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Security/cryptography
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://v12.sh/blog/the-case-of-the-9bit-aes-key" rel="noopener noreferrer"&gt;&lt;strong&gt;The case of the 9 bit AES key&lt;/strong&gt;&lt;/a&gt;: encrypt your document yourself... PDF encryption from open-source world is just broken. The keys/seeds are not coming from cryptographic random sources, then, it is easy to break.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://blog.silentsignal.eu/2026/10/29/qsyrupwd-part-2-correcting-the-rijndael-key-builder/" rel="noopener noreferrer"&gt;&lt;strong&gt;QSYRUPWD, Part 2: Correcting the Rijndael Key Builder&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://hoseinhadipour.com/blog/lean-for-cryptanalysts/" rel="noopener noreferrer"&gt;&lt;strong&gt;Lean for Cryptanalysts: A Practical Introduction to Formal Proofs&lt;/strong&gt;&lt;/a&gt;: a lot of people are talking about the &lt;a href="https://lean-lang.org/functional_programming_in_lean/" rel="noopener noreferrer"&gt;lean language&lt;/a&gt;, it is on my long list of thing to learn. When someone is writing a post about Lean and cryptanalysis, for sure it will be a banger. So, this is a great example of lean usage, and it motives me even more to learn/use it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Security/RedTeam
&lt;/h1&gt;

&lt;p&gt;🌐 &lt;a href="https://sploitus.com/exploit?id=D743A147-AC04-558E-AC44-A86A48AABB08" rel="noopener noreferrer"&gt;&lt;strong&gt;Exploit for php2shell-audit&lt;/strong&gt;&lt;/a&gt;: a "working" (yet non-tested on my side) exploit against php2-shell.&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://sploitus.com/exploit?id=2EF3AE90-EF42-5F24-AA67-C762AC236FE3" rel="noopener noreferrer"&gt;&lt;strong&gt;Exploit for CVE-2026-111497 (brotli)&lt;/strong&gt;&lt;/a&gt;: a "working" (yet non-tested on my side) exploit on nodejs brotli vulnerability.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.praetorian.com/blog/ble-testing-caeruleus/" rel="noopener noreferrer"&gt;&lt;strong&gt;Bluetooth Low Energy Security Testing, Consolidated: Introducing Caeruleus&lt;/strong&gt;&lt;/a&gt;: Bluetooth fascinate me since High School, at this time, I unsuccessfully tried to create an audio/video streaming application on Nokia SymbianOS in C++. It was fun, and bluetooth is a really interesting piece of technology. Having a list of tools to identify and attack this protocol is always useful, especially if you are developing Bluetooth application.&lt;/p&gt;

&lt;h1&gt;
  
  
  Embedded
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://www.digikey.com/reference-designs/en" rel="noopener noreferrer"&gt;&lt;strong&gt;Digikey Reference Design Library&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Update/Upgrade
&lt;/h1&gt;

&lt;p&gt;🔄 &lt;a href="https://undeadly.org/cgi?action=article;sid=20261025115016" rel="noopener noreferrer"&gt;&lt;strong&gt;LibreSSL 4.4.0&lt;/strong&gt;&lt;/a&gt;: including eMudhra security fix.&lt;/p&gt;

&lt;p&gt;🔄 &lt;a href="https://github.com/seL4/seL4/releases/tag/17.0.0" rel="noopener noreferrer"&gt;&lt;strong&gt;Sel4 17.0.0&lt;/strong&gt;&lt;/a&gt;:  many bug and security fixes. Documentation was also improved. Few platforms have been removed (Arndale, Odroid-X, HiKey, Inforce IFC6410, exynos5). The &lt;a href="https://github.com/seL4/seL4" rel="noopener noreferrer"&gt;full changelog&lt;/a&gt; is available on Github.&lt;/p&gt;

&lt;p&gt;🔄 &lt;a href="https://github.com/elixir-lang/elixir/releases/tag/v1.20.5" rel="noopener noreferrer"&gt;&lt;strong&gt;Elixir 1.20.5&lt;/strong&gt;&lt;/a&gt;: Security and bugs fixes release, including 2 CVEs.&lt;/p&gt;

&lt;p&gt;🔄 &lt;a href="https://github.com/flutter/flutter/releases/tag/3.47.9" rel="noopener noreferrer"&gt;&lt;strong&gt;Flutter 3.47.9&lt;/strong&gt;&lt;/a&gt;: bugs fixes release.&lt;/p&gt;

&lt;h1&gt;
  
  
  Theory
&lt;/h1&gt;

&lt;p&gt;📑 &lt;a href="https://www.nature.com/articles/s41562-025-02387-z" rel="noopener noreferrer"&gt;&lt;strong&gt;Evidence for the representation of non-hierarchical structures in language&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Leaks of the Week
&lt;/h1&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/ZeroDayFacts/status/2115770189426106414" rel="noopener noreferrer"&gt;&lt;strong&gt;Sony&lt;/strong&gt;&lt;/a&gt;: more than 2.5 millions customers leaked, including sensitive information like mails and phone number.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/alertes/solnet-suisse-piratage-fuite-donnees-clients-telecom-mvwjqg7ow72iqngt8te" rel="noopener noreferrer"&gt;&lt;strong&gt;Solnet&lt;/strong&gt;&lt;/a&gt;: Switzerland network provider impacted by a data leak impacting more than 5000 customers.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/blog/rassemblement-national-un-pirate-revendique-les-donnees-de-150-000-adherents" rel="noopener noreferrer"&gt;&lt;strong&gt;Rassemblement National&lt;/strong&gt;&lt;/a&gt;: more than 432000 subscribers data leaked from this French political party.&lt;/p&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/DarkWebInformer/status/2116301692476026953" rel="noopener noreferrer"&gt;&lt;strong&gt;iCloudITS&lt;/strong&gt;&lt;/a&gt;: Saudi IT Provider leaked more than 15GB of data from their database.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://darkwebinformer.com/bangkok-post-breach-claim-includes-822-140-member-accounts-and-6-9-gb-infrastructure-dump/" rel="noopener noreferrer"&gt;&lt;strong&gt;Bangkok Post&lt;/strong&gt;&lt;/a&gt;: more than 820000 members impacted by a data leak &lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/blog/francs-macons-le-grand-orient-de-france-vise-par-une-cyberattaque-67-go-de-donnees-revendiques" rel="noopener noreferrer"&gt;&lt;strong&gt;Grand Orient de France&lt;/strong&gt;&lt;/a&gt;: 6.72GB of data leaked from one of the main French freemasonry. &lt;/p&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/DarkWebInformer/status/2115459185852731693" rel="noopener noreferrer"&gt;&lt;strong&gt;French Unknown IT Company&lt;/strong&gt;&lt;/a&gt;: if true, an IT company was impacted by a huge data leaks, including their private keys API for Stripe and Vercel.&lt;/p&gt;

&lt;h1&gt;
  
  
  Misc
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://polymarket.com/event/anthropic-announces-bankruptcy-by" rel="noopener noreferrer"&gt;&lt;strong&gt;Anthropic announces bankruptcy by...?&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www-cdn.anthropic.com/519c17a5d23a794e8b6d50a854048d0b61e0d73a.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Who’s Aligned to Whom? How AI Agents Shape Experts’ Research Judgment Calls&lt;/strong&gt;&lt;/a&gt;: The conclusion contains all you need to know.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;experts may defer underdetermined decisions to an AI agent, and that this deferral can be hard to identify, even for the experts themselves [...] Judgment also depends on skill, and people who stop making these decisions may lose the ability to make them [...] institutions will need an explicit strategy for developing human skills as models become more capable [...] Institutions may want to protect these skills and human oversight even with extremely capable AI, for safety, resilience, or their own sake.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;📝 &lt;a href="https://gist.github.com/flamerix-ai/c3905705cc4205e5de3011fa2e74efce" rel="noopener noreferrer"&gt;&lt;strong&gt;Claude Code burns ~15–20% of your tokens on a 3-word status line. Here's how to turn it off&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="//www.404media.co/manifestos-fear-and-loser-thinking-inside-protons-ai-reckoning/"&gt;&lt;strong&gt;Manifestos, Fear, and ‘Loser Thinking’: Inside Proton’s AI Reckoning&lt;/strong&gt;&lt;/a&gt;: What a great leader and innovator... Calling his engineers and technicians loser is really an incredible act. So, time to move to another solution. By the way, tutanota is perhaps not a &lt;a href="https://x.com/CryptoCyberia/status/2019062136400474366" rel="noopener noreferrer"&gt;good alternative&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://x.com/devXritesh/status/2115783759672865194" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fge5aei91v3v0xin6oqha.png" alt=" " width="598" height="642"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/msimoni/status/2114088887366586517?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1ylyt6y2pfic2zyff0tt.png" alt=" " width="598" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/gf_256/status/2114051242817380507?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fug6qwf0t37x8qi4kwpn7.png" alt=" " width="598" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/teej_dv/status/2114423896955118015?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu78bj0jacdfwa0qflc9i.png" alt=" " width="598" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/BadlyLiquidated/status/2115928489413214629" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpw7xmadyj4ny098bz84b.png" alt=" " width="598" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Polymarket/status/2115911339587850419" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpy7ddiae93n15oxs61bs.png" alt=" " width="598" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/codytrades/status/2116072067061915684" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq50d4knuy4c0ioe91mh3.png" alt=" " width="598" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/gaborgurbacs/status/2116195564127715664" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F083a4pz8m0h283v77ncd.png" alt=" " width="598" height="218"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxfbo2b7wi58m7y48nck5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxfbo2b7wi58m7y48nck5.png" alt=" " width="680" height="677"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe3w6uy03ur1sbvwi3k0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe3w6uy03ur1sbvwi3k0w.png" alt=" " width="680" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4mjuuvqaysvu8n3cahbp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4mjuuvqaysvu8n3cahbp.png" alt=" " width="365" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnpxpd7xuub6my7p02lvi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnpxpd7xuub6my7p02lvi.png" alt=" " width="675" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcdw90jb2tryfl56fkfil.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcdw90jb2tryfl56fkfil.png" alt=" " width="500" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F21hcpym458qu6n4qy8p6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F21hcpym458qu6n4qy8p6.png" alt=" " width="640" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2b5ddbqkjsmbx09z24wl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2b5ddbqkjsmbx09z24wl.png" alt=" " width="549" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18325chhopv5ii0yepc4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18325chhopv5ii0yepc4.png" alt=" " width="680" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr8tsqpoz3kq03k6dzf5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr8tsqpoz3kq03k6dzf5e.png" alt=" " width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87viwoi9lav5dti1kf03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87viwoi9lav5dti1kf03.png" alt=" " width="660" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjh216v19mxdejar85pvi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjh216v19mxdejar85pvi.png" alt=" " width="680" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fecplj9xue4lsyrhbmx1i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fecplj9xue4lsyrhbmx1i.png" alt=" " width="618" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw5kt83wrorx117vu4onu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw5kt83wrorx117vu4onu.png" alt=" " width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F98lhpzqbi83kc52d4fyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F98lhpzqbi83kc52d4fyq.png" alt=" " width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhpyjq00hhc6grl8t0n1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhpyjq00hhc6grl8t0n1.png" alt=" " width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr4l28uko0l1fpmuhkzb6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr4l28uko0l1fpmuhkzb6.png" alt=" " width="800" height="901"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbl1qtduxf175yavnvvvt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbl1qtduxf175yavnvvvt.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Cover Image by &lt;a href="https://unsplash.com/@niki_emmert?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Nikolett Emmert&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-close-up-of-a-leaf-with-drops-of-water-on-it-4WhzY_EfSw8?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>weekly</category>
      <category>review</category>
    </item>
    <item>
      <title>devto is a really unstable platform to publish article. every weeks something is broken; today, I can't update one very long post... The PUT request got stuck on the server side. Crazy.</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Fri, 30 Oct 2026 15:52:19 +0000</pubDate>
      <link>https://dev.to/niamtokik/devto-is-a-really-unstable-platform-to-publish-article-every-weeks-something-is-broken-today-i-1l19</link>
      <guid>https://dev.to/niamtokik/devto-is-a-really-unstable-platform-to-publish-article-every-weeks-something-is-broken-today-i-1l19</guid>
      <description></description>
    </item>
    <item>
      <title>Isolated Network for Tor-like Services</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Wed, 28 Oct 2026 10:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/isolated-network-for-tor-like-services-31c2</link>
      <guid>https://dev.to/niamtokik/isolated-network-for-tor-like-services-31c2</guid>
      <description>&lt;p&gt;The first part of my career in IT was to be network technician/administrator, configuring firewalls, routers and switches for companies. Since this time, few devices are always ready to do some interesting stuff related to network, one of them is a pretty old &lt;a href="https://pcengines.ch/apu2.htm" rel="noopener noreferrer"&gt;pcengine apu2 firewall&lt;/a&gt; using the latest OpenBSD release. It was mostly a canary-like computer to check if everything was fine during an OpenBSD update/upgrade. Since one of my project is being entirely coded in Dart/Flutter, and because this language is not yet supported by OpenBSD, it would have been good to have a dedicated &lt;a href="https://docs.gitlab.com/runner/" rel="noopener noreferrer"&gt;CI/CD gitlab runner&lt;/a&gt; running somewhere... Why not using an old laptop and isolating it behind this firewall?&lt;/p&gt;

&lt;h1&gt;
  
  
  Configuring OpenBSD
&lt;/h1&gt;

&lt;p&gt;My APU2 is having 3 Gigabit Ethernet port called &lt;code&gt;re0&lt;/code&gt;, &lt;code&gt;re1&lt;/code&gt;, and &lt;code&gt;re2&lt;/code&gt;. All of them are using the &lt;a href="https://man.openbsd.org/re" rel="noopener noreferrer"&gt;&lt;code&gt;re&lt;/code&gt;&lt;/a&gt; driver. &lt;code&gt;re0&lt;/code&gt; is the main interface with a direct connect to another router.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/hostname.re0
&lt;span class="go"&gt;dhcp
inet6 autoconf
&lt;/span&gt;&lt;span class="gp"&gt;inet alias $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;gateway_address&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;up
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;re1&lt;/code&gt; is the interface where the server(s) hosting the worker(s) will be connected. Even if this interface will be used, it will not be set with an IP address but put in a bridge. All interfaces can be started using the &lt;a href="https://man.openbsd.org/netstart" rel="noopener noreferrer"&gt;&lt;code&gt;netstart&lt;/code&gt;&lt;/a&gt; script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/hostname.re1
&lt;span class="go"&gt;up

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ksh /etc/netstart re1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A virtual interface &lt;a href="https://man.openbsd.org/vether" rel="noopener noreferrer"&gt;&lt;code&gt;vether&lt;/code&gt;&lt;/a&gt; will be created to deal with the private network dedicated for the workers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/hostname.vether0
&lt;span class="go"&gt;inet 172.16.0.1/24
up

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ksh /etc/netstart vether0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://man.openbsd.org/bridge" rel="noopener noreferrer"&gt;&lt;code&gt;bridge0&lt;/code&gt;&lt;/a&gt; is also created to connect &lt;code&gt;re1&lt;/code&gt; and &lt;code&gt;vether&lt;/code&gt;. Based on the current configuration, a &lt;a href="https://man.openbsd.org/veb.4" rel="noopener noreferrer"&gt;&lt;code&gt;veb&lt;/code&gt;&lt;/a&gt; interface would have probably be also another correct choice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/hostname.bridge0
&lt;span class="go"&gt;destroy
add vether0
add re1
up

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas ksh /etc/netstart bridge0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The router configuration is ready. All workers will use &lt;code&gt;172.16.0.1&lt;/code&gt; as default route, and packet filter will be in charge to filter which part of the traffic is right or not.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tor Bootstrapping
&lt;/h1&gt;

&lt;p&gt;Tor is easy to install, but can be challenging to configure. Let install it first via &lt;a href="https://man.openbsd.org/pkg_add" rel="noopener noreferrer"&gt;&lt;code&gt;pkg_add&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas pkg_add tor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main Tor configuration is located in &lt;a href="https://man.freebsd.org/cgi/man.cgi?query=tor" rel="noopener noreferrer"&gt;&lt;code&gt;/etc/tor/torrc&lt;/code&gt;&lt;/a&gt; and also in &lt;code&gt;/etc/torrc.d/&lt;/code&gt; directory. The first thing to configure is the DNS resolution to avoid leaks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas &lt;span class="nb"&gt;touch&lt;/span&gt; /etc/torrc.d/dns.conf
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"AutomapHostsOnResolve 1"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="go"&gt;  | doas tee /etc/torrc.d/dns.conf

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"AutomapHostsSuffixes .exit,.onion"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="go"&gt;  | doas tee /etc/torrc.d/dns.conf
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, because our workers will mostly be connected to servers in North America or Europe, it can be nice to define the geolocation of the exit nodes. In the following case, the workers will use exit nodes from USA, UK, Europe, and Japan.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas &lt;span class="nb"&gt;touch&lt;/span&gt; /etc/torrc.d/exit_nodes.conf
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'ExitNodes {us},{uk},{eu},{ez},{jp} StrictNodes 1'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="go"&gt;  | doas tee /etc/torrc.d/exit_nodes.conf
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step is to allow Tor to listen on the correct interface, in this case, &lt;code&gt;re1&lt;/code&gt; with the IP address &lt;code&gt;172.16.0.1&lt;/code&gt;. A first instance will listen on TCP/9080 and allow only onion routing to the standard internet. A second instance will be dedicated for onion traffic only and will listen on TCP/9081. Both of them will be used as HTTP Proxies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/torrc.d/workers.conf &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="go"&gt;HTTPTunnelPort 172.16.0.1:9080 IsolateDestAddr IsolateDestPort NoOnionTraffic ClientUseIPv4
HTTPTunnelPort 172.16.0.1:9081 IsolateDestAddr IsolateDestPort OnionTrafficOnly ClientUseIPv4
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another instance will use a SOCK Proxy this time, and will listen on TCP/9050.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/torrc.d/workers.conf &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="go"&gt;SOCKSPort 127.0.0.1:9050 IsolateDestAddr IsolateDestPort ClientUseIPv4 SafeSocks 1
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, all the DNS requests must be resolved via Tor and not any other kind of DNS to avoid DNS requests leaks. To do that, Tor will listen on TCP/9053 and will use its own DNS resolver.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | doas &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/torrc.d/workers.conf &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="go"&gt;DNSPort 172.16.0.1:9053
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The configuration looks good. Let enable Tor via &lt;a href="https://man.openbsd.org/rcctl" rel="noopener noreferrer"&gt;&lt;code&gt;rcctl&lt;/code&gt;&lt;/a&gt;...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas rcctl &lt;span class="nb"&gt;enable &lt;/span&gt;tor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... And start it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas rcctl start tor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regarding this configuration, one could also configure packet filter to forward the packet directly to a Tor instance on the loopback interface, but it can make the firewall configuration a bit more complex. Another idea is to use another proxy server like Privoxy to do the relay.&lt;/p&gt;

&lt;h1&gt;
  
  
  Packet Filter Configuration
&lt;/h1&gt;

&lt;p&gt;Tor is ready, it should listen on the correct interface, but the firewall must be configure to avoid leaks. Let defines the macros first, to help us deal with the different parameters. Packet filter configuration is located in &lt;a href="https://man.openbsd.org/pf.conf" rel="noopener noreferrer"&gt;&lt;code&gt;/etc/pf.conf&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tor_if = "{ re1, bridge0, vether0 }"
tor_network = "172.16.0.0/24"
tor_gateway = "172.16.0.1"
tor_proxy_ports = "{ 9050, 9080, 9081 }"
tor_dns = 9053
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using Tor can already be painful due to the speed of the connection, so, packet filter can be optimized a bit to win few milliseconds (sometimes). The loopback interface is also ignored, at this time, it's not necessary to filter packet from it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set optimization aggressive
set skip on lo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let configure the anti spoofing features and scrub all packets coming into the firewall.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;antispoof for re0
antispoof for $tor_if
match in all scrub (no-df random-id)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default rule is to drop everything. The next part of the configuration will allow only which packets are authorized to pass through the firewall.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vcl"&gt;&lt;code&gt;block drop log on re0 
block drop log on re0 from $tor_network
block drop log on $tor_if
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nobody wants to lose access to its firewall, then, the TCP/22 port (ssh) is explicitly authorized from the main interface (&lt;code&gt;re0&lt;/code&gt;). All packets going out on this interface are also allowed. For debugging and maintenance purpose, ICMP and ICMPv6 protocols are allowed as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pass in quick on re0 proto tcp to port 22 
pass out quick on re0 keep state
pass on re0 proto icmp 
pass on re0 proto icmp6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the first part of the Tor firewall configuration. Firstly, to help see if the workers are up or down, ICMP are allowed only in one way, the workers are not allowed to send ICMP, but other servers and equipments from other part of the network are.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pass in proto icmp \
  from ! $tor_network \
  to $tor_network tag \
  tor_icmp
pass on $tor_if proto icmp \
  from $tor_network \
  to $tor_gateway \
  tag tor_icmp
pass on $tor_if proto icmp \
  from $tor_gateway \
  to $tor_network \
  tag tor_icmp
pass out proto icmp tagged tor_icmp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workers are allowed to communicate between them. Indeed, it can be useful especially if the workers can share some data, or if a server is installed to cache the artifacts. A fine grained list of host can eventually be created here. The second rules explicitly block all packets coming from the Tor network to any other network different than this network. It means workers' packets will not be able to traverse the router.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pass on $tor_if inet proto tcp \
  from $tor_gateway \
  to $tor_network \
  keep state

pass on $tor_if inet proto tcp \
  from ! $tor_network \
  to $tor_network \
  keep state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When configuring a CI/CD, it always nice to have a correct time from all the workers, if possible returning an UTC timestamp. Unfortunately, bare-metal servers can slowly be inaccurate regarding their local time, and having access to an NTP server can be helpful. Instead of allowing all workers to connect directly to a remote NTP server, the firewall - in this case - will act as a relay. Indeed, an &lt;code&gt;ntpd&lt;/code&gt; daemon will also listen on &lt;code&gt;re1&lt;/code&gt; interface and will offer the correct time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pass in on $tor_if inet proto udp \
  from $tor_network \
  to $tor_gateway port ntp \
  keep state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DNS is also another part of a network, but workers can't be allowed to request unknown server from internet. So, Tor has been previously configured to listen on port UDP/9053 for its DNS resolver. The workers must be able to reach this port and do the DNS resolution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pass on $tor_if inet proto udp \
  from $tor_network \
  to $tor_gateway port $tor_dns \
  keep state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the Tor proxies are also allowed to receive the connections from the workers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pass on $tor_if inet proto tcp \
  from $tor_network \
  to $tor_gateway port $tor_proxy_ports \
  keep state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bonus step, because my configuration for the workers required some extra-data, the workers can also reach out the firewall on the port TCP/80 (HTTP) to fetch some kind of information. The firewall here will act as a simple HTTP server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pass in on $tor_if inet proto tcp \
  from $tor_network \
  to $tor_gateway port http \
  keep state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let check packet filter configuration to see if everything is correct with the help of &lt;a href="https://man.openbsd.org/pfctl" rel="noopener noreferrer"&gt;&lt;code&gt;pfctl&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas pfctl &lt;span class="nt"&gt;-nf&lt;/span&gt; /etc/pf.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all is good, the firewall can be started.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas pfctl &lt;span class="nt"&gt;-ef&lt;/span&gt; /etc/pf.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The configuration presents on my firewall is a bit more complex, but this one should work correctly.&lt;/p&gt;

&lt;h1&gt;
  
  
  From the Workers
&lt;/h1&gt;

&lt;p&gt;With the previous configuration, the workers are easily reachable by adding a static route from any other part of my network to the firewall.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;doas route add 172.16.0.0/24 &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;gateway_ip&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;add net 172.16.0.0/24: gateway $&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;gateway_ip&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From my laptop, the firewall interface for the Tor network is answering to the pings, that's a good sign.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ping &lt;span class="nt"&gt;-c&lt;/span&gt; 3 172.16.0.1
&lt;span class="go"&gt;PING 172.16.0.1 (172.16.0.1): 56 data bytes
64 bytes from 172.16.0.1: icmp_seq=0 ttl=255 time=2.865 ms
64 bytes from 172.16.0.1: icmp_seq=1 ttl=255 time=2.782 ms
64 bytes from 172.16.0.1: icmp_seq=2 ttl=255 time=1.974 ms

--- 172.16.0.1 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 1.974/2.540/2.865/0.402 ms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It seems the worker present on the Tor network (running on alpine linux) is also answering to the pings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ping &lt;span class="nt"&gt;-c&lt;/span&gt; 3 172.16.0.2 
&lt;span class="go"&gt;PING 172.16.0.2 (172.16.0.2): 56 data bytes
64 bytes from 172.16.0.2: icmp_seq=0 ttl=63 time=4.281 ms
64 bytes from 172.16.0.2: icmp_seq=1 ttl=63 time=3.336 ms
64 bytes from 172.16.0.2: icmp_seq=2 ttl=63 time=4.176 ms

--- 172.16.0.2 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 3.336/3.931/4.281/0.423 ms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The TCP/22 port is working as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nc &lt;span class="nt"&gt;-zv&lt;/span&gt; 172.16.0.2 22
&lt;span class="go"&gt;Connection to 172.16.0.2 22 port [tcp/ssh] succeeded
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the time to connect to this worker and check the firewall configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ssh 172.16.0.2
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the worker, it is possible to ping the default route &lt;code&gt;172.16.0.1&lt;/code&gt; without problems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ping &lt;span class="nt"&gt;-c&lt;/span&gt; 3 172.16.0.1
&lt;span class="go"&gt;PING 172.16.0.1 (172.16.0.1): 56 data bytes
64 bytes from 172.16.0.1: seq=0 ttl=42 time=0.617 ms
64 bytes from 172.16.0.1: seq=1 ttl=42 time=0.669 ms
64 bytes from 172.16.0.1: seq=2 ttl=42 time=0.758 ms

--- 172.16.0.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.617/0.681/0.758 ms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Public IP addresses, like &lt;code&gt;8.8.8.8&lt;/code&gt; are not reachable, the firewall is blocking these packets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ping &lt;span class="nt"&gt;-c&lt;/span&gt; 3 8.8.8.8
&lt;span class="go"&gt;PING 8.8.8.8 (8.8.8.8): 56 data bytes

--- 8.8.8.8 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DNS resolution is important though, and all workers must have a local DNS server to use the Tor resolver. In this scenario, &lt;a href="https://dnsmasq.org/doc.html" rel="noopener noreferrer"&gt;&lt;code&gt;dnsmasq&lt;/code&gt;&lt;/a&gt; is used here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/dnsmasq.conf
&lt;span class="go"&gt;no-resolv
&lt;/span&gt;&lt;span class="gp"&gt;server=172.16.0.1#&lt;/span&gt;9053
&lt;span class="go"&gt;local-service
listen-address=127.0.0.1
conf-dir=/etc/dnsmasq.d/,*.conf
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, &lt;code&gt;/etc/resolv.conf&lt;/code&gt; must be updated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/resolv.conf 
&lt;span class="go"&gt;nameserver 127.0.0.1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this new configuration, workers are allowed to resolve domain names via the Tor network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;host google.com
&lt;span class="go"&gt;google.com has address 172.253.63.139
google.com has IPv6 address 2607:f8b0:4006:819::200e
Host google.com not found: 4(NOTIMP)
Host google.com not found: 4(NOTIMP)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All workers should also configure their environment with the correct proxies, usually &lt;code&gt;HTTP_PROXY&lt;/code&gt; and &lt;code&gt;HTTPS_PROXY&lt;/code&gt; variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; proxy
&lt;span class="go"&gt;HTTPS_PROXY='http://172.16.0.1:9080'
HTTP_PROXY='http://172.16.0.1:9080'
http_proxy='http://172.16.0.1:9080'
https_proxy='http://172.16.0.1:9080'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://curl.se/docs/manpage.html" rel="noopener noreferrer"&gt;&lt;code&gt;curl&lt;/code&gt;&lt;/a&gt; is looking for those variables by default, and should use them. It can be checked by checking the public IP address used via &lt;a href="https://www.ipify.org/" rel="noopener noreferrer"&gt;&lt;code&gt;api.ipify.org&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl https://api.ipify.org&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;span class="go"&gt;204.8.96.80
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indeed, it returns an IP address way different than the one configured on my main router.&lt;/p&gt;

&lt;h1&gt;
  
  
  What About Privoxy?
&lt;/h1&gt;

&lt;p&gt;Most of the time, &lt;a href="https://www.privoxy.org/" rel="noopener noreferrer"&gt;Privoxy&lt;/a&gt; is configured alongside Tor to use it as relay. Indeed, privoxy is way more flexible than Tor itself and can offer a better control. In our case, it will not really be necessary to use it, because nothing will be filtered from the network where the workers are present. Only the firewall needs to be correctly configured to avoid data leaks.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;It was an interesting project, but not a really great idea in the end. Most of the tor exit-nodes are blocked by Google, even more, with the recent certificate issues, using a worker always connected to Gitlab to fetch the latest version through an untrusted highly-risky network is perhaps not the best thing to do right now. This idea can be improved though, and instead of using tor, one can create a VPN and force the server to use it instead of using your public IP address.&lt;/p&gt;

&lt;p&gt;The same kind of configuration can also be used for the i2p services, it will perhaps be a bit different because i2p does not have an onion routing service... but it should work if one wants to force the workers or the servers connected to the network to only use i2p. Another cool stuff would be to create a server relay between tor and i2p.&lt;/p&gt;

&lt;p&gt;A bigger article on Tor is planned, but it is a really huge one and take time to write it. This one is just a quick note regarding the configuration of the workers from my CI/CD infrastructure. Below a schema to help you understand how it works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F82i5ushjk52khm2ydhk5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F82i5ushjk52khm2ydhk5.png" alt="Network Schema" width="421" height="1061"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As usual, have fun and happy hacking!&lt;/p&gt;




&lt;p&gt;Cover image by &lt;a href="https://unsplash.com/@jorok?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Georgi Kalaydzhiev&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/silhouette-of-person-looking-at-blurred-city-lights-at-night-fVmneYIIcc0?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>tor</category>
      <category>network</category>
      <category>privacy</category>
    </item>
    <item>
      <title>WeeklyReview#202643</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Mon, 26 Oct 2026 10:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/weeklyreview202643-4dp5</link>
      <guid>https://dev.to/niamtokik/weeklyreview202643-4dp5</guid>
      <description>&lt;p&gt;Black October: the day people discovered Internet is a dangerous place this week. And what a week... It was absurdly hard days for the security world, and it's probably not done yet (because this note has been updated a lot). A huge amount of security issues and other crazy discoveries were announced in few hours/days. Good luck to all my sysadmin friends working to make their infrastructure safer.&lt;/p&gt;

&lt;p&gt;One of the very first big issue was due to a certificate authority problem. Many certificates generated by eMudhra (an Indian company) were totally unsafe. Indeed, their private keys were all an unique integer between 0 and 255 (uint8), instead of a long integer encoded on 384 bits. All started on 17th October, when "Wayne" (a security guy playing with new tools), discovered 8 odd certificates. A ticket was opened on &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=2083449" rel="noopener noreferrer"&gt;Mozilla's Bugzilla&lt;/a&gt;. The thread is still very active. The consequences are concerning. &lt;a href="https://discuss.python.org/t/information-for-python-users-regarding-emudhra-emsign-ca-certificate-security-incident/109576" rel="noopener noreferrer"&gt;Python&lt;/a&gt; is impacted and many packages must be updated. The &lt;a href="https://com.erlef.org/wg/sec/2026/10/20/root-certs-compromised.html" rel="noopener noreferrer"&gt;Erlang Ecosystem Foundation&lt;/a&gt; did also a post about this issue explaining which modules must be upgraded as soon as possible. All &lt;a href="https://emudhra.we-have-a-problem.com/" rel="noopener noreferrer"&gt;Operating Systems&lt;/a&gt; are also impacted by this issue, and the certificates must be upgraded locally as well. The &lt;a href="https://github.com/mitmproxy/mitmproxy/issues/8497" rel="noopener noreferrer"&gt;&lt;code&gt;mitmproxy&lt;/code&gt; project&lt;/a&gt; already includes on its last version those certificates. More information below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=2082872" rel="noopener noreferrer"&gt;&lt;strong&gt;eMudhra emSign PKI Services: CP/CPS documents not updated for current requirements&lt;/strong&gt;&lt;/a&gt; from Mozilla's Bugzilla thread;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=2083449" rel="noopener noreferrer"&gt;&lt;strong&gt;eMudhra: Private key compromise of Intermediate Certificates&lt;/strong&gt;&lt;/a&gt; from Mozilla's Bugzilla thread;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://discuss.python.org/t/information-for-python-users-regarding-emudhra-emsign-ca-certificate-security-incident/109576" rel="noopener noreferrer"&gt;&lt;strong&gt;Information for Python users regarding eMudhra / emSign CA certificate security incident&lt;/strong&gt;&lt;/a&gt; from Python's Discuss thread;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://com.erlef.org/wg/sec/2026/10/20/root-certs-compromised.html" rel="noopener noreferrer"&gt;&lt;strong&gt;eMudhra CA Intermediate Certificates have been compromised, CA updates needed on all TLS components&lt;/strong&gt;&lt;/a&gt; from the Erlang Ecosystem Foundation;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.alpinelinux.org/posts/Alpine-3.21.9-3.22.7-3.23.7-3.24.3-released.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Alpine Linux 3.24.3&lt;/strong&gt;&lt;/a&gt; from Alpine Linux website;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.openbsd.org/errata80.html" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenBSD 8.0 Errata 005&lt;/strong&gt;&lt;/a&gt; from the OpenBSD website;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vuxml.freebsd.org/freebsd/070a35ef-cd22-11f1-ada3-bc241121aa0a.html" rel="noopener noreferrer"&gt;&lt;strong&gt;FreeBSD -- TLS certificate store update due to eMudhra compromise&lt;/strong&gt;&lt;/a&gt; from FreeBSD VuXML;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://blog.netbsd.org/tnf/entry/emudhra_tls_ssl_ca_compromise" rel="noopener noreferrer"&gt;&lt;strong&gt;eMudhra TLS/SSL CA compromise&lt;/strong&gt;&lt;/a&gt; from the NetBSD blog;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://lists.debian.org/debian-security-announce/2026/msg00487.html?pow_referer=" rel="noopener noreferrer"&gt;&lt;strong&gt;Debian ca-certificates security update&lt;/strong&gt;&lt;/a&gt;, from the Debian mailing-list;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://thehackernews.com/2026/10/eight-emudhra-ca-keys-compromised.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Eight eMudhra CA Keys Compromised, Triggering Emergency Fixes Across Browsers and Software&lt;/strong&gt;&lt;/a&gt; from The Hacker News;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.reuters.com/legal/litigation/indian-firm-emudhra-exits-global-digital-certificates-business-after-2026-10-22/" rel="noopener noreferrer"&gt;&lt;strong&gt;India's eMudhra exits website security business after flaws trigger global alarm&lt;/strong&gt;&lt;/a&gt; from Reuters;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.oracle.com/security-alerts/alert-cve-2026-91403.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Oracle Security Alert Advisory - CVE-2026-91403&lt;/strong&gt;&lt;/a&gt; from Oracle/Java website.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PHP is well known for Wikimedia, Drupal, Wordpress, Symphony and many other frameworks/projects widely used around the world. Unfortunately, PHP design is not the best, and during the past decades, many critical issues have been impacted it. This week, 2 huge security issues have been released  with a CVE score greater than 9 and allowing remote code executions. What's crazy here is those vulnerabilities have been discovered in 2024 (!) during an audit.&lt;/p&gt;

&lt;p&gt;PHP was my first "real" language, like probably many of the developers and sysadmin of my generation. This language was - and still is - a big joke regarding design and consistency. During the week, PHP was also impacted by 2 big security issues with a score greater than 9 on the CVE scale. The whole story is just a pure mess. Called &lt;code&gt;php2shell&lt;/code&gt;, the bug can execute arbitrary code on a remote server. Those bugs have been discovered in 2024 (!) during an audit. The PHP Foundation &lt;a href="https://thephp.foundation/blog/2026/10/21/todays-php-security-release-and-how-were-strengthening-php-security/" rel="noopener noreferrer"&gt;published a post&lt;/a&gt; on their blog explaining the whole process. Another crazy thing is, &lt;a href="https://github.com/twili8/php2shell-poc" rel="noopener noreferrer"&gt;someone&lt;/a&gt; published an exploit few days before the official release, without any consideration of the companies being impacted by this news. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://thehackernews.com/2026/10/php-issues-emergency-patches-for-two.html" rel="noopener noreferrer"&gt;&lt;strong&gt;PHP Issues Emergency Patches for Two Critical PHP2Shell RCE Flaws as Exploit Attempts Emerge&lt;/strong&gt;&lt;/a&gt; on The Hacker News;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://thehackernews.com/2026/10/php2shell-what-actually-protects-you.html" rel="noopener noreferrer"&gt;&lt;strong&gt;PHP2Shell: What Actually Protects You Before the 14:00 UTC PHP RCE Patch, and What Doesn't&lt;/strong&gt;&lt;/a&gt; on the Hacker News;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://thehackernews.com/2026/10/php2shell-two-unpatched-critical-php.html" rel="noopener noreferrer"&gt;&lt;strong&gt;PHP2Shell: Two Unpatched Critical PHP RCE Flaws (CVSS 9.2) Trigger Emergency Security Alert&lt;/strong&gt;&lt;/a&gt; on The Hacker News;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://webhosting.today/2026/10/21/two-critical-php-flaws-leaked-ahead-of-the-october-21-security-release/" rel="noopener noreferrer"&gt;&lt;strong&gt;Two Critical PHP Flaws Leaked Ahead of the October 21 Security Release&lt;/strong&gt;&lt;/a&gt; on WebHosting.today;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://thephp.foundation/blog/2026/10/21/todays-php-security-release-and-how-were-strengthening-php-security/" rel="noopener noreferrer"&gt;&lt;strong&gt;Today's PHP Security Release, and How We're Strengthening PHP Security&lt;/strong&gt;&lt;/a&gt; on the Official PHP Foundation blog;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://abraxaslabs.tech/research/php2shell" rel="noopener noreferrer"&gt;&lt;strong&gt;PHP2Shell: CVE-2026-109618 and CVE-2026-109619&lt;/strong&gt;&lt;/a&gt; exploits on Abraxas Labs;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/abraxas/php-stale-global-uaf" rel="noopener noreferrer"&gt;&lt;strong&gt;php2shell/php2dos - php-stale-global-uaf&lt;/strong&gt;&lt;/a&gt; exploit on Github;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/abraxas/php-oom-longjmp" rel="noopener noreferrer"&gt;&lt;strong&gt;php2shell - php-oom-longjmp&lt;/strong&gt;&lt;/a&gt; exploits on Github;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://xeiaso.net/shitposts/no-way-to-prevent-this/memory-safety/CVE-2026-109618/" rel="noopener noreferrer"&gt;&lt;strong&gt;Jesus Christ patch your shit now&lt;/strong&gt;&lt;/a&gt; on xeiaso.net.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A second breach in PHP has also been announced, not related to PHP2Shell, linked to the Session process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.php.net/archive/2026.php#2026-10-23-1" rel="noopener noreferrer"&gt;&lt;strong&gt;Informational advisory: Session upload progress&lt;/strong&gt;&lt;/a&gt; from PHP official website;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ivst/CVE-2026-115560" rel="noopener noreferrer"&gt;&lt;strong&gt;CVE-2026-115560 — PHP session upload progress mitigation&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the same time, QUIC/HTTP/3 was also impacted by another 0day vulnerability called &lt;a href="https://foxio.io/blog/header-accordions-qpack-amplification-attacks-against-http-3-servers" rel="noopener noreferrer"&gt;quiche&lt;/a&gt;, causing a DoS and eventually an OOM on many implementation of this protocol.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://foxio.io/blog/header-accordions-qpack-amplification-attacks-against-http-3-servers" rel="noopener noreferrer"&gt;&lt;strong&gt;Header Accordions: QPACK amplification attacks against HTTP/3 servers&lt;/strong&gt;&lt;/a&gt; on Foxio.io;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/FoxIO-LLC/blog_poc/tree/main/headeraccordions" rel="noopener noreferrer"&gt;&lt;strong&gt;headeraccordions&lt;/strong&gt;&lt;/a&gt; exploit/poc on Github.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not over... Gitlab also released emergency patches for Gitlab Community and Enterprise Edition containing 12 fixes, including one &lt;a href="https://docs.gitlab.com/releases/patches/patch-release-gitlab-19-5-1-released/#cve-2026-110264---integer-overflow-issue-in-regular-expression-compiler-impacts-gitlab-ceee" rel="noopener noreferrer"&gt;critical vulnerability&lt;/a&gt; allowing an unauthenticated user to execute arbitrary code remotely.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.gitlab.com/releases/patches/patch-release-gitlab-19-5-1-released" rel="noopener noreferrer"&gt;&lt;strong&gt;GitLab Critical Patch Release: 19.5.1, 19.4.3, 19.3.6, 19.2.9, 19.1.9, 19.0.10, 18.11.13&lt;/strong&gt;&lt;/a&gt; on Official Gitlab Documentation:&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://thehackernews.com/2026/10/critical-gitlab-flaw-cvss-100-could.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Critical GitLab Flaw (CVSS 10.0) Could Allow Unauthenticated RCE Across 12 Years of Releases&lt;/strong&gt;&lt;/a&gt; on The Hacker News.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Signal released also a series of patch to fix a critical security issue, allowing someone to keep the micro and the camera active after a call.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.theregister.com/security/2026/10/21/signal-bug-could-keep-your-mic-and-camera-on-after-hangup/5304528" rel="noopener noreferrer"&gt;&lt;strong&gt;Signal bug could keep your mic - and camera - on after hangup&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/signalapp/ringrtc/blob/a1d2ffed1de6ac5b22458a3dced8374513cc44f8/CHANGELOG.md" rel="noopener noreferrer"&gt;&lt;strong&gt;Signal v2.72.0&lt;/strong&gt;&lt;/a&gt; on Gitlab;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cwe.mitre.org/data/definitions/754.html" rel="noopener noreferrer"&gt;&lt;strong&gt;CWE-754: Improper Check for Unusual or Exceptional Conditions&lt;/strong&gt;&lt;/a&gt; on Common Weakness Enumeration website.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NodeJs, as usual, is always there to offer us more vulnerabilities, even when we don't need them. Nodejs team released a long series of patches fixing dangerous security issues, 4 of them with high level risks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/blog/vulnerability/october-2026-security-releases" rel="noopener noreferrer"&gt;&lt;strong&gt;Wednesday, October 21, 2026 Security Releases&lt;/strong&gt;&lt;/a&gt; on NodeJS official blog;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vercel.com/kb/bulletin/node-js-security-advisory" rel="noopener noreferrer"&gt;&lt;strong&gt;Node.js security advisory: Brotli decoder RCE (CVE-2026-111497)&lt;/strong&gt;&lt;/a&gt; on Vercel;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://xeiaso.net/shitposts/no-way-to-prevent-this/memory-safety/CVE-2026-111497/" rel="noopener noreferrer"&gt;&lt;strong&gt;"No way to prevent this" say users of only language where this regularly happens&lt;/strong&gt;&lt;/a&gt; on Xeiaso.net.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do you think it's over? Not at all! &lt;a href="https://trafficserver.apache.org/" rel="noopener noreferrer"&gt;Apache traffic&lt;/a&gt; HTTP server released a new released to fix 15 vulnerabilities, including remote code execution and many other crazy holes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://xeiaso.net/shitposts/no-way-to-prevent-this/memory-safety/CVE-2026-111813/" rel="noopener noreferrer"&gt;&lt;strong&gt;"No way to prevent this" say users of only language where this regularly happens&lt;/strong&gt;&lt;/a&gt; on xeiaso.net;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://lists.apache.org/thread/r95dq29ywcd1f4x30snxlqmb12z4s4kc" rel="noopener noreferrer"&gt;&lt;strong&gt;[SECURITY] Multiple vulnerabilities fixed in Apache Traffic Server 9.2.16, 10.1.5 and 10.2.1&lt;/strong&gt;&lt;/a&gt; on apache traffic mailing-list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A dangerous memory corruption bug on Bind9 can lead an attacker to execute remote code. Again, high severity issue, needs to be patched as soon as possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kb.isc.org/docs/cve-2026-94300" rel="noopener noreferrer"&gt;&lt;strong&gt;CVE-2026-94300: Concurrent GSS-TSIG messages corrupt memory&lt;/strong&gt;&lt;/a&gt; on ISC.org;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://xeiaso.net/shitposts/no-way-to-prevent-this/memory-safety/CVE-2026-94300/" rel="noopener noreferrer"&gt;&lt;strong&gt;"No way to prevent this" say users of only language where this regularly happens&lt;/strong&gt;&lt;/a&gt; on Xeiaso.net.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tor - which is becoming less and less trusted due to many design flaws and unfixed security issues - has also been impacted by a serious attack. 333 exit nodes on the tor network have been compromised and were used to do man in the middle attack on SSH connections. In case of success, the attackers were able to watch the commands and install backdoors.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://thehackernews.com/2026/10/attackers-hijacked-over-300-tor-exit.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Attackers Hijacked Over 300 Tor Exit Relays to Intercept SSH Connections&lt;/strong&gt;&lt;/a&gt; from the Hacker News;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/message/Z2B6XYKJZBBQADU77MSNL6FJP7MHZHIV/" rel="noopener noreferrer"&gt;&lt;strong&gt;[tor-relays] Re: Ebury 1.8.3 on two Quetzalcoatl relay servers: timeline, lessons, open questions&lt;/strong&gt;&lt;/a&gt; from the Tor project mailing list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The French provider OVH has been victim of a supply chain attack, replacing the binaries of many versions of their CLI tool.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://x.com/lukOlejnik/status/2113146344118337935?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;OVH supply chain compromise&lt;/strong&gt;&lt;/a&gt; on Twitter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LiteLLM Python package has been compromised with a supply chain attack as well, injecting malwares via Pypi and Docker images.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://x.com/SocketSecurity/status/2112907732877775016" rel="noopener noreferrer"&gt;&lt;strong&gt;LiteLLM, a Python package for connecting to AI model providers with 92M+ monthly downloads, has been compromised.&lt;/strong&gt;&lt;/a&gt; on Twitter;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.theregister.com/security/2026/10/21/litellm-supply-chain-attack-hoovers-up-passwords-and-secrets/5304548" rel="noopener noreferrer"&gt;&lt;strong&gt;LiteLLM supply chain attack hoovers up passwords and secrets&lt;/strong&gt;&lt;/a&gt; on The Register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PHP, NodeJS, and... Ruby. This language requires to be patched due to remote code execution vulnerability related to the Regexp module (integer overflows and double free issue). All versions of Ruby are impacted.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.ruby-lang.org/en/news/2026/10/23/regexp-fixes-for-gitlab-cves/" rel="noopener noreferrer"&gt;&lt;strong&gt;Regexp compilation fixes related to GitLab's CVE-2026-89078, CVE-2026-93577, CVE-2026-97229 and CVE-2026-110264&lt;/strong&gt;&lt;/a&gt; from the official Ruby news.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kubernetes will also have a bad time, with 4 critical CVEs released very soon, including an issue on Azure Kubernetes, allowing remote code execution.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://app.opencve.io/cve/CVE-2026-83938" rel="noopener noreferrer"&gt;&lt;strong&gt;CVE-2026-83938 - Azure Kubernetes Configuration Service Elevation of Privilege Vulnerability&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't even think it's done... And to be honest, I am not the only one to do a summary of all those security issues. Here few of them from Twitter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://x.com/techie_piyush/status/2113065045382807700?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;THE INTERNET BROKE TODAY&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/AISafetyMemes/status/2113113711644737835?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;This is the most serious 48 hours in cybersecurity history.&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/juampitech/status/2113041641481138358?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;October has been an absolute nightmare for software&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/DevMuzzammil/status/2113042127039164663?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;We can call it Black October for the security breaches:&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/RaphaelRedmer/status/2113224897199477015?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;33 security incidents in the news this October, sorted by size. 7 ran on a stolen key (K), 4 abused a trusted channel (T).&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/infinterenders/status/2113223887198519428?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;This week the internet’s core infrastructure got hit harder than most people realize&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;While writing my article on the &lt;code&gt;libsodium&lt;/code&gt; library port on Dart using FFI, I also checked the Erlang driver called &lt;a href="https://github.com/potatosalad/erlang-libsodium" rel="noopener noreferrer"&gt;&lt;code&gt;erlang-libsodium&lt;/code&gt;&lt;/a&gt;. Sadly this package was kinda old (&lt;a href="https://github.com/jedisct1/libsodium/releases#release-1.0.18-RELEASE" rel="noopener noreferrer"&gt;version 1.0.18+&lt;/a&gt; released in 2019). Few issues and PRs have been opened to fix the library, but the project seems to be dead. Anyway, I wanted to use is to test the interoperability with the Dart implementation, and decided to fork it. &lt;code&gt;libsodium&lt;/code&gt; has been updated to version 1.0.22 (the latest), the PRs have been merged, and I'm working on doing a lot of test cleanup. After that, I will - perhaps - ports the missing features from the latest release. The project can be found here: &lt;a href="https://github.com/niamtokik/erlang-libsodium/" rel="noopener noreferrer"&gt;niamtokik/erlang-libsodium&lt;/a&gt; on Github.&lt;/p&gt;




&lt;p&gt;What's happening in the economy right now is interesting -- and also terrifying. During the week, most of the big players just started to fall, as well as the Asian market.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Semiconductor (SOX) Index was hammered 11.4% [...] Supporting the bursting Bubble thesis, the semi equipment stocks were under notable pressure. Applied Materials lost 19.3%, Lam Research 17.2%, and KLA 15.3%. Coherent dropped 25.5%, Lattice Semiconductor 17.8%, and Marvell Technology 17.2%. Nvidia slumped 6.1%, down a quick 12% in eight sessions. Broadcom fell 9.1% to a six-month low. Micron sank 14.6%, Intel 14.2%, and AMD 13.1%. South Korea’s KOSPI Index was hammered 14.5% this week, with a seven-session drop of 18.3%. [...] Japan’s Nikkei Index fell 5.4%.&lt;br&gt;
-- &lt;a href="https://creditbubblebulletin.blogspot.com/2026/10/weekly-commentary-hope-im-wrong.html" rel="noopener noreferrer"&gt;Credit Bulletin Report&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In fact, this situation is a direct result of something I saw many time in the past. Most of the current companies are not really companies anymore, but they look like sects. They are selling dreams, and faith to people without having an ounce of the knowledge or the experiences required to understand the bare minimum. You don't even need to give big proofs to make them pay, you know the aphorism "fake it until you make it". You just need one small miracle to make your company grows exponentially. The result? Some "expert" will also fall in the trap, and will start to preach. It will attract more people, blindly believing in them and in fine, in the technology sold by the company. The reality is harsh, and every actions produce reactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Investors are losing confidence that revenues from the AI boom will be sufficient to support the vast debt piles financing data centres, pushing bonds backing some of the largest US infrastructure projects into increasingly stressed territory.&lt;br&gt;
-- &lt;a href="https://creditbubblebulletin.blogspot.com/2026/10/weekly-commentary-hope-im-wrong.html" rel="noopener noreferrer"&gt;Credit Bulletin Report&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The recent message(s) from Linus Torvalds are hilarious. Torlvads has a strong reputation to be against a lot of new/modern technologies, but for LLMs, that's okay, that's just another tool. It's fascinating to see someone like him using LLMs and trashing other people opinions on this subject when you know the &lt;a href="//aiwiki.ai/wiki/open_secure_ai_alliance"&gt;Open Secure AI Alliance&lt;/a&gt; joined the &lt;a href="https://www.linuxfoundation.org/blog/open-secure-ai-alliance-joins-the-linux-foundation-to-build-a-shared-open-defense-stack-for-the-ai-era" rel="noopener noreferrer"&gt;Linux Foundation&lt;/a&gt; in September. What kind of companies are present in this alliance? NVIDIA, Microsoft, Cisco, CrowdStrike, Hugging Face, IBM, Palantir, Red Hat and many others.&lt;/p&gt;

&lt;p&gt;It's not done yet, nvidia is also giving money to Linux Foundations in many other ways. They are &lt;a href="https://www.phoronix.com/news/NVIDIA-Premier-Sponsor-LVFS" rel="noopener noreferrer"&gt;LVFS sponcors&lt;/a&gt; and they are supporting many other &lt;a href="https://opensource.nvidia.com/en-us/" rel="noopener noreferrer"&gt;open-source projects&lt;/a&gt; (including the Linux Foundation). In fact, we don't even know the amount of money nvidia is giving to the Linux Foundation because it is not public. In doubt, follow the money, even a monk can be corrupted with gold.&lt;/p&gt;

&lt;p&gt;Anyway, the LLM buzz is like the blockchain/crypto-currency one. They have both been created to do what fraudsters do the best: steal the money from your pocket by selling you a dream. The sects are doing the same with their victims. The result? What will happen when investors will discover all of these companies are selling snakeoil? They will simply ask their investment back. With &lt;a href="https://www.techtimes.com/articles/323034/20260804/anthropic-stacks-second-record-debt-deal-60-days-compute-bill-defies-equity-raise.htm" rel="noopener noreferrer"&gt;$71 billions debt&lt;/a&gt; for Anthropic, and the small revenue generated by the company, it will become hard to explain that to investors.&lt;/p&gt;

&lt;p&gt;In short: this is a bubble, it will pop one day, probably very soon (if it's not already the case). To my brainwashed IT colleagues, please stop be part of these frauds...&lt;/p&gt;




&lt;h1&gt;
  
  
  Coding
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/atc1441/Vape_DOOM_ScreenShare/tree/main/PixoAspire_DOOM_Port" rel="noopener noreferrer"&gt;&lt;strong&gt;DOOM on the Aspire PIXO — natively&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  System
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://undeadly.org/cgi?action=article;sid=20261018200218" rel="noopener noreferrer"&gt;&lt;strong&gt;Introducing uncm(4)&lt;/strong&gt;&lt;/a&gt;: finally! a replacement for &lt;a href="https://man.openbsd.org/urndis" rel="noopener noreferrer"&gt;&lt;code&gt;urndis&lt;/code&gt;&lt;/a&gt; driver working with recent version of Android! Say hello to &lt;a href="https://man.openbsd.org/uncm" rel="noopener noreferrer"&gt;&lt;code&gt;uncm&lt;/code&gt;&lt;/a&gt;, providing support for the USB Network Control Model Ethernet devices.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://loige.co/hidden-design-compromises-of-docker-layers/" rel="noopener noreferrer"&gt;&lt;strong&gt;The hidden design compromises of Docker layers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://undeadly.org/cgi?action=article;sid=20261021191736" rel="noopener noreferrer"&gt;&lt;strong&gt;dbupdate(8) added to -current&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://exe.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;exe.dev&lt;/strong&gt;&lt;/a&gt;: Computers for developers and agents (Durable Sandboxes that are fast, secure, and sharable).&lt;/p&gt;

&lt;h1&gt;
  
  
  Database
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/HexaCluster/credcheck" rel="noopener noreferrer"&gt;&lt;strong&gt;credcheck&lt;/strong&gt;&lt;/a&gt;: provides few general credential checks, which will be evaluated during the user creation, during the password change and user renaming.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/ossc-db/pg_hint_plan/" rel="noopener noreferrer"&gt;&lt;strong&gt;pg_hint_plan&lt;/strong&gt;&lt;/a&gt;: makes it possible to tweak PostgreSQL execution plans using so-called "hints" in SQL comments.&lt;/p&gt;

&lt;h1&gt;
  
  
  Security
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://pwn.ai/blog/pwnescape" rel="noopener noreferrer"&gt;&lt;strong&gt;PwnEscape: Guest-to-Host KVM Escape (CVE-2026-99999)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://arxiv.org/abs/2606.19535" rel="noopener noreferrer"&gt;&lt;strong&gt;FloatDoor: Platform-Triggered Backdoors in LLMs&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=2083449" rel="noopener noreferrer"&gt;&lt;strong&gt;Private key compromise of eMudhra Intermediate Certificates&lt;/strong&gt;&lt;/a&gt;: the thread from mozilla regarding the corrupted certificate.&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://emudhra.we-have-a-problem.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;eMudhra Intermediate CA Compromise&lt;/strong&gt;&lt;/a&gt;: a longer post with solutions to apply after the CA corrupted certificate.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://kaba.cx/posts/20261020_Tor/" rel="noopener noreferrer"&gt;&lt;strong&gt;How I got over 300 Tor exit nodes removed&lt;/strong&gt;&lt;/a&gt;: a huge attack on tor network, where 333 nodes have been deployed to do MITM attack on SSH connections.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://blog.29b.net/dispatches/viltrox_re/" rel="noopener noreferrer"&gt;&lt;strong&gt;Dumping Encrypted Viltrox Lens Firmware - two times&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://quentinkaiser.be/security/2026/10/16/one-parser-two-bugs/" rel="noopener noreferrer"&gt;&lt;strong&gt;One Parser, Two Bugs, Many Routers: Exploiting Broadcom WiFi Across eCos and Linux&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://exploitgrid.net/" rel="noopener noreferrer"&gt;&lt;strong&gt;ExploitGrid&lt;/strong&gt;&lt;/a&gt;: Get notified when a CVE hits the software you run.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.phoronix.com/news/LKML-New-Trend-Vulnerabilities" rel="noopener noreferrer"&gt;&lt;strong&gt;Several Linux Kernel Vulnerabilities Accidentally Posted To Public Kernel Mailing List&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.axios.com/2026/10/22/ai-agents-banks-unauthorized-accounts-access" rel="noopener noreferrer"&gt;&lt;strong&gt;Scoop: Unvetted AI agents are accessing U.S. bank accounts&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Security/cryptography
&lt;/h1&gt;

&lt;p&gt;📑 &lt;a href="https://www.anthropic.com/research/ecdsa-curve-origins" rel="noopener noreferrer"&gt;&lt;strong&gt;Claude reveals ECDSA curve origins&lt;/strong&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://saweis.net/posts/nist-curve-seed-origins.html" rel="noopener noreferrer"&gt;&lt;strong&gt;How were the NIST ECDSA curve parameters generated?&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://mrosenberg.pub/blog/cryptoslop/" rel="noopener noreferrer"&gt;&lt;strong&gt;Can You Slop Out High-Assurance Cryptography?&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Update/Upgrade
&lt;/h1&gt;

&lt;p&gt;🔄 &lt;a href="https://www.openbsd.org/80.html" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenBSD 8.0&lt;/strong&gt;&lt;/a&gt;: another release of OpenBSD.&lt;/p&gt;

&lt;p&gt;🔄 &lt;a href="https://github.com/rabbitmq/rabbitmq-server/releases/tag/v4.4.0" rel="noopener noreferrer"&gt;&lt;strong&gt;RabbitMQ 4.4.0&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔄 &lt;a href="https://github.com/phoenixframework/phoenix/releases/tag/v1.8.16" rel="noopener noreferrer"&gt;&lt;strong&gt;Phoenix 1.8.6&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Misc
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://hackernoon.com/theo-de-raadt-the-man-who-built-the-internets-locks" rel="noopener noreferrer"&gt;&lt;strong&gt;Theo de Raadt: The Man Who Built the Internet's Locks&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/ProtonPrivacy/status/2113274715124945133" rel="noopener noreferrer"&gt;&lt;strong&gt;Meta just got hit with the largest penalty ever imposed on the company.&lt;/strong&gt;&lt;/a&gt;:  Meta will pay $25 bn for misleading Facebook users about how their data was protected. &lt;/p&gt;

&lt;h1&gt;
  
  
  Leaks of the week
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://frenchbreaches.com/alertes/pcf-fuite-donnees-personnelles-vente-forum-cybercriminel-mvl13xuxyt1dju2rbve" rel="noopener noreferrer"&gt;&lt;strong&gt;French Communist Party&lt;/strong&gt;&lt;/a&gt;: 183000 users impacted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://frenchbreaches.com/alertes/fuite-donnees-lfi-porte-a-porte-rendez-vous-mvm6atypwytjz0coskh" rel="noopener noreferrer"&gt;&lt;strong&gt;La France Insoumise&lt;/strong&gt;&lt;/a&gt;: leaks about campaigns and organization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://frenchbreaches.com/blog/admr-les-donnees-medicales-de-millions-de-francais-potentiellement-exposees" rel="noopener noreferrer"&gt;&lt;strong&gt;ADMR&lt;/strong&gt;&lt;/a&gt;: 4.5 millions people impacted, the leak include data about health and daily habits.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://frenchbreaches.com/alertes/association-m-dico-sociale-anne-morgan-amsam-rw_UVUxVFFVMUFZbkpoZG05NA" rel="noopener noreferrer"&gt;&lt;strong&gt;AMSAM&lt;/strong&gt;&lt;/a&gt;: 922GB of data stolen including invoices, bills, many kind of internal documents about 400 people.&lt;/p&gt;




&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2113335587038167169-955" src="https://platform.twitter.com/embed/Tweet.html?id=2113335587038167169"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2113335587038167169-955');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2113335587038167169&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/jaosef/status/2111215671476379891?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqz43t9e3kp9ak9f2lhy1.png" alt=" " width="598" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/moti256/status/2111045235916623934?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw1659mzg1ec7dd4j49cz.png" alt=" " width="598" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/defnotbeka/status/2111504841000517792?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbr48bgdc2o4xg9jf3va1.png" alt=" " width="598" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3zi1txh11sor7iakz206.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3zi1txh11sor7iakz206.png" alt=" " width="598" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/zekramu/status/2111485024239530140?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8en70jdwzr5jq8pv6d69.png" alt=" " width="598" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/ill_Scholar/status/2111335049744290182?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fev4vsxamj9piwnxdaf78.png" alt=" " width="598" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/JeffBohren/status/2111542985842135126?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbtyoq4wotw5q7d1l0sew.png" alt=" " width="598" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/satellitedown/status/2111879374056345937?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiusg1zfx7jn3zet762xw.png" alt=" " width="598" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/tsoding/status/2112005201557098662?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fojhuu50fr0fvwz154e1k.png" alt=" " width="598" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/FinanceLancelot/status/2111879798003741028?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fttjiqdjslnwc50opu1c1.png" alt=" " width="598" height="884"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/PluckedFruit/status/2112585058649559187?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcvwy3fppiu2segef67do.png" alt=" " width="598" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/FinanceLancelot/status/2112677522588516504?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhu7poio67oz0346u7n29.png" alt=" " width="598" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/IceSolst/status/2112639669913768363?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ficccnoy8y77lhvqjnj2i.png" alt=" " width="598" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/garybernhardt/status/2112680936060104802?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Famqtriktr6jr0t58wtfh.png" alt=" " width="598" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/shortmagsmle/status/2112758863758008613?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fllqbi5sy1ovmn14oy0az.png" alt=" " width="598" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/IzzatStatus/status/2112781125697589746?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0yk38gl4kozhihr7167p.png" alt=" " width="598" height="802"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/digitaldutta/status/2112763914249453763?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjd0fx4xsxa5r4pu46jmq.png" alt=" " width="598" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/lcamtuf/status/2112630915579162640?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Focjr6142k7ogmlzwo5go.png" alt=" " width="598" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/psankar/status/2112761583382446550?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fonukib7a1kswsqrfi43b.png" alt=" " width="598" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/IzzatStatus/status/2112781125697589746?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F381e3nniitcv6mo57hu8.png" alt=" " width="598" height="802"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/ghidraninja/status/2112616423004705070?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffu3fnrkznd5macnkffh6.png" alt=" " width="598" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/zephyr_z9/status/2113088278081741086?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fibzjfq6ikmvtkm4dxxf0.png" alt=" " width="598" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Klotzkette/status/2113335392778723472?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjg41k6pgur1i9bvkk28w.png" alt=" " width="598" height="682"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F03781umx3cvga1uym9bo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F03781umx3cvga1uym9bo.png" alt=" " width="382" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs8wbj9jpd3q8msks2ll4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs8wbj9jpd3q8msks2ll4.png" alt=" " width="500" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5ijv3nxv3rwn9yil2r0k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5ijv3nxv3rwn9yil2r0k.png" alt=" " width="400" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzyvqmb0t98wjk4684mp1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzyvqmb0t98wjk4684mp1.png" alt=" " width="680" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fae4e9nakuxnxve6fw2d3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fae4e9nakuxnxve6fw2d3.png" alt=" " width="556" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjuakhwerny8iiyy3ogkp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjuakhwerny8iiyy3ogkp.png" alt=" " width="548" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff7qxszwv8i6cmwb4kkyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff7qxszwv8i6cmwb4kkyu.png" alt=" " width="680" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6l7iuv5buw4zfz5cum2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6l7iuv5buw4zfz5cum2n.png" alt=" " width="680" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8vo3kr8aju7tb0h9c9qk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8vo3kr8aju7tb0h9c9qk.png" alt=" " width="585" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4sevp74dpkskq4d9mkji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4sevp74dpkskq4d9mkji.png" alt=" " width="479" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz1zpu8va1jps3tejlvpa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz1zpu8va1jps3tejlvpa.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuqnb2qvn1vssn4j98rm3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuqnb2qvn1vssn4j98rm3.png" alt=" " width="680" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqcdsdr86hc5dtxwp3twz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqcdsdr86hc5dtxwp3twz.png" alt=" " width="451" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqweoeccvtdq6cco25xw0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqweoeccvtdq6cco25xw0.png" alt=" " width="544" height="680"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Cover image by &lt;a href="https://unsplash.com/@thatsmrbio?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Matthew Hamilton&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/aerial-view-of-brown-leaves-I0sDI_paMq4?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>weekly</category>
      <category>review</category>
    </item>
    <item>
      <title>A review of the libsodium library in Dart</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Thu, 22 Oct 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/a-review-of-the-libsodium-library-in-dart-3b9i</link>
      <guid>https://dev.to/niamtokik/a-review-of-the-libsodium-library-in-dart-3b9i</guid>
      <description>&lt;p&gt;This article is a big sandbox based on the notes I took during my test of the &lt;a href="https://pub.dev/packages/sodium" rel="noopener noreferrer"&gt;&lt;code&gt;sodium&lt;/code&gt;&lt;/a&gt; Dart package, an implementation of the &lt;a href="https://libsodium.gitbook.io/" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; (a well known C cryptographic library), itself coming from a fork of &lt;a href="https://nacl.cr.yp.to/" rel="noopener noreferrer"&gt;&lt;code&gt;NaCl&lt;/code&gt;&lt;/a&gt;. &lt;code&gt;libsodium&lt;/code&gt; was ported on many languages like &lt;a href="https://github.com/jedisct1/libsodium.js/" rel="noopener noreferrer"&gt;javascript&lt;/a&gt;, &lt;a href="https://docs.rs/libsodium-rs/latest/libsodium_rs/" rel="noopener noreferrer"&gt;rust&lt;/a&gt;, &lt;a href="https://github.com/GoKillers/libsodium-go" rel="noopener noreferrer"&gt;go&lt;/a&gt;, &lt;a href="https://github.com/ahrefs/ocaml-sodium" rel="noopener noreferrer"&gt;ocaml&lt;/a&gt;, &lt;a href="https://hackage.haskell.org/package/libsodium" rel="noopener noreferrer"&gt;haskell&lt;/a&gt;, &lt;a href="https://github.com/potatosalad/erlang-libsodium" rel="noopener noreferrer"&gt;erlang&lt;/a&gt;, &lt;a href="https://github.com/ArteMisc/libsalty" rel="noopener noreferrer"&gt;elixir&lt;/a&gt; and many others.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sodium&lt;/code&gt; implementation tries to be a 1:1 interface to &lt;code&gt;libsodium&lt;/code&gt; but with the object oriented paradigm in mind and the specificity of the Dart language. In fact, the few examples present in the source code and the documentation looks limited to me, and did not answer my questions. The test suite is huge, and a big part of the following code will be inherited from it, to avoid you, dear readers, to do the same annoying task. &lt;code&gt;sodium&lt;/code&gt; can simply be installed using the &lt;code&gt;dart pub add sodium&lt;/code&gt; command in your current project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;dart pub add sodium
&lt;span class="go"&gt;Resolving dependencies... 
Downloading packages... 
+ archive 4.5.2
+ code_assets 2.1.0
+ csslib 1.0.2
+ freezed_annotation 3.1.0
+ hooks 2.2.0
+ html 0.15.7
+ json_annotation 4.12.0
+ posix 6.5.2
+ record_use 1.1.1
+ sodium 4.1.2
Changed 10 dependencies!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following code can easily be copy/pasted, but you should probably not do it. Keep in mind those are simply examples for some use case. Cryptography is an hard topic requiring years of experiences to do something secure. So, be really careful with my code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bootstrapping
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;sodium&lt;/code&gt; package offers 2 APIs, the "normal" one called &lt;code&gt;Sodium&lt;/code&gt; and the "sumo" one, called &lt;code&gt;SodiumSumo&lt;/code&gt;. In fact, it seems to matter ONLY if you plan to create a JavaScript/WEB application. In this case, you will need to chose the correct API depending of your needs and based on the &lt;a href="https://github.com/Skycoder42/libsodium_dart_bindings/tree/main/packages/sodium#api-status" rel="noopener noreferrer"&gt;API status table&lt;/a&gt;. In most of the case, if you plan to create a 100% native application, the &lt;code&gt;SodiumSumo&lt;/code&gt; API should be enough. One can read more on the &lt;a href="https://github.com/Skycoder42/libsodium_dart_bindings/tree/main/packages/sodium#sodium-vs-sodiumsumo" rel="noopener noreferrer"&gt;APIs differences from the README&lt;/a&gt;. To import the &lt;code&gt;SodiumSumo&lt;/code&gt; API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:sodium/sodium_sumo.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the normal API is required for some reason, simply use this header, and remove the &lt;code&gt;Sumo&lt;/code&gt; part of the next command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:sodium/sodium.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the &lt;code&gt;sodium&lt;/code&gt; library needs to be &lt;a href="https://github.com/Skycoder42/libsodium_dart_bindings/tree/main/packages/sodium#loading-libsodium" rel="noopener noreferrer"&gt;initialized/loaded&lt;/a&gt;. Indeed, a global instance of this object is required, and can be created using the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/SodiumSumoInit-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;SodiumSumoInit&lt;/code&gt;&lt;/a&gt; class, with the help of the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/SodiumSumoInit-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;init()&lt;/code&gt;&lt;/a&gt; constructor. It should return an instance of &lt;code&gt;SodiumSumoFFI&lt;/code&gt; object (an instance of &lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/SodiumSumo-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;SodiumSumo&lt;/code&gt;&lt;/a&gt; class).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;SodiumSumoInit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sodium: &lt;/span&gt;&lt;span class="si"&gt;$sodium&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"version: &lt;/span&gt;&lt;span class="si"&gt;${sodium.version}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"randombytes: &lt;/span&gt;&lt;span class="si"&gt;${sodium.randombytes}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"runtimeType: &lt;/span&gt;&lt;span class="si"&gt;${sodium.runtimeType}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let check that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;dart run
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;sodium: Instance of 'SodiumSumoFFI'
version: 1.0.22
randombytes: Instance of 'RandombytesFFI'
runtimeType: SodiumSumoFFI
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neat. It seems our main object is ready to do a bit of encryption/decryption.&lt;/p&gt;

&lt;h1&gt;
  
  
  PRNG
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://libsodium.gitbook.io/" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; has been created with portability and security in mind. It embeds its own &lt;a href="https://en.wikipedia.org/wiki/Pseudorandom_number_generator" rel="noopener noreferrer"&gt;PRNG&lt;/a&gt;, but will the one exposed by the operating system if any. For example, on most of the Linux/Unix operating system, it will read the &lt;a href="https://manpages.debian.org/trixie/manpages/urandom.4.en.html" rel="noopener noreferrer"&gt;&lt;code&gt;/dev/urandom&lt;/code&gt;&lt;/a&gt; file. If you are using &lt;a href="https://www.openbsd.org/" rel="noopener noreferrer"&gt;OpenBSD&lt;/a&gt; (like me), it will probably use &lt;a href="https://man.openbsd.org/arc4random.3" rel="noopener noreferrer"&gt;&lt;code&gt;arc4random&lt;/code&gt;&lt;/a&gt; instead. The &lt;code&gt;sodium&lt;/code&gt;&amp;nbsp;Dart implementation requires an instance of the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Randombytes-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;Randombytes&lt;/code&gt;&lt;/a&gt; object.&lt;/p&gt;

&lt;p&gt;The first method to test will be the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Randombytes/random.html" rel="noopener noreferrer"&gt;&lt;code&gt;random()&lt;/code&gt;&lt;/a&gt; one, and it will return a random integer. In the code below, 8 random integers are generated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randombytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;random&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"random: &lt;/span&gt;&lt;span class="si"&gt;$random&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;random: [1516676843, 4096214122, 3177965578, 2291181405, 4245144458, 3289700635, 106475476, 1321601073]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next method that can be used is to return an uniform random integer (inside a range) and is called &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Randombytes/uniform.html" rel="noopener noreferrer"&gt;&lt;code&gt;uniform()&lt;/code&gt;&lt;/a&gt;. In the following code, 8 uniform random numbers are generated. The output should contain integer between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1023&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;randomUniform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randombytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"randomUniform: &lt;/span&gt;&lt;span class="si"&gt;$randomUniform&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;randomUniform: [322, 681, 185, 1000, 297, 457, 376, 872]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is also possible to generate list of random integers using the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Randombytes/buf.html" rel="noopener noreferrer"&gt;&lt;code&gt;buf()&lt;/code&gt;&lt;/a&gt; method. The code snippet below will generate 8 random numbers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;randomBuf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randombytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"randomBuf: &lt;/span&gt;&lt;span class="si"&gt;$randomBuf&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;randomBuf: [241, 28, 11, 77, 198, 128, 177, 157]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://libsodium.gitbook.io/" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; is also offering a way to generate random numbers from a custom seed. It can be useful for many scenario, including testing. To do that the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Randombytes/bufDeterministic.html" rel="noopener noreferrer"&gt;&lt;code&gt;bufDeterministic&lt;/code&gt;&lt;/a&gt; method can be used, where the first argument is the length of the list returned, and the second is the seed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;seed1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;deterministicBuf1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randombytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bufDeterministic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"seed1: &lt;/span&gt;&lt;span class="si"&gt;$seed1&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"deterministicBuf: &lt;/span&gt;&lt;span class="si"&gt;$deterministicBuf1&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;seed2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;deterministicBuf2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randombytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bufDeterministic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"seed2: &lt;/span&gt;&lt;span class="si"&gt;$seed2&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"deterministicBuf: &lt;/span&gt;&lt;span class="si"&gt;$deterministicBuf2&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;deterministicBuf1: [161, 31, 143, 18, 208, 135, 111, 115]
deterministicBuf2: [61, 161, 61, 31, 87, 207, 88, 221]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same seed should always output the same random number. This MUST BE set to 32 bytes (a list of 32 integers), if it's not the case, it will throw a &lt;code&gt;RangError&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;RangeError (seed): Only allowed value is 32, but was: 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to create test with reproducible output from &lt;code&gt;sodium&lt;/code&gt;, the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Randombytes/seedBytes.html" rel="noopener noreferrer"&gt;&lt;code&gt;seedBytes&lt;/code&gt;&lt;/a&gt; attribute can be used.&lt;/p&gt;

&lt;p&gt;Finally the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Randombytes/stir.html" rel="noopener noreferrer"&gt;&lt;code&gt;stir()&lt;/code&gt;&lt;/a&gt; method is more or less related to any kind of custom PRNG that could have been created by the developer. It will reseed the generator, like defined in the &lt;a href="https://libsodium.gitbook.io/doc/generating_random_data" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; documentation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Generic Hash Function (BLAKE2b)
&lt;/h1&gt;

&lt;p&gt;Hashes are another important tools to have when dealing with encryption, and authentication. The official &lt;a href="https://pub.dev/packages/crypto" rel="noopener noreferrer"&gt;&lt;code&gt;crypto&lt;/code&gt;&lt;/a&gt; package created by the Dart team already offers a great support for the most used algorithms, including MD5, SHA1, SHA2 and HMAC (only for a subset of the algorithms previously listed). On the other hand, &lt;a href="https://libsodium.gitbook.io/doc/hashing/generic_hashing" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; selected the &lt;a href="https://www.rfc-editor.org/rfc/rfc7693.txt" rel="noopener noreferrer"&gt;&lt;code&gt;BLAKE2b&lt;/code&gt;&lt;/a&gt; hash function to be its generic one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.blake2.net/" rel="noopener noreferrer"&gt;BLAKE2&lt;/a&gt; is a modern hash function specified in &lt;a href="https://tools.ietf.org/html/rfc7693" rel="noopener noreferrer"&gt;RFC7693&lt;/a&gt;. BLAKE2b is an optimized version of BLAKE2 for 64 bits platform and can create output from 1 to 64 bytes. The reference implementation in pure-C is available on the official BLAKE2 &lt;a href="https://github.com/BLAKE2/BLAKE2" rel="noopener noreferrer"&gt;Github repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An hash can be created in two ways with &lt;code&gt;sodium&lt;/code&gt;. The first one is by using the instance present in the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Crypto/genericHash.html" rel="noopener noreferrer"&gt;&lt;code&gt;sodium.crypto.genericHash&lt;/code&gt;&lt;/a&gt; as a function (see the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/GenericHash/call.html" rel="noopener noreferrer"&gt;&lt;code&gt;call()&lt;/code&gt;&lt;/a&gt; method). The code snippet bellow will return the BLAKE2b hash of the string "test", with a 32 bytes (256 bits) output encoded in &lt;a href="https://api.flutter.dev/flutter/dart-convert/base64-constant.html" rel="noopener noreferrer"&gt;&lt;code&gt;Base64&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;message1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;hash1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;genericHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;message1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;outLen:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hash1: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(hash1)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;hash1: kosgNmlD4q/RHrwOri5TqTvxd6T881vMZNUDcE5l4gI=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same can also be done using a &lt;code&gt;Stream&lt;/code&gt; object via the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/GenericHash/stream.html" rel="noopener noreferrer"&gt;&lt;code&gt;stream()&lt;/code&gt;&lt;/a&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;message2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;hash2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;genericHash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;messages:&lt;/span&gt; &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromFuture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message2&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="nl"&gt;outLen:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hash2: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(hash2)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;hash2: kosgNmlD4q/RHrwOri5TqTvxd6T881vMZNUDcE5l4gI=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both results are identical, like expected from a hash function using the same input. &lt;code&gt;libsodium&lt;/code&gt; is also giving access to &lt;a href="https://libsodium.gitbook.io/doc/advanced/sha-2_hash_function" rel="noopener noreferrer"&gt;SHA-2&lt;/a&gt; and &lt;a href="https://libsodium.gitbook.io/doc/advanced/sha-3_hash_function" rel="noopener noreferrer"&gt;SHA-3&lt;/a&gt; hash functions. Unfortunately, it seems the Dart implementation is not offering an interface to them. If you need them, the &lt;a href="https://pub.dev/packages/crypto" rel="noopener noreferrer"&gt;&lt;code&gt;crypto&lt;/code&gt;&lt;/a&gt; package will be required.&lt;/p&gt;

&lt;h1&gt;
  
  
  Short Input Hash Function (SipHash-2-4)
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://libsodium.gitbook.io/" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; can use more specific hash functions. For example, when it comes to small input, a classic hash function can be a problem. It is useful for internal data-structure and algorithm. &lt;a href="https://github.com/veorq/SipHash" rel="noopener noreferrer"&gt;SipHash-2-4&lt;/a&gt; is the default algorithm used here.&lt;/p&gt;

&lt;p&gt;To create a digest, one can use the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Crypto/shortHash.html" rel="noopener noreferrer"&gt;&lt;code&gt;ShortHash&lt;/code&gt;&lt;/a&gt; object instance from the main sodium object, called &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Crypto/shortHash.html" rel="noopener noreferrer"&gt;&lt;code&gt;shortHash&lt;/code&gt;&lt;/a&gt;. This object is implementing the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/ShortHash/call.html" rel="noopener noreferrer"&gt;&lt;code&gt;call()&lt;/code&gt;&lt;/a&gt; and then, can be used as a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SecureKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;smallInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromList&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;smallHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shortHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;smallInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(key.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"smallInput: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(smallInput)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"smallHash: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(smallHash)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;key: tbaaEL+9ztfX000L54FlDw==
smallInput: AAAAAA==
smallHash: baRxJQlLnXg=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More information about this hash (and its usage) can be found on the official &lt;a href="https://libsodium.gitbook.io/doc/hashing/short-input_hashing" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt; documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Extendable Output Functions (Shake and TurboShake)
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://libsodium.gitbook.io/" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; also offers &lt;a href="https://libsodium.gitbook.io/doc/hashing/xof" rel="noopener noreferrer"&gt;Extendatable Output Functions (XOF)&lt;/a&gt;, these functions can be configured to return a flexible output size. A &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Xof-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;Xof&lt;/code&gt;&lt;/a&gt; object instance of each of these algorithms can be found on the main &lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/SodiumSumo-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;sodium&lt;/code&gt;&lt;/a&gt; object instance created during the initialization part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Crypto/xofShake128.html" rel="noopener noreferrer"&gt;&lt;code&gt;xofShake128&lt;/code&gt;&lt;/a&gt; for &lt;a href="https://eprint.iacr.org/2026/2080" rel="noopener noreferrer"&gt;Shake128&lt;/a&gt; algorithm;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Crypto/xofShake256.html" rel="noopener noreferrer"&gt;&lt;code&gt;xofShake256&lt;/code&gt;&lt;/a&gt; for the Shake256 algorithm&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Crypto/xofTurboshake128.html" rel="noopener noreferrer"&gt;&lt;code&gt;xofTurboshake128&lt;/code&gt;&lt;/a&gt; for the &lt;a href="https://eprint.iacr.org/2023/342" rel="noopener noreferrer"&gt;TurboShake128&lt;/a&gt; algorithm;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Crypto/xofTurboshake256.html" rel="noopener noreferrer"&gt;&lt;code&gt;xofTurboshake256&lt;/code&gt;&lt;/a&gt; for the &lt;a href="https://eprint.iacr.org/2023/342" rel="noopener noreferrer"&gt;TurboShake256&lt;/a&gt; algorithm.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let have a look at the Shake128 function first. An instance of a  can be found in the initialized &lt;code&gt;sodium&lt;/code&gt; object created at the beginning of this post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;xofShake128Input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromList&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;xofShake128Output8&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;xofShake128&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;xofShake128Input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;outLen:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;xofShake128Output32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;xofShake128&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;xofShake128Input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;outLen:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;xofShake128Output64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;xofShake128&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;xofShake128Input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;outLen:&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"xofShake128Input: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(xofShake128Input)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"xofShake128Output8: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(xofShake128Output8)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"xofShake128Output32: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(xofShake128Output32)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"xofShake128Output64: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(xofShake128Output64)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;xofShake128Input: AAAAAA==
xofShake128Output8: j5cMpCyEnKA=
xofShake128Output32: j5cMpCyEnKAMSPiNiDgMV0j0Lc9SkIgAHcUmt12xu74=
xofShake128Output64: j5cMpCyEnKAMSPiNiDgMV0j0Lc9SkIgAHcUmt12xu74TNSTXBo+lx6AI6GKH1Mc7+qGNds7/V7XPqcJ1ArqOvA==
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the output is flexible, and the first part will always be the same (a propriety of XOF). Let check that with the TurboShake256 algorithm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;xofTurboshake256Input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromList&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;xofTurboshake256Output8&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;xofTurboshake256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;xofTurboshake256Input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;outLen:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;  
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;xofTurboshake256Output32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;xofTurboshake256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;xofTurboshake256Input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;outLen:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="p"&gt;);&lt;/span&gt;  
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;xofTurboshake256Output64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;xofTurboshake256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;xofTurboshake256Input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;outLen:&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="p"&gt;);&lt;/span&gt;  
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"xofTurboshake256Input: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(xofTurboshake256Input)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"xofTurboshake256Output8: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(xofTurboshake256Output8)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"xofTurboshake256Output32: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(xofTurboshake256Output32)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"xofTurboshake256Output64: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(xofTurboshake256Output64)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;xofTurboshake256Input: AAAAAA==
xofTurboshake256Output8: /kSBXrzATNM=
xofTurboshake256Output32: /kSBXrzATNNdtXhOHkidRkpZ9IOK3jeHTWo+Zr1/pfg=
xofTurboshake256Output64: /kSBXrzATNNdtXhOHkidRkpZ9IOK3jeHTWo+Zr1/pfj20vK3er1FEbuD12Chmf11GTTi8VVe+OPfW3Tom3cI4w==
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More information regarding these algorithms can be seen on the &lt;a href="https://libsodium.gitbook.io/doc/hashing/xof" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt; xof documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Password Hashing (Argon2)
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://libsodium.gitbook.io/" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; offers an implementation of the &lt;a href="https://en.wikipedia.org/wiki/Argon2" rel="noopener noreferrer"&gt;Argon2&lt;/a&gt; algorithm, it can be an alternative to the &lt;a href="https://pub.dev/packages/argon2" rel="noopener noreferrer"&gt;argon2&lt;/a&gt; package. &lt;a href="https://en.wikipedia.org/wiki/Argon2" rel="noopener noreferrer"&gt;Argon2&lt;/a&gt; is a key derivativation function designed to be protected against brute-force; At this time, this is the recommended algorithm to store hashed password. &lt;a href="https://libsodium.gitbook.io/" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; gives us 2 versions of the algorithm, Argon2i and Argon2id, this last one is recommended by the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP team&lt;/a&gt;, but the default one used by &lt;code&gt;sodium&lt;/code&gt; is Argon2i. Anyway, let do some test here.&lt;/p&gt;

&lt;p&gt;To create a new hash, the already created instance of the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/Pwhash-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;Pwhash&lt;/code&gt;&lt;/a&gt; object in &lt;code&gt;sodium.crypto.pwhash&lt;/code&gt; can be used and the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/Pwhash/str.html" rel="noopener noreferrer"&gt;&lt;code&gt;str()&lt;/code&gt;&lt;/a&gt;&amp;nbsp;can be invoked. It will return a formatted string containing the functions parameters and the random salt generated automatically. The &lt;code&gt;opsLimit&lt;/code&gt;&amp;nbsp;represents the amount of computations to use (more CPU usage) and the &lt;code&gt;memLimit&lt;/code&gt; represents the amount of memory in bytes to allocate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"secret_password"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;hashedPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pwhash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;password:&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;opsLimit:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;memLimit:&lt;/span&gt; &lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;resultValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pwhash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strVerify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;passwordHash:&lt;/span&gt; &lt;span class="n"&gt;hashedPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;password:&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;resultInvalid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pwhash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strVerify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;passwordHash:&lt;/span&gt; &lt;span class="n"&gt;hashedPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;password:&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hashedPassword: &lt;/span&gt;&lt;span class="si"&gt;$hashedPassword&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"resultValid: &lt;/span&gt;&lt;span class="si"&gt;$resultValid&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"resultInvalid: &lt;/span&gt;&lt;span class="si"&gt;$resultInvalid&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;hashedPassword: $&lt;/span&gt;argon2id&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;19&lt;span class="nv"&gt;$m&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8,t&lt;span class="o"&gt;=&lt;/span&gt;1024,p&lt;span class="o"&gt;=&lt;/span&gt;1&lt;span class="nv"&gt;$PfWonIyaTiDh0mhyUT55UA$Y63dvkUjVtKYnvBSdzstDN0QIhyi6xcba83efmMaa7I&lt;/span&gt;
&lt;span class="go"&gt;resultValid: true
resultInvalid: false
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/Pwhash-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;Pwhash&lt;/code&gt;&lt;/a&gt; object exposes properties to know the limitations of these values, here a list of some of them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/Pwhash/memLimitInteractive.html" rel="noopener noreferrer"&gt;&lt;code&gt;memLimitInteractive&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/Pwhash/memLimitMax.html" rel="noopener noreferrer"&gt;&lt;code&gt;memLimitMax&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/Pwhash/memLimitMin.html" rel="noopener noreferrer"&gt;&lt;code&gt;memLimitMin&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/Pwhash/opsLimitInteractive.html" rel="noopener noreferrer"&gt;&lt;code&gt;opsLimitInteractive&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/Pwhash/opsLimitMax.html" rel="noopener noreferrer"&gt;&lt;code&gt;opsLimitMax&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/Pwhash/opsLimitMin.html" rel="noopener noreferrer"&gt;&lt;code&gt;opsLimitMin&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want other flavor like Argon2id13, the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/Pwhash/callStr.html" rel="noopener noreferrer"&gt;&lt;code&gt;callStr()&lt;/code&gt;&lt;/a&gt; can be used instead but it will require new parameters, like the length of the output, a random salt and the name of the algorithm to use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;salt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randombytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;hashPasswordBis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pwhash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;callStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;outLen:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;password:&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;salt:&lt;/span&gt; &lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;opsLimit:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;memLimit:&lt;/span&gt; &lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;alg:&lt;/span&gt; &lt;span class="n"&gt;CryptoPwhashAlgorithm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;argon2id13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"salt: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(salt)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hashPasswordBis: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(hashPasswordBis.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;salt: NAf4uZwlge7mm1kwT5pTZw==
hashPasswordBis: e47DIsAic0Tx9S1g/gIItsrCcf0WpLEaiIj8Jbzn1cneVfPz8w7PH50WmEbj2+kPUZFxgtZdyfRVsjP/N8l521BMxwxAA/hPWFz9a5qM4+BhaKFStMVl5JHQnq+P48ucYTTH7dNwoXe6KuyvR4/gI2kYYdzYQOnymeOzdZxl9Ipz85CfFSJD4S40zuGGLqzL/He2Edabnny1W2PFfBHQoBP1k7egv/b2ZoHVayAWyxOaRHbQ5wrsVIRzliKmG9x8bgDyq/sqP/M+MV2cdD8h5spPq6PFq88+KKAuXD4XORbnSocmCw84oqaOcscubsEcPOnMVhJYEAJIRgytDTlpHjgWNykNahQAkiLBp+UkLQx+pmVAwDG47zyTsEQmyjeAgVL+yVqRFPfT6m5hKJLVXC7wrttR/flDqh+TUgVrZ3FS6rQBOaJA6E4yc9IC/JSVO95UrsBRGABYd5K9tYJccOrEpbb3Rx69dPKw66RWUn8WIxeRB0yf+BiqD1xx6Mqp4axRmvSFTZmLV3Pz9fkXZqYDjGpucytLevUDmumtoHbP3dobuRk0lxhIIFDLfqx2cvymumnByePpwmnTC+1AXw83EX+NBMOzKcXPGVepGONNt0HnT3riW99+kBmRDDPmeHINT7I3k4VsAcWexRxdRHuGCbg9CjxQ4kzLD5DWdibS+FtivhR8D2UWgaH3QZGmNxYpslyhhzCNVcNGO+vgNVH3omyUh7gAbC/oMCL0j1u9u3he4sXBKfCERs5YACIHB7YHVEFTvgZHFfk78SNq4zyNQWfPeMlTGVLrshsOM5BjcTuUg8EJ6AnwiUVkygdSYih1wIX48jwprPW+K53SEig2exm4S6jbl4L65W/+9Ciaue9gobGQVN7zlL2+H9FopLdU+ieMXQJhIGemVZqL3+Geq1KoOm2H4ufJ9olyNbzry8cxZQpgFSdIAfqicgIYeJpBmH8Rdn4C0J9L/I6khDE+Ew63oVuw/Uk6xahYUnQDtveQG86A13F+p459DiSxQR7sJjNvUuSlKHkFWLF9qTU4wGmgzoiBIHCro9KZGegKA2H92kdQP1j+EhPxBeeeiQu/X59Miq+hDiMm0sqt4bIOra+lKBJJ8/T/Ly6VHU6NYvt0JozqazXkmFSh6rj0tfOWuZqmlRpn+OQPoWnLvPurm3iIVo+q3OS9QnZcpCKgrxQr3aJ3NBI5PnoYxslnWJUjwC9FCRTesYqmrMXjk09XCFmF+p96VqhYTXJ1hB3yu70fgFcARvY4jJocnqTfN9UBzGvWRWjK+lZDc/4imQRrbMlCzKxSVgnQKHZRjbG/xpMramlZxqn9WJ8SC3vgI2nZN7RpmCOrm9B7AAboNw==
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the output is an &lt;code&gt;Uint8List&lt;/code&gt; and not a formatted &lt;code&gt;String&lt;/code&gt;. Unfortunately, in this mode, it is not possible to generate the Unix-like format. The &lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/CryptoSumo/pwhash.html" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt; official documentation&lt;/a&gt; contains more information on this feature.&lt;/p&gt;

&lt;h1&gt;
  
  
  Symmetric Encryption (chacha20-Poly1305)
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;sodium&lt;/code&gt; is offering 3 algorithms, all of them based on the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Aead-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;Aead&lt;/code&gt;&lt;/a&gt; class&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Crypto/aeadAegis256.html" rel="noopener noreferrer"&gt;Aegis256&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Crypto/aeadChaCha20Poly1305.html" rel="noopener noreferrer"&gt;Chacha2020-Poly1305&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Crypto/aeadXChaCha20Poly1305IETF.html" rel="noopener noreferrer"&gt;XChaCha20Poly1305&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A message can be encrypted using the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Aead/encrypt.html" rel="noopener noreferrer"&gt;&lt;code&gt;encrypt()&lt;/code&gt;&lt;/a&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my message"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randombytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;SecureKey&lt;/span&gt; &lt;span class="n"&gt;keyAead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SecureKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aeadChaCha20Poly1305&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;nonce:&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;keyAead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"message: &lt;/span&gt;&lt;span class="si"&gt;$message&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(key.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"encrypted: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(encrypted)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;message: [109, 121, 32, 109, 101, 115, 115, 97, 103, 101]
key: GkjKYnsKNITUsROWYOiujw==
encrypted: SsldZX2XkQqcRTgiqyP0KH97Yz/YkQ1BIE8=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ciphertext produced by the previous method can be decrypted using the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Aead/decrypt.html" rel="noopener noreferrer"&gt;&lt;code&gt;decrypt()&lt;/code&gt;&lt;/a&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aeadChaCha20Poly1305&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;cipherText:&lt;/span&gt; &lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;nonce:&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;keyAead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"decrypted: &lt;/span&gt;&lt;span class="si"&gt;${utf8.decode(decrypted)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;decrypted: my message
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing really fancy here, the interface is quite easy to use. Be careful regarding the nonce and the key to use though, both of them are important and must be configured accordingly.&lt;/p&gt;

&lt;h1&gt;
  
  
  Public Key Generation
&lt;/h1&gt;

&lt;p&gt;This post was - at first - created to understand how public key generation was done with &lt;code&gt;sodium&lt;/code&gt;. Indeed, the Dart community does not really offer a lot of choice when it comes to encryption, and instead of using yet another library created from scratch (this is usually not a good idea in cryptography), the port to &lt;code&gt;libsodium&lt;/code&gt; looked way more safer and interesting.&lt;/p&gt;

&lt;p&gt;Anyway, &lt;a href="https://libsodium.gitbook.io/" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; is only supporting &lt;a href="https://ed25519.cr.yp.to/" rel="noopener noreferrer"&gt;Ed25519&lt;/a&gt; and &lt;a href="https://datatracker.ietf.org/doc/html/rfc7748#section-5" rel="noopener noreferrer"&gt;X25519&lt;/a&gt; algorithms. The first one is for authentication (signatured), the second is for key exchange. In both case, the method is the same to generate a pair of keys and then, return a &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/KeyPair-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;KeyPair&lt;/code&gt;&lt;/a&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;seedBytesPK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;seedBytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;secureRandomSeedPK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secureRandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seedBytesPK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;keyPair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;seedKeyPair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secureRandomSeedPK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"seedBytesPK: &lt;/span&gt;&lt;span class="si"&gt;$seedBytesPK&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"secureRandomSeedPK: &lt;/span&gt;&lt;span class="si"&gt;$secureRandomSeedPK&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"keyPair: &lt;/span&gt;&lt;span class="si"&gt;$keyPair&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"publicKey: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(keyPair.publicKey)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"secretKey: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(keyPair.secretKey.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;seedBytesPK: 32
secureRandomSeedPK: Instance of 'SecureKeyFFI'
keyPair: KeyPair(publicKey: [29, 132, 192, 107, 208, 25, 162, 211, 228, 70, 109, 169, 238, 124, 161, 248, 143, 24, 82, 64, 86, 39, 93, 254, 93, 54, 113, 62, 30, 145, 73, 50], secretKey: Instance of 'SecureKeyFFI')
publicKey: HYTAa9AZotPkRm2p7nyh+I8YUkBWJ13+XTZxPh6RSTI=
secretKey: /8SV7xv0ReOpTgau97cmmGZM5PdKSA13hbfxYYs0F1Q=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A keypair can also created using a seed via the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Box/seedKeyPair.html" rel="noopener noreferrer"&gt;&lt;code&gt;seedKeyPair&lt;/code&gt;&lt;/a&gt; method. More information can be found in the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Box-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;Box&lt;/code&gt;&lt;/a&gt; class documentation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Public Key Signature (Ed25519)
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;libsodium&lt;/code&gt; is using Ed25519 to sign messages with a private key. 3 modes of signatures have been defined by this library, &lt;a href="https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures#detached-mode" rel="noopener noreferrer"&gt;detached mode&lt;/a&gt;, &lt;a href="https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures#combined-mode" rel="noopener noreferrer"&gt;combined mode&lt;/a&gt; and &lt;a href="https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures#multi-part-messages" rel="noopener noreferrer"&gt;multi-part messages mode&lt;/a&gt;. All of them have been ported to &lt;code&gt;sodium&lt;/code&gt; via the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Sign-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;Sign&lt;/code&gt;&lt;/a&gt; class.&lt;/p&gt;

&lt;p&gt;Before using these modes, it is also necessary to understand the key generation process. One can sign a message by generating a new random key when calling the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Sign/keyPair.html" rel="noopener noreferrer"&gt;&lt;code&gt;keyPair()&lt;/code&gt;&lt;/a&gt; method, or derive a new key from an existing one using the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Sign/seedKeyPair.html" rel="noopener noreferrer"&gt;&lt;code&gt;seedKeyPair()&lt;/code&gt;&lt;/a&gt; method. For example, to derive a key from the keypair generated in the previous section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newSeedBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;seedBytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newSecureRandomSeed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secureRandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newSeedBytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newKeyPair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;seedKeyPair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newSecureRandomSeed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;derivedKeyPair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sign&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;seedKeyPair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newKeyPair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"newSeedBytes: &lt;/span&gt;&lt;span class="si"&gt;$newSeedBytes&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"newSecureRandomSeed: &lt;/span&gt;&lt;span class="si"&gt;$newSecureRandomSeed&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"newKeyPair: &lt;/span&gt;&lt;span class="si"&gt;$newKeyPair&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"derivedKeyPair: &lt;/span&gt;&lt;span class="si"&gt;$derivedKeyPair&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"derivedKeyPair.publicKey: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(derivedKeyPair.publicKey)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"derivedKeyPair.secretKey: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(derivedKeyPair.secretKey.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;newSeedBytes: 32
newSecureRandomSeed: Instance of 'SecureKeyFFI'
newKeyPair: KeyPair(publicKey: [17, 113, 139, 202, 227, 188, 47, 55, 65, 155, 129, 183, 29, 22, 170, 28, 186, 137, 114, 114, 10, 130, 235, 100, 124, 126, 64, 156, 63, 99, 192, 108], secretKey: Instance of 'SecureKeyFFI')
derivedKeyPair: KeyPair(publicKey: [12, 10, 30, 205, 0, 239, 115, 167, 34, 206, 106, 197, 126, 152, 34, 58, 162, 79, 75, 239, 76, 73, 249, 136, 211, 66, 86, 31, 187, 16, 201, 200], secretKey: Instance of 'SecureKeyFFI')
derivedKeyPair.publicKey: DAoezQDvc6cizmrFfpgiOqJPS+9MSfmI00JWH7sQycg=
derivedKeyPair.secretKey: S1dqHYqlbEO39PGZM1rY6smO/34FgEGKw7cq2G/HNy4MCh7NAO9zpyLOasV+mCI6ok9L70xJ+YjTQlYfuxDJyA==
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The combined mode is prepending the signature to the message. To sign a message with this mode, the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Sign/call.html" rel="noopener noreferrer"&gt;&lt;code&gt;call()&lt;/code&gt;&lt;/a&gt; method is used, and to validate the message, the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Sign/open.html" rel="noopener noreferrer"&gt;&lt;code&gt;open()&lt;/code&gt;&lt;/a&gt; method is required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;messageCombined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;signatureCombined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;messageCombined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;secretKey:&lt;/span&gt; &lt;span class="n"&gt;randomKeyPair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"signatureCombined: &lt;/span&gt;&lt;span class="si"&gt;$signatureCombined&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"signatureCombined: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(signatureCombined)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;verifyCombined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sign&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;signedMessage:&lt;/span&gt; &lt;span class="n"&gt;signatureCombined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;publicKey:&lt;/span&gt; &lt;span class="n"&gt;randomKeyPair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"verifyCombined: &lt;/span&gt;&lt;span class="si"&gt;$verifyCombined&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"verifyCombined: &lt;/span&gt;&lt;span class="si"&gt;${utf8.decode(verifyCombined)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;signatureCombined: [175, 80, 179, 20, 23, 55, 168, 83, 169, 53, 225, 232, 239, 10, 9, 101, 53, 236, 192, 245, 177, 194, 17, 42, 195, 100, 161, 72, 62, 172, 251, 39, 160, 26, 90, 165, 49, 158, 220, 169, 183, 149, 174, 209, 44, 85, 214, 189, 62, 246, 93, 249, 215, 40, 54, 32, 240, 150, 56, 78, 93, 23, 101, 7, 116, 101, 115, 116]
signatureCombined: r1CzFBc3qFOpNeHo7woJZTXswPWxwhEqw2ShSD6s+yegGlqlMZ7cqbeVrtEsVda9PvZd+dcoNiDwljhOXRdlB3Rlc3Q=
verifyCombined: [116, 101, 115, 116]
verifyCombined: test
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The detached mode produces a signature without altering the message. To sign the message, the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Sign/detached.html" rel="noopener noreferrer"&gt;&lt;code&gt;detached()&lt;/code&gt;&lt;/a&gt; method is invoked, and to verify it, the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Sign/verifyDetached.html" rel="noopener noreferrer"&gt;&lt;code&gt;verifyDetached()&lt;/code&gt;&lt;/a&gt; is called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;messageDetached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"message: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(messageDetached)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;signatureDetached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sign&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;detached&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;messageDetached&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;secretKey:&lt;/span&gt; &lt;span class="n"&gt;randomKeyPair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"signatureDetached: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(signatureDetached)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;verifyDetached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sign&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;verifyDetached&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;messageDetached&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;publicKey:&lt;/span&gt; &lt;span class="n"&gt;randomKeyPair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;signature:&lt;/span&gt; &lt;span class="n"&gt;signatureDetached&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"verifyDetached: &lt;/span&gt;&lt;span class="si"&gt;$verifyDetached&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;message: dGVzdA==
signatureDetached: r1CzFBc3qFOpNeHo7woJZTXswPWxwhEqw2ShSD6s+yegGlqlMZ7cqbeVrtEsVda9PvZd+dcoNiDwljhOXRdlBw==
verifyDetached: true
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the multi-part messages mode is used to sign/verify huge messages and is using a &lt;code&gt;Stream&lt;/code&gt; in the Dart implement. To sign a message in multi-part messages mode, the&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;messageMulti&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;signatureMulti&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sign&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;messages:&lt;/span&gt; &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromFuture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messageMulti&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="nl"&gt;secretKey:&lt;/span&gt; &lt;span class="n"&gt;randomKeyPair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"signatureMulti: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(signatureMulti)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;verifyMulti&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sign&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;verifyStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;messages:&lt;/span&gt; &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromFuture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messageMulti&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="nl"&gt;signature:&lt;/span&gt; &lt;span class="n"&gt;signatureMulti&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;publicKey:&lt;/span&gt; &lt;span class="n"&gt;randomKeyPair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"verifyMulti: &lt;/span&gt;&lt;span class="si"&gt;$verifyMulti&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;signatureMulti: KqgvmypphuUC0aLzZCQ56rQQ2CwidxdQFoBBlVDqLhvqiyQKZSbBvq76UsChFy9GLm+rM6ncBocevJHTthMNBg==
verifyMulti: true
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't hesitate to check the API documentation, especially the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium_sumo/SignSumo-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;SignSumo&lt;/code&gt;&lt;/a&gt; class and the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Sign/call.html" rel="noopener noreferrer"&gt;&lt;code&gt;call()&lt;/code&gt;&lt;/a&gt; method.&lt;/p&gt;

&lt;h1&gt;
  
  
  Public Key Encryption
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://libsodium.gitbook.io/" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; offers an easy interface to encrypt data with via a public key. In fact, it will use the public/private key to authenticate the message while a secret a shared between both part of the communication. The messages are then encrypted using the &lt;a href="https://libsodium.gitbook.io/doc/advanced/stream_ciphers/xsalsa20" rel="noopener noreferrer"&gt;XSalsa20&lt;/a&gt; stream cipher. Key pairs can be generated using the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Box/keyPair.html" rel="noopener noreferrer"&gt;&lt;code&gt;keyPair()&lt;/code&gt;&lt;/a&gt; method from a&lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Box-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;Box&lt;/code&gt;&lt;/a&gt; object instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kpAlice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;keyPair&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kpBob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;keyPair&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kpAlice: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(kpAlice.publicKey)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kpBob: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(kpBob.publicKey)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;kpAlice: UfVCLUDk7+W/8hdnGvGWXUAazrzhDmGJvx1b14ZTtRc=
kpBob: U9zxXl5KfUO3XcKNoLeYg/hZawnzjMIaLQ8kf01pNF8=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Box/easy.html" rel="noopener noreferrer"&gt;&lt;code&gt;easy()&lt;/code&gt;&lt;/a&gt; method can be invoked to create an encrypted payload containing all required information for the exchange.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;msg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello Bob!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nonce1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randombytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cipher1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;easy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;msg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;nonce:&lt;/span&gt; &lt;span class="n"&gt;nonce1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;publicKey:&lt;/span&gt; &lt;span class="n"&gt;kpBob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;secretKey:&lt;/span&gt; &lt;span class="n"&gt;kpAlice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"msg1: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(msg1)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nonce1: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(nonce1)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cipher1: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(cipher1)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;msg1: aGVsbG8gQm9iIQ==
nonce1: ACpqcCbUEGfeUtqF4qhjJhKLZ/56mJHh
cipher1: t0dIKRIlLxTX3Cp656DN/XgRy8rka9GApsw=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the reception of the message by the receiver, the clear text can be extracted using the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Box/openEasy.html" rel="noopener noreferrer"&gt;&lt;code&gt;openEasy()&lt;/code&gt;&lt;/a&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;recv1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;openEasy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;cipherText:&lt;/span&gt; &lt;span class="n"&gt;cipher1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;nonce:&lt;/span&gt; &lt;span class="n"&gt;nonce1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;publicKey:&lt;/span&gt; &lt;span class="n"&gt;kpAlice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;secretKey:&lt;/span&gt; &lt;span class="n"&gt;kpBob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"recv1: &lt;/span&gt;&lt;span class="si"&gt;${utf8.decode(recv1)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;recv1: hello Bob!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another exchange can be initiated using the same principle (for example to send a response to the previous message).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;msg2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hey alice"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nonce2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randombytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cipher2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;easy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;msg2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;nonce:&lt;/span&gt; &lt;span class="n"&gt;nonce2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;publicKey:&lt;/span&gt; &lt;span class="n"&gt;kpAlice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;secretKey:&lt;/span&gt; &lt;span class="n"&gt;kpBob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;msg2: SGV5IGFsaWNl
nonce2: XqvB6EwaF9GxPvSSM/TMuSkaXLmUfnDF
cipher2: q0fyatMRoWChE17eKUouJinJTqahCa8P3g==
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;recv2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;openEasy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;cipherText:&lt;/span&gt; &lt;span class="n"&gt;cipher2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;nonce:&lt;/span&gt; &lt;span class="n"&gt;nonce2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;publicKey:&lt;/span&gt; &lt;span class="n"&gt;kpBob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;secretKey:&lt;/span&gt; &lt;span class="n"&gt;kpAlice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"recv2: &lt;/span&gt;&lt;span class="si"&gt;${utf8.decode(recv2)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;recv2: Hey alice
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;libsodium&lt;/code&gt; is also offering a detached mode, it will give more flexibility when sending the information, instead of using a complete payload, the required information can be put in some other formats. To use this mode, the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Box/detached.html" rel="noopener noreferrer"&gt;&lt;code&gt;detached()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Box/openDetached.html" rel="noopener noreferrer"&gt;&lt;code&gt;openDetached()&lt;/code&gt;&lt;/a&gt; methods can be used.&lt;/p&gt;

&lt;p&gt;It is also possible to use a &lt;a href="https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes#usage" rel="noopener noreferrer"&gt;Sealed Box&lt;/a&gt; with the help of the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Box/seal.html" rel="noopener noreferrer"&gt;&lt;code&gt;seal()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Box/sealOpen.html" rel="noopener noreferrer"&gt;&lt;code&gt;sealOpen()&lt;/code&gt;&lt;/a&gt; methods. The idea is to make the exchange even more secure by always creating an ephemeral key.&lt;/p&gt;

&lt;p&gt;More information can be found on the &lt;a href="https://libsodium.gitbook.io/doc/public-key_cryptography/authenticated_encryption" rel="noopener noreferrer"&gt;official &lt;code&gt;libsodium&lt;/code&gt; documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Key Exchange
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;libsodium&lt;/code&gt; also offers some facilities to do &lt;a href="https://libsodium.gitbook.io/doc/key_exchange" rel="noopener noreferrer"&gt;key exchanges&lt;/a&gt; and &lt;a href="https://libsodium.gitbook.io/doc/key_derivation" rel="noopener noreferrer"&gt;key derivation&lt;/a&gt;. A keypair can be generate using the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kx/keyPair.html" rel="noopener noreferrer"&gt;&lt;code&gt;keyPair()&lt;/code&gt;&lt;/a&gt; method from an instance of a &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kx-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;Kx&lt;/code&gt;&lt;/a&gt; object or by deriving an existing key using the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kx/seedKeyPair.html" rel="noopener noreferrer"&gt;&lt;code&gt;seedKeyPair()&lt;/code&gt;&lt;/a&gt; method from the same instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;keyPair&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kpServer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;keyPair&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kpClient: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(kpClient.publicKey)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kpServer: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(kpServer.publicKey)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;kpClient: dPmBU3994tkERAjQUyD+ibo7rBFujq+ZV197l8FvwVU=
kpServer: 52FiQPJtOJkkBDoRoZYzC3ASjJDFsHu6SbeEP3jrswg=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A session can be started by sharing one's public key, signed with its private key, and by sharing a secret encrypted with the target public key. To do that, the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kx/clientSessionKeys.html" rel="noopener noreferrer"&gt;&lt;code&gt;clientSessionKeys()&lt;/code&gt;&lt;/a&gt; method can be used. It will return a &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/SessionKeys-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;SessionKeys&lt;/code&gt;&lt;/a&gt; object, containing the session keys to decrypt received data (&lt;a href="https://pub.dev/documentation/sodium/latest/sodium/SessionKeys/rx.html" rel="noopener noreferrer"&gt;&lt;code&gt;tx&lt;/code&gt;&lt;/a&gt; property) or encrypt (&lt;a href="https://pub.dev/documentation/sodium/latest/sodium/SessionKeys/tx.html" rel="noopener noreferrer"&gt;&lt;code&gt;tx&lt;/code&gt;&lt;/a&gt;) data to send.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;session1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clientSessionKeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;clientPublicKey:&lt;/span&gt; &lt;span class="n"&gt;kpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;clientSecretKey:&lt;/span&gt; &lt;span class="n"&gt;kpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;serverPublicKey:&lt;/span&gt; &lt;span class="n"&gt;kpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"session1: &lt;/span&gt;&lt;span class="si"&gt;$session1&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"session1.tx: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(session1.tx.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"session1.rx: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(session1.rx.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;session1: SessionKeys(rx: Instance of 'SecureKeyFFI', tx: Instance of 'SecureKeyFFI')
session1.tx: vzJw72Dib/qHhze9LOsUGwYxjFYNzWV3D6541pLMxZc=
session1.rx: r7QtsYaSFrydDg6ijk1mbNrvR3cVSJmFqMXVH3m2YV4=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous example was using the client API, but a server can also take the lead by creating its session via the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kx/serverSessionKeys.html" rel="noopener noreferrer"&gt;&lt;code&gt;serverSessionKeys()&lt;/code&gt;&lt;/a&gt; method. The same kind of object is returned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;session2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;serverSessionKeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;serverPublicKey:&lt;/span&gt; &lt;span class="n"&gt;kpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;serverSecretKey:&lt;/span&gt; &lt;span class="n"&gt;kpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;clientPublicKey:&lt;/span&gt; &lt;span class="n"&gt;kpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"session2: &lt;/span&gt;&lt;span class="si"&gt;$session2&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"session2.tx: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(session2.tx.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"session2.rx: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(session2.rx.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;session2: SessionKeys(rx: Instance of 'SecureKeyFFI', tx: Instance of 'SecureKeyFFI')
session2.tx: r7QtsYaSFrydDg6ijk1mbNrvR3cVSJmFqMXVH3m2YV4=
session2.rx: vzJw72Dib/qHhze9LOsUGwYxjFYNzWV3D6541pLMxZc=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating encrypted/authenticated sessions can be challenging, more information about this part can also be found on the &lt;a href="-%20https://libsodium.gitbook.io/doc/key_exchange"&gt;official &lt;code&gt;libsodium&lt;/code&gt; documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Public Key Encapsulation
&lt;/h1&gt;

&lt;p&gt;Secrets can also be shared using &lt;a href="https://libsodium.gitbook.io/doc/public-key_cryptography/key_encapsulation" rel="noopener noreferrer"&gt;key encapsulation mechanism&lt;/a&gt;. The idea is to share a secret with someone using public key cryptography. Firstly, let generate a key pair with the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kem/keyPair.html" rel="noopener noreferrer"&gt;&lt;code&gt;keyPair()&lt;/code&gt;&lt;/a&gt; method from a &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kem-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;Kem&lt;/code&gt;&lt;/a&gt; object instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;KeyPair&lt;/span&gt; &lt;span class="n"&gt;kpCarl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;keyPair&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kpCarl: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(kpCarl.publicKey)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;kpCarl: X0w77TyQOXGrhBQV/ypBYTYt6zx7kniSE4ttD1d+qKa8Wyt7nKZJXjFeAiI2tKh2KBHLR9J5QHSPOvIVy5q5ZXEVpnJL4rivkEcE+MKeqbGvsvaYv2iK3sN96ejMnWSMHBABucw+oJMMHUcnD5sHgLKtD6tDjwJkjnoIVlmNShzPiUHPinhdRIdPpEizBQsAYBo40Qwo0nAph8l6T7VoyOOCaLHJotGj/2Z3P7cqU6UUOIq6kUBkjPlKJ3e4Ojgd4whmNfg6HEQuxQvCMxfAyOWSKaZE9cETVDIy4WWIX1VDjmWNGISlEtaMwmdSbnVJB4pWNbAhbCZeJ3pWZoFP71Gy5yeH0tme+tg9S3C0CauNM5ZuevhVHfVeERZob1Ig7pEIRgB04qAW8kYlD9ZiMhWH/+PK8mQu3XxOiWUoCii3xdbLAsVvJfEUiAHDzzhzs4oerHe4WOEVGPAqjaGAvfNOEJYbC4NXL/NhRvenYcutteqMuKFDVuYo2gUZN9nEX/wzM2qNoLO2ByEi8kUkOmQgMXo8F3Y+P0woNZS6jYaBTip4ocuIP8N4YYRSEciJi+FcAK1PPGQ7kWNsNPFv2LVw8xl2DTFx8glsMsACz7wiSQgdWbkHzRkizKcLwSdYYdefz1FmaFaDL4wsXsAzjhaXvedG3Oou7OJtqHK9OwTL/DCWUZEavMCqqaqWYsxJZbol0qdhEWWL5hexm1GGzmYnCPNdsusKOOCItFUwQfB5v9qbBKCWOVBEN/dJ1scaT3cXhZaqrphT45R1EKgVKXCIwVxifDd7P9FwGlV7b1Acpfao00xtpha7DabC8NZkSoiHX2V8PnwveHUjBDqZUTIhlSZO71R2sBbB8kTC0YiU2PKgBspsf0ywenRHR8N0cFygn3a4LOCKMTd9kKUlbWbAi2o1QmtaaUwd7KfAXfShSwdt+murTOSgVjWi87sfhONml7tC4qDFo6SF5WI1nRFik5YexptOgteuRgVWkCpmVPJF1UJRMtaobzjDpGm+pfl2jDIHYml+XHMcHCkKy6KCnbxSj1MaAAyZLZI1nFbKHYpvYOLAsjQE1adf+TsfaOC7ydZ9ILp4QcxfzAFxlpiqVSyRmMiXhTdc4xQBoUEZnFM8IVcuy/Jec+pe1heu/UnA1zw0MtoB6SQ616RkAeq6zmuoRbKt/GgoQvyQq+tLfakFPcNAsdUU3/p/GeVkjXQa2Qx7M/osyrKmiUJvN7pNZ5lIe/VC9zpadLZnHoIODICIgqaIG4QFxLOdiTHP9hKB7dA4SmZxgJOn0Rl1nDBRAlIgvmiVW9lrPkO3cRGdDkE/3dGQppinn5OFxgjOtHFRJVi037hmuDaRZmW/OIiV8VCuTbkeCNUg3sUix8mxtxG0GrVsJypvMHY1DNWSV2soK4Mk/IjLUdUWImhhUeCudMBNaPINYiEJkQpd67g+YkuRXOlBy9djpRQjTQtaITVvwbbG3as9Q5RlunktEOQvqJg6zMK7i1Be/HFI4SLKqtxQg5ePYQhHIbUzppd1sweNpuDs+9XxRsxZKtUb2KjYeoKiltPFRojgHOr5Ik6yXD67oxPVMorCn3gZv8mMrPu5cg7vXiWnxXDuncdHEg==
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The public key can be then encrypted using the desired public key (the following example is wrong, the public key to use should have been another one, but the idea is the same). To encrypt the secret, the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kem/enc.html" rel="noopener noreferrer"&gt;&lt;code&gt;enc()&lt;/code&gt;&lt;/a&gt; method can be used, it will return a ciphertext that can be send to to the recipient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;KemEncResult&lt;/span&gt; &lt;span class="n"&gt;enc1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;publicKey:&lt;/span&gt; &lt;span class="n"&gt;kpCarl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"enc1.ciphertext: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(enc1.ciphertext)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"enc1.sharedSecret: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(enc1.sharedSecret.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;enc1.ciphertext: GgIpamj4uT72RQi1PYs8wyr5DJWGW2wAsU1tBxQIBPF4d4xke/Q3fL16FE0v5dLlF7Esvoq9DBVxSMLuGLM0xM95FU9Hz/nup6AZ2hpJEJLnzWWyw8lTMUmVmgttiKPiFCRGlaPeoZZCnofy7ccbPnST+0w3Pb0pknaxmAF6y4x6Q+Kp/u+1jbhRtx49Lb4gIWDqH3UAxWke5srjzyGnQkLBHtwsh1KIHtpFuk4KWcc5wHgZRfGHGTrim6bUZXoD6hz4KebEE4bNNEZtYDJyyME4p3sPKTLuvIBbUfJKfn3bl8rjbWBeTgDubFBoPs37PPIvg9xsJtdBRoynVoSEG6njTyNU3ZQNxbYTPgi5tVbwPpTkBwDaDc9roypNyu6QiBFVxrtSi1brsfQAeWXy2qO3PNySHhO0mcvpz27VmKE+UbaB+i93IkosxpD3TndnSkEODb0Dwzq544oTv588Qk1n02sTbEgIqofTFNjeJfyHJ3VVM/zEwKxA7lX9ud214XVZpzfLKj7AkoXlpX/0unZYUuyfyr/ooUZkvOu5cA9MBYiowZMTPNWddMkcRxCz2mRGFyZyiAGu6Xqwz8Mpv3b7Ci5r8OEZaOewke2d9XqXRSjkTEYi7hy/dVYSrX2e1STvfKxPdqtoNXCyfhg9IE+v8C0qcYgh4b34EDC1qg8BITUJl7KFFw111Qm+5B+BipVCjyttHQJUO6OoqMsDztc0NlO2kY37bI3mlU7SgHVTFEReqMHMpoIOoNWcPF6V7FwksllBkjdG5XR7bF6c0ShhQtrJViJv+wV0u7I4LtYCuHKoKnFM2+QEWMjJyrk5jpSErI3g2izscF/ku94wC3JeYUyou9gcz0u4xqMdoPBPdahZRjinmF6MzK5pY0mRhnbf6rLVkoxe5NCexmO4+ZddTEEivMx+ZCb+IYLfYfhIiWLMYYUni6MEs0hXTAv4ylS5u2JH0Ke/2YYsZ/Dj3g/zrMNPemp3IDLRSxvjWdZcF6oxP+X+tlOY/UBAiWpKFXPCTUthlH9u2KRNQX8inl4wQjqurXG4oAKqHl5SWEvTIaw6otfawZMffQIe4LjNLS/OCVZIchoFXU1KBxZX1w1Z8OW9zDIj17zYCYy5Gt+Rf0oYmqtjzq58/jQ+oggkPgj1Ey05b5XTlN2RFaID2IRJFNUMU/C0nRbpHcQJ36pS0by8UgWSHRY8Umb8u4dh6+k5zXM2X+1wEtf5SV/yN6dr7L11N7X1rHhrUuLf68Tvpuqnb0ecb3b0V5RziRC7J+NpvndDXEyqKXvZJJzOReq+mXLuc0J6qGdGpzKu7IqQwX0iKrlcTWrMNzXR667PrMnSxgMQJx7CeWHigXJGwWhWck5vhiNpy7YAZL3Awk153Zqgs0sJ+nSPVpSqkuLe1f1whfLxbiyMMQvE3KfXzYR4JY7hy5AkhKWXpehGaO+mtbxxN7+HK7n5ggKl74RO/Pl/+pPWtpEs8KfB8CY+Ng==
enc1.sharedSecret: LV6LjDbXe1v33jkOLx1YPAktFzgj2wAvQ+ns3RT6CPs=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The recipient receive the message and can decipher it using the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kem/dec.html" rel="noopener noreferrer"&gt;&lt;code&gt;dec()&lt;/code&gt;&lt;/a&gt; method. It will return the shared secret, previously generated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;SecureKey&lt;/span&gt; &lt;span class="n"&gt;dec1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;ciphertext:&lt;/span&gt; &lt;span class="n"&gt;enc1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;secretKey:&lt;/span&gt; &lt;span class="n"&gt;kpCarl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dec1: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(dec1.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;dec1: LV6LjDbXe1v33jkOLx1YPAktFzgj2wAvQ+ns3RT6CPs=
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of the time, the secret will be derived using a &lt;a href="https://libsodium.gitbook.io/doc/key_derivation" rel="noopener noreferrer"&gt;KDF&lt;/a&gt;, to do that, one can use &lt;a href="https://libsodium.gitbook.io/doc/key_derivation/hkdf" rel="noopener noreferrer"&gt;HKDF&lt;/a&gt; or the &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kdf/deriveFromKey.html" rel="noopener noreferrer"&gt;&lt;code&gt;deriveFromKey()&lt;/code&gt;&lt;/a&gt; method from a &lt;a href="https://pub.dev/documentation/sodium/latest/sodium/Kdf-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;KDF&lt;/code&gt;&lt;/a&gt; object instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;SecureKey&lt;/span&gt; &lt;span class="n"&gt;derivedKey1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deriveFromKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;masterKey:&lt;/span&gt; &lt;span class="n"&gt;dec1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;context:&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;subkeyId:&lt;/span&gt; &lt;span class="n"&gt;BigInt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;subkeyLen:&lt;/span&gt; &lt;span class="n"&gt;sodium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bytesMax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"derivedKey1: &lt;/span&gt;&lt;span class="si"&gt;$derivedKey1&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"derivedKey1: &lt;/span&gt;&lt;span class="si"&gt;${base64.encode(derivedKey1.extractBytes())}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;derivedKey1: Instance of 'SecureKeyFFI'
derivedKey1: n1a5LPoQ80DNK0Sd3wwf4WrcjtELvPhGF6O58sM6YDk7izyipRBLpsXls42vqZNzEOrB27xuPgplF4YRIgJIDQ==
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to check the official &lt;a href="https://libsodium.gitbook.io/" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt; documentation to have more information and study their examples.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;libsodium&lt;/code&gt;, like most of the cryptographic libraries, is not easy to use. Why using &lt;code&gt;sodium&lt;/code&gt; when other packets can offer a simpler interface? Well, because of its portability, working almost everywhere. To be honest, this library was also in my toolbox for many years (the javascript implementation), and was used on many of my personal projects, but the Dart interface feels... different.&lt;/p&gt;

&lt;p&gt;A big part of the functions available on &lt;code&gt;libsodium&lt;/code&gt; have been ported via FFI, and it's really a good thing to use modern cryptographic algorithms on a modern language. Some parts are missing though, for example, the function to encode correctly a password hash in the Unix-like format. The &lt;a href="https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_pwhash/argon2/argon2-encoding.c" rel="noopener noreferrer"&gt;source code is available from &lt;code&gt;libsodium&lt;/code&gt;&lt;/a&gt;, but it would have been nice to have it in the Dart implementation.&lt;/p&gt;

&lt;p&gt;I hope I will have more time to write a better post, with real use case.As usual, if you want to know a bit more about all of this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/packages/sodium/" rel="noopener noreferrer"&gt;&lt;code&gt;sodium&lt;/code&gt; package in Dart&lt;/a&gt; using FFI on pub.dev, where you will find the global information about the Dart implementation;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/packages/sodium/example" rel="noopener noreferrer"&gt;&lt;code&gt;sodium&lt;/code&gt; examples in Dart&lt;/a&gt; on pub.dev, where you will find few examples;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Skycoder42/libsodium_dart_bindings" rel="noopener noreferrer"&gt;&lt;code&gt;sodium&lt;/code&gt; source code&lt;/a&gt; on Github, where you will find the source code of the Dart package;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Skycoder42/libsodium_dart_bindings/blob/main/packages/sodium/test/" rel="noopener noreferrer"&gt;&lt;code&gt;sodium&lt;/code&gt;&amp;nbsp;test suite&lt;/a&gt; on Github, where you will find the test suite, quite useful to see more examples;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://libsodium.gitbook.io/doc" rel="noopener noreferrer"&gt;Official &lt;code&gt;libsodium&lt;/code&gt; documentation&lt;/a&gt;, where you will find the original documentation for the &lt;code&gt;libsodium&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/jedisct1/libsodium" rel="noopener noreferrer"&gt;&lt;code&gt;libsodium&lt;/code&gt; source code&lt;/a&gt; on Github, where you will find the pure-C &lt;code&gt;libsodium&lt;/code&gt; source code, especially useful if you want to check the vectors and other test suite;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nacl.cr.yp.to/" rel="noopener noreferrer"&gt;Official NaCl website&lt;/a&gt;, the original project from cr.yp.to, you should probably check, very instructive.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Always be careful when using cryptography in your code, try to reuse existing patterns and avoid creating your own stuff, it's most of the time a bad idea. &lt;/p&gt;

&lt;p&gt;But as always... Happy hacking and have fun!&lt;/p&gt;




&lt;p&gt;Cover image by &lt;a href="https://unsplash.com/@mariaspics?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Maria Petersson&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/brown-wooden-spoon-on-white-snow-OuvmgR815MQ?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>libsodium</category>
      <category>nacl</category>
      <category>cryptography</category>
      <category>dart</category>
    </item>
    <item>
      <title>WeeklyReview#202642</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Mon, 19 Oct 2026 10:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/weeklyreview202642-488o</link>
      <guid>https://dev.to/niamtokik/weeklyreview202642-488o</guid>
      <description>&lt;p&gt;While reading &lt;a href="https://xeiaso.net/shitposts/no-way-to-prevent-this/memory-safety/CVE-2026-92392/" rel="noopener noreferrer"&gt;&lt;em&gt;"No way to prevent this" say users of only language where this regularly happens&lt;/em&gt;&lt;/a&gt;, yet another complaining about C code, I was thinking... During the past 20 years, many solutions have been created, but only a few C developers are using them. More recently, the &lt;a href="https://fil-c.org/" rel="noopener noreferrer"&gt;fil-c&lt;/a&gt; was created to make C memory safe, hopefully it will be used in the future. The compilers are way better than 20 years ago, and for example, it is now possible to easily export the AST of any C project with clang/llvm. Even more, many compilers are now offering their own tools like static analyser to check the code. In fact, I was currently using few them to test my own pet project sandbox, and it's amazingly pleasant to code with all the flags and all those tools. So, why should we rewrite everything in rust, go or any other "modern" language if the AST is available, and we have ways to convert existing C/C++ code into a safer binary version?&lt;/p&gt;

&lt;p&gt;Let's go back to the article, the &lt;a href="https://curl.se/docs/CVE-2026-92392.html" rel="noopener noreferrer"&gt;CVE-2026-92392&lt;/a&gt; is an use after free bug, a classical mistake anyone do at least one time in its developer life. &lt;a href="https://fil-c.org/" rel="noopener noreferrer"&gt;fil-c&lt;/a&gt; fixes that, but let's go a bit deeper. C is known to be an interface to low-level language (assembly) and will let you do whatever you want, it means the memory management must be done manually, like any other resources. It's a complex task, and can become a nightmare when dealing with concurrency. Why not using a pattern above that, always in charge to deal with those resources... Oh, wait, it's a kind of garbage collector, right? Or perhaps a kind of state machine, where the state is a resource that can be opened, used or closed. Anyway, adding another layer will increase the complexity of the existing code, but using something like fil-c could really help a lot.&lt;/p&gt;




&lt;p&gt;A part of my free-time was dedicated to find design inspiration with Flutter. Thanks to &lt;a href="https://flutterawesome.com" rel="noopener noreferrer"&gt;Flutter Awesome&lt;/a&gt;, a long list of open-source Flutter projects can be checked! Here a quick list with the ones I liked the most &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/alperefesahin/flutter_social_chat" rel="noopener noreferrer"&gt;&lt;code&gt;flutter_social_chat&lt;/code&gt;&lt;/a&gt;: A simple chat compatible with iOS and Android. The design is really cool.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/OstrichGram/OstrichGram" rel="noopener noreferrer"&gt;&lt;code&gt;OstrichGram&lt;/code&gt;&lt;/a&gt;: a desktop (linux/windows) Nostr client.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/droperr/dash_chat_2.1" rel="noopener noreferrer"&gt;&lt;code&gt;dash_chat_2.1&lt;/code&gt;&lt;/a&gt;: an interesting library with many reusable widgets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Hamad-Anwar/Flutter-Music-Player-App-With-BLoc" rel="noopener noreferrer"&gt;&lt;code&gt;Flutter-Music-Player-App-With-BLoc&lt;/code&gt;&lt;/a&gt;: I like the clean MVC organization of this application and the fact there is no route defined, only a navigator pushing screen between context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Suzefa/bloc_flutter_app" rel="noopener noreferrer"&gt;&lt;code&gt;bloc_flutter_app&lt;/code&gt;&lt;/a&gt;: another example application using the Bloc pattern.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I was playing with the Erlang ssh key interface with Elixir (I wrote an article on that in a French magazine on this topic, but with Erlang). Let generate a public/private key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ssh-keygen &lt;span class="nt"&gt;-f&lt;/span&gt; t.key &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;Your identification has been saved in t.key 
Your public key has been saved in t.key.pub 
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file t.key.pub
&lt;span class="go"&gt;t.key.pub: OpenSSH ED25519 public key
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we can use parse and validate it. We are using the &lt;a href=""&gt;&lt;code&gt;:ssh_message&lt;/code&gt;&lt;/a&gt;&lt;a href="https://github.com/erlang/otp/blob/master/lib/ssh/src/ssh_message.erl" rel="noopener noreferrer"&gt;https://github.com/erlang/otp/blob/master/lib/ssh/src/ssh_message.erl&lt;/a&gt; Erlang module (undocumented) and the &lt;a href="https://www.erlang.org/doc/apps/public_key/public_key.html" rel="noopener noreferrer"&gt;&lt;code&gt;:public_key&lt;/code&gt;&lt;/a&gt; Erlang module to convert it from one format to another one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# open the file, it can also from any kind of String.()&lt;/span&gt;
&lt;span class="c1"&gt;# element&lt;/span&gt;
&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/t.key.pub"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Split the key with null char, it should returns a list&lt;/span&gt;
&lt;span class="c1"&gt;# of 4 elements&lt;/span&gt;
&lt;span class="c1"&gt;#   ["ssh-ed25519", pubkey, comment, ""]&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="no"&gt;Regex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;~r"\s+"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 

&lt;span class="c1"&gt;# Returns only the pubkey&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# SSH public key is base64 encoded, decode it.&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode64!&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# parse the result with ssh2_pubkey_decode/1 function.&lt;/span&gt;
&lt;span class="c1"&gt;# it returns something like that:&lt;/span&gt;
&lt;span class="c1"&gt;#   {{:ECPoint, ecpoint}, {:namedCurve, {1, 3, 101, 112}}}&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:ssh_message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ssh2_pubkey_decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# this part is to convert it in PEM format (TLS)&lt;/span&gt;
&lt;span class="c1"&gt;# the firs step is to create an entry with the correct&lt;/span&gt;
&lt;span class="c1"&gt;# ASN1 type (e.g :SubjectPublicKeyInfo)&lt;/span&gt;
&lt;span class="c1"&gt;#   {:SubjectPublicKeyInfo, pubkey, :not_encrypted}&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:public_key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pem_entry_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:SubjectPublicKeyInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# the final step is to finalize the PEM encoding&lt;/span&gt;
&lt;span class="c1"&gt;#   "-----BEGIN PUBLIC KEY-----\nbase64\n-----END PUBLIC KEY-----\n\n"&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:public_key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pem_encode&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Coding
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://dthain.github.io/books/compiler/compilerbook.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Introduction to Compilers and Language Design, Second Edition&lt;/strong&gt;&lt;/a&gt;: what a great book! It covers all compiling steps, from scanning, parsing, code generation and optimization.&lt;/p&gt;

&lt;p&gt;📖 &lt;a href="https://sdiehl.github.io/write-you-a-haskell/" rel="noopener noreferrer"&gt;&lt;strong&gt;Write You a Haskell&lt;/strong&gt;&lt;/a&gt;: yet another book in Haskell.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://eliasebner.com/blog/guides/arena-allocators-in-c/" rel="noopener noreferrer"&gt;&lt;strong&gt;Arena Allocators in C&lt;/strong&gt;&lt;/a&gt;: implementing memory allocators in C can be challenging, here a nice article on how to write one using &lt;a href="https://en.wikipedia.org/wiki/Region-based_memory_management" rel="noopener noreferrer"&gt;region-based memory management&lt;/a&gt; technique or arena allocator&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://eyereasoner.github.io/eyelang/" rel="noopener noreferrer"&gt;&lt;strong&gt;eyelang&lt;/strong&gt;&lt;/a&gt;: An experimental symbolic logic programming language using a practical subset of Prolog syntax and .pl files, with query explanations and executable checks.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://ash-hq.org/blog/concentrated-liability/" rel="noopener noreferrer"&gt;&lt;strong&gt;Concentrated Liability&lt;/strong&gt;&lt;/a&gt;: a security audit report on Ash framework using LLMs.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://eliasebner.com/blog/guides/generic-dynamic-arrays-in-c/" rel="noopener noreferrer"&gt;&lt;strong&gt;Generic Dynamic Arrays in C&lt;/strong&gt;&lt;/a&gt;: Another great article by Eliase Ebner.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://eliasebner.com/blog/guides/fixing-strings-in-c/" rel="noopener noreferrer"&gt;&lt;strong&gt;Why C Strings Suck And How I Fixed Them&lt;/strong&gt;&lt;/a&gt;: A good way to fix C strings. I like it.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://eliasebner.com/blog/thoughts/advice-for-software-developers-with-large-language-models/" rel="noopener noreferrer"&gt;&lt;strong&gt;Some Advice for Software Developers in the Age of Large Language Models&lt;/strong&gt;&lt;/a&gt;: This post has many good points regarding LLM, especially the quote below. Indeed, I already saw that in a previous position, someone losing many weeks of developing, switching and switching between LLMs to solve a problem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;what are you going to do when the LLM reaches its limit [...] and you are left having to solve the issue on your own? Ask a different LLM? And if that fails? Who are you going to turn to?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;📝 &lt;a href="https://eliasebner.com/blog/guides/c-sockets-from-scratch/" rel="noopener noreferrer"&gt;&lt;strong&gt;C Socket Programming in Linux: Build a TCP Client &amp;amp; Server (Complete Guide)&lt;/strong&gt;&lt;/a&gt;: this blog has really nice article! A must read for the one who wants to learn more about C programming!&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://www.cphof.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Competitive Programming Hall Of Fame&lt;/strong&gt;&lt;/a&gt;:  a project created to preserve the history of international championships in competitive programming. This website collects the results of final stages for both worldwide and regional contests. By international championship we mean a contest consisting of several stages available for competitors from more than one country.&lt;/p&gt;

&lt;h1&gt;
  
  
  System
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://vermaden.wordpress.com/2026/10/10/freebsd-cope-with-signal-fuckup/" rel="noopener noreferrer"&gt;&lt;strong&gt;FreeBSD Cope with Signal Fuckup&lt;/strong&gt;&lt;/a&gt;: installing signal on FreeBSD using chrooted environment. It would have been better to use a jail there, but it looks okay.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://cybersect.substack.com/p/we-can-harden-c" rel="noopener noreferrer"&gt;&lt;strong&gt;We can harden C&lt;/strong&gt;&lt;/a&gt;: why talking about rust or IA, again? If you want to increase the security of you C application, the first step is to enable all warnings and errors, but also all security features offered by your favorite compiler. It will less fun - because the compiler will blame you for every weird stuff you are doing - be the result will be way better. The next step is to ALWAYS code in C with the help of a small test suite framework like &lt;a href="https://nemequ.github.io/munit/" rel="noopener noreferrer"&gt;&lt;code&gt;munit&lt;/code&gt;&lt;/a&gt; or &lt;a href="//github.com/siu/minunit/tree/master"&gt;&lt;code&gt;minunit&lt;/code&gt;&lt;/a&gt;. Easy to install and easy to use, it will easier to create your tests and design your application. Finally, don't forget to use the modern tools available on &lt;a href="https://gcc.gnu.org/" rel="noopener noreferrer"&gt;&lt;code&gt;gcc&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://llvm.org/" rel="noopener noreferrer"&gt;&lt;code&gt;llvm&lt;/code&gt;&lt;/a&gt;, like &lt;a href="https://clang-analyzer.llvm.org/" rel="noopener noreferrer"&gt;static analyzers&lt;/a&gt;. Not everything will be fixed though, and if you need a really strong application, you should check the security features offered by FreeBSD (&lt;a href="https://man.freebsd.org/cgi/man.cgi?query=capsicum" rel="noopener noreferrer"&gt;capsicum&lt;/a&gt;), OpenBSD (&lt;a href="https://man.openbsd.org/pledge" rel="noopener noreferrer"&gt;pledge&lt;/a&gt;, &lt;a href="https://man.openbsd.org/unveil" rel="noopener noreferrer"&gt;unveil&lt;/a&gt;) or Linux. Anyway, C hardening can be challenging, not because of the complexity, but more because of our ignorance about all the tools available.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.opensourceprojects.dev/post/buildah" rel="noopener noreferrer"&gt;&lt;strong&gt;Building OCI Images Without a Daemon or a Dockerfile&lt;/strong&gt;&lt;/a&gt;: how to build OCI image from scratch, here the repository on &lt;a href="https://github.com/podman-container-tools/buildah" rel="noopener noreferrer"&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://internals-for-interns.com/posts/linux-kernel-namespaces/" rel="noopener noreferrer"&gt;&lt;strong&gt;Understanding the Linux Kernel: Namespaces&lt;/strong&gt;&lt;/a&gt;: yet another article on the namespaces.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://hackaday.com/2026/10/12/your-computer-memory-is-a-lie/" rel="noopener noreferrer"&gt;&lt;strong&gt;Your Computer Memory Is A Lie&lt;/strong&gt;&lt;/a&gt;: a post doing a summary of the problems involving memory (in general).&lt;/p&gt;

&lt;h1&gt;
  
  
  Database
&lt;/h1&gt;

&lt;p&gt;📑 &lt;a href="https://arxiv.org/pdf/2610.12692" rel="noopener noreferrer"&gt;&lt;strong&gt;Distributed Datalog at Scale with Worst-Case Optimal Joins&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/gmr/pglifecycle" rel="noopener noreferrer"&gt;&lt;strong&gt;pglifecycle&lt;/strong&gt;&lt;/a&gt;:  keeps your database schema in a version-controlled project of YAML files — one file per database object, validated against a JSON-Schema contract — and moves schema between the repository and live databases.&lt;/p&gt;

&lt;h1&gt;
  
  
  security
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://calif.io/research/big-fish" rel="noopener noreferrer"&gt;&lt;strong&gt;Big Fish: Exploiting a 37-Year-Old Kernel Bug in OpenBSD&lt;/strong&gt;&lt;/a&gt;: an interesting report about one of the security issues recently published on OpenBSD. This is a nasty issue, present there for more than 3 decades.&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://zr.ax/" rel="noopener noreferrer"&gt;&lt;strong&gt;zr.ax&lt;/strong&gt;&lt;/a&gt;: classifies executables and raw firmware, with interactive Hilbert entropy maps, a hex inspector, and batch analysis. via &lt;a href="https://x.com/in19h/status/2109069625862570330?s=20" rel="noopener noreferrer"&gt;Kenan Sulayman&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://binsec.no/posts/2026/10/one-root-case" rel="noopener noreferrer"&gt;&lt;strong&gt;Azure's Weakest Link - Five Full Cross-Tenant Compromises&lt;/strong&gt;&lt;/a&gt;: oof. a violent and nasty security issue on azure cloud that can extract user secret via a craft URL encoded path.&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://www.usenix.org/conference/woot16/workshop-program/presentation/spisak" rel="noopener noreferrer"&gt;&lt;strong&gt;Hardware-Assisted Rootkits: Abusing Performance Counters on the ARM and x86 Architectures&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://royfish.dev/fingerprints-are-the-new-cookies" rel="noopener noreferrer"&gt;&lt;strong&gt;Fingerprints are the new cookies&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://hackers-arise.com/confessions-of-a-professional-hacker-can-the-cia-or-other-intelligence-agencies-track-my-every-move-2/" rel="noopener noreferrer"&gt;&lt;strong&gt;Confessions of a Professional Hacker: Can the CIA or other Intelligence Agencies Track My Every Move?&lt;/strong&gt;&lt;/a&gt;: yes. Any state agencies with enough resources can track anybody without any problem. It's becoming very hard to be protected against that, even without any digital devices, you are becoming a target.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://adepts.of0x.cc/eufy-homestation2-firmware/" rel="noopener noreferrer"&gt;&lt;strong&gt;A story of wifi secrets, UART lockdowns and a damaged flash memory chip&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/alphafox02/openwrt-one-sdr" rel="noopener noreferrer"&gt;&lt;strong&gt;openwrt-one-sdr&lt;/strong&gt;&lt;/a&gt;: Turns an OpenWrt One router into a wideband, receive-only software-defined receiver. The board's MediaTek MT7981B Wi-Fi SoC (with an MT7976 radio front end) captures raw 14-bit IQ from the 2.4 and 5 GHz bands at 40 Msps, the dual Cortex-A53 streams it over the 2.5 GbE port as VITA 49, and a Linux host shows it as a live spectrum and waterfall in the browser.&lt;/p&gt;

&lt;h1&gt;
  
  
  Security/Cryptography
&lt;/h1&gt;

&lt;p&gt;🌐 &lt;a href="https://ecdsa.fail/" rel="noopener noreferrer"&gt;&lt;strong&gt;ecdsa.fail&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Security/Red-Team
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/dinosn/exploit-watch-archive" rel="noopener noreferrer"&gt;&lt;strong&gt;exploit-watch-archive&lt;/strong&gt;&lt;/a&gt;: durable, private aggregation of the exploit/PoC source repos tracked by the exploit-watch monitoring task.&lt;/p&gt;

&lt;h1&gt;
  
  
  Embedded
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://hackaday.com/2026/10/13/the-fpga-chronicles-ready-to-probe/" rel="noopener noreferrer"&gt;&lt;strong&gt;The FPGA Chronicles: Ready To Probe&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://hackaday.com/2026/10/15/another-wireless-chip-has-a-hidden-sdr-revealed/" rel="noopener noreferrer"&gt;&lt;strong&gt;Another Wireless Chip Has A Hidden SDR Revealed&lt;/strong&gt;&lt;/a&gt;: some ESP32 chips are embedding SDR feature. It looks provising.&lt;/p&gt;

&lt;h1&gt;
  
  
  Update/Upgrade
&lt;/h1&gt;

&lt;p&gt;🔄 &lt;a href="https://x.com/abraxas_null/status/2110120094810693729?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;OpnSense&lt;/strong&gt;&lt;/a&gt;: 7 remote exploits. Some of them looks really dangerous, please update.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/opnsense-firmware-mirror-sed" rel="noopener noreferrer"&gt;opnsense-firmware-mirror-sed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/opnsense-tunables-loader/" rel="noopener noreferrer"&gt;opnsense-tunables-loader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/opnsense-uidfield-system-uid0" rel="noopener noreferrer"&gt;opnsense-uidfield-system-uid0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/opnsense-ntp-gps-fudge" rel="noopener noreferrer"&gt;opnsense-ntp-gps-fudge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/opnsense-wlan-wpa-line" rel="noopener noreferrer"&gt;opnsense-wlan-wpa-line&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/opnsense-captive-lastseen-roam" rel="noopener noreferrer"&gt;opnsense-captive-lastseen-roam&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/opnsense-tunables-loader" rel="noopener noreferrer"&gt;opnsense-tunables-loader&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔄 &lt;a href="https://x.com/abraxas_null/status/2110041481365057758?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;pfSense&lt;/strong&gt;&lt;/a&gt;: pfSense seems to have been impacted as well.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/pfsense-qinq-parent-if" rel="noopener noreferrer"&gt;pfsense-qinq-parent-if&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/pfsense-openvpn-wizard-crlf" rel="noopener noreferrer"&gt;pfsense-openvpn-wizard-crlf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/pfsense-limiter-number" rel="noopener noreferrer"&gt;pfsense-limiter-number&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/pfsense-carp-vhid" rel="noopener noreferrer"&gt;pfsense-carp-vhid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abraxas/pfsense-ipsec-login-banner" rel="noopener noreferrer"&gt;pfsense-ipsec-login-banner&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔄 &lt;a href="https://github.com/erlang/otp/releases/tag/OTP-29.1.2" rel="noopener noreferrer"&gt;&lt;strong&gt;Erlang/OTP 29.1.2&lt;/strong&gt;&lt;/a&gt;: bugs and security fixes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Leaks of the week
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/blog/fuite-de-donnees-chez-meta-1-500-personnes-touchees-apres-un-piratage-sur-github" rel="noopener noreferrer"&gt;&lt;strong&gt;Meta&lt;/strong&gt;&lt;/a&gt;: 1500 people impacted after github repositories hacked.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/blog/noms-numeros-de-secu-conversations-medicales-ce-que-revele-le-piratage-de-maquestionmedicale" rel="noopener noreferrer"&gt;&lt;strong&gt;MaQuestionMedicale&lt;/strong&gt;&lt;/a&gt;: 96000 people impacted, 369k private messages, with name, phone number, and more.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/alertes/solutions-30-mv5nto6keh511e3t4k7" rel="noopener noreferrer"&gt;&lt;strong&gt;Solution30&lt;/strong&gt;&lt;/a&gt;: more than 10millions identifiers impacted, 11 millions phone number, 2 millions e-mail address.&lt;/p&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/H4ckmanac/status/2110981593758056679?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;Canva&lt;/strong&gt;&lt;/a&gt;: 200 millions database rows including enterprise license, and orders.&lt;/p&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/H4ckmanac/status/2110686001337127028?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;Sourcenext Corporation&lt;/strong&gt;&lt;/a&gt;: 22.5 millions customer records including name, phone numbers, e-mail addresses, passwords, postal address...&lt;/p&gt;

&lt;h1&gt;
  
  
  Misc
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://lkml.org/lkml/2026/10/13/3242" rel="noopener noreferrer"&gt;&lt;strong&gt;I don't understand this whole idiotic concept of "don't use AI for X".&lt;/strong&gt;&lt;/a&gt;: The problem is not the LLM/AI per se, but where the computation is made. A compiler and most of the software a developer is using are hosted on their own laptop or on a server they are owning. The result is their own binaries, on their own infrastructure. Today, most - if not all - LLMs are being used through big companies (e.g. Google, Microsoft, Apple, Meta, Anthropic and so on), where the definition of "freedom of usage" is globally incompatible with open-source software. Yes this is a tool, but a tool one is using remotely, on servers no one controls. That's crazy someone like Torvalds does not understand that. When local-LLMs will be working correctly, I think it will be huge win for the open-source world, but for now, this is a future trap.&lt;/p&gt;




&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2109301986189324775-605" src="https://platform.twitter.com/embed/Tweet.html?id=2109301986189324775"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2109301986189324775-605');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2109301986189324775&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/gmkurtzer/status/2109302135846555882?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4w6xzbvxdh20lxyv06zw.png" alt=" " width="598" height="858"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/johnennis/status/2108958121133510760?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftdnqp4nr8gy2gyocn7qk.png" alt=" " width="598" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/a_musingcat/status/2109447042460479703?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn8ei05xr5luuh1hhgm3k.png" alt=" " width="598" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/msimoni/status/2109349273234231676?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frfsr3u90kijdn768690v.png" alt=" " width="598" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/CodeWisdom/status/2109597719983517740?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F02zjhhhmvm3g4g1xhe32.png" alt=" " width="598" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/mcnabbd/status/2109341118550991034?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fztx4m03o290ob82quoua.png" alt=" " width="598" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/jiratickets/status/2109764284972679404?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fon2k5wbqvbhtdbw2u390.png" alt=" " width="598" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/badcop_/status/2110083558215975161?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc4eynfmwfgsw463v824w.png" alt=" " width="598" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/aiandcloud/status/2110164468244140205?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjnzfxa983801xzen8gzm.png" alt=" " width="598" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/herrmann1001/status/2110199064822489351?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd6fyn71uuyxvsqtdpldm.png" alt=" " width="598" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/chrisbanes/status/2109919479388160087?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fstqtxkmuqahrr2xcseoa.png" alt=" " width="598" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/CodeWisdom/status/2110340681759658408?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcvzvlebp168iakg7v69b.png" alt=" " width="598" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/OfMikeAndMen/status/2110708163112759448?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fce32ovyq6vjgdw0dmgqx.png" alt=" " width="598" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F488hbgbf41g866c97ly9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F488hbgbf41g866c97ly9.png" alt=" " width="598" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/ThePrimeagen/status/2111100293941219644?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5eoghuubjaldlc74org3.png" alt=" " width="598" height="576"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5fnpi6kcf1rexujcpipt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5fnpi6kcf1rexujcpipt.png" alt=" " width="675" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcrehlkd0c3qnnm60tkgp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcrehlkd0c3qnnm60tkgp.png" alt=" " width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffeo651hs1demadi7byic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffeo651hs1demadi7byic.png" alt=" " width="680" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fet4weo7mur2dty19hmaq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fet4weo7mur2dty19hmaq.png" alt=" " width="500" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F44b3qmein49q7v2ld82r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F44b3qmein49q7v2ld82r.png" alt=" " width="658" height="680"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Cover Image by &lt;a href="https://unsplash.com/@freestocks?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;freestocks&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/pumpkin-between-lighted-candles-kVv8AvoKJ7g?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>weekly</category>
      <category>review</category>
    </item>
    <item>
      <title>Q&amp;D: Using WebView with Flutter</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Thu, 15 Oct 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/qd-using-webview-with-flutter-2379</link>
      <guid>https://dev.to/niamtokik/qd-using-webview-with-flutter-2379</guid>
      <description>&lt;p&gt;Your website is already working well, compatible with mobile device? Why recreating the wheel, and simply recreate your application around the &lt;a href="https://developer.android.com/reference/android/webkit/WebView" rel="noopener noreferrer"&gt;&lt;code&gt;WebView&lt;/code&gt;&lt;/a&gt; feature? The idea is simple, use the native Android (or iOS) browser inside your application. It will not fix everything though, but you will be able to reuse your website without rewriting everything from scratch.&lt;/p&gt;

&lt;p&gt;Another purpose of &lt;code&gt;WebView&lt;/code&gt; objects is to create an interface to a platform without public API. Indeed, with &lt;code&gt;WebView&lt;/code&gt; you will have access to a real web browser capabilities, including executing requests on a remote service, storing cookies or executing Javascript script. on Dart/Flutter, the &lt;code&gt;webview_flutter&lt;/code&gt; package is required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;flutter pub add webview_flutter
&lt;span class="go"&gt;Resolving dependencies... 
Downloading packages... 
  cupertino_icons 1.0.9 (2.0.0 available)
  material_color_utilities 0.13.0 (0.13.1 available)
  meta 1.18.3 (1.19.0 available)
+ plugin_platform_interface 2.1.8
  test_api 0.7.12 (0.7.15 available)
  vector_math 2.4.2 (2.4.3 available)
+ webview_flutter 4.14.1
+ webview_flutter_android 4.14.1
+ webview_flutter_platform_interface 2.15.1
+ webview_flutter_wkwebview 3.27.0
Changed 5 dependencies!
5 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;WebView&lt;/code&gt; objects are objects to display web content (usually website) inside an application. This kind of object can be found on &lt;a href="https://developer.android.com/reference/android/webkit/WebView" rel="noopener noreferrer"&gt;Android&lt;/a&gt; and on &lt;a href="https://developer.apple.com/documentation/webkit/wkwebview" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;, both implementation offering similar (but not perfectly identical) features. When one &lt;code&gt;WebView&lt;/code&gt; object is instantiated, it can be used like a browser where a part of its interfaces are exposed to the application.&lt;/p&gt;

&lt;p&gt;The best way to demonstrate this is to create a &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewController-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;WebViewController&lt;/code&gt;&lt;/a&gt; object. The one presented in the example should do the job for now (with few modification):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewController/setJavaScriptMode.html" rel="noopener noreferrer"&gt;&lt;code&gt;setJavaScriptMode&lt;/code&gt;&lt;/a&gt; method is called, it can be set to &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/JavaScriptMode.html#disabled" rel="noopener noreferrer"&gt;&lt;code&gt;disabled&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/JavaScriptMode.html#unrestricted" rel="noopener noreferrer"&gt;&lt;code&gt;unrestricted&lt;/code&gt;&lt;/a&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewController/setNavigationDelegate.html" rel="noopener noreferrer"&gt;&lt;code&gt;setNavigationDelegate&lt;/code&gt;&lt;/a&gt; method is called, and a &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/NavigationDelegate-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;NavigationDelegate&lt;/code&gt;&lt;/a&gt; object is created. This last one is used to accept or reject the navigation changes. The following callback functions can be configured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/NavigationDelegate/onNavigationRequest.html" rel="noopener noreferrer"&gt;&lt;code&gt;onNavigationRequest&lt;/code&gt;&lt;/a&gt;: executed to accept/deny navigation;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/NavigationDelegate/onPageFinished.html" rel="noopener noreferrer"&gt;&lt;code&gt;onPageFinished&lt;/code&gt;&lt;/a&gt;: executed when the page is fully loaded;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/NavigationDelegate/onPageStarted.html" rel="noopener noreferrer"&gt;&lt;code&gt;onPageStarted&lt;/code&gt;&lt;/a&gt;: executed when the page loading started;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/NavigationDelegate/onProgress.html" rel="noopener noreferrer"&gt;&lt;code&gt;onProgress&lt;/code&gt;&lt;/a&gt;: executed during the page loading progression;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/NavigationDelegate/onWebResourceError.html" rel="noopener noreferrer"&gt;&lt;code&gt;onWebResourceError&lt;/code&gt;&lt;/a&gt;: executed when an error occurs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewController/clearCache.html" rel="noopener noreferrer"&gt;&lt;code&gt;cacheClear&lt;/code&gt;&lt;/a&gt; method is called: use the remove the cache from the &lt;code&gt;WebView&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewController/clearLocalStorage.html" rel="noopener noreferrer"&gt;&lt;code&gt;clearLocalStorage&lt;/code&gt;&lt;/a&gt; method is called: used to clear the local storage from the &lt;code&gt;WebView&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewController/loadRequest.html" rel="noopener noreferrer"&gt;&lt;code&gt;loadRequest&lt;/code&gt;&lt;/a&gt; method is called: used to load an URL.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;WebViewController&lt;/span&gt; &lt;span class="nf"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'https://authenticationtest.com/simpleFormAuth/'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// parse an URL from a string&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Return a WebViewController Object with custom callbacks&lt;/span&gt;
  &lt;span class="c1"&gt;// and parameters&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;WebViewController&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// set the javascript mode to unrestricted (javascript&lt;/span&gt;
    &lt;span class="c1"&gt;// can be executed)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setJavaScriptMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JavaScriptMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unrestricted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// configure the authorized navigation pattern&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNavigationDelegate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;NavigationDelegate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;

        &lt;span class="c1"&gt;// a progression gauge can be created if necessary&lt;/span&gt;
        &lt;span class="nl"&gt;onProgress:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"loading in progress (&lt;/span&gt;&lt;span class="si"&gt;$progress&lt;/span&gt;&lt;span class="s"&gt;)..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="c1"&gt;// when the connection to the page start&lt;/span&gt;
        &lt;span class="nl"&gt;onPageStarted:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"page start to be loaded (&lt;/span&gt;&lt;span class="si"&gt;$url&lt;/span&gt;&lt;span class="s"&gt;)."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="c1"&gt;// when the page is totally loaded&lt;/span&gt;
        &lt;span class="nl"&gt;onPageFinished:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"page loaded successfully (&lt;/span&gt;&lt;span class="si"&gt;$url&lt;/span&gt;&lt;span class="s"&gt;)."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="n"&gt;showCookies&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="c1"&gt;// what to do in case of error&lt;/span&gt;
        &lt;span class="nl"&gt;onHttpError:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpResponseError&lt;/span&gt; &lt;span class="n"&gt;error&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="c1"&gt;// this callback is used to select what kind of request&lt;/span&gt;
        &lt;span class="c1"&gt;// is allowed (to which website).&lt;/span&gt;
        &lt;span class="nl"&gt;onNavigationRequest:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NavigationRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;NavigationDecision&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}))&lt;/span&gt;

    &lt;span class="c1"&gt;// when a new object is created, clear up the cache&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clearCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// clear also the local storage&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clearLocalStorage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// and finally, load the requested url&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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;With this future object created, it is possible to include it in the flutter tree. To that, one can use a &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewWidget-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;WebViewWidget&lt;/code&gt;&lt;/a&gt; object, with the previous controller passed as argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;backgroundColor:&lt;/span&gt; 
        &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;colorScheme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inversePrimary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="n"&gt;Expanded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;WebViewWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;controller:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&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="p"&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;Some variable states can eventually store the reference of the current controller, initialized in the &lt;a href="https://api.flutter.dev/flutter/widgets/State/initState.html" rel="noopener noreferrer"&gt;&lt;code&gt;initState()&lt;/code&gt;&lt;/a&gt; method. This code was defined inside a &lt;a href="https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;StatefulWidget&lt;/code&gt;&lt;/a&gt; Widget.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;WebViewController&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="n"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;_controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;controller&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;Here the log output during the loading. Yeah, the &lt;code&gt;authenticationtest.com&lt;/code&gt; was used to retrieve some session cookies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;I/flutter (19018): page start to be loaded (https://authenticationtest.com/simpleFormAuth/).
I/flutter (19018): loading in progress (20)...
I/flutter (19018): loading in progress (20)...
I/flutter (19018): loading in progress (29)...
I/flutter (19018): loading in progress (70)...
I/flutter (19018): loading in progress (87)...
I/flutter (19018): loading in progress (100)...
I/flutter (19018): loading in progress (100)...
I/flutter (19018): loading in progress (100)...
I/flutter (19018): page loaded successfully (https://authenticationtest.com/simpleFormAuth/)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cookies from the &lt;code&gt;WebView&lt;/code&gt; can also be retrieved (and if needed stored in a local store). This can be achieved by created a new &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewCookieManager-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;WebViewCookieManager&lt;/code&gt;&lt;/a&gt; object. After having been successfully instantiated, the cookies can be exported using the &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewCookieManager/getCookies.html" rel="noopener noreferrer"&gt;&lt;code&gt;getCookies()&lt;/code&gt;&lt;/a&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;WebViewController&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="n"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;_controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;_cookieManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebViewCookieManager&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;showCookies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;currentUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;currentUrl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;Uri&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tryParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;cookies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_cookieManager&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;getCookies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;domain:&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookies&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;Here the log output when some cookies have been received from the website. Those cookies are using the &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewCookie-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;WebViewCookie&lt;/code&gt;&lt;/a&gt; object, containing 4 fields, &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewCookie/name.html" rel="noopener noreferrer"&gt;&lt;code&gt;name&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewCookie/value.html" rel="noopener noreferrer"&gt;&lt;code&gt;value&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewCookie/domain.html" rel="noopener noreferrer"&gt;&lt;code&gt;domain&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewCookie/path.html" rel="noopener noreferrer"&gt;&lt;code&gt;path&lt;/code&gt;&lt;/a&gt;. The other cookies attributes like &lt;code&gt;expires&lt;/code&gt; are not available on Android (but it seems they can be found on iOS).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;I/flutter (19018): [WebViewCookie{name: PHPSESSID, value: 8035d936660419d25f1969de60945682, domain: https://authenticationtest.com/simpleFormAuth/, path: /}]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here a screenshot of the &lt;code&gt;WebView&lt;/code&gt; from the Android emulator. Few buttons have been added to do tests, like extract the cookies and save same in a permanent store, or switch to another URL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frbt24bgfuk8t8kqycuz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frbt24bgfuk8t8kqycuz7.png" alt="WebView Flutter Screenshot from Android Application" width="800" height="1778"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WebView&lt;/code&gt;&amp;nbsp;is a really interesting feature to bypass some website limitations, especially the one with public API only. Collecting those cookies can then be reused afterward. Some of you would probably ask why I was playing with this package. Well, I needed to fetch some cookies from another website (not the one used here for test), on one of my project. Having access to the cookies will help me to query my target when authenticated. Anyway, here some interesting links if you want to know more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/packages/webview_flutter" rel="noopener noreferrer"&gt;&lt;code&gt;webview_flutter&lt;/code&gt; package&lt;/a&gt; from pub.dev;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://pub.dev/documentation/webview_flutter/latest/" rel="noopener noreferrer"&gt;official &lt;code&gt;webview_flutter&lt;/code&gt;&amp;nbsp;API documentation&lt;/a&gt; on pub.dev;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter" rel="noopener noreferrer"&gt;&lt;code&gt;webview_flutter&lt;/code&gt; source code&lt;/a&gt; from github;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://developer.android.com/reference/android/webkit/WebView" rel="noopener noreferrer"&gt;official &lt;code&gt;WebView&lt;/code&gt; documentation&lt;/a&gt; from the Android developer website;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://developer.apple.com/documentation/webkit/wkwebview" rel="noopener noreferrer"&gt;official &lt;code&gt;mkWebView&lt;/code&gt; documentation&lt;/a&gt; from the Apple developer website;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://curl.se/docs/http-cookies.html" rel="noopener noreferrer"&gt;cURL HTTP cookies documentation&lt;/a&gt; where the cURL cookies format is explained;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://www.rfc-editor.org/info/rfc6265/" rel="noopener noreferrer"&gt;RFC6265&lt;/a&gt; where the &lt;code&gt;set-cookie&lt;/code&gt; is explained, containing also the official cookies attributes with their specifications;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/theotherdevs/starting-with-flutter-how-to-embed-a-webview-5g91"&gt;Starting with Flutter: How to embed a webview&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/theotherdevs"&gt;@theotherdevs&lt;/a&gt;; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/franciscodex/converting-any-website-into-an-app-flutter-webview-55i7"&gt;Converting any website into an app: Flutter webview&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/franciscodex"&gt;@franciscodex&lt;/a&gt;; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/__2ea5fee000c/not-just-a-webview-building-a-native-engine-on-flutter-to-convert-sites-to-apps-with-sdui-4j0e"&gt;Not Just a WebView: Building a Native Engine on Flutter to Convert Sites to Apps with SDUI&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/__2ea5fee000c"&gt;@__2ea5fee000c&lt;/a&gt;; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/diamantidis/flutter-two-way-communication-between-a-webview-and-a-web-page-iji"&gt;Flutter: Two-way communication between a WebView and a web page&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/diamantidis"&gt;@diamantidis&lt;/a&gt;; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/80009751/is-there-a-way-to-show-more-cookies-fields-from-webview-flutters-webviewcookiem" rel="noopener noreferrer"&gt;Is there a way to show more cookies fields from webview_flutter's WebViewCookieManager&lt;/a&gt; on StackOverflow, where I asked a question regarding the extra cookies attributes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As usual, have fun and happy hacking!&lt;/p&gt;




&lt;p&gt;The stackoverflow user who answered me on my question found a bug in the parser (I missed it), when a value is set to base64, it returns an empty string. In fact, while I was reading the code, I did not see any limits on the size of the key or the value. This should also be tested, a malicious server could eventually overflow an application with badly crafted cookies. This protected could be implemented on the &lt;code&gt;WebView&lt;/code&gt; (Kotlin) part though and not in the &lt;code&gt;flutter&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;Anyway, I will need a way to reproduce (at least) the following bug. Notes from &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie" rel="noopener noreferrer"&gt;Mozilla documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A &lt;code&gt;&amp;lt;cookie-name&amp;gt;&lt;/code&gt; can contain any US-ASCII characters except for control characters (ASCII characters 0 up to 31 and ASCII character 127) or separator characters (space, tab and the characters: &lt;code&gt;(&lt;/code&gt; &lt;code&gt;)&lt;/code&gt; &lt;code&gt;&amp;lt;&lt;/code&gt; &lt;code&gt;&amp;gt;&lt;/code&gt; &lt;code&gt;@&lt;/code&gt; &lt;code&gt;,&lt;/code&gt; &lt;code&gt;;&lt;/code&gt; &lt;code&gt;:&lt;/code&gt; &lt;code&gt;\&lt;/code&gt; &lt;code&gt;"&lt;/code&gt; &lt;code&gt;/&lt;/code&gt; &lt;code&gt;[&lt;/code&gt; &lt;code&gt;]&lt;/code&gt; &lt;code&gt;?&lt;/code&gt; &lt;code&gt;=&lt;/code&gt; &lt;code&gt;{&lt;/code&gt; &lt;code&gt;}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;&amp;lt;cookie-value&amp;gt;&lt;/code&gt; can optionally be wrapped in double quotes and include any US-ASCII character excluding control characters (ASCII characters 0 up to 31 and ASCII character 127), Whitespace, double quotes, commas, semicolons, and backslashes.&lt;/p&gt;

&lt;p&gt;Encoding: Many implementations perform percent-encoding on cookie values. However, this is not required by the RFC specification. The percent-encoding does help to satisfy the requirements of the characters allowed for &lt;code&gt;&amp;lt;cookie-value&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;set a cookie with a base64 value (e.g. &lt;code&gt;dGVzdAo=&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;fetch the cookie as &lt;code&gt;WebCookie&lt;/code&gt;, the value returned is &lt;code&gt;""&lt;/code&gt;" instead of &lt;code&gt;"dGVzdAo="&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This issue is due to the current implementation of the parser used in the &lt;a href="https://github.com/flutter/packages/blob/a1ed23c8f76035baa4edb2003d50349d07e7d6e0/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_cookie_manager.dart#L87" rel="noopener noreferrer"&gt;&lt;code&gt;AndrdoiWebViewCookieManager&lt;/code&gt;&lt;/a&gt; implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_test/flutter_test.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// code exfiltred from official sources&lt;/span&gt;
&lt;span class="n"&gt;poc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; 
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&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;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cookieValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'='&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;cookieValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cookieValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"poc"&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="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;poc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test=dGVzdAo"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;poc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test=dGVzdAo"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"dGVzdAo"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;poc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test=dGVzdAo="&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;poc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"testdGVzdAo="&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"dGVzdAo="&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;flutter &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;00:00 +0: poc                                                                               
[(test, dGVzdAo)]
00:01 +0 -1: poc [E]                                                                        
&lt;/span&gt;&lt;span class="gp"&gt;  Expected: (String, String):&amp;lt;(test, dGVzdAo)&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;    Actual: [(String, String):(test, dGVzdAo)]

  package:matcher                                     expect
  package:flutter_test/src/widget_tester.dart 473:18  expect
&lt;/span&gt;&lt;span class="gp"&gt;  test/widget_test.dart 25:5                          main.&amp;lt;fn&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here a quick nginx configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;events&lt;/span&gt; {
    &lt;span class="n"&gt;worker_connections&lt;/span&gt;   &lt;span class="m"&gt;2000&lt;/span&gt;;
}

&lt;span class="n"&gt;http&lt;/span&gt; {
  &lt;span class="n"&gt;server&lt;/span&gt; {
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="m"&gt;4001&lt;/span&gt;;
    &lt;span class="n"&gt;add_header&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;-&lt;span class="n"&gt;Cookie&lt;/span&gt; &lt;span class="s2"&gt;"test=dGVzdAo=; Path=/"&lt;/span&gt;;
    &lt;span class="n"&gt;return&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to &lt;a href="https://stackoverflow.com/users/19418150/mahendra-dhakad" rel="noopener noreferrer"&gt;Mahendra Dhakad&lt;/a&gt;](&lt;a href="https://stackoverflow.com/a/80009898/6782635" rel="noopener noreferrer"&gt;https://stackoverflow.com/a/80009898/6782635&lt;/a&gt;) on stackoverflow.&lt;/p&gt;




&lt;p&gt;Cover Image by &lt;a href="https://unsplash.com/@pawelskor?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Paul Skorupskas&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/person-holding-camera-lens-7KLa-xLbSXA?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>webview</category>
      <category>android</category>
      <category>programming</category>
    </item>
    <item>
      <title>Q&amp;D: Android Device Information</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Wed, 14 Oct 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/qd-android-device-information-4mpb</link>
      <guid>https://dev.to/niamtokik/qd-android-device-information-4mpb</guid>
      <description>&lt;p&gt;It can be necessary, sometime, to collect device information, especially to identify a specific kind of device for debugging purpose, or to identify unique devices. In Dart/Flutter, one can install the &lt;a href="https://pub.dev/packages/device_info_plus" rel="noopener noreferrer"&gt;&lt;code&gt;device_info_plus&lt;/code&gt;&lt;/a&gt; package to have access to lot of informations regarding the device where the application is installed. Let have a quick look on this one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;flutter&lt;/span&gt; &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="n"&gt;device_info_plus&lt;/span&gt;
&lt;span class="n"&gt;Resolving&lt;/span&gt; &lt;span class="n"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt; 
&lt;span class="n"&gt;Downloading&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt; 
  &lt;span class="n"&gt;cupertino_icons&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;device_info_plus&lt;/span&gt; &lt;span class="mf"&gt;13.3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;device_info_plus_platform_interface&lt;/span&gt; &lt;span class="mf"&gt;8.1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ffi&lt;/span&gt; &lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ffi_leak_tracker&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="mf"&gt;7.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;flutter_web_plugins&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sdk&lt;/span&gt; &lt;span class="n"&gt;flutter&lt;/span&gt;
  &lt;span class="n"&gt;material_color_utilities&lt;/span&gt; &lt;span class="mf"&gt;0.13&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.13&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="mf"&gt;1.18&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.19&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;plugin_platform_interface&lt;/span&gt; &lt;span class="mf"&gt;2.1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;
  &lt;span class="n"&gt;test_api&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;vector_math&lt;/span&gt; &lt;span class="mf"&gt;2.4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;web&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;win32&lt;/span&gt; &lt;span class="mf"&gt;6.4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;win32_registry&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;Changed&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="n"&gt;dependencies&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;newer&lt;/span&gt; &lt;span class="n"&gt;versions&lt;/span&gt; &lt;span class="n"&gt;incompatible&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;dependency&lt;/span&gt; &lt;span class="n"&gt;constraints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;Try&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;flutter&lt;/span&gt; &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;outdated&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;more&lt;/span&gt; &lt;span class="n"&gt;information&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first step is to import the &lt;code&gt;device_info_plus&lt;/code&gt; package in your code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:device_info_plus/device_info_plus.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One can extract only a small subset of all device information available, for example, to extract the device &lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo/id.html" rel="noopener noreferrer"&gt;&lt;code&gt;id&lt;/code&gt;&lt;/a&gt;, the &lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo/id.html" rel="noopener noreferrer"&gt;&lt;code&gt;id&lt;/code&gt;&lt;/a&gt; property can be retrieved and returned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getDeviceId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;DeviceInfoPlugin&lt;/span&gt; &lt;span class="n"&gt;deviceInfoPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DeviceInfoPlugin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;deviceInfoPlugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deviceInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&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;If more information about a device is required, one can extract all of them as a &lt;code&gt;Map&amp;lt;String, dynamic&amp;gt;&lt;/code&gt; using the &lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/BaseDeviceInfo/data.html" rel="noopener noreferrer"&gt;&lt;code&gt;data&lt;/code&gt;&lt;/a&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getDeviceInfoMap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;DeviceInfoPlugin&lt;/span&gt; &lt;span class="n"&gt;deviceInfoPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DeviceInfoPlugin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;BaseDeviceInfo&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;deviceInfoPlugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deviceInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&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;Some information are only available on a specific kind of device (e.g. iOS, Android, Browser). If the application has been developed with portability in mind, it can also be a good idea to extract device's information based on the architecture/platform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getAndroidDeviceInfoMap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;DeviceInfoPlugin&lt;/span&gt; &lt;span class="n"&gt;deviceInfoPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DeviceInfoPlugin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;AndroidDeviceInfo&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;deviceInfoPlugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;androidInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&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;Here an example of the data extracted on an Android emulator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;I/flutter ( 3959): physicalRamSize: 2472
I/flutter ( 3959): type: user
I/flutter ( 3959): manufacturer: Google
I/flutter ( 3959): freeDiskSize: 464072704
I/flutter ( 3959): bootloader: unknown
I/flutter ( 3959): fingerprint: google/sdk_gphone64_x86_64/emu64xa:16/BE2A.250530.026.D1/13818094:user/release-keys
I/flutter ( 3959): host: e8e8f3751cda
I/flutter ( 3959): isLowRamDevice: false
I/flutter ( 3959): model: sdk_gphone64_x86_64
I/flutter ( 3959): id: BE2A.250530.026.D1
I/flutter ( 3959): brand: google
I/flutter ( 3959): hardware: ranchu
I/flutter ( 3959): product: sdk_gphone64_x86_64
I/flutter ( 3959): totalDiskSize: 6228115456
I/flutter ( 3959): supportedAbis: [x86_64, arm64-v8a]
I/flutter ( 3959): supported32BitAbis: []
I/flutter ( 3959): display: BE2A.250530.026.D1
I/flutter ( 3959): isPhysicalDevice: false
I/flutter ( 3959): version: {baseOS: , securityPatch: 2025-07-05, sdkInt: 36, release: 16, codename: REL, previewSdkInt: 0, incremental: 13818094}
I/flutter ( 3959): systemFeatures: [android.hardware.sensor.proximity, android.software.adoptable_storage, android.hardware.sensor.accelerometer, android.software.controls, android.hardware.faketouch, android.software.telecom, android.hardware.telephony.subscription, android.hardware.reboot_escrow, android.hardware.telephony.data, android.software.backup, android.hardware.touchscreen, android.hardware.touchscreen.multitouch, android.software.erofs, android.software.print, android.software.activities_on_secondary_displays, android.software.device_lock, android.software.voice_recognizers, android.software.picture_in_picture, android.hardware.fingerprint, android.hardware.sensor.gyroscope, com.google.android.feature.PERSONAL_SAFETY, android.software.vulkan.deqp.level, android.software.cant_save_state, android.hardware.security.model.compatible, android.hardware.telephony.messaging, android.hardware.telephony.calling, android.hardware.sensor.relative_humidity, android.hardware.bluetooth, android.software.window_magnification, andr
I/flutter ( 3959): tags: release-keys
I/flutter ( 3959): supported64BitAbis: [x86_64, arm64-v8a]
I/flutter ( 3959): availableRamSize: 967
I/flutter ( 3959): name: sdk_gphone64_x86_64
I/flutter ( 3959): time: 1753213259000
I/flutter ( 3959): device: emu64xa
I/flutter ( 3959): board: goldfish_x86_64
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More information can be found on Android via the &lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidBuildVersion-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;AndroidBuildVersion&lt;/code&gt;&lt;/a&gt; object (including the base name, the code name and the release).&lt;/p&gt;

&lt;p&gt;Depending on the platform, a lot of values can be extracted. Here a quick list enumerating few of them (the ones the most interesting to me):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo-class.html#instance-properties" rel="noopener noreferrer"&gt;&lt;code&gt;AndroidDeviceInfo&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo/availableRamSize.html" rel="noopener noreferrer"&gt;&lt;code&gt;availableRamSize&lt;/code&gt;&lt;/a&gt; as &lt;code&gt;int&lt;/code&gt;: Current unallocated RAM size of the device in megabytes, extracted from &lt;a href="https://developer.android.com/reference/android/app/ActivityManager.MemoryInfo#availMem" rel="noopener noreferrer"&gt;&lt;code&gt;ActivityManager.MemoryInfo&lt;/code&gt;&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo/board.html" rel="noopener noreferrer"&gt;&lt;code&gt;board&lt;/code&gt;&lt;/a&gt; as &lt;code&gt;String&lt;/code&gt;: The name of the underlying board, like "goldfish", extracted from &lt;a href="https://developer.android.com/reference/android/os/Build#BOARD" rel="noopener noreferrer"&gt;&lt;code&gt;Build.BOARD&lt;/code&gt;&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo/brand.html" rel="noopener noreferrer"&gt;&lt;code&gt;brand&lt;/code&gt;&lt;/a&gt; as &lt;code&gt;String&lt;/code&gt;: The consumer-visible brand with which the product/hardware will be associated, if any, extracted from &lt;a href="https://developer.android.com/reference/android/os/Build#BRAND" rel="noopener noreferrer"&gt;&lt;code&gt;Build.BRAND&lt;/code&gt;&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo/device.html" rel="noopener noreferrer"&gt;&lt;code&gt;device&lt;/code&gt;&lt;/a&gt; as &lt;code&gt;String&lt;/code&gt;: The name of the industrial design, extracted from &lt;a href="https://developer.android.com/reference/android/os/Build#DEVICE" rel="noopener noreferrer"&gt;&lt;code&gt;Build.DEVICE&lt;/code&gt;&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo/fingerprint.html" rel="noopener noreferrer"&gt;&lt;code&gt;fingerprint&lt;/code&gt;&lt;/a&gt; as &lt;code&gt;String&lt;/code&gt;: A string that uniquely identifies this build (Do not attempt to parse this value.), extracted from &lt;a href="https://developer.android.com/reference/android/os/Build#FINGERPRINT" rel="noopener noreferrer"&gt;&lt;code&gt;Build.FINGERPRINT&lt;/code&gt;&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo/hardware.html" rel="noopener noreferrer"&gt;&lt;code&gt;hardware&lt;/code&gt;&lt;/a&gt; as &lt;code&gt;String&lt;/code&gt;: The name of the hardware (from the kernel command line or /proc), extracted from &lt;a href="https://developer.android.com/reference/android/os/Build#HARDWARE" rel="noopener noreferrer"&gt;&lt;code&gt;Build.HARDWARE&lt;/code&gt;&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo/manufacturer.html" rel="noopener noreferrer"&gt;&lt;code&gt;manufacturer&lt;/code&gt;&lt;/a&gt; as &lt;code&gt;String&lt;/code&gt;: The manufacturer of the product/hardware, extracted from &lt;a href="https://developer.android.com/reference/android/os/Build#MANUFACTURER" rel="noopener noreferrer"&gt;&lt;code&gt;Build.MANUFACTURER&lt;/code&gt;&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidDeviceInfo/version.html" rel="noopener noreferrer"&gt;&lt;code&gt;version&lt;/code&gt;&lt;/a&gt; as &lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/AndroidBuildVersion-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;AndroidBuildVersion&lt;/code&gt;&lt;/a&gt;: Android operating system version values derived from &lt;code&gt;android.os.Build.VERSION&lt;/code&gt;;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/IosDeviceInfo-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;IosDeviceInfo&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/IosDeviceInfo/identifierForVendor.html" rel="noopener noreferrer"&gt;&lt;code&gt;identifierForVendor&lt;/code&gt;&lt;/a&gt;: Unique UUID value identifying the current device;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/IosDeviceInfo/modelName.html" rel="noopener noreferrer"&gt;&lt;code&gt;modelName&lt;/code&gt;&lt;/a&gt;: Commercial or user-known model name Examples: iPhone 16 Pro, iPad Pro 11-Inch 3;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/IosDeviceInfo/utsname.html" rel="noopener noreferrer"&gt;&lt;code&gt;utsname&lt;/code&gt;&lt;/a&gt;: Operating system information derived from sys/utsname.h;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/LinuxDeviceInfo-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;LinuxDeviceInfo&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/LinuxDeviceInfo/id.html" rel="noopener noreferrer"&gt;&lt;code&gt;id&lt;/code&gt;&lt;/a&gt;: A lower-case string identifying the operating system, excluding any version information and suitable for processing by scripts or usage in generated filenames;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/LinuxDeviceInfo/machineId.html" rel="noopener noreferrer"&gt;&lt;code&gt;machineId&lt;/code&gt;&lt;/a&gt;: A unique machine ID of the local system that is set during installation or boot. The machine ID is hexadecimal, 32-character, lowercase ID;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/MacOsDeviceInfo-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;MacOsDeviceInfo&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/MacOsDeviceInfo/systemGUID.html" rel="noopener noreferrer"&gt;&lt;code&gt;systemGUID&lt;/code&gt;&lt;/a&gt;: Device GUID;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/WindowsDeviceInfo-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;WindowsDeviceInfo&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/device_info_plus/latest/device_info_plus/WindowsDeviceInfo/deviceId.html" rel="noopener noreferrer"&gt;&lt;code&gt;deviceId&lt;/code&gt;&lt;/a&gt;: Displayed as "Device ID" in Windows Setting&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next step will be to generate an unique reproducible identifier from different systems using those information. A list of resources to help thinking about all of that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.android.com/identity/user-data-ids" rel="noopener noreferrer"&gt;Best practices for unique identifiers&lt;/a&gt; from the official Android Developers Website;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://android-developers.googleblog.com/2011/03/identifying-app-installations.html" rel="noopener noreferrer"&gt;Identifying App Installations&lt;/a&gt; from the official Android developers blog;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/cesarferreira/android-unique-device-id" rel="noopener noreferrer"&gt;&lt;code&gt;android-unique-device-id&lt;/code&gt;&lt;/a&gt; on github;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/4468248/unique-id-of-android-device" rel="noopener noreferrer"&gt;Unique ID of Android device&lt;/a&gt; on StackOverflow;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gist.github.com/tokoiwesley/27a644312fe657626996f4af0b77a276" rel="noopener noreferrer"&gt;Generate a unique Android Device ID&lt;/a&gt; on gist;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As usual, happy hacking!&lt;/p&gt;




&lt;p&gt;Cover image by &lt;a href="https://unsplash.com/@elena_ramseier?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Elena Ramseier&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-large-group-of-green-chairs-1xk8hMP-WHo?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>flutter</category>
      <category>mobile</category>
      <category>data</category>
    </item>
    <item>
      <title>WeeklyReview#202641</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Mon, 12 Oct 2026 10:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/weeklyreview202641-4beo</link>
      <guid>https://dev.to/niamtokik/weeklyreview202641-4beo</guid>
      <description>&lt;p&gt;This week was quite busy in my code. Redarging my main application/product, I started to implement the database schema with &lt;a href="https://pub.dev/packages/sqflite" rel="noopener noreferrer"&gt;&lt;code&gt;sqflite&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;flutter&lt;/code&gt;. I did also a lot of tests regarding the flexibility of &lt;a href="https://pub.dev/packages/sqflite" rel="noopener noreferrer"&gt;&lt;code&gt;sqflite&lt;/code&gt;&lt;/a&gt;, and its potential limits in my use case. To be honest, I don't really like how this library is working but it should do the jobs for now. I also played with the &lt;a href="https://pub.dev/packages/flutter_quill" rel="noopener noreferrer"&gt;&lt;code&gt;flutter_quill&lt;/code&gt;&lt;/a&gt; text editor library (and also &lt;a href="https://pub.dev/packages/fleather" rel="noopener noreferrer"&gt;&lt;code&gt;fleather&lt;/code&gt;&lt;/a&gt;). Not so complex to use, can produce something pretty cool quick. Finally, the &lt;a href="https://github.com/RandalSchwartz/BlocSignal" rel="noopener noreferrer"&gt;BlocSignal&lt;/a&gt; pattern used in Flutter seems really attractive, lot of examples are available on their repository and it can be a good alternative of my approach (doing everything from scratch to learn).&lt;/p&gt;




&lt;p&gt;It was not expected, but it looks like my motivation was focused to do C code for &lt;a href="https://github.com/niamtokik/mac_randomizer" rel="noopener noreferrer"&gt;&lt;code&gt;mac_randomizer&lt;/code&gt;&lt;/a&gt;. This is definitively a pet project, but C is still one of my favorite language, even if it can be challenging to do some things (e.g. concurrency), it's still great to do kinda low-level code. The source code tree is now clean, the Makefile is minimalist but should work on any system using GNU Makefile. Most of the functions are now sorted by categories in their own source file. The last action was to start working on a minimalist implementation of a Mealy machine, a specific kind of finite state machine, to parse mac addresses, instead of using an external regexp library. Actually, the implementation is a bit hard, not because of the complexity, but because of the interface and the abstraction. My idea is to have something like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// first tokenize the mac address to validate the&lt;/span&gt;
&lt;span class="c1"&gt;// characters used. Luckily, a mac address only has&lt;/span&gt;
&lt;span class="c1"&gt;// 23 allowed characters: [a-fA-F0-9\-\.\:]&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// char *string is the raw strings containing the&lt;/span&gt;
&lt;span class="c1"&gt;// mac address.&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// size_t length is the max size of the string, the&lt;/span&gt;
&lt;span class="c1"&gt;// tokenizer must stop when reading a NUL char or when&lt;/span&gt;
&lt;span class="c1"&gt;// it reaches the length limit&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// the struct token *tokens is an array of token, where&lt;/span&gt;
&lt;span class="c1"&gt;// each token contains the raw valid character, the &lt;/span&gt;
&lt;span class="c1"&gt;// position of the character and the kind of token (e.g.&lt;/span&gt;
&lt;span class="c1"&gt;// digit, separator).&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// the tokens should probably be defined inside another&lt;/span&gt;
&lt;span class="c1"&gt;// structure embedded the length of the array. This value&lt;/span&gt;
&lt;span class="c1"&gt;// should be incremented every time a valid character is&lt;/span&gt;
&lt;span class="c1"&gt;// found.&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="nf"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fsm_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// secondly, the parser will get the tokens and will convert&lt;/span&gt;
&lt;span class="c1"&gt;// them into an internal binary representation of the mac&lt;/span&gt;
&lt;span class="c1"&gt;// address (e.g. uint8_t mac_address[6]).&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// The arguments of this function are similar to the previous&lt;/span&gt;
&lt;span class="c1"&gt;// one. The final result is then stored in the mac_address&lt;/span&gt;
&lt;span class="c1"&gt;// variable.&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="nf"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mac_address&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fsm_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mac_address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// the question know is how to design correctly the fsm_start()&lt;/span&gt;
&lt;span class="c1"&gt;// function. It should have the possibility to deal with different&lt;/span&gt;
&lt;span class="c1"&gt;// kind of input, not only char, but also C data-structure. It&lt;/span&gt;
&lt;span class="c1"&gt;// should also be able to deal with different kind of output. Based&lt;/span&gt;
&lt;span class="c1"&gt;// on these requirements, the definition of the function should look&lt;/span&gt;
&lt;span class="c1"&gt;// like the snippet below.&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// The input argument can be a problem here, at least for the&lt;/span&gt;
&lt;span class="c1"&gt;// mac address parsing feature. Indeed, a string representing a&lt;/span&gt;
&lt;span class="c1"&gt;// mac address only has a few format, with specific length:&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;//   EUI48-IEEE: xx-xx-xx-xx-xx-xx (max length 17)&lt;/span&gt;
&lt;span class="c1"&gt;//   EUI48-IETF: xx:xx:xx:xx:xx:xx (max length 17)&lt;/span&gt;
&lt;span class="c1"&gt;//   EUI48-CISCO: xxxx.xxxx.xxxx (max length 16)&lt;/span&gt;
&lt;span class="c1"&gt;//   EUI64-IEEE: xx-xx-xx-xx-xx-xx-xx-xx (max length 23)&lt;/span&gt;
&lt;span class="c1"&gt;//   EUI64-IETF: xx:xx:xx:xx:xx:xx:xx:xx (max length 23)&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// the input string should then have a maximal value of 23&lt;/span&gt;
&lt;span class="c1"&gt;// (+1 with NUL), and a minimal value of 17(+1 with NUL). The&lt;/span&gt;
&lt;span class="c1"&gt;// output can also be limited to sizeof(uint8_t)*6=48bits or&lt;/span&gt;
&lt;span class="c1"&gt;// sizeof(uint8_t)*8=64bits. Using the 64bits version is perhaps&lt;/span&gt;
&lt;span class="c1"&gt;// the best choice because an EUI48 can be converted to an EUI64&lt;/span&gt;
&lt;span class="c1"&gt;// and vice versa. Note: I don't even think it's possible to&lt;/span&gt;
&lt;span class="c1"&gt;// compress this value, it will probably add more complexity&lt;/span&gt;
&lt;span class="c1"&gt;// for no real benefits on the long run.&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="nf"&gt;fsm_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;input_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;
&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="c1"&gt;// do something here.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// the states must also be defined somewhere. states can&lt;/span&gt;
&lt;span class="c1"&gt;// be created dynamically by instantiating different kind&lt;/span&gt;
&lt;span class="c1"&gt;// of object and pushing them together, or creating them&lt;/span&gt;
&lt;span class="c1"&gt;// "statically" in their own data-structure with their&lt;/span&gt;
&lt;span class="c1"&gt;// own callback functions. One of the idea is to create&lt;/span&gt;
&lt;span class="c1"&gt;// something like the code below.&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// The handler_enter callback is called only when a transition&lt;/span&gt;
&lt;span class="c1"&gt;// occurs between states.&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// The handler_input callback is executed when an input&lt;/span&gt;
&lt;span class="c1"&gt;// is received.&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler_enter&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler_input&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;s&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;As you can see, it's a good mental exercise to find the right way to implement something like that in C. In fact, a mealy (or moore) FSM are being use with Regexp but also with other complex protocols like TCP. Reimplementing something like that to parse well specified data like a mac address is probably the best choice, and, if correctly done, it could also be used to encode as well.&lt;/p&gt;

&lt;p&gt;Anyway, here some implementations from github:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ajrisi/fsm" rel="noopener noreferrer"&gt;&lt;strong&gt;ajrisi/fsm&lt;/strong&gt;&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/cferwin/microFSM" rel="noopener noreferrer"&gt;&lt;strong&gt;cferwin/microFSM&lt;/strong&gt;&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/At-EC/At-FSM" rel="noopener noreferrer"&gt;&lt;strong&gt;At-EC/At-FSM&lt;/strong&gt;&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/TheHumbleTransistor/HTHSM" rel="noopener noreferrer"&gt;&lt;strong&gt;TheHumbleTransistor/HTHSM&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More implementation examples can be also found in userland from OpenBSD, FreeBSD and NetBSD projects. Many of those tools can have an implementation of a finite state machine.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenBSD:

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/openbsd/src/blob/master/usr.bin/patch/ed.c" rel="noopener noreferrer"&gt;&lt;code&gt;usr.bin/patch/ed.c&lt;/code&gt;&lt;/a&gt;: it contains a small finite state machine implementation used to parse commands&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/openbsd/src/blob/master/games/bs/bs.c" rel="noopener noreferrer"&gt;&lt;code&gt;games/bs/bs.c&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/openbsd/src/blob/master/usr.sbin/npppd/npppd/fsm.c" rel="noopener noreferrer"&gt;&lt;code&gt;usr.sbin/npppd/npppd/fsm.c&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/openbsd/src/blob/master/usr.sbin/pppd/fsm.c" rel="noopener noreferrer"&gt;&lt;code&gt;usr.sbin/pppd/fsm.c&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/openbsd/src/blob/master/lib/libc/gen/unvis.c" rel="noopener noreferrer"&gt;&lt;code&gt;lib/libc/gen/unvis.c&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;FreeBSD:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/freebsd/freebsd-src/blob/main/crypto/openssl/ssl/statem/statem.c" rel="noopener noreferrer"&gt;&lt;code&gt;crypto/openssl/ssl/statem/statem.c&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NetBSD:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/NetBSD/src/blob/trunk/libexec/telnetd/state.c" rel="noopener noreferrer"&gt;&lt;code&gt;libexec/telnetd/state.c&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/NetBSD/src/blob/trunk/sbin/init/init.c" rel="noopener noreferrer"&gt;&lt;code&gt;sbin/init/init.c&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Most of my posts are currently stuck in draft mode due to that, but I like the weekly review format. It is a good summary containing a lot of information in one place. Then, I think most of the coming publications will use this format.&lt;/p&gt;

&lt;h1&gt;
  
  
  Coding
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="http://www.phoenixframework.org/blog/heex-compilation-deep-dive-liveview-1-2" rel="noopener noreferrer"&gt;&lt;strong&gt;A deep dive into HEEx compilation from LiveView 1.2&lt;/strong&gt;&lt;/a&gt;: A post explaining the foundation of the HEEx template systems present in Phoenix LiveView. I did not know it was tokenized. In fact, this is a very good news... It is becoming closer to the way clojure is dealing with HTML.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://ghuntley.com/lisp/" rel="noopener noreferrer"&gt;&lt;strong&gt;an application in lisp you grow by talking to it&lt;/strong&gt;&lt;/a&gt;: LISP is probably one of the greatest language of all time, in this article, the program is created by talking to an LLM during a coding session.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/weavefoundry/weavec" rel="noopener noreferrer"&gt;&lt;strong&gt;WeaveC&lt;/strong&gt;&lt;/a&gt;: A C compiler with inferred ownership and borrow checking for Rust-style memory safety.&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://elixir.menu/" rel="noopener noreferrer"&gt;&lt;strong&gt;Tools for your Elixir app&lt;/strong&gt;&lt;/a&gt;: A starting point for each kind of application. Recommended tools, why we use them, and when to choose something else.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/moznion/cccc" rel="noopener noreferrer"&gt;&lt;strong&gt;cccc&lt;/strong&gt;&lt;/a&gt;: measures Cognitive Complexity (SonarSource / G. Ann Campbell) and Cyclomatic Complexity (McCabe). I used similar tools in the past, like &lt;code&gt;ccc&lt;/code&gt; and &lt;code&gt;scc&lt;/code&gt; or &lt;code&gt;sccc&lt;/code&gt;. Nice to have, even before if you add it in your CI/CD to evaluate the complexity of a commit.&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://lwn.net/Articles/1095811/" rel="noopener noreferrer"&gt;&lt;strong&gt;Reducing undefined behavior in the C language&lt;/strong&gt;&lt;/a&gt;: undefined behavior in C is a nightmare. Probably one of the most complex part of the language, and it can lead to total disaster. This post is presenting the solution to avoid common mistakes and find a way to create safer C code. Actually, this is from a &lt;a href="https://www.youtube.com/watch?v=dhlYcmX_oBQ&amp;amp;list=PLEVVgAZOU9P8&amp;amp;index=14" rel="noopener noreferrer"&gt;talk&lt;/a&gt;, and the slides are &lt;a href="https://uecker.codeberg.page/kernel-recipes.pdf" rel="noopener noreferrer"&gt;available online&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html" rel="noopener noreferrer"&gt;&lt;strong&gt;What Every C Programmer Should Know About Undefined Behavior #1/3&lt;/strong&gt;&lt;/a&gt;: the first article of a series about undefined behavior in C.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://keleshev.com/abstract-syntax-tree-an-example-in-c/" rel="noopener noreferrer"&gt;&lt;strong&gt;Abstract Syntax Tree, An Example in C&lt;/strong&gt;&lt;/a&gt;: a short publication with nice example to explain how to implement and use an AST.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://keleshev.com/one-pass-compiler-primer" rel="noopener noreferrer"&gt;&lt;strong&gt;One-pass Compiler&lt;/strong&gt;&lt;/a&gt;: a nice trick to compile code directly without passed inside different layer.&lt;/p&gt;

&lt;p&gt;📖 &lt;a href="https://keleshev.com/compiling-to-assembly-from-scratch/#table-of-contents" rel="noopener noreferrer"&gt;&lt;strong&gt;Compiling to Assembly from Scratch&lt;/strong&gt;&lt;/a&gt;: a book by the author of the two previous posts. neat.&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://dl.gi.de/server/api/core/bitstreams/95165c87-561d-4b35-bed9-6175e1948a5a/content" rel="noopener noreferrer"&gt;&lt;strong&gt;CASM: Implementing an Abstract State Machine based Programming Language&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  System
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://rsadowski.de/posts/2026/update-relayd-and-httpd/" rel="noopener noreferrer"&gt;&lt;strong&gt;Headers Up! What's New in httpd and relayd&lt;/strong&gt;&lt;/a&gt;: HTTP header manipulation support and request filtering. I'm still using nginx, but &lt;code&gt;httpd&lt;/code&gt; is becoming really better every new release.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://marc.info/?l=openbsd-tech&amp;amp;m=179114222343483&amp;amp;w=2" rel="noopener noreferrer"&gt;&lt;strong&gt;Locking down openat(2) and friends with O_BELOW and F_BELOW&lt;/strong&gt;&lt;/a&gt;: a mail-exchange describing the (future?) &lt;code&gt;openat&lt;/code&gt; function to open file with relative path (and more safety).&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/Genymobile/scrcpy" rel="noopener noreferrer"&gt;&lt;strong&gt;scrcpy&lt;/strong&gt;&lt;/a&gt;: Display and control your Android device.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/floci-io/floci" rel="noopener noreferrer"&gt;&lt;strong&gt;floci&lt;/strong&gt;&lt;/a&gt;: gives you AWS-shaped services on your machine without requiring a cloud account, an auth token, or paid feature gates. &lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/riscv/learn" rel="noopener noreferrer"&gt;&lt;strong&gt;riscv/learn&lt;/strong&gt;&lt;/a&gt;: A community-driven, continuously updated compilation of RISC-V learning resources. Content is organized by topic and experience level to help you discover courses, software, documentation, and articles efficiently.&lt;/p&gt;

&lt;p&gt;📖 &lt;a href="https://simonjohnthompson.github.io/haskellcraft/" rel="noopener noreferrer"&gt;&lt;strong&gt;Haskell: The Craft of Functional Programming&lt;/strong&gt;&lt;/a&gt;: revised version.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://www.dpdk.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;DPDK (Data Plane Development Kit)&lt;/strong&gt;&lt;/a&gt;: an open source framework for fast packet processing on standard hardware. It runs in cloud infrastructure, telecom networks, financial exchanges, particle accelerators, and radio telescopes. Most of your traffic already runs through it. Start by reviewing a patch, no account or setup required. I discovered it was also running not only on Linux... I need to try that.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://ghuntley.com/unikernels/" rel="noopener noreferrer"&gt;&lt;strong&gt;unikernels were hard. key word: were&lt;/strong&gt;&lt;/a&gt;: unikernel IS THE WAY TO GO, but I still this a complex technology mixing a lot of features from many different part of any systems. In fact, this is really close to microkernel, and both are, to me, two things that should be merged together.&lt;/p&gt;

&lt;h1&gt;
  
  
  Network
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://www.openvswitch.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Open vSwitch (OVS)&lt;/strong&gt;&lt;/a&gt;: a production quality, multilayer virtual switch, designed to enable massive network automation through programmatic extension, while still supporting standard management interfaces and protocols.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://www.ovn.org/en/" rel="noopener noreferrer"&gt;&lt;strong&gt;Open Virtual Network&lt;/strong&gt;&lt;/a&gt;: a series of daemons for the Open vSwitch that translate virtual network configurations into OpenFlow.&lt;/p&gt;

&lt;h1&gt;
  
  
  Database
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/pingcap/awesome-database-learning" rel="noopener noreferrer"&gt;&lt;strong&gt;Awesome Database Learning&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/pgvector/pgvector" rel="noopener noreferrer"&gt;&lt;strong&gt;pgvector&lt;/strong&gt;&lt;/a&gt;: Open-source vector similarity search for Postgres&lt;/p&gt;

&lt;h1&gt;
  
  
  Security
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://forum.itsallwidgets.com/t/malicious-flutter-package-while-it-have-a-clean-code/4960" rel="noopener noreferrer"&gt;&lt;strong&gt;Malicious Flutter Package while it have a Clean Code?&lt;/strong&gt;&lt;/a&gt;: malware present in &lt;code&gt;example&lt;/code&gt; directory inside a flutter project. Don't trust blindly all projects.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://projectzero.google/2026/10/emergency-patching.html" rel="noopener noreferrer"&gt;&lt;strong&gt;How to fix a bug in a fix&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://blog.google/security/chromes-response-to-recent-cctld-registry-hijacks/" rel="noopener noreferrer"&gt;&lt;strong&gt;Chrome's Response to Recent ccTLD Registry Hijacks&lt;/strong&gt;&lt;/a&gt;: Following recent .gh, .sl, and .as ccTLD domain hijacks, Chrome immediately blocked unauthorized HTTPS certificates via CRLSets to protect users automatically. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://beaksec.github.io/posts/telegram-desktop-one-click-account-takeover/" rel="noopener noreferrer"&gt;&lt;strong&gt;Telegram Desktop: one-click account takeover via IPC injection&lt;/strong&gt;&lt;/a&gt;: a post describing the CVE-2026-107181, where one malicious actor can take control of a group by sharing a telegram link and opening it on the telegram desktop application. The problem is from the URI parser, when dealing with semicolons. That's an interesting attack, because many application can be ported on different systems, like Signal or SimpleXChat, and depending of the languages/tools used, some part of the can use different routines.&lt;/p&gt;

&lt;h1&gt;
  
  
  Security/Cryptography
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://blog.trailofbits.com/2026/10/02/sequencehash-multihashing-for-the-rest-of-us/" rel="noopener noreferrer"&gt;&lt;strong&gt;SequenceHash: multihashing for the rest of us&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://www.yukon.org/hashsmash" rel="noopener noreferrer"&gt;&lt;strong&gt;Hash Smash&lt;/strong&gt;&lt;/a&gt;: Find ordinary collision attacks that reach more rounds with less total computation. Select a hash function’s chart, then one of its two round counts.&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://eprint.iacr.org/2026/2363.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;MiniSHAKE&lt;/strong&gt;&lt;/a&gt;: an extendable output function based on Keccak, with unlimited size output.&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://keccak.team/files/TurboSHAKE.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;TurboSHAKE&lt;/strong&gt;&lt;/a&gt;: an extendable output function based on Keccak, with less rounds to improve performance.&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://keylength.goodkey.co/" rel="noopener noreferrer"&gt;&lt;strong&gt;Key Length&lt;/strong&gt;&lt;/a&gt;: The minimum key sizes each source publishes for protecting data until a given year. &lt;/p&gt;

&lt;h1&gt;
  
  
  Embedded
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/usamahz/cpu-performance-engineering" rel="noopener noreferrer"&gt;&lt;strong&gt;CPU Performance Engineering&lt;/strong&gt;&lt;/a&gt;: A reading path for CPU performance engineering, from one instruction to production inference. Primary sources only, with a runnable benchmark for every section.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://hackaday.com/2026/10/05/the-fpga-chronicles-open-source-it/" rel="noopener noreferrer"&gt;&lt;strong&gt;The FPGA Chronicles: Open Source It&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/BeRo1985/pasriscv" rel="noopener noreferrer"&gt;&lt;strong&gt;PasRISCV&lt;/strong&gt;&lt;/a&gt;:A RISC-V RV64GCV/RVA23 emulator written in Object Pascal. It simulates processor cores, memory, I/O, and much more.&lt;/p&gt;

&lt;h1&gt;
  
  
  Update/Upgrade
&lt;/h1&gt;

&lt;p&gt;🔄 &lt;a href="https://github.com/benoitc/hackney/releases/tag/4.8.5" rel="noopener noreferrer"&gt;&lt;strong&gt;hackney 4.8.5&lt;/strong&gt;&lt;/a&gt;: bug fixes.&lt;/p&gt;

&lt;p&gt;🔄 &lt;a href="https://ninenines.eu/articles/cowboy-2.20.0/" rel="noopener noreferrer"&gt;&lt;strong&gt;Cowboy 2.20&lt;/strong&gt;&lt;/a&gt;: security and bug fixes.&lt;/p&gt;

&lt;p&gt;🔄 &lt;a href="https://undeadly.org/cgi?action=article;sid=20261007052424" rel="noopener noreferrer"&gt;&lt;strong&gt;LibreSSL 4.2.2 and 4.3.3&lt;/strong&gt;&lt;/a&gt;: security and bug fixes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Computer Science
&lt;/h1&gt;

&lt;p&gt;📑 &lt;a href="https://web.iitd.ac.in/~debanjan/ELL318_Lecture7_MealyandMooreMachines_DBRevised.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Digital Hardware Design DFA, Mealy and Moore Machines&lt;/strong&gt;&lt;/a&gt;: a lecture on Mealy/Moore machines&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://arxiv.org/pdf/2206.04944" rel="noopener noreferrer"&gt;&lt;strong&gt;A Report on Achieving Complete Regular-Expression Matching using Mealy Machines&lt;/strong&gt;&lt;/a&gt;: an interesting (but complex) publication about regexp and finite state machine to match exact pattern.&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://link.springer.com/content/pdf/10.1007/978-3-031-08679-3_8.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Effective Reductions of Mealy Machines&lt;/strong&gt;&lt;/a&gt;: reducing mealy machines states and transitions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Misc
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://aeon.co/essays/your-brain-does-not-process-information-and-it-is-not-a-computer" rel="noopener noreferrer"&gt;&lt;strong&gt;The empty brain&lt;/strong&gt;&lt;/a&gt;: an amazing post about brain information processing. The brain is not storing information like a computer (a stream of bits), and in fact, it is not the only organ to "store it". It stores experiences, and experiences are different between every people alive, then, it will be impossible to "copy" experiences between humans. In fact, like the author is explaining in his publication, even if all neurons' states were extracted, copied and connected together, it will have no meaning because it would be outside of the body where the experiences have been learned.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because the Information Processing metaphor is not even slightly valid, we will never have to worry about a human mind going amok in cyberspace; alas, we will also never achieve immortality through downloading. [...] &lt;strong&gt;We are organisms, not computers&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/blog/victime-dune-fuite-de-donnees-voici-dans-quels-cas-vous-pouvez-reclamer-une-indemnisation" rel="noopener noreferrer"&gt;&lt;strong&gt;Victime d’une fuite de données ? Voici dans quels cas vous pouvez réclamer une indemnisation&lt;/strong&gt;&lt;/a&gt;: see also that on the &lt;a href="https://www.cnil.fr/fr/violations-de-donnees-personnelles-cas-indemnite" rel="noopener noreferrer"&gt;CNIL website&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.morningstar.com/news/marketwatch/20261008113/a-strategist-who-called-the-asian-financial-crisis-sees-parallels-with-the-ai-boom" rel="noopener noreferrer"&gt;&lt;strong&gt;A strategist who called the Asian financial crisis sees parallels with the AI boom&lt;/strong&gt;&lt;/a&gt;: another indicator the "AI" boom is not really doing what every one expect. I wanted to read &lt;a href="https://www.zerohedge.com/markets/myth-ais-miracle-albert-edwards-spots-same-fatal-flaw-sank-asia-1997" rel="noopener noreferrer"&gt;The Myth Of AI's Miracle: Albert Edwards Spots The Same Fatal Flaw That Sank Asia In 1997&lt;/a&gt;, but, well, it is a premium article.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the productivity payoff from AI remains a forecast, rather than an observation [...] No AI productivity boost in the data yet [...] too many people believed the beguiling narrative and as a consequence, lent these economies cheap, abundant capital which was misallocated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🐦 &lt;a href="https://threadout.app/thread/2108530300494230009-the-signs-that-the-ai-boom-is-built-on-fake-revenue-are-now" rel="noopener noreferrer"&gt;&lt;strong&gt;THE SIGNS THAT THE AI BOOM IS BUILT ON FAKE REVENUE ARE NOW HERE. Here is what is really happening&lt;/strong&gt;&lt;/a&gt;: a thread about what could happen with the AI financial - SCAM - scheme. Anyway, it smells really bad, even worse than the crypto-currency bubble.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every time an AI startup raises money at a higher valuation, the investor raises the value of its stake on its books and counts the increase as income. &lt;strong&gt;No cash comes in. The profit is on paper.&lt;/strong&gt; [...] A large part of the sales and profits these companies report depends on money that investors, including the tech giants themselves, keep putting into OpenAI and Anthropic. If that funding slows, the backlog, the sales and the paper profits all weaken together.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Leaks of the week
&lt;/h1&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/DarkWebInformer/status/2106514093717008857?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;Tata Consultancy Services&lt;/strong&gt;&lt;/a&gt;: source code and credentials leaked.&lt;/p&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/DarkWebInformer/status/2106471572257050887?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;UAE government&lt;/strong&gt;&lt;/a&gt;: 17 millions entries from UAE government-related software licensing database&lt;/p&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/DarkWebInformer/status/2106465040115159224?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;Get covered&lt;/strong&gt;&lt;/a&gt;: more than 1 million customer records including email, phone numbers, physical address and more.&lt;/p&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/DarkWebInformer/status/2106403088835694632?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;CAPEB&lt;/strong&gt;&lt;/a&gt;: Around 4 millions records including emails and phone numbers.&lt;/p&gt;

&lt;p&gt;🐦 &lt;a href="https://x.com/CR1337/status/2107039062469353812?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;Denmark government&lt;/strong&gt;&lt;/a&gt;: 8.8 millions people impacted, Danish citizens and emigrates. The leak include  Social security number, Age, Sex, Family relations, Physical address, Protected addresses and Sex change.&lt;/p&gt;




&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2107477791549907153-99" src="https://platform.twitter.com/embed/Tweet.html?id=2107477791549907153"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2107477791549907153-99');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2107477791549907153&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Arikalabs/status/2106511599276061021?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdenxxeanzt6ajmr7p99t.png" alt=" " width="598" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/SmokeAwayyy/status/2106566046350258515?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpr7kg56fgpi8qmo9lnxg.png" alt=" " width="598" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/AmanVirk1/status/2106610500218061051?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flt7wlurausdxrnbp0cky.png" alt=" " width="598" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/agounardes/status/2106890198369947659?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi0c4nlas90znx8k3cng3.png" alt=" " width="598" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/JustDeezGuy/status/2106931338343526541?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxl1fj6kq6h5ulrq5wza9.png" alt=" " width="598" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/wangzhr4/status/2107059715956224145?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fob72kp3wotctnzkrqfcf.png" alt=" " width="598" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/ortegaalfredo/status/2107218272416587958?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feylhovw221rw0mzvfzsp.png" alt=" " width="598" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fep1kid7iqgy1mo3xrkeg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fep1kid7iqgy1mo3xrkeg.png" alt=" " width="598" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnfj43v1633ofmxxbprn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnfj43v1633ofmxxbprn5.png" alt=" " width="598" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/pmddomingos/status/2107598154799738891?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F84epcdo057elvdf3zauu.png" alt=" " width="598" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/louiseivan/status/2107542657874661780?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7htdee7zdxpf6ralc8m9.png" alt=" " width="598" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Ross__Hendricks/status/2108249887435620559?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgt4ck2e1hlgut9iv5lvi.png" alt=" " width="598" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/IceSolst/status/2108543740411584799?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqx24s1rxk9zbb0ox8eb5.png" alt=" " width="598" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/veorq/status/2108965379829797059?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk870134p86im0ny2ca4c.png" alt=" " width="598" height="98"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9qep2bbnh7laxp9h8oia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9qep2bbnh7laxp9h8oia.png" alt=" " width="680" height="675"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Cover Image by &lt;a href="https://unsplash.com/@puregeorgia?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Alfred Schrock&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/yellow-leaves-on-black-and-yellow-concrete-road-C7E8WTsvkmY?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>weekly</category>
      <category>review</category>
    </item>
    <item>
      <title>WeeklyReview#202640</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Mon, 05 Oct 2026 10:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/weeklyreview202640-5b8i</link>
      <guid>https://dev.to/niamtokik/weeklyreview202640-5b8i</guid>
      <description>&lt;p&gt;Another week of doing Erlang/Elixir code on &lt;code&gt;expki&lt;/code&gt; project. Again, that's mostly a sandbox to remove my 2 years rust doing only Erlang code and infrastructure stuff. Things are moving though, and I have a way to deal with the &lt;code&gt;public_key&lt;/code&gt; module from Elixir. It's not perfect yet and can be optimized, but it should do the job. I think you will read that in a post very soon.&lt;/p&gt;




&lt;p&gt;My way to extract macros and records from Erlang source code has been moved to its own module called &lt;a href="https://github.com/niamtokik/preprocessing" rel="noopener noreferrer"&gt;&lt;code&gt;preprocessing&lt;/code&gt;&lt;/a&gt;. It is currently being tested, but it should work correctly. Many things remain to be added though, like the support for dynamic macros and perhaps other attributes from Erlang.&lt;/p&gt;




&lt;p&gt;Dev.to is buggy. One big article I started to write few days ago was practically destroyed because of cache issue on the browser. When editing the file from the dashboard, an old version was displayed instead of the latest one. Don't save. Don't publish. Close the window, logout from your dev.to account and reconnect.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://github.com/niamtokik/publish" rel="noopener noreferrer"&gt;&lt;code&gt;publish&lt;/code&gt;&lt;/a&gt; is now able to fetch all the posts from dev.to using the API and curl. I did not have a lot of time working on it this week though. It would be really nice to migrate few  my articles very soon on my own domain.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://github.com/niamtokik/mac_randomizer" rel="noopener noreferrer"&gt;&lt;code&gt;mac_randomizer&lt;/code&gt;&lt;/a&gt; was a pet project I got year ago, simply an idea at first. I wanted to do a bit of C this week and started to play with that. Not a really serious project though.&lt;/p&gt;

&lt;h1&gt;
  
  
  Coding
&lt;/h1&gt;

&lt;p&gt;📖 &lt;a href="https://github.com/cs341-illinois/coursebook" rel="noopener noreferrer"&gt;&lt;strong&gt;Course book&lt;/strong&gt;&lt;/a&gt;: Open Source Introductory Systems Programming Textbook for the University of Illinois&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://zero-js.vercel.app/" rel="noopener noreferrer"&gt;&lt;strong&gt;zero-js&lt;/strong&gt;&lt;/a&gt;: compiling code in HTML/CSS directly, without javascript.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://david.alvarezrosa.com/posts/optimizing-a-lock-free-ring-buffer/" rel="noopener noreferrer"&gt;&lt;strong&gt;Optimizing a Lock-Free Ring Buffer&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://engineering.legendsoflearning.com/posts/generating-functions/" rel="noopener noreferrer"&gt;&lt;strong&gt;Simplify Function Generation in Elixir with Macros&lt;/strong&gt;&lt;/a&gt;: a quick reminder to generate function in Elixir with macros. A good way to do meta-programming.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://elixir.hexdocs.pm/anonymous-functions.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Elixir Anonymous functions&lt;/strong&gt;&lt;/a&gt;: official documentation about anonymous/lambda functions in Elixir.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://elixir.hexdocs.pm/main/quote-and-unquote.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Elixir Quote and unquote&lt;/strong&gt;&lt;/a&gt;: official documentation about metaprogramming elixir with quote and unquote.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/tuist/pulso" rel="noopener noreferrer"&gt;&lt;strong&gt;pulso&lt;/strong&gt;&lt;/a&gt;: A headless, open-source observability backend: unified logs, metrics, and traces access, built-in alerting, and a native Model Context Protocol (MCP) interface, built on Elixir/OTP with a Rust hot path for columnar data.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/imboy-pub/erlang_pay" rel="noopener noreferrer"&gt;&lt;strong&gt;erlang_pay&lt;/strong&gt;&lt;/a&gt;:  A pure-Erlang payment gateway library for Alipay (App pay), WeChat Pay v3 (JSAPI/Native) and Stripe (PaymentIntent).&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://blog.codingconfessions.com/p/how-copy-on-write-works-with-memory" rel="noopener noreferrer"&gt;&lt;strong&gt;How Copy-on-Write Works with Memory-Mapped Files&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://kobzol.github.io/rust/rustc/2025/05/20/disable-debuginfo-to-improve-rust-compile-times.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Disable debuginfo to improve Rust compile times&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://pikuma.com/blog/comanche-maps-reverse-engineering" rel="noopener noreferrer"&gt;&lt;strong&gt;Reverse Engineering Novalogic's Comanche Terrain Maps&lt;/strong&gt;&lt;/a&gt;: not an expert in game programming, but reverse engineering is an amazing field. This article explains how to reverse the maps from an old game, it's in C, and it's a great one! I liked this quote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Programmers in the early 90s didn't reinvent everything. They used the formats and tools the artists already had, like PCX files straight out of a paint program, and saved their cleverness for the parts that really needed it: the renderer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;📝 &lt;a href="https://buttondown.com/hillelwayne/archive/what-tla-can-and-cant-check/" rel="noopener noreferrer"&gt;&lt;strong&gt;What TLA+ can and can't check&lt;/strong&gt;&lt;/a&gt;: TLA+ fascinated me few years ago, and I started to learn it by myself. Unfortunately, I was not really good with it. Languages formal verifications/specifications can be challenging to learn, even more if you don't have any a real usage for them. It's good to read a post on this language, even more to clarify what TLA+ can do or not.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Compiler Options Hardening Guide for C and C++&lt;/strong&gt;&lt;/a&gt;: an extremely useful guide and reference to correctly set C compiler flags for hardened applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  Database
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/dbulashev/dasha" rel="noopener noreferrer"&gt;&lt;strong&gt;Dasha&lt;/strong&gt;&lt;/a&gt;: PostgreSQL performance dashboard for analyzing database cluster health, identifying problems, and providing optimization recommendations.&lt;/p&gt;

&lt;h1&gt;
  
  
  System
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://minios.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;MiniOS&lt;/strong&gt;&lt;/a&gt;: A full-featured desktop environment with a wide range of applications. Professional tools for creativity and development.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://vinix-os.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Vinix&lt;/strong&gt;&lt;/a&gt;: Vinix is an effort to write a modern, fast, and useful operating system in the &lt;a href="https://github.com/vlang/v" rel="noopener noreferrer"&gt;V programming language&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://hardenedbsd.org/article/shawn-webb/2026-09-27/hardenedbsd-august-september-2026-status-report" rel="noopener noreferrer"&gt;&lt;strong&gt;HardenedBSD August / September 2026 Status Report&lt;/strong&gt;&lt;/a&gt;: mostly small modification and bug/security fixes.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://undeadly.org/cgi?action=article;sid=20260927120854" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenBSD-current has moved to version 8.0&lt;/strong&gt;&lt;/a&gt;: openbsd 8.0 will be ready soon.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://undeadly.org/cgi?action=article;sid=20260927115632" rel="noopener noreferrer"&gt;&lt;strong&gt;vmm(4)/vmd(8) gain support for multi-processor VMs&lt;/strong&gt;&lt;/a&gt;: OpenBSD vmm/vmd can now have more than one CPU configured, that's a very good news!&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://it-notes.dragas.net/2026/09/28/smartos-the-illumos-way-of-thinking-about-servers/" rel="noopener noreferrer"&gt;&lt;strong&gt;SmartOS: The illumos Way of Thinking About Servers&lt;/strong&gt;&lt;/a&gt;: sunos, illumos and smartos... A good way to introduce them via this article.&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/imthenachoman/How-To-Secure-A-Linux-Server" rel="noopener noreferrer"&gt;&lt;strong&gt;How To Secure A Linux Server&lt;/strong&gt;&lt;/a&gt;: An evolving how-to guide for securing a Linux server that, hopefully, also teaches you a little about security and why it matters.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.powerpc-notebook.org/2026/09/powerboard-tyche-unveiled-at-pianeta-amiga/" rel="noopener noreferrer"&gt;&lt;strong&gt;Powerboard Tyche unveiled at Pianeta Amiga&lt;/strong&gt;&lt;/a&gt;: Never got an Amiga, never installed AmigaOS, but since I learnt DragonFlyBSD kernel was a mix between FreeBSD and AmigaOS, I always wanted to test it. Another crazy thing is... the community is active! The passion for Amiga seems eternal. Crazy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Security
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://blog.trailofbits.com/2026/09/18/auditing-in-the-age-of-good-enough-ai/" rel="noopener noreferrer"&gt;&lt;strong&gt;Auditing in the age of (good enough) AI&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/newliver666/apk-reverse" rel="noopener noreferrer"&gt;&lt;strong&gt;apk-reverse&lt;/strong&gt;&lt;/a&gt;: a skill to reverse APK.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://cloud.google.com/blog/topics/threat-intelligence/hardening-code-pipelines-and-ci-cd-infrastructure" rel="noopener noreferrer"&gt;&lt;strong&gt;Proactive Defense: Hardening Code Pipelines and CI/CD Infrastructure&lt;/strong&gt;&lt;/a&gt;: a must read to apply modern protection on CI/CD.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Organizations should mandate a minimum release-age cooldown of seven days before any newly published public package version becomes installable [...] Establishing a strict seven-day buffer provides the open-source ecosystem time to detect and pull poisoned releases before they reach internal builds. [...] All external packages and container images should, wherever possible, route through a centralized internal proxy that caches, inspects, and gates each component.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;📝 &lt;a href="https://blog.qualys.com/vulnerabilities-threat-research/2026/09/28/developer-new-perimeter-supply-chain-cloud-breaches" rel="noopener noreferrer"&gt;&lt;strong&gt;The Developer is the New Perimeter: How Supply Chain Attacks Are Becoming Cloud Breaches&lt;/strong&gt;&lt;/a&gt;: the number of supply chain attacks is growing, and this is another article to remind us to always verify the security of our CI/CD.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.404media.co/cops-can-bypass-iphone-automatic-inactivity-reboot-graykey/" rel="noopener noreferrer"&gt;&lt;strong&gt;Cops Can Bypass iPhone’s Automatic Reboot to Get Into Locked Phones, Leaked Video Claims&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Security/Cryptography
&lt;/h1&gt;

&lt;p&gt;📑 &lt;a href="https://eprint.iacr.org/2026/2162.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;A Survey of Pseudorandom Codes&lt;/strong&gt;&lt;/a&gt;: &lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://eprint.iacr.org/2026/2145.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Fully Anonymous Perfect Secret-Sharing&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/atheonxyz/jolt" rel="noopener noreferrer"&gt;&lt;strong&gt;Jolt&lt;/strong&gt;&lt;/a&gt;: Just One Lookup Table. Jolt is a zkVM (zero-knowledge virtual machine) for RISC-V, built to be the simplest, fastest, and most extensible general-purpose of its kind. A &lt;a href="https://jolt.a16zcrypto.com/" rel="noopener noreferrer"&gt;book&lt;/a&gt; is available.&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://eprint.iacr.org/2026/2158.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Formally Modeling the Terrapin Attack on SSH&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://eprint.iacr.org/2026/2138.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;DASH: Distributed Asynchronous Schnorr with High Throughput&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://eprint.iacr.org/2026/2096.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Perpetual Encryption&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://eprint.iacr.org/2026/2080.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Lightweight Cryptography for Secure UAV Data Integrity Using Ascon-XOF128 and SHAKE128&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://eprint.iacr.org/2026/2131.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;Forging 1024-bit RSA signatures in nearly SNFS time&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📑 &lt;a href="https://eprint.iacr.org/2026/2167.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;New Applications of RSA&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Security/RedTeam
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://hackers-arise.com/offensive-security-pentesting-office-phones-with-sipvicious/" rel="noopener noreferrer"&gt;&lt;strong&gt;Offensive Security: Pentesting Office Phones with SIPVicious&lt;/strong&gt;&lt;/a&gt;: a post showing a quick demo of &lt;a href="https://github.com/EnableSecurity/sipvicious" rel="noopener noreferrer"&gt;sipvicious&lt;/a&gt; against VoIP local server.&lt;/p&gt;

&lt;h1&gt;
  
  
  Embedded
&lt;/h1&gt;

&lt;p&gt;🏗️ &lt;a href="https://github.com/rems-project/sail" rel="noopener noreferrer"&gt;&lt;strong&gt;Sail architecture definition language&lt;/strong&gt;&lt;/a&gt;: Sail is a language for defining the instruction-set architecture (ISA) semantics of processors: the architectural specification of the behaviour of machine instructions. Sail is an engineer-friendly language, much like earlier vendor pseudocode, but more precisely defined and with tooling to support a wide range of use-cases.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://hackaday.com/2026/09/26/you-can-make-a-microprocessor-thats-all-your-own/" rel="noopener noreferrer"&gt;&lt;strong&gt;You Can Make A Microprocessor That’s All Your Own&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://terminalbytes.com/reverse-engineering-ipod-classic-mikey-chip/" rel="noopener noreferrer"&gt;&lt;strong&gt;Reverse Engineering the iPod Classic's Undocumented Mikey Chip&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Updates/Upgrades
&lt;/h1&gt;

&lt;p&gt;🔄 &lt;a href="https://github.com/benoitc/hackney/releases/tag/4.8.1" rel="noopener noreferrer"&gt;&lt;strong&gt;Hackney 4.8.4&lt;/strong&gt;&lt;/a&gt;: many updates here, from the 4.8.1 to 4.8.4, fixing many bugs. If you are using a previous version, you should probably update it.&lt;/p&gt;

&lt;p&gt;🔄 &lt;a href="https://www.openbsd.org/errata79.html" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenBSD 7.9 Errata&lt;/strong&gt;&lt;/a&gt;: a huge amount of patch (9) to fix security issues on the whole system. &lt;code&gt;ldapd&lt;/code&gt;, &lt;code&gt;nsd&lt;/code&gt; (8 CVEs), &lt;code&gt;unbound&lt;/code&gt; (35 CVEs), &lt;code&gt;iked&lt;/code&gt; and many other issues found on the kernel.&lt;/p&gt;

&lt;p&gt;🔄 &lt;a href="https://www.qubes-os.org/news/2026/10/02/qubes-os-4-3-2-has-been-released/" rel="noopener noreferrer"&gt;&lt;strong&gt;Qubes OS 4.3.2&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Misc
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://siboehm.com/articles/22/CUDA-MMM" rel="noopener noreferrer"&gt;&lt;strong&gt;How to Optimize a CUDA Matmul Kernel for cuBLAS-like Performance: a Worklog&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://horace.io/brrr_intro.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Making Deep Learning Go Brrrr From First Principles&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://futurism.com/artificial-intelligence/ai-bros-meltdown-feelings" rel="noopener noreferrer"&gt;&lt;strong&gt;AI Bros Are Having a Meltdown Because the Associated Press Stylebook Clarifies That AIs Don’t Have Feelings&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.404media.co/someone-torturing-llms-in-a-robot-prison-has-triggered-the-dumbest-debate-in-ai-yet/" rel="noopener noreferrer"&gt;&lt;strong&gt;Someone ‘Torturing’ LLMs in a Robot Prison Has Triggered the Dumbest Debate in AI Yet&lt;/strong&gt;&lt;/a&gt;: Yeah. Crazy right? LLMs are not conscious. Adding a "feature" to feel pain/pleasure in a program does not make it conscious, it adds just another variable in the state, or another way to interpret inputs. This can be called - at best - "LLM moding".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AIs are not conscious. &lt;strong&gt;They do not feel, experience, or suffer&lt;/strong&gt;. They do not have innate preferences or underlying motivations. &lt;strong&gt;They are sequence completion engines&lt;/strong&gt;, internally hollow, &lt;strong&gt;designed to follow instructions&lt;/strong&gt;, and accomplish goals set by humans. Unfortunately, there’s a growing chorus of people who argue that AIs could now be, or may soon become, conscious. They argue that AIs may deserve rights and protections similar to those that we provide other conscious beings […] If this is how AI is developed, it will have a disastrous impact on the wellbeing of humanity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Leaks of the week
&lt;/h1&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/alertes/alaxione-mukgc44jlfsfro727v" rel="noopener noreferrer"&gt;&lt;strong&gt;Alaxione&lt;/strong&gt;&lt;/a&gt;: more than 8.5 millions patients impacted, data from 2010 to 2026. +5 millions phone numbers leaked, +1.4 millions e-mail, +300k social security number.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/alertes/groupe-kel-orisha-mukzqxqoj9x80n11kl" rel="noopener noreferrer"&gt;&lt;strong&gt;KEL/Orisha&lt;/strong&gt;&lt;/a&gt;: 1.3 million people impacted including +600k e-mail, +600+ phone number, +140k IBAN.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://www.glow.io/blogs/how-ai-agents-exposed-developer-screenshots-from-leading-tech-companies" rel="noopener noreferrer"&gt;&lt;strong&gt;PixelLeak: How AI Agents Exposed Developer Screenshots from Leading Tech Companies&lt;/strong&gt;&lt;/a&gt;: Glow labs identified more than 13k screenshots from 300 organizations (including big companies). Impacted more than 900 repositories and 100k employees. It seems it was mostly skill issue there, and the "AI" were not hardened. Interesting leaks though, because if screenshots can leak, probably other data can be leak as well.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/alertes/f-d-ration-fran-aise-de-la-randonn-e-ffr-mun6o16r4h0ud0vz18i" rel="noopener noreferrer"&gt;&lt;strong&gt;FFRandonnée&lt;/strong&gt;&lt;/a&gt;: 1.43 millions impacted people, more than 1 million e-mail and 663k phone numbers, with physical address location.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://frenchbreaches.com/alertes/cookson-clal-muomsy4ng1mk25gtxwj" rel="noopener noreferrer"&gt;&lt;strong&gt;Cookson-CLAL&lt;/strong&gt;&lt;/a&gt;: complete credit card information have been leaked. No more information about the number of people impacted though.&lt;/p&gt;

&lt;p&gt;📝 &lt;a href="https://fuitesinfos.fr/article/2026-10-01-vosfactures" rel="noopener noreferrer"&gt;&lt;strong&gt;VosFactures&lt;/strong&gt;&lt;/a&gt;: data leaks on one of the companies in charge of the digital invoices in France. No more information right now, but they have a database with more than 500k companies. Less than 1 month after the official launching of the digital invoices for the companies, one of the "big player" seems to have been impacted by a huge data leaks.&lt;/p&gt;




&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2104051150274408672-700" src="https://platform.twitter.com/embed/Tweet.html?id=2104051150274408672"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2104051150274408672-700');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2104051150274408672&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/rawsalerts/status/2103520617144389928?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flcl1vqj8axiy2b8rm8av.png" alt=" " width="598" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/tomhacks/status/2103630947883057565?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl38xmzhtzftm91zk22my.png" alt=" " width="598" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Qivshi1/status/2103856150592545225?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxvtmxz3u8tl5fvvvzcwi.png" alt=" " width="598" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/evisdrenova/status/2104052883662717347?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxmkqvc994059i11t8erq.png" alt=" " width="598" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Quasilocal/status/2104106284274581643?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffxewcf9ivfb3vz30rjlq.png" alt=" " width="598" height="682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/banteg/status/2103958454708920387?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fys5ato4curslczk559fg.png" alt=" " width="598" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/CorpAbsurdity/status/2103874469311734112?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpow6lmhf3tzrc5bwtxlh.png" alt=" " width="598" height="785"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/wangzhr4/status/2104220073120702579?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frdulc3vadvactqbcsazm.png" alt=" " width="598" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/C2IRIS/status/2104231952643428477?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr61i7i77n4v2tvow3yg7.png" alt=" " width="598" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/jaredLunde/status/2104240208032190768?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff0s5baxm2l2pbymb3op2.png" alt=" " width="598" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/PoetsLab/status/2104065575580262701?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpwtmq2gdyyskmhn679u5.png" alt="AI is malware" width="598" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Mikymigs/status/2104232663968293336?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa7xf6clcq18syvn0ya2x.png" alt="AI is cancer" width="598" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/jrysana/status/2104441570179404176?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Freiy8nrtr49nhurpowoy.png" alt=" " width="598" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxcmsfmyomvitovcwq3qc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxcmsfmyomvitovcwq3qc.png" alt=" " width="598" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Polymarket/status/2104499605245251664?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjn51inumhx9c17vrs3vu.png" alt=" " width="598" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Polymarket/status/2104719103810224299?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdnlc6vd8z2vqf4dex7rn.png" alt="Anthropic’s IPO prospectus reveals a staggering $42,000,000,000.00 net loss in 2025." width="598" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/lcamtuf/status/2105023754263028011?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwtk7ac8ru4lqpq8cpssc.png" alt=" " width="598" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Grady_Booch/status/2105157423615156439?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdd1i71lt6z7i818oxyoc.png" alt=" " width="598" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/headzoo/status/2105055215024009662?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqrs5cklhd1bsuhu29aoe.png" alt=" " width="598" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/mrjasonchoi/status/2105959199452844384?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr706o4vbxgwnryudhjz5.png" alt=" " width="598" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/shcallaway/status/2106142042405453879?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmbkzqedcalh5v73tpeh8.png" alt=" " width="598" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/LeoBuilds_/status/2106159384787345556?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff37g39oam9frnos18quq.png" alt=" " width="598" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/straceX/status/2106374472966295641?s=20" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcg7askrvwonmhsuahhkc.png" alt=" " width="598" height="138"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fue5f6xw0u722zuw1nqtk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fue5f6xw0u722zuw1nqtk.png" alt=" " width="500" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl1ygagmx4xwhe2kr0wha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl1ygagmx4xwhe2kr0wha.png" alt=" " width="800" height="794"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2z3p5texyicdqwl6yi7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2z3p5texyicdqwl6yi7n.png" alt=" " width="510" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyc22b3o6fvb0e1yh5qr5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyc22b3o6fvb0e1yh5qr5.png" alt=" " width="680" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fghmynwt9m8j9q9xu5krh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fghmynwt9m8j9q9xu5krh.png" alt=" " width="500" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcrk08a1uk64jq1w7ibbi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcrk08a1uk64jq1w7ibbi.png" alt=" " width="680" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frdcssgauqxyhmbkbi5nu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frdcssgauqxyhmbkbi5nu.png" alt=" " width="586" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Febwl67dqyedpoxrwjoob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Febwl67dqyedpoxrwjoob.png" alt=" " width="648" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8qmakhnzqzdmplr6i5et.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8qmakhnzqzdmplr6i5et.png" alt=" " width="612" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg3ndxogdb6xtulvrtala.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg3ndxogdb6xtulvrtala.png" alt=" " width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Cover Image by &lt;a href="https://unsplash.com/@kostyadyadyun?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Konstantin Dyadyun&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/brown-trees-on-brown-field-during-daytime-50hhiZf9vI0?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>weekly</category>
      <category>review</category>
    </item>
    <item>
      <title>Erlang Preprocessor and Elixir Interoperability</title>
      <dc:creator>Mathieu Kerjouan</dc:creator>
      <pubDate>Thu, 01 Oct 2026 10:00:00 +0000</pubDate>
      <link>https://dev.to/niamtokik/erlang-preprocessor-and-elixir-interoperability-4bof</link>
      <guid>https://dev.to/niamtokik/erlang-preprocessor-and-elixir-interoperability-4bof</guid>
      <description>&lt;p&gt;Erlang and Elixir are both running on the BEAM, the Erlang Virtual Machine, designed for long-living and distribute. In most of the case, talking to Erlang modules via Elixir is straightforward, doing the opposite can be a bit challenging though, but it is okay. In few cases though, extracting values from Erlang can become a real problem. The Erlang PreProcessor (&lt;code&gt;epp&lt;/code&gt;) is used to expand Erlang macros before compiling the code, this is a similar feature than one can found in &lt;code&gt;C&lt;/code&gt;, &lt;code&gt;C++&lt;/code&gt; and many other languages. This is a powerful way to avoid code-deduplication, and optimize the execution of the code by directly applying a data-structure instead of a reference. It has many other benefits, but this is not the place here to list them all.&lt;/p&gt;

&lt;h1&gt;
  
  
  Erlang From Code Source to AST
&lt;/h1&gt;

&lt;p&gt;Before doing anything, one should understand a bit how Erlang and the BEAM are working together. The procedure to compile Erlang source code into a binary file is a complex process, but it is possible to have the big picture in few steps.&lt;/p&gt;

&lt;p&gt;Firstly, one need to create a file containing Erlang source code. In fact, this is not mandatory to create a file... but we will see that later. As reminder, an Erlang file prefix is &lt;code&gt;.erl&lt;/code&gt;, and the name of the file must match the name of the module defined in the module itself..&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mod.erl &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="go"&gt;-module(mod).
-compile(export_all).
&lt;/span&gt;&lt;span class="gp"&gt;-define(DATA, &amp;lt;&amp;lt;1,2,3,4,5&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;f() -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;?DATA.
&lt;span class="go"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code created is straightforward. A simple module is created exporting all functions, a macro is defined containing a binary, and finally, a function called &lt;code&gt;f/0&lt;/code&gt; is defined, returning the content of the macro.&lt;/p&gt;

&lt;p&gt;The second step is to call the Erlang preprocessor called &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; to expand all &lt;a href="https://erlang.org/documentation/doc-4.8.2/doc/extensions/macros.html" rel="noopener noreferrer"&gt;macros&lt;/a&gt; and generate the final source code. The preprocessor will import functions or data-structures from the external libraries (&lt;code&gt;-include&lt;/code&gt; and &lt;code&gt;-include_lib&lt;/code&gt;), expands the macros (&lt;code&gt;-define&lt;/code&gt; and &lt;code&gt;?MACRO&lt;/code&gt;) and can return a list of tokens or the fully expanded source code. This part can easily be seen by using the &lt;code&gt;-P&lt;/code&gt; or &lt;code&gt;-E&lt;/code&gt; flags with the command &lt;a href="https://www.erlang.org/doc/apps/erts/erlc_cmd.html" rel="noopener noreferrer"&gt;&lt;code&gt;erlc&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erlc &lt;span class="nt"&gt;-P&lt;/span&gt; mod.erl
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;mod.P
&lt;span class="go"&gt;-file("mod.erl", 1).
-module(mod).
-compile(export_all).

&lt;/span&gt;&lt;span class="gp"&gt;f() -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;    &amp;lt;&amp;lt;1,2,3,4,5&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the file &lt;code&gt;mod.P&lt;/code&gt; does not have any &lt;code&gt;-define&lt;/code&gt; attribute, and the macro has been expanded. A new attribute &lt;code&gt;-file&lt;/code&gt; has also been added to the source, at the first line. The preprocessor did its job, and the source code can now be tokenized.&lt;/p&gt;

&lt;p&gt;The tokenization procedure can't be seen via a command line, and it will be required to evaluate an Erlang one-line with the &lt;a href="https://www.erlang.org/doc/apps/erts/erl_cmd.html" rel="noopener noreferrer"&gt;&lt;code&gt;erl&lt;/code&gt;&lt;/a&gt; command to have an idea of what's happening.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erl &lt;span class="nt"&gt;-noshell&lt;/span&gt; &lt;span class="nt"&gt;-eval&lt;/span&gt; &lt;span class="s1"&gt;'
&lt;/span&gt;&lt;span class="go"&gt;  {ok, M}=file:read_file("mod.P"), 
  T = erl_scan:string(binary_to_list(M)),
  io:format("~p~n", [T]),
  init:stop().
'
{ok,[{'-',1},
     {atom,1,file},
     {'(',1},
     {string,1,"mod.erl"},
     {',',1},
     {integer,1,1},
     {')',1},
     {dot,1},
     {'-',3},
     {atom,3,module},
     {'(',3},
     {atom,3,mod},
     {')',3},
     {dot,3},
     {'-',5},
     {atom,5,compile},
     {'(',5},
     {atom,5,export_all},
     {')',5},
     {dot,5},
     {atom,7,f},
     {'(',7},
     {')',7},
&lt;/span&gt;&lt;span class="gp"&gt;     {'-&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;',7},
&lt;/span&gt;&lt;span class="go"&gt;     {'&amp;lt;&amp;lt;',8},
     {integer,8,1},
     {',',8},
     {integer,8,2},
     {',',8},
     {integer,8,3},
     {',',8},
     {integer,8,4},
     {',',8},
     {integer,8,5},
&lt;/span&gt;&lt;span class="gp"&gt;     {'&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;',8},
&lt;/span&gt;&lt;span class="go"&gt;     {dot,8}],
    12}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;mod.P&lt;/code&gt; has been used instead of &lt;code&gt;mod.erl&lt;/code&gt;, because usually, the scanner is scanning the expanded file, not the one containing the macros. This snippet is reading the source code, calling &lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_scan.html#string/3" rel="noopener noreferrer"&gt;&lt;code&gt;erl_scan:string/1&lt;/code&gt;&lt;/a&gt; to scan the tokens, &lt;a href="https://www.erlang.org/doc/apps/stdlib/io.html#t:format/0" rel="noopener noreferrer"&gt;&lt;code&gt;io:format/2&lt;/code&gt;&lt;/a&gt; is called to print the result and finally, the VM is stopped by invoking &lt;a href="https://www.erlang.org/doc/apps/erts/init.html#stop/0" rel="noopener noreferrer"&gt;&lt;code&gt;init:stop/0&lt;/code&gt;&lt;/a&gt;. The result displayed is a list of tokens containing the annotations for each characters.&lt;/p&gt;

&lt;p&gt;A quick note here, &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; is usually privileged than &lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_scan.html" rel="noopener noreferrer"&gt;&lt;code&gt;erl_scan&lt;/code&gt;&lt;/a&gt;. The tokens from &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html#parse_file/2" rel="noopener noreferrer"&gt;&lt;code&gt;epp:parse_file/2&lt;/code&gt;&lt;/a&gt; are already ready to be used with the parser. Here and example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erl &lt;span class="nt"&gt;-noshell&lt;/span&gt; &lt;span class="nt"&gt;-eval&lt;/span&gt; &lt;span class="s1"&gt;'
&lt;/span&gt;&lt;span class="go"&gt;  {ok, T} = epp:parse_file("./mod.erl", [{source_name, mod}]),
  io:format("~p~n", [T]),
  init:stop().
'
[{attribute,1,file,{"mod",1}},
 {attribute,1,module,mod},
 {attribute,2,compile,export_all},
 {function,5,f,0,
           [{clause,5,[],[],
                    [{bin,5,
                          [{bin_element,5,{integer,5,1},default,default},
                           {bin_element,5,{integer,5,2},default,default},
                           {bin_element,5,{integer,5,3},default,default},
                           {bin_element,5,{integer,5,4},default,default},
                           {bin_element,5,{integer,5,5},default,default}]}]}]},
 {eof,6}]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let continue on the previous procedure. The next step before generating the AST (Abstract Syntax Tree) above, is to parse the tokens produced by &lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_scan.html" rel="noopener noreferrer"&gt;&lt;code&gt;erl_scan&lt;/code&gt;&lt;/a&gt;. To do that, &lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_parse.html" rel="noopener noreferrer"&gt;&lt;code&gt;erl_parse&lt;/code&gt;&lt;/a&gt; module is used. The final result can be produced with the &lt;code&gt;-S&lt;/code&gt; flag when calling &lt;a href="https://www.erlang.org/doc/apps/erts/erlc_cmd.html" rel="noopener noreferrer"&gt;&lt;code&gt;erlc&lt;/code&gt;&lt;/a&gt; or by calling &lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_parse.html" rel="noopener noreferrer"&gt;&lt;code&gt;erl_parse&lt;/code&gt;&lt;/a&gt; directly from the shell. Below, the AST produced by &lt;a href="https://www.erlang.org/doc/apps/erts/erlc_cmd.html" rel="noopener noreferrer"&gt;&lt;code&gt;erlc&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erlc &lt;span class="nt"&gt;-S&lt;/span&gt; mod.erl
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;mod.S
&lt;span class="go"&gt;{module, mod}.  %% version = 0
{exports, [{f,0},{module_info,0},{module_info,1}]}.
{attributes, []}.
{labels, 7}.
{function, f, 0, 2}.
  {label,1}.
    {line,[{location,"mod.erl",5}]}.
    {func_info,{atom,mod},{atom,f},0}.
  {label,2}.
&lt;/span&gt;&lt;span class="gp"&gt;    {move,{literal,&amp;lt;&amp;lt;1,2,3,4,5&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,&lt;span class="o"&gt;{&lt;/span&gt;x,0&lt;span class="o"&gt;}}&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;    return.
{function, module_info, 0, 4}.
  {label,3}.
    {line,[]}.
    {func_info,{atom,mod},{atom,module_info},0}.
  {label,4}.
    {move,{atom,mod},{x,0}}.
    {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
{function, module_info, 1, 6}.
  {label,5}.
    {line,[]}.
    {func_info,{atom,mod},{atom,module_info},1}.
  {label,6}.
    {move,{x,0},{x,1}}.
    {move,{atom,mod},{x,0}}.
    {call_ext_only,2,{extfunc,erlang,get_module_info,2}}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The very same result can be done using &lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_parse.html#parse_form/1" rel="noopener noreferrer"&gt;&lt;code&gt;erl_parse:parse_form/1&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_parse.html#parse_exprs/1" rel="noopener noreferrer"&gt;&lt;code&gt;erl_parse:parse_exprs/1&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_parse.html#parse_term/1" rel="noopener noreferrer"&gt;&lt;code&gt;erl_parse_term/1&lt;/code&gt;&lt;/a&gt; when the tokens are grouped using the &lt;code&gt;{dot,_}&lt;/code&gt; token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erl_parse:parse_form&lt;span class="o"&gt;([&lt;/span&gt;
&lt;span class="go"&gt;  {'-',1},{atom,1,file},{'(',1},
    {string,1,"mod.erl"},{',',1},
  {integer,1,1},{')',1},{dot,1}
]).
{ok,{attribute,1,file,{"mod.erl",1}}}

&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erl_parse:parse_form&lt;span class="o"&gt;([&lt;/span&gt;
&lt;span class="gp"&gt;  {atom,7,f}, {'(',7}, {')',7}, {'-&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;',7},
&lt;/span&gt;&lt;span class="go"&gt;     {'&amp;lt;&amp;lt;',8},
       {integer,8,1}, {',',8},
       {integer,8,2}, {',',8},
       {integer,8,3}, {',',8},
       {integer,8,4}, {',',8},
       {integer,8,5},
&lt;/span&gt;&lt;span class="gp"&gt;     {'&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;',8},
&lt;/span&gt;&lt;span class="go"&gt;     {dot,8}
]).
{ok,{function,7,f,0,
              [{clause,7,[],[],
                       [{bin,8,
                             [{bin_element,8,{integer,8,1},default,default},
                              {bin_element,8,{integer,8,2},default,default},
                              {bin_element,8,{integer,8,3},default,default},
                              {bin_element,8,{integer,8,4},default,default},
                              {bin_element,8,{integer,8,5},default,default}]}]}]}}

&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erl_parse:parse_term&lt;span class="o"&gt;([&lt;/span&gt;
&lt;span class="go"&gt;  {'&amp;lt;&amp;lt;',8},
    {integer,8,1}, {',',8},
    {integer,8,2}, {',',8},
    {integer,8,3}, {',',8},
    {integer,8,4}, {',',8},
    {integer,8,5},
&lt;/span&gt;&lt;span class="gp"&gt;  {'&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;',8},
&lt;/span&gt;&lt;span class="go"&gt;  {dot,8}
]).
&lt;/span&gt;&lt;span class="gp"&gt;{ok,&amp;lt;&amp;lt;1,2,3,4,5&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;ok, File&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; file:read_file&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"mod.P"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, 
&lt;span class="go"&gt;  {ok, Tokens, _} = erl_scan:string(
    binary_to_list(File)
  ),
  {_, AST} = lists:foldl(fun
&lt;/span&gt;&lt;span class="gp"&gt;      (D = {dot, _}, {Buf, Acc}) -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;        {ok, R} = erl_parse:parse_form(
          lists:reverse([D|Buf])
        ),
&lt;/span&gt;&lt;span class="gp"&gt;        {[], [R|Acc]};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;      (T, {Buf,Acc}) -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;        {[T|Buf], Acc}
    end,
    {[], []},
    Tokens
  ),
  lists:reverse(AST).
[{attribute,1,file,{"mod.erl",1}},
 {attribute,3,module,mod},
 {attribute,5,compile,export_all},
 {function,7,f,0,
           [{clause,7,[],[],
                    [{bin,8,
                          [{bin_element,8,{integer,8,1},default,default},
                           {bin_element,8,{integer,8,2},default,default},
                           {bin_element,8,{integer,8,3},default,default},
                           {bin_element,8,{integer,8,4},default,default},
                           {bin_element,8,{integer,8,...},default,default}]}]}]}]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More steps are executed after generating the AST, a linter and other checkers can verify the code, but it will be discarded in this part of the article. To finally generate the Erlang bytecode, the file with &lt;code&gt;.beam&lt;/code&gt; prefix, containing the compiled source code, one can call &lt;a href="https://www.erlang.org/doc/apps/erts/erlc_cmd.html" rel="noopener noreferrer"&gt;&lt;code&gt;erlc&lt;/code&gt;&lt;/a&gt; again or use the &lt;a href="https://www.erlang.org/doc/apps/compiler/compile.html#file/1" rel="noopener noreferrer"&gt;&lt;code&gt;compile:file/2&lt;/code&gt;&lt;/a&gt; function when a file is available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erlc mod.erl
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file mod.beam                                                                                                                                                                                                                                                                 
&lt;span class="go"&gt;mod.beam: Erlang BEAM file

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;hexdump &lt;span class="nt"&gt;-C&lt;/span&gt; mod.beam        
&lt;span class="go"&gt;00000000  46 4f 52 31 00 00 02 50  42 45 41 4d 41 74 55 38  |FOR1...PBEAMAtU8|
00000010  00 00 00 2d ff ff ff fb  30 6d 6f 64 10 66 b0 6d  |...-....0mod.f.m|
00000020  6f 64 75 6c 65 5f 69 6e  66 6f 60 65 72 6c 61 6e  |odule_info`erlan|
00000030  67 f0 67 65 74 5f 6d 6f  64 75 6c 65 5f 69 6e 66  |g.get_module_inf|
00000040  6f 00 00 00 43 6f 64 65  00 00 00 47 00 00 00 10  |o...Code...G....|
00000050  00 00 00 00 00 00 00 b1  00 00 00 07 00 00 00 03  |................|
00000060  01 10 99 10 02 12 22 00  01 20 40 47 00 03 13 01  |......".. @G....|
00000070  30 99 00 02 12 32 00 01  40 40 12 03 4e 10 00 01  |0....2..@@..N...|
00000080  50 99 00 02 12 32 10 01  60 40 03 13 40 12 03 4e  |P....2..`@..@..N|
00000090  20 10 03 00 53 74 72 54  00 00 00 00 49 6d 70 54  | ...StrT....ImpT|
000000a0  00 00 00 1c 00 00 00 02  00 00 00 04 00 00 00 05  |................|
000000b0  00 00 00 01 00 00 00 04  00 00 00 05 00 00 00 02  |................|
000000c0  45 78 70 54 00 00 00 28  00 00 00 03 00 00 00 03  |ExpT...(........|
000000d0  00 00 00 01 00 00 00 06  00 00 00 03 00 00 00 00  |................|
000000e0  00 00 00 04 00 00 00 02  00 00 00 00 00 00 00 02  |................|
000000f0  4c 69 74 54 00 00 00 17  00 00 00 00 00 00 00 01  |LitT............|
00000100  00 00 00 0b 83 6d 00 00  00 05 01 02 03 04 05 00  |.....m..........|
00000110  4d 65 74 61 00 00 00 2d  83 6c 00 00 00 01 68 02  |Meta...-.l....h.|
00000120  77 10 65 6e 61 62 6c 65  64 5f 66 65 61 74 75 72  |w.enabled_featur|
00000130  65 73 6c 00 00 00 01 77  0a 6d 61 79 62 65 5f 65  |esl....w.maybe_e|
00000140  78 70 72 6a 6a 00 00 00  4c 6f 63 54 00 00 00 04  |xprjj...LocT....|
00000150  00 00 00 00 41 74 74 72  00 00 00 27 83 6c 00 00  |....Attr...'.l..|
00000160  00 01 68 02 77 03 76 73  6e 6c 00 00 00 01 6e 10  |..h.w.vsnl....n.|
00000170  00 00 4a 2a a7 c3 41 6d  91 07 cf f0 1d 6d 6e 00  |..J*..Am.....mn.|
00000180  85 6a 6a 00 43 49 6e 66  00 00 00 48 83 6c 00 00  |.jj.CInf...H.l..|
00000190  00 03 68 02 77 07 76 65  72 73 69 6f 6e 6b 00 07  |..h.w.versionk..|
000001a0  39 2e 30 2e 36 2e 31 68  02 77 07 6f 70 74 69 6f  |9.0.6.1h.w.optio|
000001b0  6e 73 6a 68 02 77 06 73  6f 75 72 63 65 6b 00 13  |nsjh.w.sourcek..|
000001c0  2f 74 6d 70 2f 65 72 6c  61 6e 67 2f 6d 6f 64 2e  |/tmp/erlang/mod.|
000001d0  65 72 6c 6a 44 62 67 69  00 00 00 48 83 68 03 77  |erljDbgi...H.h.w|
000001e0  0d 64 65 62 75 67 5f 69  6e 66 6f 5f 76 31 77 11  |.debug_info_v1w.|
000001f0  65 72 6c 5f 61 62 73 74  72 61 63 74 5f 63 6f 64  |erl_abstract_cod|
00000200  65 68 02 77 04 6e 6f 6e  65 6c 00 00 00 01 68 02  |eh.w.nonel....h.|
00000210  77 03 63 77 64 6b 00 0b  2f 74 6d 70 2f 65 72 6c  |w.cwdk../tmp/erl|
00000220  61 6e 67 6a 4c 69 6e 65  00 00 00 15 00 00 00 00  |angjLine........|
00000230  00 00 00 00 00 00 00 03  00 00 00 01 00 00 00 00  |................|
00000240  51 00 00 00 54 79 70 65  00 00 00 0a 00 00 00 03  |Q...Type........|
00000250  00 00 00 01 0f ff 00 00                           |........|
00000258
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have only the AST instead of a file containing the source code, the &lt;a href="https://www.erlang.org/doc/apps/compiler/compile.html#t:forms/0" rel="noopener noreferrer"&gt;&lt;code&gt;compile:forms/2&lt;/code&gt;&lt;/a&gt; function can be invoked. It will return the name of the module as &lt;code&gt;atom()&lt;/code&gt; and the bytecode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;AST&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;epp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;parse_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./mod.erl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="n"&gt;source_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;}]).&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,[{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="s"&gt;"mod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;export_all&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,[],[],&lt;/span&gt;
                        &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                              &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="n"&gt;bin_element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                               &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bin_element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                               &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bin_element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,...},&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                               &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bin_element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,...},&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,...},&lt;/span&gt;
                               &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bin_element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,{...},...}]}]}]},&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;}]}&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Bytecode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;AST&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="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;228&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;69&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;116&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;251&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;109&lt;/span&gt;&lt;span class="p"&gt;,...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;write_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/tmp/mod.beam"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Bytecode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="n"&gt;ok&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be sure the bytecode is working, let open another shell and load it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file mod.beam
&lt;span class="go"&gt;mod.beam: Erlang BEAM file

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;hexdump &lt;span class="nt"&gt;-C&lt;/span&gt; mod.beam
&lt;span class="go"&gt;00000000  46 4f 52 31 00 00 01 e4  42 45 41 4d 41 74 55 38  |FOR1....BEAMAtU8|
00000010  00 00 00 2d ff ff ff fb  30 6d 6f 64 10 66 b0 6d  |...-....0mod.f.m|
00000020  6f 64 75 6c 65 5f 69 6e  66 6f 60 65 72 6c 61 6e  |odule_info`erlan|
00000030  67 f0 67 65 74 5f 6d 6f  64 75 6c 65 5f 69 6e 66  |g.get_module_inf|
00000040  6f 00 00 00 43 6f 64 65  00 00 00 47 00 00 00 10  |o...Code...G....|
00000050  00 00 00 00 00 00 00 b1  00 00 00 07 00 00 00 03  |................|
00000060  01 10 99 10 02 12 22 00  01 20 40 47 00 03 13 01  |......".. @G....|
00000070  30 99 00 02 12 32 00 01  40 40 12 03 4e 10 00 01  |0....2..@@..N...|
00000080  50 99 00 02 12 32 10 01  60 40 03 13 40 12 03 4e  |P....2..`@..@..N|
00000090  20 10 03 00 53 74 72 54  00 00 00 00 49 6d 70 54  | ...StrT....ImpT|
000000a0  00 00 00 1c 00 00 00 02  00 00 00 04 00 00 00 05  |................|
000000b0  00 00 00 01 00 00 00 04  00 00 00 05 00 00 00 02  |................|
000000c0  45 78 70 54 00 00 00 28  00 00 00 03 00 00 00 03  |ExpT...(........|
000000d0  00 00 00 01 00 00 00 06  00 00 00 03 00 00 00 00  |................|
000000e0  00 00 00 04 00 00 00 02  00 00 00 00 00 00 00 02  |................|
000000f0  4c 69 74 54 00 00 00 17  00 00 00 00 00 00 00 01  |LitT............|
00000100  00 00 00 0b 83 6d 00 00  00 05 01 02 03 04 05 00  |.....m..........|
00000110  4c 6f 63 54 00 00 00 04  00 00 00 00 41 74 74 72  |LocT........Attr|
00000120  00 00 00 27 83 6c 00 00  00 01 68 02 77 03 76 73  |...'.l....h.w.vs|
00000130  6e 6c 00 00 00 01 6e 10  00 f2 e4 49 4c e5 8b 35  |nl....n....IL..5|
00000140  3f a4 aa a7 4e af 2c 9c  e1 6a 6a 00 43 49 6e 66  |?...N.,..jj.CInf|
00000150  00 00 00 28 83 6c 00 00  00 02 68 02 77 07 76 65  |...(.l....h.w.ve|
00000160  72 73 69 6f 6e 6b 00 07  39 2e 30 2e 36 2e 31 68  |rsionk..9.0.6.1h|
00000170  02 77 07 6f 70 74 69 6f  6e 73 6a 6a 44 62 67 69  |.w.optionsjjDbgi|
00000180  00 00 00 2e 83 68 03 77  0d 64 65 62 75 67 5f 69  |.....h.w.debug_i|
00000190  6e 66 6f 5f 76 31 77 11  65 72 6c 5f 61 62 73 74  |nfo_v1w.erl_abst|
000001a0  72 61 63 74 5f 63 6f 64  65 68 02 77 04 6e 6f 6e  |ract_codeh.w.non|
000001b0  65 6a 00 00 4c 69 6e 65  00 00 00 1b 00 00 00 00  |ej..Line........|
000001c0  00 00 00 00 00 00 00 03  00 00 00 01 00 00 00 01  |................|
000001d0  12 51 00 03 6d 6f 64 00  54 79 70 65 00 00 00 0a  |.Q..mod.Type....|
000001e0  00 00 00 03 00 00 00 01  0f ff 00 00              |............|
000001ec

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erl &lt;span class="nt"&gt;-noshell&lt;/span&gt; &lt;span class="nt"&gt;-eval&lt;/span&gt; &lt;span class="s1"&gt;'
&lt;/span&gt;&lt;span class="go"&gt;  io:format("~p~n", [mod:f()]),
  init:stop().
'
&lt;/span&gt;&lt;span class="gp"&gt;&amp;lt;&amp;lt;1,2,3,4,5&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is only the tip of the iceberg, the compilation process in Erlang is way more complex than that. In fact, many parts of the pipeline have been discarded. Anyway, the goal of this section was simply to show you how to generate quickly Erlang bytecode. The only interesting step for the goal of the post is the preprocessing one. The idea is to extract Erlang records and macros from Erlang source code and convert them into something usable in Elixir.&lt;/p&gt;

&lt;p&gt;A last note regarding the compilation process. As you probably know, Elixir templating system using macros is really powerful and the abstraction has been really well designed. Did you know Erlang got the same feature years ago? Indeed, it is also possible to compile dynamically the code or alter the AST directly from the virtual machine via &lt;a href="https://www.erlang.org/doc/apps/syntax_tools/merl.html" rel="noopener noreferrer"&gt;&lt;code&gt;merl&lt;/code&gt;&lt;/a&gt; (for Metaprogramming in Erlang). It's way more complex to use than Elixir templates, but it works pretty well.&lt;/p&gt;

&lt;p&gt;BONUS: it is also possible to disassemble the bytecode generated by this process using the &lt;a href="https://www.erlang.org/doc/apps/stdlib/beam_lib.html#chunks/3" rel="noopener noreferrer"&gt;&lt;code&gt;beam_lib:all_chunks/1&lt;/code&gt;&lt;/a&gt; function. It will then give you a better view of the content of a beam file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erl &lt;span class="nt"&gt;-noshell&lt;/span&gt; &lt;span class="nt"&gt;-eval&lt;/span&gt; &lt;span class="s1"&gt;'
&lt;/span&gt;&lt;span class="go"&gt;  {ok, F} = file:read_file("./mod.beam"),
  {ok,_,Bytes} = beam_lib:all_chunks(F),
  io:format("~p~n", [Bytes]),
  init:stop().
'
[{"AtU8",
  &amp;lt;&amp;lt;255,255,255,251,48,109,111,100,16,102,176,109,111,100,117,108,101,95,105,
    110,102,111,96,101,114,108,97,110,103,240,103,101,116,95,109,111,100,117,
&lt;/span&gt;&lt;span class="gp"&gt;    108,101,95,105,110,102,111&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="go"&gt; {"Code",
  &amp;lt;&amp;lt;0,0,0,16,0,0,0,0,0,0,0,177,0,0,0,7,0,0,0,3,1,16,153,16,2,18,34,0,1,32,64,
    71,0,3,19,1,48,153,0,2,18,50,0,1,64,64,18,3,78,16,0,1,80,153,0,2,18,50,16,
&lt;/span&gt;&lt;span class="gp"&gt;    1,96,64,3,19,64,18,3,78,32,16,3&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="gp"&gt; {"StrT",&amp;lt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="gp"&gt; {"ImpT",&amp;lt;&amp;lt;0,0,0,2,0,0,0,4,0,0,0,5,0,0,0,1,0,0,0,4,0,0,0,5,0,0,0,2&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="go"&gt; {"ExpT",
  &amp;lt;&amp;lt;0,0,0,3,0,0,0,3,0,0,0,1,0,0,0,6,0,0,0,3,0,0,0,0,0,0,0,4,0,0,0,2,0,0,0,0,0,
&lt;/span&gt;&lt;span class="gp"&gt;    0,0,2&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="gp"&gt; {"LitT",&amp;lt;&amp;lt;0,0,0,0,0,0,0,1,0,0,0,11,131,109,0,0,0,5,1,2,3,4,5&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="go"&gt; {"Meta",
  &amp;lt;&amp;lt;131,108,0,0,0,1,104,2,119,16,101,110,97,98,108,101,100,95,102,101,97,116,
    117,114,101,115,108,0,0,0,1,119,10,109,97,121,98,101,95,101,120,112,114,
&lt;/span&gt;&lt;span class="gp"&gt;    106,106&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="gp"&gt; {"LocT",&amp;lt;&amp;lt;0,0,0,0&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="go"&gt; {"Attr",
  &amp;lt;&amp;lt;131,108,0,0,0,1,104,2,119,3,118,115,110,108,0,0,0,1,110,16,0,0,74,42,167,
&lt;/span&gt;&lt;span class="gp"&gt;    195,65,109,145,7,207,240,29,109,110,0,133,106,106&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="go"&gt; {"CInf",
  &amp;lt;&amp;lt;131,108,0,0,0,3,104,2,119,7,118,101,114,115,105,111,110,107,0,7,57,46,48,
    46,54,46,49,104,2,119,7,111,112,116,105,111,110,115,106,104,2,119,6,115,
    111,117,114,99,101,107,0,19,47,116,109,112,47,101,114,108,97,110,103,47,
&lt;/span&gt;&lt;span class="gp"&gt;    109,111,100,46,101,114,108,106&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="go"&gt; {"Dbgi",
  &amp;lt;&amp;lt;131,104,3,119,13,100,101,98,117,103,95,105,110,102,111,95,118,49,119,17,
    101,114,108,95,97,98,115,116,114,97,99,116,95,99,111,100,101,104,2,119,4,
    110,111,110,101,108,0,0,0,1,104,2,119,3,99,119,100,107,0,11,47,116,109,
&lt;/span&gt;&lt;span class="gp"&gt;    112,47,101,114,108,97,110,103,106&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="gp"&gt; {"Line",&amp;lt;&amp;lt;0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,0,81&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}&lt;/span&gt;,
&lt;span class="gp"&gt; {"Type",&amp;lt;&amp;lt;0,0,0,3,0,0,0,1,15,255&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are even more curious about this bonus, you are invited to read &lt;a href="https://github.com/happi/theBeamBook" rel="noopener noreferrer"&gt;The Beam Book&lt;/a&gt;, you will find there way more information!&lt;/p&gt;

&lt;h1&gt;
  
  
  Erlang Preprocessor (&lt;code&gt;epp&lt;/code&gt;)
&lt;/h1&gt;

&lt;p&gt;The &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; module is in charge to parse and expand macros from Erlang source code. Its source code implementation resides in &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/epp.erl" rel="noopener noreferrer"&gt;&lt;code&gt;lib/stdlib/epp.erl&lt;/code&gt;&lt;/a&gt;. The content can be intimidating with its 2600 lines of code, but it is not the most complex to read.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;epp&lt;/code&gt; is starting its own server process handling I/O protocols to read data byte by byte with the help of the &lt;a href="https://www.erlang.org/doc/apps/stdlib/io.html#scan_erl_form/3" rel="noopener noreferrer"&gt;&lt;code&gt;io:scan_erl_form/3&lt;/code&gt;&lt;/a&gt;. This server is having its own state updated every time a new correct value is parsed. Let begins our investigation by using the easiest function available to parse and expands macros, &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html#parse_file/2" rel="noopener noreferrer"&gt;&lt;code&gt;epp:parse_file/2&lt;/code&gt;&lt;/a&gt;. Ah, before doing that, let improve a bit our test module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mod2.erl &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="go"&gt;-module(mod2).
-compile(export_all).
-record(test, {field1}).
&lt;/span&gt;&lt;span class="gp"&gt;-define(DATA, &amp;lt;&amp;lt;1,2,3,4,5&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;f() -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;?DATA
&lt;span class="go"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An Erlang record called &lt;code&gt;test&lt;/code&gt; has been added. It was missing from the previous module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;ok, AST&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; epp:parse_file&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"mod2.erl"&lt;/span&gt;, &lt;span class="o"&gt;[])&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;{ok,[{attribute,1,file,{"mod2.erl",1}},
     {attribute,1,module,mod2},
     {attribute,2,compile,export_all},
     {attribute,3,record,
                {test,[{record_field,3,{atom,3,field1}}]}},
     {function,6,f,0,
               [{clause,6,[],[],
                        [{bin,6,
                              [{bin_element,6,{integer,6,1},default,default},
                               {bin_element,6,{integer,6,...},default,default},
                               {bin_element,6,{integer,...},default,...},
                               {bin_element,6,{...},...},
                               {bin_element,6,...}]}]}]},
     {eof,7}]}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, a new attribute for the record is present, containing its description but there is no trace of the &lt;code&gt;DATA&lt;/code&gt; macro defined (again). This is because &lt;code&gt;epp&lt;/code&gt; returns the fully expand source code. Great, but those macros should be stored somewhere... right? Indeed, they are stored inside the &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/epp.erl#L276" rel="noopener noreferrer"&gt;&lt;code&gt;#epp{}&lt;/code&gt; record&lt;/a&gt; present in the epp server's state. Unfortunately, this server is not directly available when using &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html#parse_file/2" rel="noopener noreferrer"&gt;&lt;code&gt;epp:parse_file/2&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html#open/1" rel="noopener noreferrer"&gt;&lt;code&gt;epp:open/1&lt;/code&gt;&lt;/a&gt; must be used instead. This function is opening a file using I/O protocols and returns a process identifier to extract all tokens step by steps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;ok, EppProcess&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; epp:open&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"mod2.erl"&lt;/span&gt;, &lt;span class="o"&gt;[]&lt;/span&gt;, &lt;span class="o"&gt;[])&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="gp"&gt;{ok,&amp;lt;0.175.0&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To avoid repetitive task, let create &lt;code&gt;EppRead/2&lt;/code&gt; lambda function to incrementally read the tokens from the epp server. Every time &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html#scan_erl_form/1" rel="noopener noreferrer"&gt;&lt;code&gt;epp:scan_erl_form/1&lt;/code&gt;&lt;/a&gt; is called, the epp server should send a message containing its position in the file. When it reaches the end of the file, it sends &lt;code&gt;{eof, Line}&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;EppRead &lt;span class="o"&gt;=&lt;/span&gt; fun EppRead&lt;span class="o"&gt;(&lt;/span&gt;Pid, Buffer&lt;span class="o"&gt;)&lt;/span&gt; -&amp;gt;
&lt;span class="go"&gt;  case epp:scan_erl_form(Pid) of
&lt;/span&gt;&lt;span class="gp"&gt;    {ok, T} -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;EppRead&lt;span class="o"&gt;(&lt;/span&gt;Pid, Buffer ++ T&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="gp"&gt;    {eof, _} -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;ok, Buffer&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;  end
end.
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;Fun&amp;lt;erl_eval.18.113135111&amp;gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;ok, Forms&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; EppRead&lt;span class="o"&gt;(&lt;/span&gt;EppProcess, &lt;span class="o"&gt;[])&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;[{'-',1},
 {atom,1,file},
 {'(',1},
 {string,1,"mod.erl"},
 {',',1},
 {integer,1,1},
 {')',1},
 {dot,1},
 {'-',1},
 {atom,1,module},
 {'(',1},
 {atom,1,mod},
 {')',1},
 {dot,1},
 {'-',2},
 {atom,2,compile},
 {'(',2},
 {atom,2,export_all},
 {')',2},
 {dot,2},
 {atom,5,f},
 {'(',5},
 {')',5},
&lt;/span&gt;&lt;span class="gp"&gt; {'-&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;',5},
&lt;/span&gt;&lt;span class="go"&gt; {'&amp;lt;&amp;lt;',5},
 {integer,5,1},
 {',',5},
 {integer,...},
 {...}|...]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, the tokens are available, it means it works correctly without any syntax errors. How to extract the process state? The &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; server does not support &lt;code&gt;sys&lt;/code&gt; patterns, and using &lt;a href="https://www.erlang.org/doc/apps/stdlib/sys.html#get_state/1" rel="noopener noreferrer"&gt;&lt;code&gt;sys:get_state/1&lt;/code&gt;&lt;/a&gt; will simply froze the current process. If you read the source code of the module, you will find the undocumented &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/epp.erl#L456" rel="noopener noreferrer"&gt;&lt;code&gt;macro_defs/1&lt;/code&gt;&lt;/a&gt; function. It sends a message to an &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; server and should return the list of macros stored in &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/epp.erl#L1172" rel="noopener noreferrer"&gt;server's state&lt;/a&gt;. Let reimplement this function ourselves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;GetMacros &lt;span class="o"&gt;=&lt;/span&gt; fun &lt;span class="o"&gt;(&lt;/span&gt;Pid&lt;span class="o"&gt;)&lt;/span&gt; -&amp;gt;
&lt;span class="go"&gt;  Pid ! {epp_request, self(), macro_defs},
  receive
&lt;/span&gt;&lt;span class="gp"&gt;    {epp_reply, Pid, Macros} -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Macros
&lt;span class="go"&gt;  after
&lt;/span&gt;&lt;span class="gp"&gt;    1000 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;error
&lt;span class="go"&gt;  end
end.
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;Fun&amp;lt;erl_eval.42.113135111&amp;gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;GetMacros&lt;span class="o"&gt;(&lt;/span&gt;EppProcess&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;[{{atom,'FEATURE_ENABLED'},[{1,{['X'],[{atom,1,false}]}}]},
 {{atom,'FEATURE_AVAILABLE'},
  [{1,
    {['X'],
     [{'(',1},
      {'(',1},
      {var,1,'X'},
      {')',1},
      {'==',1},
      {atom,1,maybe_expr},
      {')',1}]}}]},
 {{atom,'OTP_RELEASE'},{none,[{integer,1,28}]}},
 {{atom,'MACHINE'},{none,[{atom,1,'BEAM'}]}},
 {{atom,'LINE'},{none,[{integer,1,1}]}},
 {{atom,'FILE'},{none,[{string,1,"mod2.erl"}]}},
 {{atom,'MODULE'},{none,[{atom,1,mod2}]}},
 {{atom,'MODULE_STRING'},{none,[{string,1,"mod2"}]}},
 {{atom,'BASE_MODULE'},undefined},
 {{atom,'BASE_MODULE_STRING'},undefined},
 {{atom,'FUNCTION_ARITY'},undefined},
 {{atom,'FUNCTION_NAME'},undefined},
 {{atom,'BEAM'},{none,[{atom,1,true}]}},
 {{atom,'DATA'},
  [{none,{none,[{'&amp;lt;&amp;lt;',4},
                {integer,4,1},
                {',',4},
                {integer,4,2},
                {',',4},
                {integer,4,...},
                {',',...},
                {...}|...]}}]}]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indeed, all the macros have been returned, including the one defined by &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt;. The format of the macros stored here can be described below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;atom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;MacroName&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;MacroArity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;MacroTermOrExprs&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;The name of the macro is defined in &lt;code&gt;MacroName&lt;/code&gt; as a &lt;code&gt;charlist()&lt;/code&gt; type. The next part is the definition of the macro where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;MacroArity&lt;/code&gt; is the arity of the macro. If the macro does not have argument, it is set to &lt;code&gt;none&lt;/code&gt;, else, it is set to a strictly positive integer greater than 0.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;MacroTermOrExprs&lt;/code&gt; is the content of the macro, it can contain an Erlang term or an expression, and can also contain a variable previously defined in the argument part.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because &lt;code&gt;mod2.erl&lt;/code&gt; does not define any macros with arguments, let creates one to see how it is represented.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="ni"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DYN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This macro when extracted looks like the Erlang term below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;atom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;'DYN'&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="n"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;'Y'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;'Z'&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;'Y'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;'Z'&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="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;As you can see, this is not so different than the rest of AST, the arguments defined in the macro are expanded in the body of the macro  using the token &lt;code&gt;{var, Line, ArgumentName}&lt;/code&gt;. Finally, don't forget to close the file to avoid file descriptor exception at the end of this experiment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;epp:close&lt;span class="o"&gt;(&lt;/span&gt;EppServer&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;ok
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's great, it is now possible to extract both records and macros, one from the AST, the other one directly from the preprocessor state. Let find a way to deal with that in Elixir.&lt;/p&gt;

&lt;h1&gt;
  
  
  Erlang Records in Elixir
&lt;/h1&gt;

&lt;p&gt;Elixir already has an interface to deal with Erlang records called &lt;a href="https://elixir.hexdocs.pm/Record.html" rel="noopener noreferrer"&gt;&lt;code&gt;Record&lt;/code&gt;&lt;/a&gt;. This is working well in most of the case, let just have a look on it. First, a record can only created inside a module, because it uses Elixir meta-programming feature with macros and templates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; r.ex &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="go"&gt;defmodule R do
  require Record

  Record.defrecord(:test, data: "test")
end
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;c&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"r.ex"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;[R]

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;import R
&lt;span class="go"&gt;R

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;R.test&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="go"&gt;{:test, "test"}

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;R.test&lt;span class="o"&gt;(&lt;/span&gt;:data&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;1

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;R.test&lt;span class="o"&gt;()&lt;/span&gt; |&amp;gt; R.test&lt;span class="o"&gt;(&lt;/span&gt;data: &lt;span class="s2"&gt;"updated"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;{:test, "updated"}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, great, but now, let check a real-world Erlang records from some very used modules, like &lt;a href="https://www.erlang.org/doc/apps/public_key/public_key.html" rel="noopener noreferrer"&gt;&lt;code&gt;public_key&lt;/code&gt;&lt;/a&gt;. Most if not all records are defined in &lt;a href="https://github.com/erlang/otp/blob/master/lib/public_key/include/public_key.hrl" rel="noopener noreferrer"&gt;&lt;code&gt;public_key/include/public_key.hrl&lt;/code&gt;&lt;/a&gt;. The first one you will encounter is the &lt;code&gt;RSAPublicKey&lt;/code&gt; record.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="ni"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;'RSAPublicKey'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;modulus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;publicExponent&lt;/span&gt;
 &lt;span class="p"&gt;}).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can you see the problem here? When using the Elixir Record module, it creates a function to simulate the behavior of the record, but here, the record identifier is a word starting with an uppercase character. It is not possible to create a function with an uppercase character in Elixir. Just to be sure, a new module containing a function starting with an uppercase letter can be created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; up.ex &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="go"&gt;defmodule Up do
  def TestFunction(), do: 1
end
EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex&amp;gt; c("up.ex")
== Compilation error in file up.ex ==
** (SyntaxError) invalid syntax found on up.ex:2:19:
    error: unexpected ( after alias TestFunction. Function names and identifiers in Elixir start with lowercase characters or underscore. For example:

        hello_world()
        _starting_with_underscore()
        numb3rs_are_allowed()
        may_finish_with_question_mark?()
        may_finish_with_exclamation_mark!()

    Unexpected token: (
    │
  2 │   def TestFunction(), do: 1
    │                   ^
    │
    └─ up.ex:2:19
    (elixir 1.19.5) lib/kernel/parallel_compiler.ex:530: anonymous fn/5 in Kernel.ParallelCompiler.spawn_workers/8
** (CompileError) compile error
    (iex 1.19.5) lib/iex/helpers.ex:245: IEx.Helpers.c/2
    iex:15: (file)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, you would probably say something like "not a problem, if it's the only record...", I stop you right there. More than 150 records are using this format in the &lt;code&gt;public_key&lt;/code&gt; module. Defining 150+ functions is annoying, but because they are all following the same pattern, macros or module templates can be used.&lt;/p&gt;

&lt;p&gt;This issue can be solved in many different ways, the first one is to create a function &lt;code&gt;record/1&lt;/code&gt; where the first argument will contain the record name as an &lt;code&gt;atom()&lt;/code&gt; starting with an uppercase. Every new record can be added like that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;R.record&lt;span class="o"&gt;(&lt;/span&gt;:RSAPrivateKey&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;{:RSAPrivateKey, :undefined, :undefined}

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;R.record&lt;span class="o"&gt;(&lt;/span&gt;:RSAPrivateKey, modulus: 3, publicExponent: 111&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;{:RSAPrivateKey, 3, 111}

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;R.record&lt;span class="o"&gt;(&lt;/span&gt;:RSAPrivateKey&lt;span class="o"&gt;)&lt;/span&gt; |&amp;gt; R.record&lt;span class="o"&gt;(&lt;/span&gt;:modulus, 3&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;{:RSAPrivateKey, 3, :undefined}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second solution is the one I prefer. Instead of creating a function containing all record in one place, why not creating a module containing an Elixir struct to represent the record itself? Well, let create the module in charge of that. It will be called &lt;a href="https://github.com/niamtokik/preprocessing" rel="noopener noreferrer"&gt;&lt;code&gt;Preprocessing&lt;/code&gt;&lt;/a&gt; and the sources are already available on github&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Preprocessing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Record&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Listing the available records from an Erlang file is one of the main requirement. To do that, it is possible to mix 2 functions, &lt;code&gt;:code.lib_dir/1&lt;/code&gt; to get the path of the module, and &lt;code&gt;:epp.parse_file/2&lt;/code&gt; to parse the Erlang source code. The &lt;code&gt;list_records/3&lt;/code&gt; function returns all the record identifier as &lt;code&gt;[atom()]&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;list_records&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="p"&gt;%{})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="ss"&gt;:code&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lib_dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;list_records2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;list_records2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;source_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:source_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
         &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="ss"&gt;:epp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;source_name:&lt;/span&gt; &lt;span class="n"&gt;source_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;record_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record_name&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="no"&gt;false&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, a way to extract the records is required as well. In this case, the &lt;code&gt;Record.extract/2&lt;/code&gt; can be reused without, it has been created for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="no"&gt;Atom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="no"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;from_lib:&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the module template can be created with the help of the special macro called &lt;code&gt;__using__/1&lt;/code&gt;. When used on another module, it will generate all the required functions to deal with the imported record.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmacro&lt;/span&gt; &lt;span class="n"&gt;__using__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;record_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:record_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;filepath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;
    &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
    &lt;span class="n"&gt;tuple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:record_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_tuple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Macro&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;record_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="kn"&gt;quote&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Preprocessing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Record&lt;/span&gt;

      &lt;span class="k"&gt;defstruct&lt;/span&gt; &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;is_valid?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="k"&gt;cond&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
          &lt;span class="n"&gt;is_tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; 
            &lt;span class="ss"&gt;:erlang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; 
            &lt;span class="ss"&gt;:erlang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
          &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_struct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_tuple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_valid?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="n"&gt;record_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="no"&gt;Tuple&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(%&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
              &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;end&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="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:invalid_tuple&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:invalid_term&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;convert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
          &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! Let creates our first interface to an existing record. &lt;code&gt;#RSAPublicKey{}&lt;/code&gt; from the &lt;code&gt;public_key&lt;/code&gt; module is a good target.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Preprocessing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;PublicKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;RSAPublicKey&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Preprocessing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;record_id:&lt;/span&gt; &lt;span class="ss"&gt;:RSAPublicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;module:&lt;/span&gt; &lt;span class="ss"&gt;:public_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;filepath:&lt;/span&gt; &lt;span class="s2"&gt;"include/public_key.hrl"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all. The project can now be recompile and it will be possible to test our new module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;Preprocessing.PublicKey.RSAPublicKey
&lt;span class="go"&gt;Preprocessing.PublicKey.RSAPublicKey

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;RSAPublicKey.is_valid?&lt;span class="o"&gt;({&lt;/span&gt;:RSAPublicKey, :undefined, :undefined&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="go"&gt;true

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;RSAPublicKey.is_valid?&lt;span class="o"&gt;({&lt;/span&gt;:RSAPublicKey&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="go"&gt;false

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;RSAPublicKey.keys&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="go"&gt;[:modulus, :publicExponent]

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;RSAPublicKey.struct&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="go"&gt;%PublicKey.RSAPublicKey{
  modulus: :undefined,
  publicExponent: :undefined
}

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;%RSAPublicKey&lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="go"&gt;%RSAPublicKey{
  modulus: :undefined,
  publicExponent: :undefined
}

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;RSAPublicKey.convert&lt;span class="o"&gt;(&lt;/span&gt;%RSAPublicKey&lt;span class="o"&gt;{})&lt;/span&gt;
&lt;span class="go"&gt;{:RSAPublicKey, :undefined, :undefined}

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;RSAPublicKey.convert&lt;span class="o"&gt;({&lt;/span&gt;:RSAPublicKey, :undefined, :undefined&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="go"&gt;%PublicKey.RSAPublicKey{
  modulus: :undefined,
  publicExponent: :undefined
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This module is not perfect though. For example, a function to valid and convert the data correctly from the Elixir struct to the record and vice verse is required. At this time, the developer is in charge of creating the interface for this process. This solution still looks better than the first one. Every new records are treated as individual data-structure defined in their own containers with their own functions. &lt;/p&gt;

&lt;h1&gt;
  
  
  Erlang Macros Definition in Elixir
&lt;/h1&gt;

&lt;p&gt;The Erlang preprocessor macros are not so different than the Erlang records, except when it comes to their arity. In this implementation, only static macros will be supported, but it should not be too complex to implement something with arguments support. Anyway, in a previous section, we saw the macros where stored in the &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; server process state and must be extracted with an undocumented function from the &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; module. In fact, most of the hard work is already done, now, we need a way to integrate them in Elixir.&lt;/p&gt;

&lt;p&gt;Static macros are basically made of a key and a value. Why not converting them as &lt;a href="https://elixir.hexdocs.pm/Map.html" rel="noopener noreferrer"&gt;&lt;code&gt;Map.t()&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://elixir.hexdocs.pm/Keyword.html" rel="noopener noreferrer"&gt;&lt;code&gt;Keyword.t()&lt;/code&gt;&lt;/a&gt; in this case? In fact, a macro with the same name than another one present below will overwrite the value of the previous definition. This means it's impossible to have a naming conflict, perfect for a &lt;a href="https://elixir.hexdocs.pm/Map.html" rel="noopener noreferrer"&gt;&lt;code&gt;Map.t()&lt;/code&gt;&lt;/a&gt;. First, let creates a new module called &lt;code&gt;Preprocessing.Macros&lt;/code&gt;, it will contain all the functions required to extract and convert macros, but also a template to include them inside another module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Preprocessing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Macros&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;definitions/2&lt;/code&gt; functions is the only one exported from the module, and will return the converted list of macros as &lt;code&gt;Map.t()&lt;/code&gt;. This function is used to generate the template but also to find all the macros from a specific module while developing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;definitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;open_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="ss"&gt;:ok&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;definitions_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;macros&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;definitions_macros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;convert_macros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;macros&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the remaining functions are not exposed to the rest of the application, and are being used to deal with every step of the conversion. The &lt;code&gt;open_file/2&lt;/code&gt; function is a wrapper around &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html#open/1" rel="noopener noreferrer"&gt;&lt;code&gt;:epp.open/2&lt;/code&gt;&lt;/a&gt;, checking if a path is available and returning the process id of the &lt;code&gt;epp&lt;/code&gt; server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;open_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="ss"&gt;:code&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lib_dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
          &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_charlist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:epp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;([],&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;definitions_loop/1&lt;/code&gt; function is quite stupid. It will simply read the content of the opened file until it reaches the end of it. When done, it simply return &lt;code&gt;:ok&lt;/code&gt;. In fact, this step is very important, because it will load all the macros from the file and store them in the &lt;code&gt;epp&lt;/code&gt; server's state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;definitions_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:epp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_erl_form&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:eof&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="ss"&gt;:ok&lt;/span&gt;
      &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;definitions_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;definitions_macros/1&lt;/code&gt; function sends the undocumented &lt;code&gt;:macro_defs&lt;/code&gt; message to the &lt;code&gt;eep&lt;/code&gt; server and wait for its answer containing the list of all parsed macros from the source code. Those macros (a list of tuple) is then returned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;definitions_macros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:epp_request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="ss"&gt;:macro_defs&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;receive&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:epp_reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;macros&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="ss"&gt;:epp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;macros&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="ss"&gt;:epp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;after&lt;/span&gt;
        &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
          &lt;span class="ss"&gt;:epp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:timeout&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every raw macros from the &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; server's state must be converted. The &lt;code&gt;convert_macros/2&lt;/code&gt; and &lt;code&gt;convert_macros_value/1&lt;/code&gt; functions are doing the conversion and the filtering. Indeed, we are looking only for the static macros right now, not for the one with an arity, then, only the macros set to &lt;code&gt;:none&lt;/code&gt; are kept, the rest are simply dropped.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;convert_macros&lt;/span&gt;&lt;span class="p"&gt;([],&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;buffer&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="ss"&gt;:ignored&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="no"&gt;false&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
          &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
     &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;convert_macros&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;macro&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="ss"&gt;:atom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;convert_macro_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;convert_macros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;macro&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;convert_macro_value&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="ss"&gt;none:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:none&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="ss"&gt;:erl_parse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_term&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="ss"&gt;:dot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1131&lt;/span&gt;&lt;span class="p"&gt;}])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;convert_macro_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:ignored&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;escape_keys/2&lt;/code&gt; function will escape the Erlang macros definitions to insert them safely in the module template via the &lt;a href="https://elixir.hexdocs.pm/main/Macro.html#escape/2" rel="noopener noreferrer"&gt;&lt;code&gt;Macro.escape/2&lt;/code&gt;&lt;/a&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;escape_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;definitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;defs&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:maps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_list&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Macro&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;macro_keys/2&lt;/code&gt; and &lt;code&gt;macro_values/2&lt;/code&gt; functions are respectively extracting the keys and the values of the macros, converting them into a &lt;code&gt;[term()]&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;macro_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;definitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;defs&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Macro&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;macro_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;definitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;defs&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Macro&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The module template definition is probably the most important part here, because it will integrate the data from the Erlang macros into the Elixir AST. 5 functions have been created to help users to check their macros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;macros/0&lt;/code&gt;: returns the macros as a &lt;code&gt;Map.t()&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;macro/1&lt;/code&gt;: returns the value of a defined macros using its &lt;code&gt;key&lt;/code&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;macro_keys/0&lt;/code&gt;: returns the list of all macro's keys;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;macro_values/0&lt;/code&gt;: returns the list of all macro's values;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;macro_filter/1&lt;/code&gt;: a wrapper around &lt;code&gt;Map.filter/2&lt;/code&gt; to filter the macros.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;defmacro&lt;/span&gt; &lt;span class="n"&gt;__using__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;filepath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;def_keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;escape_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kn"&gt;quote&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Preprocessing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Macros&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;macros&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;def_keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;macro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;def_keys&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;macro_keys&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;macro_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;macro_values&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;macro_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;macros_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;def_keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, the goal now is to create or update a module with this template. The best target here could be the &lt;code&gt;Preprocessing.PublicKey&lt;/code&gt; module. The module to parse the Erlang macros is &lt;code&gt;:public_key&lt;/code&gt; and the path for the header is &lt;code&gt;inclyde/public_key.hrl&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Preprocessing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;PublicKey&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Preprocessing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Macros&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;module:&lt;/span&gt; &lt;span class="ss"&gt;:public_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;filepath:&lt;/span&gt; &lt;span class="s2"&gt;"include/public_key.hrl"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, this interface can be tested. The &lt;code&gt;definitions/2&lt;/code&gt; function returns the correct values from different header files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;Preprocessing.Macros
&lt;span class="go"&gt;Preprocessing.Macros

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Macros.definitions&lt;span class="o"&gt;(&lt;/span&gt;:kernel, &lt;span class="s2"&gt;"include/file.hrl"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;{:ok, [FILE_HRL_: 1]}

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Macros.definitions&lt;span class="o"&gt;(&lt;/span&gt;:kernel, &lt;span class="s2"&gt;"include/inet.hrl"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;{:ok, []}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let have a look on the &lt;code&gt;Preprocessing.PublicKey&lt;/code&gt; module now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;Preprocessing.PublicKey
&lt;span class="go"&gt;alias Preprocessing.PublicKey
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;PublicKey.macros/0&lt;/code&gt; function returns all the available macros parsed from the Erlang source code as a &lt;a href="https://elixir.hexdocs.pm/Map.html" rel="noopener noreferrer"&gt;&lt;code&gt;Map.t()&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PublicKey.macros&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="go"&gt;%{
  sect163r1: {1, 3, 132, 0, 2},
  "ub-postal-code-length": 16,
  secp256k1: {1, 3, 132, 0, 10},
  "id-RSAES-OAEP": {1, 2, 840, 113549, 1, 1, 7},
  "id-ce-policyMappings": {2, 5, 29, 33},
  "id-at-pseudonym": {2, 5, 4, 65},
  affiliationChanged: 3,
  "id-at-localityName": {2, 5, 4, 7},
  "id-at-givenName": {2, 5, 4, 42},
  "id-pkix-ocsp-service-locator": {1, 3, 6, 1, 5, 5, 7, 48, 1, 7},
  "ub-name": 32768,
  "id-qt-cps": {1, 3, 6, 1, 5, 5, 7, 2, 1},
  "pbeWithSHA1AndDES-CBC": {1, 2, 840, 113549, 1, 5, 10},
  secp160k1: {1, 3, 132, 0, 9},
  sect409k1: {1, 3, 132, 0, 36},
  "id-ce-extKeyUsage": {2, 5, 29, 37},
  "id-ml-dsa-87": {2, 16, 840, 1, 101, 3, 4, 3, 19},
  emptyString: "",
&lt;/span&gt;&lt;span class="c"&gt;  ...
&lt;/span&gt;&lt;span class="go"&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;PublicKey.macro/1&lt;/code&gt; function is doing its job by returning the value of an existing key, or &lt;code&gt;nil&lt;/code&gt; if the key is not present.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PublicKey.macro&lt;span class="o"&gt;(&lt;/span&gt;:sect163r1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;{1, 3, 132, 0, 2}

&lt;/span&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PublicKey.macro&lt;span class="o"&gt;(&lt;/span&gt;:undefined&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;nil
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;PublicKey.macro_keys/0&lt;/code&gt; and &lt;code&gt;PublicKey.macro_values/0&lt;/code&gt; are returning respectively the keys and the values from the parsed macros.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;PublicKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;macro_keys&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sect163r1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:"ub-postal-code-length"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:secp256k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:"id-RSAES-OAEP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="ss"&gt;:"id-ce-policyMappings"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:"id-at-pseudonym"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:affiliationChanged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;PublicKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;macro_values&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;132&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;132&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;840&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;113549&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="o"&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 last, the &lt;code&gt;PublicKey.macro_filter/1&lt;/code&gt; can filter the keys/values from the macros to return only the one requested via the &lt;a href="https://elixir.hexdocs.pm/Map.html#filter/2" rel="noopener noreferrer"&gt;&lt;code&gt;Map.filter/2&lt;/code&gt;&lt;/a&gt; function. The following snippet is filtering the keys using a &lt;a href="https://elixir.hexdocs.pm/Regex.html" rel="noopener noreferrer"&gt;&lt;code&gt;Regex&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;iex&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;PublicKey.macro_filter&lt;span class="o"&gt;(&lt;/span&gt;fn &lt;span class="o"&gt;({&lt;/span&gt;key,_value&lt;span class="o"&gt;})&lt;/span&gt; -&amp;gt; 
&lt;span class="go"&gt;  cond do
&lt;/span&gt;&lt;span class="gp"&gt;    Regex.match?(~r"^rsa"i, Atom.to_string(key)) -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="gp"&gt;    true -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; 
&lt;span class="go"&gt;  end 
end)
%{
  "rSASSA-PSS-Default-Identifier": {:"RSASSA-AlgorithmIdentifier",
   {1, 2, 840, 113549, 1, 1, 10},
   {:"RSASSA-PSS-params", {:HashAlgorithm, {1, 3, 14, 3, 2, 26}, :NULL},
    {:MaskGenAlgorithm, {1, 2, 840, 113549, 1, 1, 8},
     {:HashAlgorithm, {1, 3, 14, 3, 2, 26}, :NULL}}, 20, 1}},
  "rSAES-OAEP-Default-Identifier": {:"RSAES-AlgorithmIdentifier",
   {1, 2, 840, 113549, 1, 1, 7},
   {:"RSAES-OAEP-params", {:Externalvaluereference, 354, :"PKCS-1", :sha1},
    {:Externalvaluereference, 355, :"PKCS-1", :mgf1SHA1},
    {:Externalvaluereference, 356, :"PKCS-1", :pSpecifiedEmpty}}},
  rsaEncryption: {1, 2, 840, 113549, 1, 1, 1}
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is now possible to extract and convert macros from Erlang world to the Elixir universe. This implementation is perhaps not the best one, but it will make my life easier while dealing with the &lt;code&gt;public_key&lt;/code&gt; module.&lt;/p&gt;

&lt;h1&gt;
  
  
  Real World Application
&lt;/h1&gt;

&lt;p&gt;This whole post is the consequence of a sandbox project called &lt;a href="https://github.com/niamtokik/expki" rel="noopener noreferrer"&gt;&lt;code&gt;expki&lt;/code&gt;&lt;/a&gt;, created to remove all my rust from years of doing Erlang and infrastructure stuff instead of Elixir. The goal was to use Elixir and Phoenix framework to manage a small local PKI (Public Key Infrastructure) compatible with &lt;a href="https://man.openbsd.org/openssl" rel="noopener noreferrer"&gt;&lt;code&gt;openssl&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/OpenVPN/easy-rsa" rel="noopener noreferrer"&gt;&lt;code&gt;easy_rsa&lt;/code&gt;&lt;/a&gt;, a tool provided by OpenVPN to manage certificates locally. In fact, when this project started, it was expected to have a working PoC quick because Erlang was already offering a good support for TLS with the &lt;a href="//www.erlang.org/doc/apps/public_key/public_key.html"&gt;&lt;code&gt;public_key&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.erlang.org/doc/apps/crypto/crypto.html" rel="noopener noreferrer"&gt;&lt;code&gt;crypto&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://www.erlang.org/doc/apps/asn1/api-reference.html" rel="noopener noreferrer"&gt;&lt;code&gt;asn1&lt;/code&gt;&lt;/a&gt; Erlang applications.&lt;/p&gt;

&lt;p&gt;Unfortunately, most of the records name present in those modules are starting with an uppercase letter... and it blocks to create something in a short amount of time. A big part of my time on &lt;code&gt;expki&lt;/code&gt; was dedicated to read the source code and the documentation of these modules or trying to find a better way to deal with the structure from them. Here the whole list of them extract from an older version of Erlang/OTP.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;from &lt;code&gt;public_key&lt;/code&gt; (157):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;#'AAControls'{}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#'ACClearAttrs'{}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AccessDescription'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AlgorithmIdentifier'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AlgorithmIdentifierPKCS5v2{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AlgorithmIdentifierPKCS{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AlgorithmIdentifier{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AnotherName'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AttCertValidityPeriod'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Attribute'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AttributeCertificate'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AttributeCertificateInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AttributePKCS{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AttributeTypeAndValue'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Attributes_SETOF'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Attributes_SETOF_valuesWithContext_SETOF'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'AuthorityKeyIdentifier'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'BasicConstraints'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'BasicOCSPResponse'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'BuiltInDomainDefinedAttribute'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'BuiltInStandardAttributes'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'CertID'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Certificate'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'CertificateList'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'CertificationRequest'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'CertificationRequestInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'CertificationRequestInfo_attributes_SETOF'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'CertificationRequestInfo_subjectPKInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'CertificationRequestInfo_subjectPKInfo_algorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'CertificationRequest_signatureAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Characteristic{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Clearance'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ContentEncryptionAlgorithmIdentifier'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ContentInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Context'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'CrlID'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Curve'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'DHParameter'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'DSAPrivateKey'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'DigestAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'DigestAlgorithmIdentifier'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'DigestEncryptionAlgorithmIdentifier'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'DigestInfoPKCS{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'DigestedData'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'DistributionPoint'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'DomainParameters'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Dss{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ECDSA{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ECParameters'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ECPoint'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ECPrivateKey'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'EDIPartyName'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'EncryptedContentInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'EncryptedData'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'EncryptedPrivateKeyInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'EnvelopedData'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ExtendedNetworkAddress_e163{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Extension'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ExtensionAttribute'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Extension{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'FieldID'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'GeneralSubtree'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'HashAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Holder'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'IetfAttrSyntax'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'IssuerAndSerialNumber'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'IssuerSerial'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'IssuingDistributionPoint'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'KeyEncryptionAlgorithmIdentifier'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'MaskGenAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'NameConstraints'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'NoticeReference'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OCSPRequest'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OCSPResponse'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ORAddress'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPAttributeTypeAndValue'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPCertificate'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPCharacteristic{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPExtension'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPExtensionAttribute'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPFieldID'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPNoticeReference'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPOLDSubjectPublicKeyInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPOLDSubjectPublicKeyInfo_algorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPSubjectPublicKeyInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPSubjectPublicKeyInfo{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPTBSCertificate'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OTPUserNotice'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ObjectDigestInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OneAsymmetricKey'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OneAsymmetricKey_privateKeyAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'OtherPrimeInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PBEParameter'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PBES2{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PBKDF2{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PBMAC1{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PDSParameter'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PKAttribute'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PKAttribute_valuesWithContext_SETOF'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PSourceAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Pentanomial'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PersonalName'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PolicyConstraints'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PolicyInformation'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PolicyMappings_SEQOF'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PolicyQualifierInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PreferredSignatureAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PresentationAddress'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PrivateKeyInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PrivateKeyInfo_privateKeyAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PrivateKeyUsagePeriod'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'PublicKeyAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'RC2{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'RC5{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'RSAES{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'RSAPrivateKey'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'RSAPublicKey'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'RSASSA{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'RecipientInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Request'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ResponseBytes'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ResponseData'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'RevokedInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'RoleSyntax'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SecurityCategory'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ServiceLocator'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Signature'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SignatureAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SignatureAlgorithm{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SignedAndEnvelopedData'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SignedData'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SignerInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SignerInfoAuthenticatedAttributes_aaSequence_SEQOF'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SignerInfoAuthenticatedAttributes_aaSet_SETOF'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SignerInfo_unauthenticatedAttributes_uaSequence_SEQOF'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SignerInfo_unauthenticatedAttributes_uaSet_SETOF'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SingleResponse'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SubjectPublicKeyInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SubjectPublicKeyInfoAlgorithm'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SubjectPublicKeyInfo{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SvceAuthInfo'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'TBSCertList'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'TBSCertList_revokedCertificates_SEQOF'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'TBSCertificate'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'TBSRequest'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'TargetCert'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'TeletexDomainDefinedAttribute'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'TeletexPersonalName'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'UnformattedPostalAddress'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'UserNotice'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'V2Form'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ValidationParms'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Validity'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#cert{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#path_validation_state{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#revoke_state{}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;from &lt;code&gt;asn1&lt;/code&gt; (31):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;#'ComponentType'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Constraint'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'EXTENSIONMARK'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ExtensionAdditionGroup'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Externaltypereference'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Externalvaluereference'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'Object'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ObjectClassFieldType'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'ObjectSet'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SEQUENCE'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SET'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#'SymbolsFromModule'{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#abst{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#classdef{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#cmap{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#gen_state{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#gen{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#module{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#objectclass{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#pobjectdef{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#pobjectsetdef{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#ptypedef{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#pvaluedef{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#pvaluesetdef{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#seqtag{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#simpletableattributes{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#state{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#tag{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#typedef{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#type{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#valuedef{}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's a lot, right? In reality, not all are required for a Poc, only ~10 or ~20 of them will be used. This is where the &lt;code&gt;preprocessing&lt;/code&gt; will help, by creating the right interface for the right object. This post is already way to long... And we will see that on another one.&lt;/p&gt;

&lt;h1&gt;
  
  
  A Quick Note About &lt;code&gt;epp_dodger&lt;/code&gt; Module
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/syntax_tools/epp_dodger.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp_dodger&lt;/code&gt;&lt;/a&gt; is another module available in the Erlang OTP toolsuite to parse valid Erlang source code. So, why not using it instead of &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; and all the complexity relative to its server?&lt;/p&gt;

&lt;p&gt;Firstly because I wanted to dig a bit more in the Erlang parsing process. Most of my researches were focused on the "default execution path", and I totally missed &lt;a href="https://www.erlang.org/doc/apps/syntax_tools/epp_dodger.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp_dodger&lt;/code&gt;&lt;/a&gt;, even if I read the documentation.&lt;/p&gt;

&lt;p&gt;Secondly, the &lt;a href="https://www.erlang.org/doc/apps/syntax_tools/epp_dodger.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp_dodger&lt;/code&gt;&lt;/a&gt; module was not loaded by default with &lt;code&gt;iex&lt;/code&gt; (this module is from the &lt;a href="https://www.erlang.org/docs/18/apps/syntax_tools/index.html" rel="noopener noreferrer"&gt;&lt;code&gt;syntax_tools&lt;/code&gt;&lt;/a&gt; application) and &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; was already available (this module is from the &lt;code&gt;stdlib&lt;/code&gt; application).&lt;/p&gt;

&lt;p&gt;Thirdly, the Erlang toolbox is huge, I don't even think someone know every single tool available there. Every time I start to work on Erlang/OTP source code, I discover new utils.&lt;/p&gt;

&lt;p&gt;Finally, it was not planned to implement my own interface to the &lt;a href="https://www.erlang.org/doc/apps/public_key/public_key.html" rel="noopener noreferrer"&gt;&lt;code&gt;public_key&lt;/code&gt;&lt;/a&gt; module, I also missed the &lt;a href="https://x509.hexdocs.pm" rel="noopener noreferrer"&gt;&lt;code&gt;x509&lt;/code&gt;&lt;/a&gt; from hex. In fact, it is also interesting to see the differences between both implementation and it will also give me a way to improve the test suite.&lt;/p&gt;

&lt;p&gt;Anyway, let fix that with a quick example of &lt;a href="https://www.erlang.org/doc/apps/syntax_tools/epp_dodger.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp_dodger&lt;/code&gt;&lt;/a&gt; usage. If you want to have it in Elixir, you will need to load the &lt;a href="https://www.erlang.org/docs/18/apps/syntax_tools/index.html" rel="noopener noreferrer"&gt;&lt;code&gt;syntax_tools&lt;/code&gt;&lt;/a&gt; application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Application.ensure_all_started&lt;span class="o"&gt;(&lt;/span&gt;:syntax_tools&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;{:ok, [:syntax_tools]}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, the function &lt;a href="https://www.erlang.org/doc/apps/syntax_tools/epp_dodger.html#parse_file/1" rel="noopener noreferrer"&gt;&lt;code&gt;:epp_dodger.parse_file/1&lt;/code&gt;&lt;/a&gt; can be called&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;:code.lib_dir&lt;span class="o"&gt;(&lt;/span&gt;:public_key&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;"include/public_key.hrl"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="gp"&gt;  |&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Path.join&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;  |&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;:epp_dodger.parse_file&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="go"&gt;{:ok,
 [
   {:tree, :attribute, {:attr, 24, [], :none},
    {:attribute, {:atom, 24, :ifndef}, [{:atom, 24, :public_key}]}},
   {:tree, :attribute, {:attr, 25, [], :none},
    {:attribute, {:atom, 25, :define},
     [{:atom, 25, :public_key}, {:atom, 25, true}]}},
   {:tree, :attribute, {:attr, 31, [], :none},
    {:attribute, {:atom, 31, :define},
     [
       {:atom, 31, :"pkcs-1"},
       {:tree, :tuple, {:attr, 31, [], :none},
        [
          {:integer, 31, 1},
          {:integer, 31, 2},
          {:integer, 31, 840},
          {:integer, 31, 113549},
          {:integer, 31, 1},
          {:integer, 31, 1}
        ]}
     ]}},
   {:tree, :attribute, {...}, ...},
&lt;/span&gt;&lt;span class="c"&gt;   ...
&lt;/span&gt;&lt;span class="go"&gt; ]}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now is the better way? I would think using &lt;a href="https://www.erlang.org/doc/apps/syntax_tools/epp_dodger.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp_dodger&lt;/code&gt;&lt;/a&gt; can be a better solution, the &lt;a href="https://www.erlang.org/doc/apps/syntax_tools/epp_dodger.html#parse_file/1" rel="noopener noreferrer"&gt;&lt;code&gt;:epp_dodger.parse_file/1&lt;/code&gt;&lt;/a&gt; function is documented, this is not the case when it comes to the &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt; server solution. I also assume the &lt;code&gt;epp_dodger&lt;/code&gt; module, because documented, will be more stable in the future than &lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt;&lt;/a&gt;. In the end, for this first test release, I think it should do the job.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Even if the interoperability is great between Erlang and Elixir, some part has been ignored or simply discarded because only few people will be interested to use those features. Dealing with Erlang Preprocessor is one of them I guess. In fine, when one knows how Erlang is working, and where to investigate, it becomes an easy problem to fix. Yeah, it can take few hours to understand how the bricks are working, but in the end, it's not lost. Learning how the BEAM is working, and how Erlang is parsed is a fundamental knowledge anyone should have when using this ecosystem.&lt;/p&gt;

&lt;p&gt;Long time ago, I worked on an implementation of &lt;a href="https://github.com/niamtokik/zfs" rel="noopener noreferrer"&gt;ZFS&lt;/a&gt; (ZettaFileSystem) in Erlang, even if it was working for many things, it was slow and limited to a small amount of the features exposed by ZFS. One of my problem was to deal with all the internal C structure defined in ZFS, evolving sometimes between versions... but also doing mistake by implementing them poorly on the Erlang side as binaries or functions. Having a feature like this one here would have been a game changer, converting a data-structure in C into an Erlang or Elixir function would have be just crazy!&lt;/p&gt;

&lt;p&gt;Anyway, as usual, a long list of links if you are interested to know more on this topic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://erlang.github.io/prs/9333/doc/system/code_loading.html" rel="noopener noreferrer"&gt;Erlang Code Loading&lt;/a&gt; from the official Erlang documentation, where you will learn how Erlang code is loaded;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/erts/absform.html" rel="noopener noreferrer"&gt;Erlang Abstract Format&lt;/a&gt; from the official Erlang documentation, where you will learn what the Erlang abstract form is made of;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/erts/erlc_cmd.html" rel="noopener noreferrer"&gt;&lt;code&gt;erlc&lt;/code&gt; command documentation&lt;/a&gt; and &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/erl_compile.erl" rel="noopener noreferrer"&gt;its source code&lt;/a&gt; from the official Erlang documentation where you will learn how to use the &lt;code&gt;erlc&lt;/code&gt; command;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/compiler/cerl.html" rel="noopener noreferrer"&gt;Core Erlang abstract syntax trees&lt;/a&gt; from the official Erlang documentation, where you will learn about the Erlang abstract syntact tree and how to generate ot;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/compiler/compile.html" rel="noopener noreferrer"&gt;The Erlang compiler&lt;/a&gt; and its &lt;a href="https://github.com/erlang/otp/blob/master/lib/compiler/src/compile.erl" rel="noopener noreferrer"&gt;source code&lt;/a&gt; from the official Erlang documentation, where you will learn how the Erlang compiler works;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/stdlib/epp.html" rel="noopener noreferrer"&gt;&lt;code&gt;epp&lt;/code&gt; (erlang preprocessor) documentation&lt;/a&gt; and its &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/epp.erl" rel="noopener noreferrer"&gt;source code&lt;/a&gt; from the official Erlang documentation where you will learn and understand the Erlang preprocessor;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_anno.html" rel="noopener noreferrer"&gt;&lt;code&gt;erl_anno&lt;/code&gt; (compiler annotation) documentation&lt;/a&gt; and its &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/erl_anno.erl" rel="noopener noreferrer"&gt;source code&lt;/a&gt; from the official Erlang documentation, where you will learn about the Erlang compiler annotations;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_scan.html" rel="noopener noreferrer"&gt;&lt;code&gt;erl_scan&lt;/code&gt; (scanner) documentation&lt;/a&gt; and its &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/erl_scan.erl" rel="noopener noreferrer"&gt;source code&lt;/a&gt; from the official Erlang documentation, where the tokens are produced direct after reading the source code;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/stdlib/erl_parse.html" rel="noopener noreferrer"&gt;&lt;code&gt;erl_parse&lt;/code&gt; (parser) documentation&lt;/a&gt; and its &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/erl_parse.yrl" rel="noopener noreferrer"&gt;source code&lt;/a&gt; from the official Erlang documentation, where the AST is generated from the tokens previously created by the scanner;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/stdlib/io.html" rel="noopener noreferrer"&gt;&lt;code&gt;io&lt;/code&gt; module documentation&lt;/a&gt; and its &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/io.erl" rel="noopener noreferrer"&gt;source code&lt;/a&gt; from the official Erlang documentation, where you can find more information about the I/O protocols;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.erlang.org/doc/apps/stdlib/io_lib.html" rel="noopener noreferrer"&gt;&lt;code&gt;io_lib&lt;/code&gt; module documentation&lt;/a&gt; and its &lt;a href="https://github.com/erlang/otp/blob/master/lib/stdlib/src/io_lib.erl" rel="noopener noreferrer"&gt;source code&lt;/a&gt; from the official Erlang documentation;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/zuiderkwast/erlang_abstract_format" rel="noopener noreferrer"&gt;&lt;code&gt;Erlang Abstract Format&lt;/code&gt;&lt;/a&gt; on Github, where you will have another view of the Erlang Abstract Format;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/happi/theBeamBook" rel="noopener noreferrer"&gt;The Beam Book&lt;/a&gt; on Github, where you find a lot of interesting information about the low-level datastructures and how the BEAM is working.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/niamtokik/expki" rel="noopener noreferrer"&gt;&lt;code&gt;expki&lt;/code&gt; source code&lt;/a&gt; on Github, where the Erlang record and macro issues were found, while developing a PKI manager;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/niamtokik/preprocessing" rel="noopener noreferrer"&gt;&lt;code&gt;preprocessing&lt;/code&gt; source code&lt;/a&gt; on Github, created while writing this article, and to use it as library on other projects.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have fun and happy hacking!&lt;/p&gt;




&lt;p&gt;Cover Image by &lt;a href="https://unsplash.com/@igrindphoto?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Evgeniy Smersh&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-shelf-filled-with-lots-of-bottles-of-liquid-aWnA944oXLE?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>erlang</category>
      <category>elixir</category>
      <category>programming</category>
      <category>interface</category>
    </item>
  </channel>
</rss>
