/dev/zero Thoughts, insights and debugging tales of a developer. https://error418.github.io/ Wed, 20 Jan 2021 16:28:50 +0000 Wed, 20 Jan 2021 16:28:50 +0000 Jekyll v3.9.0 NGINX as a reverse proxy for Prosody <p>This article describes a simple setup to run Prosody’s <code class="language-plaintext highlighter-rouge">mod_http_upload</code> behind a NGINX reverse proxy. You will need (some) knowledge about Prosody and NGINX to follow the steps described in this article.</p> <p>First things first: Install Prosody according to the <a href="https://prosody.im/download/start">Prosody documentation</a></p> <h2 id="configuring-prosody">Configuring Prosody</h2> <p>The following settings need to be present in your configuration (replace <code class="language-plaintext highlighter-rouge">example.com</code> with your domain):</p> <div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">--------------------------------------------------------------------</span> <span class="c1">-- This config file is truncated and not complete and just contains</span> <span class="c1">-- settings relevant to this article for better readability</span> <span class="c1">--------------------------------------------------------------------</span> <span class="c1">-- http connection settings</span> <span class="n">https_ports</span> <span class="o">=</span> <span class="p">{</span> <span class="p">}</span> <span class="n">http_interfaces</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">"127.0.0.1"</span> <span class="p">}</span> <span class="n">VirtualHost</span> <span class="s2">"example.com"</span> <span class="n">disco_items</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span> <span class="s2">"jabber.example.com"</span> <span class="p">},</span> <span class="p">}</span> <span class="n">Component</span> <span class="s2">"jabber.example.com"</span> <span class="s2">"http_upload"</span> <span class="n">http_host</span> <span class="o">=</span> <span class="s2">"jabber.example.com"</span> <span class="n">http_external_url</span> <span class="o">=</span> <span class="s2">"https://jabber.example.com/"</span> <span class="n">Component</span> <span class="s2">"muc.example.com"</span> <span class="s2">"muc"</span> <span class="n">modules_enabled</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">"vcard_muc"</span><span class="p">,</span> <span class="s2">"muc_mam"</span><span class="p">,</span> <span class="p">}</span> </code></pre></div></div> <p>Please make yourself familiar with the security and expiry-settings of Prosody, <code class="language-plaintext highlighter-rouge">muc</code> and <code class="language-plaintext highlighter-rouge">mod_http_upload</code>.</p> <h2 id="nginx-site-configuration">NGINX Site configuration</h2> <p>We will use NGINX to serve all files. File uploads (PUT requests in this case) are passed to <code class="language-plaintext highlighter-rouge">mod_http_upload</code> using the <code class="language-plaintext highlighter-rouge">proxy_pass</code> directive.</p> <p>Create a NGINX Site configuration file for Prosody in <code class="language-plaintext highlighter-rouge">/etc/nginx/sites-available/prosody</code> and symlink it from <code class="language-plaintext highlighter-rouge">/etc/nginx/sites-enabled/prosody</code>. Replace <code class="language-plaintext highlighter-rouge">example.com</code> with your domain name.</p> <div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Configuration for mod_http_upload</span> <span class="k">server</span> <span class="p">{</span> <span class="kn">server_tokens</span> <span class="no">off</span><span class="p">;</span> <span class="c1"># hide server tokens</span> <span class="kn">server_name</span> <span class="s">jabber.example.com</span><span class="p">;</span> <span class="c1"># subdomain for http upload</span> <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span> <span class="kn">listen</span> <span class="s">[::]:443</span> <span class="s">ssl</span><span class="p">;</span> <span class="kn">root</span> <span class="n">/var/www/html</span><span class="p">;</span> <span class="c1"># your default serving directory</span> <span class="kn">location</span> <span class="n">/upload</span> <span class="p">{</span> <span class="kn">proxy_buffering</span> <span class="no">off</span><span class="p">;</span> <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span> <span class="c1"># pass PUT requests to mod_http_upload for processing</span> <span class="kn">if</span> <span class="s">(</span><span class="nv">$request_method</span> <span class="p">=</span> <span class="s">PUT)</span> <span class="p">{</span> <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:5280</span><span class="p">;</span> <span class="p">}</span> <span class="kn">alias</span> <span class="n">/var/lib/prosody/http_upload</span><span class="p">;</span> <span class="c1"># storage path of mod_http_upload. NGINX will serve these files to the clients.</span> <span class="p">}</span> <span class="kn">client_max_body_size</span> <span class="mi">10m</span><span class="p">;</span> <span class="c1"># certificate management here</span> <span class="p">}</span> <span class="c1"># Optional http placeholder site for mod_muc subdomain</span> <span class="c1"># You can remove this block if you do not want to deliver a page on the domain.</span> <span class="k">server</span> <span class="p">{</span> <span class="kn">server_tokens</span> <span class="no">off</span><span class="p">;</span> <span class="c1"># hide server tokens</span> <span class="kn">server_name</span> <span class="s">muc.example.com</span><span class="p">;</span> <span class="c1"># subdomain for MUC</span> <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span> <span class="kn">listen</span> <span class="s">[::]:443</span> <span class="s">ssl</span><span class="p">;</span> <span class="kn">root</span> <span class="n">/var/www/html</span><span class="p">;</span> <span class="c1"># your default serving directory</span> <span class="c1"># certificate management here</span> <span class="p">}</span> </code></pre></div></div> <h2 id="update-permissions">Update permissions</h2> <p>At this point NGINX will not be able to read files in the Prosody data directory due to missing permissions. We need to perform following steps to allow read access to the uploaded files written by <code class="language-plaintext highlighter-rouge">mod_http_upload</code> to the file upload directory:</p> <ol> <li>Create Group for XMPP Web Data <code class="language-plaintext highlighter-rouge">www-data-xmpp</code></li> <li>Add <code class="language-plaintext highlighter-rouge">prosody</code> to group <code class="language-plaintext highlighter-rouge">www-data-xmpp</code></li> <li>Add NGINX User <code class="language-plaintext highlighter-rouge">www-data</code> to group <code class="language-plaintext highlighter-rouge">www-data-xmpp</code></li> <li>Modify directory owners</li> </ol> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># create a dedicated group</span> groupadd www-data-xmpp <span class="c"># add prosody to group</span> usermod <span class="nt">-a</span> <span class="nt">-G</span> www-data-xmpp prosody <span class="c"># add www-data to grouo</span> usermod <span class="nt">-a</span> <span class="nt">-G</span> www-data-xmpp www-data <span class="c"># change owner group of mod_http_upload directory</span> <span class="nb">chgrp</span> <span class="nt">-R</span> www-data-xmpp /var/lib/prosody/http_upload/ <span class="c"># change owner group of prosody file system storage</span> <span class="nb">chgrp </span>www-data-xmpp /var/lib/prosody <span class="c"># set setgid flag for mod_http_upload directory</span> <span class="nb">chmod </span>g+s /var/lib/prosody/http_upload/ </code></pre></div></div> <h2 id="wrapping-it-up">Wrapping it up</h2> <ol> <li>Restart your prosody server <code class="language-plaintext highlighter-rouge">service prosody restart</code></li> <li>Reload your NGINX server <code class="language-plaintext highlighter-rouge">nginx -s reload</code></li> <li>Have fun</li> </ol> Wed, 20 Jan 2021 09:04:00 +0000 https://error418.github.io/server/2021/01/20/xmpp-nginx.html https://error418.github.io/server/2021/01/20/xmpp-nginx.html server Automated OWASP Zap Security Scans <p><a href="https://owasp.org/www-project-zap/">OWASP Zap</a> (aka Zed Attack Proxy) is a security scanner, which scans your web application for security issues. I wrote a <a href="https://swingletree-oss.github.io/swingletree/blog/2020/06/24/zap/">blog post</a> on this topic for the Swingletree page.</p> Sat, 27 Jun 2020 09:04:00 +0000 https://error418.github.io/code/cicd/2020/06/27/zap-ci.html https://error418.github.io/code/cicd/2020/06/27/zap-ci.html code cicd Using SonarQube branch analysis with GitHub PRs <p>On my job I have a lot to do with <a href="https://www.sonarqube.org/">SonarQube</a>. Like many other companies we use this tool to perform static code analysis for our projects.</p> <p>I was excited when Sonarqube announced the <a href="https://docs.sonarqube.org/display/SONAR/Branch+Analysis">Branch Analysis Feature</a> for its <a href="https://www.sonarsource.com/plans-and-pricing/developer/">SonarQube Developer Edition</a>, which enabled us to increase the transparency of quality issues for our development branches in relation to our <code class="language-plaintext highlighter-rouge">master</code>-branch.</p> <p>We were using (and still use) the <a href="https://docs.sonarqube.org/display/PLUG/GitHub+Plugin">Sonar GitHub Plugin</a> to help developers when approving pull requests. This solution is based on so called Sonar <code class="language-plaintext highlighter-rouge">preview</code>-scans, which can cover only a subset of the full Sonar scan and can therefore not compute a useful <a href="https://docs.sonarqube.org/display/SONAR/Fixing+the+Water+Leak">leak period</a>.</p> <p>The idea for <a href="https://github.com/swingletree-oss/swingletree">Swingletree</a> was born. A pretty non-invasive integration using <a href="https://docs.sonarqube.org/display/SONAR/Webhooks">Sonar webhooks</a> and <a href="https://developer.github.com/apps/differences-between-apps/">GitHub Apps</a>. More details about the internals of Swingletree can be found in the project’s readme.</p> <p>Keep in mind you will need a license for the <a href="https://www.sonarsource.com/plans-and-pricing/developer/">SonarQube Developer Edition</a> (or a higher license edition) to be able to use the <a href="https://docs.sonarqube.org/display/SONAR/Branch+Analysis">Branch Analysis Feature</a>.</p> Sat, 30 Jun 2018 21:04:00 +0000 https://error418.github.io/code/2018/06/30/swingletree.html https://error418.github.io/code/2018/06/30/swingletree.html code Inversion of control in Typescript <p>When writing <a href="https://github.com/error418/swingletree">Swingletree</a> I came across <a href="http://inversify.io/">InversifyJS</a>, which enables us to use Dependency Injection in our TypeScript applications. The refactor-hammer was more than ready to be swung, as soon as I discovered that constructor injection is supported and almost everything is managed via annotations.</p> <p>So.. how does it look like? Let’s take a look at an injectable class supporting constructor injection:</p> <div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// omitted other imports for clarity</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">injectable</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">inversify</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">inject</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">inversify</span><span class="dl">"</span><span class="p">;</span> <span class="p">@</span><span class="nd">injectable</span><span class="p">()</span> <span class="kd">class</span> <span class="nx">GithubWebhook</span> <span class="p">{</span> <span class="kd">constructor</span><span class="p">(</span> <span class="p">@</span><span class="nd">inject</span><span class="p">(</span><span class="nx">EventBus</span><span class="p">)</span> <span class="nx">eventBus</span><span class="p">:</span> <span class="nx">EventBus</span><span class="p">,</span> <span class="p">@</span><span class="nd">inject</span><span class="p">(</span><span class="nx">ConfigurationService</span><span class="p">)</span> <span class="nx">configService</span><span class="p">:</span> <span class="nx">ConfigurationService</span> <span class="p">)</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nx">eventBus</span> <span class="o">=</span> <span class="nx">eventBus</span><span class="p">;</span> <span class="k">this</span><span class="p">.</span><span class="nx">configService</span> <span class="o">=</span> <span class="nx">configService</span><span class="p">;</span> <span class="p">}</span> <span class="c1">// ...</span> <span class="p">}</span> </code></pre></div></div> <p>Everything needs to be strapped together using an inversify container, which takes care of the dependency injections and class instantiation:</p> <div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="dl">"</span><span class="s2">reflect-metadata</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">Container</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">inversify</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">ConfigurationService</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">../configuration</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">EventBus</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">../event-bus</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">GithubWebhook</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">../github/github-webhook</span><span class="dl">"</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">container</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Container</span><span class="p">();</span> <span class="nx">container</span><span class="p">.</span><span class="nx">bind</span><span class="o">&lt;</span><span class="nx">EventBus</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">EventBus</span><span class="p">).</span><span class="nx">toSelf</span><span class="p">().</span><span class="nx">inSingletonScope</span><span class="p">();</span> <span class="nx">container</span><span class="p">.</span><span class="nx">bind</span><span class="o">&lt;</span><span class="nx">ConfigurationService</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">ConfigurationService</span><span class="p">).</span><span class="nx">toSelf</span><span class="p">().</span><span class="nx">inSingletonScope</span><span class="p">();</span> <span class="nx">container</span><span class="p">.</span><span class="nx">bind</span><span class="o">&lt;</span><span class="nx">GithubWebhook</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">GithubWebhook</span><span class="p">).</span><span class="nx">toSelf</span><span class="p">().</span><span class="nx">inSingletonScope</span><span class="p">();</span> <span class="k">export</span> <span class="k">default</span> <span class="nx">container</span><span class="p">;</span> </code></pre></div></div> <p>Keep in mind that classes only get instantiated when they are a dependency of an other class. You can manually require them by using this:</p> <div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">container</span><span class="p">.</span><span class="kd">get</span><span class="o">&lt;</span><span class="nx">CommitStatusSender</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">CommitStatusSender</span><span class="p">);</span> </code></pre></div></div> <p>Inversify has some very good examples, if you want to get into the details.</p> Mon, 23 Apr 2018 21:04:00 +0000 https://error418.github.io/typescript/code/2018/04/23/inversion-of-control-in-typescript.html https://error418.github.io/typescript/code/2018/04/23/inversion-of-control-in-typescript.html typescript code Dusty machines and lubuntu <p>Spring is coming. Therefore my better three-quarter declared global spring cleaning, which led me to the discovery of an old Asus eee 1000H PC. After my duty was done I couldn’t resist to boot it up to lay my eyes upon an antique Windows XP.</p> <p>The urge to change this was instantly rising and I looked up some lightweight Linux distributions, due to the very limited hardware specifications of this machine (1.6 GHz, 1GB RAM). <a href="https://lubuntu.net/">Lubuntu</a> was one of the candidates, so I downloaded the 32 bit image and prepared an USB stick. This should be an easy job.</p> <p>So I booted from the USB drive and wanted to install Lubuntu directly without launching the live demo. After I configured the partitions (with encryption) the installer threw an error message and cancelled the installation.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Unsafe swap space detected </code></pre></div></div> <p>A quick Google search revealed the solution to this error. Just boot the live preview of Lubuntu and run the following commands before invoking the installer</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># fixes the 'Unsafe swap space detected' error</span> <span class="nb">sudo </span>swapoff <span class="nt">--all</span> <span class="c"># fixes the 'Autopartitioning failed' error (if you use lvm)</span> <span class="nb">sudo </span>apt-get <span class="nb">install </span>lvm2 </code></pre></div></div> <p>You can read about the solutions <a href="https://askubuntu.com/questions/393418/unsafe-swap-space-detected">here</a> and <a href="https://askubuntu.com/questions/845401/installing-lubuntu-16-10-with-encrytion">here</a></p> <p>Make sure you are installing the updates during the setup. Without the updates I had issues with the graphic chip driver of the machine resulting in a partial black screen.</p> <p>After a few hours the system was running; the only thing I need is an use-case now.</p> Wed, 11 Apr 2018 21:04:00 +0000 https://error418.github.io/misc/2018/04/11/lubuntu.html https://error418.github.io/misc/2018/04/11/lubuntu.html misc More privacy in your network with pihole <p><em>“Just set up a <a href="https://pi-hole.net/">PiHole</a> and look, what is going on”</em>. Since my home is not massively IOT’ized I didn’t suspect much traffic going to analytic servers; but a relatively free weekend offered the opportunity for a small side-project.</p> <p>The setup is very simple. I used a spare Raspberry PI 1 with a 2GB SD card and flashed the latest <a href="https://www.raspberrypi.org/downloads/raspbian/">Raspbian Lite</a> image.</p> <p><strong>Tip:</strong> In case your Raspberry is running headless: Put an empty file named <code class="language-plaintext highlighter-rouge">ssh</code> on the SD card after writing the image. The system will then be configured to accept SSH connections.</p> <p>Just update everything and you will be ready to install Pihole</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt-get update <span class="nb">sudo </span>apt-get upgrade </code></pre></div></div> <p>pihole offers a simple installation method:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -sSL https://install.pi-hole.net | bash </code></pre></div></div> <p>Simplicity is great, but be careful, if you install things this way. It is always a good idea to check what the script does before executing it.</p> <p>You will now be guided through a setup wizard and at the end of it you will have a fully configured pihole. Be sure to note the generated admin password and set your Raspberry up to use a static ip address.</p> <p>Be sure you configure the pihole as a DHCP server and deactivate all other DHCP servers in your network. Pihole will be able to filter the requests as soon as the cached DNS addresses and DHCP leases are expiring.</p> <p>Following things I noticed so far:</p> <ul> <li>no ads in apps (on my mobile)</li> <li>Redirection Ad target sites are blocked</li> <li>Chromecast is not able to phone home</li> <li>Tracking sites are blocked</li> </ul> <p>What gets blocked depends on your selection of block lists.</p> <p>Have fun! :)</p> Sun, 28 Jan 2018 21:04:00 +0000 https://error418.github.io/raspberry/2018/01/28/pihole.html https://error418.github.io/raspberry/2018/01/28/pihole.html raspberry Alpine and Oracle Java <p>So, finally we got an Alpine Repository running. <em>“Let’s build a Java image on top of that, like, right now!”</em>, I greenly said to my colleague, not knowing, that it will not be that easy.</p> <p>Let’s start with some basic details about <a href="https://alpinelinux.org/">Alpine Linux</a>. It is a Linux distribution built on top of <a href="https://www.musl-libc.org/">musl</a> and <a href="http://www.busybox.net/">BusyBox</a>. Alpine enables us to build very small images, since it is stripped of almost everything.</p> <blockquote> <p>Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox.</p> </blockquote> <p>Wait a moment.. <code class="language-plaintext highlighter-rouge">musl</code> instead of <code class="language-plaintext highlighter-rouge">glibc</code>? A quick Google search confirmed the bad feeling I’ve had after receiving the first weird error messages from the freshly built container. Oracle JRE, as well as Oracle JDK are not compatible with <code class="language-plaintext highlighter-rouge">musl</code>. Unfortunately, <code class="language-plaintext highlighter-rouge">glibc</code> is a hard dependency of these packages. <a href="http://openjdk.java.net/">OpenJDK</a>, on the other side, runs (thanks to <a href="http://openjdk.java.net/projects/portola/">Project Portola</a>) on <code class="language-plaintext highlighter-rouge">musl</code>-based environments.</p> <p>You will find some <a href="https://developer.atlassian.com/blog/2015/08/minimal-java-docker-containers/">instructions</a> on how to run Oracle Java on Alpine, but I sense a “workaroundy” aftertaste in such solutions.</p> Sat, 23 Dec 2017 21:04:00 +0000 https://error418.github.io/docker/2017/12/23/alpine-java.html https://error418.github.io/docker/2017/12/23/alpine-java.html docker