118 lines
3.0 KiB
Go
118 lines
3.0 KiB
Go
|
|
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())
|
||
|
|
})
|
||
|
|
})
|
||
|
|
|