summary refs log tree commit diff
path: root/pkgs
diff options
context:
space:
mode:
authorMichael Weiss <dev.primeos@gmail.com>2021-05-14 21:59:39 +0200
committerMichael Weiss <dev.primeos@gmail.com>2021-05-14 22:54:38 +0200
commit45bd7b39a444c904986324b5f7c46ba867612575 (patch)
tree87e8089f2f6236a4e67671a08ca46d52d6325027 /pkgs
parent940dfa99401c04c78bc530c72ecba6f6ccee62e8 (diff)
downloadnixpkgs-45bd7b39a444c904986324b5f7c46ba867612575.tar
nixpkgs-45bd7b39a444c904986324b5f7c46ba867612575.tar.gz
nixpkgs-45bd7b39a444c904986324b5f7c46ba867612575.tar.bz2
nixpkgs-45bd7b39a444c904986324b5f7c46ba867612575.tar.lz
nixpkgs-45bd7b39a444c904986324b5f7c46ba867612575.tar.xz
nixpkgs-45bd7b39a444c904986324b5f7c46ba867612575.tar.zst
nixpkgs-45bd7b39a444c904986324b5f7c46ba867612575.zip
signal-desktop: Add a Python wrapper to re-encrypt DBs
This is super hacky... :o
But then again it should at least prevent data loss.

Note: At least this isn't required for NixOS 21.05.
Diffstat (limited to 'pkgs')
-rwxr-xr-xpkgs/applications/networking/instant-messengers/signal-desktop/db-reencryption-wrapper.py92
-rw-r--r--pkgs/applications/networking/instant-messengers/signal-desktop/default.nix15
2 files changed, 106 insertions, 1 deletions
diff --git a/pkgs/applications/networking/instant-messengers/signal-desktop/db-reencryption-wrapper.py b/pkgs/applications/networking/instant-messengers/signal-desktop/db-reencryption-wrapper.py
new file mode 100755
index 00000000000..8556ee1e4d7
--- /dev/null
+++ b/pkgs/applications/networking/instant-messengers/signal-desktop/db-reencryption-wrapper.py
@@ -0,0 +1,92 @@
+#!@PYTHON@
+
+import json
+import os
+import re
+import shlex
+import sqlite3
+import subprocess
+import sys
+
+
+DB_PATH = os.path.join(os.environ['HOME'], '.config/Signal/sql/db.sqlite')
+DB_COPY = os.path.join(os.environ['HOME'], '.config/Signal/sql/db.tmp')
+CONFIG_PATH = os.path.join(os.environ['HOME'], '.config/Signal/config.json')
+
+
+def zenity_askyesno(title, text):
+    args = [
+        '@ZENITY@',
+        '--question',
+        '--title',
+        shlex.quote(title),
+        '--text',
+        shlex.quote(text)
+    ]
+    return subprocess.run(args).returncode == 0
+
+
+def start_signal():
+    os.execvp('@SIGNAL-DESKTOP@', ['@SIGNAL-DESKTOP@'] + sys.argv[1:])
+
+
+def copy_pragma(name):
+    result = subprocess.run([
+        '@SQLCIPHER@',
+        DB_PATH,
+        f"PRAGMA {name};"
+    ], check=True, capture_output=True).stdout
+    result = re.search(r'[0-9]+', result.decode()).group(0)
+    subprocess.run([
+        '@SQLCIPHER@',
+        DB_COPY,
+        f"PRAGMA key = \"x'{key}'\"; PRAGMA {name} = {result};"
+    ], check=True, capture_output=True)
+
+
+try:
+    # Test if DB is encrypted:
+    con = sqlite3.connect(f'file:{DB_PATH}?mode=ro', uri=True)
+    cursor = con.cursor()
+    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
+    con.close()
+except:
+    # DB is encrypted, everything ok:
+    start_signal()
+
+
+# DB is unencrypted!
+answer = zenity_askyesno(
+        "Error: Signal-Desktop database is not encrypted",
+        "Should we try to fix this automatically?"
+        + "You likely want to backup ~/.config/Signal/ first."
+)
+if not answer:
+    answer = zenity_askyesno(
+            "Launch Signal-Desktop",
+            "DB is unencrypted, should we still launch Signal-Desktop?"
+            + "Warning: This could result in data loss!"
+    )
+    if not answer:
+        print('Aborted')
+        sys.exit(0)
+    start_signal()
+
+# Re-encrypt the DB:
+with open(CONFIG_PATH) as json_file:
+    key = json.load(json_file)['key']
+result = subprocess.run([
+    '@SQLCIPHER@',
+    DB_PATH,
+    f" ATTACH DATABASE '{DB_COPY}' AS signal_db KEY \"x'{key}'\";"
+    + " SELECT sqlcipher_export('signal_db');"
+    + " DETACH DATABASE signal_db;"
+]).returncode
+if result != 0:
+    print('DB encryption failed')
+    sys.exit(1)
+# Need to copy user_version and schema_version manually:
+copy_pragma('user_version')
+copy_pragma('schema_version')
+os.rename(DB_COPY, DB_PATH)
+start_signal()
diff --git a/pkgs/applications/networking/instant-messengers/signal-desktop/default.nix b/pkgs/applications/networking/instant-messengers/signal-desktop/default.nix
index 38d52b26bff..e1ba5884de7 100644
--- a/pkgs/applications/networking/instant-messengers/signal-desktop/default.nix
+++ b/pkgs/applications/networking/instant-messengers/signal-desktop/default.nix
@@ -10,6 +10,9 @@
 , hunspellDicts, spellcheckerLanguage ? null # E.g. "de_DE"
 # For a full list of available languages:
 # $ cat pkgs/development/libraries/hunspell/dictionaries.nix | grep "dictFileName =" | awk '{ print $3 }'
+, python3
+, gnome
+, sqlcipher
 }:
 
 let
@@ -112,7 +115,7 @@ in stdenv.mkDerivation rec {
 
     # Symlink to bin
     mkdir -p $out/bin
-    ln -s $out/lib/Signal/signal-desktop $out/bin/signal-desktop
+    ln -s $out/lib/Signal/signal-desktop $out/bin/signal-desktop-unwrapped
 
     runHook postInstall
   '';
@@ -137,6 +140,16 @@ in stdenv.mkDerivation rec {
     patchelf --add-needed ${libpulseaudio}/lib/libpulse.so $out/lib/Signal/resources/app.asar.unpacked/node_modules/ringrtc/build/linux/libringrtc.node
   '';
 
+  postFixup = ''
+    # This hack is temporarily required to avoid data-loss for users:
+    cp ${./db-reencryption-wrapper.py} $out/bin/signal-desktop
+    substituteInPlace $out/bin/signal-desktop \
+      --replace '@PYTHON@' '${python3}/bin/python3' \
+      --replace '@ZENITY@' '${gnome.zenity}/bin/zenity' \
+      --replace '@SQLCIPHER@' '${sqlcipher}/bin/sqlcipher' \
+      --replace '@SIGNAL-DESKTOP@' "$out/bin/signal-desktop-unwrapped"
+  '';
+
   # Tests if the application launches and waits for "Link your phone to Signal Desktop":
   passthru.tests.application-launch = nixosTests.signal-desktop;