128 views
# Message Identity Specifications (Draft v1) ## NOTE: superceded by [**Draft v2**](https://notes.status.im/oUChlPB3Q2aUPLYBSjq6MQ?both) The following specification detaisl the methods and processes by which to handle user defined identity data, including: - ENS name data - Display name data - Profile image data ## Table of contents [toc] ## Protobuf structure ```protobuf // ProfileImage represents data associated with a user's profile image message ProfileImage { // source_type allows the application to use a range of image sources SourceType source_type = 1; // source is a context based source for the profile image data, // context is determined by the `source_type` string source = 2; // SourceType are the predefined types of image source allowed enum SourceType { UNKNOWN_SOURCE_TYPE = 0; // ENS_AVATAR uses the ENS record's resolver get-text-data.avatar data // if `source` is empty inspect record // if `source` is set use source URL // The parent `ChatMessageIdentity` must have a valid `ens_name` set ENS_AVATAR = 1; // IPFS_ADDRESS uses IPFS to get the image data // 'source' must be set // `source` is an IPFS address IPFS_ADDRESS = 2; // URL_ADDRESS uses a standard internet URL to the image data // `source` must be set // `source` is a URL URL_ADDRESS = 3; // RAW_PAYLOAD uses base64 encoded image data // `source` must be set // `source` is base64 encoded image data RAW_PAYLOAD = 4; } } // ChatMessageIdentity represents the user defined identity associated with their messages message ChatMessageIdentity { // ens_name is the valid ENS name associated with the chat key string ens_name = 1; // display_name is the user's chosen display name string display_name = 2; // profile_image is the data associated with the user's profile image ProfileImage profile_image = 3; } message ChatMessage { //... // Self defined identity data of sender ChatMessageIdentity identity = 5; //... } ``` ## JSON Examples **Display name with IPFS profile image** ```json { "ChatMessage": { "text": "Hey there!", "identity": { "display_name": "lilblockchainz", "profile_image": { "source": "QmR7GSQM93Cx5eAg6a6yRzNde1FQv7uL6X1o4k7zrJa3LX", "source_type": 2 } } } } ``` **ENS name with ENS avatar profile image** ```json { "ChatMessage": { "text": "Hey there!", "identity": { "ens_name": "lilblockchainz.eth", "profile_image": { "source_type": 1 } } } } ``` **No display name (defaults to random 3 word) URL profile image** ```json { "ChatMessage": { "text": "Hey there!", "identity": { "profile_image": { "source": "https://example.com/images/profile.png", "source_type": 3 } } } } ``` **No message identity (defaults to random 3 word)** ```json { "ChatMessage": { "text": "Hey there!" } } ``` **Empty template** ```json { "ChatMessage": { "text": "", "identity": { "ens_name": "", "display_name": "", "profile_image": { "source": "", "source_type": 0 } } } } ``` ## Persistence ### User's identity data // TODO ### Other user's (correspondants) identity data To efficiently handle identity data of messages from other identities the device should implement persistence. **Note:** Update the existing `contacts` table to handle persistence ```sql CREATE TABLE IF NOT EXISTS message_identities ( /* chat_key the message author's public chat key, used as the index*/ chat_key VARCHAR PRIMARY KEY ON CONFLICT REPLACE, /* identity_hash the sha256 hash of the parsed ChatMessageIdentity */ identity_hash VARCHAR NOT NULL, /* last_clock is the clock value of the message that contained the last */ /* unique ChatMessageIdentity hash, used to determine which identity */ /* data should be given priority if the message sender changes their */ /* data multiple times since the last message pull */ last_clock /* ens_name a valid ENS name associated with the user's chat key */ ens_name VARCHAR, /* display_name the given display name */ display_name VARCHAR, /* profile_image_dst the local path to the profile image cached on the user's device */ profile_image_dst VARCHAR /* profile_image_source_type is an enum representing the source type of the profile image */ profile_image_source_type int /* profile_image_last_updated is the last date that the profile image cache was updated */ profile_image_last_updated TIME ); ``` #### `identity_hash` The `identity_hash` is a sha256 hash of the parsed ChatMessageIdentity protobuf, used to make checking for identity changes simple. #### `profile_image_dst` The `profile_image_dst` is the file path of the locally stored image file of a message identity profile image. The file represents a sanitised cache of the image file to be renewed every 7 days or when an image update is received from a new message or a manual image update request is given. ## Security precautions Sanitise and cache all images to be displayed by the device. ## Process flows ### Setting Identity process flow ```mermaid graph LR %% Intities user((User)) subgraph status [Status App] subgraph status-react UI{UI} end subgraph status-go db[(db - chat_identity)] int[Account management service] API[Account management API Endpoint] end end %% Connections user --> UI UI --> API API --> int int --> db ``` ### Sending message process flow ```mermaid graph LR %% Intities user((User)) subgraph status [Status App] subgraph status-react UI{UI} end subgraph status-go db[(db - chat_identity)] int[Send message service] API[Send Message API Endpoint] end end network{{Waku Network}} %% Connections user --> UI UI --> API API -->|Step 1| int int -->|Step 2| db db -->|Step 3| int int -->|Step 4| network ``` Step 1 - Standard unchanged send message API call Step 2 - query db for user identity data from `chat_identity` table, or memory store Step 3 - attach identity data to waku message Step 4 - Standard unchanged broadcast to waku network ### Receiving message process flow ```mermaid graph BT %% Intities user((User)) subgraph status [Status App] subgraph status-react UI{UI} end subgraph status-go db[(db - message_identities)] ser[Get Messages service] API[Get Messages API Endpoint] dir[Image Cache] end end network{{Waku Network}} %% Connections user --> UI -->|Step 11| user UI --> API -->|Step 10| UI API -->|Step 1| ser -->|Step 9| API ser -->|Step 2| network -->|Step 3 & 4| ser ser -->|Step 5| db -->|Step 6| ser ser -->|Step 7| dir ser -->|Step 8| db ``` 1. Standard unchanged get message API call 2. Standard call to Waku network / mailserver for new messages 3. Standard messages return 4. Parse messages - Extract any `ChatMessageIdentity` data from chat message payloads - Calculate hashes for all unique `ChatMessageIdentity` - Assign `ChatMessageIdentity` to memory mapping (`map[chat_key]ChatMessageIdentity`) - ignore any duplicates or any `ChatMessageIdentity` from a message with a lower clock than in the mapping 5. Get `identity_hash`, `last_clock` and `profile_image_last_updated` stored in `message_identities` where the chat keys match the map indexes 6. Compare `identity_hash` and `last_clock` against each chat key - If the new message clock is higher and the hash does not match proceed to step 7 - If no record was found for the chat key proceed to step 7 7. Check image is new or that cache age is too old - Resolve parsed protobuf `ProfileImage` (because there are many potential sources for an image this would be a large part of the work) - Get raw image data from ENS, IPFS, payload, URL etc - Parse and sanitise the image data - Store image on local device disk 8. Update or create record in the database 9. Append to the `MessengerResponse.Contact` struct return data to API endpoint 10. Standard message response return 11. `status-react` populates new messages in the chat view with contact data - Setting the user display names, profile photos, etc ### Image cache update process flow In theory this would only affect images with a source type of `ENS_AVATAR` or `URL_ADDRESS`, as these two are the only sources that have the potential to change without the altering the `ChatMessageIdentity` hash. This process would be triggered by an API call and/or as part of the [Receiving message process flow](#Receiving-message-process-flow) ```mermaid graph LR %% Intities subgraph status-go db[(db - message_identities)] ser[Update Profile Image Cache service] dir[Image Cache] end %% Connections Signal -->|Step 1| ser db -->|Step 2| ser -->|Step 3| db ser -->|Step 4| dir ser -->|Step 5| db ``` // TODO detail the steps