Phase 1 Steps 4-6 (the receive pipeline, minus the App/sync wiring which lands next). - chat_message: the in-memory ChatMessage model (direction, kind, txid, cid, peer zaddr/pubkey, body, timestamp, payload_position). No libsodium. - chat_store: threads messages by conversation_id and dedups by (txid, payload_position) so re-scanning the chain never double-inserts. - chat_service: owns the long-lived chat identity keypair (move-disabled, wiped on destruction/clear) and the store. ingest() decrypts each Message (drops undecryptable ones silently — no plaintext/memo logging), passes a ContactRequest's plaintext through, and threads the result. No-op without an identity. Tests: a metadata batch decrypts into a threaded conversation; re-ingest dedups; a contact request carries through; a wrong identity decrypts nothing; no-identity ingest is a no-op. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
48 lines
1.8 KiB
C++
48 lines
1.8 KiB
C++
#pragma once
|
|
|
|
// DragonX Wallet - HushChat service: turns harvested memo metadata into decrypted, threaded
|
|
// messages. Owns the long-lived chat identity keypair (a secret) + the in-memory store.
|
|
// Move-disabled (the secret stays pinned); wipes the secret on destruction/clear.
|
|
// Not thread-safe — drive from the main thread (where refresh results are applied).
|
|
|
|
#include "chat_crypto.h" // ChatKeyPair
|
|
#include "chat_protocol.h" // HushChatTransactionMetadata
|
|
#include "chat_store.h"
|
|
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
namespace dragonx::chat {
|
|
|
|
class ChatService {
|
|
public:
|
|
ChatService() = default;
|
|
~ChatService();
|
|
ChatService(const ChatService&) = delete;
|
|
ChatService& operator=(const ChatService&) = delete;
|
|
ChatService(ChatService&&) = delete;
|
|
ChatService& operator=(ChatService&&) = delete;
|
|
|
|
// Provision (or replace) the chat identity. Copies the keypair — the caller should wipe
|
|
// its own copy afterwards (see chat_identity.h ownership note).
|
|
void setIdentity(const ChatKeyPair& keys);
|
|
bool hasIdentity() const { return has_identity_; }
|
|
void clearIdentity(); // wipes the held secret key
|
|
|
|
// Decrypt/record each metadata entry (a Message is decrypted; a ContactRequest carries its
|
|
// plaintext through) and thread it into the store. `txTimestamp` is stamped onto every
|
|
// message in this batch. Returns the number of NEW messages added. Returns 0 with no
|
|
// identity. Undecryptable Messages are dropped silently (no logging of memo/plaintext).
|
|
int ingest(const std::vector<HushChatTransactionMetadata>& metadata, std::int64_t txTimestamp = 0);
|
|
|
|
const ChatStore& store() const { return store_; }
|
|
ChatStore& store() { return store_; }
|
|
|
|
private:
|
|
ChatKeyPair identity_{};
|
|
bool has_identity_ = false;
|
|
ChatStore store_;
|
|
};
|
|
|
|
} // namespace dragonx::chat
|