summaryrefslogtreecommitdiffstats
path: root/internal/nym/client.go
diff options
context:
space:
mode:
authorGab Virebent <gabriel1@virebent.art>2026-07-11 13:37:23 +0200
committerGab Virebent <gabriel1@virebent.art>2026-07-11 13:37:23 +0200
commitbec3734676faf3868ea225e0316e77ad5a7e4421 (patch)
tree78bc62532fcdb9f42eb92c41f0841b5fdeeb063d /internal/nym/client.go
parentf21e4d8781c06c0686f4a8697ce0697f9bf6a5cc (diff)
downloadnymdrop-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.go45
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