A Weird Imagination

Viewing Signal messenger backups

Posted in

The problem#

Signal is a privacy-focused instant messaging application which ensures end-to-end encryption on all messages and generally goes out of its way to avoid accidentally revealing your conversations to third parties. As is common with security mechanisms, this necessarily adds some friction some some tasks you actually want to do. In particular, this means viewing your message history outside of the official app is unsupported. Which is especially a problem due to the app being tied to a smartphone that will likely only continue being usable for at most several years. So there's no official way to maintain access to your conversations indefinitely in contrast to IRC and Pidgin logs I have going back decades.

The solution#

The Signal Andriod app supports making encrypted backups (there is no way to get messages out of Signal iOS).

When you enable backups, it gives you a "passphrase" (a sequence of 30 digits). If you have lost this passphrase, there is no way to recover it, but you can disable backups and then re-enable them which will generate a fresh passphrase that will be used for your backups going forward. I recommend storing this passphrase in a password manager like KeePassXC.

To actually use the backup file, you'll need to know where it is. The location is shown on the Signal settings under Chats -> Chat backups -> Backup folder. You can copy it to your computer by plugging the phone in with a USB cable and using an MTP client, which is included in most file managers (I use XFCE's Thunar).

Once you have the backup file and passphrase, you can use signalbackup-tools to convert the backup to something human-readable:

signalbackup-tools [input] [passphrase] \
                   --exporthtml [directory] --allhtmlpages

The output does a good job of trying to look like the Signal interface. See the documentation for more options on controlling the output including various options to filter the output to just some conversations or time ranges.

The details#

Read more…

Move window to current desktop

The problem#

Previously, I wrote a script for opening and immediately focusing xfce4-appfinder. But xfce4-appfinder will notice if it's already open and just assume you want to use the existing window. Even if it's on a different desktop. And therefore attempting to focus it will either do nothing or switch to that desktop, neither of which is desirable.

The solution#

The actual solution I settled on is more of a workaround than a solution: having xfce4-appfinder on a different desktop doesn't really make sense, so I just set it to be on all desktops (specified as the non-existent desktop -1), so it would never be on the wrong desktop:

xdotool set_desktop_for_window "$winid" -1

To actually move the window to the current desktop, replace xdotool windowactivate "$winid" with

desktop="$(xdotool get_desktop)"
win_desktop="$(xdotool get_desktop_for_window "$winid")"
if [[ "$desktop" == "$win_desktop" ]]
then
  xdotool windowactivate "$winid"
else
  xdotool set_desktop_for_window "$winid" -1
  xdotool set_desktop_for_window "$winid" "$desktop" \
          windowactivate "$winid"
fi

Although this assumes that you know the $winid of the window you want to move. If you have just the title it works just as well to use

wmctrl -R "Application Finder"

The details#

Read more…

Killing pipes from within

The problem#

Last week, I mentioned that I needed a hack to kill xprop that seemed like it should be unnecessary. Specifically, I had its output piped to a Bash while read loop and once that had found a line to act on, there was no further need to get more lines from xprop, but break or exit didn't result in xprop exiting.

The solution#

Use $BASHPID to get the actual PID of the subshell, ps to climb the process tree to the appropriate parent and pkill to kill its children:

some_pipeline |
  while read -r line
  do
    # Do whatever until ready to kill the pipe...
    # ... then kill it:
    ppid=$BASHPID
    ppid=$(ps -o ppid:1= "$ppid")
    pkill -9 -P "$ppid" 
  done

Rewrite appfinder-and-focus.sh from last time:

#!/usr/bin/bash
xprop -spy -root _NET_CLIENT_LIST | stdbuf -oL head -2 |
  while read -r l
  do
    winid="${l/#*, /}"
    if [[ $(xdotool getwindowname "$winid") == \
      "Application Finder" ]]
    then
      xdotool windowactivate "$winid"
      ppid=$BASHPID
      ppid=$(ps -o ppid:1= "$ppid")
      pkill -9 -P "$ppid" 
    fi
  done) 2>/dev/null &
xfce4-appfinder &

The details#

Read more…

Force focus new window immediately

The problem#

I have my window manager set to not focus new windows because I dislike having a new window pop up while typing and having the keystrokes surprisingly sent to the new window instead of the one I thought I was typing in. While this is usually what I want, this does mean extra clicks when I did mean to open the new window.

This is particularly bad for xfce4-appfinder (or any other application launcher), since the purpose to be able to set a global keyboard shortcut like Super+Space so you can press that combination and quickly type in the application or action you want (or, even better, type just the first few characters of its name). And since it's being intentionally launched by a keyboard shortcut, there's no real concern of it grabbing keyboard focus unexpectedly.

The solution#

Put the following script in a file appfinder-and-focus.sh and set the keyboard shortcut to run it instead of just running xfce4-appfinder directly:

#!/usr/bin/bash
(xprop -spy -root _NET_CLIENT_LIST | stdbuf -oL tail -n +2 |
  while read -r line
  do
    winid="${line/#*, /}"
    if [[ $(xdotool getwindowname "$winid") == \
        "Application Finder" ]]
    then
      xdotool windowactivate "$winid"
    fi
  done) 2>/dev/null &
xfce4-appfinder &

# Wait for window to appear, then kill xprop.
xdotool search --sync --name "Application Finder" >/dev/null
pkill -P "$(jobs -p %1)"

The details#

Read more…

Formulas in Gnumeric

Posted in

The problem#

I mostly use Gnumeric for my personal spreadsheets, which are generally quite simple. But recently I wanted do some analysis that required writing a formula more complicated than just using the SUM() function and found Gnumeric's function documentation quite lacking in sufficiently detailed explanations and examples to be able to figure out how to use any of the more complicated functions.

The specific problem I was trying to solve was that I had some data on payments over time labeled with categories and wanted to summarize payments by category for each time period.

The solution#

The short version is that Gnumeric's formula language is nearly the same as Microsoft Excel's formula language, so there's no need to look for Gnumeric-specific help on writing formulas. There's plenty of advice online on writing formulas for Excel, and the information transfers without modification to writing formulas for Gnumeric.

For my specific problem, my layout was that each column was a time period and each row was a payee with column A being the name of the payee and column B being the category. I made entries further down in column A of the categories and wanted the cells in those rows to be the sum of the payments for the corresponding column's time period but only for the payees matching the category for the row. The function to do that is called SUMIF(), but that documentation page from Gnumeric is very unhelpful except for the line

This function is Excel compatible.

The Excel help page on SUMIF() has examples and a lot more explanation. Here's what the formula looks like in cell P50:

=SUMIF($B$2:$B$40,$A50,P$2:P$40)

where B2:B40 is the range where the categories are given for each payee (named in A2:A40), A50 contains the category being summed, and P2:P40 contains the actual values being conditionally summed (i.e., the values for the time period named in P1).

The details#

Read more…

Virtualizing your own computer

Posted in

The problem#

It's annoying to test boot sequences, either of flash drives or your computer. Rebooting every time you want to test a change is slow and loses your place. Which is especially frustrating if you're using a live USB to attempt to repair a broken bootloader and you have to try multiple times. For a bootable flash drive, at least you might have another computer to test it on, making the problem just mildly inconvenient. But what if you didn't have to boot your computer to test the boot sequence?

The solution#

Of course, you have to boot some computer. But it doesn't have to be a physical one: it can be a virtual machine. While virtual machines often use virtual hard disks backed by files, they can also use real disks. And QEMU's -snapshot flag lets you read from a real disk without actually writing back to it. All changes are stored in temporary storage unless you "commit" them, which you do not want to do for this purpose.

IMPORTANT: Always make sure to use -snapshot when running QEMU on a real disk, especially if that disk is in use by the host system. The following commands also have you set the file permissions so QEMU does not have write access to the disks to be extra careful.

The following will run a virtual machine booting off a flash drive (change /dev/sdc to the appropriate device):

# Grant current user read-only access to flash drive
sudo chgrp "$(id -gn)" /dev/sdc
sudo chmod g=r /dev/sdc
# Boot VM off flash drive
qemu-system-x86_64 -snapshot \
    -net none -machine q35 \
    -bios /usr/share/ovmf/OVMF.fd \
    -cpu host -m 8G -enable-kvm \
    /dev/sdc

To instead boot off your machine's internal drive (assuming it is an NVME SSD with device name /dev/nvme0n1):

uefivars -i efivarfs -o edk2 \
    -I /sys/firmware/efi/efivars -O OVMF_VARS.fd
# Grant current user read-only access to primary SSD
sudo chgrp "$(id -gn)" /dev/nvme0n1
sudo chmod g=r /dev/nvme0n1
# Boot VM off primary SSD
qemu-system-x86_64 -snapshot \
    -net none \
    -drive file=/dev/nvme0n1,if=none,id=nvm \
    -device nvme,serial=deadbeef,drive=nvm \
    -machine q35 \
    -drive if=pflash,format=raw,unit=0,readonly=on,\
file=/usr/share/OVMF/OVMF_CODE_4M.fd \
    -drive if=pflash,format=raw,unit=1,file=OVMF_VARS.fd \
    -cpu host -m 8G -enable-kvm

Those commands require QEMU, KVM, and OVMF installed as well as the Python package uefivars. The paths for OVMF are where Debian installed the files on my system, but they may be in a different place or have slightly different filenames on your system.

Note booting the VM may not be instant: that second command takes almost a minute to reach the GRUB menu on my computer.

The details#

Read more…

Installing an OS

Posted in

The problem#

You know how to make a bootable flash drive, but you want to actually use it to install a permanent operating system (OS) onto your computer.

The solution#

Luckily, modern OS installs are very straightforward. Just download the installation image (e.g. Debian Linux or Windows 11), put it on a flash drive, boot off it, and click "Next" a few times and wait a bit. The defaults will usually erase all data on the computer, but if it's a new computer, there's nothing to erase.

Of course, you can make things more complicated if you don't like the defaults, have a special situation, or just want to know more precisely what's going on.

The details#

Read more…

What to boot off flash drives

Posted in

The problem#

Last week, I talked about making bootable flash drives, but didn't go in depth about why you might want to do so.

The solution#

Bootable flash drives have a lot of different uses. The most common ones are simply dealing with an operating system that fails to boot or installing an operating system on a computer that doesn't have one. But there's also some cases where it's useful to not be using the main OS even if it is functional.

The details#

Read more…

Booting off flash drives

Posted in

The problem#

So you've built a new computer with fresh blank storage. How do you actually do anything with that computer that has no software? Navigating the BIOS menus can only hold your interest for so long.

The solution#

The old way of doing things was to have a bootable CD or DVD, but now that most computers don't even have an optical drive, the common way to handle this with bootable USB flash drives.

Most Linux distributions' default download is an image for a bootable "live" flash drive (or DVD) that runs the OS in addition to having an option to perform a permanent install. Some of the most popular ones are Debian, Ubuntu, Mint, and Fedora.

You can boot Windows off a flash drive using Hiren's BootCD, which also includes a lot of recovery and diagnostic tools.

While most boot drives will boot into Linux or Windows, there's a small set of specialized lower-level tools. One very useful one is Memtest86+ (included in many Linux distros), which will determine if your RAM is functional. As bad RAM can cause very weird and different to track down problems, you should always test new RAM.

The details#

Read more…

Testing cheap flash drives

Posted in

The problem#

USB flash drives have gotten very cheap, especially if you don't care too much about the speed or capacity. It's convenient to buy multiple for no more than a few dollars each to always have one available or even to just give away. But sometimes very cheap hardware is non-functional or even counterfeit, claiming to be able to store more data than it really can, so when you try to read that data it will be corrupted or missing.

The solution#

f3 ("Fight Flash Fraud") is a tool for testing flash drives (including SSDs). The basic usage is

( f3write '/mnt/usb/' && f3read '/mnt/usb/' ) | tee f3-log

Replacing /mnt/usb/ with the directory your flash drive is mounted at. If you're testing multiple drives, give the log file a descriptive name to identify which drive the test is for.

(Or use the log-f3wr helper script included with f3 which does basically the same thing.)

That will write files to fill the flash drive and then read them back and verify they contain the same data that was written. This both checks for counterfeit drives as well as failing (or dead-on-arrival) drives. In addition to reporting if the drive is in fact capable of storing as much data as it claims, it will report the average write/read speeds while performing those operations, so it doubles as a simple benchmark.

You should always test new drives before trusting them with real data.

The details#

Read more…