commit
537a851a94
52
account.go
52
account.go
|
@ -12,6 +12,7 @@ type Account struct {
|
||||||
PubKey string
|
PubKey string
|
||||||
Mnemonic string
|
Mnemonic string
|
||||||
Username string
|
Username string
|
||||||
|
Image string
|
||||||
channels []*Channel
|
channels []*Channel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,19 +40,58 @@ func (a *Account) createAndJoin(name, password string) (*Channel, error) {
|
||||||
return a.Join(name, topicID, symKey)
|
return a.Join(name, topicID, symKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnContactRequest executes specified ContactRequestHandler logic when a contact
|
||||||
|
// request is received
|
||||||
|
func (a *Account) OnContactRequest(fn ContactRequestHandler) error {
|
||||||
|
topicID, err := a.calculatePublicChannelTopicID(discoveryChannelName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
filterID, err := newShhMessageFilterFormatRequest(a.conn, []string{topicID}, "", a.PubKey)
|
||||||
|
if err != nil {
|
||||||
|
println(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
discoveryChannel := &Channel{
|
||||||
|
account: a,
|
||||||
|
name: discoveryChannelName,
|
||||||
|
filterID: filterID,
|
||||||
|
TopicID: topicID,
|
||||||
|
ChannelPubKey: a.PubKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = discoveryChannel.Subscribe(func(msg *Msg) {
|
||||||
|
switch c := msg.Properties.(type) {
|
||||||
|
case *NewContactKeyMsg:
|
||||||
|
fn(&Contact{
|
||||||
|
account: a,
|
||||||
|
SymKey: c.Address,
|
||||||
|
TopicID: c.Topic,
|
||||||
|
Name: c.Contact.Name,
|
||||||
|
Address: c.Contact.Address,
|
||||||
|
Image: c.Contact.Image,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Join joins a status channel
|
// Join joins a status channel
|
||||||
func (a *Account) Join(channelName, topicID, symKey string) (*Channel, error) {
|
func (a *Account) Join(channelName, topicID, symKey string) (*Channel, error) {
|
||||||
filterID, err := newShhMessageFilterFormatRequest(a.conn, []string{topicID}, symKey)
|
filterID, err := newShhMessageFilterFormatRequest(a.conn, []string{topicID}, symKey, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := &Channel{
|
ch := &Channel{
|
||||||
account: a,
|
account: a,
|
||||||
name: channelName,
|
name: channelName,
|
||||||
filterID: filterID,
|
filterID: filterID,
|
||||||
TopicID: topicID,
|
TopicID: topicID,
|
||||||
ChannelKey: symKey,
|
ChannelSymKey: symKey,
|
||||||
}
|
}
|
||||||
a.channels = append(a.channels, ch)
|
a.channels = append(a.channels, ch)
|
||||||
|
|
||||||
|
|
11
chan.go
11
chan.go
|
@ -7,12 +7,15 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const discoveryChannelName = "contact-discovery"
|
||||||
|
|
||||||
// Channel : ...
|
// Channel : ...
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
account *Account
|
account *Account
|
||||||
name string
|
name string
|
||||||
filterID string
|
filterID string
|
||||||
ChannelKey string
|
ChannelSymKey string
|
||||||
|
ChannelPubKey string
|
||||||
TopicID string
|
TopicID string
|
||||||
visibility string
|
visibility string
|
||||||
subscriptions []*Subscription
|
subscriptions []*Subscription
|
||||||
|
@ -69,9 +72,9 @@ func (c *Channel) ContactRequest(username, image string) error {
|
||||||
// contact accepts the contact request. It will be sent on the topic that
|
// contact accepts the contact request. It will be sent on the topic that
|
||||||
// was provided in the NewContactKey message and use the sym-key.
|
// was provided in the NewContactKey message and use the sym-key.
|
||||||
// Both users will therefore have the same filter.
|
// Both users will therefore have the same filter.
|
||||||
func (c *Channel) ConfirmedContactRequest(username, image string) error {
|
func (c *Channel) ConfirmedContactRequest(ct *Contact) error {
|
||||||
format := `["%s",["%s","%s","%s","%s"]]`
|
format := `["%s",["%s","%s","%s","%s"]]`
|
||||||
msg := fmt.Sprintf(format, ConfirmedContactRequestType, username, image, c.account.Address, "")
|
msg := fmt.Sprintf(format, ConfirmedContactRequestType, c.account.Username, c.account.Image, c.account.Address, "")
|
||||||
|
|
||||||
return c.SendPostRawMsg(msg)
|
return c.SendPostRawMsg(msg)
|
||||||
}
|
}
|
||||||
|
@ -118,7 +121,7 @@ func (c *Channel) ContactUpdateRequest(username, image string) error {
|
||||||
func (c *Channel) SendPostRawMsg(body string) error {
|
func (c *Channel) SendPostRawMsg(body string) error {
|
||||||
msg := Message{
|
msg := Message{
|
||||||
Signature: c.account.AddressKeyID,
|
Signature: c.account.AddressKeyID,
|
||||||
SymKeyID: c.ChannelKey,
|
SymKeyID: c.ChannelSymKey,
|
||||||
Payload: rawrChatMessage(body),
|
Payload: rawrChatMessage(body),
|
||||||
Topic: c.TopicID,
|
Topic: c.TopicID,
|
||||||
TTL: 10,
|
TTL: 10,
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package sdk
|
||||||
|
|
||||||
|
// Contact details for a known user
|
||||||
|
type Contact struct {
|
||||||
|
account *Account
|
||||||
|
ch *Channel
|
||||||
|
SymKey string
|
||||||
|
TopicID string
|
||||||
|
Name string
|
||||||
|
Image string
|
||||||
|
Address string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept accepts a contact as a friend, sends back a ConfirmedContactRequest
|
||||||
|
func (c *Contact) Accept() error {
|
||||||
|
// Add the proposed symkey
|
||||||
|
symkey, err := addSymKey(c.account.conn, c.SymKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.ch, err = c.account.Join(c.Name, c.TopicID, symkey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.ch.ConfirmedContactRequest(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContactRequestHandler handler for contact requests
|
||||||
|
type ContactRequestHandler func(*Contact)
|
|
@ -7,20 +7,28 @@ func shhGenerateSymKeyFromPasswordRequest(sdk *SDK, password string) (string, er
|
||||||
}
|
}
|
||||||
|
|
||||||
type shhFilterFormatParam struct {
|
type shhFilterFormatParam struct {
|
||||||
AllowP2P bool `json:"allowP2P"`
|
AllowP2P bool `json:"allowP2P"`
|
||||||
Topics []string `json:"topics"`
|
Topics []string `json:"topics"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
SymKeyID string `json:"symKeyID"`
|
SymKeyID string `json:"symKeyID"`
|
||||||
|
PrivateKeyID string `json:"privateKeyID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newShhMessageFilterFormatRequest(sdk *SDK, topics []string, symKey string) (string, error) {
|
func newShhMessageFilterFormatRequest(sdk *SDK, topics []string, symKey, privateKeyID string) (string, error) {
|
||||||
// `{"jsonrpc":"2.0","id":2,"method":"shh_newMessageFilter","params":[{"allowP2P":true,"topics":["%s"],"type":"sym","symKeyID":"%s"}]}`
|
// `{"jsonrpc":"2.0","id":2,"method":"shh_newMessageFilter","params":[{"allowP2P":true,"topics":["%s"],"type":"sym","symKeyID":"%s"}]}`
|
||||||
var res string
|
var res string
|
||||||
params := &shhFilterFormatParam{
|
params := &shhFilterFormatParam{
|
||||||
AllowP2P: true,
|
AllowP2P: true,
|
||||||
Topics: topics,
|
Topics: topics,
|
||||||
Type: "sym",
|
Type: "sym",
|
||||||
SymKeyID: symKey,
|
SymKeyID: symKey,
|
||||||
|
PrivateKeyID: privateKeyID,
|
||||||
|
}
|
||||||
|
if len(symKey) > 0 {
|
||||||
|
params.SymKeyID = symKey
|
||||||
|
}
|
||||||
|
if len(privateKeyID) > 0 {
|
||||||
|
params.PrivateKeyID = privateKeyID
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, sdk.RPCClient.Call(&res, "shh_newMessageFilter", params)
|
return res, sdk.RPCClient.Call(&res, "shh_newMessageFilter", params)
|
||||||
|
@ -83,7 +91,8 @@ func shhGetFilterMessagesRequest(sdk *SDK, filter string) (interface{}, error) {
|
||||||
// Message message to be sent though ssh_post calls
|
// Message message to be sent though ssh_post calls
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Signature string `json:"sig"`
|
Signature string `json:"sig"`
|
||||||
SymKeyID string `json:"symKeyID"`
|
SymKeyID string `json:"symKeyID,omitempty"`
|
||||||
|
PubKey string `json:"pubKey,omitempty"`
|
||||||
Payload string `json:"payload"`
|
Payload string `json:"payload"`
|
||||||
Topic string `json:"topic"`
|
Topic string `json:"topic"`
|
||||||
TTL uint32 `json:"ttl"`
|
TTL uint32 `json:"ttl"`
|
||||||
|
@ -93,5 +102,11 @@ type Message struct {
|
||||||
|
|
||||||
func shhPostRequest(sdk *SDK, msg *Message) (string, error) {
|
func shhPostRequest(sdk *SDK, msg *Message) (string, error) {
|
||||||
var res string
|
var res string
|
||||||
return res, sdk.RPCClient.Call(&res, "shh_post", msg)
|
return res, sdk.RPCClient.Call(&res, "shhext_post", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addSymKey(sdk *SDK, symKey string) (string, error) {
|
||||||
|
// {"jsonrpc":"2.0","method":"shh_addSymKey", "params":["` + symkey + `"], "id":1}
|
||||||
|
var res string
|
||||||
|
return res, sdk.RPCClient.Call(&res, "shh_addSymKey", symKey)
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ func TestDictionaryMethods(t *testing.T) {
|
||||||
{
|
{
|
||||||
Description: "shhPostRequest",
|
Description: "shhPostRequest",
|
||||||
Response: &str,
|
Response: &str,
|
||||||
Method: "shh_post",
|
Method: "shhext_post",
|
||||||
Params: &Message{},
|
Params: &Message{},
|
||||||
Callback: func(sdk *SDK) {
|
Callback: func(sdk *SDK) {
|
||||||
response, err := shhPostRequest(sdk, &Message{})
|
response, err := shhPostRequest(sdk, &Message{})
|
||||||
|
@ -100,7 +100,7 @@ func TestDictionaryMethods(t *testing.T) {
|
||||||
SymKeyID: "",
|
SymKeyID: "",
|
||||||
},
|
},
|
||||||
Callback: func(sdk *SDK) {
|
Callback: func(sdk *SDK) {
|
||||||
response, err := newShhMessageFilterFormatRequest(sdk, []string{}, "")
|
response, err := newShhMessageFilterFormatRequest(sdk, []string{}, "", "")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, response)
|
assert.NotNil(t, response)
|
||||||
},
|
},
|
||||||
|
|
File diff suppressed because one or more lines are too long
2
msg.go
2
msg.go
|
@ -166,7 +166,7 @@ type ContactMsg struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func contactMsgFromProperties(properties []interface{}) *ContactMsg {
|
func contactMsgFromProperties(properties []interface{}) *ContactMsg {
|
||||||
crProperties := properties[2].([]interface{})
|
crProperties := properties[1].([]interface{})
|
||||||
|
|
||||||
return &ContactMsg{
|
return &ContactMsg{
|
||||||
Name: crProperties[0].(string),
|
Name: crProperties[0].(string),
|
||||||
|
|
Loading…
Reference in New Issue