<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Peek Read Info (Posts about quick post)</title><link>https://peekread.info/</link><description></description><atom:link href="https://peekread.info/tags/quick-post.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2024 &lt;a href="mailto:dugite-code@peekread.info"&gt;Dugite-Code&lt;/a&gt; 
&lt;a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"&gt;
&lt;img alt="Creative Commons License BY-SA"
width="88px" height="31px" style="border-width:0; margin-bottom:12px;"
src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png"&gt;&lt;/a&gt;</copyright><lastBuildDate>Wed, 14 Feb 2024 06:35:19 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>The Hugo Switch</title><link>https://peekread.info/blog/20240214-the-hugo-switch/</link><dc:creator>Dugite-Code</dc:creator><description>&lt;p&gt;I've decided to shake things up a bit, and I'm switching my blog over from &lt;a href="https://www.getnikola.com/"&gt;Nikola&lt;/a&gt; to &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Page Bundles and Obsidian&lt;/h2&gt;
&lt;p&gt;Page bundles offer great convenience for storing my blog posts in Obsidian. With Hugo, they group content along with associated resources like images and files. With this portability, I can store my posts within my note structure. While Nikola could provide similar capabilities to some extent, it's worth exploring alternatives, especially as I would have to rebuild my site anyway.&lt;/p&gt;
&lt;h2&gt;Better Asset Pipelines&lt;/h2&gt;
&lt;p&gt;One of the things that really drew me to Hugo is its asset pipeline. With image scaling, format conversion (hello, webp! Everyone hates you, but Google's bots sure don't), CSS and JS minification, Hugo makes my life easier. Plus, Hugo plays nice with deployment tools like purgecss, reducing the chances of mistakes with automation.&lt;/p&gt;
&lt;p&gt;I'm even using the &lt;code&gt;module.mounts&lt;/code&gt; feature to import my CSS and JS from a &lt;code&gt;node_modules&lt;/code&gt; folder, making it easier to keep them up to date.&lt;/p&gt;
&lt;h2&gt;I've Just Learned a Lot&lt;/h2&gt;
&lt;p&gt;I'll admit it—I've made my fair share of mistakes along the way with this blog. From opting for a basic Bootstrap theme with little to no dark mode support, to not optimizing my HTML as thoroughly as I could have, I've certainly had some learning moments. But it's all part of the learning experience, so I'll take this opportunity to start fresh.&lt;/p&gt;</description><category>quick post</category><guid>https://peekread.info/blog/20240214-the-hugo-switch/</guid><pubDate>Tue, 13 Feb 2024 16:00:00 GMT</pubDate></item><item><title>Using fdupes to cleanup my file server</title><link>https://peekread.info/tech/20230706-using-fdupes-to-cleanup-my-file-server/</link><dc:creator>Dugite-Code</dc:creator><description>&lt;h4&gt;The overall problem:&lt;/h4&gt;
&lt;p&gt;Like many of us, I am guilty of copying files haphazardly, promising myself that I'll organize them later. This has built up to a significant problem over the years, particularly with old smartphone backups. I had a bad habit of dumping photo folder backups onto my server, with each dump containing even more dumps of old photos, resulting in multiple levels of duplication. Using the command-line tool called &lt;code&gt;fdupes&lt;/code&gt; I've only just managed to get some of it under control.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fdupes&lt;/code&gt; is a command-line application designed to find and identify duplicate files within a directory or a set of directories. It employs various techniques to compare file contents and determine duplicates, enabling efficient cleanup and reclamation of storage space.&lt;/p&gt;
&lt;p&gt;To streamline the review process and make sure I know what's about to happen before deleting any files, I created a simple bash wrapper script. This script acts as a nice safety belt, preventing accidental fat finger deletions.&lt;/p&gt;
&lt;h4&gt;Avoiding the &lt;code&gt;rm -rf&lt;/code&gt; Pitfall:&lt;/h4&gt;
&lt;p&gt;As many of us have learned the hard way, the &lt;code&gt;rm -rf&lt;/code&gt; command can have disastrous consequences if misused (goodbye email server with 2000 emails). A simple typo or a wrong path can result in irreversible data loss. To mitigate this risk, the bash wrapper script avoids using &lt;code&gt;rm -rf&lt;/code&gt; altogether. Instead, it leverages the safer alternative of moving duplicate files to a temporary trash directory for review and then subsequent manual deletion.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;TRASH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/tmp/trash"&lt;/span&gt;

find_files&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;fdupes&lt;span class="w"&gt; &lt;/span&gt;-rn&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Duplicate files have listed in &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

remove_files&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Reading from &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Type yes to continue"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;choice
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$choice&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;yes&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TRASH&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;mv&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;line&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TRASH&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Duplicate files have been moved to &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TRASH&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Exiting"&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;getopts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rf:"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;option&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;option&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;r&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;f&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPTARG&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;dupes&lt;/span&gt;&lt;span class="p"&gt;.txt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="nb"&gt;shift&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="nv"&gt;OPTIND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$remove&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;remove_files
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;find_files&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;
&lt;span class="k"&gt;esac&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Understanding the Script:&lt;/h4&gt;
&lt;p&gt;The script utilizes the &lt;code&gt;fdupes&lt;/code&gt; command-line tool to identify duplicate files within a given directory or set of directories. Here's how it works:&lt;/p&gt;
&lt;h5&gt;Finding Duplicate Files:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;find_files&lt;/code&gt; function invokes the &lt;code&gt;fdupes&lt;/code&gt; command with the &lt;code&gt;-rn&lt;/code&gt; flags, instructing it to recursively search for duplicates and list the results in a specified file.&lt;/li&gt;
&lt;li&gt;If no file name is provided as an argument, the script will use the default file name &lt;code&gt;dupes.txt&lt;/code&gt; to store the duplicate file list.&lt;/li&gt;
&lt;li&gt;After the duplicates are found, the script informs us that the duplicate files have been listed in the &lt;code&gt;dupes.txt&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Removing Duplicate Files:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;remove_files&lt;/code&gt; function allows us to decide whether to remove the duplicates. Make sure to review the &lt;code&gt;dupes.txt&lt;/code&gt; file before running.&lt;/li&gt;
&lt;li&gt;If no file name is provided as an argument, the script will still refer to the default &lt;code&gt;dupes.txt&lt;/code&gt; file to read the duplicate file list.&lt;/li&gt;
&lt;li&gt;After printing the file listing the duplicates, the script prompts us to confirm our decision by typing "yes."&lt;/li&gt;
&lt;li&gt;If confirmed, the script creates a temporary trash directory and proceeds to move the duplicate files to it.&lt;/li&gt;
&lt;li&gt;Finally, it provides a message confirming that the duplicate files have been successfully moved to the trash directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Using the Script:&lt;/h4&gt;
&lt;p&gt;To utilize the script effectively, follow these steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copy the script into a text editor and save it as &lt;code&gt;ddup.sh&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Open a terminal and navigate to the directory containing the script.&lt;/li&gt;
&lt;li&gt;Make the script executable by running the command: &lt;code&gt;chmod +x ddup.sh&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Execute the script with appropriate options:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;To find duplicate files: &lt;code&gt;./ddup.sh &amp;lt;directory&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To remove duplicate files: &lt;code&gt;./ddup.sh -r&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: If you don't specify a file name using the &lt;code&gt;-f&lt;/code&gt; argument, it will default to using the &lt;code&gt;dupes.txt&lt;/code&gt; file for listing duplicate files.&lt;/p&gt;</description><category>fdupes</category><category>nextcloud</category><category>quick post</category><guid>https://peekread.info/tech/20230706-using-fdupes-to-cleanup-my-file-server/</guid><pubDate>Wed, 05 Jul 2023 16:00:00 GMT</pubDate></item><item><title>Readable Nginx configs</title><link>https://peekread.info/tech/20220907-readable-nginx-configs/</link><dc:creator>Dugite-Code</dc:creator><description>&lt;p&gt;&lt;/p&gt;&lt;div class="d-flex position-relative pt-3 pb-3"&gt;
    &lt;div class="flex-shrink-0 me-3"&gt;
        &lt;img data-pagefind-meta="image[src], image_alt[alt]" style="height:89px;" src="https://peekread.info/images/2019/0625-server-set-up-checklist/image01.png" alt="Configure your linux server"&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;p class="mt-3"&gt;&lt;/p&gt;&lt;p&gt;A recent project announcement on the subredit &lt;a href="https://www.reddit.com/r/selfhosted/comments/x7gpwd/making_nginx_easier_to_use_like_caddy/"&gt;/r/selfhosted&lt;/a&gt; reminded me to post about a simple trick I've started using to make the configuration of the webserver Nginx a little more ergonomic.&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Nginx allows you to include files inline in your configs to make re-using code simple. An example would be all your ssl proxy settings as per generated using the &lt;a href="https://ssl-config.mozilla.org/#server=nginx&amp;amp;version=1.17.7&amp;amp;config=modern&amp;amp;openssl=1.1.1k&amp;amp;guideline=5.6"&gt;Mozilla ssl-config&lt;/a&gt; generator.&lt;/p&gt;
&lt;p&gt;simply add this config to a file like &lt;code&gt;/etc/nginx/include.d/include.ssl_sec&lt;/code&gt; with your cert paths modified and include it in your config:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;upstream&lt;span class="w"&gt; &lt;/span&gt;example_service&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;server&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;127&lt;/span&gt;.0.0.1:8080&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;keepalive&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

server&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;server_name&lt;span class="w"&gt; &lt;/span&gt;example.tld&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;#Mozilla modern tls config&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;include&lt;span class="w"&gt; &lt;/span&gt;/etc/nginx/include.d/include.ssl_sec&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;location&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;#Common Proxy settings&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;include&lt;span class="w"&gt; &lt;/span&gt;/etc/nginx/include.d/include.proxy_settings&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;proxy_pass&lt;span class="w"&gt; &lt;/span&gt;http://example_service/&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you have a nice easy config file that can be easily used as a template for new services. Adding additional configurations to files really makes it quick and easy to deploy new services without needing complicated projects like Nginx Proxy Manager&lt;/p&gt;</description><category>nginx</category><category>quick post</category><guid>https://peekread.info/tech/20220907-readable-nginx-configs/</guid><pubDate>Tue, 06 Sep 2022 16:00:00 GMT</pubDate></item><item><title>The Depressing Age of the Walled Garden</title><link>https://peekread.info/blog/20201124-the-depressing-age-of-the-walled-garden/</link><dc:creator>Dugite-Code</dc:creator><description>&lt;p&gt;&lt;img alt="Sigh" class="float-left d-block text-center mr-3" height="64" loading="lazy" src="https://peekread.info/images/2020/1124-the-depressing-age-of-the-walled-garden/image01.png" width="64"&gt; I remember being excited for Android. The age of a popular Linux device was upon us! I had moved to Reddit and was seeing new and interesting things and opinions every day, The Internet and Tech was vibrant! I no longer feel this way.&lt;/p&gt;
&lt;div class="pb-3" style="clear: both;"&gt;&lt;/div&gt;

&lt;h4&gt;Android became heavily dependent on Google&lt;/h4&gt;
&lt;p&gt;Due to the quirks of the Mobile SOC's updating was... complicated. Add to that OEM customizations and you got a recipe for Google to swoop in and "fix" the issue by making key components, that used to part of the AOSP, proprietary. Where once we had the assurance of open development we now have even more black boxes of code being downloaded onto our mobile devices.&lt;/p&gt;
&lt;h4&gt;Android got DRM&lt;/h4&gt;
&lt;p&gt;Wildvine drm snuck onto our phones. Now you can have a legitimate bit of general purpose hardware where some services don't work as well as the hardware supports (Looking at you Netflix) simply because the market share of that device wasn't great enough for them to "certify" it's use.&lt;/p&gt;
&lt;h4&gt;The Walled Gardens of the Internet&lt;/h4&gt;
&lt;p&gt;At some point the Internet seamed to shrink. Once there was new (Admittedly sometimes terrible) sites to explore every day. Now it feels like everyone is siloed into Facebook, Twitter and Reddit. Reddit introduced Anti user "optimizations" to their Mobile website in the idiotic attempt to push users into their app. In 2020 a website no longer wants to be a website built on open technologies, they want it locked down like Twitter and Facebook in an Application.&lt;/p&gt;
&lt;h4&gt;IOT locked in the cloud&lt;/h4&gt;
&lt;p&gt;I was promised a smart home when I was a child. Now we have insecure IOT devices that are, for all intents and purposes, owned by someone else. The software can randomly be killed like Google did for some Nest devices and the open API's can be locked down with little to no notice. Sure we have the hacky open ecosystem for the ESP8266 and the ESP32 is great for DIY projects. However the ESP32 introduces flash encryption and secure boot. Meaning that even in this wonderful open hardware hacking space, the future is a locked down dystopia&lt;/p&gt;
&lt;h4&gt;It's all a war against General Purpose computing&lt;/h4&gt;
&lt;p&gt;Now you see things like Apple's M1 ARM based chip replacing x86 chips for their computers. They claim it's about user experience and performance but there is no denying that by moving to ARM from x86 gives them the same locked down hardware control they enjoy on the iPhone and iPad. From the articles I have read we will also begin to see them begin to slowly port the same software controls over as well, will we soon see the death of alternative browser Engines on their computers? unless they get hit by a good anti-trust charge or too I wouldn't be surprised if it happens in just a couple of years.&lt;/p&gt;
&lt;p&gt;Now I read that Microsoft's Pluton hardware coming to our General purpose x86 CPU's. Cryptographic technology originally employed in the XBOX for DRM&lt;/p&gt;</description><category>quick post</category><guid>https://peekread.info/blog/20201124-the-depressing-age-of-the-walled-garden/</guid><pubDate>Mon, 23 Nov 2020 16:00:00 GMT</pubDate></item><item><title>TOTP with sudo (Google Auth)</title><link>https://peekread.info/tech/20200610-totp-with-sudo-google-auth/</link><dc:creator>Dugite-Code</dc:creator><description>&lt;p&gt;I was reading the posts over on lobste.rs and saw this post: &lt;a href="https://lobste.rs/s/hs7yjv/is_sudo_almost_useless"&gt;Is &lt;code&gt;sudo&lt;/code&gt; almost useless?&lt;/a&gt;. Typically I see sudo as a safety belt to protect you from doing something stupid with administrator privileges rather than a security shield. But that doesn't mean it can't be both&lt;/p&gt;
&lt;p&gt;As with ssh, outlined in my previous post &lt;a href="https://peekread.info/tech/20190614-totp-with-ssh-google-auth/"&gt;TOTP with SSH (Google Auth)&lt;/a&gt;, you can certainly boost your sudo usefulness security wise by throwing 2FA via &lt;a href="https://github.com/google/google-authenticator-libpam"&gt;google-authenticator-libpam&lt;/a&gt; on top of it.&lt;/p&gt;
&lt;h3&gt;Install google-authenticator-libpam&lt;/h3&gt;
&lt;p&gt;On debian/ubuntu:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;google-authenticator-libpam
&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Set-up your secret keys&lt;/h3&gt;
&lt;p&gt;We now need to create the secret key, this should not be kept in the user folder, after all what is the point of 2FA if the user we are authenticating can just read the secret files. In my case I keep them in the root dir&lt;/p&gt;
&lt;p&gt;Replace the variable &lt;code&gt;${USER}&lt;/code&gt; if/when you create a key for a user other than the active one.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;google-authenticator&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/root/.sudo_totp/&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/.google_authenticator
sudo&lt;span class="w"&gt; &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;/root/.sudo_totp/
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You will see a QR code/secret key that you can scan with a TOTP app like &lt;a href="https://f-droid.org/en/packages/org.shadowice.flocke.andotp/"&gt;andotp&lt;/a&gt;, &lt;a href="https://play.google.com/store/apps/details?id=com.authy.authy"&gt;authy&lt;/a&gt;, &lt;a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2"&gt;google authenticator&lt;/a&gt; or in my case I added it to my yubikey. There are also your emergency scratch codes that you should record somewhere safe.&lt;/p&gt;
&lt;h3&gt;Enable in PAM&lt;/h3&gt;
&lt;p&gt;You now need to let PAM know it should be checking the codes. There are two ways to do this, Mandatory and Only if secret key exists. I have it as Mandatory any user using sudo &lt;strong&gt;MUST&lt;/strong&gt; have a secret key&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;/etc/pam.d/sudo&lt;/code&gt; add the following configuration lines to the end of the file.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Use Google Auth -- Mandatory&lt;/span&gt;
auth&lt;span class="w"&gt; &lt;/span&gt;required&lt;span class="w"&gt; &lt;/span&gt;pam_google_authenticator.so&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/root/.sudo_totp/&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/.google_authenticator&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root

&lt;span class="c1"&gt;# Use Google Auth -- Only if secret key exists&lt;/span&gt;
&lt;span class="c1"&gt;# auth required pam_google_authenticator.so secret=/root/.sudo_totp/${USER}/.google_authenticator user=root nullok&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Bonus do this for su as well&lt;/h3&gt;
&lt;p&gt;You can do the same thing for su as well however obviously the user variable will be root rather than the user attempting to elevate their privilege's.&lt;/p&gt;
&lt;p&gt;Setup the key as before, just for the root user&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;google-authenticator&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/root/.google_authenticator
sudo&lt;span class="w"&gt; &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;/root/.google_authenticator
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In &lt;code&gt;/etc/pam.d/su&lt;/code&gt; add the following configuration lines to the end of the file.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Use Google Auth -- Mandatory&lt;/span&gt;
auth&lt;span class="w"&gt; &lt;/span&gt;required&lt;span class="w"&gt; &lt;/span&gt;pam_google_authenticator.so&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/root/.google_authenticator&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root
&lt;/pre&gt;&lt;/div&gt;</description><category>linux</category><category>quick post</category><category>security</category><category>sudo</category><guid>https://peekread.info/tech/20200610-totp-with-sudo-google-auth/</guid><pubDate>Tue, 09 Jun 2020 16:00:00 GMT</pubDate></item><item><title>You should probably know about LetsEncrypt DNS challenge validation</title><link>https://peekread.info/tech/20200429-you-should-probably-know-about-letsencrypt-dns-challenge-validation/</link><dc:creator>Dugite-Code</dc:creator><description>&lt;p&gt;Everyone knows the basic way to renew a LetsEncrypt cert. Open port 80 and let LetsEncrypt connect to your server. But what if you don't want to open your network or you limit access to a handful of IP addresses? Well you can just use the DNS challenge validation, no need for web servers and no need for port wrangling.&lt;/p&gt;
&lt;p&gt;For example I use the &lt;a href="https://certbot-dns-cloudflare.readthedocs.io/en/stable/"&gt;certbot-dns-cloudflare&lt;/a&gt; for my work intranet allowing it to remain VPN only.&lt;/p&gt;
&lt;p&gt;Another great option is to use &lt;a href="https://github.com/acmesh-official/acme.sh"&gt;acme.sh&lt;/a&gt; as it supports a massive list of dns providers and the ever popular &lt;a href="https://github.com/acmesh-official/acme.sh/wiki/dnsapi#27-use-duckdnsorg-api"&gt;duckdns&lt;/a&gt; out of the box.&lt;/p&gt;
&lt;p&gt;Given in the past I found the most fragile part of my LetsEncrypt setup was making sure port 80 was accessible to LetsEncrypt I personally use this method even if I have a network accessible from the wider internet.&lt;/p&gt;</description><category>dns</category><category>letsencrypt</category><category>quick post</category><category>ssl</category><guid>https://peekread.info/tech/20200429-you-should-probably-know-about-letsencrypt-dns-challenge-validation/</guid><pubDate>Tue, 28 Apr 2020 16:00:00 GMT</pubDate></item><item><title>App Passwords for docker-mailserver</title><link>https://peekread.info/tech/20191022-app-passwords-for-docker-mailserver/</link><dc:creator>Dugite-Code</dc:creator><description>&lt;p&gt;Recently I got rid of my virtual &lt;a href="https://www.netgate.com/solutions/pfsense/sg-1100.html"&gt;IPFire&lt;/a&gt; firewall and setup a &lt;a href="https://www.netgate.com/solutions/pfsense/sg-1100.html"&gt;Netgate SG1100&lt;/a&gt; as my home firewall. I did this mainly because the NIC on the IPFire host NUC was starting to fail, also we use Pfsense at work and it's good to be able to tinker on a common platform. As my email server was virtualized on the same host NUC as my firewall I switched my virtual &lt;a href="https://modoboa.org/en/"&gt;modoboa&lt;/a&gt; email server install to the &lt;a href="https://github.com/tomav/docker-mailserver"&gt;docker-mailserver&lt;/a&gt; project. This makes my mail server more portable than the old virtual machine was.&lt;/p&gt;
&lt;p&gt;I then setup app specific passwords for my email following &lt;a href="https://www.happyassassin.net/2014/08/26/adding-application-specific-passwords-to-dovecot-when-using-system-user-accounts/"&gt;this guide&lt;/a&gt; Below is the changes I needed to do for the docker image.&lt;/p&gt;
&lt;p&gt;Adding this to the docker-mailserver &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;volumes:
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;###################################&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;#### Dovecot App Passwords Mod ####&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;###################################&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;/opt/mail/custom/dovecot/10-auth.conf:/etc/dovecot/conf.d/10-auth.conf:ro
&lt;span class="w"&gt;    &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;/opt/mail/custom/dovecot/auth-appspecificpasswd.conf.ext:/etc/dovecot/conf.d/auth-appspecificpasswd.conf.ext:ro
&lt;span class="w"&gt;    &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;/opt/mail/custom/dovecot/app_specific_passwd:/etc/dovecot/app_specific_passwd:ro
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;/opt/mail/custom/dovecot/10-auth.conf&lt;/code&gt; file&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nv"&gt;auth_mechanisms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;plain&lt;span class="w"&gt; &lt;/span&gt;login
!include&lt;span class="w"&gt; &lt;/span&gt;auth-passwdfile.inc
!include&lt;span class="w"&gt; &lt;/span&gt;auth-appspecificpasswd.conf.ext
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;/opt/mail/custom/dovecot/auth-appspecificpasswd.conf.ext&lt;/code&gt; file&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;passdb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;driver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;passwd-file

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;scheme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SHA512-CRYPT&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;username_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%u&lt;span class="w"&gt; &lt;/span&gt;/etc/dovecot/app_specific_passwd

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;/opt/mail/custom/dovecot/app_specific_passwd&lt;/code&gt; file (example)&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;K9emaillapp:&lt;span class="o"&gt;{&lt;/span&gt;SHA512-CRYPT&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="m"&gt;123456789&lt;/span&gt;...::::::user&lt;span class="o"&gt;=&lt;/span&gt;foo
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Assuming your docker-mailserver is called mail you can get the format you passwords for the &lt;code&gt;app_specific_passwd&lt;/code&gt; file by using:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nv"&gt;docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;mail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;doveadm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;SHA512&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;CRYPT&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can now user the username &lt;code&gt;K9emaillapp&lt;/code&gt; and the associated password to log in to your email account&lt;/p&gt;</description><category>colection</category><category>quick post</category><guid>https://peekread.info/tech/20191022-app-passwords-for-docker-mailserver/</guid><pubDate>Mon, 21 Oct 2019 16:00:00 GMT</pubDate></item><item><title>Something neat I did with FitNotes and Tasker</title><link>https://peekread.info/tech/20190722-fitnotes-and-tasker/</link><dc:creator>Dugite-Code</dc:creator><description>&lt;p&gt;&lt;/p&gt;&lt;div class="d-flex position-relative pt-3 pb-3"&gt;
    &lt;div class="flex-shrink-0 me-3"&gt;
        &lt;img data-pagefind-meta="image[src], image_alt[alt]" style="height:89px;" src="https://peekread.info/images/2019/0722-fitnotes-and-tasker/image1.png" alt="FitNotes App for Android"&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;p class="mt-3"&gt;&lt;/p&gt;&lt;p&gt;I use the fitness tracking app FitNotes on Android. It's a great application that I have happily used for years. The greatest issue I had with it was manually entering my body weight. Well I finally got myself into gear and fixed that issue using the fantastic staple of Android automation, &lt;a href="https://tasker.joaoapps.com/"&gt;Tasker&lt;/a&gt;&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Using a Xiaomi Mi Smart Scale that I hooked up to my home server using my &lt;a href="https://github.com/dugite-code/miscale.py"&gt;python gatttool wrapper&lt;/a&gt; I Dump it's weight data into a Google spreadsheet.&lt;/p&gt;
&lt;p&gt;Using my &lt;a href="https://github.com/dugite-code/GSheet-Scripts/tree/master/Simple%20API"&gt;Simple API&lt;/a&gt; (Because Google's own API is a pain) and the helper task &lt;a href="http://tasker.wikidot.com/getformatteddate"&gt;getformatteddate&lt;/a&gt;, I pull a unix timestamp and the weight onto my Phone. I then run a &lt;code&gt;INSERT&lt;/code&gt; SQL command on FitNote's database (using root of course)&lt;/p&gt;
&lt;p&gt;I also did a bulk body weight record import via &lt;code&gt;.csv&lt;/code&gt; using &lt;a href="https://sqlitebrowser.org/"&gt;sqlitebrowser&lt;/a&gt;. Now I no longer have to manually enter my body weight, should have done this years ago.&lt;/p&gt;
&lt;p&gt;Here is my Tasker task if you are interested:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;Healthapi&lt;span class="w"&gt; &lt;/span&gt;(&lt;span class="m"&gt;44&lt;/span&gt;)
&lt;span class="w"&gt;        &lt;/span&gt;A1:&lt;span class="w"&gt; &lt;/span&gt;Flash&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Text:%date&lt;span class="w"&gt; &lt;/span&gt;%time&lt;span class="w"&gt; &lt;/span&gt;Long:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A2:&lt;span class="w"&gt; &lt;/span&gt;Flash&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Text:Updating&lt;span class="w"&gt; &lt;/span&gt;Health&lt;span class="w"&gt; &lt;/span&gt;Report&lt;span class="w"&gt; &lt;/span&gt;Long:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A3:&lt;span class="w"&gt; &lt;/span&gt;HTTP&lt;span class="w"&gt; &lt;/span&gt;Get&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Server:Port:https://script.google.com&lt;span class="w"&gt; &lt;/span&gt;Path:/macros/s/myprivatesheet/exec&lt;span class="w"&gt; &lt;/span&gt;Attributes:key=myapikey&lt;span class="w"&gt; &lt;/span&gt;Cookies:&lt;span class="w"&gt; &lt;/span&gt;User&lt;span class="w"&gt; &lt;/span&gt;Agent:&lt;span class="w"&gt; &lt;/span&gt;Timeout:&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Mime&lt;span class="w"&gt; &lt;/span&gt;Type:&lt;span class="w"&gt; &lt;/span&gt;Output&lt;span class="w"&gt; &lt;/span&gt;File:&lt;span class="w"&gt; &lt;/span&gt;Trust&lt;span class="w"&gt; &lt;/span&gt;Any&lt;span class="w"&gt; &lt;/span&gt;Certificate:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A4:&lt;span class="w"&gt; &lt;/span&gt;Variable&lt;span class="w"&gt; &lt;/span&gt;Set&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Name:%data&lt;span class="w"&gt; &lt;/span&gt;To:%HTTPD&lt;span class="w"&gt; &lt;/span&gt;Recurse&lt;span class="w"&gt; &lt;/span&gt;Variables:Off&lt;span class="w"&gt; &lt;/span&gt;Do&lt;span class="w"&gt; &lt;/span&gt;Maths:Off&lt;span class="w"&gt; &lt;/span&gt;Append:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A5:&lt;span class="w"&gt; &lt;/span&gt;Variable&lt;span class="w"&gt; &lt;/span&gt;Set&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Name:%newline&lt;span class="w"&gt; &lt;/span&gt;To:
&lt;span class="w"&gt;     &lt;/span&gt;Recurse&lt;span class="w"&gt; &lt;/span&gt;Variables:Off&lt;span class="w"&gt; &lt;/span&gt;Do&lt;span class="w"&gt; &lt;/span&gt;Maths:Off&lt;span class="w"&gt; &lt;/span&gt;Append:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A6:&lt;span class="w"&gt; &lt;/span&gt;Variable&lt;span class="w"&gt; &lt;/span&gt;Split&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Name:%data&lt;span class="w"&gt; &lt;/span&gt;Splitter:%newline&lt;span class="w"&gt; &lt;/span&gt;Delete&lt;span class="w"&gt; &lt;/span&gt;Base:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A7:&lt;span class="w"&gt; &lt;/span&gt;Variable&lt;span class="w"&gt; &lt;/span&gt;Split&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Name:%data1&lt;span class="w"&gt; &lt;/span&gt;Splitter:,&lt;span class="w"&gt; &lt;/span&gt;Delete&lt;span class="w"&gt; &lt;/span&gt;Base:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A8:&lt;span class="w"&gt; &lt;/span&gt;Read&lt;span class="w"&gt; &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;File:Tasker/lastdate.dat&lt;span class="w"&gt; &lt;/span&gt;To&lt;span class="w"&gt; &lt;/span&gt;Var:%lastdate&lt;span class="w"&gt; &lt;/span&gt;Continue&lt;span class="w"&gt; &lt;/span&gt;Task&lt;span class="w"&gt; &lt;/span&gt;After&lt;span class="w"&gt; &lt;/span&gt;Error:On&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A9:&lt;span class="w"&gt; &lt;/span&gt;If&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;%lastdate&lt;span class="w"&gt; &lt;/span&gt;neq&lt;span class="w"&gt; &lt;/span&gt;%data11&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A10:&lt;span class="w"&gt; &lt;/span&gt;Write&lt;span class="w"&gt; &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;File:Tasker/lastdate.dat&lt;span class="w"&gt; &lt;/span&gt;Text:%data11&lt;span class="w"&gt; &lt;/span&gt;Append:Off&lt;span class="w"&gt; &lt;/span&gt;Add&lt;span class="w"&gt; &lt;/span&gt;Newline:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A11:&lt;span class="w"&gt; &lt;/span&gt;Perform&lt;span class="w"&gt; &lt;/span&gt;Task&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Name:getFormattedDate&lt;span class="w"&gt; &lt;/span&gt;Priority:%priority&lt;span class="w"&gt; &lt;/span&gt;Parameter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;(%par1):%data11&lt;span class="w"&gt; &lt;/span&gt;Parameter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;(%par2):yyyy-mm-dd&lt;span class="w"&gt; &lt;/span&gt;Return&lt;span class="w"&gt; &lt;/span&gt;Value&lt;span class="w"&gt; &lt;/span&gt;Variable:%date&lt;span class="w"&gt; &lt;/span&gt;Stop:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A12:&lt;span class="w"&gt; &lt;/span&gt;Perform&lt;span class="w"&gt; &lt;/span&gt;Task&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Name:getFormattedDate&lt;span class="w"&gt; &lt;/span&gt;Priority:%priority&lt;span class="w"&gt; &lt;/span&gt;Parameter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;(%par1):%data11&lt;span class="w"&gt; &lt;/span&gt;Parameter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;(%par2):hh:nn:ss&lt;span class="w"&gt; &lt;/span&gt;Return&lt;span class="w"&gt; &lt;/span&gt;Value&lt;span class="w"&gt; &lt;/span&gt;Variable:%time&lt;span class="w"&gt; &lt;/span&gt;Stop:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A13:&lt;span class="w"&gt; &lt;/span&gt;Variable&lt;span class="w"&gt; &lt;/span&gt;Set&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Name:%measurement_id&lt;span class="w"&gt; &lt;/span&gt;To:&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Do&lt;span class="w"&gt; &lt;/span&gt;Maths:Off&lt;span class="w"&gt; &lt;/span&gt;Append:On&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A14:&lt;span class="w"&gt; &lt;/span&gt;Variable&lt;span class="w"&gt; &lt;/span&gt;Set&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Name:%value&lt;span class="w"&gt; &lt;/span&gt;To:%data12&lt;span class="w"&gt; &lt;/span&gt;Do&lt;span class="w"&gt; &lt;/span&gt;Maths:Off&lt;span class="w"&gt; &lt;/span&gt;Append:On&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A15:&lt;span class="w"&gt; &lt;/span&gt;Variable&lt;span class="w"&gt; &lt;/span&gt;Set&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Name:%query&lt;span class="w"&gt; &lt;/span&gt;To:INSERT&lt;span class="w"&gt; &lt;/span&gt;INTO&lt;span class="w"&gt; &lt;/span&gt;MeasurementRecord&lt;span class="w"&gt; &lt;/span&gt;(measurement_id,&lt;span class="w"&gt; &lt;/span&gt;date,&lt;span class="w"&gt; &lt;/span&gt;time,&lt;span class="w"&gt; &lt;/span&gt;value,&lt;span class="w"&gt; &lt;/span&gt;comment)&lt;span class="w"&gt; &lt;/span&gt;VALUES&lt;span class="w"&gt; &lt;/span&gt;("%measurement_id",&lt;span class="w"&gt; &lt;/span&gt;"%date",&lt;span class="w"&gt; &lt;/span&gt;"%time",&lt;span class="w"&gt; &lt;/span&gt;"%value","");&lt;span class="w"&gt; &lt;/span&gt;Do&lt;span class="w"&gt; &lt;/span&gt;Maths:Off&lt;span class="w"&gt; &lt;/span&gt;Append:Off&lt;span class="w"&gt; &lt;/span&gt;]
&lt;span class="w"&gt;        &lt;/span&gt;A16:&lt;span class="w"&gt; &lt;/span&gt;SQL&lt;span class="w"&gt; &lt;/span&gt;Query&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;Mode:Raw&lt;span class="w"&gt; &lt;/span&gt;File:/data/data/com.github.jamesgay.fitnotes/databases/database.db&lt;span class="w"&gt; &lt;/span&gt;Table:&lt;span class="w"&gt; &lt;/span&gt;Columns:&lt;span class="w"&gt; &lt;/span&gt;Query:%query&lt;span class="w"&gt; &lt;/span&gt;Selection&lt;span class="w"&gt; &lt;/span&gt;Parameters:&lt;span class="w"&gt; &lt;/span&gt;Order&lt;span class="w"&gt; &lt;/span&gt;By:&lt;span class="w"&gt; &lt;/span&gt;Output&lt;span class="w"&gt; &lt;/span&gt;Column&lt;span class="w"&gt; &lt;/span&gt;Divider:&lt;span class="w"&gt; &lt;/span&gt;Variable&lt;span class="w"&gt; &lt;/span&gt;Array:%test&lt;span class="w"&gt; &lt;/span&gt;Use&lt;span class="w"&gt; &lt;/span&gt;Root:On&lt;span class="w"&gt; &lt;/span&gt;]
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I hope you found this interesting, if only in the abstract &lt;em&gt;"hey that's a thing you can totally do"&lt;/em&gt; kind of way. If you want me to write a complete how-to let me know in the comments down below.&lt;/p&gt;</description><category>hacking</category><category>quick post</category><guid>https://peekread.info/tech/20190722-fitnotes-and-tasker/</guid><pubDate>Mon, 22 Jul 2019 05:00:00 GMT</pubDate></item><item><title>TOTP with SSH (Google Auth)</title><link>https://peekread.info/tech/20190614-totp-with-ssh-google-auth/</link><dc:creator>Dugite-Code</dc:creator><description>&lt;p&gt;For your ssh you can use &lt;a href="https://github.com/google/google-authenticator-libpam"&gt;google-authenticator-libpam&lt;/a&gt; to add time based codes to your ssh login.&lt;/p&gt;
&lt;p&gt;On debian/ubuntu:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;google-authenticator-libpam

&lt;span class="w"&gt;    &lt;/span&gt;google-authenticator

&lt;span class="w"&gt;    &lt;/span&gt;Do&lt;span class="w"&gt; &lt;/span&gt;you&lt;span class="w"&gt; &lt;/span&gt;want&lt;span class="w"&gt; &lt;/span&gt;authentication&lt;span class="w"&gt; &lt;/span&gt;tokens&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;be&lt;span class="w"&gt; &lt;/span&gt;time-based&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;y/n&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;y
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Do&lt;span class="w"&gt; &lt;/span&gt;you&lt;span class="w"&gt; &lt;/span&gt;want&lt;span class="w"&gt; &lt;/span&gt;me&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt; &lt;/span&gt;your&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/home/dugite/.google_authenticator"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file?&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;y/n&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;y
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You will see a QR code/secret key that you can scan with a TOTP app like &lt;a href="https://f-droid.org/en/packages/org.shadowice.flocke.andotp/"&gt;andotp&lt;/a&gt;, &lt;a href="https://play.google.com/store/apps/details?id=com.authy.authy"&gt;authy&lt;/a&gt; or &lt;a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2"&gt;google authenticator&lt;/a&gt; (WARNING Google authenticator has no backup options). There are also your emergency scratch codes.&lt;/p&gt;
&lt;p&gt;In /etc/ssh/sshd_config Add:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Use Challenge Response Auth i.e. TOTP&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;ChallengeResponseAuthentication&lt;span class="w"&gt; &lt;/span&gt;yes
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Require both publickey and TOTP&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;AuthenticationMethods&lt;span class="w"&gt; &lt;/span&gt;publickey,keyboard-interactive
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In /etc/pam.d/sshd&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Comment out Standard Un*x authentication.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# @include common-auth&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Load the google TOTP Authentication module&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;auth&lt;span class="w"&gt; &lt;/span&gt;required&lt;span class="w"&gt; &lt;/span&gt;pam_google_authenticator.so
&lt;/pre&gt;&lt;/div&gt;</description><category>quick post</category><guid>https://peekread.info/tech/20190614-totp-with-ssh-google-auth/</guid><pubDate>Thu, 13 Jun 2019 16:00:00 GMT</pubDate></item><item><title>Goodbye Chrome and other things</title><link>https://peekread.info/tech/20190530-goodbye-chrome-and-other-things/</link><dc:creator>Dugite-Code</dc:creator><description>&lt;p&gt;Google, once the tech enthusiast darling is looking more and more like Microsoft did in the mid 90's.&lt;/p&gt;
&lt;h4&gt;&lt;a href="https://news.ycombinator.com/item?id=20044430"&gt;Google to restrict modern ad blocking Chrome extensions to enterprise users&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Google is first and foremost an &lt;a href="http://fortune.com/2017/01/04/google-facebook-ad-industry/"&gt;ad company&lt;/a&gt; so it should come as no surprise that now they are leading the &lt;a href="https://www.netmarketshare.com/browser-market-share.aspx?options=%7B%22filter%22%3A%7B%22%24and%22%3A%5B%7B%22deviceType%22%3A%7B%22%24in%22%3A%5B%22Desktop%2Flaptop%22%5D%7D%7D%5D%7D%2C%22dateLabel%22%3A%22Trend%22%2C%22attributes%22%3A%22share%22%2C%22group%22%3A%22browser%22%2C%22sort%22%3A%7B%22share%22%3A-1%7D%2C%22id%22%3A%22browsersDesktop%22%2C%22dateInterval%22%3A%22Monthly%22%2C%22dateStart%22%3A%222018-05%22%2C%22dateEnd%22%3A%222019-04%22%2C%22segments%22%3A%22-1000%22%7D"&gt;browser market share&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="All hail the King" class="light-image mx-auto" loading="lazy" max-height="297" max-width="800" src="https://peekread.info/images/2019/0530-goodbye-chrome-and-other-things/image01.png"&gt;&lt;/p&gt;
&lt;p&gt;Now &lt;a href="https://news.ycombinator.com/item?id=18595069"&gt;Microsoft is switching to chromium&lt;/a&gt; as a browser backend it's no surprise we see Google moving to limit Ad-blockers.&lt;/p&gt;
&lt;h4&gt;&lt;a href="https://www.tablix.org/~avian/blog/archives/2019/04/google_is_eating_our_mail/"&gt;Google is eating our mail&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Google really got entrenched with the tech enthusiast crowd because gmail was free, quick and had good spam filtering. Now we are all feeling the consequences of encouraging non-technical people to centralize their emails with them. A once open and vibrant standard is increasingly looking like a mono-culture with both Google and Microsoft's opaque filtering and non-standard blocking making running your own email server almost impossible. Along with the launch of google's &lt;a href="https://news.ycombinator.com/item?id=19493378"&gt;AMP for email&lt;/a&gt; we see yet another example of Google pushing through their own interests over the interests of the email ecosystem.&lt;/p&gt;
&lt;h4&gt;What you can do&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Switch to &lt;a href="https://www.mozilla.org/en-US/firefox/new/"&gt;Firefox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Switch to alternative search engines like &lt;a href="https://duckduckgo.com/"&gt;Duckduckgo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Use more privacy &lt;a href="https://www.privacytools.io/"&gt;respecting tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><category>quick post</category><guid>https://peekread.info/tech/20190530-goodbye-chrome-and-other-things/</guid><pubDate>Wed, 29 May 2019 16:00:00 GMT</pubDate></item></channel></rss>