Migrated to new site

Who likes change? I’m not surprised that nobody raised a hand.

I have migrated my site to a new url and new backend. I am now building my site with the Nikola static site generator at https://bgstack15.ddns.net/blog/. I will do a full write-up of the migration process and buildout of my new web server, for the curious.

I have no plans currently to remove this WordPress site, but it will no longer receive new contents.

I have nothing against WordPress, but I wanted to branch out into managing more of the infra and contents, and I didn’t want to set up a LAMP stack. I’m acceptably handy with python and Nikola fit my experience and expectations, and the static contents idea really appeals to me.

ps show start time in ISO 8601 format

From unix.stackexchange.com:

ps -e --no-headers -o lstart,pid,command --sort=start_time | awk '{ cmd="date -d\""$1 FS $2 FS $3 FS $4 FS $5"\" +\047%Y-%m-%dT%H:%M:%S\047"; cmd | getline d; close(cmd); $1=$2=$3=$4=$5=""; printf "%s\n",d$0 }'
2021-08-24T07:42:42     25863 [kworker/0:3-events]
2021-08-24T07:42:42     25927 [kworker/2:3-events]
2021-08-24T07:43:08     27437 [kworker/u9:0-xprtiod]
2021-08-24T07:44:00     30436 /usr/lib/firefox/firefox -contentproc -childID 114 -isForBrowser -prefsLen 10798 -prefMapSize 258189 -parentBuildID 20210504152106 -appdir /usr/lib/firefox/browser 5803 true tab
2021-08-24T07:49:28     16224 [kworker/u8:0-kcryptd/254:0]
2021-08-24T07:49:34     16656 sleep 2
2021-08-24T07:49:36     16688 sleep 0.75

You of course can adapt this to whichever additional parameters you need to send to ps, or grep for.

Import passwords to Chrome browser with csv file

If your Chome web browser is locked down and unable to offer to save passwords, you can probably still load in passwords. You can use csv import and export features to examine how Chrome exports them, and then write your csv entry manually and import it. You might need to enable password import: Visit chrome://flags#PasswordImport and enable that flag.

Export any current passwords you have to a csv, so you can examine the columns. For me, the columns were:


The passwords are saved in file “Login Data” which in Windows is stored as %localappdata%\Google\Chrome\User Data\Default\Login Data.

If Chrome is wiping your passwords when you close the browser, then you can mark the “Login Data” file as read-only before running Chrome. But to import a new password from csv, you need to run the program with the file as writeable, and then back up the file after importing the password. Then, close the browser and it will wipe the passwords in the main file. Then restore your backup, and mark it as read-only, and then you can run Chrome and close it at will, with the new passwords.

Mirror a copr, all architectures and releases and versions

coprmirror is my yum mirror solution, with a wrapper to mirror specifically a named COPR repository.


COPR is a distro-run community offering that lets users build yum/dnf repositories with their own software (primarily if not exclusively in rpm format). COPR performs the builds, and then hosts the binary and source rpms for client machines. My project today downloads using native GNU/Linux tools the yum repositories that collectively make up a COPR, so each release-releasever-basearch triplet. The end goal is to have a local copy of the entire current yum repos. This does not copy the build assets or log files; just what a yum repository defines and also the gpg public key.

Notably this utility needs the yum python packages present only for evaluating yum variables in the inurl (baseurl from a .repo file), so if you have a string literal as the inurl value, you can run this on a system that does not have yum installed.


Configure coprmirror.conf from the provided .example file, and then run:

COPRMIRROR_CONF=coprmirror.conf VERBOSE=1 DEBUG=1 ./coprmirror.sh


Original content

The get_file function was improved after being imported from my Reference 1 script.


I felt like ansible and system are overkill, but if you like those, this is perfect for you: https://github.com/ganto/ansible-copr_reposync


wget, grep, awk, sed, jq


Mirror an OBS repository locally — update 1 [this blog]

Chicago95 icon set for LibreOffice now upstreamed

The upstream folks at Chicago95 total conversion mod for Xfce desktop environment on GNU/Linux have graciously upstreamed my Chicago95 icon theme for LibreOffice! Check it out in the official repository: https://github.com/grassmunk/Chicago95/tree/master/Extras/libreoffice-chicago95-iconset.

Now if only we could get them to make a new release, so I could go update the dpkgs in the apt repo in the Open Build Service

LibreOffice Writer with the Chicago95 iconset

Use gtk3-classic on Devuan Ceres for type-to-navigate in file dialog

Gtk3-classic-build-deb is builder utility for gtk3-classic for Devuan Ceres. Check out the final assets at my OBS sub-project.


Notable improvements over stock gtk3 include

  • Regular type-to-navigate-to-filename in the file dialog instead of the “typeahead” behavior
  • CSDs are removed, which actually could deprecate gtk3-nocsd (official upstream Debian package)

Notable weaknesses include:


The gtk3-classic-build-deb.sh script and Makefile can be used to generate the build assets that can be used to build the binary dpkgs of gtk3 with the gtk3-classic patches.

The shell script finds the available gtk3 versions in debian, and gtk3-classic releases, and then finds the highest version that matches between the two. This highest version then gets downloaded, given the patches in debian/patches/series, and then the .dsc and .debian.tar.xz file are generated!


Build script

The build script is loosely inspired by luigifab/deb.sh (gist.github.com), but is maintained separately.


The gtk3-classic patch set is one of the main inputs to this process.


The debian orig tarball is used for the build process.


gtk3-stackrpms suite which suits my needs almost exactly, minus the file dialog type-to-find functionality.


To run the build script you need:

  • rmadison
  • git
  • tar

To build gtk3, you need the standard set which is available in the debian/control file.


Read RDP certificate in use

One minor problem I have come across a few times is, “How do I confirm that a Remote Desktop server is actually using the correct TLS certificate?” I deal with end results, and not policies or settings, so how I check tls servers is make a connection with openssl s_client. Well, RDP doesn’t start with the certificate, so s_client cannot extract the certificate information directly.

A solution I devised is to capture the packets of an initial RDP connection, and then extract the certificate from the TLSv1 Certificates protocol.

My project can read a packet capture, really any pcap that contains the TLSv1 Certificate protocol, and save from the TLSv1 Certificates packets any pem-format certificates to disk. Of course this project is open-source, so you can adapt it to do whatever you want.

You need to generate a packet capture file, which can be done with wireshark or tcpdump. I used filters:

sudo tcpdump -w ~/packets.in -n -v -A "port 3389 and (tcp[((tcp[12] & 0xf0) >> 2)] = 0x16)"

In wireshark, you can even use a display of tls.handshake.type == 11 as well.

So with this pcap file, run read_rdp_cert.py.

./read_rdp_cert.py --pcapfile ~/packets.in

The utility will extract all certificates that it can find from the tls handshake packets, into the current directory.

I was unable to find any other projects on the World Wide Web that solve the problem I am solving here.

I depended heavily on an example from cuckoolinux -> network.py to narrow down inside a network packet. Unfortunately the dpkt library has very weak documentation so I had to implement my own partial protocol analyzer to get to the good parts inside the TLS handshake.

Maybe a future version of this tool will even make the RDP requests, so it can be a self-contained utility.

Notes for jellyfin

Jellyfin is the Free Software Media System (from their website). I had installed a demo at some point in 2019 but that effort failed for undocumented reasons (the worst kind).

I tried again this month, and am incredibly pleased! I also installed it on a beefy machine this time and not a flimsy 1-vCPU virtual machine with <2 GB of RAM. My media already conforms to the Plex media organization methodology, mostly.

One hangup I still had was getting Chromecast support from the Android mobile app. While Jellyfin is available on f-droid, I learned, it does not contain the necessary bits to talk to Chromecast because it is the libre release. The Chromecast support is in the Play store version. However, to get Chromecast to operate successfully, I was told, you need to have https on the jellyfin connection.

I use apache httpd for my reverse proxy, so it was thankfully easy to get my Let’s Encrypt tls certificate on that. However, the jellyfin documentation that demonstrates using apache as a reverse proxy makes jellyfin take up the top-level virtual path, i.e., https://example.com/. I use my httpd instance for many things, so I could not afford to lose my entire site. The main networking page states that you can change the baseurl (which I believe is more accurately called base path, but now I’m quibbling) to use /jellyfin/ for example, but this breaks certain client softwares including Chromecast.

So I experimented with just shoving it under a different port on apache httpd, and thankfully Chromecast handles it just fine! So as long as my users remember to add port 500 in the url, everything will work including the much-used Chromecast!

My apache configs can be boiled down to the following.

Listen 192.168.300.52:500
SSLSessionCache   shmcb:/run/httpd/sslcache(512000)
SSLSessionCacheTimeout 300
<VirtualHost 192.168.300.52:500>
   ServerName  www.example.com:500
   ServerAlias www.example.com www server1 server1.ipa.internal.com internal.ignorelist.com

   SSLEngine on
   SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
   SSLHonorCipherOrder on

   SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
   SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem

   # This is important to allow the httpsonly part to work
   DocumentRoot   /var/www/external

   SSLProxyEngine On
   RewriteEngine On

   ProxyPreserveHost On
   ProxyPass "/.well-known/" "!"
   ProxyPass "/socket" "ws://vm4.ipa.internal.com:8096/socket"
   ProxyPassReverse "/socket" "ws://vm4.ipa.internal.com:8096/socket"
   ProxyPass "/" "http://vm4.ipa.internal.com:8096/"
   ProxyPassReverse "/" "http://vm4.ipa.internal.com:8096/"

And for good measure, I added file /var/www/jellyfin/index.html with the following line, to act as a redirect for when people visit https://www.example.com/jellyfin/&#8221;

<meta http-equiv="Refresh" content="0; url=https://www.example.com:500/">

Drag-and-drop target to open video weblinks in VLC or youtube-dl

Drop-videos is a small project for personal use, that displays an icon that acts as a drag-and-drop target that invokes either a downloader or a viewer, depending on how you invoked the program. The main utility is drop-videos.sh which displays a small icon that lets you drop video links on it. Depending on the environment variables at invocation, the program will download/view the links.


Several example scripts are provided, which is every script in this directory excluding drop-videos.sh. My main use cases include the following provided examples.

Use case file
Download all videos from this playlist save-playlist.sh
Download the specific link save-audio.sh
View the specific link view-video.sh

The application accepts the standard environment variables DEBUG and DRYRUN.



This project uses a customized dragon binary. The diff is provided here, as well as the customized source code.


I read article Open YouTube (And More) Videos From Your Web Browser With mpv [Firefox, Chrome] – Linux Uprising Blog which describes how to set up a browser extension that lets you add a userscript that shows a small button in a youtube browser page that opens that video in a local video player. This worked on my systems (aside from the fact that I don’t have mpv installed so the protocol handler fails), but I wanted a solution that would work without having to visit each and every link first. This article that inspired me refers to Tampermonkey which appears to be a fork of greasemonkey which has a fork for Palemoon. This Greasemonkey can use the userscript that will introduce a custom protocol which you can configure the OS to send to a specific program.



To compile the C binary, you need gtk3 libraries.


Bourne shell
vlc or other media player