adding peer/contactcard attributes
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
@@ -64,7 +64,7 @@ func CreateAndStoreUserMessage(message string, peer_uid string, replyToUid strin
|
||||
}
|
||||
}
|
||||
usermessage.Status.Sent = uint64(time.Now().UTC().Unix())
|
||||
usermessage.Status.AnswerToUuid = replyToUid
|
||||
usermessage.Status.ReplyToUuid = replyToUid
|
||||
|
||||
// Store message
|
||||
err = peer.StoreMessage(usermessage, nil)
|
||||
|
||||
@@ -26,6 +26,7 @@ type Peer struct {
|
||||
MyIdentity *meowlib.KeyPair `json:"my_identity,omitempty"`
|
||||
MyEncryptionKp *meowlib.KeyPair `json:"my_encryption_kp,omitempty"`
|
||||
MyLookupKp *meowlib.KeyPair `json:"my_lookup_kp,omitempty"`
|
||||
MySymKey string `json:"my_sym_key,omitempty"`
|
||||
MyPullServers []string `json:"my_pull_servers,omitempty"`
|
||||
// Peer keys and infos
|
||||
//Contact meowlib.ContactCard `json:"contact,omitempty"` // todo : remove
|
||||
@@ -40,6 +41,8 @@ type Peer struct {
|
||||
LastMessage *InternalUserMessage `json:"last_message,omitempty"`
|
||||
// Internal management attributes
|
||||
Visible bool `json:"visible,omitempty"`
|
||||
SendDeliveryAck bool `json:"send_delivery_ack,omitempty"`
|
||||
SendProcessingAck bool `json:"send_processing_ack,omitempty"`
|
||||
VisiblePassword string `json:"visible_password,omitempty"`
|
||||
PasswordType string `json:"password_type,omitempty"`
|
||||
Blocked bool `json:"blocked,omitempty"`
|
||||
|
||||
7
doc/messaging/sq_msg02_bgpoll.puml
Normal file
7
doc/messaging/sq_msg02_bgpoll.puml
Normal file
@@ -0,0 +1,7 @@
|
||||
@startuml
|
||||
ClientFdThread -> Lib : write poll job list
|
||||
ClientFdThread -> ClientBgThread : notify job ?
|
||||
ClientBgThread -> Lib : poll for servers
|
||||
ClientBgThread -> ClientFdThread : notify message here
|
||||
ClientFdThread -> Lib : Read redeived message and update db
|
||||
@enduml
|
||||
7
doc/messaging/sq_msg02_bgsend.puml
Normal file
7
doc/messaging/sq_msg02_bgsend.puml
Normal file
@@ -0,0 +1,7 @@
|
||||
@startuml
|
||||
ClientFdThread -> Lib : write msg to db, encrypted msg for user to file, and job file
|
||||
ClientFdThread -> ClientBgThread : notify job
|
||||
ClientBgThread -> Lib : encrypt for server(s) and send including retries
|
||||
ClientBgThread -> Lib: notify send result
|
||||
ClientFdThread -> Lib : Read job report and update db
|
||||
@enduml
|
||||
314
doc/multi_device_sync_plan.md
Normal file
314
doc/multi_device_sync_plan.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# Multi-Device Conversation Sync — Implementation Plan
|
||||
|
||||
## Context
|
||||
|
||||
meowlib already has scaffolding for multi-device sync:
|
||||
|
||||
| Existing artefact | Where |
|
||||
|---|---|
|
||||
| `Identity.Device *KeyPair` | `client/identity.go:35` |
|
||||
| `Identity.OwnedDevices PeerList` | `client/identity.go:40` |
|
||||
| `Peer.Type string` | `client/peer.go:52` |
|
||||
| `ToServerMessage.device_messages` (field 10) | `pb/messages.proto:75` |
|
||||
| `FromServerMessage.device_messages` (field 9) | `pb/messages.proto:99` |
|
||||
| `BackgroundJob.Device *KeyPair` | `client/identity.go:334` |
|
||||
|
||||
The server (`server/router.go`) does **not** yet implement `device_messages` routing; it goes through `messages`/`Chat` today.
|
||||
|
||||
---
|
||||
|
||||
## Chosen Sync Scheme: Event-Driven Delta Sync over Existing Message Infrastructure
|
||||
|
||||
### Rationale
|
||||
|
||||
| Approach | Pros | Cons | Verdict |
|
||||
|---|---|---|---|
|
||||
| Full DB sync | Complete history | Huge payloads, merge conflicts, wasteful | ❌ |
|
||||
| Inbox/outbox file sharing | Simple to reason about | File-level granularity, no dedup, breaks privacy model | ❌ |
|
||||
| **Event-driven delta sync** | Minimal data, no merge needed, reuses existing crypto + server stack | Requires dedup table | ✅ |
|
||||
|
||||
Each message event (received, sent, status change) is forwarded immediately to sibling devices through the **same server infrastructure** as regular peer messages. Each device maintains its own complete local DB. Convergence is eventual; dedup via `ConversationStatus.Uuid`.
|
||||
|
||||
### Key Design Decisions
|
||||
|
||||
1. **Zero server changes required.** Device sync messages are addressed to the sibling device's lookup key and travel through the existing `msg:{lookup_key}` Redis sorted-set on the server, returned in `from_server.Chat` — identical to peer messages.
|
||||
|
||||
2. **Device peers reuse the `Peer` struct** with `Type = "device"`, stored in `Identity.OwnedDevices`. They have their own three keypairs (`MyIdentity`, `MyEncryptionKp`, `MyLookupKp`) and `MyPullServers`.
|
||||
|
||||
3. **A new proto message `DeviceSyncPayload`** is added to `messages.proto`. It is serialised and placed in `UserMessage.Appdata`; the parent `UserMessage.Type` is set to `"device_sync"`. This lets the client recognise sync messages without any server-side awareness.
|
||||
|
||||
4. **`GetRequestJobs()`** is extended to include device lookup keys alongside peer lookup keys for the appropriate servers, so the background poll thread picks up device sync messages without any extra call.
|
||||
|
||||
5. **Dedup** is handled by a small SQLite table `device_sync_seen` (one table per identity folder, not per peer) keyed on `DeviceSyncPayload.DedupId`.
|
||||
|
||||
---
|
||||
|
||||
## New Protobuf Message
|
||||
|
||||
Add to `pb/messages.proto` before re-generating:
|
||||
|
||||
```protobuf
|
||||
// Payload carried inside UserMessage.appdata for device-to-device sync.
|
||||
// The enclosing UserMessage.type MUST be "device_sync".
|
||||
message DeviceSyncPayload {
|
||||
string sync_type = 1; // "msg" | "status" | "peer_event"
|
||||
string peer_uid = 2; // local UID of the peer conversation on the sending device
|
||||
DbMessage db_message = 3; // the DbMessage to replicate
|
||||
string dedup_id = 4; // globally unique ID (= DbMessage.status.uuid or generated)
|
||||
}
|
||||
```
|
||||
|
||||
Run `cd pb && ./protogen.sh` after adding this.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1 — Device Pairing
|
||||
|
||||
**Files to touch:** `client/identity.go`, `client/helpers/` (new file `deviceHelper.go`)
|
||||
|
||||
**Goal:** Allow two app instances owned by the same user to establish a shared keypair relationship, mirroring the peer invitation flow but flagging the peer as `Type = "device"`.
|
||||
|
||||
#### 1.1 `Identity.InitDevicePairing(myDeviceName string, serverUids []string) (*Peer, error)`
|
||||
- Identical to `InvitePeer` but sets `peer.Type = "device"`.
|
||||
- Stores the resulting peer in `Identity.OwnedDevices` (not `Peers`).
|
||||
- Returns the peer so the caller can produce a `ContactCard` QR/file.
|
||||
|
||||
#### 1.2 `Identity.AnswerDevicePairing(myDeviceName string, receivedContact *meowlib.ContactCard) (*Peer, error)`
|
||||
- Mirrors `AnswerInvitation`, stores in `OwnedDevices`.
|
||||
|
||||
#### 1.3 `Identity.FinalizeDevicePairing(receivedContact *meowlib.ContactCard) error`
|
||||
- Mirrors `FinalizeInvitation`, operates on `OwnedDevices`.
|
||||
|
||||
#### 1.4 Helper functions (new file `client/helpers/deviceHelper.go`)
|
||||
```go
|
||||
// DevicePairingCreateMessage – wraps an invitation step-1 for a device peer.
|
||||
func DevicePairingCreateMessage(peer *client.Peer, serverUid string) ([]byte, string, error)
|
||||
|
||||
// DevicePairingAnswerMessage – wraps invitation step-3 answer for a device peer.
|
||||
func DevicePairingAnswerMessage(peer *client.Peer, serverUid string) ([]byte, string, error)
|
||||
```
|
||||
These reuse `invitationCreateHelper.go`/`invitationAnswerHelper.go` logic.
|
||||
|
||||
#### 1.5 Extend `PeerStorage` operations for OwnedDevices
|
||||
`OwnedDevices` is currently a `PeerList` (in-memory slice). For scalability it should use the same Badger-backed `PeerStorage` mechanism as `Peers`. Consider adding a second `PeerStorage` field `DeviceStorage` to `Identity` with its own `DbFile`.
|
||||
|
||||
---
|
||||
|
||||
### Phase 2 — Sync Payload Helpers
|
||||
|
||||
**Files to touch:** `client/helpers/deviceHelper.go` (continued), `client/dbmessage.go`
|
||||
|
||||
#### 2.1 Build a sync message for one sibling device
|
||||
|
||||
```go
|
||||
// BuildDeviceSyncMessage wraps a DbMessage into a UserMessage addressed to a
|
||||
// sibling device peer. The caller then calls peer.ProcessOutboundUserMessage.
|
||||
func BuildDeviceSyncMessage(
|
||||
devicePeer *client.Peer,
|
||||
syncType string, // "msg" | "status" | "peer_event"
|
||||
peerUid string,
|
||||
dbm *meowlib.DbMessage,
|
||||
dedupId string,
|
||||
) (*meowlib.UserMessage, error)
|
||||
```
|
||||
|
||||
Implementation:
|
||||
1. Serialise `DeviceSyncPayload{SyncType, PeerUid, DbMessage, DedupId}` with `proto.Marshal`.
|
||||
2. Create a `UserMessage` with `Type = "device_sync"`, `Destination = devicePeer.ContactLookupKey`, `Appdata = serialisedPayload`.
|
||||
3. Set `Status.Uuid = dedupId`.
|
||||
|
||||
#### 2.2 Dispatch sync to all sibling devices
|
||||
|
||||
```go
|
||||
// DispatchSyncToDevices sends a DeviceSyncPayload to every device peer whose
|
||||
// pull server list overlaps with the available servers.
|
||||
// It enqueues a SendJob per device, reusing the existing bgSendHelper queue.
|
||||
func DispatchSyncToDevices(
|
||||
storagePath string,
|
||||
syncType string,
|
||||
peerUid string,
|
||||
dbm *meowlib.DbMessage,
|
||||
dedupId string,
|
||||
) error
|
||||
```
|
||||
|
||||
Iterates `identity.OwnedDevices`, builds and queues one `SendJob` per device (just like `CreateUserMessageAndSendJob` but using device peer keys and putting the message in `outbox/` with a recognisable prefix, e.g. `dev_{devPeerUid}_{dedupId}`).
|
||||
|
||||
The message is packed into `ToServerMessage.Messages` (same field as regular chat). No server changes needed.
|
||||
|
||||
---
|
||||
|
||||
### Phase 3 — Integrate Dispatch into Send/Receive Paths
|
||||
|
||||
**Files to touch:** `client/helpers/messageHelper.go`, `client/helpers/bgPollHelper.go`
|
||||
|
||||
#### 3.1 After outbound message stored (`CreateAndStoreUserMessage`)
|
||||
|
||||
At the end of `CreateAndStoreUserMessage` (after `peer.StoreMessage`), add:
|
||||
|
||||
```go
|
||||
// Async: do not block the caller
|
||||
go DispatchSyncToDevices(storagePath, "msg", peerUid, dbm, usermessage.Status.Uuid)
|
||||
```
|
||||
|
||||
The `dbm` is obtained from `UserMessageToDbMessage(true, usermessage, nil)` (files are excluded from sync — they stay on the originating device or are re-requested).
|
||||
|
||||
#### 3.2 After inbound message stored (`ConsumeInboxFile`)
|
||||
|
||||
After `peer.StoreMessage(usermsg, filenames)` succeeds:
|
||||
|
||||
```go
|
||||
dbm := client.UserMessageToDbMessage(false, usermsg, nil)
|
||||
go DispatchSyncToDevices(storagePath, "msg", peer.Uid, dbm, usermsg.Status.Uuid)
|
||||
```
|
||||
|
||||
#### 3.3 After ACK status update (`ReadAckMessageResponse` — currently a stub)
|
||||
|
||||
When status timestamps (received/processed) are updated in the DB, dispatch a `"status"` sync with the updated `DbMessage`.
|
||||
|
||||
---
|
||||
|
||||
### Phase 4 — Receive & Consume Device Sync Messages
|
||||
|
||||
**Files to touch:** `client/helpers/bgPollHelper.go`, new `client/helpers/deviceSyncHelper.go`
|
||||
|
||||
#### 4.1 Extend `GetRequestJobs()` to include device lookup keys
|
||||
|
||||
In `identity.go:GetRequestJobs()`, after the loop over `Peers`, add a similar loop over `OwnedDevices`:
|
||||
|
||||
```go
|
||||
for _, devPeer := range id.OwnedDevices {
|
||||
for _, server := range devPeer.MyPullServers {
|
||||
if job, ok := srvs[server]; ok {
|
||||
job.LookupKeys = append(job.LookupKeys, devPeer.MyLookupKp)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Device messages will now arrive inside `from_server.Chat` alongside regular peer messages. The next step distinguishes them.
|
||||
|
||||
#### 4.2 Distinguish device vs peer messages in `ConsumeInboxFile`
|
||||
|
||||
After `identity.Peers.GetFromMyLookupKey(packedUserMessage.Destination)` returns `nil`, try:
|
||||
|
||||
```go
|
||||
devPeer := identity.OwnedDevices.GetFromMyLookupKey(packedUserMessage.Destination)
|
||||
if devPeer != nil {
|
||||
err := ConsumeDeviceSyncMessage(devPeer, packedUserMessage)
|
||||
// continue to next message
|
||||
continue
|
||||
}
|
||||
// original error path
|
||||
```
|
||||
|
||||
#### 4.3 `ConsumeDeviceSyncMessage` (new file `client/helpers/deviceSyncHelper.go`)
|
||||
|
||||
```go
|
||||
func ConsumeDeviceSyncMessage(
|
||||
devPeer *client.Peer,
|
||||
packed *meowlib.PackedUserMessage,
|
||||
) error
|
||||
```
|
||||
|
||||
Steps:
|
||||
1. Decrypt with `devPeer.ProcessInboundUserMessage(packed.Payload, packed.Signature)`.
|
||||
2. Check `usermsg.Type == "device_sync"`.
|
||||
3. Deserialise `DeviceSyncPayload` from `usermsg.Appdata`.
|
||||
4. Dedup check: call `IsDeviceSyncSeen(payload.DedupId)`. If yes, skip.
|
||||
5. Mark seen: `MarkDeviceSyncSeen(payload.DedupId)`.
|
||||
6. Dispatch by `payload.SyncType`:
|
||||
- `"msg"`: find the local peer by `payload.PeerUid`, call `client.StoreDeviceSyncedMessage(peer, payload.DbMessage)`.
|
||||
- `"status"`: update the status fields in the existing DB row matched by `payload.DbMessage.Status.Uuid`.
|
||||
- `"peer_event"`: (future) update peer metadata.
|
||||
|
||||
#### 4.4 `StoreDeviceSyncedMessage` in `client/messagestorage.go`
|
||||
|
||||
A thin wrapper around `storeMessage` that:
|
||||
- Marks the message as synced (a new bool field `Synced` in `DbMessage`, or use a naming convention in `DbMessage.Appdata`).
|
||||
- Does **not** trigger a second round of sync dispatch (no re-broadcast).
|
||||
- Handles absent file paths gracefully (files are not synced, only metadata).
|
||||
|
||||
---
|
||||
|
||||
### Phase 5 — Dedup Store
|
||||
|
||||
**Files to touch:** new `client/devicesyncdedup.go`
|
||||
|
||||
A single SQLite DB per identity folder: `{StoragePath}/{IdentityUuid}/devicesync.db`.
|
||||
|
||||
Schema:
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS seen (
|
||||
id TEXT NOT NULL PRIMARY KEY,
|
||||
seen_at INTEGER NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
Functions:
|
||||
```go
|
||||
func IsDeviceSyncSeen(storagePath, identityUuid, dedupId string) (bool, error)
|
||||
func MarkDeviceSyncSeen(storagePath, identityUuid, dedupId string) error
|
||||
func PruneDeviceSyncSeen(storagePath, identityUuid string, olderThan time.Duration) error
|
||||
```
|
||||
|
||||
`PruneDeviceSyncSeen` is called periodically (e.g. weekly) from the background thread to remove entries older than 30 days.
|
||||
|
||||
---
|
||||
|
||||
## File Change Summary
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `pb/messages.proto` | Add `DeviceSyncPayload` message |
|
||||
| `pb/protogen.sh` → re-run | Regenerate `.pb.go` |
|
||||
| `client/identity.go` | Add `InitDevicePairing`, `AnswerDevicePairing`, `FinalizeDevicePairing`; extend `GetRequestJobs()` |
|
||||
| `client/peer.go` | No changes needed (Type field already exists) |
|
||||
| `client/messagestorage.go` | Add `StoreDeviceSyncedMessage` |
|
||||
| `client/devicesyncdedup.go` | **New** — dedup SQLite helpers |
|
||||
| `client/helpers/deviceHelper.go` | **New** — `BuildDeviceSyncMessage`, `DispatchSyncToDevices`, pairing message helpers |
|
||||
| `client/helpers/deviceSyncHelper.go` | **New** — `ConsumeDeviceSyncMessage` |
|
||||
| `client/helpers/messageHelper.go` | Add `DispatchSyncToDevices` call after outbound store |
|
||||
| `client/helpers/bgPollHelper.go` | Add device message detection in `ConsumeInboxFile` |
|
||||
|
||||
Server package: **no changes required**.
|
||||
|
||||
---
|
||||
|
||||
## Sync Scope
|
||||
|
||||
| Data | Synced | Notes |
|
||||
|---|---|---|
|
||||
| Message text / data | ✅ | In `DbMessage.Data` |
|
||||
| Outbound flag | ✅ | In `DbMessage.Outbound` |
|
||||
| Message UUID | ✅ | Via `ConversationStatus.Uuid` |
|
||||
| Sent/received timestamps | ✅ | In `ConversationStatus` |
|
||||
| File content | ❌ | Not synced; only `FilePaths` metadata synced |
|
||||
| Peer metadata (keys, servers) | ❌ | Phase 2+ scope |
|
||||
| Identity blob | ❌ | Out of scope; handled by manual export |
|
||||
|
||||
---
|
||||
|
||||
## Privacy Properties
|
||||
|
||||
- Device sync messages are end-to-end encrypted (same X25519 + PGP as peer messages).
|
||||
- The server sees only the device lookup key as destination; it has no knowledge this is a sync vs a peer message.
|
||||
- Including device lookup keys in batch pull requests does not leak which other device belongs to you (same privacy model as multiple peer lookup keys per request).
|
||||
- `OwnedDevices` peers should be considered "hidden" (not shown in contact lists) and can optionally be stored in the hidden peer store.
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
1. **Unit tests** for `DeviceSyncPayload` serialisation round-trip.
|
||||
2. **Unit tests** for dedup store (seen/mark/prune lifecycle).
|
||||
3. **Integration test** extending `TestEndToEnd`:
|
||||
- Create identity, two device peers (DeviceA, DeviceB).
|
||||
- Send a message on DeviceA.
|
||||
- Verify DeviceB's DB contains the synced message after `ConsumeDeviceSyncMessage`.
|
||||
- Resend the same dedup_id — verify no duplicate row created.
|
||||
4. **Integration test** for inbound sync:
|
||||
- DeviceA receives a peer message.
|
||||
- Verify DeviceB gets the sync and stores it correctly.
|
||||
113
messages.pb.go
113
messages.pb.go
@@ -669,7 +669,7 @@ func (x *FromServerMessage) GetContactCard() []*ContactCard {
|
||||
type MatriochkaServer struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` // Server Url
|
||||
PublicKey string `protobuf:"bytes,2,opt,name=publicKey,proto3" json:"publicKey,omitempty"` // Server Public Key
|
||||
PublicKey string `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` // Server Public Key
|
||||
Uuid string `protobuf:"bytes,3,opt,name=uuid,proto3" json:"uuid,omitempty"` // Optional, uuid for delivery confirmation
|
||||
Delay int32 `protobuf:"varint,4,opt,name=delay,proto3" json:"delay,omitempty"` // Max delay requested for message forwarding or delivery tracking
|
||||
unknownFields protoimpl.UnknownFields
|
||||
@@ -736,7 +736,7 @@ func (x *MatriochkaServer) GetDelay() int32 {
|
||||
|
||||
type Matriochka struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
LookupKey string `protobuf:"bytes,1,opt,name=lookupKey,proto3" json:"lookupKey,omitempty"` // Optional, only if you want delivery tracking, less stealth
|
||||
LookupKey string `protobuf:"bytes,1,opt,name=lookup_key,json=lookupKey,proto3" json:"lookup_key,omitempty"` // Optional, only if you want delivery tracking, less stealth
|
||||
Prev *MatriochkaServer `protobuf:"bytes,2,opt,name=prev,proto3" json:"prev,omitempty"` // Optional, like above
|
||||
Next *MatriochkaServer `protobuf:"bytes,3,opt,name=next,proto3" json:"next,omitempty"` // Next server to deliver the message to
|
||||
Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` // Matriochka data
|
||||
@@ -902,10 +902,11 @@ type ContactCard struct {
|
||||
ContactPublicKey string `protobuf:"bytes,2,opt,name=contact_public_key,json=contactPublicKey,proto3" json:"contact_public_key,omitempty"` // contact public key, will be used to authenticate her/his messages
|
||||
EncryptionPublicKey string `protobuf:"bytes,3,opt,name=encryption_public_key,json=encryptionPublicKey,proto3" json:"encryption_public_key,omitempty"` // public key you must use to to write encrypted messages to that contact
|
||||
LookupPublicKey string `protobuf:"bytes,4,opt,name=lookup_public_key,json=lookupPublicKey,proto3" json:"lookup_public_key,omitempty"` // public key you will use as "destination identifier" for her/him to lookup for your messages on the servers
|
||||
PullServers []*ServerCard `protobuf:"bytes,5,rep,name=pull_servers,json=pullServers,proto3" json:"pull_servers,omitempty"` // list the servers where the contact will look for messages from you
|
||||
Version uint32 `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"`
|
||||
InvitationId string `protobuf:"bytes,7,opt,name=invitation_id,json=invitationId,proto3" json:"invitation_id,omitempty"`
|
||||
InvitationMessage string `protobuf:"bytes,8,opt,name=invitation_message,json=invitationMessage,proto3" json:"invitation_message,omitempty"`
|
||||
SymetricKey string `protobuf:"bytes,5,opt,name=symetric_key,json=symetricKey,proto3" json:"symetric_key,omitempty"` // agreed key for payload symetric encryption
|
||||
PullServers []*ServerCard `protobuf:"bytes,6,rep,name=pull_servers,json=pullServers,proto3" json:"pull_servers,omitempty"` // list the servers where the contact will look for messages from you
|
||||
Version uint32 `protobuf:"varint,7,opt,name=version,proto3" json:"version,omitempty"`
|
||||
InvitationId string `protobuf:"bytes,8,opt,name=invitation_id,json=invitationId,proto3" json:"invitation_id,omitempty"`
|
||||
InvitationMessage string `protobuf:"bytes,9,opt,name=invitation_message,json=invitationMessage,proto3" json:"invitation_message,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -968,6 +969,13 @@ func (x *ContactCard) GetLookupPublicKey() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContactCard) GetSymetricKey() string {
|
||||
if x != nil {
|
||||
return x.SymetricKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContactCard) GetPullServers() []*ServerCard {
|
||||
if x != nil {
|
||||
return x.PullServers
|
||||
@@ -1002,7 +1010,7 @@ type PackedUserMessage struct {
|
||||
Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` // the peer's current conversation lookup public key
|
||||
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` // the message UserMessage encrypted with the destination peer's public key
|
||||
Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` // the payload signature with the client identity private key
|
||||
ServerTimestamp []int64 `protobuf:"varint,4,rep,packed,name=serverTimestamp,proto3" json:"serverTimestamp,omitempty"` // server time stamp, might be several in matriochka mode
|
||||
ServerTimestamp []int64 `protobuf:"varint,4,rep,packed,name=server_timestamp,json=serverTimestamp,proto3" json:"server_timestamp,omitempty"` // server time stamp, might be several in matriochka mode
|
||||
ServerDeliveryUuid string `protobuf:"bytes,5,opt,name=server_delivery_uuid,json=serverDeliveryUuid,proto3" json:"server_delivery_uuid,omitempty"` // message uuid, for server delivery tracking, omitted if not delivery tracking desired
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -1075,14 +1083,15 @@ func (x *PackedUserMessage) GetServerDeliveryUuid() string {
|
||||
|
||||
type ConversationStatus struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"`
|
||||
AnswerToUuid string `protobuf:"bytes,2,opt,name=answer_to_uuid,json=answerToUuid,proto3" json:"answer_to_uuid,omitempty"` // message is an answer to another one, specify uuid here
|
||||
LocalSequence uint64 `protobuf:"varint,3,opt,name=localSequence,proto3" json:"localSequence,omitempty"` // seq number in local conversation for custom reordering
|
||||
Sent uint64 `protobuf:"varint,4,opt,name=sent,proto3" json:"sent,omitempty"` // timestamp of the message sent
|
||||
Received uint64 `protobuf:"varint,5,opt,name=received,proto3" json:"received,omitempty"` // timestamp of the message received
|
||||
Processed uint64 `protobuf:"varint,6,opt,name=processed,proto3" json:"processed,omitempty"` // timestamp of the message processed
|
||||
MyNextIdentity *ContactCard `protobuf:"bytes,7,opt,name=my_next_identity,json=myNextIdentity,proto3" json:"my_next_identity,omitempty"`
|
||||
PeerNextIdentityAck int32 `protobuf:"varint,8,opt,name=peer_next_identityAck,json=peerNextIdentityAck,proto3" json:"peer_next_identityAck,omitempty"` // version of the new peer accepted id
|
||||
Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` // uuid of message, or uuid of related message if uuid_action is not empty
|
||||
UuidAction int32 `protobuf:"varint,2,opt,name=uuid_action,json=uuidAction,proto3" json:"uuid_action,omitempty"` // empty => normal message, 1: receivedack, 2: processedack, 3:reaction
|
||||
ReplyToUuid string `protobuf:"bytes,3,opt,name=reply_to_uuid,json=replyToUuid,proto3" json:"reply_to_uuid,omitempty"` // this message replies to the specified uuid
|
||||
LocalSequence uint64 `protobuf:"varint,4,opt,name=local_sequence,json=localSequence,proto3" json:"local_sequence,omitempty"` // seq number in local conversation for custom reordering
|
||||
Sent uint64 `protobuf:"varint,5,opt,name=sent,proto3" json:"sent,omitempty"` // timestamp of the message sent
|
||||
Received uint64 `protobuf:"varint,6,opt,name=received,proto3" json:"received,omitempty"` // timestamp of the message received
|
||||
Processed uint64 `protobuf:"varint,7,opt,name=processed,proto3" json:"processed,omitempty"` // timestamp of the message processed
|
||||
MyNextIdentity *ContactCard `protobuf:"bytes,8,opt,name=my_next_identity,json=myNextIdentity,proto3" json:"my_next_identity,omitempty"`
|
||||
PeerNextIdentityAck int32 `protobuf:"varint,9,opt,name=peer_next_identity_ack,json=peerNextIdentityAck,proto3" json:"peer_next_identity_ack,omitempty"` // version of the new peer accepted id
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -1124,9 +1133,16 @@ func (x *ConversationStatus) GetUuid() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ConversationStatus) GetAnswerToUuid() string {
|
||||
func (x *ConversationStatus) GetUuidAction() int32 {
|
||||
if x != nil {
|
||||
return x.AnswerToUuid
|
||||
return x.UuidAction
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ConversationStatus) GetReplyToUuid() string {
|
||||
if x != nil {
|
||||
return x.ReplyToUuid
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1234,7 +1250,7 @@ type UserMessage struct {
|
||||
Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
|
||||
Status *ConversationStatus `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"`
|
||||
Contact *ContactCard `protobuf:"bytes,6,opt,name=contact,proto3" json:"contact,omitempty"`
|
||||
KnownServers *ServerCard `protobuf:"bytes,7,opt,name=knownServers,proto3" json:"knownServers,omitempty"`
|
||||
KnownServers *ServerCard `protobuf:"bytes,7,opt,name=known_servers,json=knownServers,proto3" json:"known_servers,omitempty"`
|
||||
Group *Group `protobuf:"bytes,8,opt,name=group,proto3" json:"group,omitempty"`
|
||||
Files []*File `protobuf:"bytes,9,rep,name=files,proto3" json:"files,omitempty"`
|
||||
CurrentLocation *Location `protobuf:"bytes,10,opt,name=current_location,json=currentLocation,proto3" json:"current_location,omitempty"`
|
||||
@@ -1849,15 +1865,17 @@ const file_messages_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"video_data\x18\n" +
|
||||
" \x01(\v2\x12.meowlib.VideoDataR\tvideoData\x127\n" +
|
||||
"\fcontact_card\x18\v \x03(\v2\x14.meowlib.ContactCardR\vcontactCard\"l\n" +
|
||||
"\fcontact_card\x18\v \x03(\v2\x14.meowlib.ContactCardR\vcontactCard\"m\n" +
|
||||
"\x10MatriochkaServer\x12\x10\n" +
|
||||
"\x03url\x18\x01 \x01(\tR\x03url\x12\x1c\n" +
|
||||
"\tpublicKey\x18\x02 \x01(\tR\tpublicKey\x12\x12\n" +
|
||||
"\x04uuid\x18\x03 \x01(\tR\x04uuid\x12\x14\n" +
|
||||
"\x05delay\x18\x04 \x01(\x05R\x05delay\"\x9c\x01\n" +
|
||||
"\x03url\x18\x01 \x01(\tR\x03url\x12\x1d\n" +
|
||||
"\n" +
|
||||
"Matriochka\x12\x1c\n" +
|
||||
"\tlookupKey\x18\x01 \x01(\tR\tlookupKey\x12-\n" +
|
||||
"public_key\x18\x02 \x01(\tR\tpublicKey\x12\x12\n" +
|
||||
"\x04uuid\x18\x03 \x01(\tR\x04uuid\x12\x14\n" +
|
||||
"\x05delay\x18\x04 \x01(\x05R\x05delay\"\x9d\x01\n" +
|
||||
"\n" +
|
||||
"Matriochka\x12\x1d\n" +
|
||||
"\n" +
|
||||
"lookup_key\x18\x01 \x01(\tR\tlookupKey\x12-\n" +
|
||||
"\x04prev\x18\x02 \x01(\v2\x19.meowlib.MatriochkaServerR\x04prev\x12-\n" +
|
||||
"\x04next\x18\x03 \x01(\v2\x19.meowlib.MatriochkaServerR\x04next\x12\x12\n" +
|
||||
"\x04data\x18\x04 \x01(\fR\x04data\"\xc3\x01\n" +
|
||||
@@ -1870,42 +1888,45 @@ const file_messages_proto_rawDesc = "" +
|
||||
"\x03url\x18\x04 \x01(\tR\x03url\x12\x14\n" +
|
||||
"\x05login\x18\x05 \x01(\tR\x05login\x12\x1a\n" +
|
||||
"\bpassword\x18\x06 \x01(\tR\bpassword\x12\x1c\n" +
|
||||
"\tsignature\x18\a \x01(\tR\tsignature\"\xd5\x02\n" +
|
||||
"\tsignature\x18\a \x01(\tR\tsignature\"\xf8\x02\n" +
|
||||
"\vContactCard\x12\x12\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\x12,\n" +
|
||||
"\x12contact_public_key\x18\x02 \x01(\tR\x10contactPublicKey\x122\n" +
|
||||
"\x15encryption_public_key\x18\x03 \x01(\tR\x13encryptionPublicKey\x12*\n" +
|
||||
"\x11lookup_public_key\x18\x04 \x01(\tR\x0flookupPublicKey\x126\n" +
|
||||
"\fpull_servers\x18\x05 \x03(\v2\x13.meowlib.ServerCardR\vpullServers\x12\x18\n" +
|
||||
"\aversion\x18\x06 \x01(\rR\aversion\x12#\n" +
|
||||
"\rinvitation_id\x18\a \x01(\tR\finvitationId\x12-\n" +
|
||||
"\x12invitation_message\x18\b \x01(\tR\x11invitationMessage\"\xc9\x01\n" +
|
||||
"\x11lookup_public_key\x18\x04 \x01(\tR\x0flookupPublicKey\x12!\n" +
|
||||
"\fsymetric_key\x18\x05 \x01(\tR\vsymetricKey\x126\n" +
|
||||
"\fpull_servers\x18\x06 \x03(\v2\x13.meowlib.ServerCardR\vpullServers\x12\x18\n" +
|
||||
"\aversion\x18\a \x01(\rR\aversion\x12#\n" +
|
||||
"\rinvitation_id\x18\b \x01(\tR\finvitationId\x12-\n" +
|
||||
"\x12invitation_message\x18\t \x01(\tR\x11invitationMessage\"\xca\x01\n" +
|
||||
"\x11PackedUserMessage\x12 \n" +
|
||||
"\vdestination\x18\x01 \x01(\tR\vdestination\x12\x18\n" +
|
||||
"\apayload\x18\x02 \x01(\fR\apayload\x12\x1c\n" +
|
||||
"\tsignature\x18\x03 \x01(\fR\tsignature\x12(\n" +
|
||||
"\x0fserverTimestamp\x18\x04 \x03(\x03R\x0fserverTimestamp\x120\n" +
|
||||
"\x14server_delivery_uuid\x18\x05 \x01(\tR\x12serverDeliveryUuid\"\xb6\x02\n" +
|
||||
"\tsignature\x18\x03 \x01(\fR\tsignature\x12)\n" +
|
||||
"\x10server_timestamp\x18\x04 \x03(\x03R\x0fserverTimestamp\x120\n" +
|
||||
"\x14server_delivery_uuid\x18\x05 \x01(\tR\x12serverDeliveryUuid\"\xd7\x02\n" +
|
||||
"\x12ConversationStatus\x12\x12\n" +
|
||||
"\x04uuid\x18\x01 \x01(\tR\x04uuid\x12$\n" +
|
||||
"\x0eanswer_to_uuid\x18\x02 \x01(\tR\fanswerToUuid\x12$\n" +
|
||||
"\rlocalSequence\x18\x03 \x01(\x04R\rlocalSequence\x12\x12\n" +
|
||||
"\x04sent\x18\x04 \x01(\x04R\x04sent\x12\x1a\n" +
|
||||
"\breceived\x18\x05 \x01(\x04R\breceived\x12\x1c\n" +
|
||||
"\tprocessed\x18\x06 \x01(\x04R\tprocessed\x12>\n" +
|
||||
"\x10my_next_identity\x18\a \x01(\v2\x14.meowlib.ContactCardR\x0emyNextIdentity\x122\n" +
|
||||
"\x15peer_next_identityAck\x18\b \x01(\x05R\x13peerNextIdentityAck\"K\n" +
|
||||
"\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x1f\n" +
|
||||
"\vuuid_action\x18\x02 \x01(\x05R\n" +
|
||||
"uuidAction\x12\"\n" +
|
||||
"\rreply_to_uuid\x18\x03 \x01(\tR\vreplyToUuid\x12%\n" +
|
||||
"\x0elocal_sequence\x18\x04 \x01(\x04R\rlocalSequence\x12\x12\n" +
|
||||
"\x04sent\x18\x05 \x01(\x04R\x04sent\x12\x1a\n" +
|
||||
"\breceived\x18\x06 \x01(\x04R\breceived\x12\x1c\n" +
|
||||
"\tprocessed\x18\a \x01(\x04R\tprocessed\x12>\n" +
|
||||
"\x10my_next_identity\x18\b \x01(\v2\x14.meowlib.ContactCardR\x0emyNextIdentity\x123\n" +
|
||||
"\x16peer_next_identity_ack\x18\t \x01(\x05R\x13peerNextIdentityAck\"K\n" +
|
||||
"\x05Group\x12\x12\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\x12.\n" +
|
||||
"\amembers\x18\x02 \x03(\v2\x14.meowlib.ContactCardR\amembers\"\x94\x04\n" +
|
||||
"\amembers\x18\x02 \x03(\v2\x14.meowlib.ContactCardR\amembers\"\x95\x04\n" +
|
||||
"\vUserMessage\x12 \n" +
|
||||
"\vdestination\x18\x01 \x01(\tR\vdestination\x12\x12\n" +
|
||||
"\x04from\x18\x02 \x01(\tR\x04from\x12\x12\n" +
|
||||
"\x04type\x18\x03 \x01(\tR\x04type\x12\x12\n" +
|
||||
"\x04data\x18\x04 \x01(\fR\x04data\x123\n" +
|
||||
"\x06status\x18\x05 \x01(\v2\x1b.meowlib.ConversationStatusR\x06status\x12.\n" +
|
||||
"\acontact\x18\x06 \x01(\v2\x14.meowlib.ContactCardR\acontact\x127\n" +
|
||||
"\fknownServers\x18\a \x01(\v2\x13.meowlib.ServerCardR\fknownServers\x12$\n" +
|
||||
"\acontact\x18\x06 \x01(\v2\x14.meowlib.ContactCardR\acontact\x128\n" +
|
||||
"\rknown_servers\x18\a \x01(\v2\x13.meowlib.ServerCardR\fknownServers\x12$\n" +
|
||||
"\x05group\x18\b \x01(\v2\x0e.meowlib.GroupR\x05group\x12#\n" +
|
||||
"\x05files\x18\t \x03(\v2\r.meowlib.FileR\x05files\x12<\n" +
|
||||
"\x10current_location\x18\n" +
|
||||
@@ -2015,7 +2036,7 @@ var file_messages_proto_depIdxs = []int32{
|
||||
10, // 19: meowlib.Group.members:type_name -> meowlib.ContactCard
|
||||
12, // 20: meowlib.UserMessage.status:type_name -> meowlib.ConversationStatus
|
||||
10, // 21: meowlib.UserMessage.contact:type_name -> meowlib.ContactCard
|
||||
9, // 22: meowlib.UserMessage.knownServers:type_name -> meowlib.ServerCard
|
||||
9, // 22: meowlib.UserMessage.known_servers:type_name -> meowlib.ServerCard
|
||||
13, // 23: meowlib.UserMessage.group:type_name -> meowlib.Group
|
||||
15, // 24: meowlib.UserMessage.files:type_name -> meowlib.File
|
||||
16, // 25: meowlib.UserMessage.current_location:type_name -> meowlib.Location
|
||||
|
||||
@@ -81,7 +81,6 @@ message ToServerMessage {
|
||||
Credentials credentials = 13; // credentials for a new user or mandatory server creds
|
||||
}
|
||||
|
||||
|
||||
// structure defining a from server receiver message decrypted from a "packedmessage" payload
|
||||
message FromServerMessage {
|
||||
string type = 1; // Type
|
||||
@@ -105,13 +104,13 @@ message FromServerMessage {
|
||||
|
||||
message MatriochkaServer {
|
||||
string url = 1; // Server Url
|
||||
string publicKey = 2; // Server Public Key
|
||||
string public_key = 2; // Server Public Key
|
||||
string uuid = 3 ; // Optional, uuid for delivery confirmation
|
||||
int32 delay = 4; // Max delay requested for message forwarding or delivery tracking
|
||||
}
|
||||
|
||||
message Matriochka {
|
||||
string lookupKey = 1; // Optional, only if you want delivery tracking, less stealth
|
||||
string lookup_key = 1; // Optional, only if you want delivery tracking, less stealth
|
||||
MatriochkaServer prev = 2; // Optional, like above
|
||||
MatriochkaServer next = 3; // Next server to deliver the message to
|
||||
bytes data = 4; // Matriochka data
|
||||
@@ -134,10 +133,11 @@ message ContactCard {
|
||||
string contact_public_key = 2; // contact public key, will be used to authenticate her/his messages
|
||||
string encryption_public_key = 3; // public key you must use to to write encrypted messages to that contact
|
||||
string lookup_public_key = 4; // public key you will use as "destination identifier" for her/him to lookup for your messages on the servers
|
||||
repeated ServerCard pull_servers =5; // list the servers where the contact will look for messages from you
|
||||
uint32 version = 6;
|
||||
string invitation_id=7;
|
||||
string invitation_message=8;
|
||||
string symetric_key = 5; // agreed key for payload symetric encryption
|
||||
repeated ServerCard pull_servers = 6; // list the servers where the contact will look for messages from you
|
||||
uint32 version = 7;
|
||||
string invitation_id = 8;
|
||||
string invitation_message = 9;
|
||||
}
|
||||
|
||||
// structure for sending a message to be forwarded to another user in protobuf format
|
||||
@@ -145,19 +145,21 @@ message PackedUserMessage {
|
||||
string destination = 1; // the peer's current conversation lookup public key
|
||||
bytes payload = 2; // the message UserMessage encrypted with the destination peer's public key
|
||||
bytes signature = 3; // the payload signature with the client identity private key
|
||||
repeated int64 serverTimestamp=4; // server time stamp, might be several in matriochka mode
|
||||
repeated int64 server_timestamp = 4; // server time stamp, might be several in matriochka mode
|
||||
string server_delivery_uuid = 5; // message uuid, for server delivery tracking, omitted if not delivery tracking desired
|
||||
}
|
||||
|
||||
message ConversationStatus {
|
||||
string uuid = 1;
|
||||
string answer_to_uuid=2; // message is an answer to another one, specify uuid here
|
||||
uint64 localSequence = 3 ; // seq number in local conversation for custom reordering
|
||||
uint64 sent = 4 ; // timestamp of the message sent
|
||||
uint64 received = 5; // timestamp of the message received
|
||||
uint64 processed = 6; // timestamp of the message processed
|
||||
ContactCard my_next_identity = 7;
|
||||
int32 peer_next_identityAck = 8; // version of the new peer accepted id
|
||||
string uuid = 1; // uuid of message, or uuid of related message if uuid_action is not empty
|
||||
int32 uuid_action = 2; // empty => normal message, 1: receivedack, 2: processedack, 3:reaction
|
||||
string reply_to_uuid = 3; // this message replies to the specified uuid
|
||||
uint64 local_sequence = 4 ; // seq number in local conversation for custom reordering
|
||||
uint64 sent = 5 ; // timestamp of the message sent
|
||||
uint64 received = 6; // timestamp of the message received
|
||||
uint64 processed = 7; // timestamp of the message processed
|
||||
ContactCard my_next_identity = 8;
|
||||
int32 peer_next_identity_ack = 9; // version of the new peer accepted id
|
||||
|
||||
}
|
||||
|
||||
message Group{
|
||||
@@ -165,7 +167,6 @@ message Group{
|
||||
repeated ContactCard members = 2;
|
||||
}
|
||||
|
||||
|
||||
// structure defining information that might be exchanged between two peers.
|
||||
message UserMessage {
|
||||
string destination = 1; // Lookupkey
|
||||
@@ -174,7 +175,7 @@ message UserMessage {
|
||||
bytes data = 4;
|
||||
ConversationStatus status = 5;
|
||||
ContactCard contact = 6;
|
||||
ServerCard knownServers = 7;
|
||||
ServerCard known_servers = 7;
|
||||
Group group = 8;
|
||||
repeated File files = 9;
|
||||
Location current_location = 10;
|
||||
@@ -190,7 +191,6 @@ message UserMessage {
|
||||
// 4 : location request
|
||||
// 5 : location response
|
||||
|
||||
|
||||
message File {
|
||||
string filename = 1; // the proposed filename
|
||||
uint64 size = 2; // the file size
|
||||
|
||||
Reference in New Issue
Block a user