<?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: Youssef El Idrissi</title>
    <description>The latest articles on Forem by Youssef El Idrissi (@0xw3ston).</description>
    <link>https://forem.com/0xw3ston</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%2F1147867%2F1221c231-44bd-485e-bcc6-fcc0e7e3ef26.jpeg</url>
      <title>Forem: Youssef El Idrissi</title>
      <link>https://forem.com/0xw3ston</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/0xw3ston"/>
    <language>en</language>
    <item>
      <title>Design Patterns: Facade</title>
      <dc:creator>Youssef El Idrissi</dc:creator>
      <pubDate>Wed, 25 Feb 2026 01:45:00 +0000</pubDate>
      <link>https://forem.com/techlabma/design-patterns-facade-23d3</link>
      <guid>https://forem.com/techlabma/design-patterns-facade-23d3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;(This Blog post is part of a collaborative work between &lt;strong&gt;Me&lt;/strong&gt; and &lt;strong&gt;Mustapha El Idrissi&lt;/strong&gt;, Consult his devTo page for more information: &lt;a href="https://dev.to/appsbymuss"&gt;https://dev.to/appsbymuss&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&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%2F1y0lzt9tzyvfegvr2pzj.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%2F1y0lzt9tzyvfegvr2pzj.png" alt=" " width="800" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Facade Pattern
&lt;/h2&gt;

&lt;p&gt;This &lt;strong&gt;Structural Pattern&lt;/strong&gt; provides a simplified interface to a complex subsystem, making it easier to use by encapsulating the intricacies of the system behind a single, unified interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's its purpose ?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Facade Pattern helps in reducing the complexity of interactions with a complex system by providing a higher-level interface that abstracts away the underlying details.&lt;/li&gt;
&lt;li&gt;It’s useful when you want to simplify communication with a subsystem, allowing clients to interact with the system in a more straightforward way without needing to understand its complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Concepts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Facade Class:&lt;/strong&gt; The main class that provides a simplified interface to the client. It delegates client requests to the appropriate components within the subsystem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subsystem Classes:&lt;/strong&gt; The classes that represent the complex functionality of the system. These classes contain the actual implementation details and logic but are hidden from the client.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example: Home Automation System
&lt;/h2&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%2F9x89pxlf5vm8c2mcjno7.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%2F9x89pxlf5vm8c2mcjno7.png" alt=" " width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;these are &lt;strong&gt;Subsystem Classes&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LightSystem&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;TurnOnLights&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Lights are on."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;TurnOffLights&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Lights are off."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MusicSystem&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;PlayMusic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Playing music."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;StopMusic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Music stopped."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecuritySystem&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ArmSystem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Security system armed."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DisarmSystem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Security system disarmed."&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;ul&gt;
&lt;li&gt;This is the &lt;strong&gt;Facade Class&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeAutomationFacade&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;LightSystem&lt;/span&gt; &lt;span class="n"&gt;_lights&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;MusicSystem&lt;/span&gt; &lt;span class="n"&gt;_music&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;SecuritySystem&lt;/span&gt; &lt;span class="n"&gt;_security&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;HomeAutomationFacade&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_lights&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LightSystem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;_music&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MusicSystem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;_security&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SecuritySystem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;LeaveHome&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_lights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TurnOffLights&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;_music&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StopMusic&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;_security&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ArmSystem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Home is in 'leave' mode."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;EnterHome&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_security&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DisarmSystem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;_lights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TurnOnLights&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;_music&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PlayMusic&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Home is in 'enter' mode."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&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%2F0ai5lmdshzioihi0tble.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%2F0ai5lmdshzioihi0tble.png" alt=" " width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;And this is the Test (aka Consumer class)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;TestFacade&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;HomeAutomationFacade&lt;/span&gt; &lt;span class="n"&gt;homeSystem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HomeAutomationFacade&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;homeSystem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnterHome&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;homeSystem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LeaveHome&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;h2&gt;
  
  
  The Good, The Bad and the Ugly
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Advantages
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Simplifies the interface for interacting with complex subsystems, making it easier for clients to use.&lt;/li&gt;
&lt;li&gt;Reduces dependencies between clients and subsystems, promoting loose coupling.&lt;/li&gt;
&lt;li&gt;Encapsulates subsystem complexity, allowing for easier maintenance and understanding.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Disadvantages
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The facade can become a "God Object" if it tries to handle too many responsibilities.&lt;/li&gt;
&lt;li&gt;May hide system complexities that might be needed for advanced usage.&lt;/li&gt;
&lt;li&gt;Over-simplifying can lead to limitations in functionality for clients needing deeper access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  When to not use
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;When a subsystem is simple enough that no facade is needed.&lt;/li&gt;
&lt;li&gt;If clients require direct access to the components of a subsystem for customization or extension.&lt;/li&gt;
&lt;li&gt;In cases where the added layer of abstraction complicates the system rather than simplifying it.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>softwareengineering</category>
      <category>designpatterns</category>
      <category>programming</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Design Patterns: Introduction</title>
      <dc:creator>Youssef El Idrissi</dc:creator>
      <pubDate>Wed, 25 Feb 2026 01:34:22 +0000</pubDate>
      <link>https://forem.com/techlabma/design-patterns-introduction-377g</link>
      <guid>https://forem.com/techlabma/design-patterns-introduction-377g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;(This Blog post is part of a collaborative work between &lt;strong&gt;Me&lt;/strong&gt; and &lt;strong&gt;Mustapha El Idrissi&lt;/strong&gt;, Consult his devTo page for more information: &lt;a href="https://dev.to/appsbymuss"&gt;https://dev.to/appsbymuss&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Design patterns are proven, reusable solutions to common problems that occur during software design and development. They are like templates that can be adapted to address specific challenges within various contexts. Design patterns are not code themselves but rather descriptions of how to solve problems in a way that maximizes efficiency, scalability, and maintainability.&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%2Fa89tmif0b0i8ffs8lxsv.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%2Fa89tmif0b0i8ffs8lxsv.png" alt="Design Patterns" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is in general 3 types of design patterns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creational Design Patterns (such as: Singleton Pattern, Simple Factory Pattern)&lt;/li&gt;
&lt;li&gt;Structural Design Patterns (such as: Decorator Pattern, Facade Pattern, Adapter Pattern, Proxy Pattern)&lt;/li&gt;
&lt;li&gt;Behavioral Design Patterns (such as: Strategy Pattern, Observer Pattern)&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>softwareengineering</category>
      <category>csharp</category>
      <category>programming</category>
    </item>
    <item>
      <title>Push Notifications: How Your App Speaks When It’s Sleeping</title>
      <dc:creator>Youssef El Idrissi</dc:creator>
      <pubDate>Sun, 18 May 2025 06:48:11 +0000</pubDate>
      <link>https://forem.com/techlabma/push-notifications-4lma</link>
      <guid>https://forem.com/techlabma/push-notifications-4lma</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;(This Blog post is part of a collaborative work between &lt;strong&gt;Me&lt;/strong&gt; and &lt;strong&gt;Mustapha El Idrissi&lt;/strong&gt;, Consult his devTo page for more information: &lt;a href="https://dev.to/appsbymuss"&gt;https://dev.to/appsbymuss&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What are Push Notifications ?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Push notifications&lt;/strong&gt; are messages sent from an app or website to a user's device, even when the app or site isn’t actively open. They appear as pop-up alerts, banners, or notification icons on devices like smartphones, tablets, and computers.&lt;/p&gt;

&lt;p&gt;The mechanism with which these "Push Notifications" work is usually the use of some sort of background processes, these processes maintain a persistent connection with the designated "Push Server" depending on their device (in the case of Native Push) or their navigator (in the case of Web Push).&lt;/p&gt;

&lt;p&gt;There's two types of Push Notifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native Push: This one usually is linked directly to the Operating System of the Device where Push notifications were activated, for example, Windows, MacOS, Android or IOS.&lt;/li&gt;
&lt;li&gt;Web Push: This one is linked to specific navigators instead of the OS directly, Firefox, Chrome (or any Chromium based navigator like Opera...), Firefox etc...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a difference between both the execution and implementation of these two types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Push
&lt;/h2&gt;

&lt;p&gt;Web Push is a Protocol/technology that allows &lt;strong&gt;websites to send push notifications to users’ devices&lt;/strong&gt; (desktop, mobile) &lt;strong&gt;even when the browser is closed&lt;/strong&gt;. It’s part of the &lt;strong&gt;Push API&lt;/strong&gt; and &lt;strong&gt;Notifications API&lt;/strong&gt; standards, because it's not tightly coupled with the OS, sometimes it could not work as proficiently.&lt;br&gt;
On some mobile OSes, browsers may be restricted from running background processes aggressively to save battery, causing delays or missed notifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native Push
&lt;/h2&gt;

&lt;p&gt;The Native one works the greatest because Push Notifications are considered Top Priority by the OS, meaning that as long as the user has actual internet connection, they will 100% receive that Push notification, unless they go out of their way to tamper with the settings concerning those notifications or maybe they simply deactivate them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrappers
&lt;/h2&gt;

&lt;p&gt;They’re &lt;strong&gt;libraries or services&lt;/strong&gt; that &lt;strong&gt;abstract the differences between native push services&lt;/strong&gt; (like Apple Push Notification Service for iOS, Firebase Cloud Messaging for Android, Windows Notification Service, and Web Push for browsers) so you can send notifications without writing separate code for each platform. The issue with these "wrappers" is summarized in two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Due to the abstractions offered by third-party wrappers, a new problem could arise, instead of fully operating your system/mechanism, you rely on a third party service.&lt;/li&gt;
&lt;li&gt;These "wrapper" services usually either cost money or are "fremiums" (meaning they are free for a certain amount of traffic/messages, after that it becomes paid once it passes a certain threshold)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Push Server
&lt;/h2&gt;

&lt;p&gt;One of the most important components when it comes to push notifications is the "Push Server". The way it works is that we subscribe a device for a specific app/notification etc., which generates a very Unique URL, the vendor-specific server registers that this specific device "subscribed" to listen for push notifications coming on that navigator/device, the Unique URL generated gets stored in the backend so that we send a request to it, which in turns gets the actual vendor-specific server to push those notifications to those devices, So in very simple words, it's just a middleman, we don't get the right to directly push notifications from the backend to the device.&lt;/p&gt;

&lt;p&gt;Push Notifications usually operate with a &lt;strong&gt;Pub/Sub Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subscribers&lt;/strong&gt;: are the devices that want to receive notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broker&lt;/strong&gt;: being the Push Server that mediates between the Broadcaster (Backend) and the actual subscribed clients.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publisher(s)&lt;/strong&gt;: the backend that wants to broadcast events/messages (new discounts etc.)&lt;/li&gt;
&lt;/ul&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%2Fu9u58fvvcwc9pbo73hn8.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%2Fu9u58fvvcwc9pbo73hn8.png" alt="pub/sub architecture in a Push Notification System" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are Push Servers that handle notifications for each OS/Browser:&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%2F38ecqwf1w9w9itfqtp8q.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%2F38ecqwf1w9w9itfqtp8q.png" alt="Push Notifications: Native vs Web vs Wrappers" width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Diagram above demonstrates the common &lt;strong&gt;Native Push Servers&lt;/strong&gt; for each platform/browser (on the left), and it also shows how wrappers could be used to hide all that technical implementation behind abstractions that end up offering the developers very simplified API endpoints/library methods to use (on the far right)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advantages of Push Notifications:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;One of the main advantages is the ability to distribute specific messages/notifications to devices/browsers that aren’t currently open or in use.&lt;/li&gt;
&lt;li&gt;If there are multiple Websites/apps that use the same vendor-specific server to push their notifications to devices, then a singular connection gets persisted with multiple "Publishers" but with the same "Broker" which minimizes back-and-forth Network communication, for this reason &lt;strong&gt;Multiplexing&lt;/strong&gt; is used to minimize battery drain, especially on phones. &lt;/li&gt;
&lt;/ul&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%2F5y2s002p8i67wasi323o.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%2F5y2s002p8i67wasi323o.png" alt="Efficiency Mechanism of Push Notifications" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example(s) of Use Cases:
&lt;/h2&gt;

&lt;p&gt;1) An admin needs to be notified immediately when a new order is placed, even if the browser or device is idle or closed. Push notifications ensure that the admin receives timely updates regardless of the app’s active state.&lt;br&gt;
2) A user needs to know when a new message is received. While real-time communication methods like WebSockets, Polling, or Server-Sent Events (SSE) work when the app is open, they fail when the window is minimized or fully closed. In such cases, push notifications become the most reliable strategy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up: WebPush
&lt;/h1&gt;

&lt;p&gt;To setup WebPush on your web server, we're going to use a minimal wrapper library called "web-push" (it exists in NodeJS, Python and PHP and there are other implementations aswell).&lt;/p&gt;

&lt;p&gt;There are 2 major sections:&lt;/p&gt;

&lt;h2&gt;
  
  
  1 - Backend
&lt;/h2&gt;

&lt;p&gt;Now each website/API is identified with a pair of &lt;strong&gt;VAPID&lt;/strong&gt; keys (&lt;strong&gt;Voluntary Application Server Identification&lt;/strong&gt;), In order for our Web server to send push notifications, VAPID keys are used to authenticate the web server to the push server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To generate the VAPID keys, we run the following instruction:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;webPush&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web-push&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webPush&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateVAPIDKeys&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;


&lt;span class="c1"&gt;// response:&lt;/span&gt;
&lt;span class="cm"&gt;/* {
  publicKey: 'BENBPj_33ywKcH109jfokUTiS91pLbD2SmVNbUja9KBN4Ppn8HTuZNC_TKEGGsJLRzx4X02kiNA7I-7uKYnLwRM',
  privateKey: '0LLLufPFBBXYFWOymFzrrLkLFeh0GTJzZ-XKf-Ehe_w'      
} */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We set those details with this function:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;webPush&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setVapidDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="s2"&gt;`mailto:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PRIMARY_EMAIL_OF_MENTAINER&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;vapidKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;vapidKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;privateKey&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now we need 2 methods.&lt;/li&gt;
&lt;li&gt;One Method for adding the "Push Endpoints" for each app/device (aka the subscribers)&lt;/li&gt;
&lt;li&gt;One other method is for sending the actual Push Notification.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;subscribers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setNewAdminSubscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;subscribers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new subscription&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendAdminsNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;adminSub&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;subscribers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;webPush&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;adminSub&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2 - Frontend
&lt;/h2&gt;

&lt;p&gt;Okay on the front end we have to setup 2 things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Service Worker&lt;/strong&gt;, which is basically a type of process that runs in the background, it's seperated from the web page itself, so it can do background fetching, handle push notifications and other things..&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;strong&gt;Function to Subscribe&lt;/strong&gt;, This would accomplish two things, show an "allow notifications ?" popup to show up, and also subscribe to the designated "Push Server" (depending on which navigator is being used).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For the service worker we create a file named "sw.js" (or any other name, it doesn't matter)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This handles the push notification in a way that it shows a popup and specifies the vibration settings (if the navigator is on a phone) etc etc.. basically customizing the popup that will show up.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// sw.js&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;push&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This notification is a teest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;images/example.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;vibrate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="c1"&gt;// data: {&lt;/span&gt;
        &lt;span class="c1"&gt;//     dateOfArrival: Date.now(),&lt;/span&gt;
        &lt;span class="c1"&gt;//     primaryKey: '2'&lt;/span&gt;
        &lt;span class="c1"&gt;// },&lt;/span&gt;
        &lt;span class="c1"&gt;// sticky: true,&lt;/span&gt;
        &lt;span class="na"&gt;requireInteraction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;explore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Explore this new world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;images/checkmark.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;images/xmark.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&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;ul&gt;
&lt;li&gt;Now to actually register it within the website, you have to run this code in the index.js (if you're using an SPA like React), or maybe index.html (inside a |script| block)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.js&lt;/span&gt;
&lt;span class="cm"&gt;/* ... */&lt;/span&gt;

&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StrictMode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/StrictMode&amp;gt;&lt;/span&gt;&lt;span class="err"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sw.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Service Worker Registered.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Service Worker Ready&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now this would be the actual subscribe action:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;userVisibleOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;applicationServerKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;VAPID-PUBLIC-KEY&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/subscribe-push&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;push&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;At this point you're basically done, all you have to do now is incorporate the "sendPushNotification" method in critical parts of your backend.&lt;/p&gt;

&lt;p&gt;In an E-commerce website it could be a simple "new order has been created!" notification when an order has been created (on a &lt;strong&gt;Model/ORM/T-SQL Level&lt;/strong&gt;) or it could be of other uses.&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%2Fwl2ty7iy2cr7qajzy292.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%2Fwl2ty7iy2cr7qajzy292.png" alt="Flow of a Push Notification Mechanism in an E-Commerce website" width="800" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1) &lt;strong&gt;The Client makes a purchase (aka confirms an order)&lt;/strong&gt;&lt;br&gt;
2) &lt;strong&gt;The Web Server then logs the successful order in a Database (using an ORM or a Native DB-Adapter), then using the method we defined, the backend initializes a Push Notification to the Push Server&lt;/strong&gt;&lt;br&gt;
3) &lt;strong&gt;The Push Server then Pushes the notification to the Admin's Browser&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The point is that you could broadcast any notification to anyone, conditional statements could be added to make sure specific notifications get sent to specific "User-Agents" and so on.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>systemdesign</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>GitHub Webhook CI/CD: Step-by-step guide</title>
      <dc:creator>Youssef El Idrissi</dc:creator>
      <pubDate>Tue, 04 Feb 2025 21:33:53 +0000</pubDate>
      <link>https://forem.com/techlabma/github-webhook-cicd-step-by-step-guide-1j6g</link>
      <guid>https://forem.com/techlabma/github-webhook-cicd-step-by-step-guide-1j6g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;(This Blog post is part of a collaborative work between &lt;strong&gt;Me&lt;/strong&gt; and &lt;strong&gt;Mustapha El Idrissi&lt;/strong&gt;, Consult his devTo page for more information: &lt;a href="https://dev.to/appsbymuss"&gt;https://dev.to/appsbymuss&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is CI/CD
&lt;/h2&gt;

&lt;p&gt;CI/CD, or &lt;strong&gt;Continuous Integration and Continuous Delivery/Deployment&lt;/strong&gt;, is a set of practices and tools that automates the process of software development, testing, and release. It helps developers deliver code changes more frequently, safely, and reliably.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Continuous Integration&lt;/strong&gt;: This is a development practice where developers frequently integrate their code changes into a shared repository.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Continuous Delivery&lt;/strong&gt;:  This goes one step further by automating the entire release process. Once code passes all testing stages, it is automatically deployed to the production environment.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are lot of tools that are used to perform &lt;strong&gt;CI&lt;/strong&gt; and &lt;strong&gt;CD&lt;/strong&gt; such as and not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Jenkins&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Actions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitLab CI/CD&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Travis CI&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However these tools are usually followed by resource use restrictions or require monetary contributions to be used efficiently and at the same time beginners struggle to use such tools at the start of their Software Development career.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is however an easier-to-bootstrap and harder-to-efficiently-setup way to achieve CI/CD which is &lt;strong&gt;"GitHub &lt;a href="https://www.youtube.com/watch?v=Q_VPL6KrH2o" rel="noopener noreferrer"&gt;Webhooks&lt;/a&gt;"&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to setup GitHub Webhook ?
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Step 0: Create a repo
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Ofcourse when we have a new project we have to create a new repository for it to store our code changes (aka commits), but in this case it will also be useful to achieve our CI/CD goal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 1: Create a route for the POST-webhook
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Assuming that you already have a server with your desired runtime environment/Framework up and running on a specific port.&lt;/li&gt;
&lt;li&gt;You're gonna have to also make a webhook in order to let Github have a way to reach your server in the case of new change to the &lt;strong&gt;main/production branch on your github repo&lt;/strong&gt; like so:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedAt&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;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;verifySignature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-hub-signature-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// GitHub sends the signature here&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No signature found on request&lt;/span&gt;&lt;span class="dl"&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hmac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REPO_WEBHOOK_SECRET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;digest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&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;signature&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Signature does not match&lt;/span&gt;&lt;span class="dl"&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;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Signature is valid&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/cicd/github-cicd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// The raw body of the request&lt;/span&gt;
    &lt;span class="c1"&gt;// const isValid = verifySignature(req, res, buf);&lt;/span&gt;

    &lt;span class="cm"&gt;/* if (!isValid) {
            return res.status(401).send('Invalid signature');
    }*/&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;refs/heads/main&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// PM2 is my instance manager&lt;/span&gt;
        &lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;git pull origin main &amp;amp;&amp;amp; pm2 restart cicd_app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/cicd/time&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Listening on Port 80...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;a href="https://github.com/0xW3ston/ci_cd_basics" rel="noopener noreferrer"&gt;Full source code&lt;/a&gt;)&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Configure the repo's settings
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go to [YourRepo -&amp;gt; Settings -&amp;gt; Webhooks]&lt;br&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%2F1ylrjzqbebg5ut9mcjdg.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%2F1ylrjzqbebg5ut9mcjdg.png" alt=" " width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then&lt;br&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%2Fq8kx2eo2055ujnbi897q.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%2Fq8kx2eo2055ujnbi897q.png" alt=" " width="785" height="126"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then we get to the webhook creation panel&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[&lt;strong&gt;warn&lt;/strong&gt;] Depending on the SSL state of your website (if it's activated or not), choose the "SSL Verification" option accordingly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[&lt;strong&gt;warn&lt;/strong&gt;] Incase you want Github to include a "secret" token to authenticate itself to your server to ensure it's Github and not a threat actor, then put a secret word, otherwise leave empty. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fmv6wd4cpwaobh67h7hkm.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%2Fmv6wd4cpwaobh67h7hkm.png" alt=" " width="785" height="815"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Ready !
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;After Setting up your webhook on your &lt;strong&gt;webserver&lt;/strong&gt; and &lt;strong&gt;github webhook&lt;/strong&gt; of your repo, then you're basically good to go.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Macro
&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%2Faj7a380u8nvbw468fmew.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%2Faj7a380u8nvbw468fmew.png" alt=" " width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First&lt;/strong&gt; a developer will push their commit (code changes) to GitHub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secondly&lt;/strong&gt; GitHub will send a POST Request to our server, and specifically to our webhook route with the body in JSON with information related to that github push that we've done just a moment ago.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thirdly&lt;/strong&gt; The server will then ofcourse treat said request as a way to know that there are changes on the production branch that must be applied as soon as possible, therefor a &lt;strong&gt;git pull&lt;/strong&gt; will be attempted and then tests and new builds and whatnot are going to be executed. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finally&lt;/strong&gt; The server will consequently restart with the updated source code.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>devops</category>
      <category>node</category>
      <category>github</category>
    </item>
    <item>
      <title>Vim: an epic terminal-based text editor</title>
      <dc:creator>Youssef El Idrissi</dc:creator>
      <pubDate>Sat, 28 Sep 2024 06:01:59 +0000</pubDate>
      <link>https://forem.com/techlabma/vim-an-epic-terminal-based-text-editor-4p9m</link>
      <guid>https://forem.com/techlabma/vim-an-epic-terminal-based-text-editor-4p9m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;(This Blog post is part of a collaborative work between &lt;strong&gt;Me&lt;/strong&gt; and &lt;strong&gt;Mustapha El Idrissi&lt;/strong&gt;, Consult his devTo page for more information: &lt;a href="https://dev.to/appsbymuss"&gt;https://dev.to/appsbymuss&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction about Vim
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Vim&lt;/strong&gt; (short for &lt;strong&gt;V&lt;/strong&gt;i &lt;strong&gt;IM&lt;/strong&gt;proved) is a highly configurable and efficient text editor that extends the functionality of the classic Unix-based Vi editor. Created by &lt;u&gt;Bram Moolenaar&lt;/u&gt;, Vim is designed to maximize productivity in text editing through a combination of keyboard-driven commands and modes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Buffers in vim ?
&lt;/h2&gt;

&lt;p&gt;In Vim, a buffer is essentially an in-memory representation of a file. When you open a file in Vim, it is loaded into a buffer, allowing you to make changes to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basics of Vim
&lt;/h2&gt;

&lt;h4&gt;
  
  
  To Edit a file (or Create one)
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;vim &amp;lt;file_name&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Saving and Quitting
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;To save the modifications to a file&lt;/strong&gt;: you simply press [:] then type &lt;a href="https://dev.towhich%20stands%20for%20[w]rite"&gt;w&lt;/a&gt; and press ENTER&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;To save the mods. and quit the file&lt;/strong&gt;: you do the same thing except it's &lt;a href="https://dev.towhich%20is%20w[rite]%20and%20q[uit]"&gt;:wq&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;To quit a file and discard the mods.&lt;/strong&gt;: press [:] and type [q!] then ENTER&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  There are 4 Modes in Vim
&lt;/h4&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%2Fbz9tvpdd2s87m959te8g.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%2Fbz9tvpdd2s87m959te8g.png" alt=" " width="800" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;strong&gt;NORMAL MODE&lt;/strong&gt;: It is the default mode. It is mostly useful for navigating through a file, however there are some shortcuts that make modifications to the file even with this mode. For example:
&lt;/h6&gt;

&lt;ul&gt;
&lt;li&gt;Pressing [0]: Places the cursor at the start of the current line.&lt;/li&gt;
&lt;li&gt;Pressing [$]: Places the cursor at the end of the current line.&lt;/li&gt;
&lt;li&gt;Pressing [u]: Undo's the last change that was done to the "buffer".&lt;/li&gt;
&lt;li&gt;Pressing [x]: Deletes one character (where the cursor is).&lt;/li&gt;
&lt;li&gt;Pressing [dd]: Deletes the current line (but it gets saved in the "paste buffer", which means the contents can be "pasted".&lt;/li&gt;
&lt;li&gt;Pressing [p]: Pastes whatever is copied (in the "paste buffer")&lt;/li&gt;
&lt;li&gt;Pressing [gg]: Places the cursor at the first line in the file.&lt;/li&gt;
&lt;li&gt;Pressing [G]: Places the cursor at the last line in the file&lt;/li&gt;
&lt;/ul&gt;

&lt;h6&gt;
  
  
  &lt;strong&gt;INSERT MODE&lt;/strong&gt;: This mode is activated by pressing [i]. It is used to insert new data to the document. Here are some examples of shortcuts:
&lt;/h6&gt;

&lt;ul&gt;
&lt;li&gt;Pressing [a + Shift]: Places the cursor at the end of the current line and activates INSERT MODE.&lt;/li&gt;
&lt;li&gt;Pressing [i]: Activates INSERT MODE.&lt;/li&gt;
&lt;/ul&gt;

&lt;h6&gt;
  
  
  &lt;strong&gt;VISUAL MODE&lt;/strong&gt;: This mode is useful to select specific subtext and apply modifications on it. It is activated by pressing [v]. Here are a few examples of shortcuts:
&lt;/h6&gt;

&lt;ul&gt;
&lt;li&gt;Pressing [y]: The selected section of text will be copied (not cut) and get placed in the "paste buffer" (to be pasted somewhere)&lt;/li&gt;
&lt;li&gt;Pressing [:] then Typing [sort ui]: This will sort the selected lines alphabetically and ensure there are no duplicate lines.&lt;/li&gt;
&lt;/ul&gt;

&lt;h6&gt;
  
  
  &lt;strong&gt;COMMAND MODE&lt;/strong&gt;: Accessed by pressing [:]. Used for entering commands such as saving files, quitting Vim, and searching.
&lt;/h6&gt;

&lt;p&gt;examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[:! &amp;lt;LINUX_COMMAND&amp;gt;] - Execute a command while in vim&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  File Operations
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;[:q] - Close the current window/buffer.&lt;/li&gt;
&lt;li&gt;[:w] - Write changes to the current file.&lt;/li&gt;
&lt;li&gt;[:q!] - Close the current window/buffer and discard of the changes.&lt;/li&gt;
&lt;li&gt;[:wq] - Write changes to the current file and close the window.&lt;/li&gt;
&lt;li&gt;[:r &amp;lt;file_name&amp;gt;] - Copy the buffer of "file_name" and paste it in the current buffer.&lt;/li&gt;
&lt;li&gt;[:w &amp;lt;file_name&amp;gt;] - Copy and Write the current buffer to "file_name"&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  String Search
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;[:%s/&amp;lt;regExpr&amp;gt;] - Search and highlight the first occurence of a string/pattern.&lt;/li&gt;
&lt;li&gt;[:%s/&amp;lt;regExpr&amp;gt;/String2/g] - Search and replace ALL the occurences of a string/pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Buffers
&lt;/h2&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%2Fwsd0ed3fyu3a7gucgh3p.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%2Fwsd0ed3fyu3a7gucgh3p.png" alt=" " width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Buffers can be extremely useful when you want to edit multiple files at the same time. Using COMMAND MODE, here are some useful tricks:&lt;/p&gt;

&lt;p&gt;[:ls] - Lists all the buffers currently accessible. (the one active has a %a sign)&lt;br&gt;
[:e &amp;lt;file_name&amp;gt;] - Load a file into a new buffer.&lt;br&gt;
[:b &amp;lt;buffer_number&amp;gt;] - To switch to a buffer&lt;br&gt;
[:enew] - To create an empty buffer (whose content that you can later on save to a file or to another buffer)&lt;br&gt;
[:bn] - Switches to the next buffer in the list.&lt;br&gt;
[:bp] - Switches to the previous buffer in the list.&lt;br&gt;
[:bw &amp;lt;buffer_number&amp;gt;] - Saves changes to the buffer X.&lt;br&gt;
[:bd &amp;lt;buffer_name&amp;gt;] - Deletes the buffer X.&lt;br&gt;
[:bd! &amp;lt;buffer_name&amp;gt;] - Deletes the buffer X discarding of any changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Splitting the screen
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Horizentally
&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%2Fu59kzof9pz88n3s73ai0.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%2Fu59kzof9pz88n3s73ai0.png" alt=" " width="728" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[:sp[lit] &amp;lt;file_name&amp;gt;] - Splits the current file with "file_name" horizentally, This step can be done multiple times with multiple files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vertically
&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%2F0p6jwngle74urz2midpi.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%2F0p6jwngle74urz2midpi.png" alt=" " width="728" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[:vsp[lit] &amp;lt;file_name&amp;gt;] - Splits the current file with "file_name" horizentally, This step can be done multiple times with multiple files.&lt;br&gt;
[Ctrl + ww] - To switch between "splits".&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages of a Terminal-based Text editor
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Vim is very light resources-wise, which makes it ideal to run on low-end machines.&lt;/li&gt;
&lt;li&gt;It is terminal-based which means it can be executed and used remotely without any trouble using something like SSH.&lt;/li&gt;
&lt;li&gt;The learning curve to master Vim is a bit steep but everyone can master the basics quite easily after a bit of practice.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>vim</category>
      <category>terminal</category>
    </item>
    <item>
      <title>Diffie-Hellman Key Exchange (DHKE) Algorithm</title>
      <dc:creator>Youssef El Idrissi</dc:creator>
      <pubDate>Sat, 31 Aug 2024 17:12:48 +0000</pubDate>
      <link>https://forem.com/techlabma/diffie-hellman-key-exchange-dhke-algorithm-505b</link>
      <guid>https://forem.com/techlabma/diffie-hellman-key-exchange-dhke-algorithm-505b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction &amp;amp; History
&lt;/h2&gt;

&lt;p&gt;The Diffie-Hellman Key Exchange algorithm is a fascinating method that allows two parties to securely share a secret key over an insecure communication channel (for example: over the internet). Introduced by &lt;u&gt;Whitfield Diffie&lt;/u&gt; and &lt;u&gt;Martin Hellman&lt;/u&gt; in 1976 and it marked a significant advancement in the field of cryptography because, prior to its development, securely exchanging keys was a major challenge, particularly in the realm of &lt;strong&gt;symmetric encryption&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the "DHKE" Algorithm?
&lt;/h2&gt;

&lt;p&gt;The Diffie-Hellman Key Exchange algorithm is &lt;strong&gt;a type of public key cryptography&lt;/strong&gt; that enables two parties, who may have never communicated before and are connected &lt;strong&gt;over an unsecured network&lt;/strong&gt;, to establish a shared secret. This shared secret can then be used to encrypt subsequent communications using &lt;strong&gt;symmetric encryption algorithms&lt;/strong&gt; (such as AES-256).&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase I: Initialization
&lt;/h2&gt;

&lt;p&gt;Two parties, typically called Alice and Bob, agree on a common set of public parameters:&lt;br&gt;
&lt;strong&gt;- 𝑝:&lt;/strong&gt; A large prime number, which will be used as the "modulus".&lt;br&gt;
&lt;strong&gt;- g:&lt;/strong&gt; a primitive root (also known as the generator) of 𝑝, which is a number that, when raised to various powers, generates all the numbers from 1 to 𝑝−1 under modulo 𝑝.&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%2Fvet7ysnjbhfy99zbwxak.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%2Fvet7ysnjbhfy99zbwxak.png" alt=" " width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase II: Key Exchange
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Private Key Selection:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Alice&lt;/strong&gt; selects a &lt;strong&gt;private key X&lt;/strong&gt;, which is a random integer that she keeps secret.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bob&lt;/strong&gt; selects a &lt;strong&gt;private key Y&lt;/strong&gt;, which is also a random integer that he keeps secret.&lt;/li&gt;
&lt;/ul&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%2Fpuwvfqyb3j2cs3klyvwj.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%2Fpuwvfqyb3j2cs3klyvwj.png" alt=" " width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Public Key Computation and Exchange:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Both &lt;strong&gt;Alice&lt;/strong&gt; and &lt;strong&gt;Bob&lt;/strong&gt; calculate their public keys respectively using the equations in the graph shown below.&lt;/li&gt;
&lt;/ul&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%2Frxk8l2dwpyq9q63ljohh.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%2Frxk8l2dwpyq9q63ljohh.png" alt=" " width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then &lt;strong&gt;Alice&lt;/strong&gt; and &lt;strong&gt;Bob&lt;/strong&gt; exchange their public keys (&lt;strong&gt;A&lt;/strong&gt; and &lt;strong&gt;B&lt;/strong&gt; over the insecure channel)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Phase III: Shared Secret Computation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Shared Secret Derivation:
&lt;/h3&gt;

&lt;p&gt;The Last step is to derive the &lt;strong&gt;Shared Secret&lt;/strong&gt; using the equations below&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%2F5rlubldzjvtg7dio03co.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%2F5rlubldzjvtg7dio03co.png" alt=" " width="800" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both calculations result in the same shared secret &lt;strong&gt;K&lt;/strong&gt;, which can now be used as a key for &lt;strong&gt;symmetric encryption&lt;/strong&gt; to securely communicate.&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%2Fage7qz1vdlr5r6yf8vzt.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%2Fage7qz1vdlr5r6yf8vzt.png" alt=" " width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Disadvantages...
&lt;/h2&gt;

&lt;p&gt;Diffie-Hellman is a great algorithm but when used alone there are vulnerabilities such as, &lt;strong&gt;Man-in-The-Middle attack (MiTM)&lt;/strong&gt;.&lt;br&gt;
It goes like the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the exact moment that "Alice" and "Bob" have generated their Public Keys (A and B) and when one of them tries to share their public key with the other over an insecure network, an Attacker ("Aku" for example) intercepts that public key, only to replace it with his own calculated Public key.&lt;/li&gt;
&lt;li&gt;The process then happens the same way for both parties (Bob and Alice).&lt;/li&gt;
&lt;li&gt;Aku Sends his Public Key C to Bob and receives Bob's public key B.&lt;/li&gt;
&lt;li&gt;Aku Sends his Public Key C to Alice and receives Alice's public key A.&lt;/li&gt;
&lt;/ul&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%2F3gok1ihzwkmobn7ysxm6.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%2F3gok1ihzwkmobn7ysxm6.png" alt=" " width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shared Secret Derivation gets calculated by Bob, Alice, and as for Aku, he does that calculation 2 times (one for Aku-Bob shared secret, and another for Aku-Alice shared secret)&lt;/li&gt;
&lt;/ul&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%2Fw2k6voouklsn6u7l2qjb.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%2Fw2k6voouklsn6u7l2qjb.png" alt=" " width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the end, Aku ends up seeing what both Alice and Bob send each other over the network.&lt;/li&gt;
&lt;/ul&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%2Fnoq2i5mncyvyfs35vyr1.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%2Fnoq2i5mncyvyfs35vyr1.png" alt=" " width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Digital Certificates help against this type of Attack because it confirms that "Bob" is Bob and that "Alice" is Alice.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cybersecurity</category>
      <category>learning</category>
      <category>security</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>The SSH Protocol</title>
      <dc:creator>Youssef El Idrissi</dc:creator>
      <pubDate>Mon, 05 Aug 2024 03:40:00 +0000</pubDate>
      <link>https://forem.com/0xw3ston/the-ssh-protocol-1k1e</link>
      <guid>https://forem.com/0xw3ston/the-ssh-protocol-1k1e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;(This Blog post is part of a collaborative work between &lt;strong&gt;Me&lt;/strong&gt; and &lt;strong&gt;Mustapha El Idrissi&lt;/strong&gt;, Consult his devTo page for more information: &lt;a href="https://dev.to/appsbymuss"&gt;https://dev.to/appsbymuss&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is SSH
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Secure Shell&lt;/strong&gt; (&lt;strong&gt;SSH&lt;/strong&gt;) is a cryptographic network protocol used for secure data communication, remote shell services, and command execution between two networked computers. Developed as a replacement for older, less secure protocols like Telnet and rlogin, SSH provides a robust layer of security by encrypting the connection and ensuring data integrity.&lt;/p&gt;

&lt;p&gt;SSH is widely used in various domains, including system administration, software development, and network engineering. It enables administrators to manage servers, configure devices, and transfer files securely over an insecure network. The protocol is also instrumental in automating scripts and processes, making it a critical tool in modern IT environments.&lt;/p&gt;

&lt;p&gt;One of the most significant advantages of SSH is its ability to facilitate secure remote access. By using SSH, users can log into remote machines, execute commands, and manage systems as if they were physically present, all while maintaining a high level of security. This feature is particularly valuable in today's distributed work environments, where remote access to servers and devices is a necessity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up an OpenSSH server
&lt;/h2&gt;

&lt;p&gt;An OpenSSH server is setup in a way that a machine can be accessed using the SSH protocol.&lt;br&gt;
It can be setup on any &lt;strong&gt;Windows, Macintosh or Linux&lt;/strong&gt; machine.&lt;br&gt;
To set it up on a Linux machine of the &lt;strong&gt;Ubuntu distro&lt;/strong&gt;, we must install the necessary packages. &lt;/p&gt;

&lt;p&gt;1- Update Package List&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="nb"&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2- Install OpenSSH&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="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;openssh-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3- Adjust firewall rules (Optional, but &lt;strong&gt;&lt;u&gt;Highly encouraged&lt;/u&gt;&lt;/strong&gt; due to security concerns)&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;# This allows incoming traffic on OpenSSH (by default it's port 22)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow ssh
&lt;span class="c"&gt;# If the port is changed (not 22), Do this instead:&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow &amp;lt;custom_port_for_openssh&amp;gt;

&lt;span class="c"&gt;# This enables the Host-Firewall if it isn't enabled yet.&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4- Turning ON the Service&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;# For systemctl machines:&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start ssh
&lt;span class="c"&gt;# otherwise&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;service ssh start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Server-Side Configuration
&lt;/h2&gt;

&lt;p&gt;On Debian-based machines, the configuration file can be found in: &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# by default
&lt;/span&gt;&lt;span class="err"&gt;Port&lt;/span&gt; &lt;span class="err"&gt;22&lt;/span&gt;
&lt;span class="err"&gt;MaxAuthTries&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;
&lt;span class="err"&gt;MaxSessions&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;
&lt;span class="err"&gt;PasswordAuthentication&lt;/span&gt; &lt;span class="err"&gt;yes&lt;/span&gt;
&lt;span class="err"&gt;PubkeyAuthentication&lt;/span&gt; &lt;span class="err"&gt;no&lt;/span&gt;

&lt;span class="err"&gt;Banner&lt;/span&gt; &lt;span class="err"&gt;none&lt;/span&gt;
&lt;span class="err"&gt;X11Forwarding&lt;/span&gt; &lt;span class="err"&gt;no&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Port&lt;/strong&gt;: We can choose a port (as long as it isn't being used by another service) from &lt;u&gt;1 to 65535&lt;/u&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MaxAuthTries&lt;/strong&gt;: is an important parameter for controlling how many times a client can attempt to authenticate before being disconnected. Setting it to a reasonable value helps improve the security of your SSH server by reducing the risk of unauthorized access through brute-force attacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MaxSessions&lt;/strong&gt;: this is a SSH server parameter that limits the number of simultaneous sessions a single SSH connection can establish.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fvg36j65yfwdp1p6itxr6.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%2Fvg36j65yfwdp1p6itxr6.png" alt=" " width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PasswordAuthentication&lt;/strong&gt;: choose if a user can or can not authenticate to the server with a password.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PubkeyAuthentication&lt;/strong&gt;: choose if a user can or can not authenticate to the server with a Private key (which is from a previously generated Public/Private key value pair).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Banner&lt;/strong&gt;: This parameter isn't really of any security meaning, but rather one could customize their server's welcoming Banner.&lt;br&gt;
If set, it should point to the file that should be echo'ed, otherwise leave it as "none"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;X11Forwarding&lt;/strong&gt;: This allows users to have the GUI apps on the remote server virtually executed on the actual Host machine using something called the  &lt;strong&gt;"X Window System"&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AllowTcpForwarding&lt;/strong&gt;: This setting allows &lt;strong&gt;TCP forwarding&lt;/strong&gt;, which means that users can create SSH tunnels to forward arbitrary TCP connections over the SSH connection. This is used for port forwarding, which includes both local and remote forwarding.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-&amp;gt; Example: You have mysql-server installed on the remote server, but you didn't expose the port of that mysql server outside of that machine (one can't connect to it with a GUI tool remotely with a Client tool like "MySQL Workbench"), and instead of making the port of that DB service exposed, we just want to use the mysql-workbench gui app on the remote machine itself, and have that graphical interface "forwarded" to us to see and manipulate. X Window comes in handy here.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;at the end, we need to restart the openssh server:&lt;br&gt;
&lt;code&gt;sudo service ssh restart&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  SSH Key Management (PubkeyAuthentication)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When it comes to Authentication in SSH, there's multiple ways, such as &lt;strong&gt;Password&lt;/strong&gt;, &lt;strong&gt;Public Key&lt;/strong&gt; and &lt;strong&gt;PAM&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;When it comes to "PubkeyAuthentication" (which is the more secure option than Password), we are talking about Asymmetric Encryption, Public and Private key pairs.&lt;/li&gt;
&lt;li&gt;In order to securely authenticate as a user to an SSH server, asymmetric encryption is used.&lt;/li&gt;
&lt;li&gt;To utilize this method of Authentication, the user should add this modification to the SSH server's config file:
&lt;code&gt;PubkeyAuthentication yes&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&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%2Fsg19m08vigyp1qebrlzo.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%2Fsg19m08vigyp1qebrlzo.png" alt=" " width="644" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user has to generate a key pair, and then they have to append the contents of the "public key" to the end of the server's "authorized_keys" file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Client Setup
&lt;/h3&gt;

&lt;p&gt;1- Generate Key Pair&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa/ecdsa/ed25519... &lt;span class="nt"&gt;-b&lt;/span&gt; 2048 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"email@gmail.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-t:&lt;/strong&gt; This parameter specifies which asymmetric encryption algorithm to use, there are multiple such as rsa, ecdsa ect... &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-b:&lt;/strong&gt; This parameter specifies the number of bits of the key (the correct values depend on which algorithm is choosen, &lt;strong&gt;ex:&lt;/strong&gt; rsa accepts "2048" or "4096".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-c (optional):&lt;/strong&gt; you can associate a custom description with your key, &lt;strong&gt;ex:&lt;/strong&gt; Your email.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2- Once it is generated, by default the private and public keys are both gonna be in under the &lt;strong&gt;"USERNAME/.ssh"&lt;/strong&gt; folder, That means:&lt;br&gt;
    - C:/Users/&lt;strong&gt;USERNAME&lt;/strong&gt;/&lt;em&gt;.ssh&lt;/em&gt; &lt;strong&gt;(on Windows)&lt;/strong&gt;&lt;br&gt;
    - /home/&lt;strong&gt;USERNAME&lt;/strong&gt;/&lt;em&gt;.ssh&lt;/em&gt; &lt;strong&gt;(on Linux)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Public key is the one with the extension "&lt;strong&gt;.pub&lt;/strong&gt;" and the Private one is the one without any extension. &lt;strong&gt;ex:&lt;/strong&gt; &lt;em&gt;id_rsa&lt;/em&gt; and &lt;em&gt;id_rsa.pub&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3- Once generated, we need to declare it to the SSH server, in a way that we add Our Public key to the SSH Server's "whitelist" (aka the authorized_keys file).&lt;/p&gt;

&lt;p&gt;The process is fairly simple, we have to copy the content of the Public key, and add it to the SSH Server's "authorized_keys" file.&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%2Fy232662mi1kyu7kfyv6b.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%2Fy232662mi1kyu7kfyv6b.png" alt=" " width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since we have Linux as our SSH Server, there's already a command that could faciltate this process:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-copy-id &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/mykey.pub user@remote_host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-i&lt;/strong&gt;: specifies the path to &lt;strong&gt;the public key&lt;/strong&gt; that has to be allowed by the SSH Server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4- We can then easily connect to our SSH Server with our private key like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/myprivatekey user@remote_host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-i&lt;/strong&gt;: specifies the path to &lt;strong&gt;the private key&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;5 (optional)- We can create a file that remembers the key path with its correspondant username and remoteHost ect with &lt;strong&gt;config&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This "config"-named file has to be created in the ".ssh" folder that we previously discussed.&lt;/li&gt;
&lt;li&gt;The contents are like so:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="err"&gt;Host&lt;/span&gt; &lt;span class="err"&gt;customHost1&lt;/span&gt;
  &lt;span class="err"&gt;User&lt;/span&gt; &lt;span class="err"&gt;ubuntu&lt;/span&gt;
  &lt;span class="err"&gt;HostName&lt;/span&gt; &lt;span class="err"&gt;test.host.com&lt;/span&gt;
  &lt;span class="err"&gt;Port&lt;/span&gt; &lt;span class="err"&gt;22&lt;/span&gt;

&lt;span class="err"&gt;Host&lt;/span&gt; &lt;span class="err"&gt;customHost2&lt;/span&gt;
  &lt;span class="err"&gt;User&lt;/span&gt; &lt;span class="err"&gt;ubuntu&lt;/span&gt;
  &lt;span class="err"&gt;HostName&lt;/span&gt; &lt;span class="err"&gt;test2.host.com&lt;/span&gt;
  &lt;span class="err"&gt;IdentityFile&lt;/span&gt; &lt;span class="err"&gt;PATH/TO/id_rsa&lt;/span&gt;
  &lt;span class="err"&gt;IdentitiesOnly&lt;/span&gt; &lt;span class="err"&gt;yes&lt;/span&gt;

&lt;span class="err"&gt;Host&lt;/span&gt; &lt;span class="err"&gt;customHost3&lt;/span&gt;
  &lt;span class="err"&gt;User&lt;/span&gt; &lt;span class="err"&gt;root&lt;/span&gt;
  &lt;span class="err"&gt;HostName&lt;/span&gt; &lt;span class="err"&gt;server.mydomain.tech&lt;/span&gt;
  &lt;span class="err"&gt;IdentityFile&lt;/span&gt; &lt;span class="err"&gt;PATH/TO/id_rsa&lt;/span&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Host&lt;/strong&gt;: This defines the "profile" or "alias" to connect to a specific server with a specific Hostname ect..&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User&lt;/strong&gt;: Specify the username&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HostName&lt;/strong&gt;: Specify the hostname (or host ip)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port&lt;/strong&gt;: Specify the port (if not specified, PORT 22 is assumed)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IdentityFile&lt;/strong&gt;: Set the Path of where the Private Key is. (If the server uses PubKeyAuthentication)&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LocalForward&lt;/strong&gt;: The LocalForward parameter sets up a local port on your machine to forward to a port on a remote machine. This is known as "port forwarding" or "tunneling" and is often used to access services running on a remote machine as if they were running locally.&lt;br&gt;(syntax: &lt;strong&gt;&lt;code&gt;LocalForward &amp;lt;local_port&amp;gt; &amp;lt;remote_host&amp;gt;:&amp;lt;remote_port&amp;gt;&lt;/code&gt;&lt;/strong&gt;)&lt;br&gt;
&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RemoteForward&lt;/strong&gt;: The RemoteForward parameter works similarly to LocalForward, but in the opposite direction. It forwards a port on the remote machine to a port on your local machine. This can be useful for making services on your local machine accessible to the remote machine. &lt;br&gt;(syntax: &lt;strong&gt;&lt;code&gt;RemoteForward &amp;lt;remote_port&amp;gt; &amp;lt;local_host&amp;gt;:&amp;lt;local_port&amp;gt;&lt;/code&gt;&lt;/strong&gt;)&lt;br&gt;
&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DynamicForward&lt;/strong&gt;: The DynamicForward parameter sets up a local port to act as a SOCKS proxy. When you connect to this port, SSH will dynamically forward the traffic to the appropriate remote host and port, based on the connections made by the SOCKS proxy. This is useful for creating a secure tunnel for a variety of protocols and services.&lt;br&gt;(syntax: &lt;strong&gt;&lt;code&gt;DynamicForward &amp;lt;local_port&amp;gt;&lt;/code&gt;&lt;/strong&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;After Doing all of this, We can simply connect using the set "Host" alias we setup like so:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;ssh acreaweb1&lt;/code&gt;&lt;/p&gt;

</description>
      <category>ssh</category>
    </item>
    <item>
      <title>Front-End &amp; Back-End (CSR)</title>
      <dc:creator>Youssef El Idrissi</dc:creator>
      <pubDate>Fri, 02 Aug 2024 02:37:01 +0000</pubDate>
      <link>https://forem.com/0xw3ston/front-end-back-end-csr-2lj2</link>
      <guid>https://forem.com/0xw3ston/front-end-back-end-csr-2lj2</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
Once when I started Programming, I started with simple PHP and then gradually switched to &lt;strong&gt;laravel&lt;/strong&gt;, but I always had this misconception about websites, I thought the backend and frontend have to always be on one server that handles everything (like in the case of Server-Side Rendering frameworks), but after a while I discovered that there's something called "React" which is a re-usable library that is javascript-based and only then did I realize that yes, front end and back end could actually be on seperate servers or shall we say "nodes".&lt;br&gt;
And it did make a lot of sense because it seems to me that it would be a little complicated to maintain a website/system that has tons of features on both the front end and back end respectively.&lt;/p&gt;

&lt;p&gt;-We will be discussing Client-Side Rendering (CSR) for the most part in this blog.&lt;/p&gt;

&lt;p&gt;-we will not focus that much on deployment so there would be no discussion of specific cloud service providers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we consider as "front end"?&lt;/strong&gt;&lt;br&gt;
in the context of CSR, there's multiple frameworks in different programming languages,&lt;br&gt;
the most popular in my experience are React, Angular and Vue.&lt;br&gt;
there's multiple purposes these frameworks serve, but mainly those frameworks (when hosted on a "node") are responsible for human interaction with the website (referring to User Interface and User Experience UX/UI) to make it look as smooth as possible for the user.&lt;br&gt;
behind the scenes each interaction from the user with the UI means a certain action should be done (usually by the backend) or some content should be shown (usually a fetch from the backend to get specific data)&lt;br&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%2Fe7l157q5aqz8jfg38pwt.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%2Fe7l157q5aqz8jfg38pwt.png" alt="Front-End Requests" width="259" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we consider as "back end"?&lt;/strong&gt;&lt;br&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%2F5y4jvlb20flrk4uvau5v.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%2F5y4jvlb20flrk4uvau5v.png" alt="Back-end accepting Requests" width="561" height="81"&gt;&lt;/a&gt;&lt;br&gt;
what we can consider a backend is usually a codebase that processes requests coming from a front end node for further processing (fetching, execute a certain method etc...)&lt;br&gt;
There are multiple frameworks and languages that actually work well with CSR-based apps since they act just as an API for the front-end to consume:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for PHP there's Laravel (although PHP has some limits when it comes to processing due to its blocking nature but if the scale of the app is small to medium it's mostly fine to work with)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ExpressJS&lt;/strong&gt; is minimalistic so you'd have to add the libraries you want to work with by your own using NPM, it's good for beginners because one will have to be creative to organize their own folder structure, their &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NestJS&lt;/strong&gt; comes with some features out-of-the-box and also has great support for the Micro-services architecture, however it does use Typescript heavily so that should be considered when choosing the right framework to use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Big Picture&lt;/strong&gt;&lt;br&gt;
Now that we understand what we can consider as back-end and front-end, the most crucial and important part is actually making the front end able to communicate with the back-end and vice versa.&lt;br&gt;
There are many communication styles to achieve that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST API is one of them, it relies on the HTTP Protocol to provide a Request/Response style and it is also the most common.&lt;/li&gt;
&lt;li&gt;GraphQL is a another way to "query" data from the back-end in a more precise way, therefor getting rid of the extra data that might be fetched and immediately discarded in a typical REST API Request.
(An example would be fetching an array of users, each user object having: "id", "full name", "age", "username", "password", "email". And then use for example only the "username" and "password" keys, and as in GraphQL we can specifically "query" that we only need the username's and password's)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Besides that, we need a way to keep track of our users, especially if they're "logged In" or not.&lt;/p&gt;

&lt;p&gt;API Keys come to the rescue and act like an access card to a guarded building (the back-end), usually on each connection from the user on the Front End, an API Call gets to the Back End (the very first request is usually a login HTTP Request containing the username and password) then the back-end processes that request and if everything went well, the back-end issues a unique API Key for the Front End to store for any more additional requests.&lt;/p&gt;

&lt;p&gt;In Most Frameworks that handles the UI, there's always a notion of a "local storage". in Android it's "Shared Preferences", in Desktop it could be an encrypted file storing sensitive data and so on.&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%2F8jatyywwuk9ecdjerdyj.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%2F8jatyywwuk9ecdjerdyj.png" alt="Full Stack setup" width="711" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;in this context of ours it's the same thing, we store the API Key(s) in the available local data store (or any key/value local data store) implementation that is available to us, in React it's "local storage".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Key Types&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There many type of API keys with specific roles , advantages and inconvenient, in this article I Will focus much on JsonWebTokens (JWT) and Classic generate-on-demand keys.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Classic API Keys&lt;/strong&gt;: usually a hash generated by the back-end taking into consideration identifiants of the specific user that is logging-in, after that it's stored in the database (a relational one most of the time), and on each request (other than login), the key will be searched for in our database, if it's found then the request is valid, if not (or somehow "expired") then we should return a specific HTTP Code to announce that.&lt;/li&gt;
&lt;/ul&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%2F5nud2a28mhwmyp3if7c8.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%2F5nud2a28mhwmyp3if7c8.png" alt="Classic API" width="361" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JWT Token&lt;/strong&gt;: the same thing, a hash generated by the back-end, however it's not necessarily stored in the database, why? because the back-end can verify if the token is legit and "not expired" without even interacting with the database, because it's more of an algorithm computation than a mere SQL statement, on the back-end when we generate a JWT Token, it wraps auth information (such as username, password) and an expiration date (it could be minutes, hours , days ect..).
On receiving the Key on the back-end to do some specific task, the back-end runs a "verify_if_token_is_legit" method which as mentioned before, is just cryptography math and after that the back-end can even access the auth information that was wrapped in there before at the time of the creation of that key.&lt;/li&gt;
&lt;/ul&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%2Fcwc412c35x1lz9dok8n3.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%2Fcwc412c35x1lz9dok8n3.png" alt="JWT API" width="512" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
