Whisperfish is a third-party, unofficial client for Signal, the private messenger, for SailfishOS. It is available on OpenRepos, or as master-branch builds on Gitlab.
You have a question? Please check our Frequently Asked Questions. If the FAQ does not answer your question, join us on Matrix or Libera.Chat, make an issue on Gitlab or send me an email, Signal or text message!
If you want to edit this wiki, you can do so through this mirror repository.
Two modes of registration
Since beta.11, you may choose between a registration as either primary or secondary device. We recommend using Whisperfish as secondary/linked device.
Notably unimplemented features
- Contact discovery and sharing, see also https://github.com/Michael-F-Bryan/libsignal-service-rs/pull/52.
-
Many GroupV2 features:
- Invites (they need to add you, not invite you!)
- Creating groups/managing groups, although you can do this from Signal Desktop
- Fingerprint changes don't seem to be always handled correctly.
Known issues
- Sending a message to a contact that has registered newly after Februari 2021
(#237).
This is due to Signal stopping the provisioning via E164-based pre-key paths
in their API.
Symptoms: "413 Rate Limit Exceeded" and "404 Not Found" both on
/v2/keys/+...
Specifically to SailfishOS 4.0
Exhaustive list of issues at https://gitlab.com/whisperfish/whisperfish/-/issues?label_name%5B%5D=SailfishOS%3A%3Aversion+4.x
- Registration is impossible on SailfishOS 4.0 without a patch. Please upgrade to SailfishOS 4.1+.
Debugging and logging
We often ask for a trace log when encountering a new issue.
Most interesting data can be obtained by running harbour-whisperfish -v
or
harbour-whisperfish --verbose
on the CLI, either on fingerterm or via SSH,
as of Whisperfish beta.1
or dev.b1016
.
For very obscure bugs (related to CPU usage, hangs, ...), you may need
RUST_LOG=trace harbour-whisperfish
instead.
This is extremely verbose, because it prints trace-logs for every dependency.
Logging with Sailjail
You can start the Whisperfish inside Sailjail (like the launcher icon does) using this command:
/usr/bin/invoker --type=qt5 /usr/bin/harbour-whisperfish
But, the invoker
command used to start Whisperfish within Sailjail refuses to pass --verbose
to the binary. Luckily there's a configuration option to enable it. Edit ~/.config/[rubdos.be?]harbour-whisperfish/config.yml
and set verbose: true
.
Unfortunately the output of invoker
can't be simply redirected to a file (with e.g. > whisperfish.log
), which makes collecting the log messages a bit trickier. The easiest workaround is the following:
- SSH into the device using a PC
- Start Whisperfish with the command above
- Copy the output text to a new text file
Don't forget to censor your logs (see below), and set verbose: false
when you're done.
Censor your logs
Logs contain sensitive information (#124). Currently the following information should be censored:
-
Phone numbers
Note that they can appear with or without a plus sign. Throw these out or mask them (e.g.+324xxxxx
). -
Profile keys and group IDs
Look forGroupContext
and throw out theid
field.
Look forGroupContextV2
and throw out themaster_key
.
Look forprofile_key
and throw it out. -
Passwords
Look out specifically for a line containing a password, e.g.:[…] Some("login=9bad15b5-dca3-418a-9949-7ca357b7fe47&password=xxxxxx") […]
and throw the password out.
The log can contain this line multiple times, which indicates some connection failure. -
UUIDs
You may want to look for UUIDs (like9bad15b5-dca3-418a-9949-7ca357b7fe47
) and throw these out. They are your personal ID, or your friends personal ID(s) on Signal.
Please note that this list and the below python script might not take care of all privacy issues. If in doubt don't make your logs public.
Click this to see a python script that tries to take care of the above.
#!/usr/bin/python
import sys
import re
# read file
###########
with open(sys.argv[1], 'r') as file :
contents = file.read()
# censor
########
# password
contents = re.sub(r'&password=[^"]+"', '&password=censored_pass"', contents)
# uuids
(contents, count) = re.subn(r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', 'censored-uuid-uuid-uuid-12characters', contents)
print('Censored ' + str(count) + ' uuids.')
# phone numbers
# Watch out: These could be with or without the plus sign.
# Better censor anything that looks like a phone number.
# According to https://stackoverflow.com/a/43993566 minimum length without + is 7 digits
# And Wikipedia says it's 15 max. https://en.wikipedia.org/wiki/Telephone_numbering_plan
# This will most probably also kill some IDs and timestamps.
(contents, count) = re.subn(r'[0-9]{7,15}', 'censored_possible_phone_no', contents)
print('Censored ' + str(count) + ' possible phone numbers.')
# parameters -- are followed by data, a commma and the next parameter or a }
def censor_parameter(key, contents):
(out, count) = re.subn(r'([^a-z_]' + key + r'):[^:\}]+((, ?[0-9a-zA-Z\-_]+:)|(\}))', '\1: censored_\1\2', contents)
print('Censored ' + str(count) + " times '" + key + "'.")
return out
contents = censor_parameter('master_key', contents)
contents = censor_parameter('profile_key', contents)
contents = censor_parameter('id', contents)
# contents = censor_parameter('uuid', contents) # should already be censored
# save censored file
####################
newfilename = 'censored.' + sys.argv[1]
with open(newfilename, 'w') as file:
file.write(contents)
print("\nWrote output to file '" + newfilename + "'")