diff options
| author | Gab Virebent <gabriel1@virebent.art> | 2026-07-11 13:37:23 +0200 |
|---|---|---|
| committer | Gab Virebent <gabriel1@virebent.art> | 2026-07-11 13:37:23 +0200 |
| commit | bec3734676faf3868ea225e0316e77ad5a7e4421 (patch) | |
| tree | 78bc62532fcdb9f42eb92c41f0841b5fdeeb063d /internal/nym/client.go | |
| parent | f21e4d8781c06c0686f4a8697ce0697f9bf6a5cc (diff) | |
| download | nymdrop-bec3734676faf3868ea225e0316e77ad5a7e4421.tar.gz nymdrop-bec3734676faf3868ea225e0316e77ad5a7e4421.tar.xz nymdrop-bec3734676faf3868ea225e0316e77ad5a7e4421.zip | |
Switch Nym WS transport to nym-client's binary protocol, drop second base64 layer
Client.Send now speaks nym-client's native binary websocket protocol
(tag || recipient || conn_id || data_len || data) instead of wrapping
the ciphertext in a JSON text message, which required base64-encoding
it a second time on top of the browser's own base64 layer.
The reader's self-address query also switched to the binary protocol:
nym-client picks text-vs-binary for every later "received" push based
on the format of the last request seen on a connection, so leaving the
reader in JSON/text mode would have made nym-client run a lossy UTF-8
conversion over the now-unencoded binary payload, corrupting it. Fixed
the binary Received-frame parsing along the way (previous code assumed
a fixed 16-byte tag with no length prefix, which never matched the real
protocol and was never exercised while the connection stayed text-mode).
Verified end-to-end against the real embedded nym-client 1.1.76 binary,
with the exact wire format cross-checked against upstream nym source at
the pinned build commit.
Diffstat (limited to 'internal/nym/client.go')
| -rw-r--r-- | internal/nym/client.go | 45 |
1 files changed, 22 insertions, 23 deletions
diff --git a/internal/nym/client.go b/internal/nym/client.go index 89fcf52..e0b14d2 100644 --- a/internal/nym/client.go +++ b/internal/nym/client.go @@ -1,8 +1,7 @@ package nym import ( - "encoding/base64" - "encoding/json" + "encoding/binary" "fmt" "io" "io/fs" @@ -18,6 +17,7 @@ import ( // Client sends payloads through the Nym mixnet via an embedded nym-client subprocess. type Client struct { journalistAddr string + recipient []byte // parsed 96-byte wire form of journalistAddr wsPort int dryRun bool process *exec.Cmd @@ -26,8 +26,12 @@ type Client struct { configDir string } -func New(journalistAddr string, binFS fs.FS) *Client { - return &Client{journalistAddr: journalistAddr, wsPort: 1978, binFS: binFS} +func New(journalistAddr string, binFS fs.FS) (*Client, error) { + recipient, err := ParseRecipient(journalistAddr) + if err != nil { + return nil, fmt.Errorf("parse journalist nym address: %w", err) + } + return &Client{journalistAddr: journalistAddr, recipient: recipient, wsPort: 1978, binFS: binFS}, nil } func NewDryRun(journalistAddr string) *Client { @@ -75,31 +79,26 @@ func (c *Client) Start() error { return fmt.Errorf("nym-client websocket did not start in time") } -type sendMsg struct { - Type string `json:"type"` - Message string `json:"message"` - Recipient string `json:"recipient"` - WithReplySurb bool `json:"withReplySurb"` -} - -// Send delivers payload to the journalist's Nym address through the mixnet. +// Send delivers payload to the journalist's Nym address through the mixnet +// using nym-client's binary websocket protocol (tag || recipient || conn_id || +// data_len || data). This avoids the JSON+base64 wrapping of the old text +// protocol, which inflated every payload by ~4/3 before it ever reached the +// nym-client's own 16MB hardcoded websocket message limit. func (c *Client) Send(payload []byte) error { if c.dryRun { fmt.Printf("[dry-run] payload received: %d bytes — would send to %s\n", len(payload), c.journalistAddr) return nil } - msg := sendMsg{ - Type: "send", - Message: base64.StdEncoding.EncodeToString(payload), - Recipient: c.journalistAddr, - WithReplySurb: false, - } - raw, err := json.Marshal(msg) - if err != nil { - return fmt.Errorf("marshal: %w", err) - } - if err := websocket.Message.Send(c.ws, string(raw)); err != nil { + + req := make([]byte, 0, 1+len(c.recipient)+8+8+len(payload)) + req = append(req, ReqSend) + req = append(req, c.recipient...) + req = binary.BigEndian.AppendUint64(req, 0) // connection_id: none + req = binary.BigEndian.AppendUint64(req, uint64(len(payload))) + req = append(req, payload...) + + if err := websocket.Message.Send(c.ws, req); err != nil { return fmt.Errorf("ws send: %w", err) } return nil |
