<?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>Forem: Kamil</title>
    <description>The latest articles on Forem by Kamil (@elwin013).</description>
    <link>https://forem.com/elwin013</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F515142%2Fbf1cc322-49d3-48c9-b00a-5d1e41dc6a98.jpg</url>
      <title>Forem: Kamil</title>
      <link>https://forem.com/elwin013</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/elwin013"/>
    <language>en</language>
    <item>
      <title>When JavaScript regex can surprise you - a silly bug story</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Wed, 15 Feb 2023 09:25:00 +0000</pubDate>
      <link>https://forem.com/elwin013/when-javascript-regex-can-surprise-you-a-silly-bug-story-101f</link>
      <guid>https://forem.com/elwin013/when-javascript-regex-can-surprise-you-a-silly-bug-story-101f</guid>
      <description>&lt;p&gt;Recently one of my customers let me know that they have probably a bug in their app. They want me to look into it - so I jump into “Sherlock, the bug hunter” mode and start snooping!&lt;/p&gt;

&lt;p&gt;The misbehaving feature was some kind of search. It takes an input, a Javascript regular expression and as an output returns &lt;em&gt;true&lt;/em&gt; if regex was satisfied - and &lt;em&gt;false&lt;/em&gt; otherwise.&lt;/p&gt;

&lt;p&gt;The feature was pretty simple on the code side - the search function looked similar to the one below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&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="kc"&gt;true&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="kc"&gt;false&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;So we can see that the heart of it was a simple &lt;code&gt;regex.test&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;The bug report stated that misbehaving example was regex &lt;code&gt;/pony/g&lt;/code&gt; and text &lt;code&gt;this is a pony and not a horse&lt;/code&gt; - we have 100% sure that &lt;code&gt;pony&lt;/code&gt; is in this sentence. To check if everything was working correctly I opened console in Chrome Developer Tools, loaded the search function and check its result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Below returns true&lt;/span&gt;
&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/pony/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;this is a pony and not a horse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="c1"&gt;// this also returns true!&lt;/span&gt;
&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/pony/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;this is a pony and not a horse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="c1"&gt;// ... five runs later&lt;/span&gt;
&lt;span class="c1"&gt;// eh? still returns true!&lt;/span&gt;
&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/pony/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;this is a pony and not a horse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is going on?! Every run of this function returns the correct and expected value.&lt;/p&gt;

&lt;p&gt;But wait… the &lt;code&gt;regex&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt; was passed using variables from &lt;em&gt;somewhere else&lt;/em&gt;. Let’s put them in the variables and try to run the function multiple times again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/pony/g&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;this is a pony and not a horse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pony&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// returns true as expected&lt;/span&gt;
&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pony&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// returns false :O&lt;/span&gt;
&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pony&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// returns true - what a trickery!&lt;/span&gt;
&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pony&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// returns false - wut?!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we have a problem - despite the fact we should get &lt;code&gt;true&lt;/code&gt; every time we sometimes get &lt;code&gt;false&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;The answer to this weird behaviour is in the… documentation. Quick look at the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test" rel="noopener noreferrer"&gt;RegExp.prototype.test() on mdn web docs&lt;/a&gt;and we have found the culprit:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;JavaScript RegExp objects are stateful when they have the global or sticky flags set (e.g., &lt;code&gt;/foo/g&lt;/code&gt; or &lt;code&gt;/foo/y&lt;/code&gt;). They store a &lt;code&gt;lastIndex&lt;/code&gt; from the previous match&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the &lt;code&gt;latIndex&lt;/code&gt; property is described as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;lastIndex&lt;/code&gt; data property of a RegExp instance specifies the index at which to start the next match.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We have the global option in our regex - and that was the reason that it behaves in a not expected manner. Similar results will be if our test text were &lt;em&gt;this is a pony and second pony&lt;/em&gt; - it will give us &lt;code&gt;true&lt;/code&gt; for the first and the second search (as we have two ponies!) and &lt;code&gt;false&lt;/code&gt; for the third one.&lt;/p&gt;

&lt;p&gt;The solution for this issue was simply to reset the &lt;code&gt;lastIndex&lt;/code&gt; property of regex if something was found&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// reset lastIndex property to make sure &lt;/span&gt;
        &lt;span class="c1"&gt;// that next test will start from beginning&lt;/span&gt;
        &lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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="kc"&gt;false&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;That’s all folks! One line, resetting one property, is all that was needed to fix the issue.&lt;/p&gt;

&lt;p&gt;What is the takeaway from this issue? When in doubt and especially when working with regexes - read documentation. It can save you a lot of time. :-)&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>regex</category>
    </item>
    <item>
      <title>Accessing Kubernetes cluster using SSH tunnel</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Wed, 14 Dec 2022 10:20:00 +0000</pubDate>
      <link>https://forem.com/elwin013/accessing-kubernetes-cluster-using-ssh-tunnel-4d3c</link>
      <guid>https://forem.com/elwin013/accessing-kubernetes-cluster-using-ssh-tunnel-4d3c</guid>
      <description>&lt;p&gt;Whether we want it or not adoption of Kubernetes is growing. It can be set up as a managed solution (all major cloud providers provide such products) or we can set it up by yourselves. No matter if we select the former or the latter - we would like to make it as secure as it can be. One of the solutions to make the Kubernetes cluster more secure is to hide a control plane (to be more specific - &lt;code&gt;kube-apiserver&lt;/code&gt;) behind a firewall. That means cluster management is not available from the Internet.&lt;/p&gt;

&lt;p&gt;That creates problems with accessing it. We can SSH to a server that is in the same network and run &lt;code&gt;kubectl&lt;/code&gt; commands from there, but this is a nuisance which we want to avoid. Fortunately, SSH tunnels came with help in that case (&lt;a href="https://banach.net.pl/posts/2022/how-to-expose-local-service-using-nginx-and-ssh/" rel="noopener noreferrer"&gt;not for the first time!&lt;/a&gt;) - we can create a tunnel to the server in the same network and pass all traffic to the cluster through it!&lt;/p&gt;

&lt;p&gt;To do it we can run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh our-gate.example.com &lt;span class="nt"&gt;-L&lt;/span&gt; 16443:10.0.10.2:443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the command, we’re assuming that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;our server is available with the domain &lt;code&gt;our-gate.example.com&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;the cluster is in the same local network as the server and its control plane is available at &lt;code&gt;10.0.10.2&lt;/code&gt; IP address,&lt;/li&gt;
&lt;li&gt;we want the tunnel to be available at port &lt;code&gt;16443&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we need to replace IP address / hostname of cluster in &lt;code&gt;~/.kube/config&lt;/code&gt; to point to local tunnel. To do this we will open aforementioned file and replace put &lt;code&gt;https://127.0.0.1:16443&lt;/code&gt; in &lt;code&gt;clusters.cluster.server&lt;/code&gt; property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;clusters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;certificate-authority-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;long string with CA data&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;# line below was something like https://our-public-address-of-cluster.example.com or just local IP like https://10.0.10.2 &lt;/span&gt;
&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://127.0.0.1:16443&lt;/span&gt; 
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-k8s-cluster&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that we can try to run a command like &lt;code&gt;kubectl cluster-info&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl cluster-info
To further debug and diagnose cluster problems, use &lt;span class="s1"&gt;'kubectl cluster-info dump'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Unable to connect to the server: x509: certificate is valid &lt;span class="k"&gt;for &lt;/span&gt;our-public-address-of-cluster.example.com, 10.0.10.2, not 127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It fails, but why? It is because we want to connect to &lt;code&gt;127.0.0.1&lt;/code&gt; but API (securely server over https) is responding with a certificate issued for different domain / IP address. Fortunately solution for that is simple which is to put &lt;code&gt;clusters.cluster.tls-server-name&lt;/code&gt; property with one of the valid values from the error message - in our case it can be &lt;code&gt;10.0.10.2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our final configuration will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;clusters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;certificate-authority-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;long string with CA data&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://127.0.0.1:16443&lt;/span&gt;
&lt;span class="na"&gt;tls-server-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.0.10.2&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-k8s-cluster&lt;/span&gt;
&lt;span class="na"&gt;contexts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-k8s-cluster&lt;/span&gt;
&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-k8s-cluster&lt;/span&gt;
&lt;span class="na"&gt;current-context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-k8s-cluster&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Config&lt;/span&gt;
&lt;span class="na"&gt;preferences&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;
&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;some-fancy-token&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now running &lt;code&gt;cluster-info&lt;/code&gt; command will gives us what we expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;~ &amp;gt; kubectl cluster-info&lt;/span&gt;
&lt;span class="s"&gt;Kubernetes control plane is running at https://10.0.10.2:16443&lt;/span&gt;
&lt;span class="s"&gt;GLBCDefaultBackend is running at https://10.0.10.2:16443/api/v1/namespaces/kube-system/services/default-http-backend:http/proxy&lt;/span&gt;
&lt;span class="s"&gt;KubeDNS is running at https://10.0.10.2:16443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy&lt;/span&gt;
&lt;span class="s"&gt;Metrics-server is running at https://10.0.10.2:16443/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yay! Now we can use &lt;code&gt;kubectl&lt;/code&gt;, &lt;code&gt;helm&lt;/code&gt; and other software that uses configuration from &lt;code&gt;~/.kube/config&lt;/code&gt; from our local machine!&lt;/p&gt;

&lt;p&gt;And a small “bonus” (and also describing it to the future myself) - accessing Kubernetes in GCP (GKE) through Identity Aware Proxy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud compute ssh &lt;span class="s2"&gt;"some-instance"&lt;/span&gt; &lt;span class="nt"&gt;--zone&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ZONE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PROJECT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--tunnel-through-iap&lt;/span&gt; &lt;span class="nt"&gt;--ssh-flag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-L 16443:10.0.10.2:443"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it - the SSH tunnel again saves the day! :-)&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ssh</category>
      <category>gcp</category>
      <category>devops</category>
    </item>
    <item>
      <title>Project YALA - MongoDB Atlas Hackathon 2022 on DEV submission</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Mon, 05 Dec 2022 07:32:49 +0000</pubDate>
      <link>https://forem.com/elwin013/project-yala-mongodb-atlas-hackathon-2022-on-dev-submission-3ibl</link>
      <guid>https://forem.com/elwin013/project-yala-mongodb-atlas-hackathon-2022-on-dev-submission-3ibl</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;I built Project YALA (or simply YALA) which is "Yet Another Link-shortener App". &lt;/p&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Think Outside the JS Box&lt;/strong&gt; - as it is not-the-JS-stack but still nothing wacky to put in other category ;-)&lt;/p&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://project-yala.fly.dev/" rel="noopener noreferrer"&gt;https://project-yala.fly.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;App is run in preview mode - no add/delete options provided.&lt;/p&gt;

&lt;p&gt;Example links with data (some short link which redirects to dev.to):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;details page: &lt;a href="https://project-yala.fly.dev/link/638a74cb82478a464c478282/3d9ae405-ba98-4930-9979-4ec11c7c2454" rel="noopener noreferrer"&gt;https://project-yala.fly.dev/link/638a74cb82478a464c478282/3d9ae405-ba98-4930-9979-4ec11c7c2454&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;details (analitycs) page: &lt;a href="https://project-yala.fly.dev/link/638a74cb82478a464c478282/3d9ae405-ba98-4930-9979-4ec11c7c2454/visits" rel="noopener noreferrer"&gt;https://project-yala.fly.dev/link/638a74cb82478a464c478282/3d9ae405-ba98-4930-9979-4ec11c7c2454/visits&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;link to click with preview - to show what URL is going to be opened: &lt;a href="https://project-yala.fly.dev/j/3fe3fd2/preview" rel="noopener noreferrer"&gt;https://project-yala.fly.dev/j/3fe3fd2/preview&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2F6quxsgzlknbu65wwj9cv.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.amazonaws.com%2Fuploads%2Farticles%2F6quxsgzlknbu65wwj9cv.png" alt="Index page" width="800" height="565"&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.amazonaws.com%2Fuploads%2Farticles%2Ffinzjxf9bmehj0rbs123.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.amazonaws.com%2Fuploads%2Farticles%2Ffinzjxf9bmehj0rbs123.png" alt="Link info page" width="800" height="565"&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.amazonaws.com%2Fuploads%2Farticles%2Fnvdy84a8druems19n8pj.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.amazonaws.com%2Fuploads%2Farticles%2Fnvdy84a8druems19n8pj.png" alt="Link visits page" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;YALA is a simple link shortener that works without logging in - instead it creates "secret key" which allows to view details of created short link and it's statistics.&lt;/p&gt;

&lt;p&gt;Generally it is simple app to show that we do not need fancy frameworks to make nice looking, fully working application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/elwin013/project-yala" rel="noopener noreferrer"&gt;https://github.com/elwin013/project-yala&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;MIT, &lt;a href="https://github.com/elwin013/project-yala/blob/master/LICENSE.md" rel="noopener noreferrer"&gt;https://github.com/elwin013/project-yala/blob/master/LICENSE.md&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I always wanted to create simple link shortener, just for fun. :-) Additionally this was good moment to look into new &lt;a href="https://www.mongodb.com/docs/manual/core/timeseries-collections/" rel="noopener noreferrer"&gt;Timeseries&lt;/a&gt; features from MongoDB.&lt;/p&gt;

&lt;p&gt;Instead of using commonly used frameworks (like Spring Framework) I preffered to use something that is small and doesn't have "magic" in it. So I've chosen &lt;a href="https://javalin.io" rel="noopener noreferrer"&gt;Javalin&lt;/a&gt; as a simple web framework, added MongoDB client libraries nad &lt;a href="https://jte.gg" rel="noopener noreferrer"&gt;jte&lt;/a&gt;  as template engine. To show that simple and clean looking apps doesn't need any big JS libraries I've selected &lt;a href="https://jenil.github.io/chota" rel="noopener noreferrer"&gt;chota&lt;/a&gt; - one of micro CSS frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it
&lt;/h3&gt;

&lt;p&gt;On the app side I've used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.toJavalin"&gt;https://javalin.io/&lt;/a&gt; - simple web framework, &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.tojte"&gt;https://jte.gg/&lt;/a&gt; - template library,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.tochota"&gt;https://jenil.github.io/chota&lt;/a&gt; - micro CSS framework,&lt;/li&gt;
&lt;li&gt;MongoDB for database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the MongoDB side I've used just two collections - one with data about links and the second one with visits. For the latter I used  timeseries collection to aggregate data into some chunks (in case of example - group visits per hour).&lt;/p&gt;

&lt;p&gt;All MongoDB related stuff was done on the code side (except creating cluster, database and user to access). It is pretty great that as long as you have access to database you can work with it freely - e.g. collection is created as soon as first document is saved!&lt;/p&gt;

&lt;p&gt;For deployment I've used &lt;a href="https://fly.io" rel="noopener noreferrer"&gt;https://fly.io&lt;/a&gt; - mostly because I wanted to check out some Big-Three (AWS,GCP,Azure) alternative for hosting apps!&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;p&gt;Nothing I can think of! ;-)&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>resources</category>
    </item>
    <item>
      <title>MongoDB sequences (auto-increment) - The Java Way</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Fri, 02 Dec 2022 21:30:00 +0000</pubDate>
      <link>https://forem.com/elwin013/mongodb-sequences-auto-increment-the-java-way-4081</link>
      <guid>https://forem.com/elwin013/mongodb-sequences-auto-increment-the-java-way-4081</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;tl;dr: Full code available at my Github - &lt;a href="https://github.com/elwin013/mongodb-sequences" rel="noopener noreferrer"&gt;elwin013/mongodb-sequences&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of the missing elements while using MongoDB is lack of the auto-increment fields, commonly called sequences (e.g. in PostgreSQL). For MongoDB Atlas (managed MongoDB solution) there is a posibility to mimic this feature using database triggers (as mentioned on &lt;a href="https://www.mongodb.com/basics/mongodb-auto-increment" rel="noopener noreferrer"&gt;MongoDB page&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;But what about self-hosted database? Unfortunately, there are no triggers there (or I’m not aware of them :-)), so we need to improvise and make that happen with custom code.&lt;/p&gt;

&lt;p&gt;To make this work we will create a collection called &lt;code&gt;sequence&lt;/code&gt; which will have documents with two fields describing the sequence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_id&lt;/code&gt; with a name,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;value&lt;/code&gt; with a value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code will be relying on MongoDB’s &lt;a href="https://www.mongodb.com/docs/manual/core/write-operations-atomicity/" rel="noopener noreferrer"&gt;document write atomicity&lt;/a&gt;. Linked documentation says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A findAndModify operation on a document is atomic&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the case of the Java Mongo driver, our operation is &lt;code&gt;findOneAndUpdate&lt;/code&gt;. We will be searching for exactly one document with the selected id (name of the sequence), increment value and return that document after the update. Let’s do it!&lt;/p&gt;

&lt;p&gt;Below is &lt;code&gt;Sequence&lt;/code&gt; record (it can be replaced with the classic POJO if we need to run code on e.g. Java 11 or 8).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.bson.codecs.pojo.annotations.BsonId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Sequence&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@BsonId&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Worth mentioning is the &lt;code&gt;@BsonId&lt;/code&gt; annotation - this annotation will make field &lt;code&gt;name&lt;/code&gt; an id field (&lt;code&gt;_id&lt;/code&gt;) for document in collection. So our document will have two fields - &lt;code&gt;_id&lt;/code&gt; (which will contain sequence name and will be mapped to &lt;code&gt;name&lt;/code&gt; field in code) and &lt;code&gt;value&lt;/code&gt; with value.&lt;/p&gt;

&lt;p&gt;Now we can write code to update (increment) and return sequence value. We also want to be sure that the document always is created (update and insert, so upsert) and will be returned after creation. To achieve that we will customize options of &lt;code&gt;findOneAndUpdate&lt;/code&gt; request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FindOneAndUpdateOptions&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;upsert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;returnDocument&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReturnDocument&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AFTER&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the cherry on the top - &lt;code&gt;findOneAndUpdate&lt;/code&gt; operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCollection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sequence"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Sequence&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findOneAndUpdate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="nc"&gt;Filters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"important_sequence"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                    &lt;span class="nc"&gt;Updates&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inc&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="o"&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;options&lt;/span&gt;
            &lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above will search for a document with id &lt;code&gt;important_sequence&lt;/code&gt;, increment the document’s &lt;code&gt;value&lt;/code&gt; field by one and return the document - exactly what we need. And if the document doesn’t exist - it will be created and &lt;code&gt;seq.value()&lt;/code&gt; will give us &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can always change the value of sequence using similar code (&lt;code&gt;Updates.set&lt;/code&gt; instead of &lt;code&gt;Updates.inc&lt;/code&gt;) - but we need to set it to &lt;code&gt;0&lt;/code&gt; if the next value needs to be &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And that is all - we have sequences in MongoDB without any additional tools! Feels great! :-)&lt;/p&gt;

&lt;p&gt;Full code available at my Github - &lt;a href="https://github.com/elwin013/mongodb-sequences" rel="noopener noreferrer"&gt;elwin013/mongodb-sequences&lt;/a&gt; - including record class, DAO and some fancy tests using &lt;a href="https://www.testcontainers.org/" rel="noopener noreferrer"&gt;TestContainers&lt;/a&gt; to test code using MongoDB on Docker.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>java</category>
      <category>database</category>
    </item>
    <item>
      <title>Reading JWT token claims without a library</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Fri, 14 Oct 2022 13:49:00 +0000</pubDate>
      <link>https://forem.com/elwin013/reading-jwt-token-claims-without-a-library-a4l</link>
      <guid>https://forem.com/elwin013/reading-jwt-token-claims-without-a-library-a4l</guid>
      <description>&lt;p&gt;Almost everybody who works on web apps knows what JWT (JSON Web Token) is. They become pretty popular and are now widely used.&lt;/p&gt;

&lt;p&gt;Without going into details (which can be read e.g. at &lt;a href="https://jwt.io/introduction" rel="noopener noreferrer"&gt;jwt.io/introduction&lt;/a&gt;) JWT is built from three parts divided by dots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;header.payload.signature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The middle part, payload, is interesting for us. It contains claims, which are statements about an entity (e.g. the user) and some additional data.&lt;/p&gt;

&lt;p&gt;For purpose of this post we will use an example token from &lt;a href="https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" rel="noopener noreferrer"&gt;jwt.io&lt;/a&gt; (click on the link to open it in the debugger!) which looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The payload in the token is just a &lt;a href="https://en.wikipedia.org/wiki/Base64" rel="noopener noreferrer"&gt;base64&lt;/a&gt; encoded JSON object. That means we can decode it and load this JSON string into the dictionary to have easy access to properties.&lt;/p&gt;

&lt;p&gt;There is only one tricky part here - base64 padding! The payload in the JWT is alfa-numeric only, there is no &lt;code&gt;=&lt;/code&gt; character. To be sure that it will be decoded properly we need to add max padding (&lt;code&gt;==&lt;/code&gt;) to the payload string - it will be ignored if not needed. But if we will not have it there (but it is expected to be) - decoder will throw an error.&lt;/p&gt;

&lt;p&gt;To sum up all above stuff in simple lines of code in Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="c1"&gt;# Assuming the token is in the token variable 
&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; \
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; \
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="c1"&gt;# Split by dot and get middle, payload, part;
&lt;/span&gt;&lt;span class="n"&gt;token_payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&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="c1"&gt;# Payload is base64 encoded, let's decode it to plain string
# To make sure decoding will always work - we're adding max padding ("==")
# to payload - it will be ignored if not needed.
&lt;/span&gt;&lt;span class="n"&gt;token_payload_decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token_payload&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Payload is JSON - we can load it to dict for easy access
&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token_payload_decoded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# And now we can access its' elements - e.g. name
&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;# Let's print it - it should show "John Doe"
&lt;/span&gt;&lt;span class="nf"&gt;print&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run it in the browser on Replit (&lt;a href="https://replit.com/@elwin013/Reading-JWT-token-without-a-library#main.py" rel="noopener noreferrer"&gt;Reading JWT token without library on Replit&lt;/a&gt;) or locally with Python 3.&lt;/p&gt;

&lt;p&gt;And that’s all. It is pretty simple, isn’t it?&lt;/p&gt;

&lt;p&gt;And it feels great to be able to do it without any additional tools! :-)&lt;/p&gt;

</description>
      <category>python</category>
      <category>jwt</category>
      <category>web</category>
    </item>
    <item>
      <title>How to customize Jetty in Spring - Custom Error Handler</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Tue, 21 Jun 2022 13:41:00 +0000</pubDate>
      <link>https://forem.com/elwin013/how-to-customize-jetty-in-spring-custom-error-handler-1fk</link>
      <guid>https://forem.com/elwin013/how-to-customize-jetty-in-spring-custom-error-handler-1fk</guid>
      <description>&lt;p&gt;Last week we found out that in some cases our application is showing redundant data on error - for example stacktrace. It happens when there was an error which was handled by the application container which was Jetty. For example, sending a header like &lt;code&gt;X-FORWARDED-PORT: some-not-numeric-value&lt;/code&gt; causes&lt;code&gt;NumberFormatException&lt;/code&gt; and shows a full stacktrace.&lt;/p&gt;

&lt;p&gt;We’ve looked over the documentation and see that we could hide stacktrace in default error handler. Instead of that, we decided to replace it with a custom one. That allows us to put an additional logging logic and customize the output. And this is a short description of how to do it. ;-)&lt;/p&gt;

&lt;p&gt;To implement the custom error handler we can extend &lt;code&gt;org.eclipse.jetty.server.handler.AbstractHandler&lt;/code&gt; and override &lt;code&gt;handle&lt;/code&gt; method. On the code snippet below there is an example handler. For sake of clarity it returns always simple text (content-type &lt;code&gt;text/plain&lt;/code&gt;) with code, error message and URL used.&lt;/p&gt;

&lt;p&gt;We can extend it by adding additional logic like different responses based on headers from the client, additional logging and so on. :-)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;pl.net.banach.customizeJetty&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.IOException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.OutputStreamWriter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.PrintWriter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.nio.BufferOverflowException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.nio.ByteBuffer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.nio.charset.StandardCharsets&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.servlet.ServletException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.servlet.http.HttpServletRequest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.servlet.http.HttpServletResponse&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.jetty.http.MimeTypes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.jetty.io.ByteBufferOutputStream&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.jetty.server.Dispatcher&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.jetty.server.Request&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.jetty.server.handler.AbstractHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.eclipse.jetty.util.StringUtil&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomJettyErrorHandler&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&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="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;baseRequest&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                       &lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                       &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
                       &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ServletException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;


        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Get error message, sanitize it, just in case.&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StringUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sanitizeXmlString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dispatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ERROR_MESSAGE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Get error code that will returned&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StandardCharsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UTF_8&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Get writer used&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;baseRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResponse&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getHttpOutput&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getBuffer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ByteBufferOutputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrintWriter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OutputStreamWriter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

            &lt;span class="c1"&gt;// Set content type, encoding and write response&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setContentType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MimeTypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCharacterEncoding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HTTP ERROR "&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\nMessage: "&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&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;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\nURI: "&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequestURI&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;


            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BufferOverflowException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;baseRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResponse&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;resetContent&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;baseRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getHttpChannel&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;sendResponseAndComplete&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we have the error handler ready then it registering it is easy. To do this we will create a custom configuration which implements &lt;code&gt;WebServerFactoryCustomizer&lt;/code&gt; with &lt;code&gt;@Configuration&lt;/code&gt; annotation. In a &lt;code&gt;customize&lt;/code&gt; method we will create a customizer and add a newly created error handler.&lt;/p&gt;

&lt;p&gt;Seems simple, but be sure to put this configuration class in a package that is scanned by Spring &lt;code&gt;@ComponentScan&lt;/code&gt; annotation!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;pl.net.banach.customizeJetty&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.web.embedded.jetty.JettyServerCustomizer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.web.server.WebServerFactoryCustomizer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.context.annotation.Configuration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JettyConfiguration&lt;/span&gt;
            &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;WebServerFactoryCustomizer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;JettyServletWebServerFactory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;customize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JettyServletWebServerFactory&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;JettyServerCustomizer&lt;/span&gt; &lt;span class="n"&gt;customizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setErrorHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomJettyErrorHandler&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;};&lt;/span&gt;
        &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addServerCustomizers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customizer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s all - from now all errors that go to Jetty (application server) will be handled by our custom handler. :-)&lt;/p&gt;

</description>
      <category>java</category>
      <category>jetty</category>
      <category>spring</category>
      <category>web</category>
    </item>
    <item>
      <title>How to expose local service using nginx and SSH</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Fri, 25 Mar 2022 19:20:00 +0000</pubDate>
      <link>https://forem.com/elwin013/how-to-expose-local-service-using-nginx-and-ssh-1jmj</link>
      <guid>https://forem.com/elwin013/how-to-expose-local-service-using-nginx-and-ssh-1jmj</guid>
      <description>&lt;p&gt;One of my colleagues needs to expose the local running app to an external service. There were simple constraints - the domain name under which service was exposed cannot change (because it needs to be whitelisted) and need to be a subdomain of the company domain. &lt;/p&gt;

&lt;p&gt;They already have some virtual machines for developers with external IP adresses and SSH access running. I’ve proposed using them to solve this task - below you can find the solution that can be applied.&lt;/p&gt;

&lt;p&gt;What will be needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;publicly available server (external IP) with (GNU/)Linux and nginx (for this post I’m assuming it is Ubuntu),&lt;/li&gt;
&lt;li&gt;user and permissions to change nginx configuration (sudo/root),&lt;/li&gt;
&lt;li&gt;SSH access for that server,&lt;/li&gt;
&lt;li&gt;some domain name, for example - &lt;code&gt;some.domain.tld&lt;/code&gt; - pointing to the server external IP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s start with configuration - in &lt;code&gt;/etc/nginx/sites-available/some.domain.tld&lt;/code&gt; write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
  listen 80;
  listen [::]:80;

  gzip on;
  server_name         some.domain.tld;

  location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_redirect off;
    proxy_set_header Host 127.0.0.1;
    proxy_set_header X-Original-Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration will proxy requests for &lt;code&gt;some.domain.tld&lt;/code&gt; to the local port 8080 on the server.&lt;/p&gt;

&lt;p&gt;To enable it we need to link this configuration to &lt;code&gt;sites-enabled&lt;/code&gt; directory using command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ln -s /etc/nginx/sites-available/some.domain.tld /etc/nginx/sites-enabled/some.domain.tld

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and restart nginx - &lt;code&gt;systemctl restart nginx&lt;/code&gt;. Now under domain &lt;code&gt;some.domain.tld&lt;/code&gt; visitors will see an error page with the message “bad gateway” - all because on 8080 port there is nothing.&lt;/p&gt;

&lt;p&gt;Now, with the power of a ssh tunnel, we will make this 8080 port on remote server will point to some port on our local machine.&lt;/p&gt;

&lt;p&gt;To expose our local service we can use the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -N -R $PORT_ON_SERVER:localhost:$LOCAL_PORT $LOGIN@$SERVER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$PORT_ON_SERVER is the port which we forward request to on server,&lt;/li&gt;
&lt;li&gt;$LOCAL_PORT - local port on dev machine where something is running,&lt;/li&gt;
&lt;li&gt;$LOGIN and $SERVER are the username and address of the server running proxy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assuming that username is &lt;code&gt;alice&lt;/code&gt;, the server is available under &lt;code&gt;some.domain.tld&lt;/code&gt; domain and our local service is available under port 4502:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -N -R 8080:localhost:4502 alice@some.domain.tld
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s all - after opening the domain in the browser we will see our local service. And anybody on the Internet can also view it, so watch out! ;-)&lt;/p&gt;

</description>
      <category>nginx</category>
      <category>web</category>
      <category>ssh</category>
    </item>
    <item>
      <title>How to prevent running script if there are changes in local Git working space</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Fri, 30 Jul 2021 08:49:00 +0000</pubDate>
      <link>https://forem.com/elwin013/how-to-prevent-running-script-if-there-are-changes-in-local-git-working-space-242e</link>
      <guid>https://forem.com/elwin013/how-to-prevent-running-script-if-there-are-changes-in-local-git-working-space-242e</guid>
      <description>&lt;p&gt;Recently I spent some time making improvements around deploying an application. Some of them are bash scripts automating some boring actions. All of them has one common part - should not be run if there are any changes (staged or not) in the local Git repository (working tree). Fortunately, it is simple to incorporate checks like this into scripts!&lt;/p&gt;

&lt;p&gt;To get the information about staged (added with &lt;code&gt;git add&lt;/code&gt;) and not staged files we will use &lt;code&gt;git diff&lt;/code&gt; command. Without any parameters, it will give us detailed information of what changed. That is a bit too much than our needs, so we will use &lt;code&gt;--stat&lt;/code&gt; flag to get only statistics - path to file and the number of lines added and removed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ~/repository&amp;gt; git diff --stat
unstagedFile.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For staged files we will use very similar command - it will be &lt;code&gt;git diff --stat&lt;/code&gt; but with&lt;code&gt;--cached&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ~/repository&amp;gt; git diff --cached --stat
stagedFile.txt | 1 +
1 file changed, 1 insertion(+)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both commands will return empty strings when no changes. We will use that information to show the message and stop (exit) script. In the end, script will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Fill up variables&lt;/span&gt;
&lt;span class="nv"&gt;STAGED_CHANGES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nt"&gt;--stat&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;NOT_STAGED_CHANGES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;git diff &lt;span class="nt"&gt;--stat&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="c"&gt;# Check if there are any staged but not committed changes&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[!&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STAGED_CHANGES&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="c"&gt;# Show message&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"You have staged, but not committed changes. Not releasing!"&lt;/span&gt;
&lt;span class="c"&gt;# And exit with non-zero code&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="c"&gt;# Check if there are any not staged&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[!&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NOT_STAGED_CHANGES&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="c"&gt;# Show message&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"You have not staged and not committed changes. Not releasing!"&lt;/span&gt;
&lt;span class="c"&gt;# And exit with non-zero code&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="c"&gt;## Anything else we need to do! ##&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run commands mentioned above,&lt;/li&gt;
&lt;li&gt;store results in variables,&lt;/li&gt;
&lt;li&gt;if any of those variables are not empty - show the message and exit script with non-zero return value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why non-zero return value? Because by default &lt;code&gt;0&lt;/code&gt; is treated as “everything was OK” and any other value means “error”. This allows to chain commands like &lt;code&gt;doSomething &amp;amp;&amp;amp; doMagic&lt;/code&gt; - in that case, &lt;code&gt;doMagic&lt;/code&gt; will run only if &lt;code&gt;doSomething&lt;/code&gt; return exited with &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Bonus stuff - we can make output red using some magic numbers which we can put in a script (in echo command):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;RED_START&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\0&lt;/span&gt;&lt;span class="s2"&gt;33[1;31m"&lt;/span&gt;
&lt;span class="nv"&gt;RED_END&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;[0m"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"Normal message!"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED_START&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Normal message but in RED!&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED_END&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result of the script above will look like this: &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.amazonaws.com%2Fuploads%2Farticles%2F1bgl9o3ucd50txjui8vg.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.amazonaws.com%2Fuploads%2Farticles%2F1bgl9o3ucd50txjui8vg.png" alt="The result of the colourful script" width="415" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that’s all folks! If you find this post useful - let me know! :-)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to put pom.xml version and build date in properties?</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Fri, 04 Jun 2021 19:27:55 +0000</pubDate>
      <link>https://forem.com/elwin013/how-to-put-pom-xml-version-and-build-date-in-properties-3i4b</link>
      <guid>https://forem.com/elwin013/how-to-put-pom-xml-version-and-build-date-in-properties-3i4b</guid>
      <description>&lt;p&gt;While working on webapp API in Java I need to send the app version and the build date to the frontend. But how to make this? &lt;/p&gt;

&lt;p&gt;As my API build is based on maven I thought about getting version from &lt;code&gt;pom.xml&lt;/code&gt; file. So, let's make it this way!&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution! Almost...
&lt;/h2&gt;

&lt;p&gt;I need to put in the &lt;code&gt;pom.xml&lt;/code&gt; file configuration responsible for resources filtering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
 &lt;span class="c"&gt;&amp;lt;!-- clipped --&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;resources&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/main/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;filtering&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/filtering&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/resources&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in the &lt;code&gt;app.properties&lt;/code&gt; properties which will be replaced during build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;build.version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${pom.version}&lt;/span&gt;
&lt;span class="py"&gt;build.date&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${timestamp}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the build my &lt;code&gt;app.properties&lt;/code&gt; is filled with expected data:&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.amazonaws.com%2Fuploads%2Farticles%2Fxtzurfh0l75jafc5x041.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.amazonaws.com%2Fuploads%2Farticles%2Fxtzurfh0l75jafc5x041.png" alt="image" width="280" height="88"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now I can access version from POM and last build in Java app easily!&lt;/p&gt;

&lt;h2&gt;
  
  
  And fin^H^H... another problem?
&lt;/h2&gt;

&lt;p&gt;Everything works smoothly, I can get the version from the &lt;code&gt;pom.xml&lt;/code&gt; and also the build date. But... a favicon is now broken! What?!&lt;/p&gt;

&lt;p&gt;Frontend is deployed along with backend (using &lt;a href="https://javalin.io/documentation#static-files" rel="noopener noreferrer"&gt;Javalin static files feature&lt;/a&gt; and files were loaded from resources folder.&lt;/p&gt;

&lt;p&gt;It turns out that the resource filtering plugin processe &lt;code&gt;favicon.ico&lt;/code&gt; (in fact all &lt;code&gt;.ico&lt;/code&gt; files) and broke them by saving them incorrectly. So I need to exclude those files from filtering!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final solution
&lt;/h2&gt;

&lt;p&gt;Final configuration in the &lt;code&gt;pom.xml&lt;/code&gt; looks like in snippet below. &lt;/p&gt;

&lt;p&gt;It processing all files in &lt;code&gt;src/main/resources&lt;/code&gt; except all &lt;code&gt;.ico&lt;/code&gt; files. But I want &lt;code&gt;.ico&lt;/code&gt; in resource folder - so I need add them but without filtering (processing them).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
 &lt;span class="c"&gt;&amp;lt;!-- clipped --&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;resources&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/main/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;filtering&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/filtering&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;excludes&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;exclude&amp;gt;&lt;/span&gt;**/*.ico&lt;span class="nt"&gt;&amp;lt;/exclude&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;/excludes&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/main/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;filtering&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/filtering&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;includes&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;include&amp;gt;&lt;/span&gt;**/*.ico&lt;span class="nt"&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;/includes&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/resources&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's all - everything is now OK ;-)&lt;/p&gt;

</description>
      <category>java</category>
      <category>maven</category>
      <category>webapp</category>
    </item>
    <item>
      <title>Why my session is not persisted?! Another story of (de)serialising...</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Thu, 14 Jan 2021 08:00:00 +0000</pubDate>
      <link>https://forem.com/elwin013/why-my-session-is-not-persisted-another-story-of-de-serialising-do6</link>
      <guid>https://forem.com/elwin013/why-my-session-is-not-persisted-another-story-of-de-serialising-do6</guid>
      <description>&lt;p&gt;Yep, that’s another story of “always check if serialising and de-serialising works as expected”. And some kind of reminder for future-me if I forgot about this! ;-)&lt;/p&gt;

&lt;p&gt;Session of logged users seems to be a pretty easy topic, yep? For sure it is! What if you want to share that session between different instances of your app? That seems quite easy too - let’s store it in a database and you’re good to go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Need and sort of “background”
&lt;/h2&gt;

&lt;p&gt;For my last project, I’m using a simple web framework called &lt;a href="https://javalin.io/" rel="noopener noreferrer"&gt;Javalin&lt;/a&gt;, which runs default on &lt;em&gt;Jetty&lt;/em&gt;. And after making PoC I’ve come across of topic “single user using many app instances”. Fortunately, there is even tutorial about it on Javalin page (&lt;a href="https://javalin.io/tutorials/jetty-session-handling" rel="noopener noreferrer"&gt;here&lt;/a&gt;). I’ve checked it, wrote a bit code aaaand… it is not working as expected!&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;When enabled saving session into database and user was… logged out instantly! Error 401 was sent from the secured resource and frontend was redirecting to the login which invalidates session (which, in fact, was desired behaviour). But the question is - why this 401 was sent if the user logged in correctly?&lt;/p&gt;

&lt;p&gt;After debugging and looking into saved session object in database I’ve found out that there is NO USER DATA THERE!&lt;/p&gt;

&lt;p&gt;Wait, what? I’m sure that I’ve put that data into the session. It works if the session was in memory!&lt;/p&gt;

&lt;p&gt;Let’s see how writing and reading values into session looks in Javalin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// saving value&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sessionAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mystery"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"I like trains"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// and reading value to the "value" variable&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sessionAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mystery"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty simple, yep? And this is how saving user details was in my app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserDetails&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// ... filling up data and saving to session&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sessionAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"USER"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userDetails&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks the same… and not working. But &lt;code&gt;mystery&lt;/code&gt; above works, so what the heck is going on?!&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution!
&lt;/h2&gt;

&lt;p&gt;You might already know because I’ve already written it in the beginning - serialisation. Session store (from class &lt;code&gt;JDBCSessionDataStoreFactory&lt;/code&gt;) didn’t know how to save object with user details to the database. So it simply ignores it. And the rest of the app didn’t work because there was no user data, so no info about user roles, so no cookies and big “NONONO”.&lt;/p&gt;

&lt;p&gt;So, solution was simply to serialise and de-serialise it, for example as a JSON. For that I’ve used Jackson mapper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// yep, simple com.fasterxml.jackson.databind.ObjectMapper&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// serialize before saving to session&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserDetails&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// ... filling up data and saving to session&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sessionAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"USER"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeValueAsString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userDetails&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// and reading it in some other place&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userDetailsStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sessionAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="no"&gt;USER_SESSION_KEY&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;userDetailsStr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
    &lt;span class="nc"&gt;UserDetails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And everything started to work smoothly and as expected!&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;I will repeat myself from the beginning - always check if serialising and de-serialising works as it should. And additionally - check if data is saved. That can save a lot of work and time. :-)&lt;/p&gt;

</description>
      <category>java</category>
      <category>javalin</category>
    </item>
    <item>
      <title>Git config based on current (sub)folder</title>
      <dc:creator>Kamil</dc:creator>
      <pubDate>Sun, 29 Nov 2020 15:00:00 +0000</pubDate>
      <link>https://forem.com/elwin013/git-config-based-on-current-sub-folder-4a7c</link>
      <guid>https://forem.com/elwin013/git-config-based-on-current-sub-folder-4a7c</guid>
      <description>&lt;p&gt;Some time ago I’ve looked over my current company repositories. Surprisingly there was a lot of commits with emails that are not company ones. Instead of those - a lot of &lt;em&gt;gmail.com&lt;/em&gt;, _outlook.com_and other free email providers!&lt;/p&gt;

&lt;p&gt;That looks a bit unprofessional, isn’t it? Even if we do some freelance gigs - we probably want to put nicer email than private one used for social websites. And if, for some reason, we’re forced to use company email - we need to be sure that it will be used!&lt;/p&gt;

&lt;p&gt;So, what we can do to make it better? Just configure it with couple lines of code ;-) Let’s assume that all our work-related stuff will live in &lt;code&gt;~/work&lt;/code&gt; folder and all other is personal. So, let’s start with a simple &lt;code&gt;~/.gitconfig&lt;/code&gt; configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ~/.gitconfig
[user]
name = Johny Mnemonic
email = johny@mnemonic.tld
[includeIf "gitdir:~/work/"]
path = ~/work/.gitconfig

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configuration in &lt;em&gt;user&lt;/em&gt; section will be default one. We will overwrite it in other configuration files, like in folders with work.&lt;/p&gt;

&lt;p&gt;Let’s then create an additional configuration for work, just in our work folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ~/work/.gitconfig
[user]
email = johny@memory.courier.tld

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want to put our name in commits, yep? So only one thing that we overwrite will be the email address. Instead of &lt;em&gt;private&lt;/em&gt; one, there will be company email.&lt;/p&gt;

&lt;p&gt;And that’s it. Now all repositories, that didn’t have set up individual user settings, will use ones that are based on the folder, e.g.:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;~/work/super-duper&lt;/code&gt; will use work configuration,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/project/my-website&lt;/code&gt; will use private (default) one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope that “short writeup” will help somebody in some way. :-) Also - did you have any comments? Drop me a line on &lt;a href="https://twitter.com/elwin013/" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>git</category>
    </item>
  </channel>
</rss>
