-
Notifications
You must be signed in to change notification settings - Fork 0
/
patch-signal-desktop.js
executable file
·134 lines (121 loc) · 5.19 KB
/
patch-signal-desktop.js
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env node
import path from "node:path";
import os from "node:os";
import { inspect } from "node:util";
import { promises as fs } from "node:fs";
import crypto from "node:crypto";
import asar from "@electron/asar";
// https://stackoverflow.com/questions/17699599/node-js-check-if-file-exists
function file_exists(path) {
return fs.stat(path).then(() => true, () => false);
}
async function replace_in_file(path, replacements) {
let content = await fs.readFile(path, 'utf8');
for (const [matcher, replacement] of replacements) {
const new_content = content.replace(matcher, replacement);
if (new_content === content) {
throw new Error(`Nothing in ${path} was changed when attempting ` +
`to replace \n${inspect(matcher)} with \n${inspect(replacement)}`);
}
content = new_content;
}
await fs.writeFile(path, content, 'utf8');
}
// e.g. %LOCALAPPDATA%\Programs\signal-desktop
const signal_desktop_path = process.argv[2];
if (!signal_desktop_path) {
throw new Error(`Required argument not given: path to Signal-Desktop directory, e.g. %LOCALAPPDATA%\\Programs\\signal-desktop`);
}
console.log(`Patching Signal-Desktop in ${signal_desktop_path} ...`);
const asar_path = path.join(signal_desktop_path, "resources", "app.asar");
if (!await file_exists(asar_path)) {
throw new Error(`Expected file ${asar_path} to exist, but it does not.`);
}
const asar_orig_path = path.join(signal_desktop_path, "resources", "app.asar.orig");
if (!await file_exists(asar_orig_path)) {
console.log(`Backing up \n ${asar_path} -> \n ${asar_orig_path} ...`);
await fs.copyFile(asar_path, asar_orig_path);
} else {
console.log(`Backup at ${asar_orig_path} already exists, not overwriting.`);
}
if (!await file_exists(`${asar_orig_path}.unpacked`)) {
// A copy of the .unpacked directory that we have to make just for the asar module
// to be able to extract. https://github.com/electron/asar/issues/71
console.log(`Backing up \n ${asar_path}.unpacked -> \n ${asar_orig_path}.unpacked ...`);
await fs.cp(`${asar_path}.unpacked`, `${asar_orig_path}.unpacked`, {recursive: true});
} else {
console.log(`Backup at ${asar_orig_path}.unpacked already exists, not overwriting.`);
}
const extract_path = path.join(os.tmpdir(), `patch-signal-desktop-${crypto.randomUUID()}`);
console.log(`Extracting ${asar_orig_path} -> ${extract_path} ...`);
await asar.extractAll(asar_orig_path, extract_path);
// Signal-Desktop introduced a verified checkmark badge on "Notes to Self" to
// prevent someone from impersonating "Notes to Self", but the blue color matches
// the "new message" badge, making it look like you have a new message when you do not.
//
// Patch it to to make it grayscale.
//
// https://github.com/signalapp/Signal-Desktop/issues/6339
console.log(`Making the "Note to Self" badge grayscale ...`);
await replace_in_file(
path.join(extract_path, "stylesheets", "manifest.css"), [
[
"\n.ContactModal__official-badge {\n",
"\n.ContactModal__official-badge {\n filter: grayscale(1);\n",
],
[
"\n.ContactModal__official-badge__large {\n",
"\n.ContactModal__official-badge__large {\n filter: grayscale(1);\n",
],
]
);
console.log(`Fixing the typography and colors ...`);
for (const css_file of ["manifest.css", "manifest_bridge.css"]) {
await replace_in_file(
path.join(extract_path, "stylesheets", css_file), [
[
/\bfont-family: Inter, [^;]+;/g,
"font-family: 'Inter Display'; /* was Inter, ... */",
],
[
/\bfont-size: 14px;/g,
"font-size: 15px; /* was 14px */",
],
[
/\bline-height: 20px;/g,
"line-height: 23px; /* was 20px */",
],
[
/\bletter-spacing: ([^;]+);/g,
"/* was letter-spacing: $1; */",
],
[
/\bfont-weight: (bold|bolder|600|700);/g,
"font-weight: 550; /* was font-weight: $1; */",
],
/* Reduce brightness of message text */
[
/([\s\{])color: (#e9e9e9|rgba\(255,\s?255,\s?255,\s?0\.9\));/g,
"$1color: rgb(216 216 216); /* was color: $2; */",
],
]
);
}
// Signal servers work with old builds for a very long time, but Signal-Desktop
// ships with a short (~31 day?) timebomb with each Signal-Desktop build that
// forces you to update frequently.
console.log(`Disabling the build expiration timebomb ...`);
await replace_in_file(
path.join(extract_path, "preload.bundle.js"), [
[
/\)=>{if\([_$a-zA-Z0-9]+\(\)!=="production"&&e===0\)return!1;/,
')=>{return false; /* no timebomb */;',
],
]
);
console.log(`Writing patched archive to ${asar_path} ...`);
// Don't pack the .node files into the .asar; they need to go into .asar.unpacked/
// Note that asar archives include unpacked files in their metadata.
await asar.createPackageWithOptions(extract_path, asar_path, {unpack: "*.node"});
console.log(`Removing ${extract_path} ...`);
await fs.rm(extract_path, {recursive: true});