func MustNewNonce() *sf.Nonce { n, err := sf.NewNonce() if err != nil { panic(err) } return n }
// Request encrypts a request to the server and decrypts the response. // // If the client and server have securely exchanged keys out of band, // confidentiality does not depend on TLS. func (c *Client) Request(method string, path string, contents []byte) ([]byte, error) { nonce, err := sf.NewNonce() if err != nil { return nil, errgo.Mask(err) } encReq := box.Seal(nil, contents, (*[24]byte)(nonce), (*[32]byte)(c.serverKey), (*[32]byte)(c.keyPair.PrivateKey)) reqMessage := wire.Message{ ID: nonce.Encode(), Contents: encReq, } reqContents, err := json.Marshal(&reqMessage) if err != nil { return nil, errgo.Mask(err) } req, err := http.NewRequest(method, c.serverURL+path, bytes.NewBuffer(reqContents)) if err != nil { return nil, errgo.Mask(err) } req.Header.Set("Content-Type", "application/json") resp, err := c.client.Do(req) if err != nil { return nil, errgo.Mask(err) } defer resp.Body.Close() respContents, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, errgo.Mask(err) } if resp.StatusCode != http.StatusOK { return nil, errgo.Mask(newHTTPClientError(resp.StatusCode, string(respContents))) } decResp, ok := box.Open(nil, respContents, (*[24]byte)(nonce), (*[32]byte)(c.serverKey), (*[32]byte)(c.keyPair.PrivateKey)) if !ok { return nil, errgo.New("failed to authenticate response from server") } return decResp, nil }
// Push pushes a message to a recipient. func (c *Client) Push(recipient string, contents []byte) error { nonce, err := sf.NewNonce() if err != nil { return errgo.Mask(err) } rcptKey, err := sf.DecodePublicKey(recipient) if err != nil { return errgo.Mask(err) } encMsg := box.Seal(nil, contents, (*[24]byte)(nonce), (*[32]byte)(rcptKey), (*[32]byte)(c.keyPair.PrivateKey)) pushWire := []wire.PushMessage{{ Message: wire.Message{ ID: nonce.Encode(), Contents: encMsg, }, Recipient: recipient, }} reqContents, err := json.Marshal(&pushWire) if err != nil { return errgo.Mask(err) } respContents, err := c.Request("POST", "/outbox/"+c.keyPair.PublicKey.Encode(), reqContents) if err != nil { return errgo.Mask(err) } var pushReceipts []wire.PushReceipt err = json.Unmarshal(respContents, &pushReceipts) if err != nil { return errgo.Mask(err) } for _, receipt := range pushReceipts { if receipt.OK && receipt.ID == nonce.Encode() { return nil } } return errgo.New("not acknowledged") }