summaryrefslogtreecommitdiffstats
path: root/internal/relay
diff options
context:
space:
mode:
authorGab Virebent <gabriel1@virebent.art>2026-06-20 01:07:45 +0000
committerGab Virebent <gabriel1@virebent.art>2026-06-20 01:07:45 +0000
commitaa459e3b84cc4c5d908f3781c9253848c18640c3 (patch)
tree8454b956cc0fa027034c8291f39d58ece469e10c /internal/relay
downloadnymdrop-aa459e3b84cc4c5d908f3781c9253848c18640c3.tar.gz
nymdrop-aa459e3b84cc4c5d908f3781c9253848c18640c3.tar.xz
nymdrop-aa459e3b84cc4c5d908f3781c9253848c18640c3.zip
Initial public release: Nym-native anonymous submission system
End-to-end verified pipeline (browser -> HTTP relay -> Nym mixnet -> reader). Client-side X25519+HKDF+AES-GCM-256, no-log blind relay, AGPL-3.0.
Diffstat (limited to 'internal/relay')
-rw-r--r--internal/relay/relay.go47
1 files changed, 47 insertions, 0 deletions
diff --git a/internal/relay/relay.go b/internal/relay/relay.go
new file mode 100644
index 0000000..9cd0366
--- /dev/null
+++ b/internal/relay/relay.go
@@ -0,0 +1,47 @@
+package relay
+
+import (
+ "crypto/rand"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "nymdrop/internal/nym"
+)
+
+const maxPayloadBytes = 10 * 1024 * 1024 // 10 MB
+
+// Relay receives ciphertext and forwards it through Nym. Nothing is written to disk.
+type Relay struct {
+ nym *nym.Client
+}
+
+func New(client *nym.Client) *Relay {
+ return &Relay{nym: client}
+}
+
+// Forward reads ciphertext from r, sends it over Nym, then zeros the buffer.
+func (r *Relay) Forward(body io.Reader) error {
+ buf := make([]byte, maxPayloadBytes)
+ n, err := io.ReadFull(body, buf)
+ if err != nil && err != io.ErrUnexpectedEOF {
+ return fmt.Errorf("read payload: %w", err)
+ }
+ payload := buf[:n]
+ defer zeroBytes(payload)
+
+ // Prepend a random nonce so identical submissions look different on the wire.
+ nonce := make([]byte, 16)
+ if _, err := rand.Read(nonce); err != nil {
+ return fmt.Errorf("nonce: %w", err)
+ }
+ packet := append([]byte(hex.EncodeToString(nonce)+":"), payload...)
+ defer zeroBytes(packet)
+
+ return r.nym.Send(packet)
+}
+
+func zeroBytes(b []byte) {
+ for i := range b {
+ b[i] = 0
+ }
+}