Files
voice-cat/server/src/identity.h
Talon 63f457fc54 feat(M1): TCP/TLS control plane -- auth, channels, ephemeral text
Implements the full M1 milestone. Two clients authenticate over TLS 1.3
(guest + Argon2id password) and exchange channel + private text messages
through a real server. All five ctest --preset m1-dev tests pass in ~1 s.

Key components added:
- vcpkg baseline + m1-dev preset (protobuf/mbedTLS/libsodium/asio/sqlite3)
- FrameCodec feed+emit, encode/decode_envelope, protobuf codegen
- TcpServerConn with blocking TLS handshake thread + tls_read_loop
- TlsContext (mbedTLS 1.3, ECDSA-P256 self-signed cert, TOFU on client)
- WorkerPool (3 threads, used for Argon2id)
- Database: SQLite + libsodium Argon2id, account lifecycle, bootstrap admin
- ServerIdentityManager: Ed25519 key + cert generate/persist/fingerprint
- ConnSession state machine: WaitingHello -> WaitingAuth -> Authenticated
- SessionRegistry: channel tree, user map, text routing, broadcast
- vc_client full M1 C ABI: connect/TLS/handshake/auth/text/disconnect
- voicecat-admin CLI: account add/reset/del/list
- test_m1_integration: M1 exit criterion, verified green

Bug fixed: double-framing in ConnSession::send_envelope -- encode_envelope
was adding the [4-byte len] prefix, then TcpServerConn::send_frame added
a second one, causing the client to parse [len][proto] as protobuf (silent
failure). Fixed by serializing raw protobuf bytes in send_envelope and
letting send_frame apply the single length prefix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 23:48:44 +02:00

41 lines
1.1 KiB
C++

/*
* server/identity.h — Server identity manager.
*
* Loads or generates the Ed25519 identity key + self-signed TLS cert on first run.
* Persists both to data_dir/identity.key and data_dir/server.{crt,key}.
*/
#ifndef VOICECAT_SERVER_IDENTITY_H
#define VOICECAT_SERVER_IDENTITY_H
#ifdef VOICECAT_HAS_NET
#include <filesystem>
#include <string>
#include "crypto/crypto.h"
namespace voicecat::server {
class ServerIdentityManager {
public:
// Load from data_dir, or generate on first run.
// Returns false on fatal I/O error.
bool init(const std::filesystem::path& data_dir, const std::string& server_name,
std::string& error);
const crypto::ServerIdentity& identity() const { return identity_; }
const crypto::ServerCert& cert() const { return cert_; }
// "AA:BB:CC:..." hex for display
std::string fingerprint_display() const { return identity_.fingerprint_hex(); }
private:
crypto::ServerIdentity identity_;
crypto::ServerCert cert_;
};
} // namespace voicecat::server
#endif // VOICECAT_HAS_NET
#endif // VOICECAT_SERVER_IDENTITY_H