<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mac OS &#8211; Digitaldocblog</title>
	<atom:link href="https://digitaldocblog.com/category/mac/feed/" rel="self" type="application/rss+xml" />
	<link>https://digitaldocblog.com</link>
	<description>Various digital documentation</description>
	<lastBuildDate>Thu, 01 Jan 2026 08:03:47 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>

<image>
	<url>https://digitaldocblog.com/wp-content/uploads/2022/08/cropped-website-icon-star-500-x-452-transparent-32x32.png</url>
	<title>Mac OS &#8211; Digitaldocblog</title>
	<link>https://digitaldocblog.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Manage GnuPG securely</title>
		<link>https://digitaldocblog.com/mac/manage-gnupg-securely/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 27 Dec 2025 05:09:59 +0000</pubDate>
				<category><![CDATA[Mac OS]]></category>
		<category><![CDATA[Security]]></category>
		<guid isPermaLink="false">https://digitaldocblog.com/?p=256</guid>

					<description><![CDATA[This article is about GnuPG setup from scratch and show how to manage the entire lifecycle securely. Here is a comprehensive overview of all the steps and commands, including the&#8230;]]></description>
										<content:encoded><![CDATA[
<p>This article is about GnuPG setup from scratch and show how to manage the entire lifecycle securely. Here is a comprehensive overview of all the steps and commands, including the security best practices.</p>




<h3 class="wp-block-heading">Chapter 1: Initial Setup and Key Creation</h3>



<p>This stage establishes your key pair and trust level.</p>




<p><strong>Create Master Key Pair incl. encryption subkey</strong></p>




<pre class="wp-block-code"><code>gpg --full-gen-key
</code></pre>



<p>On the following dialog you use ECC algorithms (ed25519 for signing, cv25519 for encryption) and chose option (9) ECC (sign, encryption) <em>standard</em>. You set an expiration date (e.g., 5 years) for forward compatibility. Finally you choose a strong, unique passphrase!	</p>




<p><strong>Create signing Subkey</strong></p>




<p>Do not use the Master Key for signing in your daily work. Create an additional separate subkey for signing (S).</p>




<pre class="wp-block-code"><code>gpg --edit-key &lt;KEY-ID&gt;

gpg\&gt; addkey
</code></pre>



<p>You type <em>addkey</em> and then option (10) ECC (only sign). </p>




<p>Then you check the generated Master Key including the subkeys</p>




<pre class="wp-block-code"><code>gpg --list-secret-keys

sec   ed25519 2025-12-25 [SC] [verfällt: 2030-12-24]
	C957EA3BD909D1D3BA594D2CE14085D8197A0018
uid        [ ultimativ ] Patrick Rottlaender [patrick@rottlaender.eu](mailto:patrick@rottlaender.eu)
ssb   cv25519 2025-12-25 [E] [verfällt: 2030-12-24]
ssb   ed25519 2025-12-25 [S] [verfällt: 2030-12-24]
</code></pre>



<p>sec: The secret master key (sec) is for Signing and Certification (SC). </p>




<p>KEY-ID: C957EA3BD909D1D3BA594D2CE14085D8197A0018.</p>




<p>ssb: The first subkey (ssb) is for encryption (E). </p>




<p>ssb: The second subkey (ssb) is for signing (S). </p>




<p>All Keys expire at 2030-12-24. </p>




<p><strong>Set Trust Level</strong></p>




<p>As you can see above my trust level is already ultimate. So here just for completion the command how to set the trust level on your keys. </p>




<p>Mark your own key as ultimately trusted so GnuPG relies on your certifications (key separation, subkey creation).	</p>




<pre class="wp-block-code"><code>gpg --edit-key &lt;KEY-ID&gt;

gpg\&gt; trust
</code></pre>



<p>Then type trust and select option 5 (ultimate).</p>




<h3 class="wp-block-heading">Chapter 2: Security and Hardening</h3>



<p>This stage prepares the necessary backups and secures the master key.</p>




<p><strong>Backup the Master Key and generate Revocation Certificate</strong></p>




<p>Do this immediately and store the fullback-up file and the revocation certificate file offline.</p>




<pre class="wp-block-code"><code>gpg --export-secret-keys --armor &lt;KEY-ID&gt; &gt; fullbackup.asc	

gpg --output revocation.asc --gen-revoke &lt;KEY-ID&gt;
</code></pre>



<p><strong>Implement Key Separation</strong></p>




<p>Check the key setup again to identify clearly your 3 Key-IDs. Here we use the long format command.</p>




<pre class="wp-block-code"><code>gpg --list-secret-keys --keyid-format long

sec   ed25519/E14085D8197A0018 2025-12-25 \[SC] \[verfällt: 2030-12-24]
	  C957EA3BD909D1D3BA594D2CE14085D8197A0018
uid              [ ultimativ ] Patrick Rottlaender [patrick@rottlaender.eu](mailto:patrick@rottlaender.eu)

ssb   cv25519/AF0CB4F423538B80 2025-12-25 [E] [verfällt: 2030-12-24]

ssb   ed25519/56025D0BF8BF5B2F 2025-12-25 [S] [verfällt: 2030-12-24]
</code></pre>



<p>Master Key-ID (SC): E14085D8197A0018</p>




<p>Subkey 1-Key-ID (E): AF0CB4F423538B80</p>




<p>Subkey 2-Key-ID (S): 56025D0BF8BF5B2F</p>




<p>The goal is: Remove the Master Secret Key (sec) from your local machine using the delete command, turning it into a stub (sec#). This protects the core of your identity from malware. Keep both Subkeys for daily encryption (E) and signing (S).</p>




<p>Before you run the delete command, you must be 100% certain your backup file is valid. If you delete the master key now without a verified backup, you are back to the fatal &#8222;lost key&#8220; situation. Run the following 2 checks.</p>




<p><strong>Check 1:</strong></p>




<pre class="wp-block-code"><code>gpg --list-packets /path/to/fullbackup.asc | grep "secret key packet"

:secret key packet:
</code></pre>



<p>The output must! show:</p>




<pre class="wp-block-code"><code>:secret key packet:
</code></pre>



<p><strong>Check 2:</strong></p>




<pre class="wp-block-code"><code>gpg --list-packets /path/to/fullbackup.asc

off=0 ctb=94 tag=5 hlen=2 plen=134
:secret key packet:
	version 4, algo 22, created 1766645842, expires 0
	pkey[0]: [80 bits] ed25519 (1.3.6.1.4.1.11591.15.1)
	pkey[1]: [263 bits]
	iter+salt S2K, algo: 7, SHA1 protection, hash: 2, salt: E5DD0BCA22F746A5
	protect count: 65011712 (255)
	protect IV:  d6 b2 c9 5d e2 3f 05 d3 35 fb cc 7b 87 41 cf f5
	skey[2]: [v4 protected]
	keyid: E14085D8197A0018
# off=136 ctb=b4 tag=13 hlen=2 plen=44
:user ID packet: "Patrick Rottlaender [patrick@rottlaender.eu](mailto:patrick@rottlaender.eu)"
# off=182 ctb=88 tag=2 hlen=2 plen=153
:signature packet: algo 22, keyid E14085D8197A0018
	version 4, created 1766645842, md5len 0, sigclass 0x13
	digest algo 10, begin of digest f0 54
	hashed subpkt 33 len 21 (issuer fpr v4 C957EA3BD909D1D3BA594D2CE14085D8197A0018)
	hashed subpkt 2 len 4 (sig created 2025-12-25)
	hashed subpkt 27 len 1 (key flags: 03)
	hashed subpkt 9 len 4 (key expires after 5y0d0h0m)
	hashed subpkt 11 len 4 (pref-sym-algos: 9 8 7 2)
	hashed subpkt 34 len 1 (pref-aead-algos: 2)
	hashed subpkt 21 len 5 (pref-hash-algos: 10 9 8 11 2)
	hashed subpkt 22 len 3 (pref-zip-algos: 2 3 1)
	hashed subpkt 30 len 1 (features: 07)
	hashed subpkt 23 len 1 (keyserver preferences: 80)
	subpkt 16 len 8 (issuer key ID E14085D8197A0018)
	data: [256 bits]
	data: [255 bits]
# off=337 ctb=9c tag=7 hlen=2 plen=139
:secret sub key packet:
	version 4, algo 18, created 1766645842, expires 0
	pkey[0]: [88 bits] cv25519 (1.3.6.1.4.1.3029.1.5.1)
	pkey[1]: [263 bits]
	pkey[2]: [32 bits]
	iter+salt S2K, algo: 7, SHA1 protection, hash: 2, salt: 2DE27015BEF91567
	protect count: 65011712 (255)
	protect IV:  f8 13 05 2b 8d a0 97 0d 22 99 3b b5 c3 62 43 be
	skey[3]: [v4 protected]
	keyid: AF0CB4F423538B80
# off=478 ctb=88 tag=2 hlen=2 plen=126
:signature packet: algo 22, keyid E14085D8197A0018
	version 4, created 1766645842, md5len 0, sigclass 0x18
	digest algo 10, begin of digest fc 2e
	hashed subpkt 33 len 21 (issuer fpr v4 C957EA3BD909D1D3BA594D2CE14085D8197A0018)
	hashed subpkt 2 len 4 (sig created 2025-12-25)
	hashed subpkt 27 len 1 (key flags: 0C)
	hashed subpkt 9 len 4 (key expires after 5y0d0h0m)
	subpkt 16 len 8 (issuer key ID E14085D8197A0018)
	data: [254 bits]
	data: [256 bits]
# off=606 ctb=9c tag=7 hlen=2 plen=134
:secret sub key packet:
	version 4, algo 22, created 1766645997, expires 0
	pkey[0]: [80 bits] ed25519 (1.3.6.1.4.1.11591.15.1)
	pkey[1]: [263 bits]
	iter+salt S2K, algo: 7, SHA1 protection, hash: 2, salt: 09FD8782B037DC77
	protect count: 65011712 (255)
	protect IV:  e3 fc 51 3f 7d 35 f8 78 a9 43 72 fe 73 f9 82 16
	skey[2]: [v4 protected]
	keyid: 56025D0BF8BF5B2F
# off=742 ctb=88 tag=2 hlen=2 plen=245
:signature packet: algo 22, keyid E14085D8197A0018
	version 4, created 1766645997, md5len 0, sigclass 0x18
	digest algo 10, begin of digest fe 58
	hashed subpkt 33 len 21 (issuer fpr v4 C957EA3BD909D1D3BA594D2CE14085D8197A0018)
	hashed subpkt 2 len 4 (sig created 2025-12-25)
	hashed subpkt 27 len 1 (key flags: 02)
	hashed subpkt 9 len 4 (key expires after 5y0d0h0m)
	subpkt 16 len 8 (issuer key ID E14085D8197A0018)
	subpkt 32 len 117 (signature: v4, class 0x19, algo 22, digest algo 10)
	data: [256 bits]
	data: [256 bits]
</code></pre>



<p>This is the expected output: You expect 3 packets most important is the <em>:secret key packet:</em></p>




<p><strong>Master Key package:</strong></p>




<p>:secret key packet: secret master key packet with KeyID: E14085D8197A0018</p>




<p>:signature packet: This show the signature packet belonging to your secret key packet and issuer key ID E14085D8197A0018</p>




<p><strong>Subkey 1 Key package:</strong></p>




<p>:secret sub key packet: secret subkey packet with KeyID: AF0CB4F423538B80</p>




<p>:signature packet: This show the signature packet belonging to your secret sub key packet and issuer key ID E14085D8197A0018</p>




<p><strong>Subkey 2 Key package:</strong></p>




<p>:secret sub key packet: secret subkey packet with keyid: 56025D0BF8BF5B2F</p>




<p>:signature packet: This show the signature packet belonging to your secret sub key packet and issuer key ID E14085D8197A0018</p>




<p>Only in case :secret key packet: is available proceed!</p>




<p>GnuPG does not have a single command like <em>—delete-only-master key</em>. Instead, the standard &#8222;clean&#8220; way to do this is a three-step process.</p>




<p><strong>Step 1:</strong> Export ONLY your Secret Subkeys in a temporary subkeys-only file</p>




<pre class="wp-block-code"><code>gpg --export-secret-subkeys --armor E14085D8197A0018 &gt; subkeys-only.asc
</code></pre>



<p><strong>Step 2:</strong> Delete the current Secret Key (complete wipe) from your MacBook</p>




<pre class="wp-block-code"><code>gpg --delete-secret-keys E14085D8197A0018
</code></pre>



<p><strong>Step 3:</strong> Import the Secret Subkeys</p>




<pre class="wp-block-code"><code>gpg --import subkeys-only.asc
</code></pre>



<p><strong>Step 4:</strong> Remove the temporary subkeys-only file</p>




<pre class="wp-block-code"><code>rm subkeys-only.asc
</code></pre>



<p>Then check your local setup.</p>




<pre class="wp-block-code"><code>gpg --list-secret-keys

sec#  ed25519 2025-12-25 [SC] [verfällt: 2030-12-24]
      C957EA3BD909D1D3BA594D2CE14085D8197A0018
uid        [ ultimativ ] Patrick Rottlaender &lt;patrick@rottlaender.eu&gt;
ssb   cv25519 2025-12-25 [E] [verfällt: 2030-12-24]
ssb   ed25519 2025-12-25 [S] [verfällt: 2030-12-24]
</code></pre>



<p>Here you see your Master Secret Key (sec) has been removed from your local machine and turning it into a stub (sec#).</p>




<h3 class="wp-block-heading">Chapter 3: Reset and Restore (Scenario: Start From Scratch)</h3>



<p>These steps show how to completely wipe your local key and restore it using the backup.</p>




<p><strong>Delete Complete Key Set (Local Wipe)</strong></p>




<p>Use both commands to ensure both the remaining subkeys and the Public Key are completely removed from your local keyring before restoring.	</p>




<pre class="wp-block-code"><code>gpg --delete-secret-keys &lt;KEY-ID&gt; (Deletes subkeys/stubs)
gpg --delete-keys &lt;KEY-ID&gt; (Deletes public key)
</code></pre>



<p><strong>Import Complete Key Set (Restore)</strong></p>




<p>Use the verified backup file created in Step 2 to fully restore your Master Key and Subkeys back to the pre-separation state. </p>




<p>First you check the fullback file before you run the import.</p>




<pre class="wp-block-code"><code>#Check the backupfile
gpg --show-keys /path/to/fullbackup.asc

sec   ed25519 2025-12-25 [SC] [verfällt: 2030-12-24]
	  C957EA3BD909D1D3BA594D2CE14085D8197A0018
uid        [ ultimativ ] Patrick Rottlaender [patrick@rottlaender.eu](mailto:patrick@rottlaender.eu)
ssb   cv25519 2025-12-25 [E] [verfällt: 2030-12-24]
ssb   ed25519 2025-12-25 [S] [verfällt: 2030-12-24]

#run the import
gpg --import /path/to/fullbackup.asc
</code></pre>



<h3 class="wp-block-heading">Chapter 4: Useful commands</h3>



<p>List public keys</p>




<pre class="wp-block-code"><code>gpg –list-keys

pub   ed25519 2025-12-25 [SC] [verfällt: 2030-12-24]
	  C957EA3BD909D1D3BA594D2CE14085D8197A0018
uid        [ ultimativ ] Patrick Rottlaender [patrick@rottlaender.eu](mailto:patrick@rottlaender.eu)
sub   cv25519 2025-12-25 [E] [verfällt: 2030-12-24]
sub   ed25519 2025-12-25 [S] [verfällt: 2030-12-24]
</code></pre>



<p>List secret keys</p>




<pre class="wp-block-code"><code>gpg –list-secret-keys

sec   ed25519 2025-12-25 [SC] [verfällt: 2030-12-24]
	  C957EA3BD909D1D3BA594D2CE14085D8197A0018
uid        [ ultimativ ] Patrick Rottlaender [patrick@rottlaender.eu](mailto:patrick@rottlaender.eu)
ssb   cv25519 2025-12-25 [E] [verfällt: 2030-12-24]
ssb   ed25519 2025-12-25 [S] [verfällt: 2030-12-24]
</code></pre>



<p>List public keys showing all KeyIDs</p>




<pre class="wp-block-code"><code>gpg --list-keys --keyid-format long

pub   ed25519/E14085D8197A0018 2025-12-25 [SC] [verfällt: 2030-12-24]
	  C957EA3BD909D1D3BA594D2CE14085D8197A0018
uid              [ ultimativ ] Patrick Rottlaender [patrick@rottlaender.eu](mailto:patrick@rottlaender.eu)
sub   cv25519/AF0CB4F423538B80 2025-12-25 [E] [verfällt: 2030-12-24]
sub   ed25519/56025D0BF8BF5B2F 2025-12-25 [S] [verfällt: 2030-12-24]
</code></pre>



<p>List secret keys showing all KeyIDs</p>




<pre class="wp-block-code"><code>gpg --list-secret-keys --keyid-format long

sec   ed25519/E14085D8197A0018 2025-12-25 [SC] [verfällt: 2030-12-24]
	  C957EA3BD909D1D3BA594D2CE14085D8197A0018
uid              [ ultimativ ] Patrick Rottlaender [patrick@rottlaender.eu](mailto:patrick@rottlaender.eu)
ssb   cv25519/AF0CB4F423538B80 2025-12-25 [E] [verfällt: 2030-12-24]
ssb   ed25519/56025D0BF8BF5B2F 2025-12-25 [S] [verfällt: 2030-12-24]
</code></pre>



<p>Master Key (SC): E14085D8197A0018</p>




<p>Subkey 1 (E): AF0CB4F423538B80</p>




<p>Subkey 2 (S): 56025D0BF8BF5B2F</p>




<p>Encrypt</p>




<pre class="wp-block-code"><code>gpg -e -r patrick@rottlaender.eu file.txt
</code></pre>



<p>Decrypt</p>




<pre class="wp-block-code"><code>gpg -d file.txt.gpg &gt; file.txt
</code></pre>



<p>Sign &amp; Encrypt</p>




<pre class="wp-block-code"><code>gpg -se -r recipient@email.com file.txt
</code></pre>



<p>Decrypt &amp; Verify</p>




<pre class="wp-block-code"><code>#shows the signature status automatically
gpg -d file.txt.gpg
</code></pre>



<h3 class="wp-block-heading">Chapter 5: General note</h3>



<p>ed25519 and cv25519 are algorithms based on Curve25519</p>




<p>ed25519 (Master Key &amp; Signing Subkey)</p>




<p>Feature	Description</p>




<p>Full Name: Edwards-curve Digital Signature Algorithm over Curve25519.</p>




<p>Cryptographic Role: Digital Signing and Verification. It is designed to create a mathematical signature that proves the origin (authenticity) and integrity of a message or file.</p>




<p>GnuPG Use: Used for your Master Key ([C]) to certify other keys, and your Signing Subkey ([S]) to sign emails or commits.</p>




<p>Security Property: It is highly resistant to various side-channel attacks and has a very reliable, straightforward implementation.</p>




<p>cv25519 (Encryption Subkey)</p>




<p>Feature	Description</p>




<p>Full Name: Curve25519 variant used for Key Exchange.</p>




<p>Cryptographic Role: Key Exchange and Encryption. It is designed for the Diffie-Hellman (DH) key exchange process, which allows two parties to securely establish a shared secret (like a session key) over an insecure channel.</p>




<p>GnuPG Use: Used for your Encryption Subkey ([E]). It enables others to encrypt data to you, and you to decrypt it using the established session key.</p>




<p>Security Property: Highly efficient and designed specifically for confidential (private) communication.</p>




<p>Modern GnuPG key management strictly separates cryptographic roles signing and encryption for security reasons:</p>




<pre class="wp-block-code"><code>• You sign with ed25519: To prove you are the one you are (in my case I am Patrick!).
• You encrypt with cv25519: To ensure privacy.
</code></pre>



<p>This separation of duties means if one subkey were ever theoretically broken, it wouldn&#8217;t automatically compromise the function of the other key. For example, if your signing key (ed25519) was compromised, your ability to decrypt past files or conversations (protected by cv25519) would remain secure.</p>




]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Create a virtual Hacking Lab on Apple Silicon Mac</title>
		<link>https://digitaldocblog.com/mac/create-a-virtual-hacking-lab-on-apple-silicon-mac/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 12 Apr 2023 05:36:31 +0000</pubDate>
				<category><![CDATA[Mac OS]]></category>
		<category><![CDATA[Homebrew]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://digitaldocblog.com/?p=214</guid>

					<description><![CDATA[When you are a cyber security consultant, a pen tester or even a system operator with technical interest then you want to perform attacks on systems to understand exactly how&#8230;]]></description>
										<content:encoded><![CDATA[
<p>When you are a cyber security consultant, a pen tester or even a system operator with technical interest then you want to perform attacks on systems to understand exactly how hackers work in real life and which vulnerabilities are exploited in order to take control of the system. If you know how hackers attack your system, you can protect it better. </p>



<p>Under no circumstances should you start attacks on systems located on the internet, even if the systems belong to you, because from a legal point of view it is always a risk and you can get into trouble. You should build a game environment in your local network in which you install attacker and victim system. It is important that you only use private IP addresses and that the game environment does not route any data traffic to and from the Internet. This gaming environment is then your <strong>Hacking Lab</strong> in which you can try out different attack scenarios safely and securely.</p>



<p>The idea is to install a virtualization software on the operating system of the host computer which is in my case an M2 Apple Mac with Ventura 13.3. The virtualization software I use is <a href="https://mac.getutm.app" title="UTM for Mac">UTM</a>. UTM create the virtual guest machines in a virtual Lan (Vlan) isolated from the host operating system and the local network. The virtual guest machines can talk to each other but can not access the local network or the internet via the host. The host can talk to the virtual guest machines. This network mode is defined as <strong>host only</strong> mode.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img fetchpriority="high" decoding="async" width="3950" height="1141" src="https://digitaldocblog.com/wp-content/uploads/2023/04/01-network.png" alt="Network setup for the Hacking Lab" class="wp-image-211" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/01-network.png 3950w, https://digitaldocblog.com/wp-content/uploads/2023/04/01-network-300x87.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/01-network-1024x296.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/01-network-768x222.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/01-network-1536x444.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/01-network-2048x592.png 2048w" sizes="(max-width: 3950px) 100vw, 3950px" /><figcaption class="wp-element-caption">Network setup for the Hacking Lab</figcaption></figure>
</div>


<p><em>Note: UTM provide various network operating modes. Details can be read in the <a href="https://docs.getutm.app/settings-qemu/devices/network/network/" title="UTM network modes">UTM documentation</a>.</em></p>



<p>The installation of UTM can be done in two ways:</p>



<ol class="wp-block-list">
<li>Payed version in the Apple <a href="https://apps.apple.com/de/app/utm-virtual-machines/id1538878817?mt=12" title="UTM in the App Store">App Store</a></li>



<li>Free download from the <a href="https://mac.getutm.app" title="Download UTM">UTM site</a></li>
</ol>



<p>I recommend to install the payed version from the App Store. You will get all updates whenever there are updates available and you support the development of this fantastic tool. At the time of writing this article the costs for the payed version of UTM were 11.99 Euro.</p>



<p>Once UTM has been installed we need to create the attacker and the victim as virtual guest machines in UTM. The attacker is a <a href="https://www.kali.org/get-kali/#kali-installer-images" title="Get Kali Linux Images">Kali Linux Image</a> the victim will be a host prepared with vulnarabilities from <a href="https://www.vulnhub.com" title="Vulnerable Hub. Hosts to be attacked">vulnerable hub</a>. </p>



<p>On vulnerable hub you find vulnerable virtual machines. These machines are prepared from cyber security enthusiasts for other security enthusiasts. These machines are available with vulnerabilities and created specifically for the purpose of hacking them. </p>



<h3 class="wp-block-heading">Create a vulnerable virtual machine in UTM</h3>



<p>To create a victim in UTM you search for a machine which best suits your needs and download the virtual machine from vulnerable hub which is available there in the <a href="https://docs.fileformat.com/disc-and-media/ova/" title="OVA File format explained">.ova format</a>. OVA is basically a tar based archive that contains among other things, an <a href="https://docs.fileformat.com/disc-and-media/ovf/" title=".ovf File format">.ovf file</a> with the specification of the virtual machine and in most cases disk image files in the format .vdi and .vmdk. Other files contained in the .ova file we don&#8217;t consider.</p>



<p>On vulnerable hub we <a href="https://www.vulnhub.com/?q=Robot" title="search for Robot">search for Robot</a> and find 3 search results. We look for <a href="https://www.vulnhub.com/entry/mr-robot-1,151/" title="Mr-Robot: 1 vulnerable machine">Mr-Robot: 1</a>, click on it and find the download link to download the .ova file for the vulnerable virtual machine.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img decoding="async" width="2208" height="1436" src="https://digitaldocblog.com/wp-content/uploads/2023/04/02-Vulnerable-Hub-Search-Robot-1.jpeg" alt="Find Mr-Robot: 1 an volnerable hub" class="wp-image-201" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/02-Vulnerable-Hub-Search-Robot-1.jpeg 2208w, https://digitaldocblog.com/wp-content/uploads/2023/04/02-Vulnerable-Hub-Search-Robot-1-300x195.jpeg 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/02-Vulnerable-Hub-Search-Robot-1-1024x666.jpeg 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/02-Vulnerable-Hub-Search-Robot-1-768x499.jpeg 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/02-Vulnerable-Hub-Search-Robot-1-1536x999.jpeg 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/02-Vulnerable-Hub-Search-Robot-1-2048x1332.jpeg 2048w" sizes="(max-width: 2208px) 100vw, 2208px" /><figcaption class="wp-element-caption">Find Mr-Robot: 1 an volnerable hub</figcaption></figure>
</div>


<p>   To install Mr-Robot: 1 as virtual machine in UTM we first must unpack the .ova file. </p>



<pre class="wp-block-code"><code>patrick % ls
total 2884016
mrRobot.ova

patrick % tar -xvf mrRobot.ova 
x mrRobot.ovf
x mrRobot.mf
x mrRobot-disk1.vmdk

patrick % ls
total 2884016
mrRobot-disk1.vmdk mrRobot.mf mrRobot.ova mrRobot.ovf

</code></pre>



<p>Then we convert the disk image file mrRobot-disk1.vmdk into the .qcow2 format which is the supported format by UTM. If you need some more detailed information there is a very good explanation on <a href="https://www.xmodulo.com/convert-ova-to-qcow2-linux.html" title="How to convert ova to qcow2">Xmodulo</a>. </p>



<p>To convert the disk image from into .qcow2 we need the utility qemu-img. I install the complete <a href="https://formulae.brew.sh/formula/qemu#default" title="Qemu Emulator on homebrew">qemu emulator</a> from <a href="https://formulae.brew.sh" title="Homebrew">homebrew</a> as the qemu utilities are not available as single option. If you don&#8217;t know homebrew or in case homebrew is not installed on your Mac just go to my blog site <a href="https://digitaldocblog.com" title="Digitaldocblog">digitaldocblog</a> and read <a href="https://digitaldocblog.com/mac/how-to-setup-homebrew-on-mac-os/" title="How to setup homebrew on a Mac">the article</a> how to intstall and use homebrew on your Mac.</p>



<pre class="wp-block-code"><code>patrick %  brew install qemu

patrick % ls
total 2884016
mrRobot-disk1.vmdk mrRobot.mf mrRobot.ova mrRobot.ovf

patrick % qemu-img convert -O \
qcow2 mrRobot-disk1.vmdk mrRobot.qcow2

patrick % ls
total 2884016
mrRobot-disk1.vmdk mrRobot.mf mrRobot.ova mrRobot.ovf
mrRobot.qcow2

</code></pre>



<p>Then you start UTM from the main menue and click create new virtual machine. </p>


<div class="wp-block-image">
<figure class="aligncenter"><img decoding="async" width="2208" height="1436" src="https://digitaldocblog.com/wp-content/uploads/2023/04/03-UTM-Create-Virt-Machine.jpeg" alt="UTM main menue" class="wp-image-209" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/03-UTM-Create-Virt-Machine.jpeg 2208w, https://digitaldocblog.com/wp-content/uploads/2023/04/03-UTM-Create-Virt-Machine-300x195.jpeg 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/03-UTM-Create-Virt-Machine-1024x666.jpeg 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/03-UTM-Create-Virt-Machine-768x499.jpeg 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/03-UTM-Create-Virt-Machine-1536x999.jpeg 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/03-UTM-Create-Virt-Machine-2048x1332.jpeg 2048w" sizes="(max-width: 2208px) 100vw, 2208px" /><figcaption class="wp-element-caption">UTM main menue</figcaption></figure>
</div>


<p>Then you click on <strong>Emulate</strong>. You click on Emulate because the virtual machine you are going to install is compiled for the x86 64 Intel CPU Architechture. This Intel CPU must be emulated by UTM to provide the basis that your host can run as guest on your Apple ARM Silicon Mac (M1 and M2). In the next chapter when we install the attacker Linux we choose a virtual machine that is compiled for the Apple ARM 64 Silicon architechture. Then we click Virtualize because this guest machine is compiled for your host architecture (M1 or M2).</p>



<p>After Emulate you click on <strong>Custom</strong>. Then you <strong>skip ISO boot</strong>, accept in the following all default values ​​and assign a name fitting your needs for your new virtual host. At the end, the configuration is completed with safe.</p>



<p>In the left panel you see the virtual machine you just created. Mark it and click on the <strong>settings menue</strong> at the top right side.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2208" height="1436" src="https://digitaldocblog.com/wp-content/uploads/2023/04/04-UTM-virtual-machine-settings-2.png" alt="Virtual Machine Settings" class="wp-image-199" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/04-UTM-virtual-machine-settings-2.png 2208w, https://digitaldocblog.com/wp-content/uploads/2023/04/04-UTM-virtual-machine-settings-2-300x195.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/04-UTM-virtual-machine-settings-2-1024x666.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/04-UTM-virtual-machine-settings-2-768x499.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/04-UTM-virtual-machine-settings-2-1536x999.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/04-UTM-virtual-machine-settings-2-2048x1332.png 2048w" sizes="auto, (max-width: 2208px) 100vw, 2208px" /><figcaption class="wp-element-caption">Virtual Machine Settings</figcaption></figure>
</div>


<p>In the left panel of the settings go to the <strong>Drives section</strong> and delete the IDE drive. Stay in the Drives section and create a new drive. Here you click on Import and select the .qcow2 file on your hard disk (the one you created as you converted the .vmdk file). After this step go to the <strong>QEMU section</strong> where you unselect UEFI Boot. To set the correct network settings go to <strong>Network section</strong> and select Host only. Finally you click on safe and end the configuration.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2208" height="1436" src="https://digitaldocblog.com/wp-content/uploads/2023/04/07-UTM-network-1.png" alt="Virtual machine network settings" class="wp-image-203" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/07-UTM-network-1.png 2208w, https://digitaldocblog.com/wp-content/uploads/2023/04/07-UTM-network-1-300x195.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/07-UTM-network-1-1024x666.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/07-UTM-network-1-768x499.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/07-UTM-network-1-1536x999.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/07-UTM-network-1-2048x1332.png 2048w" sizes="auto, (max-width: 2208px) 100vw, 2208px" /><figcaption class="wp-element-caption">Virtual machine network settings</figcaption></figure>
</div>


<h3 class="wp-block-heading">Create the attacker virtual machine in UTM</h3>



<p>To launch attacks against a vulnerable virtual host I recommend installing a standard Kali Linux machine in UTM. Most tools are already pre-installed here and you can start immediately. </p>



<p>We go on the Kali.org website an there into the section <a href="https://www.kali.org/get-kali/" title="Get Kali on Kali.org">get Kali</a>. I choose installer images and then we select the ARM Silicon (ARM64) for download the Kali especially compiled for our Apple ARM Silicon M2 architecture (if you have a M1 this is also working fine). Click on the recommended installer and download the iso image to your hard drive.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2208" height="1436" src="https://digitaldocblog.com/wp-content/uploads/2023/04/08-Kali-Installer-Image-1.png" alt="Kali Linux Installer for ARM64" class="wp-image-204" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/08-Kali-Installer-Image-1.png 2208w, https://digitaldocblog.com/wp-content/uploads/2023/04/08-Kali-Installer-Image-1-300x195.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/08-Kali-Installer-Image-1-1024x666.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/08-Kali-Installer-Image-1-768x499.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/08-Kali-Installer-Image-1-1536x999.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/08-Kali-Installer-Image-1-2048x1332.png 2048w" sizes="auto, (max-width: 2208px) 100vw, 2208px" /><figcaption class="wp-element-caption">Kali Linux Installer for ARM64</figcaption></figure>
</div>


<p>After you have downloaded the iso image the installation will be performed in 2 steps. First you create a new virtual machine in virtualization mode and then in step 2 you install the Kali Linux on it.</p>



<p>Click on the + sign in the top menue and then select Virtualize.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2208" height="1436" src="https://digitaldocblog.com/wp-content/uploads/2023/04/09-Install-Virtual-Machine-Virtualization-Mode-1.png" alt="Install virtual machine in virtualization mode" class="wp-image-206" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/09-Install-Virtual-Machine-Virtualization-Mode-1.png 2208w, https://digitaldocblog.com/wp-content/uploads/2023/04/09-Install-Virtual-Machine-Virtualization-Mode-1-300x195.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/09-Install-Virtual-Machine-Virtualization-Mode-1-1024x666.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/09-Install-Virtual-Machine-Virtualization-Mode-1-768x499.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/09-Install-Virtual-Machine-Virtualization-Mode-1-1536x999.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/09-Install-Virtual-Machine-Virtualization-Mode-1-2048x1332.png 2048w" sizes="auto, (max-width: 2208px) 100vw, 2208px" /><figcaption class="wp-element-caption">Install virtual machine in virtualization mode</figcaption></figure>
</div>


<p>After that you can select the OS you want to install. Here you click on Linux and  here you select the iso image you downloaded from Kali in the Boot-Iso-Image section.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2208" height="1436" src="https://digitaldocblog.com/wp-content/uploads/2023/04/10-Select-ISO-Image-5.png" alt="Select the iso image in the Boot-Iso-Image section" class="wp-image-196" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/10-Select-ISO-Image-5.png 2208w, https://digitaldocblog.com/wp-content/uploads/2023/04/10-Select-ISO-Image-5-300x195.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/10-Select-ISO-Image-5-1024x666.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/10-Select-ISO-Image-5-768x499.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/10-Select-ISO-Image-5-1536x999.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/10-Select-ISO-Image-5-2048x1332.png 2048w" sizes="auto, (max-width: 2208px) 100vw, 2208px" /><figcaption class="wp-element-caption">Select the iso image in the Boot-Iso-Image section</figcaption></figure>
</div>


<p>Then you click continue and keep the default value for the RAM but set the CPU cores to 4.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2208" height="1436" src="https://digitaldocblog.com/wp-content/uploads/2023/04/11-CPU-Cores-To-4-3.png" alt="Set CPU Cores to 4" class="wp-image-198" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/11-CPU-Cores-To-4-3.png 2208w, https://digitaldocblog.com/wp-content/uploads/2023/04/11-CPU-Cores-To-4-3-300x195.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/11-CPU-Cores-To-4-3-1024x666.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/11-CPU-Cores-To-4-3-768x499.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/11-CPU-Cores-To-4-3-1536x999.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/11-CPU-Cores-To-4-3-2048x1332.png 2048w" sizes="auto, (max-width: 2208px) 100vw, 2208px" /><figcaption class="wp-element-caption">Set CPU Cores to 4</figcaption></figure>
</div>


<p>In the following you can keep all default values i.e. for storage and always click on continue until you come to the Summary section. Here you can give you new virtual machine a name according to your needs. Finally you click on safe.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2208" height="1436" src="https://digitaldocblog.com/wp-content/uploads/2023/04/12-Summary-Virtual-Host-1.png" alt="Give your virtual machine a name" class="wp-image-208" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/12-Summary-Virtual-Host-1.png 2208w, https://digitaldocblog.com/wp-content/uploads/2023/04/12-Summary-Virtual-Host-1-300x195.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/12-Summary-Virtual-Host-1-1024x666.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/12-Summary-Virtual-Host-1-768x499.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/12-Summary-Virtual-Host-1-1536x999.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/12-Summary-Virtual-Host-1-2048x1332.png 2048w" sizes="auto, (max-width: 2208px) 100vw, 2208px" /><figcaption class="wp-element-caption">Give your virtual machine a name</figcaption></figure>
</div>


<p>Then click on the settings to open the settings menue. Go to the Devices section and click on new and add a new serial device emulation. This is very important for the installation of Kali Linux on your virtual machine otherwise the installer will not start. </p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2208" height="1436" src="https://digitaldocblog.com/wp-content/uploads/2023/04/13-New-Serial-Device-Emulation-5.png" alt="New Serial Device Emulation" class="wp-image-197" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/13-New-Serial-Device-Emulation-5.png 2208w, https://digitaldocblog.com/wp-content/uploads/2023/04/13-New-Serial-Device-Emulation-5-300x195.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/13-New-Serial-Device-Emulation-5-1024x666.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/13-New-Serial-Device-Emulation-5-768x499.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/13-New-Serial-Device-Emulation-5-1536x999.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/13-New-Serial-Device-Emulation-5-2048x1332.png 2048w" sizes="auto, (max-width: 2208px) 100vw, 2208px" /><figcaption class="wp-element-caption">New Serial Device Emulation</figcaption></figure>
</div>


<p> Run the virtual machine to start the installation. Here you see that 2 windows will be opened. Choose the window that says terminal one and start the installation. Don’t choose Graphical installation. Then follow the installation steps. You can see a very good <a href="https://www.youtube.com/watch?v=9zdjQ9w_v_4" title="How To Install Kali Linux 2022 On M1 / M2 Mac Using UTM">video on YouTube</a> that guide you through the standard installation.</p>



<p>Once you see the finish installation screen then use the navigation bar of this window terminal 1 and shut down the virtual machine. Close the second window that has been opened when you started with the installation.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1288" height="924" src="https://digitaldocblog.com/wp-content/uploads/2023/04/14-Installation-Completed-1.png" alt="Installation Completed. Shut down." class="wp-image-205" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/14-Installation-Completed-1.png 1288w, https://digitaldocblog.com/wp-content/uploads/2023/04/14-Installation-Completed-1-300x215.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/14-Installation-Completed-1-1024x735.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/14-Installation-Completed-1-768x551.png 768w" sizes="auto, (max-width: 1288px) 100vw, 1288px" /><figcaption class="wp-element-caption">Installation Completed. Shut down.</figcaption></figure>
</div>


<p>Then you go to the main window, select the virtual machine you just installed, go to the main window and unmount the iso at the bottom of the page.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2006" height="1480" src="https://digitaldocblog.com/wp-content/uploads/2023/04/15-Unmount-iso-1.png" alt="Unmount the iso" class="wp-image-200" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/15-Unmount-iso-1.png 2006w, https://digitaldocblog.com/wp-content/uploads/2023/04/15-Unmount-iso-1-300x221.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/15-Unmount-iso-1-1024x755.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/15-Unmount-iso-1-768x567.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/15-Unmount-iso-1-1536x1133.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/15-Unmount-iso-1-120x90.png 120w" sizes="auto, (max-width: 2006px) 100vw, 2006px" /><figcaption class="wp-element-caption">Unmount the iso</figcaption></figure>
</div>


<p>Open the settings and go to the device sections and remove the serial device you created before. To set the correct network settings go to <strong>Network section</strong> and select Host only. Finally you click on safe and end the configuration.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2006" height="1440" src="https://digitaldocblog.com/wp-content/uploads/2023/04/16-remove-serial-device-1.png" alt="Remove serial device" class="wp-image-202" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/16-remove-serial-device-1.png 2006w, https://digitaldocblog.com/wp-content/uploads/2023/04/16-remove-serial-device-1-300x215.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/16-remove-serial-device-1-1024x735.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/16-remove-serial-device-1-768x551.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/16-remove-serial-device-1-1536x1103.png 1536w" sizes="auto, (max-width: 2006px) 100vw, 2006px" /><figcaption class="wp-element-caption">Remove serial device</figcaption></figure>
</div>


<h3 class="wp-block-heading">Check the network configuration</h3>



<p>Run both virtual machines in UTM, Robot1VulnerableHost and the Attacker machine KaliLinux. When you run Robot1VulnerableHost you see the logon screen after the machine has beefed. Of course you don’t have login credentials because you want to hack into it instead of logging in. This is different on your KaliLinux. Here you created an account during the installation. </p>



<p>Log into KaliLinux and open a Terminal. Check the ip address from KaliLinux. The ip address is <strong>192.168.128.5</strong>.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2558" height="1440" src="https://digitaldocblog.com/wp-content/uploads/2023/04/17-check-IP-Kali.png" alt="Check the IP Addess of KaliLinux" class="wp-image-210" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/17-check-IP-Kali.png 2558w, https://digitaldocblog.com/wp-content/uploads/2023/04/17-check-IP-Kali-300x169.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/17-check-IP-Kali-1024x576.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/17-check-IP-Kali-768x432.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/17-check-IP-Kali-1536x865.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/17-check-IP-Kali-2048x1153.png 2048w, https://digitaldocblog.com/wp-content/uploads/2023/04/17-check-IP-Kali-1140x641.png 1140w, https://digitaldocblog.com/wp-content/uploads/2023/04/17-check-IP-Kali-540x304.png 540w" sizes="auto, (max-width: 2558px) 100vw, 2558px" /><figcaption class="wp-element-caption">Check the IP Addess of KaliLinux</figcaption></figure>
</div>


<p>Then discover the network 192.168.128.0/24 to find other hosts in the same subnet. Type the following command.</p>



<pre class="wp-block-code"><code>
kaliLinux % netdiscover -r 192.168.128.0/24

</code></pre>



<p>You see 2 hosts in your subnet <strong>192.168.128.1</strong> which is the bridge between your local host network and your vlan and you see <strong>192.168.128.6</strong> which is Robot1VulnerableHost on the same subnet.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2558" height="1440" src="https://digitaldocblog.com/wp-content/uploads/2023/04/18-netdiscover-vlan.png" alt="Discover the virtual network" class="wp-image-212" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/18-netdiscover-vlan.png 2558w, https://digitaldocblog.com/wp-content/uploads/2023/04/18-netdiscover-vlan-300x169.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/18-netdiscover-vlan-1024x576.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/18-netdiscover-vlan-768x432.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/18-netdiscover-vlan-1536x865.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/18-netdiscover-vlan-2048x1153.png 2048w, https://digitaldocblog.com/wp-content/uploads/2023/04/18-netdiscover-vlan-1140x641.png 1140w, https://digitaldocblog.com/wp-content/uploads/2023/04/18-netdiscover-vlan-540x304.png 540w" sizes="auto, (max-width: 2558px) 100vw, 2558px" /><figcaption class="wp-element-caption">Discover the virtual network</figcaption></figure>
</div>


<p>You can ping Robot1VulnerableHost but you cannot ping the host computer which is my Mac on subnet 192.168.0.0/24 with the ip address 192.168.0.38. So the bridge does not route traffic from your vlan into the local network which is what we need. The guests can talk to each other but they can not talk to the outside world. </p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2558" height="1440" src="https://digitaldocblog.com/wp-content/uploads/2023/04/19-ping-1.png" alt="Guests can talk with each other but not with the host" class="wp-image-207" srcset="https://digitaldocblog.com/wp-content/uploads/2023/04/19-ping-1.png 2558w, https://digitaldocblog.com/wp-content/uploads/2023/04/19-ping-1-300x169.png 300w, https://digitaldocblog.com/wp-content/uploads/2023/04/19-ping-1-1024x576.png 1024w, https://digitaldocblog.com/wp-content/uploads/2023/04/19-ping-1-768x432.png 768w, https://digitaldocblog.com/wp-content/uploads/2023/04/19-ping-1-1536x865.png 1536w, https://digitaldocblog.com/wp-content/uploads/2023/04/19-ping-1-2048x1153.png 2048w, https://digitaldocblog.com/wp-content/uploads/2023/04/19-ping-1-1140x641.png 1140w, https://digitaldocblog.com/wp-content/uploads/2023/04/19-ping-1-540x304.png 540w" sizes="auto, (max-width: 2558px) 100vw, 2558px" /><figcaption class="wp-element-caption">Guests can talk with each other but not with the host</figcaption></figure>
</div>


<p>Then I ping the virtual guests from my Mac. Here you see the host can talk to them. So the network setup of the Hacking Lab is correct.  </p>



<pre class="wp-block-code"><code>patrick % ping 192.168.128.5
PING 192.168.128.5 (192.168.128.5): 56 data bytes
64 bytes from 192.168.128.5: icmp_seq=0 ttl=64 time=0.979 ms
64 bytes from 192.168.128.5: icmp_seq=1 ttl=64 time=0.568 ms
64 bytes from 192.168.128.5: icmp_seq=2 ttl=64 time=0.811 ms
64 bytes from 192.168.128.5: icmp_seq=3 ttl=64 time=0.718 ms
^C

patrick % ping 192.168.128.6
PING 192.168.128.6 (192.168.128.6): 56 data bytes
64 bytes from 192.168.128.6: icmp_seq=0 ttl=64 time=2.663 ms
64 bytes from 192.168.128.6: icmp_seq=1 ttl=64 time=2.298 ms
64 bytes from 192.168.128.6: icmp_seq=2 ttl=64 time=2.330 ms
64 bytes from 192.168.128.6: icmp_seq=3 ttl=64 time=2.310 ms
64 bytes from 192.168.128.6: icmp_seq=4 ttl=64 time=2.318 ms
^C

patrick %

</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Python on MacOS BigSur</title>
		<link>https://digitaldocblog.com/mac/python-on-macos-bigsur/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 20 Oct 2021 12:00:00 +0000</pubDate>
				<category><![CDATA[Mac OS]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://digitaldocblog.com/?p=144</guid>

					<description><![CDATA[MacOS comes with Python 2 pre-installed. Python 2 is required by the Operating System and managed by MacOS. This System Python should never be touched. System Python is installed in&#8230;]]></description>
										<content:encoded><![CDATA[
<p>MacOS comes with Python 2 pre-installed. Python 2 is required by the Operating System and managed by MacOS. This <em>System Python</em> should <strong>never be touched</strong>.   </p>



<p>System Python is installed in <em>/usr/bin</em> directory which is owned by <em>root</em>. This mean all files and symlinks in <em>/usr/bin</em> are system owned which means managed by the system and not managed by the user. In <em>/usr/bin</em> you find python symlinks pointing to the Python binaries in <em>/System/Library/Frameworks/Python.framework/Versions/2.7/bin</em> directory. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % ls -l /usr/bin/python* 

lrwxr-xr-x  1 root  wheel      75  1 Jan  2020 /usr/bin/python -&gt; ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7

lrwxr-xr-x  1 root  wheel      75  1 Jan  2020 /usr/bin/python2 -&gt; ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7

lrwxr-xr-x  1 root  wheel      75  1 Jan  2020 /usr/bin/python2.7 -&gt; ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7

....

patrick@PatrickMBNeu ~ %
</code></pre>



<p>The symlinks python, python2 and python2.7 in <em>/usr/bin</em> each point to the same binary in <em>/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7</em>. So when you type one of these as shell command in your shell terminal the binary in <em>/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7</em> will be executed.  </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % python --version
Python 2.7.16

patrick@PatrickMBNeu ~ % python2 --version
Python 2.7.16

patrick@PatrickMBNeu ~ % python2.7 --version
Python 2.7.16

patrick@PatrickMBNeu
</code></pre>



<p>Type in the command without using the path like <em>/usr/bin/python</em> works because <em>/usr/bin</em> is configured in the shell PATH variable. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

patrick@PatrickMBNeu ~ %  
</code></pre>



<p>The shell lookup for a command in the paths defined in the PATH variable and starts on the left side of the PATH. So python, python2 and python2.7 do not exist in <em>/usr/local/bin</em> but in <em>/usr/bin</em>. </p>



<p>When you came from Catalina and upgraded to BigSur you realized that System Python has not been upgraded from Python 2 to Python 3 for example. So obviously BigSur still relies on Python 2 which is ok for your Mac but maybe not for you as a Developer. You might need newer or different versions of Python on your system. You must install this them separately. </p>



<p>Many people use <em><a href="https://brew.sh/">Homebrew</a></em> to install software packages on their MacOS. Homebrew can also be used to install a Python version in addition to the System Python. You can check if Python is installed via Homebrew on your system using the command <em>brew info &lt;formula&gt;</em>. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % brew info python
python@3.9: stable 3.9.7 (bottled)
Interpreted, interactive, object-oriented programming language
https:&#47;&#47;www.python.org/
/usr/local/Cellar/python@3.9/3.9.7_1 (3,191 files, 56MB) *
  Poured from bottle on 2021-10-15 at 07:09:27
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/python@3.9.rb
License: Python-2.0
==&gt; Dependencies
Build: pkg-config &#x2714;
Required: gdbm &#x2714;, mpdecimal &#x2714;, openssl@1.1 &#x2714;, readline &#x2714;, sqlite &#x2714;, xz &#x2714;
==&gt; Caveats
Python has been installed as
  /usr/local/bin/python3

Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to
`python3`, `python3-config`, `pip3` etc., respectively, have been installed into
  /usr/local/opt/python@3.9/libexec/bin

You can install Python packages with
  pip3 install &lt;package&gt;
They will install into the site-package directory
  /usr/local/lib/python3.9/site-packages

tkinter is no longer included with this formula, but it is available separately:
  brew install python-tk@3.9

See: https://docs.brew.sh/Homebrew-and-Python
==&gt; Analytics
install: 717,857 (30 days), 1,988,212 (90 days), 8,421,529 (365 days)
install-on-request: 322,364 (30 days), 784,390 (90 days), 2,811,664 (365 days)
build-error: 0 (30 days)

patrick@PatrickMBNeu ~ %
</code></pre>



<p>Here on my system Python has been installed with Homebrew in the directory <em>/usr/local/bin</em> which is owned by the user. That means all files and symlinks in this directory can be managed by the user. In <em>/usr/local/bin</em> you find the python symlinks python3 and python3.9 pointing to further symlinks in the Homebrew Cellar in <em>/usr/local/Cellar</em>. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % ls -l /usr/local/bin/python*

lrwxr-xr-x  1 patrick  admin  40 15 Okt 07:09 /usr/local/bin/python3 -&gt; ../Cellar/python@3.9/3.9.7_1/bin/python3

lrwxr-xr-x  1 patrick  admin  42 15 Okt 07:09 /usr/local/bin/python3.9 -&gt; ../Cellar/python@3.9/3.9.7_1/bin/python3.9

...

patrick@PatrickMBNeu ~ %
</code></pre>



<p>The python3 symlink in the Homebrew Cellar point again to another python3 symlink in <em>/usr/local/Frameworks/Python.framework/Versions/3.9/bin</em> and this symlink point finally to python3.9 binary <em>/usr/local/Frameworks/Python.framework/Versions/3.9/bin</em>. The python3.9 symlink from the Homebrew Cellar point directly to the python3.9 binary in <em>/usr/local/Frameworks/Python.framework/Versions/3.9/bin</em>. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % ls -l /usr/local/Frameworks/Python.framework/Versions/3.9/bin
total 136

lrwxr-xr-x  1 patrick  admin      9 30 Aug 21:19 python3 -&gt; python3.9

-rwxr-xr-x  1 patrick  admin  50472 15 Okt 07:09 python3.9

...

patrick@PatrickMBNeu ~ % 
</code></pre>



<p>So If you enter python3 or python3.9 as a command in the terminal the shell lookup these symlinks in directory <em>/usr/local/bin</em> and find a match. In any case you always end up with the python3.9 binary in <em>/usr/local/Frameworks/Python.framework/Versions/3.9/bin</em> and execute the same binary.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % python3 --version
Python 3.9.7

patrick@PatrickMBNeu ~ % python3.9 --version
Python 3.9.7

patrick@PatrickMBNeu ~ %
</code></pre>



<p>It is not a problem to install other Python versions with Homebrew in addition to the System Python, but the Homebrew ecosystem has a special feature: dependencies. Python versions that are installed in the Homebrew perimeter can also represent a dependency on other applications. node, for example, needs Python 3.9. If we uninstall Python 3.9, we have a problem with node. Therefore, Python can never be seen completely isolated in the Homebrew ecosystem and this is exactly the problem we solve with <a href="https://github.com/pyenv/pyenv">pyenv</a>.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % brew info node   
                                                 
node: stable 16.11.1 (bottled), HEAD
Platform built on V8 to build network applications
https:&#47;&#47;nodejs.org/
/usr/local/Cellar/node/16.11.1 (1,980 files, 45.4MB) *
  Poured from bottle on 2021-10-15 at 07:09:45
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/node.rb
License: MIT
==&gt; Dependencies
Build: pkg-config &#x2714;
Required: brotli &#x2714;, c-ares &#x2714;, icu4c &#x2714;, libnghttp2 &#x2714;, libuv &#x2714;, openssl@1.1 &#x2714;, python@3.9 &#x2714;
==&gt; Options
--HEAD
	Install HEAD version
==&gt; Analytics
install: 501,912 (30 days), 1,345,537 (90 days), 4,731,822 (365 days)
install-on-request: 404,509 (30 days), 1,070,393 (90 days), 3,650,272 (365 days)
build-error: 0 (30 days)

patrick@PatrickMBNeu ~ %
</code></pre>



<p>pyenv create a complete isolated environment for your Python versions. You are able to install, use and uninstall Python versions and you can switch between them.  pyenv can be easily installed with Homebrew. pyenv is therefore installed in the <em>/usr/local/bin</em> directory.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % which pyenv
/usr/local/bin/pyenv

patrick@PatrickMBNeu ~ % pyenv --version
pyenv 2.1.0

patrick@PatrickMBNeu ~ % 
</code></pre>



<p>We must adapt the PATH variable for the standard shell. Here in my example this is configured in the .zshrc file in my Home-Directory. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % cat .zshrc

# ~/.pyenv provides Python before others of the same name
export PYENV_ROOT=$(pyenv root)
export PATH="$PYENV_ROOT/shims:$PATH"

patrick@PatrickMBNeu ~ %
</code></pre>



<p>You check the versions managed by pyenv with the following command. As you see pyenv realize the System Python. With the command <em>pyenv install 3.9.7</em> you install Python 3.9.7 in your pyenv environment. You can switch to your desired Python version using the command <em>pyenv global &lt;version&gt;</em> .</p>



<p>When you then run the command <em>python</em> you are directly connected to global python version you selected. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % pyenv versions 
*  system

patrick@PatrickMBNeu ~ % pyenv install 3.9.7

.....

patrick@PatrickMBNeu ~ % pyenv versions 
* system
  3.9.7 (set by /Users/patrick/.pyenv/version)

patrick@PatrickMBNeu ~ % pyenv global 3.9.7

patrick@PatrickMBNeu ~ % pyenv versions 
  system
* 3.9.7 (set by /Users/patrick/.pyenv/version)

patrick@PatrickMBNeu ~ % python
Python 3.9.7 (default, Oct 19 2021, 16:02:07) 
&#91;Clang 13.0.0 (clang-1300.0.29.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; exit()

patrick@PatrickMBNeu ~ % pyenv global system

patrick@PatrickMBNeu ~ % pyenv versions     
* system (set by /Users/patrick/.pyenv/version)
  3.9.7

patrick@PatrickMBNeu ~ % python             

WARNING: Python 2.7 is not recommended. 
This version is included in macOS for compatibility with legacy software. 
Future versions of macOS will not include Python 2.7. 
Instead, it is recommended that you transition to using 'python3' from within Terminal.

Python 2.7.16 (default, Aug 30 2021, 14:43:11) 
&#91;GCC Apple LLVM 12.0.5 (clang-1205.0.19.59.6) &#91;+internal-os, ptrauth-isa=deploy on darwin
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; exit()

patrick@PatrickMBNeu ~ %
</code></pre>



<p>Finally: To avoid a warning message from brew when you run <em>brew doctor</em> you must create a brew alias in your .zshrc file. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % cat .zshrc

alias brew='PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin brew'

# ~/.pyenv provides Python before others of the same name
export PYENV_ROOT=$(pyenv root)
export PATH="$PYENV_ROOT/shims:$PATH"

patrick@PatrickMBNeu ~ %
</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to add a Mac OS User to sudoers</title>
		<link>https://digitaldocblog.com/mac/how-to-add-a-mac-os-user-to-sudoers/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 16 Mar 2021 12:30:00 +0000</pubDate>
				<category><![CDATA[Mac OS]]></category>
		<guid isPermaLink="false">https://digitaldocblog.com/?p=133</guid>

					<description><![CDATA[When I set up my Mac I configured first the Admin-User and then I created a new Standard-User for the daily work. On my Mac I have the Admin-User AdminPR&#8230;]]></description>
										<content:encoded><![CDATA[
<p>When I set up my Mac I configured first the <strong>Admin-User</strong> and then I created a new <strong>Standard-User</strong> for the daily work. On my Mac I have the Admin-User <code>AdminPR</code> and the Standard-User <code>patrick</code>. When I am logged in with my Standard-User <code>patrick</code> I cannot perform commands as <code>root</code> at the Terminal app with sudo. </p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ sudo cat /private/etc/sudoers
Password:
patrick is not in the sudoers file.  This incident will be reported.
</code></pre>



<h2 class="wp-block-heading">Add a Standard User to sudoers</h2>



<p>To be able to run any command as root I must add the Standard-User to my <code>/private/etc/sudoers</code> file or I must put the Standard-User <code>patrick</code> into the <code>sudo</code> Group.</p>



<p>To get some information I list all Users on the system using the <code>dscl</code> command (Directory Service Command Line Tool). Here I find both of my created Users the Admin-User <code>AdminPR</code> and the Standard-User <code>patrick</code>. With the <code>id</code> command I can check the group memberships. The User <code>AdminPR</code> is member of the <code>admin</code> Group and <code>patrick</code> ist not in the <code>admin</code> Group.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ dscl . -list /Users
.....
_amavisd
_analyticsd
_appinstalld
_appleevents
_applepay
....
_wwwproxy
_xserverdocs
AdminPR
daemon
nobody
patrick
root

Patricks-Macbook Pro:~ patrick$ id -nG AdminPR
staff com.apple.sharepoint.group.1 everyone localaccounts _appserverusr admin _appserveradm _lpadmin com.apple.sharepoint.group.2 _appstore _lpoperator _developer _analyticsusers com.apple.access_ftp com.apple.access_screensharing com.apple.access_ssh com.apple.access_remote_ae

Patricks-Macbook Pro:~ patrick$ id -nG patrick
staff com.apple.sharepoint.group.2 everyone localaccounts access_bpf com.apple.sharepoint.group.1 _lpoperator

Patricks-Macbook Pro:~ patrick$ 
</code></pre>



<p>In the default User <code>sudo</code> specification any Users belonging to the <code>admin</code> Group are enabled to use <code>sudo</code> and can run any command as <code>root</code>. Therefore I must work with the admin user to make any changes to <code>/private/etc/sudoers</code>. </p>



<p>To check this I switch to my Admin-User using the <code>su</code> command in the Terminal and then I print the content of my  <code>/private/etc/sudoers</code> file to the console using the <code>cat</code> command. In the User specification part of  <code>/private/etc/sudoers</code> file it is defined that members of the  <code>admin</code> Group can run all commands as <code>root</code> using sudo ( <code>%admin …</code> ).</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ su AdminPR
Password:

The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.

bash-3.2$ sudo cat /etc/private/sudoers
Password:

.....

##
# User specification
##

# root and users in group wheel can run anything on any machine as any user
root        ALL = (ALL) ALL
%admin      ALL = (ALL) ALL

....

bash-3.2$ exit
Patricks-Macbook Pro:~ patrick$
</code></pre>



<p>To enable my Standard-User <code>patrick</code> to run <code>root</code> with <code>sudo</code> I basically have 2 options: </p>



<ul class="wp-block-list"><li>I add the Standard-User <code>patrick</code> to the admin Group or </li><li>I add the user <code>patrick</code> to the User specification part in <code>/private/etc/sudoers</code> file. <br></li></ul>



<p>Both tasks can currently only be performed using the Admin-User as this is the only user that can run <code>sudo</code> commands. </p>



<p>I decide to add user <code>patrick</code> to sudoers. So I <code>su</code> into the <code>AdminPR</code> account again and add the Standard-User <code>patrick</code> to <code>/private/etc/sudoers</code> file in the User specification part as follows. I use my favorite editor <code>nano</code> for this.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ su AdminPR
Password:

The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.

bash-3.2$ sudo nano /etc/private/sudoers
Password:

##
# User specification
##

# root and users in group wheel can run anything on any machine as any user
root        ALL = (ALL) ALL
%admin      ALL = (ALL) ALL
patrick     ALL = (ALL) ALL

bash-3.2$ exit
Patricks-Macbook Pro:~ patrick$ 
</code></pre>



<p>Finally I successfully check that the configuration works.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ sudo cat /private/etc/sudoers
Password:

#
# Sample /etc/sudoers file.
#
# This file MUST be edited with the 'visudo' command as root.
#
# See the sudoers man page for the details on how to write a sudoers file.

##
# Override built-in defaults
##
Defaults    env_reset
Defaults    env_keep += "BLOCKSIZE"
Defaults    env_keep += "COLORFGBG COLORTERM"
Defaults    env_keep += "__CF_USER_TEXT_ENCODING"
Defaults    env_keep += "CHARSET LANG LANGUAGE LC_ALL LC_COLLATE LC_CTYPE"
Defaults    env_keep += "LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME"
Defaults    env_keep += "LINES COLUMNS"
Defaults    env_keep += "LSCOLORS"
Defaults    env_keep += "SSH_AUTH_SOCK"
Defaults    env_keep += "TZ"
Defaults    env_keep += "DISPLAY XAUTHORIZATION XAUTHORITY"
Defaults    env_keep += "EDITOR VISUAL"
Defaults    env_keep += "HOME MAIL"

Defaults    lecture_file = "/etc/sudo_lecture"

##
# User alias specification
##
# User_Alias    FULLTIMERS = millert, mikef, dowdy

##
# Runas alias specification
##
# Runas_Alias    OP = root, operator

##
# Host alias specification
##
# Host_Alias    CUNETS = 128.138.0.0/255.255.0.0
# Host_Alias    CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0
# Host_Alias    SERVERS = master, mail, www, ns
# Host_Alias    CDROM = orion, perseus, hercules

##
# Cmnd alias specification
##
# Cmnd_Alias    PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less

##
# User specification
##

# root and users in group wheel can run anything on any machine as any user
root        ALL = (ALL) ALL
%admin        ALL = (ALL) ALL
patrick     ALL = (ALL) ALL

## Read drop-in files from /private/etc/sudoers.d
## (the '#' here does not indicate a comment)
#includedir /private/etc/sudoers.d

Patricks-Macbook Pro:~ patrick$ 
</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to setup Homebrew on Mac OS</title>
		<link>https://digitaldocblog.com/mac/how-to-setup-homebrew-on-mac-os/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 16 Mar 2021 12:00:00 +0000</pubDate>
				<category><![CDATA[Mac OS]]></category>
		<category><![CDATA[Homebrew]]></category>
		<guid isPermaLink="false">https://digitaldocblog.com/?p=130</guid>

					<description><![CDATA[Most of the Mac OS users install software via the Apple App store or download a .dmg file from the Internet and and copy the app into the Applications directory&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Most of the Mac OS users install software via the Apple App store or download a .dmg file from the Internet and and copy the app into the Applications directory or run an installation script to install the software on the Mac. Another way to install software on your Mac is using a package manager like <a href="https://brew.sh">Homebrew</a>. Homebrew is very easy to use and you have access to a large number of free software packages from developers around the world. </p>



<h2 class="wp-block-heading">Homebrew Installation and Uninstallation</h2>



<p>First check if Homebrew is (already) installed.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ brew --version
Homebrew 3.0.5
Homebrew/homebrew-core (git revision 4324a52c3e; last commit 2021-03-14)
Homebrew/homebrew-cask (git revision 16c4718ac7; last commit 2021-03-14)
Macbook Pro:~ user$
</code></pre>



<p>The above output show Homebrew 3.0.5.<br></p>



<p>In case Homebrew is not installed first check the requirements for Mac OS on the <a href="https://docs.brew.sh/Installation">Homebrew Installation site</a>.  Here you find that Homebrew requires Command Line Tools (CLT) for Xcode. Therefore I first check if Command Line Tools are installed on my Mac.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ xcode-select -p
/Library/Developer/CommandLineTools
Macbook Pro:~ patrick$
</code></pre>



<p>The above command return that Command Line Tools for xcode (CLT) are installed on my Mac and show the path where the Command Line Tools are installed.</p>



<p>In case Command Line Tools for xcode are not installed run the following command before you start with the Homebrew installation.</p>



<pre class="wp-block-code"><code>:$ xcode-select --install
</code></pre>



<p>Then go to the <a href="https://brew.sh/">Homebrew Website</a> and check the actual installation instructions. At the time of writing this document you run the following script to install Homebrew.</p>



<pre class="wp-block-code"><code>:$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
</code></pre>



<p>After the installation I check the Homebrew version and run <code>brew doctor</code>.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ brew --version
Homebrew 3.0.5
Homebrew/homebrew-core (git revision 4324a52c3e; last commit 2021-03-14)
Homebrew/homebrew-cask (git revision 16c4718ac7; last commit 2021-03-14)

Macbook Pro:~ user$ brew doctor
Your system is ready to brew.
Macbook Pro:~ user$
</code></pre>



<p>The shell output show that Homebrew version 3.0.5 is installed on the system and that I am ready to brew which means that I am now ready to install software with Homebrew.</p>



<p>To uninstall Homebrew you run the following script.</p>



<pre class="wp-block-code"><code>:$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall.sh)"
</code></pre>



<h2 class="wp-block-heading">Update Command Line Tools for xcode</h2>



<p>Homebrew need Command Line Tools for xcode but sometimes Command Line Tools can be outdated. When you run <code>brew doctor</code> and see the following message that Command Line Tools are outdated you must ensure that the latest version of Command Line Tools is installed on your Mac.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ brew doctor
Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don't worry or file an issue; just ignore this. Thanks!

Warning: A newer Command Line Tools release is available.
Update them from Software Update in System Preferences or run:
  softwareupdate --all --install --force

If that doesn't show you any updates, run:
  sudo rm -rf /Library/Developer/CommandLineTools
  sudo xcode-select --install

Alternatively, manually download them from:
  https:&#47;&#47;developer.apple.com/download/more/.

Patricks-Macbook Pro:~ patrick$ ls -l /Library/Developer
total 0
drwxr-xr-x  5 root  admin  160 15 Sep 07:18 CommandLineTools
drwxr-xr-x  4 root  admin  128  9 Okt  2019 PrivateFrameworks

Patricks-Macbook Pro:~ patrick$ 
</code></pre>



<p>To update Command Line Tools for xcode they must first be uninstalled and then re- installed on the system. Pls. find additional information <a href="https://www.openguru.com/2020/07/how-to-uninstall-mac-os-xcode-command.html">how to uninstall</a> Command Line Tools for xcode and check the related <a href="https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-HOW_CAN_I_UNINSTALL_THE_COMMAND_LINE_TOOLS_">Apple Developer Docs</a>.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ sudo rm -rf /Library/Developer/CommandLineTools

Patricks-Macbook Pro:~ patrick$ ls -l /Library/Developer
total 0
drwxr-xr-x  4 root  admin  128  9 Okt  2019 PrivateFrameworks

Patricks-Macbook Pro:~ patrick$ sudo xcode-select --install
xcode-select: note: install requested for command line developer tools

Patricks-Macbook Pro:~ patrick$ ls -l /Library/Developer
total 0
drwxr-xr-x  5 root  wheel  160 28 Feb 06:35 CommandLineTools
drwxr-xr-x  4 root  admin  128  9 Okt  2019 PrivateFrameworks

Patricks-Macbook Pro:~ patrick$ xcode-select -p
/Library/Developer/CommandLineTools

Patricks-Macbook Pro:~ patrick$
</code></pre>



<h2 class="wp-block-heading">Homebrew Software Repositories and Tap(s)</h2>



<p>With Homebrew package manager you have access to a wide range of software that can be installed on your system. After Homebrew has been installed on your system you find Homebrew under <code>/usr/local/Homebrew</code> on your system.</p>



<p>Homebrew differentiates between Core Software Packages and Cask Software or so-called Casks. All Software Packages are available in GitHub Repositories.</p>



<p><a href="https://github.com/Homebrew/homebrew-core">Homebrew Core Software Packages</a> are free software developed from developers around the world to be installed on Mac OS platforms using Homebrew. Core software will be installed based on so called formulae. A formula contain the required information for the installation such as i.e. from where the installation files should be loaded, which dependencies exist and how the installation should be performed on the different Mac platforms. All formulae for Core Software Packages have been loaded from Homebrew&#8217;s <strong>GitHub Core-Repository</strong> <a href="https://github.com/Homebrew/homebrew-core">Homebrew/homebrew-core</a> into the <strong>core Tap</strong> on your machine. This Tap can be found on you machine in <code>/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core</code></p>



<p><a href="https://github.com/Homebrew/homebrew-cask">Homebrew Cask Software Packages</a> are native Mac OS Apps like Google Chrome, Firefox or other Mac OS Apps that can be installed using the <a href="https://github.com/Homebrew/homebrew-cask">Homebrew Cask</a> extension of the Homebrew Package Manager instead of installing the software via the Apple App Store or drag and drop a dmg file into the Application folder. How to use Homebrew Cask can be read on the <a href="https://github.com/Homebrew/homebrew-cask/blob/master/USAGE.md">Homebrew Cask GitHub site</a>. Casks will be loaded from the Homebrew&#8217;s <strong>GitHub Cask-Repository</strong> <a href="https://github.com/Homebrew/homebrew-cask">Homebrew/homebrew-cask</a> into the <strong>cask Tap</strong> on your machine. This Tap can be found on you machine in <code>/usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask</code>.</p>



<p>It is also possible to install Software that is not available on Homebrew&#8217;s GitHub Core-Repository or Homebrew&#8217;s GitHub Cask-Repository. In this case you must first <code>tap</code> the GitHub Repository to let Homebrew know, from where it should load the formula or cask to install the software package.</p>



<p>For example the formula for <strong>MongoDB</strong> has been removed from the GitHub Core-Repository. But fortunately the MongoDB Team is maintaining a custom GitHub-Repository <a href="https://github.com/mongodb/homebrew-brew">mongodb/homebrew-brew</a> from where you can tap the formulae on your local machine. </p>



<pre class="wp-block-code"><code>:$ brew tap mongodb/homebrew-brew
</code></pre>



<p>On GitHub, a Homebrew repository must be named <strong>homebrew-<something></strong> in order to use the form of the <code>brew tap</code> with only one argument. When you use <code>brew tap</code> you can leave out the homebrew- prefix. </p>



<pre class="wp-block-code"><code>:$ brew tap mongodb/brew
</code></pre>



<p>This <code>brew tap &lt;username&gt;/brew</code> be used as a shortcut for the long version <code>brew tap &lt;username&gt;/homebrew-brew</code>. Homebrew will automatically add back the homebrew<em>&#8211;</em> prefix whenever it’s necessary.</p>



<p>The command <code>brew tap</code> without any arguments lists the GitHub repositories that are currently tapped on your local machine and available to install software from these sources.</p>



<pre class="wp-block-code"><code>Patricks-MBP:~ patrick$ brew tap
homebrew/cask
homebrew/core
homebrew/services
mongodb/brew
</code></pre>



<h2 class="wp-block-heading">Where are Packages on your System</h2>



<p>Homebrew create symlinks for each installed package in <code>/usr/local/bin</code> and usually point to the binary in <code>/usr/local/Cellar/&lt;package_name&gt;/&lt;version&gt;/bin</code>. This is the standard. Depending on the definitions in the formula of a certain package the binaries can be also linked somewhere else on your system.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ ls -l /usr/local/bin
total 0
lrwxr-xr-x  1 user  admin  28 11 Nov  2016 brew -&gt; /usr/local/Homebrew/bin/brew
lrwxr-xr-x  1 user  admin  34  1 Nov  2017 ccmake -&gt; ../Cellar/cmake/3.9.4_1/bin/ccmake
lrwxr-xr-x  1 user  admin  33  1 Nov  2017 cmake -&gt; ../Cellar/cmake/3.9.4_1/bin/cmake
lrwxr-xr-x  1 user  admin  39  1 Nov  2017 cmakexbuild -&gt; ../Cellar/cmake/3.9.4_1/bin/cmakexbuild
lrwxr-xr-x  1 user  admin  33  1 Nov  2017 cpack -&gt; ../Cellar/cmake/3.9.4_1/bin/cpack
lrwxr-xr-x  1 user  admin  41 16 Dez  2016 cryptest.exe -&gt; ../Cellar/cryptopp/5.6.5/bin/cryptest.exe
lrwxr-xr-x  1 user  admin  33  1 Nov  2017 ctest -&gt; ../Cellar/cmake/3.9.4_1/bin/ctest
lrwxr-xr-x  1 user  admin  32  1 Nov  2017 evm -&gt; ../Cellar/ethereum/1.7.2/bin/evm

.......
</code></pre>



<p>The Homebrew binary link named brew point to <code>/usr/local/Homebrew/bin/brew</code>. Any other binary link point into the Cellar in <code>/usr/local/Cellar/&lt;package_name&gt;/&lt;version&gt;/bin</code>. The Cellar is the place on your system where you usually find Homebrew installed software packages. As you see on my system I have installed a couple of software packages like boost, cmake and node.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ ls -l /usr/local/Cellar
total 0
drwxr-xr-x  4 user  admin  128  1 Nov  2017 boost
drwxr-xr-x  4 user  admin  128  1 Nov  2017 cmake
drwxr-xr-x  3 user  admin   96 16 Dez  2016 cryptopp
drwxr-xr-x  5 user  admin  160  1 Nov  2017 ethereum
drwxr-xr-x  4 user  admin  128  1 Nov  2017 gmp
drwxr-xr-x  5 user  admin  160  1 Nov  2017 go
drwxr-xr-x  4 user  staff  128  6 Okt 07:16 hugo
drwxr-xr-x  3 user  staff   96  3 Aug 06:48 icu4c
drwxr-xr-x  4 user  admin  128  1 Nov  2017 jsoncpp
drwxr-xr-x  4 user  staff  128  9 Okt 07:39 node
drwxr-xr-x  3 user  admin   96 12 Nov  2017 openssl
drwxr-xr-x  4 user  admin  128  1 Nov  2017 solidity
</code></pre>



<p>Cask software is installed in the following directory.</p>



<pre class="wp-block-code"><code>Patricks-MBP:~ patrick$ ls -l /usr/local/Caskroom
total 0
drwxr-xr-x  4 patrick  admin  128 11 Jun 09:00 opera
</code></pre>



<p>Homebrew Cask create a symlink in <code>/usr/local/Caskroom/&lt;package_name&gt;/&lt;version&gt;/&lt;symlink&gt;</code> and point it to the app in the Applications directory where the app will be copied.</p>



<pre class="wp-block-code"><code>Patricks-MBP:~ patrick$ ls -l /usr/local/Caskroom/opera/68.0.3618.165
total 0
lrwxr-xr-x  1 patrick  admin  23 11 Jun 09:00 Opera.app -&gt; /Applications/Opera.app
</code></pre>



<h2 class="wp-block-heading">Install, Uninstall and Update Software Packages</h2>



<p>To install a package using the <code>brew install</code> command.</p>



<pre class="wp-block-code"><code>:$ brew install &lt;formula&gt;
</code></pre>



<p>To uninstall a package using the <code>brew uninstall</code> command.</p>



<pre class="wp-block-code"><code>:$ brew uninstall &lt;formula&gt;
</code></pre>



<p>To update and upgrade all packages with Homebrew use the following commands.</p>



<pre class="wp-block-code"><code>:$ brew update
:$ brew upgrade
</code></pre>



<p>You can also update and upgrade only a certain package.</p>



<pre class="wp-block-code"><code>:$ brew update &lt;formula&gt;
:$ brew upgrade &lt;formula&gt;
</code></pre>



<p>The update command load the new formulae and the upgrade command installs the newer software versions in the Cellar. Depending on the amount of packages you have installed this might take some time.</p>



<p>When you install Cask Software the app must be copied into your Applications Directory. Here you need to provide your user password.</p>



<p>You can list the Casks installed on your Mac.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % brew list --casks
opera
patrick@PatrickMBNeu ~ % 
</code></pre>



<p>You can search for packages<br></p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % brew search opera
==&gt; Formulae
operator-sdk
==&gt; Casks
opera &#x2714;                                                    opera-mobile-emulator                                      operator
opera-gx                                                   opera-neon                                                 homebrew/cask-versions/opera-beta
opera-mail                                                 operadriver                                                homebrew/cask-versions/opera-developer
patrick@PatrickMBNeu ~ %
</code></pre>



<p>You install a cask package using the <code>brew install</code> command.</p>



<pre class="wp-block-code"><code>:$ brew install &lt;cask-package&gt;
</code></pre>



<p>You uninstall a cask package using the <code>brew uninstall</code> command.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % brew uninstall opera     
==&gt; Uninstalling Cask opera
==&gt; Purging files for version 68.0.3618.165 of Cask opera
patrick@PatrickMBNeu ~ % brew list --casks        
patrick@PatrickMBNeu ~ % 
</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to manage different Python Versions on Mac OS 11 Big Sur</title>
		<link>https://digitaldocblog.com/mac/how-to-manage-different-python-versions-on-mac-os-11-big-sur/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 13 Mar 2021 12:00:00 +0000</pubDate>
				<category><![CDATA[Mac OS]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://digitaldocblog.com/?p=127</guid>

					<description><![CDATA[Before you go on reading this article ensure that Homebrew is installed on your Mac. There are installation instructions on my blog digitaldocblog.com or you can just go to the&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Before you go on reading this article ensure that <a href="https://brew.sh/">Homebrew</a> is installed on your Mac. There are installation instructions on my blog <a href="https://digitaldocblog.com/singleblog?article=0">digitaldocblog.com</a> or you can just go to the <a href="https://brew.sh/">Homebrew website</a> and follow the instructions there.</p>



<p>But first of all I would like to describe my initial situation. I think some Mac users have python installed on their mac by themselves in one way or another and are surprised when checking the current version with <code>python -V</code> or when checking which python binary is currently being executed with the command <code>which python</code>.  I installed python 2 and 3 with <a href="https://brew.sh/">Homebrew</a> and after executing these commands I was surprised and found that on my system different python versions were running than I expected.</p>



<p>I found that there must be a problem when you install different Python versions on a Mac and I was looking for an easy way to switch between these versions. Switching between the versions is necessary because when you are a developer you might have the need to run your code on a certain version. So it has to be easy to install different python versions on your Mac and to switch between them as needed. There are of course several ways of dealing with this matter. I decided to use the version manager <a href="https://github.com/pyenv/pyenv">Pyenv</a>. But more on that later. First of all, back to my initial situation.</p>



<h2 class="wp-block-heading">Initial Situation</h2>



<p>It all started with a <a href="https://brew.sh/">Homebrew</a> error message after my update to Mac OS Big Sur (Mac OS 11). I had python 2 and 3 installed on my system with <a href="https://brew.sh/">Homebrew</a>. I had carried out these installations under Catalina. The <code>brew doctor</code> command gave me the error message saying I had installed kegs without a formula and I should uninstall python@2 because it is an outdated and no longer supported python version. What ?</p>



<p>My first check was on the <code>/usr/local/bin</code> directory because I wanted to know whether the python binaries had been linked correctly from <a href="https://brew.sh/">Homebrew</a>.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % ls -l /usr/local/bin/python*
lrwxr-xr-x  1 patrick  admin   32  6 Mär 10:23 python -&gt; ../Cellar/python@2/2.7.17/bin/python
lrwxr-xr-x  1 patrick  admin   32  6 Mär 10:23 python2 -&gt; ../Cellar/python@2/2.7.17/bin/python2
lrwxr-xr-x  1 patrick  admin   32  6 Mär 10:23 python2.7 -&gt; ../Cellar/python@2/2.7.17/bin/python2.7
</code></pre>



<p>Here it seems to me that only python 2 has been installed by Homebrew and the binary links all refer to the python@2 directory in the Homebrew Cellar.  My second check was on the Hombrew Cellar directory because I wanted to know whether there are Formulars of the two python versions available.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % ls -l /usr/local/Cellar/python*
drwxr-xr-x  3 patrick  staff  96 26 Feb 18:46 python@2
drwxr-xr-x  3 patrick  staff  96 26 Feb 18:46 python@3.8
</code></pre>



<p>This made it clear: Python 2 is correctly installed and linked in the Cellar (but out of date) but Python 3 was obviously not installed correctly (no binary links in <code>/usr/local/bin</code>). I understood that this must be the message from Homebrews error message. But then I was curious what the version check would tell me.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % which python
/usr/local/bin/python
patrick@PatrickMBNeu ~ % python --version
2.7.17
patrick@PatrickMBNeu ~ % which python3
/usr/bin/python3
patrick@PatrickMBNeu ~ % python3 --version
3.8.2
</code></pre>



<p>The command <code>which python</code> refers to the python 2 version installed with Homebrew in <code>/usr/local/bin</code> but what the hell is in <code>/usr/bin</code> ? </p>



<p>I googled around a bit and <a href="https://medium.com/faun/the-right-way-to-set-up-python-on-your-mac-e923ffe8cf8e">finally I found out</a> that it must be the python version that comes with Mac OS. So the command <code>which python3</code> refers to the python 3 version pre-installed on the Mac in <code>/usr/bin</code>.  And I learned that it must be avoided in any case to remove these so-called System Python Versions from the system. Apple install in <code>/usr/bin</code> while Homebrew install in <code>/usr/local/bin</code> and <code>/usr/local/Cellar</code>. So stay away from everything that is installed in <code>/usr/bin</code> with regard to Python.</p>



<p>Then I wanted to understand what Apple installed in <code>/usr/bin</code>.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % ls -l /usr/bin/python*
lrwxr-xr-x  1 root  wheel      75  1 Jan  2020 /usr/bin/python -&gt; ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
lrwxr-xr-x  1 root  wheel      75  1 Jan  2020 /usr/bin/python2 -&gt; ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
lrwxr-xr-x  1 root  wheel      75  1 Jan  2020 /usr/bin/python2.7 -&gt; ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
-rwxr-xr-x  1 root  wheel  137552  1 Jan  2020 /usr/bin/python3
patrick@PatrickMBNeu ~ % 
</code></pre>



<p>Apple apparently installs Python 2 and Python 3. But the command  <code>which python</code> clearly tells me (see above) that the Python 2 version of Homebrew from <code>/usr/local/bin</code> is currently active in some way, while the command <code>which python3</code> apparently refers to the System Python 3 version in <code>/usr/bin</code>.</p>



<p>How do I get the mess cleaned up ?</p>



<p>I decided to uninstall the python 2 version of Homebrew normally with the command <code>brew uninstall python@2</code>. And I also removed manually the <code>/usr/local/Cellar/python@3.8</code> directory. Then I checked the python versions again.<br></p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % which python
/usr/bin/python
patrick@PatrickMBNeu ~ % python --version
2.7.16
patrick@PatrickMBNeu ~ % which python3
/usr/bin/python3
patrick@PatrickMBNeu ~ % python3 --version
3.8.2
</code></pre>



<p>I was satisfied with the result. Both System Pythons in <code>/usr/bin</code> are currently active on my system and this is exactly what I wanted to achieve with my clean up. I can now think about how I would like to manage other, different python versions on my system. And this is exactly where I come back to <a href="https://github.com/pyenv/pyenv">Pyenv</a>.</p>



<h2 class="wp-block-heading">Managing Python on Mac OS with Pyenv</h2>



<p>First I install <a href="https://github.com/pyenv/pyenv">Pyenv</a> with Homebrew. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % brew update
patrick@PatrickMBNeu ~ % brew install pyenv
</code></pre>



<p>Then I create a <code>~/.zshrc</code> file in my home directory and add the command <code>pyenv init</code> at the end of the <code>~/.zshrc</code> configuration file to enable pyenv shims in my <code>PATH</code> variable.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % echo -e 'eval "$(pyenv init -)" ' &gt;&gt; ~/.zshrc
patrick@PatrickMBNeu ~ % cat .zshrc

eval "$(pyenv init -)"

patrick@PatrickMBNeu ~ % 
</code></pre>



<p>It is very important to make sure that the command  <code>eval "$(pyenv init -)"</code> is placed at the end of the shell configuration because it manipulates the <code>PATH</code> environment variable during the shell initialization.</p>



<p>Then I close the terminal and restart it again. </p>



<p>With the command <code>pyenv versions</code> you can check the existing python versions on your Mac. After my cleanup the only version on my Mac is the System Python and marked with <code>system</code>. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % pyenv versions     
* system (set by /Users/patrick/.pyenv/version)
patrick@PatrickMBNeu ~ % python --version
Python 2.7.16
patrick@PatrickMBNeu ~ % python3 --version
Python 3.8.2
patrick@PatrickMBNeu ~ %
</code></pre>



<p>When you check the version of the current System Python with the command <code>python</code> <code>--``version</code> and <code>python3</code> <code>--``version</code> you see that I still run the System Python Versions 2.7.16 and 3.8.2. Thats what I expected. </p>



<p>With Pyenv you can also install Python using the <code>pyenv install</code> command. With the command <code>pyenv install --list</code> you can list all available Python version that can be installed. This would be a long list but you can pipe it into grep to restrict the displayed list a little. Here I restrict the list to all available Python 3.8.* and 3.9.* versions. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % pyenv install --list | grep " 3\.&#91;89]"  
  3.8.0
  3.8-dev
  3.8.1
  3.8.2
  3.8.3
  3.8.4
  3.8.5
  3.8.6
  3.8.7
  3.9.0
  3.9-dev
  3.9.1
patrick@PatrickMBNeu ~ % 
</code></pre>



<p>Then I install Python 3.9.1 which is the latest Python available at the time of writing this article.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % pyenv install 3.9.1
</code></pre>



<p>Then I check the existing pythons again with <code>pyenv versions</code> and I can already see that the 3.9.1 version has been added. Now comes the real advantage of pyenv. With the command <code>pyenv global</code> I set the 3.9.1 version as the currently active one.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % pyenv versions     
* system (set by /Users/patrick/.pyenv/version)
  3.9.1
patrick@PatrickMBNeu ~ % pyenv global 3.9.1 
patrick@PatrickMBNeu ~ % pyenv versions   
  system
* 3.9.1 (set by /Users/patrick/.pyenv/version)
patrick@PatrickMBNeu ~ % python --version 
Python 3.9.1
patrick@PatrickMBNeu ~ % python3 --version 
Python 3.9.1
patrick@PatrickMBNeu ~ % python
Python 3.9.1 (default, Mar  8 2021, 18:50:54) 
&#91;Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; exit()
patrick@PatrickMBNeu ~ %  
</code></pre>



<p>I check again if the default python is now set to 3.9.1 using the command <code>python</code> <code>--``version</code>. The output in the terminal shows the active version marked with a star. This is Python 3.9.1 and exactly what I expected.  Then I login into the interactive python command interpreter and this also confirmed that it is currently the 3.9.1 version. </p>



<p>So I manage my Pythons on my Mac OS Big Sur from now on with Pyenv. </p>



<h2 class="wp-block-heading">Make Pyenv working perfectly with Homebrew</h2>



<p>When I finished installing Pyenv everything worked fine until I tried to use the brew doctor command to check my Homebrew installations. </p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % brew doctor
Warning: "config" scripts exist outside your system or Homebrew directories.
`./configure` scripts often look for *-config scripts to determine if
software packages are installed, and what additional flags to use when
compiling and linking.

Having additional scripts in your path can confuse software installed via
Homebrew if the config script overrides a system or Homebrew provided
script of the same name. We found the following "config" scripts:

    /Users/patrick/.pyenv/shims/python-config
    /Users/patrick/.pyenv/shims/python3-config
    /Users/patrick/.pyenv/shims/python3.9-config

patrick@PatrickMBNeu ~ %
</code></pre>



<p>I googled a little and I <a href="https://titanwolf.org/Network/Articles/Article?AID=f6d65982-5922-4ccc-9244-8d3dfa687e4c#gsc.tab=0">found out this</a>. Very interesting Article about the <code>PATH</code> settings I enforced in my <code>~/.zshrc</code> file when I installed Pyenv (see above). </p>



<p>Then I checked my environment variables with the command <code>env</code>.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % env
TMPDIR=/var/folders/zy/3s2n4mh502z3320837q80qdm0000gp/T/
__CFBundleIdentifier=com.apple.Terminal
XPC_FLAGS=0x0
TERM=xterm-256color
SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.ZIRHZWPkYD/Listeners
XPC_SERVICE_NAME=0
TERM_PROGRAM=Apple_Terminal
TERM_PROGRAM_VERSION=440
TERM_SESSION_ID=53DE5B52-55E2-4D61-A4E4-7F47D5C401AC
SHELL=/bin/zsh
HOME=/Users/patrick
LOGNAME=patrick
USER=patrick
PATH=/Users/patrick/.pyenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/MacGPG2/bin
SHLVL=1
PWD=/Users/patrick
OLDPWD=/Users/patrick
PYENV_SHELL=zsh
LANG=de_DE.UTF-8
_=/usr/bin/env
patrick@PatrickMBNeu ~ % 
</code></pre>



<p>The problem seems to be the <code>PATH</code> which is set by the entry <code>eval "$ (pyenv init -)"</code> in my <code>~/.zshrc</code> file.<br></p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % cat .zshrc
eval "$(pyenv init -)"

patrick@PatrickMBNeu ~ %
</code></pre>



<p>This entry leads to that <code>/Users/patrick/.pyenv/shims</code> is set at the beginning of the <code>PATH</code> variable when <code>zsh</code> is executed. </p>



<p>When you look at the complete <code>PATH</code> you see that the command <code>brew doctor</code> can be executed without specifying  <code>/usr/local/bin/brew</code> because the required path specification <code>/usr/local/bin</code> is also available but further back. So brew reads first the path <code>/Users/patrick/.pyenv/shims</code> and only then the path <code>/usr/local/bin</code> and exactly there in <code>/Users/patrick/.pyenv/shims</code> are the <code>*-config</code> files used from Pyenv. So it seems to be that brew has problems with these config files.</p>



<p>Since these config files seems to confuse brew in some way, the best would be if brew could somehow ignore these files. This is possible if we define an <code>alias</code> environment variable. We can define <code>brew</code> as an alias and then instruct <code>zsh</code> that in the event that <code>brew</code> is called a specific <code>PATH</code> applies namely the <code>PATH</code> without the shims directory. For this we have to adapt the <code>~/.zshrc</code> as follows.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % cat .zshrc
alias brew='PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin brew'
eval "$(pyenv init -)"
patrick@PatrickMBNeu ~ %
</code></pre>



<p>After restarting the terminal I was able to run the <code>brew doctor</code> command without this error message. The problem is solved.</p>



<pre class="wp-block-code"><code>patrick@PatrickMBNeu ~ % brew update 
Already up-to-date.
patrick@PatrickMBNeu ~ % brew doctor     
Your system is ready to brew.
patrick@PatrickMBNeu ~ % 
</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Node.js series Part 4. Express Website with authentication and authorization in a Mac Production Environment</title>
		<link>https://digitaldocblog.com/mac/nodejs-series-part-4-express-website-with-authentication-and-authorization-in-a-mac-production-environment/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 18 Jun 2020 07:00:00 +0000</pubDate>
				<category><![CDATA[Mac OS]]></category>
		<category><![CDATA[Web-Development]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[Webserver]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[Blog-Application]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Express.js]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Mongoose]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[NPM Node package manager]]></category>
		<category><![CDATA[Role Based Access Control]]></category>
		<category><![CDATA[Web-Application]]></category>
		<guid isPermaLink="false">https://digitaldocblog.com/?p=117</guid>

					<description><![CDATA[In a real production environment the app runs as a service in the background and this service is managed by a process manager. And the app should run behind a&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In a real production environment the app runs as a service in the background and this service is managed by a process manager. And the app should run behind a reverse proxy server. This reverse proxy server manage the TLS encryption, receives the requests from the client and route any request to the app running in the background. So the connection from the client to the reverse proxy server is TLS encrypted. Therefore the data transferred between client and the reverse proxy are secured. </p>



<p>How to setup such a <strong>production environment</strong> will be shown in the <strong>first chapter</strong> of this documentation. </p>



<p>The express app itself also contains some <strong>security features</strong>. The app contains a session based user authentication and HTTP headers which help to further secure the app. This is explained of the <strong>second chapter</strong> of this documentation.</p>



<p>Finally the express app should use the <strong>template engine PUG</strong> to render the HTML for us. This is describes of the <strong>third chapter</strong> of this documentation. </p>



<h3 class="wp-block-heading">1. Setup the production environment</h3>



<h4 class="wp-block-heading">Installation of mongodb</h4>



<p>The command <code>brew tap</code> without any arguments lists the GitHub repositories that are currently linked to your Homebrew installation. </p>



<pre class="wp-block-code"><code>Patricks-MBP:~ patrick$ brew tap
homebrew/cask
homebrew/core
homebrew/services
</code></pre>



<p>The formula mongodb has been removed from homebrew-core. But fortunately the MongoDB Team is maintaining a custom <a href="https://github.com/mongodb/homebrew-brew">Homebrew tap on GitHub</a>. Read the instructions in the README.md file. </p>



<p>Add the custom tap in the Mac OS terminal and install mongodb.</p>



<pre class="wp-block-code"><code>Patricks-MBP:~ patrick$ brew tap mongodb/brew

Patricks-MBP:~ patrick$ brew tap
homebrew/cask
homebrew/core
homebrew/services
mongodb/brew

Patricks-MBP:~ patrick$ brew install mongodb-community@4.2

</code></pre>



<p>After the installation the relevant paths are.</p>



<pre class="wp-block-code"><code>the configuration file (/usr/local/etc/mongod.conf)
the log directory path (/usr/local/var/log/mongodb)
the data directory path (/usr/local/var/mongodb)

</code></pre>



<p>Check the services with homebrew</p>



<pre class="wp-block-code"><code>brew services list

Name              Status  User    Plist
mongodb-community started patrick /Users/patrick/Library/LaunchAgents/homebrew.mxcl.mongodb-community.plist
  
</code></pre>



<p>Start and stop mongodb.</p>



<pre class="wp-block-code"><code>brew services start mongodb-community

brew services stop mongodb-community

</code></pre>



<h4 class="wp-block-heading">Setup mongodb for the project</h4>



<p>Setup an admin user</p>



<pre class="wp-block-code"><code>:# mongo

&gt; use admin
switched to db admin

&gt; db
admin

&gt; db.createUser({ user: "adminUser", pwd: "adminpassword", roles: &#91;{ role: "userAdminAnyDatabase", db: "admin" }, {"role" : "readWriteAnyDatabase", "db" : "admin"}] })

&gt; db.auth("adminUser", "adminpassword")
1

&gt; show users
{
    "_id" : "admin.adminUser",
    "userId" : UUID("5cbe2fc4-1e54-4c2d-89d1-317340429571"),
    "user" : "adminUser",
    "db" : "admin",
    "roles" : &#91;
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        },
        {
            "role" : "readWriteAnyDatabase",
            "db" : "admin"
        }
    ],
    "mechanisms" : &#91;
        "SCRAM-SHA-1",
        "SCRAM-SHA-256"
    ]
}

&gt; exit

</code></pre>



<p>Enable authentication with <code>security: authorization: enabled</code></p>



<pre class="wp-block-code"><code>#&gt; nano /usr/local/etc/mongod.conf

systemLog:
  destination: file
  path: /usr/local/var/log/mongodb/mongo.log
  logAppend: true
storage:
  dbPath: /usr/local/var/mongodb
net:
  port: 27017
  bindIp: 127.0.0.1
security:
  authorization: enabled


</code></pre>



<p>Login and authenticate with admin</p>



<pre class="wp-block-code"><code>#&gt; mongo

MongoDB shell version v4.2.3
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&amp;gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("b3e7f48a-a05c-4894-87db-996cb34eb1fb") }
MongoDB server version: 4.2.3

&gt; show dbs
&gt; db
test
&gt; use admin
switched to db admin
&gt; db
admin
&gt; show dbs
&gt; db.auth("adminUser", "adminpassword")
1
&gt; show dbs
admin               0.000GB
config              0.000GB
local               0.000GB

&gt; 

</code></pre>



<p>If you login you dont see any databases when you call <code>show dbs</code>. The default database you are connected to is <code>test</code>. </p>



<p>Then you connect to admin database. For admin you setup the admin user with the roles <code>userAdminAnyDatabase</code> and <code>readWriteAnyDatabase</code>. With these permissions the admin user can manage users for any database and has read and write access to any database. </p>



<p>So wehen you logon to admin database with the admin user you are able to see all databases with <code>show dbs</code>. </p>



<p>Mongodb comes with 3 standard dbs pre installed:</p>



<ul class="wp-block-list"><li>admin </li><li>config</li><li>local<br></li></ul>



<p>Create a new database for our express-security app (authenticated as admin user &#8211; see above)</p>



<pre class="wp-block-code"><code>&gt; use express-security
switched to db express-security
&gt; db
express-security
&gt; show dbs
admin               0.000GB
config              0.000GB
local               0.000GB
&gt; 

</code></pre>



<p>The DB which you&#8217;ve created is not listed here. We need to insert at least one collection into it for displaying that database in the list. </p>



<pre class="wp-block-code"><code>&gt; db
express-security

&gt; db.createCollection("col_default")
{ "ok" : 1 }

&gt; show dbs
admin               0.000GB
config              0.000GB
express-security    0.000GB
local               0.000GB

&gt; exit

</code></pre>



<p>Create an owner user for express-security database using the admin user</p>



<pre class="wp-block-code"><code>#&gt; mongo

MongoDB shell version v4.2.3
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&amp;gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("79f79b63-9d08-489f-9e6c-bfc10d8cc09e") }
MongoDB server version: 4.2.3

&gt; db
test

&gt; show dbs

&gt; use admin
switched to db admin

&gt; db.auth("adminUser", "adminpassword")
1

&gt; db
admin

&gt; show dbs
admin               0.000GB
config              0.000GB
express-security    0.000GB
local               0.000GB

&gt; use express-security
switched to db express-security

&gt; db.createUser({ user: "owner_express-security", pwd: "passowrd", roles: &#91;{ role: "dbOwner", db: "express-security" }] })
Successfully added user: {
	"user" : "owner_express-security",
	"roles" : &#91;
		{
			"role" : "dbOwner",
			"db" : "express-security"
		}
	]
}

&gt; db
express-security

&gt; show users
{
	"_id" : "express-security.owner_express-security",
	"userId" : UUID("7a0bafb2-d2ed-4d18-9aba-e2f15a503ec5"),
	"user" : "owner_express-security",
	"db" : "express-security",
	"roles" : &#91;
		{
			"role" : "dbOwner",
			"db" : "express-security"
		}
	],
	"mechanisms" : &#91;
		"SCRAM-SHA-1",
		"SCRAM-SHA-256"
	]
}

&gt; exit 
</code></pre>



<p>Connection string to connect to express-security db using the owner_express-security user:</p>



<pre class="wp-block-code"><code>mongodb://owner_express-security:password@localhost/express-security
</code></pre>



<h4 class="wp-block-heading">Installation of PM2</h4>



<p>PM2 is a process manager for Node.js applications. It can daemonize applications to run them as a service in the background.</p>



<p>I install pm2 as a global npm package on my Mac.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ npm install pm2 -g
</code></pre>



<p>Then navigate to your project directory.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ cd Software/dev/node/articles/2020-05-15-express-security/express-security

Patricks-Macbook Pro:~ patrick$ ls -l 
total 112
drwxr-xr-x    5 patrick  staff    160 30 Mai 05:28 database
drwxr-xr-x  115 patrick  staff   3680 30 Mai 19:35 node_modules
-rw-r--r--    1 patrick  staff  34366 30 Mai 19:35 package-lock.json
-rw-r--r--    1 patrick  staff    339 30 Mai 19:35 package.json
-rw-r--r--@   1 patrick  staff  12343 30 Jun 05:00 secserver.js
drwxr-xr-x    3 patrick  staff     96 30 Mai 05:03 static

Patricks-Macbook Pro:express-security patrick$ 

</code></pre>



<p>Start your app using pm2</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:express-security patrick$ pm2 start secserver.js

Patricks-Macbook Pro:~ patrick$ pm2 list
┌─────┬──────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id  │ name         │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├─────┼──────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0   │ secserver    │ default     │ 1.0.0   │ fork    │ 640      │ 16h    │ 0    │ online    │ 0%       │ 48.6mb   │ patrick  │ disabled │
└─────┴──────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘

Patricks-Macbook Pro:~ patrick$ 

</code></pre>



<p>Other comands to control the process manager. </p>



<pre class="wp-block-code"><code>pm2 start secserver.js

pm2 start &lt;id&gt;

pm2 list

pm2 stop &lt;id&gt;

pm2 restart &lt;id&gt;

pm2 show &lt;id&gt;

</code></pre>



<h4 class="wp-block-heading">Installation of nginx</h4>



<p><a href="https://nginx.org/en/">nginx</a> is an open source HTTP and an HTTP Reverse Proxy Server (also mail proxy and load balancer etc.). I install nginx on my Mac with Homebrew. </p>



<pre class="wp-block-code"><code>brew install nginx

</code></pre>



<p>You can list the brew services with the following command.</p>



<pre class="wp-block-code"><code>Patricks-MBP:digitaldocblog-V3 patrick$ brew services list

Name              Status  User    Plist
mongodb-community started patrick /Users/patrick/Library/LaunchAgents/homebrew.mxcl.mongodb-community.plist
nginx             started patrick /Users/patrick/Library/LaunchAgents/homebrew.mxcl.nginx.plist
Patricks-MBP:digitaldocblog-V3 patrick$
</code></pre>



<p>You can start and stop the brew services as follows.</p>



<pre class="wp-block-code"><code>brew install nginx

brew services start nginx

brew services stop nginx

</code></pre>



<h4 class="wp-block-heading">Setup nginx with TLS/SSL</h4>



<p>SSL/TLS works by using the combination of a public certificate and a private key. </p>



<p>The <strong>SSL key (private key)</strong> is kept secret on the server. It is used to encrypt content sent to clients. </p>



<p>The <strong>SSL certificate</strong> is publicly shared with anyone requesting the content. It can be used to decrypt the content signed by the associated SSL key.</p>



<p><strong>create private key</strong></p>



<pre class="wp-block-code"><code>Patricks-MBP:express-security patrick$ cd /usr/local/etc/nginx

Patricks-MBP:nginx patrick$ ls -l
total 144
-rw-r--r--  1 patrick  admin  1077  5 Apr 13:18 fastcgi.conf
-rw-r--r--  1 patrick  admin  1077  5 Apr 13:18 fastcgi.conf.default
-rw-r--r--  1 patrick  admin  1007  5 Apr 13:18 fastcgi_params
-rw-r--r--  1 patrick  admin  1007  5 Apr 13:18 fastcgi_params.default
-rw-r--r--  1 patrick  admin  2837  5 Apr 13:18 koi-utf
-rw-r--r--  1 patrick  admin  2223  5 Apr 13:18 koi-win
-rw-r--r--  1 patrick  admin  5231  5 Apr 13:18 mime.types
-rw-r--r--  1 patrick  admin  5231  5 Apr 13:18 mime.types.default
-rw-r--r--  1 patrick  admin  3106 15 Mai 05:19 nginx.conf
-rw-r--r--  1 patrick  admin  2680  5 Apr 13:18 nginx.conf.default
-rw-r--r--  1 patrick  admin  3091 21 Jan 05:40 nginx.conf.working
-rw-r--r--  1 patrick  admin   636  5 Apr 13:18 scgi_params
-rw-r--r--  1 patrick  admin   636  5 Apr 13:18 scgi_params.default
drwxr-xr-x  3 patrick  admin    96 21 Jan 06:02 servers
-rw-r--r--  1 patrick  admin   664  5 Apr 13:18 uwsgi_params
-rw-r--r--  1 patrick  admin   664  5 Apr 13:18 uwsgi_params.default
-rw-r--r--  1 patrick  admin  3610  5 Apr 13:18 win-utf

Patricks-MBP:nginx patrick$ mkdir ssl

Patricks-MBP:nginx patrick$ ls -l
total 152
-rw-r--r--  1 patrick  admin  1077  5 Apr 13:18 fastcgi.conf
-rw-r--r--  1 patrick  admin  1077  5 Apr 13:18 fastcgi.conf.default
-rw-r--r--  1 patrick  admin  1007  5 Apr 13:18 fastcgi_params
-rw-r--r--  1 patrick  admin  1007  5 Apr 13:18 fastcgi_params.default
-rw-r--r--  1 patrick  admin  2837  5 Apr 13:18 koi-utf
-rw-r--r--  1 patrick  admin  2223  5 Apr 13:18 koi-win
-rw-r--r--  1 patrick  admin  5231  5 Apr 13:18 mime.types
-rw-r--r--  1 patrick  admin  5231  5 Apr 13:18 mime.types.default
-rw-r--r--@ 1 patrick  admin   373 18 Mai 05:38 nginx.conf
-rw-r--r--  1 patrick  admin  2680  5 Apr 13:18 nginx.conf.default
-rw-r--r--  1 patrick  admin  3091 21 Jan 05:40 nginx.conf.working
-rw-r--r--@ 1 patrick  admin  1390 17 Mai 05:19 nginx_old.conf
-rw-r--r--  1 patrick  admin   636  5 Apr 13:18 scgi_params
-rw-r--r--  1 patrick  admin   636  5 Apr 13:18 scgi_params.default
drwxr-xr-x  5 patrick  admin   160 18 Mai 05:20 servers
drwxr-xr-x  4 patrick  admin   128 16 Mai 05:41 ssl
-rw-r--r--  1 patrick  admin   664  5 Apr 13:18 uwsgi_params
-rw-r--r--  1 patrick  admin   664  5 Apr 13:18 uwsgi_params.default
-rw-r--r--  1 patrick  admin  3610  5 Apr 13:18 win-utf

Patricks-MBP:nginx patrick$ cd ssl

Patricks-MBP:ssl patrick$ pwd
/usr/local/etc/nginx/ssl

Patricks-MBP:ssl patrick$ openssl genrsa -out privateKey.pem 4096

Patricks-MBP:ssl patrick$ ls -l
total 16
-rw-r--r--  1 patrick  admin  3247 16 Mai 05:22 privateKey.pem

</code></pre>



<p><strong>create certificate signing request (CSR)</strong></p>



<pre class="wp-block-code"><code>Patricks-MBP:ssl patrick$ pwd
/usr/local/etc/nginx/ssl

Patricks-MBP:ssl patrick$ openssl req -new -key privateKey.pem -out csr.pem

Patricks-MBP:ssl patrick$ ls -l
total 16
-rw-r--r--  1 patrick  admin  1740 16 Mai 05:23 csr.pem
-rw-r--r--  1 patrick  admin  3247 16 Mai 05:22 privateKey.pem

</code></pre>



<p>In case I would like to request an official certificate I must send this csr to the certificate authority. This authority would then create an <strong>authority signed certificate</strong> from the CSR and send it back to me.</p>



<p>This step is done by ourselves and this is the reason why we create a <strong>self signed certificate</strong>. This self signed certificate is not a official certificae and not trusted by any browser. It is not useful to use a self signed certificate in production because it produces error messages in the browsers. But for local development a self signed certificate is ok. </p>



<p>So create the self signed certificale. The csr file can then be removed. </p>



<p><strong>create the self signed certificate</strong></p>



<pre class="wp-block-code"><code>Patricks-MBP:ssl patrick$ pwd
/usr/local/etc/nginx/ssl

Patricks-MBP:ssl patrick$ openssl x509 -in csr.pem -out selfsignedcertificate.pem -req -signkey privateKey.pem -days 365

Patricks-MBP:ssl patrick$ ls -l
total 24
-rw-r--r--  1 patrick  admin  1740 16 Mai 05:23 csr.pem
-rw-r--r--  1 patrick  admin  3247 16 Mai 05:22 privateKey.pem
-rw-r--r--  1 patrick  admin  1980 16 Mai 05:39 selfsignedcertificate.pem

Patricks-MBP:ssl patrick$ rm csr.pem

Patricks-MBP:ssl patrick$ ls -l
total 24
-rw-r--r--  1 patrick  admin  3247 16 Mai 05:22 privateKey.pem
-rw-r--r--  1 patrick  admin  1980 16 Mai 05:39 selfsignedcertificate.pem
 
</code></pre>



<p><strong>show certificate details</strong></p>



<pre class="wp-block-code"><code>Patricks-MBP:ssl patrick$ pwd
/usr/local/etc/nginx/ssl

Patricks-MBP:ssl patrick$ openssl x509 -in selfsignedcertificate.pem -text -noout

</code></pre>



<h4 class="wp-block-heading">Configure nginx Servers with SSL</h4>



<p>In our configuration we enforce ssl. Therefore we create a <strong>default Webserver</strong> listening on Port 80 with the server name  <code>servtest.rottlaender.lan</code>. </p>



<p>Any request to <code>servtest.rottlaender.lan:80</code> is redirected to my <strong>Reverse Proxy Server</strong> which is listening on <code>servtest.rottlaender.lan:443</code>.<br></p>



<p>The <strong>default Webserver</strong> is configured in <code>/usr/local/etc/nginx/nginx.conf</code>.</p>



<pre class="wp-block-code"><code># /usr/local/etc/nginx/nginx.conf
# default Webserver

worker_processes  1;
error_log  /usr/local/etc/nginx/logs/error.log;

events {
    worker_connections  1024;
}

http {
    include       		mime.types;
    default_type  		application/octet-stream;
    sendfile        	on;
    keepalive_timeout  	65;

    access_log  /usr/local/etc/nginx/logs/access.log;

    # default Webserver redirect from port 80 to port 443 ssl
    
    server {
      	listen 80;
    	listen &#91;::]:80;
    	server_name servtest.rottlaender.lan;
    	return 301 https://$host$request_uri;
    }
    
    include servers/*;
    
}
</code></pre>



<p>The <strong>Reverse Proxy Server</strong> is configured in <code>/usr/local/etc/nginx/servers/reverse</code>.</p>



<pre class="wp-block-code"><code>// /usr/local/etc/nginx/servers/reverse
// reverse Proxy Server

server {

    listen      443 ssl;
    server_name servtest.rottlaender.lan;

    ssl_certificate      ssl/selfsignedcertificate.pem;
    ssl_certificate_key  ssl/privateKey.pem;
    ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;
    ssl_ciphers  HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers  on;

    location / {
       proxy_pass http://localhost:3300;
       proxy_set_header X-Forwarded-For $remote_addr;
    }
}

</code></pre>



<p>The server name servtest.rottlaender.lan is linked in /private/etc/hosts to the ip 192.168.178.20 which is the ip of my computer in my local network.</p>



<pre class="wp-block-code"><code>Patricks-MBP:digitaldocblog-V3 patrick$ cat /private/etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1			localhost
255.255.255.255		broadcasthost
::1             	localhost
192.168.178.20 		servtest.rottlaender.lan
</code></pre>



<h3 class="wp-block-heading">2. Express Secure App (Security Features HTML version)</h3>



<p>This is a very simple application but show the basic security features you should use when you run a node app in a production environment. </p>



<p>The app is a website with a simple layout and navigation. </p>



<p>The Home page contain static information and can be accessed by everyone. </p>



<p>On the register page, users can find a form to register. The user data entered here are saved in the database and the user is logged in at the same time. Known users can log in with their email and password after successful registration on the login page. The login and register page can only be accessed if the user is not logged in. If a user is logged in and tries to access the login or register, he will be redirected to the dashboard page.</p>



<p>The dashboard is a personalized area of the website. This area can only be accessed if the user is logged in. If a user is not logged in, he will be redirected to the login page.</p>



<p>Logout is not really a page but a link that contains a logout function. Users who are logged in can log out using this link. Users who are not already logged in will be redirected to the login page.</p>



<h4 class="wp-block-heading">Download the code from GitHub</h4>



<p>Pls. <a href="https://github.com/prottlaender/node-part-4-express-security-with-db-html">go to my GitHub site</a> and clone the code. Here you find a some inline documentation in the code. The details are explained in this chapter. </p>



<h4 class="wp-block-heading">Create your app home directory express-security</h4>



<p>My app home directory is different to the one that is available after you cloned the code from GitHub. </p>



<pre class="wp-block-code"><code>Patricks-MBP:2020-05-15-express-security patrick$ pwd
/Users/patrick/software/dev/node/articles/2020-05-15-express-security

Patricks-MBP:2020-05-15-express-security patrick$ mv node-part-5-express-security-with-db-pug express-security

Patricks-MBP:2020-05-15-express-security patrick$ cd express-security

Patricks-MBP:express-security patrick$ pwd
/Users/patrick/software/dev/node/articles/2020-05-15-express-security/express-security
</code></pre>



<h4 class="wp-block-heading">Manage environment variables</h4>



<p>To manage environment variables for my app I use <code>envy</code>. First you need the files <code>.env</code> and <code>.env.example</code> in the root of your project directory. In <code>.env.example</code> you create a list of all potential environment variables without any values and in <code>.env</code> you use the defined variables and assign the values to them. </p>



<pre class="wp-block-code"><code>Patricks-MBP:express-security patrick$ ls -al
total 152
drwxr-xr-x   14 patrick  staff    448 23 Jun 05:29 .
drwxr-xr-x    4 patrick  staff    128 26 Mai 05:40 ..
-rw-------    1 patrick  staff    181 23 Jun 05:59 .env
-rw-r--r--    1 patrick  staff     53 23 Jun 05:59 .env.example
....

Patricks-MBP:express-security patrick$ cat .env.example
port=
mongodbpath=
sessionsecret=
sessioncookiename=

Patricks-MBP:express-security patrick$ cat .env
port=&lt;YOUR_PORT&gt;
mongodbpath=&lt;YOUR_CONNECTION_STRING&gt;
sessionsecret=&lt;YOUR_SESSION_SECRET&gt;
sessioncookiename=&lt;YOUR_SESSION_COOKIE_NAME&gt;

Patricks-MBP:express-security patrick$ 

</code></pre>



<p>Envy must be installed as dependency and required in the main application file <em>secserver.js</em>. Then you can set the environment variables as follows. </p>



<pre class="wp-block-code"><code>// secserver.js

....

// envy module to manage environment variables
const envy = require('envy');

// set the environment variables
const env = envy()
const port = env.port
const mongodbpath = env.mongodbpath
const sessionsecret = env.sessionsecret
const sessioncookiename = env.sessioncookiename
....
</code></pre>



<h4 class="wp-block-heading">Start the MongoDB Server</h4>



<p>To run the db server we install <code>mongoose</code> as dependency and require it in the db.js configuration file. The database connection will be initiated with <code>mongoose.connect</code> and the StartMongoServer function will be exported to be called in the main application file <em>secserver.js</em>.</p>



<pre class="wp-block-code"><code>const envy = require('envy')
const env = envy()

const mongodbpath = env.mongodbpath

const mongoose = require('mongoose');
mongoose.set('useNewUrlParser', true);
mongoose.set('useUnifiedTopology', true);

const StartMongoServer = async function() {
  try {

    await mongoose.connect(mongodbpath)
    .then(function() {
      console.log(`Mongoose connection open on ${mongodbpath}`);
    })
    .catch(function(error) {
      console.log(`Connection error message: ${error.message}`);
    })

  } catch(error) {
    res.json( { status: "db connection error", message: error.message } );
  }

};

module.exports = StartMongoServer;
</code></pre>



<h4 class="wp-block-heading">Authentication and authorization</h4>



<p>For user authentication we use the module <code>express-session</code> and to store session data in the session store in our database we use <code>connect-mongodb-session</code>. Therefore we install these modules as dependencies in our project and require the modules in our <em>secserver.js</em> main application file.</p>



<p>Then we create with <code>new MongoDBStore</code> a session storage in our MongoDB to store session data in collection <code>col_sessions</code>. errors are catched with <code>store.on</code>. </p>



<p>We use the session in our app with <code>app.use( session({...}) )</code>. With every request to our site a new session object is created with a unique session ID which include a session cookie object. The session object has keys options and the values for each key define how to deal with the session object. The session ID is created and signed using the <code>secret</code> option. We use <code>name</code> to provide a session cookie name and <code>store</code> to define where the session object should be stored (in case we store the session). </p>



<p>We can access the session object with <code>req.session</code> and the session ID with <code>req.session.id</code>. With every request we have a new session and this new session will be created but not stored anywhere so far. We say the session is <em>uninitialized</em>. The <code>saveUninitialized</code> false option ensure that a session will only be written to the store in case it has been modified. What does this mean?<br></p>



<p>We can modify the session when we store additional data into it. We always do this when the user is logging in via the <code>login</code> or the <code>register</code> route. When we post the data from the <em>login-</em> or from the <em>registration-form</em> to the server we call <em>loginUser</em> or the <em>createUser</em> module which is defined in <code>database/controllers/userC.js</code>. Both modules do basically the same thing: They create a userData Object and store the userData object into the session object and redirect the user to the dashboard when login or registration was successful. </p>



<pre class="wp-block-code"><code>....

var userData = { 
	userId: user._id, 
	name: user.name, 
	lastname: user.lastname, 
	email: user.email, 
	role: user.role 
	}

    req.session.userData = userData

    res.redirect('/dashboard')

....

</code></pre>



<p>If the user is successfully logged in the session is <em>initialized</em> (modified), the session object incl. the userData object are stored into the store and a cookie is stored into the requesting browser. The content of the cookie is only a hash of the session Id and with each request of a logged in user the session on the server is looked up. </p>



<p>The cookie in the browser will live max 1 week as we defined in the cookie object <code>maxAge</code> set to 1 week. Because of the cookie option <code>sameSite</code> true the cookie scope is limited to the same site. </p>



<p>Then the <code>resave</code> false option ensures that the session will not be updated with every request. This mean the session ID that has been created when the user has logged in will be kept until the user is logged out again.<br></p>



<pre class="wp-block-code"><code>// secserver.js

....

// server side session and cookie module
const session = require('express-session');
// mongodb session storage module
const connectMdbSession = require('connect-mongodb-session');

....

// Create MongoDB session storage
const MongoDBStore = connectMdbSession(session)
const store = new MongoDBStore({
  uri: mongodbpath,
  collection: 'col_sessions'
});

// catch errors in case store creation fails
store.on('error', function(error) {
  console.log(`error store session in session store: ${error.message}`);
});

// Create the express app
const app = express();

....

// use session to create session and session cookie
app.use(session({
  secret: sessionsecret,
  name: sessioncookiename,
  store: store,
  resave: false,
  saveUninitialized: false,
  // set cookie to 1 week maxAge
  cookie: {
    maxAge: 1000 * 60 * 60 * 24 * 7,
    sameSite: true
  },

}));

....
</code></pre>



<h4 class="wp-block-heading">Secure HTTP headers</h4>



<p>Response headers are HTTP header that come with the HTTP response from the server to the client. The http response header contain data that could possibly damage the integrity of the client. It is therefore important to secure the response header of your application.</p>



<p>To secure the http response headers I user the module <a href="https://helmetjs.github.io/">helmet</a>. This is a relatively easy-to-use module consisting of various middleware functionalities to secure various http response headers.</p>



<p>First we install <code>helmet</code>as a dependency of our project. Then we require helmet and use helmet right after we created the app. </p>



<pre class="wp-block-code"><code>// secserver.js

// hTTP module
const http = require('http');
// express module
const express = require('express');
// hTTP header security module
const helmet = require('helmet');

// Create the express app
const app = express();

....

// use secure HTTP headers using helmet
app.use(helmet())

</code></pre>



<p>Using simply <code>app.use(helmet())</code> set the http header security to default. Then the following 7 out 11 helmet features can be used.</p>



<ol class="wp-block-list"><li><a href="https://helmetjs.github.io/docs/dns-prefetch-control">dnsPrefetchControl</a> controls browser DNS prefetching</li><li><a href="https://helmetjs.github.io/docs/frameguard/">frameguard</a> to prevent clickjacking</li><li><a href="https://helmetjs.github.io/docs/hide-powered-by/">hidePoweredBy</a> to remove the X-Powered-By header</li><li><a href="https://helmetjs.github.io/docs/hsts/">hsts</a> for HTTP Strict Transport Security</li><li><a href="https://helmetjs.github.io/docs/ienoopen/">ieNoOpen</a> sets X-Download-Options for IE8+</li><li><a href="https://helmetjs.github.io/docs/dont-sniff-mimetype/">noSniff</a> to keep clients from sniffing the MIME type</li><li><a href="https://helmetjs.github.io/docs/xss-filter/">xssFilter</a> adds some small XSS protections<br></li></ol>



<p>When we then request our home page to retrieve the http headers using <code>curl -k --head</code> in the terminal we see the following output. </p>



<pre class="wp-block-code"><code>Patricks-MBP:express-security patrick$ curl -k --head https://servtest.rottlaender.lan
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Fri, 26 Jun 2020 16:14:14 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 1734
Connection: keep-alive
X-DNS-Prefetch-Control: off
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=15552000; includeSubDomains
X-Download-Options: noopen
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
ETag: W/"6c6-U2uWyDNyzlyBAbSI/Quxqo9RRQE"

Patricks-MBP:express-security patrick$ 
</code></pre>



<h4 class="wp-block-heading">App routing</h4>



<p><strong>get routes:</strong> We have the following <code>get</code> routes and navigation.</p>



<ul class="wp-block-list"><li>Home (/)</li><li>Login (/login)</li><li>Register (/register)</li><li>Dashboard (/dashboard)</li><li>Logout (/logout)<br></li></ul>



<p><code>get</code> routes involve an optional middleware and respond HTML back to the client. </p>



<pre class="wp-block-code"><code>app.get('/&lt;route&gt;', &lt;optional: someMiddleware&gt;, (req, res) =&gt; {
	
	res.send(`&lt;some HTML&gt;`)
})
</code></pre>



<p>I will not explain the HTML and css in detail. But as everyone can see, the HTML is the same for every route except for the <code>&lt;body&gt;</code>. Of course, this is not very nice and becomes a bit more efficient with the use of a template engine, which I will explain below using the <a href="https://pugjs.org/api/getting-started.html">PUG template engine</a>. I will then rebuild the app using PUG.</p>



<p>Lets have a look at the <code>middleware</code>. If a request is made for a route and a middleware function is included, the middleware function is first executed before the next routing function <code>function(req, res)</code> is called. A condition is built into the middleware function which is checked. My middleware is built so that in case the condition is true the middleware code is executed directly and the next routing function is omitted. If the condition is false, the next routing function <code>function(req, res)</code> is called.</p>



<p>I have built 2 different middleware functions which each check</p>



<p><strong>middleware 1 (login- and register route):</strong> a user is logged in</p>



<pre class="wp-block-code"><code>// secserver.js
....
// middleware 1 to redirect authenticated users to their dashboard
const redirectDashboard = (req, res, next) =&gt; {
  if (req.session.userData) {
    res.redirect('/dashboard')

  } else {
    next()
  }
}
....
</code></pre>



<p>If a user is logged in the request should be redirected to the dashboard route, in any other case (user is not logged in) the next routing function <code>function(req, res)</code> is called and respond the HTML to the browser. This middleware 1 is included in the <strong>/login-</strong> and <strong>/register</strong> route. This mean logged in users will be redirected to their dashboard, not logged in users will see the login- and register form. </p>



<p><strong>middleware 2 (dashboard- and logout route):</strong> a user is not logged in.</p>



<pre class="wp-block-code"><code>// secserver.js
....

// middleware 2 to redirect not authenticated users to login
const redirectLogin = (req, res, next) =&gt; {
  if (!req.session.userData) {
    res.redirect('/login')
  } else {
    next()
  }
}
....
</code></pre>



<p>If a user is not logged in the request should be redirected to the login roure, in any other case (user is logged in) the next routing function <code>function(req, res)</code> is called and respond the HTML to the browser. This middleware 2 is included in the <strong>/dashboard-</strong> and <strong>/logout</strong> route. This mean not logged in users will be redirected to login route, logged in users will see the dashboard- or can log themselves out. </p>



<p><strong>post routes:</strong> We have the following <code>post</code> routes.</p>



<ul class="wp-block-list"><li>/login</li><li>/register<br></li></ul>



<p>The login and the register <code>get</code> routes contain a form in the HTML. With these forms the user provide the data to login and for user registration. When the user click the send button the <em>action</em> is to call the login- or register <code>post</code> route. This will happen for all not logged in users. The login and the register <code>get</code> routes have the middleware <code>redirectDashboard</code>to redirect the user to the dashbard if the user is already logged in.<br></p>



<pre class="wp-block-code"><code>// secserver.js
....

app.get('/login', redirectDashboard, (req, res) =&gt; {
....
res.send(`
....
&lt;div class="form"&gt;
	&lt;form id='register_form' method='post' action='/register'&gt;
	......
	&lt;label for='send'&gt;
   		&lt;input class='sendbutton' type='submit' name='send' value='Send'&gt;
	&lt;/label&gt;
	&lt;/form&gt;
&lt;/div&gt;

`)
)}
....

app.get('/register', redirectDashboard, (req, res) =&gt; {
....
res.send(`
....
&lt;div class="form"&gt;
	&lt;form id='login_form' method='post' action='/login'&gt;
	......
	&lt;label for='send'&gt;
   		&lt;input class='sendbutton' type='submit' name='send' value='Send'&gt;
	&lt;/label&gt;
	&lt;/form&gt;
&lt;/div&gt;
`)
)}
.....
</code></pre>



<p>The <code>post</code> routes contain functions to login- (loginUser) or register (createUser) the user.<br></p>



<pre class="wp-block-code"><code>// secserver.js
....
// Post routes to manage user login and user registration
app.post('/login', userController.loginUser);

app.post('/register', userController.createUser);
....
</code></pre>



<p>The <code>loginUser</code> function is defined in the user controller <code>database/controllers/userC.js</code>. This function lookup a user in the database based on the email address that has been provided by the request body. The data that are attached to the request body have been provided by the user vie the login form of the app. If no user could be found in the database login is not possible. If a user exist with the given email address then the provided password will be compared with the one stored in the database. If the password match fail login is not possible because the provided password is wrong. in any other case, the login takes place and a userData object is created and attached to the session object.</p>



<pre class="wp-block-code"><code>// database/controllers/userC.js

User.findOne({ email: req.body.email }, function(error, user) {
  if (!user) {
    res.status(400).send({ code: 400, status: 'Bad Request', message: 'No User found with this email' })

    } else {
      if (bcrypt.compareSync(req.body.password, user.password)) {
    
        var userData = { userId: user._id, name: user.name, lastname: user.lastname, email: user.email, role: user.role }

          req.session.userData = userData

          res.redirect('/dashboard')

        } else {
          res.status(400).send({ code: 400, status: 'Bad Request', message: 'Wrong User password' })
        }

      }
    })

  }
</code></pre>



<p>The <code>createUser</code> function is also defined in the user controller <code>database/controllers/userC.js</code>. This function create a new User object based on the data from the request body provided by the user via the form. The provided password will be hashed and stored together with all other data into the database. Finally a userData object is created and attached to the session and the user will be redirected to the dashboard after the registration was successful.<br></p>



<pre class="wp-block-code"><code>// database/controllers/userC.js

createUser: async function (req, res) {
    // assign input data from request body to input variables
    const name = req.body.name
    const lastname = req.body.lastname
    const email = req.body.email
    const password = req.body.password
    const role = req.body.role

    const newUser = new User({
      name: name,
      lastname: lastname,
      email: email,
      password: password,
      role: role
    })

    newUser.password = await bcrypt.hash(newUser.password, saltRounds)

    await newUser.save(function(err, user) {
          if (err) {
            // if a validation err occur end request and send response
            res.status(400).send({ code: 400, status: 'Bad Request', message: err.message })
          } else {
            // req.session.userId = user._id

            var userData = { userId: user._id, name: user.name, lastname: user.lastname, email: user.email, role: user.role }

            req.session.userData = userData

            res.redirect('/dashboard')
          }
        })
  },
</code></pre>



<p>And we have a default <code>get</code> route.</p>



<ul class="wp-block-list"><li>/favicon.ico<br></li></ul>



<p>Browsers will by default try to request /favicon.ico from the root of a hostname, in order to show an icon in the browser tab. As we dont use favicon so far we must avoid that these requests returning a 404 (Not Found). Here The /favicon.ico request will be catched and send a 204 No Content status.</p>



<pre class="wp-block-code"><code>// secserver.js
....
app.get('/favicon.ico', function(req, res) {
    console.log(req.url);
    res.status(204).json({status: 'no favicon'});
});
....
</code></pre>



<h3 class="wp-block-heading">3. Express App (Pug Template Version)</h3>



<p>From a functional point of view this app is pretty much the same app then the HTML version. The difference is that we use PUG templates instead of HTML in each res.send().</p>



<h4 class="wp-block-heading">Setup a seperate Database</h4>



<p>For the PUG version of my app I set up a new database to manage the users and the sessions.</p>



<pre class="wp-block-code"><code>#&gt; mongo

MongoDB shell version v4.2.3
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&amp;gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("b3e7f48a-a05c-4894-87db-996cb34eb1fb") }
MongoDB server version: 4.2.3

&gt; db
test

&gt; use admin
switched to db admin

&gt; db
admin

&gt; db.auth("adminUser", "adminpassword")
1

&gt; show dbs
admin               0.000GB
config              0.000GB
express-security    0.000GB
local               0.000GB

&gt; use express-security-pug
switched to db express-security-pug

&gt; db.createUser({ user: "owner_express-security-pug", pwd: "passowrd", roles: &#91;{ role: "dbOwner", db: "express-security-pug" }] })

Successfully added user: {
    "user" : "owner_express-security-pug",
    "roles" : &#91;
        {
            "role" : "dbOwner",
            "db" : "express-security-pug"
        }
    ]
}

&gt; db
express-security-pug

&gt; exit
</code></pre>



<p>Connection string to connect to express-security-pug db using the owner_express-security-pug user.</p>



<pre class="wp-block-code"><code>mongodb://owner_express-security-pug:password@localhost/express-security-pug
</code></pre>



<h4 class="wp-block-heading">Download the code from GitHub</h4>



<p>Pls. <a href="https://github.com/prottlaender/node-part-5-express-security-with-db-pug">go to my GitHub site</a> and clone the code. Here you find some inline documentation in the code.</p>



<h4 class="wp-block-heading">Create your app home directory express-security-pug</h4>



<p>My app home directory is different to the one that is available after you cloned the code from GitHub. </p>



<pre class="wp-block-code"><code>Patricks-MBP:2020-05-15-express-security patrick$ pwd
/Users/patrick/software/dev/node/articles/2020-05-15-express-security

Patricks-MBP:2020-05-15-express-security patrick$ mv node-part-5-express-security-with-db-pug express-security-pug

Patricks-MBP:2020-05-15-express-security patrick$ cd express-security-pug

Patricks-MBP:express-security-pug patrick$ pwd
/Users/patrick/software/dev/node/articles/2020-05-15-express-security/express-security-pug
</code></pre>



<h4 class="wp-block-heading">Install PUG and use it in your app</h4>



<p>First we install <a href="https://pugjs.org/api/getting-started.html">PUG</a> as a dependency. </p>



<pre class="wp-block-code"><code>Patricks-MBP:express-security-pug patrick$ pwd
/Users/patrick/software/dev/node/articles/2020-05-15-express-security/express-security-pug

Patricks-MBP:express-security-pug patrick$ npm install pug --save
</code></pre>



<p><a href="https://pugjs.org/api/getting-started.html">PUG</a> is already <a href="https://pugjs.org/api/express.html">fully integrated</a> into Express. Pls. read the documentation <a href="https://expressjs.com/en/guide/using-template-engines.html">how to use template engines in Express</a>. </p>



<p>After you installed PUG the view engine must be set in your main application file <em>secserverpug.js</em>.</p>



<pre class="wp-block-code"><code>// secserverpug.js
....
// use Pug Template Engine
app.set('view engine', 'pug')
app.set('views', './views')
....
</code></pre>



<p>These instructions tell your app that PUG template engine is used and that the templates can be found in <code>/views</code> directory.</p>



<h4 class="wp-block-heading">PUG Directory setup</h4>



<p>In <code>/views</code> I setup the templates for home, login, registration and an error template. </p>



<p>In <code>/views/includes</code> I setup the files containing HTML or JavaScript. These can be included in the templates. </p>



<pre class="wp-block-code"><code>Patricks-MBP:express-security-pug patrick$ ls -l
total 128
-rw-r--r--    1 patrick  staff    771  1 Jul 06:04 README.md
drwxr-xr-x    5 patrick  staff    160 29 Jun 05:26 database
drwxr-xr-x  150 patrick  staff   4800 29 Jun 06:11 node_modules
-rw-r--r--    1 patrick  staff  47547 29 Jun 06:11 package-lock.json
-rw-r--r--    1 patrick  staff    367 29 Jun 06:11 package.json
-rw-r--r--    1 patrick  staff   4393  2 Jul 05:34 secserverpug.js
drwxr-xr-x    3 patrick  staff     96 29 Jun 05:26 static
drwxr-xr-x    8 patrick  staff    256  2 Jul 05:45 views

Patricks-MBP:express-security-pug patrick$ ls -l views
total 40
-rw-r--r--  1 patrick  staff   549 30 Jun 05:35 dashboard.pug
-rw-r--r--  1 patrick  staff   522  2 Jul 05:50 err.pug
-rw-r--r--  1 patrick  staff   420 29 Jun 05:39 home.pug
drwxr-xr-x  6 patrick  staff   192 29 Jun 05:17 includes
-rw-r--r--  1 patrick  staff   735 30 Jun 05:02 login.pug
-rw-r--r--  1 patrick  staff  1067 30 Jun 05:08 register.pug

Patricks-MBP:express-security-pug patrick$ ls -l views/includes
total 32
-rw-r--r--  1 patrick  staff   76 29 Jun 05:39 foot.pug
-rw-r--r--  1 patrick  staff  167 29 Jun 05:24 head.pug
-rw-r--r--  1 patrick  staff  489  2 Jul 05:13 nav.pug
-rw-r--r--  1 patrick  staff  420 29 Jun 05:08 script.js

Patricks-MBP:express-security-pug patrick$ 
</code></pre>



<h4 class="wp-block-heading">The responsive Website Design</h4>



<p>Each site like <em>home</em>, <em>login</em>, <em>register</em> and <em>dashboard</em> has a <strong>specific site template</strong> in <code>/views</code> directory. The site content will be defined in the <em>main section</em> of each template. PUG enables files with HTML or JavaScript to be included. This makes the <em>site templates</em> clear and easy to maintain. The <strong>includes</strong> are located in <code>/views/includes</code> directory.</p>



<p>The website is build based on a grid design and each site template has the following structure.</p>



<pre class="wp-block-code"><code>doctype html

HTML

	Head
		include includes/head.pug	
	
	Body
		
		Grid-Container
			
				Header
					include includes/nav.pug
			
				Main
					... site template specific HTML ...
			
				Footer
					include includes/foot.pug
					
		&lt;script&gt;
			  include includes/script.js

</code></pre>



<p>The design of the website is defined in the css in <code>static/css/style.css</code>.</p>



<p>Here in the css we define the <strong>Site Structure</strong> as <em>grid areas</em> consisting of header, main and footer and link them to the <em>grid-container</em>. </p>



<pre class="wp-block-code"><code>....

.header { grid-area: header; background-color: #ffffff; border-radius: 5px;}
.main { grid-area: main; background-color: #ffffff; border-radius: 5px;}
.footer { grid-area: footer; background-color: #ffffff; border-radius: 5px;}

.grid-container {
  display: grid;
  grid-template-areas:
      "header"
      "main"
      "footer";
  grid-gap: 5px;
  background-color: #d1d1e0;
  padding: 50px;
}

....
</code></pre>



<p>The <strong>Navigation</strong> is defined in the Header area of the Grid-Container and the HTML comes into the template via <code>include includes/nav.pug</code>.</p>



<pre class="wp-block-code"><code>// includes/nav.pug

//(this) refers to the DOM element to which the onclick attribute belongs to
// the a DOM element will be given as parameter to the function

a(class="burgericon" onclick="myFunction(this)")
  div(class='burgerline' id='bar1')
  div(class='burgerline' id='bar2')
  div(class='burgerline' id='bar3')

a(class='link' href='/') Home
a(class='link' href='/login') Login
a(class='link' href='/register') Register
a(class='link' href='/dashboard') Dashboard
a(class='link' href='/logout') Logout
</code></pre>



<p>So the navigation design is then defined in the css. Each navigation object is an <code>a</code> link. We have <code>a</code> links with class <code>link</code> and <code>burgericon</code>. The burgericon is used to open the navigation bar onclick when the screen is smaller than 600px (like iphone displays etc., explained below), is cosisting of 3 burgerlines and these lines are created using 3 div objects with class <code>burgerline</code>. The burgelines will be transformed with speed 0.4s when you click on the burgericon (explained below). The burgericon is not visible and aligned on the right edge. All other navigation links are visible and aligned on the left edge.<br></p>



<pre class="wp-block-code"><code>/* static/css/style.css */
....

/* style the navigation links with float on the left (side by side) */
.header a.link {
  float: left;
  display: block;
  padding: 14px 16px;
  text-decoration: none;
  font-size: 1.4vw;
  color: #28283e;
}

/* hover effect for each navigation link */
.header a.link:hover {
  background-color: #28283e;
  color: #ffffff;
}

/* style the burgericon link on the right */
.header a.burgericon {
  float: right;
  display: none;
  padding: 14px 16px;
}

/* style each burgerline that create the burgericon */
.burgerline {
  width: 35px;
  height: 5px;
  background-color: #28283e;
  margin: 6px 0;
  transition: 0.4s;
}
....
</code></pre>



<p>When the display screen is lower than 600px the navigation links will not be shown and the burgericon (on the right side) will be faded in instead. </p>



<pre class="wp-block-code"><code>/* static/css/style.css */
....
/* for screens up to 600px remove the navigation links and show the burgericon instead */
@media screen and (max-width: 600px) {
  .header a.link { display: none; }
  .header a.burgericon { display: block; }
}
....
</code></pre>



<p>When you click on the burgericon the burgerlines will be transformed so that you will see a cross instead of the hamburger like icon. The 2nd burgerline with <code>id='bar2'</code> will not be shown at all while the other 2 burgelines will be rotated 45 degrees counterclockwise (burgerline with <code>id='bar1'</code>) and clockwise (burgerline with <code>id='bar1'</code>). </p>



<pre class="wp-block-code"><code>/* static/css/style.css */
....
/* style burgerlines after on onclick event */
/* the .change class will be added onclick with classList.toggle in the JavaScript */
/* rotate first bar */
.change #bar1 {
  /* rotate -45 degrees (counterclockwise) move 15px down in Y-direction */
  transform: rotate(-45deg) translateY(15px);
}
/* fade out the second bar */
.change #bar2 {
  opacity: 0;
}
/* rotate third bar */
.change #bar3 {
  /* rotate +45 degrees (clockwise) move 15px up in Y-direction */
  transform: rotate(45deg) translateY(-15px);
}
....
</code></pre>



<p>After clicking on the burgericon, the burgerlines are transformed as described. The links of the navigation menu are displayed one below the other (float none) and aligned left.</p>



<pre class="wp-block-code"><code>/* static/css/style.css */
....
/* for screens up to 600px and after onclick event the responsive class will be added to the header */
@media screen and (max-width: 600px) {
  /* show navigation links left with no float (links shown among themselves) */
  .header.responsive a.link {
    float: none;
    display: block;
    text-align: left;
  }
}
....
</code></pre>



<p>All onclick functionalities are controlled by the javascript which is embedded in the HTML of each site template (pls see above includes/nav.pug). In the HTML, the onclick event is initiated in the burgericon link and the function myFunction is called with <code>onclick =" myFunction(this) "</code>. With the parameter <em>this</em> the entire burgericon object is transferred to the javascript function.</p>



<p>With each click on the burger icon, the class <code>change</code> is added to each burgerline or, if available, removed. This is done by the toggle() function. If <code>change</code> is set, the hamburg icon is transformed into a cross according to the specification in the css (see above). If <code>change</code> is withdrawn with a new click, the hamburger icon is displayed again.</p>



<p>But it happens even more in the javascript when you click on the hamburger icon. The element that has the id <code>responsivenav</code> is searched for and the variable<code>reponsiveNavElement</code> is assigned to this element. Is the class of the reponsiveNavElement <code>header</code> the class<code>responsive</code> is added after clicking on the hamburger icon. If the class <code>responsive</code> is set, as described above, the links of the navigation menu are displayed one below the other (float none) and aligned left. So it applies in the css <code>.header.responsive a.link {....}</code></p>



<p>In all other cases only the class <code>header</code> is set. So it applies in the css <code>.header a.link {....}</code> and the navigation links are not shown. </p>



<pre class="wp-block-code"><code>// includes/script.js

// the (burgerlines) parameter represent the DOM element that has been given to the function
function myFunction(burgerlines) {
  burgerlines.classList.toggle('change');

  var reponsiveNavElement = document.getElementById('responsivenav');
    if (reponsiveNavElement.className === 'header') {
      reponsiveNavElement.classList.add('responsive')
    } else {
      reponsiveNavElement.className = 'header';
    }
  }

</code></pre>



<p>Finally at the end of the css we define the defaults for <em>h1</em>, for our text content, the forms, the input fields and the send buttons.<br></p>



<h3 class="wp-block-heading">Summary and Outlook</h3>



<p>In this part 4 of my little node.js series we have seen how to setup a production ready environment for our express app. I showed this using a Mac OS, but in principle this setup also applies to Linux, for example.</p>



<p>The basic setup is, to put it simply, the app runs as a service on the server in the background using a Process Manager, but has no interface to the client. This client interface regulates a reverse proxy which is upstream of the app and accepts all requests and forwards them to the app, as well as the responses from the app back to the client. The communication is SSL/TLS secured.</p>



<p>At the center of the setup is a separate local MongoDB that manages all application data. In our example, these are the users, but also the sessions. I prefer to set up my own MongoDB on my server but of course it is conceivable to use a cloud-based solution or to install another database locally.</p>



<p>The express app itself uses secure HTTP response headers so that HTTP attacks like <em>clickjacking</em>, <em>MIME type sniffing</em> or some <em>smaller XSS attacks</em> on the client are made as difficult as possible. Access to personal areas of the application is secured by session-based authentication and authorization. The session-relevant data is stored in the database and not in the browser cookie, which means additional security with regard to attacks on the client. The browser cookie only contains a hash of the session ID to query the relevant user data from the database.</p>



<p>I would like to end my node.js series with Part 4. I discussed and demonstrated the basic concepts and procedures in parts 1 to 4. Of course there will be other interesting articles on the topic node.js and web programming on <a href="https://digitaldocblog.com">Digitaldocblog</a>. Just take a look.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>node.js and npm on Mac OS</title>
		<link>https://digitaldocblog.com/mac/nodejs-and-npm-on-mac-os/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 10 Sep 2019 17:00:00 +0000</pubDate>
				<category><![CDATA[Mac OS]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[NPM Node package manager]]></category>
		<guid isPermaLink="false">https://digitaldocblog.com/?p=61</guid>

					<description><![CDATA[node.js (or simply node) basically is a server side programming language to run JavaScript Code outside the browser. With node a developer can create server side programs in Java Script.&#8230;]]></description>
										<content:encoded><![CDATA[
<p><a href="https://nodejs.org/en">node.js</a> (or simply node) basically is a server side programming language to run JavaScript Code outside the browser. With node a developer can create server side programs in Java Script.</p>



<p>node contain various modules directly compiled into the node package like modules to access the network in asynchrons mode or modules to access the file system. Furthermore other modules can be embedded. These are precompiled files with .node extension or JavaScript modules. To manage these modules for node the <a href="https://docs.npmjs.com">node package manager (npm)</a> exist. The npm package repository has more than 700.000 packages that can be installed with the npm package manager.<br></p>



<h3 class="wp-block-heading">Installation of node and npm</h3>



<p>node can be installed on a Mac with <a href="https://brew.sh/index_de">homebrew</a>. <a href="https://nodejs.org/en">node</a> comes with <a href="https://docs.npmjs.com">npm</a>.</p>



<p>Before node can be installed it must be checked if xcode command line tools are installed on the system.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ xcode-select -p
/Library/Developer/CommandLineTools
Macbook Pro:~ user$

</code></pre>



<p>The above command return that xcode command line tools are installed on your Mac and show the directory path where xcode command line tools are installed.</p>



<p>In case xcode command line tools are not installed run the following command in shell:</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ xcode-select --install

</code></pre>



<p>Then it must be checked if Homebrew is installed.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ brew --version
Homebrew 1.7.7
Homebrew/homebrew-core (git revision 45d56; last commit 2018-10-08)
Homebrew/homebrew-cask (git revision 33e4d; last commit 2018-10-09)
Macbook Pro:~ user$

</code></pre>



<p>The above output show Homebrew 1.7.7 is installed on the Mac. In case Homebrew is not istalled so far run the follwoing command from shell:</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

</code></pre>



<p>Check the Homebrew installation.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ brew doctor
Your system is ready to brew.
Macbook Pro:~ user$

</code></pre>



<p>To start with the node installation run the following command from shell:</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ brew install node

</code></pre>



<p>After installation Homebrew created symlinks for node and npm in <code>/usr/local/bin</code> and symlink to the location where the relevant binaries have been installed.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ ls -l /usr/local/bin
total 8

....

lrwxr-xr-x  1 patrick  admin   30  5 Jun 09:04 node -&gt; ../Cellar/node/14.4.0/bin/node
lrwxr-xr-x  1 patrick  admin   38  5 Jun 14:22 npm -&gt; ../lib/node_modules/npm/bin/npm-cli.js

....

</code></pre>



<p>We see that node has been installed in</p>



<p><code>/usr/local/Cellar/node/14.4.0/bin/node</code></p>



<p>and npm has been installed in </p>



<p><code>/usr/local/lib/node_modules/npm/bin</code></p>



<h3 class="wp-block-heading">npm package management</h3>



<p>npm install software packages always in <code>node_modules</code> directory. If you have not installed any software oackages with npm so far this directory does not exist and will be created during the installation process.</p>



<p>The installation of a software package with npm will be started with the following command.</p>



<p><code>npm install &lt;package&gt;</code> </p>



<p>You can install software packages as <em>Global Software Packages</em> or as <em>Local Software Packages</em>. </p>



<h3 class="wp-block-heading">Global Software Packages</h3>



<p>If you want to use a software not only within a specific project but in global context on your machine then you provide the <code>-g</code> option in the install command.</p>



<p><code>npm install -g &lt;package&gt;</code></p>



<p>Then npm install this package in a global <code>node_modules</code> directory. </p>



<p><code>{prefix}/lib/node_modules</code></p>



<p>The <code>prefix</code> can be determined as follows</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ npm config get prefix
/usr/local
Macbook Pro:~ user$

</code></pre>



<p>On my machine all global packages are installed under </p>



<p><code>/usr/local/lib/node_modules</code></p>



<p>To list all installed global packages on your machine you can <code>ls -l</code> the global <code>node_modules</code> directory.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:~ patrick$ ls -l /usr/local/lib/node_modules
total 0
drwxr-xr-x  24 patrick  admin  768  5 Jun 14:22 npm
drwxr-xr-x  21 patrick  admin  672  5 Jun 14:21 pm2

</code></pre>



<p>You can also list all global packages with the npm command.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ npm list -g --depth=0
/usr/local/lib
├── firebase-tools@5.0.1
└── npm@6.4.1
Macbook Pro:~ user$
</code></pre>



<p>To maintain your global packages run the following commands.</p>



<p>Check for outdated global packages</p>



<p><code>npm outdated -g --depth=0</code></p>



<p>Update a specific global package</p>



<p><code>npm update -g &lt;package&gt;</code></p>



<p>Update all global packages</p>



<p><code>npm update -g</code></p>



<h3 class="wp-block-heading">Local Software Packages</h3>



<p>Local Software Packages are dependencies of a node project. This mean these software packages are required by the project code to run correctly. </p>



<p>If you want to use a software package only in the context of a node project then you create a separate project subfolder on your system and change to this subfolder with <code>cd</code>. Any software package that will be installed under this subfolder is a dependency of your node project. </p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:test patrick$ pwd
/Users/patrick/Software/dev/node/test

Patricks-Macbook Pro:test patrick$ cd mytestproject

Patricks-Macbook Pro:mytestproject patrick$ pwd
/Users/patrick/Software/dev/node/test/mytestproject

Patricks-Macbook Pro:mytestproject patrick$ 

</code></pre>



<p>Now you are in the <code>mytestproject</code> application root directory. Run the command <code>npm init</code> from the application root directory.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:mytestproject patrick$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install &lt;pkg&gt;` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (mytestproject) 
version: (1.0.0) 
description: This is my Test Project
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: Patrick Rottlaender
license: (ISC) 
About to write to /Users/patrick/Software/dev/node/test/mytestproject/package.json:

{
  "name": "mytestproject",
  "version": "1.0.0",
  "description": "This is my Test Project",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;&amp; exit 1"
  },
  "author": "Patrick Rottlaender",
  "license": "ISC"
}


Is this OK? (yes) yes
Patricks-Macbook Pro:mytestproject patrick$ ls -l
total 8
-rw-r--r--  1 patrick  staff  251 14 Jun 08:58 package.json

Patricks-Macbook Pro:mytestproject patrick$

</code></pre>



<p>A package.json file has been created in your application root directory. This package.json file contain meta data about your project. Now we create the index.js file as our main application file for the project.</p>



<p>You can name the main application file as you like. It is only important that under &#8222;main&#8220; in the package.json file the file name match with the main application file name in your project root directory.</p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:mytestproject patrick$ touch index.js

Patricks-Macbook Pro:mytestproject patrick$ ls -l
total 8
-rw-r--r--  1 patrick  staff    0 14 Jun 09:08 index.js
-rw-r--r--  1 patrick  staff  251 14 Jun 08:58 package.json

Patricks-Macbook Pro:mytestproject patrick$
</code></pre>



<p>Dependencies are installed as local packages from a project root directory running the following command.</p>



<p><code>npm install &lt;package_name&gt; --save</code></p>



<p>npm will then create a <code>node_modules</code> directory under your project root directory and install the local packages there (incl. the dependencies of this new local package if there are any). npm will also create a <code>package-lock.json</code> file containing the current complete directory tree of all dependencies. </p>



<p>The package.json file is adapted and the new local software package is entered there as a dependency.</p>



<p>I have taken the following example 1:1 from the <a href="https://www.taniarascia.com/how-to-install-and-use-node-js-and-npm-mac-and-windows">website of Tanja Rascia</a>. If you want to read more details pls. go to Tanjas website. </p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:mytestproject patrick$ npm install left-pad --save

npm WARN deprecated left-pad@1.3.0: use String.prototype.padStart()
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN mytestproject@1.0.0 No repository field.

+ left-pad@1.3.0
added 1 package from 1 contributor and audited 1 package in 0.974s
found 0 vulnerabilities

Patricks-Macbook Pro:mytestproject patrick$ ls -l
total 16
-rw-r--r--  1 patrick  staff    0 14 Jun 09:08 index.js
drwxr-xr-x  3 patrick  staff   96 14 Jun 09:27 node_modules
-rw-r--r--  1 patrick  staff  366 14 Jun 09:27 package-lock.json
-rw-r--r--  1 patrick  staff  301 14 Jun 09:27 package.json

Patricks-Macbook Pro:mytestproject patrick$ cat package.json
{
  "name": "mytestproject",
  "version": "1.0.0",
  "description": "This is my Test Project",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;&amp; exit 1"
  },
  "author": "Patrick Rottlaender",
  "license": "ISC",
  "dependencies": {
    "left-pad": "^1.3.0"
  }
}
Patricks-Macbook Pro:mytestproject patrick$ 
</code></pre>



<p>After this we can write the code in <code>index.js</code> and use the functionality of <code>left-pad</code>. Therefore we must require the dependency at the beginning of the code.</p>



<pre class="wp-block-code"><code>// index.js

const leftPad = require('left-pad') // Require left pad
const output = leftPad('Hello, World!', 15) // Define output

// Send output to the console
console.log(output)

</code></pre>



<p>We run the programm using the following command and get the output on the console. </p>



<pre class="wp-block-code"><code>Patricks-Macbook Pro:mytestproject patrick$ node index.js
  Hello, World!
Patricks-Macbook Pro:mytestproject patrick$

</code></pre>



<p>For more information about npm and package management pls. check the getting started section on <a href="https://docs.npmjs.com">npm documentation site</a> and the <a href="https://www.npmjs.com">npm website</a> .</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Homebrew Package Manager on Mac OS</title>
		<link>https://digitaldocblog.com/mac/homebrew-package-manager-on-mac-os/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Mon, 22 Oct 2018 16:06:00 +0000</pubDate>
				<category><![CDATA[Mac OS]]></category>
		<category><![CDATA[Homebrew]]></category>
		<guid isPermaLink="false">https://digitaldocblog.com/?p=57</guid>

					<description><![CDATA[Most of the Mac OS users install software via the Apple App store or download a .dmg file from the Internet and run an installation script to install the software&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Most of the Mac OS users install software via the Apple App store or download a .dmg file from the Internet and run an installation script to install the software on the Mac. Applications that will be installed this way are installed into the Application folder of your Mac.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ ls -l /Applications
total 0
drwxr-xr-x@  3 root     wheel   96 11 Jul 19:10 App Store.app
drwxr-xr-x@  3 root     wheel   96 21 Jun 18:48 Automator.app
drwxr-xr-x@  3 user     admin   96 14 Jun 09:32 Brackets.app
drwxr-xr-x@  3 root     wheel   96 21 Jun 18:48 Calculator.app
drwxr-xr-x@  3 root     wheel   96 21 Jun 18:48 Calendar.app
drwxr-xr-x@  3 root     wheel   96 11 Jul 19:10 Chess.app
drwxr-xr-x   3 user     admin   96  2 Okt 07:18 CleanMyMac 3.app
drwxr-xr-x   3 user     admin   96 19 Feb  2018 ClipGrab.app
drwxr-xr-x@  3 root     wheel   96 11 Jul 19:10 Contacts.app
drwxr-xr-x@  3 root     wheel   96 21 Jun 18:48 DVD Player.app

........

</code></pre>



<p>An alternative way to install software in your Mac is using a package manager like <a href="https://brew.sh">Homebrew</a>. With Homebrew you have access to a large number of free software packages developed by developers for the installation via Homebrew.</p>



<h3 class="wp-block-heading">Homebrew installation</h3>



<p>Check if xcode command line tools are installed.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ xcode-select -p
/Library/Developer/CommandLineTools
Macbook Pro:~ patrick$

</code></pre>



<p>The above command return that xcode command line tools for xcode (CLT) are installed on your Mac and show the directory path where xcode command line tools are installed.</p>



<p>In case xcode command line tools are not installed run the following command in shell:</p>



<pre class="wp-block-code"><code>xcode-select --install

</code></pre>



<p>Check if Homebrew is (already) installed.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ brew --version
Homebrew 1.7.7
Homebrew/homebrew-core (git revision 45d56; last commit 2018-10-08)
Homebrew/homebrew-cask (git revision 33e4d; last commit 2018-10-09)
Macbook Pro:~ user$

</code></pre>



<p>The above output show Homebrew 1.7.7.</p>



<p>In case Homebrew is not istalled run the follwoing command from shell to install Homebrew:</p>



<pre class="wp-block-code"><code>ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

</code></pre>



<p>If you run the above shown ruby script you will be asked to run the following command.</p>



<pre class="wp-block-code"><code>/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

</code></pre>



<p>Check the Homebrew installation.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ brew --version
Homebrew 1.7.7
Homebrew/homebrew-core (git revision 02721; last commit 2018-10-21)
Homebrew/homebrew-cask (git revision 4bcf; last commit 2018-10-22)

Macbook Pro:~ user$ brew doctor
Your system is ready to brew.
Macbook Pro:~ user$

</code></pre>



<p>The shell output show that Homebrew version 1.7.7 is installed on the system and that you are ready to brew which means that you are ready to install software.</p>



<h3 class="wp-block-heading">Homebrew Software Repositories and Tap(s)</h3>



<p>With Homebrew package manager you have access to a wide range of software that can be installed on your system. After Homebrew has been installed on your system you find Homebrew under <code>/usr/local/Homebrew</code> on your system. </p>



<p>In principle, Homebrew differentiates between Core Software Packages, Non-Core Software Packages and so-called Cask(s). These Software Packages are available in GitHub Repositories or so called Tap(s).<br></p>



<p>Core Software Packages are free software developed from developers around the world to be installed on Mac OS platforms using Homebrew. Core software will be installed based on so called formulae. A formula contain the basic package definition and tell Homebrew i.e. how a package should be installed. This mean a formula of a certain software package contain the required information for the installation such as i.e. from where the installation files should be loaded, which dependencies exist and how the installation should be performed on the different Mac platforms. All formulae for Core Software Packages have been loaded from Homebrew&#8217;s GitHub Core-Repository-Tap <a href="https://github.com/Homebrew/homebrew-core">Homebrew/homebrew-core</a> into <code>/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula</code>on your machine. </p>



<p>It is also possible that Software can be installed with Homebrew but the formula is not available on Homebrew&#8217;s GitHub Core-Repository-Tap. Then we speak of Non-Core Software Packages because these Software Packages are not <code>tap(ed)</code> into the Homebrew Core-Repository-Tap. In this case you must first <code>tap</code> the Non-Core-Repository-Tap to let Homebrew know from where it should load the formula to install the software package. </p>



<p>Cask software or <code>Casks</code> are native Mac OS Apps like Google Chrome, Firefox or other native Mac OS Apps that can be also installed using the Homebrew Package Manager. All available Casks to install Mac OS native Apps have been loaded from Homebrew&#8217;s GitHub Profile <a href="https://github.com/Homebrew/homebrew-cask">Homebrew/homebrew-cask</a> into <code>/usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask/Casks</code>.</p>



<p>To get an overview which tap(s) are currently linked to your Homebrew Installation use th efollowing command. </p>



<pre class="wp-block-code"><code>Patricks-MBP:~ patrick$ brew tap
homebrew/cask
homebrew/core
homebrew/services
mongodb/brew

</code></pre>



<h3 class="wp-block-heading">Where is Homebrew on your System</h3>



<p>Homebrew create symlinks for each installed package in <code>/usr/local/bin</code> and symlink the relevant binary. Usually this symlink will point to <code>/usr/local/Cellar/&lt;package_name&gt;/&lt;version&gt;/bin</code> but it can also be anywhere else on your system.</p>



<p>So lets <code>ls -l /usr/local/bin</code>:</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ ls -l /usr/local/bin
total 0
lrwxr-xr-x  1 user  admin  28 11 Nov  2016 brew -&gt; /usr/local/Homebrew/bin/brew
lrwxr-xr-x  1 user  admin  34  1 Nov  2017 ccmake -&gt; ../Cellar/cmake/3.9.4_1/bin/ccmake
lrwxr-xr-x  1 user  admin  33  1 Nov  2017 cmake -&gt; ../Cellar/cmake/3.9.4_1/bin/cmake
lrwxr-xr-x  1 user  admin  39  1 Nov  2017 cmakexbuild -&gt; ../Cellar/cmake/3.9.4_1/bin/cmakexbuild
lrwxr-xr-x  1 user  admin  33  1 Nov  2017 cpack -&gt; ../Cellar/cmake/3.9.4_1/bin/cpack
lrwxr-xr-x  1 user  admin  41 16 Dez  2016 cryptest.exe -&gt; ../Cellar/cryptopp/5.6.5/bin/cryptest.exe
lrwxr-xr-x  1 user  admin  33  1 Nov  2017 ctest -&gt; ../Cellar/cmake/3.9.4_1/bin/ctest
lrwxr-xr-x  1 user  admin  32  1 Nov  2017 evm -&gt; ../Cellar/ethereum/1.7.2/bin/evm

.......

</code></pre>



<p>Homebrew package manager binary is named <strong>brew</strong> and symlinked to <code>/usr/local/Homebrew/bin/brew</code>. The Homebrew package is installed in <code>/usr/local/Homebrew</code> This is the place on your system where Homebrew is installed.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ ls -l /usr/local/Homebrew
total 64
-rw-r--r--   1 user  admin    98 16 Dez  2016 CHANGELOG.md
-rw-r--r--   1 user  admin  3161  1 Nov  2017 CODE_OF_CONDUCT.md
-rw-r--r--   1 user  admin   827  9 Okt 07:38 CONTRIBUTING.md
-rw-r--r--   1 user  admin  1334  1 Nov  2017 LICENSE.txt
drwxr-xr-x   7 user  admin   224  9 Okt 07:38 Library
-rw-r--r--   1 user  admin  8471  9 Okt 07:38 README.md
-rw-r--r--   1 user  admin   899  9 Okt 07:38 azure-pipelines.yml
drwxr-xr-x   3 user  admin    96  9 Okt 07:38 bin
drwxr-xr-x   5 user  admin   160  1 Nov  2017 completions
drwxr-xr-x  49 user  admin  1568  9 Okt 07:38 docs
drwxr-xr-x   5 user  admin   160  9 Okt 07:38 manpages

</code></pre>



<h3 class="wp-block-heading">Where are Core Software Packages on your System</h3>



<p>Also the symlinks from other packages that you install with Homebrew have been created in <code>/usr/local/bin</code> directory and symlinked into <code>/usr/local/Cellar/...</code>. The Cellar is the place on your system where you usually find Homebrew installed software packages.</p>



<p>As you see on my system I have installed a couple of software packages like boost, cmake, node but also hugo which is my static website genrator.</p>



<pre class="wp-block-code"><code>Macbook Pro:~ user$ ls -l /usr/local/Cellar
total 0
drwxr-xr-x  4 user  admin  128  1 Nov  2017 boost
drwxr-xr-x  4 user  admin  128  1 Nov  2017 cmake
drwxr-xr-x  3 user  admin   96 16 Dez  2016 cryptopp
drwxr-xr-x  5 user  admin  160  1 Nov  2017 ethereum
drwxr-xr-x  4 user  admin  128  1 Nov  2017 gmp
drwxr-xr-x  5 user  admin  160  1 Nov  2017 go
drwxr-xr-x  4 user  staff  128  6 Okt 07:16 hugo
drwxr-xr-x  3 user  staff   96  3 Aug 06:48 icu4c
drwxr-xr-x  4 user  admin  128  1 Nov  2017 jsoncpp
drwxr-xr-x  4 user  staff  128  9 Okt 07:39 node
drwxr-xr-x  3 user  admin   96 12 Nov  2017 openssl
drwxr-xr-x  4 user  admin  128  1 Nov  2017 solidity

</code></pre>



<h3 class="wp-block-heading">Install and Uninstall Core Software</h3>



<p>To install formula with Homebrew to your system use the command.</p>



<p><code>brew install &lt;formula&gt;</code> </p>



<p>To uninstall a formula from your system simply use the command. </p>



<p><code>brew uninstall &lt;formula&gt;</code></p>



<p>After installation the software package exist in the Cellar. </p>



<p><code>/usr/local/Cellar/&lt;formula&gt;/&lt;version&gt;</code></p>



<h3 class="wp-block-heading">Update and Upgrade Core Software packages</h3>



<p>First you update all formulae and Casks using the following command.</p>



<p><code>brew update</code></p>



<p>or if you want to update only a specific formula</p>



<p><code>brew update &lt;formula&gt;</code></p>



<p>Then you upgrade all your software packages using the following command.</p>



<p><code>brew upgrade</code> </p>



<p>or if you want to upgrade only a specific formula</p>



<p><code>brew upgrade &lt;formula&gt;</code></p>



<p>The upgrade command installs newer software versions of all packages in the Cellar. Depending on the amount of packages you have installed this might take some time.</p>



<h3 class="wp-block-heading">Where are Cask Software Packages on your System</h3>



<p>Cask software is installed in the following directory.</p>



<pre class="wp-block-code"><code>Patricks-MBP:~ patrick$ ls -l /usr/local/Caskroom
total 0
drwxr-xr-x  4 patrick  admin  128 11 Jun 09:00 opera

</code></pre>



<p>From the output above you can see that I installed a GUI software package with the help of Homebrew. It is the Opera browser. </p>



<p>The installation takes place in the following path <code>/usr/local/Caskroom/&lt;package_name&gt;/&lt;version&gt;/&lt;symlink&gt;</code>. The symlink point to the /Applications directory where Homebrew copy the app.</p>



<pre class="wp-block-code"><code>Patricks-MBP:~ patrick$ ls -l /usr/local/Caskroom/opera
total 0
drwxr-xr-x@ 3 patrick  admin  96 11 Jun 09:00 68.0.3618.165
Patricks-MBP:~ patrick$ ls -l /usr/local/Caskroom/opera/68.0.3618.165
total 0
lrwxr-xr-x  1 patrick  admin  23 11 Jun 09:00 Opera.app -&gt; /Applications/Opera.app
</code></pre>



<h3 class="wp-block-heading">Install and uninstall Cask GUI Software Packages</h3>



<p>When you install GUI Software the app must be copied into your Applications Directory. Here you need to provide your user password.</p>



<pre class="wp-block-code"><code>drwxr-xr-x  4 patrick  admin  128  9 Aug  2018 java
Patricks-MBP:~ patrick$ brew cask install opera
==&gt; Downloading https://get.geo.opera.com/pub/opera/desktop/68.0.3618.165/mac/Opera_68.0.3618.165_Setup.dmg
######################################################################## 100.0%
==&gt; Verifying SHA-256 checksum for Cask 'opera'.
==&gt; Installing Cask opera
==&gt; Moving App 'Opera.app' to '/Applications/Opera.app'.
Password:
&#x1f37a;  opera was successfully installed!
</code></pre>



<p>To uninstall GUI Software Packeges you simply provide the uninstall command like this. </p>



<pre class="wp-block-code"><code>Patricks-MBP:~ patrick$ brew cask uninstall java
==&gt; Uninstalling Cask java
==&gt; Removing launchctl service com.oracle.java.Helper-Tool
==&gt; Removing launchctl service com.oracle.java.Java-Updater
==&gt; Uninstalling packages:
com.oracle.jdk-10.0.2
com.oracle.jre
==&gt; Removing files:
/Library/Internet Plug-Ins/JavaAppletPlugin.plugin
/Library/Java/JavaVirtualMachines/jdk-10.0.2.jdk/Contents
/Library/PreferencePanes/JavaControlPanel.prefPane
/Library/Java/Home
/Library/Java/MacOS
==&gt; Removing directories if empty:
/Library/Java/JavaVirtualMachines/jdk-10.0.2.jdk
==&gt; Purging files for version 10.0.2,13:19aef61b38124481863b1413dce1855f of Cask java
</code></pre>



<h3 class="wp-block-heading">Update Cask GUI Software Packages</h3>



<p>To update Casks you can check if some Casks are outdated using the following command <code>brew cask outdated</code>. Outdated Casks can be updated using the <code>brew cask upgrade</code> command.</p>



<p>More detailed information regarding the brew cask usage can be found on <a href="https://github.com/Homebrew/homebrew-cask/blob/master/USAGE.md">Homebrew-Cask</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
