Signal-desktop: [Feature Request] Support 32-bit Windows

Created on 1 Nov 2017  ยท  46Comments  ยท  Source: signalapp/Signal-Desktop

The desktop version for Windows only supports 64-bit Windows. Do you develop a version for 32-bit Windows in future?

Feature Request

Most helpful comment

Just tried setting Signal up on my Surface Pro X and was very surprised to find out that there isn't an ARM64 or 32bit version available.

Please do at least one!

Microsoft is pushing ARM64 heavily on upcoming devices, so this will be a growing issue.

All 46 comments

To be honest, it's not very high on our list. We have more people asking for support for different distributions of Linux. Our research indicates that the vast majority of Windows users are on 64bit installs at this point.

Maybe you could tell me more about your situation? Find others in your situation?

Backblaze claims only 4.3% of their Windows users run 32-bit versions of their software. Assuming it's the same for Signal, it doesn't seem worth bothering with it. As Scott said, I would prefer if they found a way of keeping their Flatpak up to date so that people won't be running ancient versions in a few months.

I'm using 32bit Windows and wonder if it is really so much more work supporting 32bit Windows than some Linux distribution that has much less users.
4.3% of Windows users might still be more than most Linux distributions, regarding that OSX is coming second after Windows...

You are absolutely right that there are fewer Linux users than 32-bit Windows users. However, I'd say there are more Signal Linux users than Signal 32-bit users since Linux users are usually more tech sawy and Signal has always been a nerd program. As Scott said, they are getting more requests for a Flatpak than they are for a 32-bit Windows version. Maybe they will consider making one for 32-bit users if the interest is high when the Flatpak is out, so who knows?

My last post here, don't want to spam Scott with emails. Feel free making a thread on the forum:
https://whispersystems.discoursehosting.net/

I think you will lose less time developing a web-based solution like Whatsapp did, than developing 10 different OS versions.
I also run WIN 7 32 bits and I am annoyed.
Don't lose current Whatsapp/Facebook bad reputation benefits! It's time to...

Backblaze claims only 4.3% of their Windows users run 32-bit versions of their software. Assuming it's the same for Signal, it doesn't seem worth bothering with it.

Firefox's hardware report (source) says that 18% of FireFox users are still on 32-bit operating systems.

2018-05-08_21-07-59

There's a small decline in number of 32-bit users each quarter, but 18% is still a sizeable portion of computer users.

I tried to install Signal in ReactOS. It didn't worked. Because ReactOS doesn't have 64-bit support.

A 32-bit client would be 100% compatible with 64-bit Windows, and would be universal. On a tiny app like this are there even any benefits to being 64-bit only? Microsoft _highly_ recommends using 32-bit Office (on 64-bit machines), unless spreadsheets are so large they run into memory constraints. Only then is 64-bit advised.

I use 32-bit clients whenever possible (VMs, etc) for speed and reduced memory footprint, and was utterly surprised when I found that Signal was 64-bit only.

As of May 2018, Firefox shows 30%+ of users are running 32-bit Firefox , and 18%+ of users are on a 32-bit OS. (Both metrics _exclude_ XP/Vista.) This is a sizable chunk to write off completely.

@a-woolf In general, you should avoid 32bit builds because 64bit has a plentitude of benefits, not limited to:

  • 8 additional general purpose registers
  • sse registers
  • nx bit for pages instead of segments
  • minor security benefits like a large address space which makes countermeasures like ASLR more effective

A more complete list is at wikipedia.

Signal-Desktop uses electron and thus is almost a full browser, not a small app. 32bit binaries would neither be faster (because they would use less registers and not cause significantly more cache misses), nor would the memory footprint increase by a noteworthy amount, since only pointers grow to the double of their size.

But do we have any disadvantage? The 32bit client would run on any windows.
AFAIK Riot also uses electron and runs on 32bit Windows.

I think you will lose less time developing a web-based solution like Whatsapp did, than developing 10 different OS versions.
I also run WIN 7 32 bits and I am annoyed.
Don't lose current Whatsapp/Facebook bad reputation benefits! It's time to...

I fully agree... kill a dozen birds with one stone. Go web-based as opposed to native apps. While most of my gear is x64, I do have a tiny Win10 32-bit tablet/hybrid I use for travel that I can no longer use Signal on. Major bummer. Web-based is definitely the way to go. I understand that there are security concerns with that... aka using a compromised or outdated browser... but that is the same for native apps... if the device is compromised or outdated, it poses increased risk. If you can't do web-based for some reason, at least do x86 for your main platform as mentioned above... then it will work on both x86 and x64 architectures.

I fully agree... kill a dozen birds with one stone. Go web-based as opposed to native apps.

Nah... Web based things are slow and lack offline possibilities (in case you need to read something while disconnected). Telegram also has a native 32bit Windows app. Can't be too difficult if you can cross-compile the soure.

I'd like to mention a case where it's become impossible to run Signal on new(ish) hardware. Some laptops and tablets, even though the hardware is 64bit capable, have shipped with 32bit Windows 10 due to limited eMMC capacity of 32GB and perhaps other reasons. So it has become impossible to run Signal on these types of devices (prob. what also Soldier4Life above has experienced).

I fully agree... kill a dozen birds with one stone. Go web-based as opposed to native apps.

Nah... Web based things are slow and lack offline possibilities (in case you need to read something while disconnected). Telegram also has a native 32bit Windows app. Can't be too difficult if you can cross-compile the soure.

I hear you... it is definitely a trade-off between broad spectrum compatibility and features/performance. It seems like the simple solution would be to just use x86 based architecture for all of Windows Desktop... then it can run on both. Unless there is a specific reason not to do so, that I might be missing.

I doubt I will be installing new copies of an operating system just to run an program that has been working for many years. At least let us use the old app and we can bear any security issues.

I am incline to agree with MagentoUno, as long as the security issues are restricted merely to the 32bit machine, and not compromising the entire signal accounts on the contact list.

I'm currently running Windows 7 32-bit and it's the only desktop PC I have. I use Signal on my phone because it has all the features I require.

I am sure I am not alone in the idea that most users do not care about the architecture of the software, but whether or not they can use it on all of their devices to stay connected.

If I had the skills, I would build a 32-bit release myself, but I do not.

It would be a lot to a lot of people to be able to have this option.

I just wanted to install Signal on my thin laptop, too - tiny ssd, <4gb ram so it's running Win32 OS. Alas, no can do. Bye bye Signal, back to good ol' workin' Telegram. Meh.

Listen, I am a nerd too. I own a Google Pixel 3a and will only buy phones whose bootloaders may be unlocked. My home computer runs Linux Mint.

However, I am at the mercy of my employer during weekdays. I have for years used Google Hangouts to message my wife because I can do so using the computer without having to alternate between my phone and my computer. As many of you know, Google Hangouts/Google Chat is a completely unsecured messaging system and the messages are infinitely stored on Google's servers for you to see. I would like to use Signal on my work Windows desktop computer, but it's running 32-bit Windows. This may not change for a few years when they replace the computer.

So I may be a nerd and have updated phones and a computer. But my workplace is another story. Please make it a priority to have a 32-bit Windows version. If there is already a 64-bit Windows version, is it much more work to port it to a 32-bit Windows version? Is this really an uncommon request?

If there is no 32-bit Windows version, I might want to switch to Whatsapp instead. Whatsapp is now owned by Facebook. I have never trusted Facebook and have not had a Facebook account for years.

@midtempo you'd better switch to Riot.im if you want to stay with open source, this even has a federated server structure. Only downside is that you have to verify every device if you want to have encryption.

But back to Signal: Does a 32 bit version need a lot of rework, or does it just need someone who is able to compile a 32bit version without having to change a lot? In that case it would be great to have the possibility for donating for certain features.

I've switched to Wire by now, it's evolving to a very mature oss client (https://github.com/wireapp/wire) and of course has a 32bit version (https://wire.com/en/download) ... I'd still like to use Signal for my legacy contacts, but as supporting a broad userbase isn't Signal's priority, supporting Signal isn't mine either.

A 32-bit client would be 100% compatible with 64-bit Windows, and would be universal.

ARM64 Windows 10 can run Win32 (x86) apps, but cannot run Win64 (x86-64) apps without recompiling. This reinforces the need for a Win32 build - universal compatibility, as requested here over 2 years ago.

See: https://github.com/signalapp/Signal-Desktop/issues/3156 and https://github.com/signalapp/Signal-Desktop/issues/3745

To add yet another use case, there's also a number of Intel Atom tablets out there (the 32-bit UEFI only ones, ie Clover Trail) which can only run 32-bit Windows 10. Some of us don't have the budget to replace these.

And the above line of "Signal has always been a nerd program" is the wrong approach, and a little bit self-defeating - if you want to get things like Signal into the hands of more people and not just journalists and nerds, you need to make it more widely compatible.

Tech nerd here using a Microsoft Surface Pro X with an arm64 cpu that can run x86 apps but not x64. Both arm64 or x86 builds would work for me, but neither are supported.

VSCode just released arm64 support, here's their github issue: https://github.com/microsoft/vscode/issues/33620

Just build the dang 32 bit version already. People have been asking for it for _years_ now.
_More_ use cases keep coming up, as non-x86 systems can now run x86 code (but not x86-64 code).

Just tried setting Signal up on my Surface Pro X and was very surprised to find out that there isn't an ARM64 or 32bit version available.

Please do at least one!

Microsoft is pushing ARM64 heavily on upcoming devices, so this will be a growing issue.

Just tried setting Signal up on my Surface Pro X and was very surprised to find out that there isn't an ARM64 or 32bit version available.

Please do at least one!

Microsoft is pushing ARM64 heavily on upcoming devices, so this will be a growing issue.

I'm in the exact same boat. I would love to use signal as my sole messaging service, being able to have signal double as my SMS app on my phone is great, but lacking desktop support is frustrating.

Same problem here. Surface Pro X, want to use signal and can't.

I'm coaching several people working with small Atom notebooks. I would like to urge them do kick Whatsapp off their phones and switch to signal, but without a 32 bit desktop version... no chance.

Just tried building Signal Desktop both for arm64 and 32-bit Windows. arm64 will be a bit more difficult due to some native dependencies that need updates (got errors while running set npm_config_arch=arm64 and yarn install), so I think we'll have better chances to build for 32-bit for now.

32-bit builds successfully and boots on my Surface Pro X (arm64), but then it just keeps loading at the splash screen:

image

... at least it's a start ๐Ÿ˜‰

In package.json, under build > win, replace

      "target": [
        "nsis"
      ]

with

      "target": [
        {
          "target": "nsis",
          "arch": [
            "ia32",
            "x64"
          ]
        }
      ]

you will then get a release\win-ia32-unpacked folder which contains a 32-bit build. I'll try to work a bit more on this when I have some more time, probably in a few weeks from now.

Might get a bit closer by running set npm_config_arch=ia32, then yarn install

I started working on 32-bit support, it's more work than expected ๐Ÿ˜… some native modules will need to be compiled for 32-bit (and ideally arm64) as well as they're 64-bit only currently. I'm stuck at one native module, more details here: https://github.com/signalapp/Signal-Desktop/pull/4514 - would appreciate if anyone could help as I'm not familiar with Rust/GN/etc.

UPDATE September 14: think I've found the culprit for the issue mentioned above. Looks like one of ringrtc's dependencies needs an update to support x86. Details: https://github.com/signalapp/ringrtc/pull/12

Hope the Signal team will accept the PRs when they're done! ๐Ÿš€

Hi Dennis, glad to hear that you have taken up the fight. Not having the know-how to help you out, all I can do is to wish you good success, without too much hassle.

Hello Dennis, I'm new to Github. Thanks for looking into a 32 bit version. I can't help with the any software support. However I can make a financial donation to the project. I can't see a "sponsor" on your profile ?

@MagentaUno thanks! I appreciate the offer, but before accepting any donations I need to be 100% sure that the Signal team is willing to look into/approve my PRs related to 32-bit support (I'm not part of the Signal team). I'm currently waiting for one more dependency to be updated, then I'll have a better idea of how much work is left for 32-bit support.

Quite optimistic that I'm pretty close to that already. Hope to have more news within a few weeks (or whenever said dependency will be updated), will keep you posted here.

would be nice to have a 32-Bit version, thanks

I run Windows on a T60p which can't run anything but 32-bit architecture.

@dennisameling Just checking to see if you've been able to make any progress. I'll keep checking back, but I guess I'll need to use Telegram.

To earlier comments in the thread, some of us are "nerds" enough that we're trying to bring our Boomer parents into the 20th century. I doubt mine are running anything above Windows XP right now, but I really want to be able to use a secure video client with them when we talk. They don't even understand what 32bit or 64bit IS and we're 3000 miles apart, doing tech support over chat - Signal of all things. And they can't figure out why it won't install.

So thank you to Dennis for at least making the attempt!

@skerichards Thanks for checking in. I'm very keen on getting the ball rolling here, but I'm stuck at https://github.com/signalapp/ringrtc/pull/12 where I'm waiting for a dependency (https://github.com/neon-bindings/neon) to update to Node's N-API. Once that's done, it should become a lot easier to get 32-bit/arm64 builds for ringrtc and then Signal Desktop itself.

I have all notifications turned on for the neon repo so that I know once they have a migration doc in place. You can subscribe to https://github.com/neon-bindings/neon/issues/596 to follow the progress there. Gotta say the Neon team has been doing an awesome job working towards N-API go-live - just look at the frequency at which they're releasing new versions: https://github.com/neon-bindings/neon/releases

When the migration doc is in place, I will be able to support the ringrtc maintainers migrate to the Neon N-API backend and (hopefully) get cross-compilation to 32-bit/arm64 working. It's just a matter of time, fingers crossed ๐Ÿคž๐Ÿผ

I have been using WhatsApp as an alternative because it can be run on my 32-bit Windows work computer, and it works pretty much the same way as Signal. This is because WhatsApp uses Signal as the central component. Starting this February though, Facebook is changing the terms of use of WhatsApp to share more data and analytics with Facebook. This has now made this project more important.

Dennis, your work in this regard is really appreciated to those following this thread.

WhatsApp uses Signal as the central component

Yes, we heard that they use the "same protocol". Did they proof that? It's all about the correct implementation. "And now we use 4096 bit xyz encryption which Tesla uses somewhere in their car, so your chat is secure. Fully E2EE*. Trust us."

This has now made this project more important.

You are absolutely right. One more reason. But in general it would be good to support as much as possible different versions of the yet good platform set. To give everyone (even kids) the chance to use well secured communication tools even on older hardware (at least my kids won't have the newest hardware until they buy them by themselves ๐Ÿ˜‰).
So thanks for working on that long lasting topic ๐Ÿ‘.

*) for user satisfaction we backup the keys to help you restoring your device at anytime...

Btw, Pidgin has a plugin for Signal: https://pidgin.im/plugins/?publisher=all&query=&type=
Maybe this helps getting Signal to work on 32bit machines.

Btw, Pidgin has a plugin for Signal: https://pidgin.im/plugins/?publisher=all&query=&type=

If I get it right, the author of this plugin is not too optimistic:

"The new and annoying dependency of zkgroups.dll for the V2 groups is a sign they will eventually move away from the current implementation completely. It looks like with my plug-ins (signal and signald), I am basically riding dying horses. I am considering to throw things. It was fun while it lasted, though." [https://github.com/hoehermann/purple-signal/issues/1]

Hi there. Thanks for mentioning purple-signal. I am the author of purple-signal. I want to access signal without a resource-hogging browser solution. Long-term goal is a fully-fledged signal integration in Pidgin (with Pidgin 3 โ€“ if it ever gets released โ€“ probably supporting audio and video conferencing, too) and chatty. However, with libsignal-service-java being moved and hidden within the Signal-Android sources, libsignal-protocol-c looking abandoned and libsignal-client not deemed ready for production, I am trying to hit an elusive target which turns out to be moving rather swiftly. I will not supply users with the native binaries libsignal-service-java is depending on, especially if the number of dependencies increases. Right now with dennisameling, we are in luck, but that may change any time.

32 bit version when :(

Great news! I was able to get Signal to boot on Windows 10 32-bit (in a VM):

image

โš ๏ธ This really only is a proof-of-concept for now!

We at least need the following PRs to be merged before the Signal team could even consider 32-bit builds:

For cross-reference: issue for Windows ARM64 support: https://github.com/signalapp/Signal-Desktop/issues/3745

I'm working from this branch: https://github.com/dennisameling/Signal-Desktop/tree/windows-multi-arch-support

โœ… All automated tests are passing after applying the PRs above:


Test logs

PS C:\Users\Admin\repos\signal-desktop> yarn test
yarn run v1.22.10
$ yarn test-node && yarn test-electron
$ electron-mocha --file test/setup-test-node.js --recursive test/app test/modules ts/test-node ts/test-both

x-attr dependency did not load successfully


  Attachments
    createWriterForNew
      โˆš should write file to disk and return path
    createWriterForExisting
      โˆš should write file to disk on given path and return path
      โˆš throws if relative path goes higher than root
    createReader
      โˆš should read file from disk
      โˆš throws if relative path goes higher than root
    copyIntoAttachmentsDirectory
      โˆš throws if passed a non-string
      โˆš returns a function that rejects if the source path is not a string
      โˆš returns a function that rejects if the source path is not in the user config directory
      โˆš returns a function that copies the source path into the attachments directory
    createDeleter
      โˆš should delete file from disk
      โˆš throws if relative path goes higher than root
    createName
      โˆš should return random file name with correct length
    getRelativePath
      โˆš should return correct path
    createAbsolutePathGetter
      โˆš combines root and relative path
      โˆš throws if relative path goes higher than root

  SignalMenu
    createTemplate
      macOS
        without setup options
          โˆš should return correct template
        with setup options
          โˆš should return correct template
      Windows
        without setup options
          โˆš should return correct template
        with setup options
          โˆš should return correct template
      Linux
        without setup options
          โˆš should return correct template
        with setup options
          โˆš should return correct template

  Protocol Filter
    _urlToPath
      โˆš returns proper file path for unix style file URI with hash
      โˆš returns proper file path for unix style file URI with querystring
      โˆš returns proper file path for unix style file URI with hash and querystring
      โˆš returns proper file path for file URI on windows
      โˆš translates from URL format to filesystem format
      โˆš translates from URL format to filesystem format
      โˆš handles SMB share path
      โˆš handles SMB share path on windows
      โˆš hands back a path with .. in it

  SpellCheck
    getLanguages
      โˆš works with locale and base available
      โˆš works with neither locale nor base available
      โˆš works with only base locale available
      โˆš works with only full locale available
      โˆš works with base provided and base available
      โˆš works with base provided and base not available

  Link previews
    #isLinkSafeToPreview
      โˆš returns false for invalid URLs
      โˆš returns false for non-HTTPS URLs
      โˆš returns false if the link is "sneaky"
      โˆš returns true for "safe" urls
    #findLinks
      โˆš returns all links if no caretLocation is provided
      โˆš includes all links if cursor is not in a link
      โˆš excludes a link not at the end if the caret is inside of it
      โˆš excludes a link not at the end if the caret is at its end
      โˆš excludes a link at the end of the caret is inside of it
      โˆš includes link at the end if cursor is at its end
    #isLinkSneaky
      โˆš returns true for =
      โˆš returns true for $
      โˆš returns true for +
      โˆš returns true for ^
      โˆš returns true for URLs with a length of 4097 or higher
      auth
        โˆš returns true for hrefs with auth (or pretend auth)
      domain
        โˆš returns false for all-latin domain
        โˆš returns false for IPv4 addresses
        โˆš returns true for IPv6 addresses
        โˆš returns true for Latin + Cyrillic domain
        โˆš returns true for Latin + Greek domain
        โˆš returns true for ASCII and non-ASCII mix
        โˆš returns true for Latin + High Greek domain
        โˆš returns true if the domain doesn't contain a .
        โˆš returns true if the domain has any empty labels
        โˆš returns true if the domain is longer than 2048 UTF-16 code points
      pathname
        โˆš returns false for no pathname
        โˆš returns false if the pathname contains valid characters
        โˆš returns true if the pathname contains invalid characters
      query string
        โˆš returns false for no query
        โˆš returns false if the query string contains valid characters
        โˆš returns true if the query string contains invalid characters
      hash
        โˆš returns false for no hash
        โˆš returns false if the hash contains valid characters
        โˆš returns true if the hash contains invalid characters

  Privacy
    redactPhoneNumbers
      โˆš should redact all phone numbers
    redactUuids
      โˆš should redact all uuids
    redactGroupIds
      โˆš should redact all group IDs
      โˆš should remove newlines from redacted group IDs
      โˆš should remove newlines from redacted group V2 IDs
    redactAll
      โˆš should redact all sensitive information
    _redactPath
      โˆš should redact file paths
      โˆš should redact URL-encoded paths
      โˆš should redact stack traces with both forward and backslashes
      โˆš should redact stack traces with escaped backslashes

  Attachment
    replaceUnicodeOrderOverrides
      โˆš should sanitize left-to-right order override character
      โˆš should sanitize right-to-left order override character
      โˆš should sanitize multiple override characters
      โˆš should ignore non-order-override characters (112ms)
    replaceUnicodeV2
      โˆš should remove all bad characters
      โˆš should should leave normal filename alone
      โˆš should handle missing fileName
    removeSchemaVersion
      โˆš should remove existing schema version
    migrateDataToFileSystem
      โˆš should write data to disk and store relative path to it
      โˆš should skip over (invalid) attachments without data
      โˆš should throw error if data is not valid

  Contact
    parseAndWriteAvatar
      โˆš handles message with no avatar in contact
      โˆš turns phone numbers to e164 format
      โˆš removes contact avatar if it has no sub-avatar
      โˆš writes avatar to disk
      โˆš removes number element if it ends up with no value
      โˆš drops address if it has no real values
      โˆš removes invalid elements if no values remain in contact
      โˆš handles a contact with just organization
    _validate
      โˆš returns error if contact has no name.displayName or organization
      โˆš logs if no values remain in contact

  Errors
    toLogFormat
      โˆš should return error stack trace if present
      โˆš should return error string representation if stack is missing
      โˆš should return `0` argument
      โˆš should return `false` argument
      โˆš should return `null` argument
      โˆš should return `undefined` argument

  Message
    createAttachmentDataWriter
      โˆš should ignore messages that didnโ€™t go through attachment migration
      โˆš should ignore messages without attachments
      โˆš should write attachments to file system on original path
      โˆš should process quote attachment thumbnails
      โˆš should process contact avatars
    initializeSchemaVersion
      โˆš should ignore messages with previously inherited schema
      for message without attachments
        โˆš should initialize schema version to zero
      for message with attachments
        โˆš should inherit existing attachment schema version
    upgradeSchema
      โˆš should upgrade an unversioned message to the latest version
      with multiple upgrade steps
        โˆš should return last valid message when any upgrade step fails
        โˆš should skip out-of-order upgrade steps
    _withSchemaVersion
      โˆš should require a version number
      โˆš should require an upgrade function
      โˆš should skip upgrading if message has already been upgraded
      โˆš should return original message if upgrade function throws
      โˆš should return original message if upgrade function returns null
    _mapQuotedAttachments
      โˆš handles message with no quote
      โˆš handles quote with no attachments
      โˆš handles zero attachments
      โˆš handles attachments with no thumbnail
      โˆš does not eliminate thumbnails with missing data field
      โˆš calls provided async function for each quoted attachment
    _mapContact
      โˆš handles message with no contact field
      โˆš handles one contact

  MIME
    isJPEG
      โˆš should return true for `image/jpeg`
      โˆš should return false for `jpg`
      โˆš should return false for `jpeg`
      โˆš should return false for `image/jpg`
      โˆš should return false for `image/gif`
      โˆš should return false for `image/tiff`
      โˆš should return false for `application/json`
      โˆš should return false for `0`
      โˆš should return false for `false`
      โˆš should return false for `null`
      โˆš should return false for `undefined`

  SchemaVersion
    isValid
      โˆš should return true for positive integers
      โˆš should return false for any other value (40ms)

  LeftPane
    getRowFromIndex
      given only pinned chats
        โˆš returns pinned chats, not headers
      given only non-pinned chats
        โˆš returns conversations, not headers
      given only pinned and non-pinned chats
        โˆš returns headers and conversations
      given not showing archive with archived conversation
        โˆš returns an archive button last
      given showing archive and archive chats
        โˆš returns archived conversations

  groupMediaItemsByDate
    โˆš should group mediaItems

  license comments
    โˆš includes a license comment at the top of every relevant file (214ms)

  isLinkPreviewDateValid
    โˆš returns false for non-numbers
    โˆš returns false for zero
    โˆš returns false for NaN
    โˆš returns false for any infinite value
    โˆš returns false for timestamps more than a day from now
    โˆš returns true for timestamps before tomorrow

  uploadDebugLogs
    โˆš makes a request to get the S3 bucket, then uploads it there
    โˆš rejects if we can't get a token
    โˆš rejects with an invalid token body
    โˆš rejects if the upload doesn't return a 204

  logging
    #isLineAfterDate
      โˆš returns false if falsy
      โˆš returns false if invalid JSON
      โˆš returns false if date is invalid
      โˆš returns false if log time is invalid
      โˆš returns false if date before provided date
      โˆš returns true if date is after provided date
    #eliminateOutOfDateFiles
      โˆš deletes an empty file
      โˆš deletes a file with invalid JSON lines
      โˆš deletes a file with all dates before provided date
      โˆš keeps a file with first line date before provided date
      โˆš keeps a file with last line date before provided date
    #eliminateOldEntries
      โˆš eliminates all non-parsing entries
      โˆš preserves all lines if before target date
    #fetchLog
      โˆš returns error if file does not exist
      โˆš returns empty array if file has no valid JSON lines
      โˆš returns just three fields in each returned line
    #fetch
      โˆš returns single entry if no files
      โˆš returns sorted entries from all files

  MemberRepository
    #updateMembers
      โˆš updates with given members
    #getMemberById
      โˆš returns undefined when there is no search id
      โˆš returns a matched member
      โˆš returns undefined when it does not have the member
    #getMemberByUuid
      โˆš returns undefined when there is no search uuid
      โˆš returns a matched member
      โˆš returns undefined when it does not have the member
    #search
      given a prefix-matching string on last name
        โˆš returns the match
      given a prefix-matching string on first name
        โˆš returns the match
      given a prefix-matching string on profile name
        โˆš returns the match
      given a prefix-matching string on title
        โˆš returns the match
      given a match in the middle of a name
        โˆš returns zero matches

  matchMention
    โˆš handles an AtMentionify from clipboard
    โˆš handles an MentionBlot from clipboard
    โˆš converts a missing AtMentionify to string
    โˆš converts a missing MentionBlot to string
    โˆš passes other clipboard elements through

  getDeltaToRemoveStaleMentions
    given text
      โˆš retains the text
    given stale and valid mentions
      โˆš retains the valid and replaces the stale
    given emoji embeds
      โˆš retains the embeds
    given other ops
      โˆš passes them through

  getTextAndMentionsFromOps
    given only text
      โˆš returns only text trimmed
      โˆš returns trimmed of trailing newlines
    given text, emoji, and mentions
      โˆš returns the trimmed text with placeholders and mentions
    given only mentions
      โˆš returns the trimmed text with placeholders and mentions
      โˆš does not trim newlines padding mentions

  getDeltaToRestartMention
    given text and emoji
      โˆš returns the correct retains, a delete, and an @

  Attachment
    getUploadSizeLimitKb
      โˆš returns 6000 kilobytes for supported non-GIF images
      โˆš returns 25000 kilobytes for GIFs
      โˆš returns 100000 for other file types
    getFileExtension
      โˆš should return file extension from content type
      โˆš should return file extension for QuickTime videos
    getSuggestedFilename
      for attachment with filename
        โˆš should return existing filename if present
      for attachment without filename
        โˆš should generate a filename based on timestamp
      for attachment with index
        โˆš should generate a filename based on timestamp
    isVisualMedia
      โˆš should return true for images
      โˆš should return true for videos
      โˆš should return false for voice message attachment
      โˆš should return false for other attachments
    isFile
      โˆš should return true for JSON
      โˆš should return false for images
      โˆš should return false for videos
      โˆš should return false for voice message attachment
    isVoiceMessage
      โˆš should return true for voice message attachment
      โˆš should return true for legacy Android voice message attachment
      โˆš should return false for other attachments

  Contact
    getName
      โˆš returns displayName if provided
      โˆš returns organization if no displayName
      โˆš returns givenName + familyName if no displayName or organization
      โˆš returns just givenName
      โˆš returns just familyName
    contactSelector
      โˆš eliminates avatar if it has had an attachment download error
      โˆš does not calculate absolute path if avatar is pending
      โˆš calculates absolute path

  Message
    initializeAttachmentMetadata
      โˆš should classify visual media attachments
      โˆš should classify file attachments
      โˆš should classify voice message attachments
      โˆš does not include long message attachments
      โˆš handles not attachments

  MIME
    isGif
      โˆš returns true for GIFs
      โˆš returns false for non-GIFs

  Settings
    getAudioNotificationSupport
      โˆš returns native support on macOS
      โˆš returns no support on Windows 7
      โˆš returns native support on Windows 8
      โˆš returns custom support on Linux
    isAudioNotificationSupported
      โˆš returns true on macOS
      โˆš returns false on Windows 7
      โˆš returns true on Windows 8
      โˆš returns true on Linux
    isNotificationGroupingSupported
      โˆš returns true on macOS
      โˆš returns true on Windows 7
      โˆš returns true on Windows 8
      โˆš returns true on Linux
    isHideMenuBarSupported
      โˆš returns false on macOS
      โˆš returns true on Windows 7
      โˆš returns true on Windows 8
      โˆš returns true on Linux
    isDrawAttentionSupported
      โˆš returns false on macOS
      โˆš returns true on Windows 7
      โˆš returns true on Windows 8
      โˆš returns true on Linux

  updater/signatures
    #getVersion
      โˆš successfully gets version
    #getUpdateFileName
      โˆš successfully gets version
    #isUpdateFileNameValid
      โˆš returns true for normal filenames
      โˆš returns false for problematic names
    #validatePath
      โˆš succeeds for simple children
      โˆš returns false for problematic names

  updater/curve
    โˆš roundtrips
    โˆš verifies with our own key

  updater/signatures
    โˆš _getFileHash returns correct hash (54ms)
    โˆš roundtrips binary file writes
    โˆš roundtrips signature (90ms)
    โˆš fails signature verification if version changes (90ms)
    โˆš fails signature verification if signature tampered with (107ms)
    โˆš fails signature verification if binary file tampered with (102ms)
    โˆš fails signature verification if signed by different key (89ms)

  combineNames
    โˆš returns undefined if no names provided
    โˆš returns first name only if family name not provided
    โˆš returns returns combined names
    โˆš returns given name first if names in Chinese
    โˆš returns given name first if names in Japanese
    โˆš returns given name first if names in Korean

  getAnimatedPngDataIfExists
    โˆš returns null for empty buffers
    โˆš returns null for non-PNG files
    โˆš returns null for non-animated PNG files
    โˆš returns data for animated PNG files

  getOwn
    โˆš returns undefined when asking for a non-existent property
    โˆš returns undefined when asking for a non-own property
    โˆš returns own properties
    โˆš works even if `hasOwnProperty` has been overridden for the object

  getTextWithMentions
    given mention replacements
      โˆš replaces them
      โˆš sorts them to go from back to front

  getUserAgent
    โˆš returns the right User-Agent on Windows
    โˆš returns the right User-Agent on macOS
    โˆš returns the right User-Agent on Linux
    โˆš omits the platform on unsupported platforms

  isFileDangerous
    โˆš returns false for images
    โˆš returns false for documents
    โˆš returns true for executable files
    โˆš returns true for Microsoft settings files
    โˆš returns false for non-dangerous files that end in ".", which can happen on Windows
    โˆš returns true for dangerous files that end in ".", which can happen on Windows
    โˆš returns false for empty filename
    โˆš returns false for exe at various parts of filename
    โˆš returns true for upper-case EXE

  isMuted
    โˆš returns false if passed undefined
    โˆš returns false if passed a date in the past
    โˆš returns false if passed a date in the future

  isPathInside
    โˆš returns false if the child path is not inside the parent path
    โˆš returns true if the child path is inside the parent path

  LatestQueue
    โˆš if the queue is empty, new tasks are started immediately
    โˆš only enqueues the latest operation

  nonRenderedRemoteParticipant
    โˆš returns a video request object a width and height of 0

  normalizeGroupCallTimestamp
    โˆš returns undefined if passed NaN
    โˆš returns undefined if passed 0
    โˆš returns undefined if passed a negative number
    โˆš returns undefined if passed a string that cannot be parsed as a number
    โˆš returns undefined if passed a BigInt of 0
    โˆš returns undefined if passed a negative BigInt
    โˆš returns undefined if passed a non-parseable type
    โˆš returns positive numbers passed in
    โˆš parses strings as numbers
    โˆš only parses the first 15 characters of a string
    โˆš converts positive BigInts to numbers

  sgnlHref
    isSgnlHref
      โˆš returns false for non-strings
      โˆš returns false for invalid URLs
      โˆš returns false if the protocol is not "sgnl:"
      โˆš returns true if the protocol is "sgnl:"
      โˆš accepts URL objects
    isSignalHttpsLink
      โˆš returns false for non-strings
      โˆš returns false for invalid URLs
      โˆš returns false if the protocol is not "https:"
      โˆš returns true if the protocol is "https:"
      โˆš returns false if username or password are set
      โˆš returns false if port is set
      โˆš accepts URL objects
    parseSgnlHref
      โˆš returns a null command for invalid URLs
      โˆš parses the command for URLs with no arguments
      โˆš parses a command's arguments
      โˆš treats the port as part of the command
      โˆš ignores duplicate query parameters
      โˆš includes hash
      โˆš ignores other parts of the URL
      โˆš doesn't do anything fancy with arrays or objects in the query string
    parseSignalHttpsLink
      โˆš returns a null command for invalid URLs
      โˆš handles signal.art links
      โˆš handles signal.group links

  sleep
    โˆš returns a promise that resolves after the specified number of milliseconds

  sniffImageMimeType
    โˆš returns undefined for empty buffers
    โˆš returns undefined for non-image files
    โˆš sniffs ICO files
    โˆš sniffs BMP files
    โˆš sniffs GIF files
    โˆš sniffs WEBP files
    โˆš sniffs PNG files
    โˆš sniffs JPEG files
    โˆš handles ArrayBuffers

  sortByTitle
    โˆš does nothing to arrays that don't need to be sorted
    โˆš sorts the array by title
    โˆš doesn't mutate its argument

  toggleMaximizedBrowserWindow
    โˆš maximizes an unmaximized window
    โˆš unmaximizes a maximized window

  writeWindowsZoneIdentifier
    โˆš writes zone transfer ID 3 (internet) to the Zone.Identifier file
    โˆš fails if there is an existing Zone.Identifier file
    โˆš fails if the original file does not exist
    โˆš fails if not on Windows

  environment utilities
    parseEnvironment
      โˆš returns Environment.Production for non-strings
      โˆš returns Environment.Production for invalid strings
      โˆš parses "development" as Environment.Development
      โˆš parses "production" as Environment.Production
      โˆš parses "staging" as Environment.Staging
      โˆš parses "test" as Environment.Test
      โˆš parses "test-lib" as Environment.TestLib

  shouldUseFullSizeLinkPreviewImage
    โˆš returns false if there is no image
    โˆš returns false is the preview is a sticker pack
    โˆš returns false if either of the image's dimensions are missing
    โˆš returns false if either of the image's dimensions are <200px
    โˆš returns false if the image is square
    โˆš returns false if the image is roughly square
    โˆš returns false for large attachments that aren't images
    โˆš returns true for larger images

  cleanDataForIpc
    โˆš does nothing to JSON primitives
    โˆš does nothing to undefined
    โˆš converts BigInts to strings
    โˆš converts functions to `undefined` but does not mark them as cleaned, for backwards compatibility
    โˆš converts symbols to `undefined`
    โˆš converts ArrayBuffers to `undefined`
    โˆš converts valid dates to ISO strings
    โˆš converts invalid dates to `undefined`
    โˆš converts other iterables to arrays
    โˆš deeply cleans arrays, removing `undefined` and `null`s
    โˆš deeply cleans sets and converts them to arrays
    โˆš deeply cleans maps and converts them to objects
    โˆš calls `toNumber` when available
    โˆš deeply cleans objects with a `null` prototype
    โˆš deeply cleans objects with a prototype of `Object.prototype`
    โˆš deeply cleans class instances

  both/state/selectors/conversations
    #getConversationSelector
      โˆš returns empty placeholder if falsey id provided
      โˆš returns empty placeholder if no match
      โˆš returns conversation by e164 first
      โˆš returns conversation by uuid
      โˆš returns conversation by groupId
      โˆš returns conversation by conversationId
      โˆš does proper caching of result
    #getLeftPaneList
      โˆš sorts conversations based on timestamp then by intl-friendly title
      given pinned conversations
        โˆš sorts pinned conversations based on order in storage

  both/state/selectors/items
    #getPinnedConversationIds
      โˆš returns pinnedConversationIds key from items
      โˆš returns empty array if no saved data

  both/state/selectors/search
    #getMessageSearchResultSelector
      โˆš returns undefined if message not found in lookup
      โˆš returns undefined if type is unexpected
      โˆš returns incoming message
      โˆš returns outgoing message and caches appropriately

  assert
    โˆš does nothing if the assertion passes
    โˆš throws because we're in a test environment

  assignWithNoUnnecessaryAllocation
    โˆš returns the same object if there are no modifications
    โˆš returns a new object if there are modifications
    โˆš only performs a shallow comparison
    โˆš doesn't modify the original object when there are no modifications
    โˆš doesn't modify the original object when there are modifications

  calling notification helpers
    getCallingNotificationText
      โˆš says that the call has ended
      โˆš includes the creator's first name when describing a call
      โˆš if the creator doesn't have a first name, falls back to their title
      โˆš has a special message if you were the one to start the call
      โˆš handles an unknown creator

  isIterable
    โˆš returns false for non-iterables
    โˆš returns true for iterables

  makeLookup
    โˆš returns an empty object if passed an empty array
    โˆš returns an object that lets you look up objects by string key
    โˆš if there are duplicates, the last one wins
    โˆš ignores undefined properties
    โˆš allows key of 0
    โˆš converts the lookup to a string
    โˆš looks up own and inherited properties

  reallyJsonStringify
    โˆš returns the same thing as JSON.stringify when JSON.stringify returns a string
    โˆš returns a string when JSON.stringify returns undefined
    โˆš returns a string when JSON.stringify would error

  themeClassName
    โˆš returns "light-theme" when passed a light theme
    โˆš returns "dark-theme" when passed a dark theme

  version utilities
    isBeta
      โˆš returns false for non-beta version strings
      โˆš returns true for beta version strings

  both/util/webSafeBase64
    โˆš roundtrips with all elements
    #toWebSafeBase64
      โˆš replaces +
      โˆš replaces /
      โˆš removes =
    #fromWebSafeBase64
      โˆš replaces -
      โˆš replaces _
      โˆš adds ===
      โˆš adds ==
      โˆš adds =


  449 passing (2s)

$ yarn grunt test
$ grunt test
Running "unit-tests" task
Starting path C:\Users\Admin\repos\signal-desktop\node_modules\.bin\electron.cmd with args [ 'C:\\Users\\Admin\\repos\\signal-desktop\\main.js' ]
App started. Now waiting for test results...
>> 459 tests passed.

Running "lib-unit-tests" task
Starting path C:\Users\Admin\repos\signal-desktop\node_modules\.bin\electron.cmd with args [ 'C:\\Users\\Admin\\repos\\signal-desktop\\main.js' ]
App started. Now waiting for test results...
>> 123 tests passed.

Done.
Done in 23.69s.

I welcome dennisameling's win32 builds of zkgroup.dll very much. The node binary seems to be okay for node usage, but does anyone know any sources for a win32 build of signal_jni.dll for native use? My users request it, but I do not really want to build it myself.

Was this page helpful?
0 / 5 - 0 ratings