Skip to content
This repository has been archived by the owner on Oct 14, 2022. It is now read-only.

Felix' Wire API File Tests

Fi0x edited this page Dec 4, 2020 · 23 revisions

The goal of these test is finding out how to send and receive files in Wire

Analysis of the Wire API

Getting information from the List of Operations

Analyzing the Wire repositories on GitHub

Testing in Java

  • Checking the notification received when another client sends a file

Results

List of Operations

Since there are no special HTTP requests to get files, audio messages, videos or pictures, the website was not helpful at the beginning. But after analyzing file transport on other repositories and testing it out on our client, we realized that a file needs to be uploaded before a link to it can be sent to the recipient. With this knowledge we found the /assets/v3 POST request that uploads an asset, which is exactly what we want.

Analyzing the wire repositories

Wire xenon (repository)

This repository provided some useful classes that are also added in lithium. The classes we thought might be important are: AudioPreview, FileAssetPreview, VideoPreview, AudioAsset, FileAsset, Picture, VideoAsset. These classes all implement the Igeneric interface and the four classes that are not called Preview additionally implement the IAsset interface. More information about these classes will be in the litium analysis.

The other classes we found and did not analyze yet are: AttachmentMessage, AudioMessage, ImageMessage, VideoMessage. These classes implement the MessageAssetBase.

Wire lithium (repository)

Since the litium repository clones the xenon files, we started by analyzing the classes we found in xenon and searched for code that calls these classes. We found out the following about these classes:

  • AudioPreview implements IGeneric
  • FileAssetPreview implements IGeneric
    • Is always created and sent before FileAsset
    • Is sent as a normal message
  • VideoPreview implements IGeneric
  • AudioAsset implements IGeneric and IAsset
  • FileAsset implements IGeneric and IAsset
    • Only the first two constructors are used, the one that contains an asset key is never called.
    • FileAssetPreview is always created and sent to the user before
    • This is uploaded to the server and then the assetKey and assetToken are set
    • The last step is to send a message with this as content to the recipient
  • Picture implements IGeneric and IAsset
  • VideoAsset implements IGeneric and IAsset

Tests in Java

Reading the notification received by a sent file

By analyzing the HTTP response, we found out, that the body contains the exact same information as a ping and text message do. This happens because the entire generic message gets encrypted and therefor it is not possible to know what type of a message you received until you decrypt it.

With this knowledge, we added a print right after the decryption of the message that shows us some more information about the decrypted generic message. The following table shows the booleans we tested and the message types they are active with

Sent Asset Text Knock Calling Confirmation Deleted Edited Ephemeral Location
Picture ✔️
Document ✔️
PNG ✔️✔️
Video ✔️✔️✔️
Voice msg ✔️✔️
Gif ✔️ ✔️
Normal text ✔️
Link ✔️
Emoji ✔️
@person ✔️
Ping ✔️
Calls ✔️
Received ✔️✔️
Deleting msg ✔️
Editing msg ✔️
Timed msg ✔️
Location ✔️

We tested the following booleans as well, but they were always false: Availability, Button Action, Button Confirmation, Cleared, Client Action, Composite, External, Hidden, Image, Read, Reaction.

Receiving a Gif takes two notifications, the first is a text notification, the second contains an asset. Voice calls and video calls create one notification for starting and one for ending the call. When the chat partner receives a message, he sends two "confirmation" messages back. The deleted notification is for deleting a picture, document, PNG, video or Gif. The edited boolean is for editing a text message. Some message types are always sent two or three times, like documents. This can be explained by looking at the lithium code, which seems to send a preview first, and after that the real file.

Asset content of the first file-message

  • original
    • mime_type
    • size
    • name
    • image
      • width
      • height
  • expects_read_confirmation
  • legal_hold_status

Asset content of the second file-message

  • uploaded
    • otr_key
    • sha256
    • asset_id
  • expects_read_confirmation
  • legal_hold_status

The "original" and "uploaded" variables are contained in all other messages that contain the asset key. This means that they are not useful to determine weather the received message is a file or something else. But the variables "expects_read_confirmation" and "legal_hold_status" are only contained in both file messages and both PNG-messages. This leads to the conclusion that the PNGs we sent were handled as files, since the only difference between them and the file messages is the mime_type. There is also a difference between a video that was recorded on the phone and a video that was uploaded on a pc. The video from the phone creates three messages as shown in the table above, but the video from the pc only creates two messages that have the layout of a file-message. The video to test this took a while to upload, so there was a delay between the first and second message, which matches the time the upload took. Therefor we can assume that the second message with the "uploaded" key is only sent after the file was uploaded successfully.

Trying to send a file

To send a file, we need to put the file into a generic message, encrypt the generic message and then send the encrypted data. After analyzing lithium, we decided to use the FileAsset and FileAssetPreview classes from that repository. This way we make no redundant work and reduce the risk of mistakes.

Using FileAsset from lithium

The FileAsset class from lithium has multiple constructors, which we modified slightly to fit our needs. After creating a FileAsset, we need to call the createGenericMsg method, to transform the FileAsset into a generic message which can then be handled like any other message we send. The problem in transforming to a generic message is, that the generic message requires the following fields to be filled.

  • assetKey: needs to be set manually
  • assetToken: needs to be set manually
  • otrKey: randomly generated
  • sha256: generated with the encBytes that are generated automatically
  • file: provided in the constructor parameters
  • mimeType: provided in the constructor parameters
  • UUID: provided in the constructor parameters

For the first message we did not know what to set the assetKey, assetToken and mimeType to. So we provided an empty String for the mimeType and did not set the assetKey and assetToken. This lead to an error which we fixed by putting a random String to the assetKey and assetToken. After sending a message with these values, we got a message, but it was not recognized correctly. That led us to belief that we had to send a FileAssetPreview first.

Using FileAsset and FileAssetPreview from lithium

Because sending a FileAsset on its own did not work, we added a second message containing a FileAssetPreview that we sent just before the actual message. The constructor of the FileAssetPreview class requires a name instead of a whole file and a size parameter in addition to the parameters the FileAsset constructor uses. After providing these values and sending both messages, we had a success. The file was recognized by the web-app, but could not be downloaded. To fix this, we tried setting the mimeType manually, but that did not help.

After analyzing the lithium code again, we found out, that they first send the preview and before they send the real message, they upload the asset. To upload the asset we tested the /assets/v3 POST request from the wire API list of operations and after another look at the lithium code we had success. The POST request produces a response that contains a key and a token that can be used to download the asset again. Theses need to be sent to the recipient as part of the second message.