about summary refs log tree commit diff
path: root/pkgs/applications/networking/instant-messengers/signal-desktop/db-reencryption-wrapper.py
blob: 8556ee1e4d7368a12985e5250fad4be127209ebe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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()