package ownwire_sdk_test import ( "context" "crypto/ecdh" "crypto/rand" "encoding/base64" "encoding/json" "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" sdk "ownwire.net/ownwire-sdk" ) var _ = Describe("Client", func() { It("connects, emits opened, handles pending frame, and Send writes encrypted JSON", func() { ctx := context.Background() conn := sdk_test_new_inmem_conn() client_kp, err := sdk.GenClientKey() Expect(err).To(BeNil()) curve := ecdh.P256() server_priv, err := curve.GenerateKey(rand.Reader) Expect(err).To(BeNil()) server_pub_raw := server_priv.PublicKey().Bytes() server_pub_b64 := base64.StdEncoding.EncodeToString(server_pub_raw) salt_raw := make([]byte, 32) _, err = rand.Read(salt_raw) Expect(err).To(BeNil()) salt_b64 := base64.StdEncoding.EncodeToString(salt_raw) session_id := "cb653f53-6f7d-4aeb-ba0d-d2b17c290d8a" shared_key, err := sdk.DeriveSharedKey(session_id, client_kp.ClientPriv, server_pub_raw, salt_raw) Expect(err).To(BeNil()) session_id_bytes, err := sdk.ParseUUIDBytes(session_id) Expect(err).To(BeNil()) opts := sdk.ClientOptions{ Conn: conn, Handshaker: sdk.Handshaker{ GenClientKeyF: func() (sdk.Keypair, error) { return client_kp, nil }, }, } client := sdk.NewClient(opts) go func() { written := <-conn.write_ch Expect(written).To(HavePrefix("/create:")) history_enc, err := sdk.EncryptAESGCM(shared_key, session_id_bytes, []byte("hist"), 10, false) Expect(err).To(BeNil()) history_json, _ := json.Marshal(map[string]any{ "content": history_enc.ContentB64, "metadata": "", "seq_num": 10, "is_encrypted": true, "is_response": false, "salt": history_enc.SaltHex, "created_at": int64(1), }) conn.read_ch <- string(history_json) conn.read_ch <- "/session:" + session_id + ":" + server_pub_b64 + ":" + salt_b64 + ":12:34" }() err = client.Connect(ctx, "") Expect(err).To(BeNil()) select { case ev := <-client.Events(): Expect(ev.Kind).To(Equal(sdk.EventOpened)) case <-time.After(2 * time.Second): Fail("timeout waiting for opened event") } select { case ev := <-client.Events(): Expect(ev.Kind).To(Equal(sdk.EventMessage)) Expect(ev.Message.Content).To(Equal("hist")) Expect(ev.Message.SeqNum).To(Equal(uint64(10))) case <-time.After(2 * time.Second): Fail("timeout waiting for history message event") } go func() { written := <-conn.write_ch var payload map[string]any err := json.Unmarshal([]byte(written), &payload) Expect(err).To(BeNil()) Expect(payload["is_encrypted"]).To(Equal(true)) Expect(payload["salt"]).ToNot(BeEmpty()) seq_num := uint64(payload["seq_num"].(float64)) content_b64 := payload["content"].(string) salt_hex := payload["salt"].(string) pt, err := sdk.DecryptAESGCM(shared_key, session_id_bytes, content_b64, salt_hex, seq_num, false) Expect(err).To(BeNil()) Expect(string(pt)).To(Equal("hello")) }() err = client.Send(ctx, "hello", "") Expect(err).To(BeNil()) }) })