summaryrefslogtreecommitdiffstats
path: root/internal/relay/relay.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/relay/relay.go')
-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
+ }
+}