Sorry

This feed does not validate.

In addition, interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: https://feeds.feedburner.com/Wisselnetfeed

  1. <?xml version="1.0"?>
  2. <rss version="2.0">
  3. <channel>
  4. <title>wissel.net Usability - Productivity - Business - The web - Singapore and Twins</title>
  5. <link>https://wissel.net/blog/stories.rss</link>
  6. <description>Thoughts, Insights and Opinions of Stephan H. Wissel. Topics included: Salesforce, Lotus Notes and Domino, IBM Websphere, NodeJS, JavaScript,  J2EE, .Net, Software Archtecture, Personcentric Development, Agile Software, SDLC, Singapore and my Twins</description>
  7. <language>en,de</language>
  8. <copyright>(C) 2003 - 2021 Stephan H. Wissel, All rights reserved</copyright>
  9. <pubdate>Tue, 16 Apr 2024 12:38:36 +0000</pubdate>
  10. <item>
  11. <title>Maven build with multiple Java versions</title>
  12. <description>&lt;p&gt;Imagine, you are tasked with maintaining a &lt;a href="https://opensource.hcltechsw.com/Domino-rest-api/index.html"&gt;Java application&lt;/a&gt; that needs to run on more than one Java version. You want to ensure that it compiles, tests and builds on all of them.&lt;br&gt;
  13.  This is our story, buckle up, there are a few moving parts&lt;/p&gt;
  14. &lt;h3&gt;The big picture&lt;/h3&gt;
  15. &lt;ul&gt;
  16. &lt;li&gt;We use &lt;a href="https://maven.apache.org/"&gt;Apache Maven&lt;/a&gt; to drive the project using the &lt;code&gt;pom.xml&lt;/code&gt;&lt;/li&gt;
  17. &lt;li&gt;The &lt;a href="https://maven.apache.org/plugins/maven-toolchains-plugin/"&gt;Maven Toolchains&lt;/a&gt; plugin controls the Java versions&lt;/li&gt;
  18. &lt;li&gt;Using &lt;code&gt;&amp;lt;properties&amp;gt; ... &amp;lt;/properties&amp;gt;&lt;/code&gt; and &lt;a href="https://maven.apache.org/guides/introduction/introduction-to-profiles.html"&gt;Build Profiles&lt;/a&gt; to adjust conditions for processing&lt;/li&gt;
  19. &lt;li&gt;Annotatiosn like &lt;code&gt;@Only8&lt;/code&gt; and &lt;code&gt;@Only17&lt;/code&gt; help to qualify tests&lt;/li&gt;
  20. &lt;li&gt;Our build tool (&lt;a href="https://www.jenkins.io/"&gt;Jenkins&lt;/a&gt; or &lt;a href="https://github.com/features/actions"&gt;Github Actions&lt;/a&gt;) will use a container provided (in our case based on &lt;a href="https://www.redhat.com/en/blog/introducing-red-hat-universal-base-image"&gt;Redhat UBI&lt;/a&gt;)&lt;/li&gt;
  21. &lt;/ul&gt;</description>
  22. <link>2024/04/maven-build-with-multiple-java-versions.html</link>
  23. <author>Stephan H. Wissel</author>
  24. <guid>e01d6620-fbcb-11ee-83f2-810c012896ec</guid>
  25. <pubDate>16 April 2024</pubDate>
  26.  
  27. </item>
  28. <item>
  29. <title>nginx as ingress for Docker compose</title>
  30. <description>&lt;p&gt;In June I wrote about how to use &lt;a href="/blog/2023/06/docker-nginx-spa-and-brotli-compression.html"&gt;Docker &amp;amp; nginx&lt;/a&gt; to deliver statically rendered &lt;a href="https://github.com/google/brotli"&gt;brotli&lt;/a&gt; files for your web (frontend) application. It improves delivery quite a bid, but left me wonder: isn't there too much static WebServer involved?&lt;/p&gt;
  31. &lt;h3&gt;Double hop to deliver static files&lt;/h3&gt;
  32. &lt;p&gt;A typical web application using micro/mini/midi services looks like this:&lt;/p&gt;
  33. &lt;p&gt;&lt;img src="/blog/images/2023/TypicalDockerConfig.jpg" alt="A typical Docker configuration"&gt;&lt;/p&gt;
  34. &lt;p&gt;It is common, easy and concerns quite separated. However it comes with a set of challenges:&lt;/p&gt;
  35. &lt;ul&gt;
  36. &lt;li&gt;nginx doesn't do http/2 on &lt;a href="https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/"&gt;&lt;code&gt;proxy_pass&lt;/code&gt;&lt;/a&gt;, so you miss the ability to serve static files directly with http/2&lt;/li&gt;
  37. &lt;li&gt;For static file we have two nginx involved&lt;/li&gt;
  38. &lt;li&gt;Each service needs to be exposed to the host at some port&lt;/li&gt;
  39. &lt;li&gt;The service architecture leaks to the host based nginx. SO any change in service needs an update to the &lt;code&gt;docker-compose.yml&lt;/code&gt; &lt;strong&gt;AND&lt;/strong&gt; the host based nginx configuration&lt;/li&gt;
  40. &lt;li&gt;the containers depend on that, external to them, configuration&lt;/li&gt;
  41. &lt;/ul&gt;
  42. &lt;p&gt;So I tried to design a better way to handle this without going all &lt;a href="https://kubernetes.io/"&gt;K-in&lt;/a&gt;:&lt;/p&gt;
  43. &lt;p&gt;&lt;img src="/blog/images/2023/DockerConfigWithNginx.jpg" alt="Docker configuration with ingress as component"&gt;&lt;/p&gt;
  44. &lt;p&gt;This looed like a more promising approach:&lt;/p&gt;
  45. &lt;ul&gt;
  46. &lt;li&gt;Services could be addressed with their internal network name&lt;/li&gt;
  47. &lt;li&gt;Only Ports 80 and 443 of one container need exposure on the host&lt;/li&gt;
  48. &lt;li&gt;The nginx configuration inside the container is immutable and can't accidentially be reconfigured in production (your image comes from a pipeline isn't it)&lt;/li&gt;
  49. &lt;/ul&gt;
  50. &lt;h3&gt;Challenges&lt;/h3&gt;
  51. &lt;ul&gt;
  52. &lt;li&gt;When trying to configure certbot, I initially tried using the &lt;code&gt;--nginx&lt;/code&gt; parameter with an http challenge and shared data mounts. None of the attempts worked satisfactory, so at the end I settled on a&lt;a href="https://letsencrypt.org/docs/challenge-types/#dns-01-challenge"&gt;DNS-01&lt;/a&gt; using &lt;a href="https://www.cloudflare.com/"&gt;CloudFlare&lt;/a&gt;.&lt;/li&gt;
  53. &lt;li&gt;Since I wanted the nginx configuration to be inside the container image (and not on a data mount), a good understandig of nginx's configuration is necessary. The only persisted information was &lt;code&gt;/etc/letsencrypt&lt;/code&gt; for the certificate and a secret for CloudFlare credentials&lt;/li&gt;
  54. &lt;li&gt;When the nginx configuration is statically configured for TLS, on initial load it will fail since the certs don't exist yet. Auntie Google suggested a manual run of certbot, but I favour &lt;code&gt;docker compose up&lt;/code&gt; to handle everything&lt;/li&gt;
  55. &lt;li&gt;I ended up creating my own docker images, which was an epiphany: it absolutely makes sense to build a container image for single use instead of trying hard to make it configurable and vulnerable to mis-configuration&lt;/li&gt;
  56. &lt;/ul&gt;</description>
  57. <link>2023/11/nginx-as-ingress-for-docker-compose.html</link>
  58. <author>Stephan H. Wissel</author>
  59. <guid>c5cd81d0-83ab-11ee-a943-5f6e43c4acd6</guid>
  60. <pubDate>15 November 2023</pubDate>
  61.  
  62. </item>
  63. <item>
  64. <title>Quarkus and GraalVM starter</title>
  65. <description>&lt;p&gt;When &lt;a href="https://www.java.com/en/"&gt;Java&lt;/a&gt; is one of the languanges in your portfolio, you might have heard of &lt;a href="https://quarkus.io/"&gt;Quarkus&lt;/a&gt;, an alternative to &lt;a href="https://spring.io/projects/spring-boot"&gt;Spring Boot&lt;/a&gt; build on top of &lt;a href="https://vertx.io"&gt;vert.x&lt;/a&gt; and &lt;a href="https://www.graalvm.org/"&gt;GraalVM&lt;/a&gt;, a polyglot runtime for Java and other languages.&lt;/p&gt;
  66. &lt;p&gt;This article describes the getting started that worked for me.&lt;/p&gt;
  67. &lt;h3&gt;Moving parts&lt;/h3&gt;
  68. &lt;p&gt;The fist hurdle to overcome is to install all the bits and pieces. There are plenty of versions (Java 11 - Java 21) and methods (maven, CLI, packet managers), so it con be confusing what to pick. I tried most of them and created a mess and a deep appreciation for the "reset to snapshot" feature afforded by virtual machines. Instructions work for macOS, Linux or &lt;a href="https://www.graalvm.org/"&gt;Linux on Windows&lt;/a&gt;.Here we go:&lt;/p&gt;
  69. &lt;ol&gt;
  70. &lt;li&gt;install &lt;a href="https://sdkman.io/"&gt;SdkMan&lt;/a&gt;.&lt;/li&gt;
  71. &lt;/ol&gt;
  72. &lt;p&gt;The tool helps to keep your software development kits under control. From their website:&lt;/p&gt;
  73. &lt;p&gt;&lt;em&gt;"Meet SDKMAN! ? your reliable companion for effortlessly managing multiple Software Development Kits on Unix systems. Imagine having different versions of SDKs and needing a stress-free way to switch between them. SDKMAN! steps in with its easy-to-use Command Line Interface (CLI) and API."&lt;/em&gt;&lt;/p&gt;
  74. &lt;pre&gt;&lt;code class="language-bash"&gt;curl -s "https://get.sdkman.io" | bash
  75. &lt;/code&gt;&lt;/pre&gt;
  76. &lt;p&gt;You can thank me later. Side note: there are 16 different JDK offerings that can be installed, we are spoiled &lt;a href="https://thedecisionlab.com/reference-guide/economics/the-paradox-of-choice"&gt;for choices&lt;/a&gt;&lt;/p&gt;
  77. &lt;ol&gt;
  78. &lt;li&gt;install &lt;a href="https://www.graalvm.org/"&gt;GraalVM&lt;/a&gt;&lt;/li&gt;
  79. &lt;/ol&gt;
  80. &lt;p&gt;Currently, as of time of writing, there are three GraalVM distributions available. The Open Source, community supported &lt;a href="https://github.com/oracle/graal/"&gt;GraalVM Community Edition&lt;/a&gt;, the commercial, Oracle supported &lt;a href="https://www.graalvm.org/downloads/"&gt;Oracle GraalVM&lt;/a&gt; which requires a license in production and the ReedHat backed &lt;a href="https://github.com/graalvm/mandrel"&gt;Mandrel&lt;/a&gt;. Mandrel is advertised as "specifically to support Quarkus". The Java 21 version was not yet available on sdkman, so I used the community edition. To stick with Mandrel I will use the container build option, later more on that&lt;/p&gt;
  81. &lt;pre&gt;&lt;code class="language-bash"&gt;# List SDKs
  82. sdk list java
  83. # install GraalVM
  84. sdk install java 21-graaalce
  85. &lt;/code&gt;&lt;/pre&gt;
  86. &lt;ol&gt;
  87. &lt;li&gt;Install &lt;a href="https://quarkus.io/"&gt;Quarkus&lt;/a&gt;&lt;/li&gt;
  88. &lt;/ol&gt;
  89. &lt;p&gt;This will install the Quarkus CLI and for good measure &lt;a href="https://maven.apache.org"&gt;Apache Maven&lt;/a&gt;. The Quarkus CLI makes a &lt;a href="https://quarkus.io/guides/ide-tooling"&gt;pleasant developer experience&lt;/a&gt;&lt;/p&gt;
  90. &lt;pre&gt;&lt;code class="language-bash"&gt;sdk install quarkus
  91. sdk install mvn
  92. &lt;/code&gt;&lt;/pre&gt;
  93. &lt;ol&gt;
  94. &lt;li&gt;Install &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;&lt;/li&gt;
  95. &lt;/ol&gt;
  96. &lt;p&gt;You can use &lt;a href="https://www.docker.com/products/docker-desktop/"&gt;Docker desktop&lt;/a&gt; (required a license for larger organisations) or &lt;a href="https://rancherdesktop.io/"&gt;Rancher Desktop&lt;/a&gt; (which also handles Kubernetes), &lt;a href="https://podman-desktop.io/"&gt;Podman Desktop&lt;/a&gt;, any of &lt;a href="https://alternativeto.net/browse/search/?q=Docker"&gt;the alternatives&lt;/a&gt; or the command line. New to Docker? There's &lt;a href="https://www.google.com/search?q=how+to+install+docker"&gt;plenty of fish&lt;/a&gt;&lt;/p&gt;
  97. &lt;p&gt;Now we are good to go. Skipping the &lt;a href="https://quarkus.io/get-started/"&gt;Code with Quarkus&lt;/a&gt; tutorial lets build a n app in java and native put it into a container&lt;/p&gt;</description>
  98. <link>2023/10/quarkus-and-graalvm-starter.html</link>
  99. <author>Stephan H. Wissel</author>
  100. <guid>59234250-69c9-11ee-ba4c-cfc559bbd988</guid>
  101. <pubDate>13 October 2023</pubDate>
  102.  
  103. </item>
  104. <item>
  105. <title>Fun with Azure Active Directory &amp; JWT</title>
  106. <description>&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Active_Directory"&gt;Active Directory&lt;/a&gt; has been the dominant standard for IT directories, even if it isn't &lt;a href="/blog/2014/01/a-short-history-of-directory-trees.html"&gt;the prettiest tree&lt;/a&gt; in the forrest. It's younger sibling &lt;a href="https://en.wikipedia.org/wiki/Microsoft_Azure_Active_Directory"&gt;~~Azure Active Directory~~ Entra ID&lt;/a&gt; is a big player in cloud based &lt;a href="https://en.wikipedia.org/wiki/Identity_provider"&gt;Identity Providers (IdP)&lt;/a&gt;. Unsurprisingly it behaves differently than the gold standard &lt;a href="https://www.keycloak.org/"&gt;KeyCloak&lt;/a&gt;&lt;/p&gt;
  107. &lt;h3&gt;JWT expectations&lt;/h3&gt;
  108. &lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/JSON_Web_Token"&gt;Json Web Token (JWT)&lt;/a&gt; payload is a &lt;strong&gt;very&lt;/strong&gt; losely definded &lt;a href="https://en.wikipedia.org/wiki/JSON"&gt;JSON&lt;/a&gt; object with various claims. There is only a minimal consent of properties":&lt;/p&gt;
  109. &lt;pre&gt;&lt;code class="language-json"&gt;{
  110.  "iss": "https://where-it-came-from",
  111.  "audience": "https://where-it-should-be-valid",
  112.  "iat": "DATE/TIME -&amp;gt; issued at",
  113.  "exp": "DATE/TIME -&amp;gt; expiry",
  114.  "scope": "space separated list of scopes",
  115.  "email": "user's email"
  116. }
  117. &lt;/code&gt;&lt;/pre&gt;
  118. &lt;p&gt;The whole thing is (un)defined in &lt;a href="https://datatracker.ietf.org/doc/html/rfc7519"&gt;RFC7519&lt;/a&gt;, sufficiently loose, so anyone can claim to be standard compliant and nothing is interoperable (just like &lt;a href="https://datatracker.ietf.org/doc/html/rfc5545"&gt;ical&lt;/a&gt;). There is a &lt;a href="https://www.iana.org/assignments/jwt/jwt.xhtml"&gt;list of known claims&lt;/a&gt;, but RFC7519 states: "&lt;em&gt;None of the claims&lt;br&gt;
  119.   defined below are intended to be mandatory to use or implement in all&lt;br&gt;
  120.   cases, but rather they provide a starting point for a set of useful,&lt;br&gt;
  121.   interoperable claims.&lt;/em&gt;"&lt;/p&gt;
  122. &lt;p&gt;To ease validation of signatures, one can use an URL &lt;code&gt;.../.well-known/openid-configuration&lt;/code&gt; which provides a number of needed properties:&lt;/p&gt;
  123. &lt;ul&gt;
  124. &lt;li&gt;various endpoint URLs for authentication and token exchange&lt;/li&gt;
  125. &lt;li&gt;&lt;code&gt;issuer&lt;/code&gt;: The value corresponding to the &lt;code&gt;iss&lt;/code&gt; property in a JWT&lt;/li&gt;
  126. &lt;li&gt;&lt;code&gt;jwks_uri&lt;/code&gt;: URL to read the public key to validate signatures&lt;/li&gt;
  127. &lt;li&gt;&lt;code&gt;scopes_supported&lt;/code&gt;: what scopes does the API support&lt;/li&gt;
  128. &lt;/ul&gt;
  129. &lt;h3&gt;Azure - same but different&lt;/h3&gt;
  130. &lt;p&gt;When you setup &lt;a href="https://help.hcltechsw.com/domino/12.0.2/admin/secu_config_http_bearer_auth_using_oidc_c.html"&gt;Domino for JWT&lt;/a&gt; you need a series of specific conditions. The interesting parts from the documentation:&lt;/p&gt;
  131. &lt;ul&gt;
  132. &lt;li&gt;&lt;em&gt;One of the JWT's "aud" (audience) claims must match the Domino Internet Site's host name&lt;/em&gt;&lt;/li&gt;
  133. &lt;li&gt;&lt;em&gt;JWTs must contain a "iss" (issuer) claim matching the "issuer" returned from the OIDC provider's .well-known/openid-configuration endpoint&lt;/em&gt;&lt;/li&gt;
  134. &lt;li&gt;&lt;em&gt;JWTs must contain a "scope" claim that includes "Domino.user.all"&lt;/em&gt;&lt;/li&gt;
  135. &lt;/ul&gt;
  136. &lt;p&gt;When you follow &lt;a href="https://opensource.hcltechsw.com/Domino-rest-api/howto/IdP/configuringAD.html"&gt;KEEP's how to configure Azure AD&lt;/a&gt; you will find a set of pain points, in no specific order:&lt;/p&gt;
  137. &lt;ul&gt;
  138. &lt;li&gt;You can't remove claims you don't need&lt;/li&gt;
  139. &lt;li&gt;Azure AD will not issue a &lt;code&gt;scope&lt;/code&gt; claim, but an &lt;code&gt;scp&lt;/code&gt; claim&lt;/li&gt;
  140. &lt;li&gt;The &lt;code&gt;aud&lt;/code&gt; claim is fixed to the "Application ID URI"&lt;/li&gt;
  141. &lt;li&gt;The &lt;code&gt;iss&lt;/code&gt; claim in a token does not match the &lt;code&gt;issuer&lt;/code&gt; property from &lt;code&gt;well-known/openid-configuration&lt;/code&gt;&lt;/li&gt;
  142. &lt;li&gt;The &lt;code&gt;jwks_uri&lt;/code&gt; URL does not return an &lt;code&gt;alg&lt;/code&gt; property for the algorythm (nor did I find any way to request an &lt;a href="https://en.wikipedia.org/wiki/Elliptic-curve_cryptography"&gt;Elliptic-curve&lt;/a&gt; signer)&lt;/li&gt;
  143. &lt;/ul&gt;
  144. &lt;p&gt;So there's tons of fun to be had with Azure ~~Active Directory~~ Entra ID&lt;/p&gt;</description>
  145. <link>2023/08/fun-with-azure-active-directory-and-jwt.html</link>
  146. <author>Stephan H. Wissel</author>
  147. <guid>0fd1b040-465c-11ee-8527-1ded1f8f3d81</guid>
  148. <pubDate>29 August 2023</pubDate>
  149.  
  150. </item>
  151. <item>
  152. <title>Primary Posture Applications</title>
  153. <description>&lt;p&gt;We use a multitude of applications per day. Each of them captures some level of attention and interaction. &lt;a href="https://en.wikipedia.org/wiki/Alan_Cooper"&gt;Alan Cooper&lt;/a&gt; coined the term &lt;a href="https://en.wikipedia.org/wiki/Application_posture"&gt;Application posture&lt;/a&gt;, with the mainly used application being the &lt;a href="https://uxplanet.org/application-posture-d896bceda537"&gt;&lt;strong&gt;sovereign application&lt;/strong&gt;&lt;/a&gt;. I personally like the term &lt;strong&gt;primary posture application&lt;/strong&gt; better and will use it in this post&lt;/p&gt;
  154. &lt;h3&gt;Being primany&lt;/h3&gt;
  155. &lt;p&gt;Since users spend most of their time in it, there's a willingness to become "senior intermediate experts". Shortcuts are learned, workflows get shared and a deeper understanding is desired. Depending on the nature of your work, very different application are your primary&lt;/p&gt;
  156. &lt;ul&gt;
  157. &lt;li&gt;for a graphic desiger it might be &lt;a href="https://www.gimp.org/"&gt;GIMP&lt;/a&gt; or &lt;a href="https://inkscape.org/"&gt;Inkscape&lt;/a&gt;&lt;/li&gt;
  158. &lt;li&gt;a vlogger spends lot of time in &lt;a href="https://obsproject.com/"&gt;OBS&lt;/a&gt;&lt;/li&gt;
  159. &lt;li&gt;The controllers spend their days in spreadsheets&lt;/li&gt;
  160. &lt;li&gt;The sales manager in &lt;a href="https://salesforce.com/"&gt;CRM&lt;/a&gt;&lt;/li&gt;
  161. &lt;li&gt;Operations is fond of &lt;a href="https://sap.com/"&gt;ERP&lt;/a&gt;&lt;/li&gt;
  162. &lt;li&gt;eMail and chat are strong contenders too&lt;/li&gt;
  163. &lt;li&gt;the Scrum master lives in Jira, while developers on the command-line and IDE&lt;/li&gt;
  164. &lt;/ul&gt;
  165. &lt;h3&gt;Primary posture by association&lt;/h3&gt;
  166. &lt;p&gt;To cover anything else, aggregators were used. Trailblazer here was the &lt;a href="https://en.wikipedia.org/w/index.php?title=Lotus_Notes"&gt;Lotus Notes Client&lt;/a&gt;: One did everything in Notes, the main job and all the auxiliary and transient would be there. This consistency was attempted to recreate using portals and intranets (for inspiration what intranets can achieve, head over to &lt;a href="https://www.nngroup.com/reports/topic/intranets/"&gt;The Nielsen Norman Group&lt;/a&gt;).&lt;/p&gt;
  167. &lt;h3&gt;Auxiliary applications&lt;/h3&gt;
  168. &lt;p&gt;You need to complete a task fast and want effortless results. An auxiliary posture helps with that. Adding an appointment in a calendar, booking a ride share, filing tax returns.&lt;/p&gt;
  169. &lt;h3&gt;Auxiliary applications with a primary posture&lt;/h3&gt;
  170. &lt;p&gt;One's primary application is another's auxiliary. This is a huge problem especially for bespoke applications. Typically they are comissioned by departments who will use them in "primary posture" (e.g. the leave management system gets commissioned by HR). The leave administrator will happily learn all bells and whistles, while mortal users are irritated by the complexity. I recall working on a leave management system where the initial application form had over 30 fields to cover all eventualities. We were able to convince the application owner to take a 2 form approach: the initial form had: coming, going, type of leave and optional "on behalf". 2 buttons were offered: "more" and "submit". "More" would lead to the 30+ fields form. We monitored usage for 6 month. Not a single time the larger form was submitted.&lt;/p&gt;
  171. &lt;h3&gt;Multiple front-ends&lt;/h3&gt;
  172. &lt;p&gt;To avoid the primary auxiliary trap, a clear API that separates UI from business logic helps. It allows to build smaller front-ends that are auxiliary in nature but don't compromize integrity. &lt;a href="https://www.openapis.org/"&gt;OpenAPI&lt;/a&gt; is your friend&lt;/p&gt;</description>
  173. <link>2023/08/primary-posture-applications.html</link>
  174. <author>Stephan H. Wissel</author>
  175. <guid>77462770-40a2-11ee-9a9a-81b1521576ba</guid>
  176. <pubDate>21 August 2023</pubDate>
  177.  
  178. </item>
  179. <item>
  180. <title>Passphrase Generator</title>
  181. <description>&lt;p&gt;Passphrases are considered easier to remember for humans and harder to crack for machines, famously explained in &lt;a href="https://xkcd.com/936/"&gt;this comic&lt;/a&gt;:&lt;/p&gt;
  182. &lt;p&gt;&lt;a href="https://xkcd.com/936/"&gt;&lt;img src="https://imgs.xkcd.com/comics/password_strength.png" alt="Pasword strength"&gt;&lt;/a&gt;&lt;/p&gt;
  183. &lt;p&gt;The challenge then is to have a good word list to pick from. There are &lt;a href="https://wordcounter.io//blog/how-many-words-does-the-average-person-know"&gt;various measurements&lt;/a&gt; on how many words one person would &lt;strong&gt;use&lt;/strong&gt; which could be as low as a thousand. Note there is a huge difference between &lt;em&gt;recognize&lt;/em&gt; and &lt;em&gt;use&lt;/em&gt;.&lt;/p&gt;
  184. &lt;h3&gt;Passphrases and dices&lt;/h3&gt;
  185. &lt;p&gt;In a recent &lt;a href="https://chaos.social/@stw/110756503711275152"&gt;Toot exchange&lt;/a&gt; &lt;a href="https://chaos.social/@ospalh"&gt;ospalh&lt;/a&gt; pointed me to &lt;a href="https://en.wikipedia.org/wiki/Diceware"&gt;Diceware&lt;/a&gt;, a method to use &lt;a href="https://diceware.dmuth.org"&gt;dice rolls&lt;/a&gt; and a word list to determine a passphrase. Usually one uses the regular 6 sides dices and 5 dices, which lets you pick from a 7776 member word list. The &lt;a href="https://www.eff.org"&gt;EFF&lt;/a&gt; published &lt;a href="https://www.eff.org/deeplinks/2018/08/dragon-con-diceware"&gt;a version using the 20-sided dice&lt;/a&gt; from &lt;a href="https://en.wikipedia.org/wiki/Dungeons_%26_Dragons"&gt;Dungeon and Dragons&lt;/a&gt; as well as various word lists.&lt;/p&gt;
  186. &lt;h3&gt;Wordlists&lt;/h3&gt;
  187. &lt;p&gt;An attacker who doesn't know that they are dealing with a passphrase, using conventional cracking methods stands little chance to decipher the phrase. However as the defender you must assume, they know your word list, so it is imperative to keep it long, while maintaining the odds to remember (in any case you can use some &lt;a href="https://bitwarden.com"&gt;extra brain&lt;/a&gt;). SOme of the word lists you can find online:&lt;/p&gt;
  188. &lt;ul&gt;
  189. &lt;li&gt;&lt;a href="https://theworld.com/%7Ereinhold/diceware.wordlist.asc"&gt;Arnold Reinhold's Diceware list&lt;/a&gt;, 1995, 7776 entries&lt;/li&gt;
  190. &lt;li&gt;&lt;a href="https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt"&gt;EFF list from 2016&lt;/a&gt;, 2016, 7776 entries (introduced &lt;a href="https://www.eff.org/deeplinks/2016/07/new-wordlists-random-passphrases"&gt;here&lt;/a&gt;)&lt;/li&gt;
  191. &lt;li&gt;&lt;a href="https://www.eff.org/deeplinks/2018/08/dragon-con-diceware"&gt;Fandom generated word lists&lt;/a&gt; by EFF for the 20 side dice&lt;/li&gt;
  192. &lt;li&gt;&lt;a href="https://www.eff.org/files/2018/08/29/gameofthrones_8k-2018.txt"&gt;Game of Thrones&lt;/a&gt;, 2018, 4000 entries&lt;/li&gt;
  193. &lt;li&gt;&lt;a href="https://www.eff.org/files/2018/08/29/harrypotter_8k_3column-txt.txt"&gt;Harry Potter&lt;/a&gt;, 2018, 4000 entries&lt;/li&gt;
  194. &lt;li&gt;&lt;a href="https://www.eff.org/files/2018/08/29/memory-alpha_8k_2018.txt"&gt;Star Track&lt;/a&gt;, 2018, 4000 entries&lt;/li&gt;
  195. &lt;li&gt;&lt;a href="https://www.eff.org/files/2018/08/29/starwars_8k_2018.txt"&gt;Star Wars&lt;/a&gt;, 2018, 4000 entries&lt;/li&gt;
  196. &lt;/ul&gt;
  197. &lt;h3&gt;Math.random() to replace dices&lt;/h3&gt;
  198. &lt;p&gt;Let's roll (pun intended) our own passphrase generator. To make it a little more fun these are our constrains:&lt;/p&gt;
  199. &lt;ul&gt;
  200. &lt;li&gt;passphrase has 5 elements: 4 words and one 6 digit number&lt;/li&gt;
  201. &lt;li&gt;the number appears at a random position&lt;/li&gt;
  202. &lt;li&gt;elements are separated by a &lt;code&gt;-&lt;/code&gt; (for readability, in active use you might just filter them out)&lt;/li&gt;
  203. &lt;/ul&gt;</description>
  204. <link>2023/07/passphrase-generator.html</link>
  205. <author>Stephan H. Wissel</author>
  206. <guid>20817830-29fb-11ee-8ef8-8bb241062b76</guid>
  207. <pubDate>24 July 2023</pubDate>
  208.  
  209. </item>
  210. <item>
  211. <title>Keep your github container registry tidy</title>
  212. <description>&lt;p&gt;SO you drank the cool-aid, like me, and use &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; to build your projects and &lt;a href="https://github.com/features/packages"&gt;GitHub pacckages&lt;/a&gt; for your private containers, maven produced Jars, npm modules. Soon your honeymoon is over and you hit the storage limit of your account.&lt;/p&gt;
  213. &lt;h3&gt;You need to clean up&lt;/h3&gt;
  214. &lt;p&gt;Looking at the packages you will notice, that they are all there, all the version, in case of containers even the untagged ones. The root of the problem is equally the solution: a GitHub Action to &lt;a href="https://github.com/marketplace/actions/delete-package-versions"&gt;delete package versions&lt;/a&gt;. The package is very flexible and well documented, outlining &lt;a href="https://github.com/marketplace/actions/delete-package-versions#scenarios"&gt;several scenarios&lt;/a&gt; how to put it to use&lt;/p&gt;
  215. &lt;h2&gt;Things to watch out for&lt;/h2&gt;
  216. &lt;p&gt;You have to decide when you want to put it to use:&lt;/p&gt;
  217. &lt;ul&gt;
  218. &lt;li&gt;on schedule, like &lt;a href="https://www.youtube.com/watch?v=mthSq-u2i7A"&gt;every Friday&lt;/a&gt;&lt;/li&gt;
  219. &lt;li&gt;manual, pressing a button&lt;/li&gt;
  220. &lt;li&gt;on each build, when you add a new package&lt;/li&gt;
  221. &lt;/ul&gt;
  222. &lt;p&gt;I also experienced that &lt;code&gt;{{ secrets.GITHUB_TOKEN }}&lt;/code&gt; wouldn't work when the package you target is private, even when it is in the same repository. Once you know, it's not a big deal, just create a &lt;a href="https://github.com/settings/tokens"&gt;PAT&lt;/a&gt; and add it to the repository's secrets. You might want to add &lt;code&gt;workflow_dispatch&lt;/code&gt; to all triggers, so you can test run them anytime.&lt;/p&gt;</description>
  223. <link>2023/07/keep-your-github-container-registry-tidy.html</link>
  224. <author>Stephan H. Wissel</author>
  225. <guid>8d4324b0-253b-11ee-aa6d-b183cc9640ea</guid>
  226. <pubDate>18 July 2023</pubDate>
  227.  
  228. </item>
  229. <item>
  230. <title>Deploy private npm packages into private containers using github actions</title>
  231. <description>&lt;p&gt;&lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; are rapidly becoming my favorite CI environment. Their &lt;a href="https://github.com/marketplace?type=actions"&gt;marketplace&lt;/a&gt; has an action for everything. Sometimes it takes a little trial and error before things work smoothly. This is one of that stories.&lt;/p&gt;
  232. &lt;h3&gt;Authentication is everything&lt;/h3&gt;
  233. &lt;p&gt;Imagine the following scenario: you have developed a set of private TypeScript (or JavaScript) packages and have &lt;a href="https://docs.github.com/en/packages/quickstart"&gt;successfully deployed&lt;/a&gt; them to the &lt;strong&gt;private&lt;/strong&gt; GitHub npm registry under the name &lt;code&gt;@myfamousorg/coolpackage&lt;/code&gt; - where &lt;code&gt;myfamousorg&lt;/code&gt; must match the repository owner (org or individual).&lt;/p&gt;
  234. &lt;p&gt;Now you want to use them in your application. That application shall be packed in a Container and made available in GitHub's private registry. All that automated using GitHub Actions.&lt;/p&gt;
  235. &lt;h3&gt;You will need a PAT (or two)&lt;/h3&gt;
  236. &lt;p&gt;In GitHub, head to the &lt;a href="https://github.com/settings/tokens"&gt;Personal access tokens / Tokens (classic)&lt;/a&gt; section of your developer settings in profile. You need to &lt;a href="https://github.com/settings/tokens/new"&gt;create tokens&lt;/a&gt; that allow you to handle packages.&lt;/p&gt;
  237. &lt;p&gt;&lt;img src="/blog/images/2023/GitHubToken.png" alt="GitHub Tokens"&gt;&lt;/p&gt;
  238. &lt;p&gt;There are two places where you want to enter that token:&lt;/p&gt;
  239. &lt;ul&gt;
  240. &lt;li&gt;In &lt;code&gt;https://github.com/[your-org]/[your-repo]/settings/secrets/actions&lt;/code&gt; create a key &lt;code&gt;GIT_NPM_PACKAGES&lt;/code&gt; and copy your PAT there. You can pick any name, you will need it in the GitHub action later&lt;/li&gt;
  241. &lt;li&gt;In &lt;code&gt;~/.npmrc&lt;/code&gt;, your global settings for npm in your home directory. Don't put the info in the &lt;code&gt;.npmrc&lt;/code&gt; in your git project.&lt;/li&gt;
  242. &lt;/ul&gt;
  243. &lt;pre&gt;&lt;code class="language-properties"&gt;prefix=/home/[your username]/.npm-packages
  244. @myfamousorg:registry=https://npm.pkg.github.com
  245. //npm.pkg.github.com/:_authToken=[here goes the token]
  246.  
  247. &lt;/code&gt;&lt;/pre&gt;
  248. &lt;p&gt;The &lt;code&gt;prefix&lt;/code&gt; property allows you to run `npm install -g [package] without admin access.&lt;/p&gt;</description>
  249. <link>2023/07/deploy-nodejs-with-private-packages-in-docker.html</link>
  250. <author>Stephan H. Wissel</author>
  251. <guid>a81d27ba-4cf9-444d-99e6-c4813be2e9f4</guid>
  252. <pubDate>16 July 2023</pubDate>
  253.  
  254. </item>
  255. <item>
  256. <title>Handle HTTP chunked responses</title>
  257. <description>&lt;p&gt;Objects &lt;a href="https://www.youtube.com/watch?v=nFDAK8NY4JY"&gt;I need a lot of objects&lt;/a&gt;. When dealing with APIs there is one fundamental question to answer: how much data do you want to retrieve?&lt;/p&gt;
  258. &lt;p&gt;The old school answer: let's page results, &lt;a href="https://retrocomputing.stackexchange.com/questions/5629/why-did-80x25-become-the-text-monitor-standard"&gt;25 at a time&lt;/a&gt;. Then &lt;a href="https://www.nngroup.com/articles/infinite-scrolling-tips/"&gt;infinite scrolling came along&lt;/a&gt; and changed expectations.&lt;/p&gt;
  259. &lt;h3&gt;I got some chunk for you&lt;/h3&gt;
  260. &lt;p&gt;One way to operate is for the server to send all data, but using &lt;a href="https://en.wikipedia.org/wiki/Chunked_transfer_encoding"&gt;&lt;code&gt;Transfer-Encoding: chunked&lt;/code&gt;&lt;/a&gt; (&lt;a href="https://tools.ietf.org/html/rfc9112#section-7.1"&gt;RFC 9112&lt;/a&gt;) in the header and deliver data in several packages, aptly named chunks. A client can process each chunk on arrival to allow interactivity before data transmission concludes.&lt;/p&gt;
  261. &lt;p&gt;However this requires adjustments on both sides. The server needs to send data with a clear delimiter, e.g. &lt;code&gt;\n&lt;/code&gt; (newline) and the client needs to process the data as a stream&lt;/p&gt;
  262. &lt;h3&gt;The usual way won't work&lt;/h3&gt;
  263. &lt;p&gt;We typically find code like this:&lt;/p&gt;
  264. &lt;pre&gt;&lt;code class="language-js"&gt;fetch(url)
  265.  .then((resp) =&amp;gt; resp.json())
  266.  .then((json) =&amp;gt; {
  267.    for (let row in json) {
  268.      addRow(json[row], parentElement);
  269.    }
  270.  });
  271. &lt;/code&gt;&lt;/pre&gt;
  272. &lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API"&gt;&lt;code&gt;fetch&lt;/code&gt;&lt;/a&gt; hides a lot of complexity, we need to handle when we process a chunked result as it arrives.&lt;/p&gt;</description>
  273. <link>2023/07/handle-http-chunked-responses.html</link>
  274. <author>Stephan H. Wissel</author>
  275. <guid>a73f182a6-e51d-4c0f-9b95-10c640d637dd</guid>
  276. <pubDate>04 July 2023</pubDate>
  277.  
  278. </item>
  279. <item>
  280. <title>Docker, nginx, SPA and brotli compression</title>
  281. <description>&lt;p&gt;Contemporary web development separates front-end and back-end, resulting in the front-end being a few static files. Besides setting long cache headers, pre-compression is one way to speed up delivery&lt;/p&gt;
  282. &lt;h3&gt;Setting the stage&lt;/h3&gt;
  283. &lt;ul&gt;
  284. &lt;li&gt;we have a NodeJS project that outputs our &lt;a href="https://en.wikipedia.org/wiki/Single-page_application"&gt;SPA&lt;/a&gt; in &lt;code&gt;/usr/dist&lt;/code&gt; directory. Highly recommended here: &lt;a href="https://vitejs.dev/"&gt;VITE&lt;/a&gt;. Works for multi-page applications too.&lt;/li&gt;
  285. &lt;li&gt;We target only &lt;a href="https://caniuse.com/?search=brotli"&gt;modern browsers&lt;/a&gt; that understand &lt;a href="https://github.com/google/brotli"&gt;brotli&lt;/a&gt; (Sorry not IE). Legacy will have to deal with uncompressed files&lt;/li&gt;
  286. &lt;li&gt;We want to go light on CPU, so we compress at build time, not runtime&lt;/li&gt;
  287. &lt;/ul&gt;
  288. &lt;h3&gt;Things to know&lt;/h3&gt;
  289. &lt;ul&gt;
  290. &lt;li&gt;When &lt;a href="https://www.nginx.com/"&gt;nginx&lt;/a&gt; is configured for brotli and the file &lt;code&gt;index.html&lt;/code&gt; gets requested, the file &lt;code&gt;index.html.br&lt;/code&gt; gets served if present and the browser indicated (what it does by default) that it can accept br&lt;/li&gt;
  291. &lt;li&gt;There are tons of information about the &lt;a href="https://www.sobyte.net/post/2022-04/docker-nginx-brotli/"&gt;need to compile nginx&lt;/a&gt; due to the lack of brotli support out of the box. That's not necessary (see below)&lt;/li&gt;
  292. &lt;li&gt;brotli is both OpenSource and the open standard &lt;a href="https://www.ietf.org/rfc/rfc7932.txt"&gt;RFC 7932&lt;/a&gt;&lt;/li&gt;
  293. &lt;li&gt;brotli currently &lt;a href="https://github.com/google/brotli/issues/970"&gt;lacks&lt;/a&gt; gzip's &lt;code&gt;-r&lt;/code&gt; flag, so some bash magic is needed&lt;/li&gt;
  294. &lt;/ul&gt;
  295. &lt;h3&gt;Moving parts&lt;/h3&gt;
  296. &lt;ul&gt;
  297. &lt;li&gt;DockerFile&lt;/li&gt;
  298. &lt;li&gt;nginx configuration&lt;/li&gt;
  299. &lt;/ul&gt;
  300. &lt;p&gt;The Dockerfile will handle the brotli generation&lt;/p&gt;</description>
  301. <link>2023/06/docker-nginx-spa-and-brotli-compression.html</link>
  302. <author>Stephan H. Wissel</author>
  303. <guid>61bc1e40-1231-11ee-a61a-ef046a8827ca</guid>
  304. <pubDate>24 June 2023</pubDate>
  305.  
  306. </item>
  307.  
  308. </channel>
  309. </rss>
  310.  
Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda