Skip to content

Commit

Permalink
Add timestamp to contact signature object
Browse files Browse the repository at this point in the history
  • Loading branch information
cammellos committed Oct 4, 2021
1 parent 44d9596 commit 52209af
Showing 1 changed file with 34 additions and 71 deletions.
105 changes: 34 additions & 71 deletions docs/draft/6-payloads.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ as various clients created using different technologies.
- [Audio content type](#audio-content-type)
- [Message types](#message-types)
- [Clock vs Timestamp and message ordering](#clock-vs-timestamp-and-message-ordering)
- [Signature](#signature)
- [ContactRequestSignature](#contact-request-signature)
- [Chats](#chats)
- [Contact Update](#contact-update)
- [Payload](#payload-2)
Expand All @@ -47,8 +47,6 @@ as various clients created using different technologies.
- [Payload](#payload-3)
- [Contact Request](#contact-request)
- [Backwards compatibility](#backwards-compatibility)
- [Contacts persistence](#contacts-persistence)
- [Contacts Sync](#contacts-sync)
- [EmojiReaction](#emojireaction)
- [SyncInstallationContact](#syncinstallationcontact)
- [Payload](#payload-4)
Expand Down Expand Up @@ -125,10 +123,9 @@ message ChatMessage {
AudioMessage audio = 11;
}
// Signature of the receiving user. Only sent in one on one messages.
// That signature is received when teh other user sends a contact request.
// It is used to prove that we were once contacts
string signature = 12;
// ContactRequestSignature is a signature that proves that the receiving user
// has added us in the contacts
ContactRequestSignature contact_request_signature = 12;
enum ContentType {
UNKNOWN_CONTENT_TYPE = 0;
Expand Down Expand Up @@ -158,7 +155,7 @@ message ChatMessage {
| 7 | message_type | `MessageType` | The type of message, different for one-to-one, public or group chats |
| 8 | content_type | `ContentType` | The type of the content of the message |
| 9 | payload | `Sticker` I `Image` I `Audio` I `nil` | The payload of the message based on the content type |
| 10 | signature | `string` | Signature of the receiving user |
| 10 | contact_request_signature | `ContactRequestSignature` | Signature of the receiving user |

#### Content types

Expand Down Expand Up @@ -288,15 +285,33 @@ Messages with a `clock` less than `120` seconds under the Whisper/Waku timestamp

The node uses `clock` value for the message ordering. The algorithm used, and the distributed nature of the system produces casual ordering, which might produce counter-intuitive results in some edge cases. For example, when a user joins a public chat and sends a message before receiving the exist messages, their message `clock` value might be lower and the message will end up in the past when the historical messages are fetched.

#### Signature
#### ContactRequestSignature

The `signature` in a message is only present in `ONE_TO_ONE` message type.
The `contact_request_signature` in a message is only present in `ONE_TO_ONE` message type.

It is used to prove that the sender was once a contact with the receiver. The reason for its presence is because, when an account is reset and re-imported, Contacts are lost.

To make sure the message is not ignored, the sender sends this `signature` as proof, so the receiver can know that it once had the sender as a contact.
To make sure the message is not ignored, the sender sends this `contact_request_signature` as proof, so the receiver can know that it once had the sender as a contact.

If the receiver puts the sender as blocked, teh `signature` is then ignored, as well as the message.
```
message ContactRequestSignature {
bytes signature = 1;
uint64 timestamp = 2;
}
```

`signature` is constructed as follow:

```
Keccak256(contactSignaturePrefix+PublicKey1+PublicKey2+Timestamp)
```

Where `PublicKey1` and `PublicKey2` are the public keys of the two users, ordered by `X` first and `Y` in order to break ties, in ascending order.
`Timestamp` is the `uint64` representation in bytes of the unix timestamp in seconds when the signature was generated, in Little Endian order.

The signature should be periodically refreshed and sent over to contacts, as old signature MIGHT be discarded by peers and considered invalid after an arbitrary amount of time.

`contactSignaturePrefix` is the bytes `[]byte{0x12,0x13}`, and it's used to avoid clashes in signatures schemes.

#### Chats

Expand All @@ -322,6 +337,7 @@ message ContactUpdate {
uint64 clock = 1;
string ens_name = 2;
string profile_image = 3;
ContactRequestSignature contact_request_signature = 4;
}
```

Expand All @@ -332,6 +348,7 @@ message ContactUpdate {
| 1 | clock | `uint64` | The clock of the chat with the user |
| 2 | ens_name | `string` | The ENS name if set |
| 3 | profile_image | `string` | The base64 encoded profile picture of the user |
| 4 | contact_request_signature | `ContactRequestSignature` | Signature of the sending user |

#### Contact update

Expand All @@ -342,48 +359,17 @@ A client SHOULD send a `ContactUpdate` to all the contacts each time:

A client SHOULD also periodically send a `ContactUpdate` to all the contacts, the interval is up to the client, the Status official client sends these updates every 48 hours.

### Contact

`Contact` is a representation of other accounts encountered on the app. They are added through `ContactUpdate`s propagated.
A `Contact` does not mean a "friend". Any account from which we receive a `ContactUpdate` is added to the table.

Users are considered "Friends" when they are **mutual** contacts, meaning that both of them have the `added` and `requestReceived` boolean set as `true`, which then triggers setting `mutualContact` to `true`. This is done through `ContactRequest`s.

#### Payload
`ContactRequestSignature` is MUST be signed by the sending user, the format is described in [ContactRequestSignature](#contact-request-signature)

| Field | Name | Type | Description |
| ----- | ---- | ---- | ---- |
| 1 | id | `string` | ID of the contact. Hex-encoded public key (prefixed with 0x). |
| 2 | address | `string` | Ethereum address of the contact |
| 3 | name | `string` | Contact's ENS name |
| 4 | ensVerified | `bool` | Whether the name of the contact is verified |
| 5 | alias | `string` | Contact's generated username |
| 6 | identicon | `string` | Identicon generated from public key |
| 7 | lastUpdated | `uint64` | Last time an update was received from the contact |
| 8 | blocked | `bool` | Whether the contact is blocked |
| 9 | added | `bool` | Whether the contact is added |
| 10 | requestReceived | `bool` | Whether the contact requested us to add them |
| 11 | mutualContact | `bool` | Whether the contact is mutual |
| 12 | deviceInfo | `[]ContactDeviceInfo` | |
| 13 | localNickname | `string` | Nickname set by the user for the contact |
| 14 | images | `map[string]images.IdentityImage` | Contact's profile images (thumbnail and large) |
| 15 | message | `Message` | Message sent with a contact request |
| 15 | signature | `string` | User signature proving that the other user added the current user as contact |

`blocked` acts as a blacklist. If `blocked` is `true`, `added`, `mutualContact` and `requestReceived` are ignored.

`mutualContact` is set to `true` once `added` is `true` and `requestReceived` is also set to `true`. This is a utility property to simplify the clients' use.
### Contact

#### Contact Request

Users can only chat with another in one to one channels while being mutal contacts. To do so, they need to send contact requests.

When adding another account as a contact, a `Contact` payload is sent to the other containing the `requestReceived` flag set to `true`, a `message` object and a `signature`.
Users can only chat with another in one to one channels while being mutual contacts. To do so, they need to send contact requests.

That `signature` is kept in the database and is sent in one to one messages to prove that we were once added as a contact. See `Message` payload for more information.
When adding another account as a contact, a `ContactRequestSignature` payload is sent to the other, either on a `ContactRequest` or a `Message` object.

When the other account accepts the contact request, the same `Contact` payload with `requestReceived` set to `true` is sent.
When `requestReceived: true` is reeived and `added` was previously set to `true`, `mutualContact` is also set to `true`.
That `ContactRequestSignature` is kept in the database and is sent in one to one messages to prove that we were once added as a contact. See `Message` payload for more information.

##### Backwards compatibility

Expand All @@ -393,29 +379,6 @@ Old versions will not understand the contact request, but will still get the mes

Newer versions will ignore the message since it is not from a contact, but the contact request will be processed as above.

#### Contacts persistence

Contacts are lost when an account is reset and re-imported. To remedy this situation, the contacts will be sent as a payload to the topic bearing the user's public key followed by `-contacts`. eg: `0x0401d01625bba5d6f0e576519ac6c1b4f343b15fdf2916815ab059d18c51ff826bf23fffff0aa33643140aa3762ab627c4718693a9a0dbf4e84f4429a454136856-contacts`.

This payload is to be sent only once per day on login and only when the `contacts_dirty` field of `contacts_sync` is set to `true`. The last send date will be kept in `contacts_sync` as `last_sent`.

The last payload is going to be fetched before sending. That payload is going to be compared to the current contacts using the `lastUpdated` field.

Again, the fetching of the payload is done once per day using `last_fetched` in `contacts_sync`.

The payload is an array of the Contacts table items, but only containing contacts that have `added` or `blocked` set as `true`.

##### Contacts Sync

The `contacts_sync` table is used to keep the last timestamps of when the contacts payload were sent and fetched to and from the topic.

It has three columns, `last_sent` and `last_fetched`, both containing a `uint64`, and `contacts_dirty` as a `bool`.

`last_sent` and `last_fetched` are the timestamps for the last time the payload was sent and fetched, and are used to make sure those actions are only done once per day.

The `contacts_dirty` field is set to `true` whenever a contact is changed by the user. A change is anything that changes the `added`, `blocked` or `mutualContact` properties of a contact.
After sending the payload with the updated contacts, the `contacts_dirty` field is set back to `false`.

### EmojiReaction

`EmojiReaction`s represents a user's "reaction" to a specific chat message. For more information about the concept of
Expand Down

0 comments on commit 52209af

Please sign in to comment.