forked from cwtch.im/cwtch
Lots of peerand serverstuff
This commit is contained in:
parent
c29186979f
commit
914be9e46a
|
@ -3,11 +3,12 @@ package model
|
|||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"git.mascherari.press/cwtch/protocol"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/s-rah/go-ricochet/utils"
|
||||
"golang.org/x/crypto/nacl/secretbox"
|
||||
"io"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"git.mascherari.press/cwtch/protocol"
|
||||
"github.com/s-rah/go-ricochet/utils"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -52,7 +53,9 @@ func (g *Group) Invite() []byte {
|
|||
GroupName: g.GroupID,
|
||||
GroupSharedKey: g.GroupKey[:],
|
||||
ServerHost: g.GroupServer,
|
||||
SignedGroupId: g.SignedGroupID[:],
|
||||
}
|
||||
log.Printf("INVITEBEFORE %v", gci)
|
||||
cp := &protocol.CwtchPeerPacket{
|
||||
GroupChatInvite: gci,
|
||||
}
|
||||
|
@ -63,11 +66,11 @@ func (g *Group) Invite() []byte {
|
|||
|
||||
func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, verified bool) {
|
||||
timelineMessage := Message{
|
||||
Message: message.GetText(),
|
||||
Timestamp: time.Unix(int64(message.GetTimestamp()),0),
|
||||
Message: message.GetText(),
|
||||
Timestamp: time.Unix(int64(message.GetTimestamp()), 0),
|
||||
Signature: message.GetSignature(),
|
||||
Verified:verified,
|
||||
PeerID: message.GetOnion(),
|
||||
Verified: verified,
|
||||
PeerID: message.GetOnion(),
|
||||
}
|
||||
g.Timeline = append(g.Timeline, timelineMessage)
|
||||
}
|
||||
|
@ -88,7 +91,7 @@ func (g *Group) EncryptMessage(message *protocol.DecryptedGroupMessage) []byte {
|
|||
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wire,err := proto.Marshal(message)
|
||||
wire, err := proto.Marshal(message)
|
||||
utils.CheckError(err)
|
||||
encrypted := secretbox.Seal(nonce[:], []byte(wire), &nonce, &g.GroupKey)
|
||||
return encrypted
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"git.mascherari.press/cwtch/protocol"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestGroup(t *testing.T) {
|
||||
g := NewGroup("server.onion")
|
||||
dgm := &protocol.DecryptedGroupMessage{
|
||||
Onion: proto.String("onion"),
|
||||
Text: proto.String("Hello World!"),
|
||||
Timestamp: proto.Int32(int32(time.Now().Unix())),
|
||||
Onion: proto.String("onion"),
|
||||
Text: proto.String("Hello World!"),
|
||||
Timestamp: proto.Int32(int32(time.Now().Unix())),
|
||||
SignedGroupId: []byte{},
|
||||
Signature: []byte{},
|
||||
|
||||
Signature: []byte{},
|
||||
}
|
||||
encMessage := g.EncryptMessage(dgm)
|
||||
ok, message := g.DecryptMessage(encMessage)
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
|
||||
// Message is a local representation of a given message sent over a group chat channel.
|
||||
type Message struct {
|
||||
Timestamp time.Time
|
||||
|
|
|
@ -3,34 +3,33 @@ package model
|
|||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"encoding/asn1"
|
||||
"encoding/json"
|
||||
"git.mascherari.press/cwtch/protocol"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/s-rah/go-ricochet/utils"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
"encoding/asn1"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
// PublicProfile is a local copy of a CwtchIdentity
|
||||
type PublicProfile struct {
|
||||
Name string
|
||||
Ed25519PublicKey ed25519.PublicKey
|
||||
Trusted bool
|
||||
Blocked bool
|
||||
Trusted bool
|
||||
Blocked bool
|
||||
}
|
||||
|
||||
|
||||
// Profile encapsulates all the attributes necessary to be a Cwtch Peer.
|
||||
type Profile struct {
|
||||
PublicProfile
|
||||
Contacts map[string]PublicProfile
|
||||
Ed25519PrivateKey ed25519.PrivateKey
|
||||
OnionPrivateKey *rsa.PrivateKey
|
||||
Onion string
|
||||
Onion string
|
||||
Groups map[string]*Group
|
||||
}
|
||||
|
||||
|
@ -96,6 +95,12 @@ func (p *Profile) VerifyMessage(onion string, message string, signature []byte)
|
|||
return ed25519.Verify(p.Contacts[onion].Ed25519PublicKey, []byte(message), signature)
|
||||
}
|
||||
|
||||
// VerifyMessage confirms the authenticity of a message given an onion, message and signature.
|
||||
func (p *Profile) VerifyGroupMessage(onion string, groupID string, message string, timestamp int32, signature []byte) bool {
|
||||
m := message + groupID + strconv.Itoa(int(timestamp))
|
||||
return ed25519.Verify(p.Contacts[onion].Ed25519PublicKey, []byte(m), signature)
|
||||
}
|
||||
|
||||
// SignMessage takes a given message and returns an Ed21159 signature
|
||||
func (p *Profile) SignMessage(message string) []byte {
|
||||
sig := ed25519.Sign(p.Ed25519PrivateKey, []byte(message))
|
||||
|
@ -107,11 +112,14 @@ func (p *Profile) SignMessage(message string) []byte {
|
|||
func (p *Profile) StartGroup(server string) (groupID string, invite []byte) {
|
||||
group := NewGroup(server)
|
||||
groupID = group.GroupID
|
||||
signedGroupId := p.SignMessage(groupID)
|
||||
group.SignGroup(signedGroupId)
|
||||
invite = group.Invite()
|
||||
p.AddGroup(group)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Profile) GetGroupByGroupId(groupID string) (*Group) {
|
||||
func (p *Profile) GetGroupByGroupId(groupID string) *Group {
|
||||
return p.Groups[groupID]
|
||||
}
|
||||
|
||||
|
@ -119,6 +127,7 @@ func (p *Profile) GetGroupByGroupId(groupID string) (*Group) {
|
|||
func (p *Profile) ProcessInvite(gci *protocol.GroupChatInvite, peerHostname string) {
|
||||
group := new(Group)
|
||||
group.GroupID = gci.GetGroupName()
|
||||
group.SignedGroupID = gci.GetSignedGroupId()
|
||||
copy(group.GroupKey[:], gci.GetGroupSharedKey()[:])
|
||||
group.GroupServer = gci.GetServerHost()
|
||||
group.Accepted = false
|
||||
|
@ -126,7 +135,7 @@ func (p *Profile) ProcessInvite(gci *protocol.GroupChatInvite, peerHostname stri
|
|||
p.AddGroup(group)
|
||||
}
|
||||
|
||||
// AddGroup is a conveniance method for adding a group to a profle.
|
||||
// AddGroup is a conveniance method for adding a group to a profile.
|
||||
func (p *Profile) AddGroup(group *Group) {
|
||||
existingGroup, exists := p.Groups[group.GroupID]
|
||||
if !exists {
|
||||
|
@ -145,12 +154,13 @@ func (p *Profile) AddGroup(group *Group) {
|
|||
}
|
||||
|
||||
// AttemptDecryption takes a ciphertext and signature and attempts to decrypt it under known groups.
|
||||
func (p *Profile) AttemptDecryption(ciphertext []byte, signature []byte) {
|
||||
func (p *Profile) AttemptDecryption(ciphertext []byte) {
|
||||
for _, group := range p.Groups {
|
||||
success, dgm := group.DecryptMessage(ciphertext)
|
||||
log.Printf("Decrypt Attempt %v %v", success, dgm)
|
||||
if success {
|
||||
// FIXME
|
||||
verified := p.VerifyMessage(dgm.GetOnion(), dgm.GetText(), dgm.GetSignature())
|
||||
verified := p.VerifyGroupMessage(dgm.GetOnion(), group.GroupID, dgm.GetText(), dgm.GetTimestamp(), dgm.GetSignature())
|
||||
group.AddMessage(dgm, verified)
|
||||
}
|
||||
}
|
||||
|
@ -162,12 +172,12 @@ func (p *Profile) EncryptMessageToGroup(message string, groupID string) (ciphert
|
|||
group := p.Groups[groupID]
|
||||
timestamp := time.Now().Unix()
|
||||
signature = p.SignMessage(message + groupID + strconv.Itoa(int(timestamp)))
|
||||
dm := &protocol.DecryptedGroupMessage {
|
||||
Onion: proto.String(p.Onion),
|
||||
Text: proto.String(message),
|
||||
SignedGroupId: group.SignedGroupID,
|
||||
Timestamp: proto.Int32(int32(timestamp)),
|
||||
Signature: signature,
|
||||
dm := &protocol.DecryptedGroupMessage{
|
||||
Onion: proto.String(p.Onion),
|
||||
Text: proto.String(message),
|
||||
SignedGroupId: group.SignedGroupID[:],
|
||||
Timestamp: proto.Int32(int32(timestamp)),
|
||||
Signature: signature,
|
||||
}
|
||||
ciphertext = group.EncryptMessage(dm)
|
||||
return
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"Name":"Sarah","Ed25519PublicKey":"08Q49pmOe/8Edn/jR1Qq8d26SU1MzPbJ2PmJ64S6BY8=","Trusted":false,"Blocked":false,"Contacts":{},"Ed25519PrivateKey":"/hhjerGW66QyhAKPtwGbBBzhY5/auK6T2b/vjRGuXnjTxDj2mY57/wR2f+NHVCrx3bpJTUzM9snY+YnrhLoFjw==","OnionPrivateKey":{"N":146328154189193884086641737732621103864374553173215703384122944250992002089624680210913011506081609406766798073335357829207459154214042241028123233139603802979024475926282158611908322463042012748984945285776401165814190414695182764240512995788636041616865870623261762908273890987461235956226167821197856348839,"E":65537,"D":131000281712443101868127073809425903015557376501501621205628292187530749753611841209312116988644890475820095160882129401029342867327559796231167833968091809253818237330927694966481136799400760644381429766064366889564088512676631446803130802140311950212661905465119640487794003192289760147304713580532618877313,"Primes":[11046905119315044599912769443513046649297228971109751902148448569336221142449837623971448415395377389790939200512488865059980264758837294990542341171570219,13246076852180554978507253920836715985718751717246338099834768101497493531807293249274887847720805074264534287152405900588792629153510158525691602692356981],"Precomputed":{"Dp":9951771949347089936659442878755668922509550306762893515157001442446411893285295532588832483100280468945131000782113044435070797127756136171042614443284033,"Dq":6285403633811601060799526716666618760759292321939158372044213473615958219816946235957557750406970050497863607761501422044192947211740832046507430314584393,"Qinv":6371034795994819655941418536323418056681675622606010416374029760428023006446243689515420082688972242794843497150013283993628462297774942497647603736899599,"CRTValues":[]}},"Onion":"3qs4j52zt24qqnor","Groups":{}}
|
||||
{"Name":"Sarah","Ed25519PublicKey":"57Vq0cuSR354/iWji5HYo1wRLejxtUHt3oG7Su/apTs=","Trusted":false,"Blocked":false,"Contacts":{},"Ed25519PrivateKey":"J8ccHg0nDRTt2hUcWFgcja7zp3q+stire73hfHQDlGDntWrRy5JHfnj+JaOLkdijXBEt6PG1Qe3egbtK79qlOw==","OnionPrivateKey":{"N":106324796443231372795329965451792784374908475257731042677987977989945962496419819543299936408371285042498791020833780363910141715665590232533252599354509160780458961503863367842703504977430864504358617442294691508603803037645994752383061089701523494391193738887906210739432038880652477581768063943643214298049,"E":65537,"D":52882540623824249319263554234503221073355763301661673056925036705376788585582196893867658378736750343245656531655368795367730890395281737333932003731626103306294071690361237344309695692052986927494790956908776032726936870574424804180862906949851814015510618834696423905205181829311680766288721499332239092113,"Primes":[10562771257917076828400600569279483678021278216385409474099349073602122852652613259317666843104807170827922546052248527778489213047126675685744594423055011,10065994410656021893110220970838146088057898596082565348257922502730196228417367015775815130802667391440031211811041050535960601302390904626913561708368459],"Precomputed":{"Dp":14666710170902757089650955213153379231578136284710503412469914181268492295823547104657028590300707272919739257072411249032493376066779490782348262698903,"Dq":8351748051846008307669886865591879879827216596130210009260002655117828861809706712999156561217721929245207091771627754763620453429647494239789002112611857,"Qinv":5157808396374745421942830050538059633959311365944586097995200192447276074688521466971512517666145546534306106545362826255395595072097617674779280863162908,"CRTValues":[]}},"Onion":"cf3nb4kb4ekfep7t","Groups":{}}
|
|
@ -38,41 +38,26 @@ func TestProfileIdentity(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestProfileGroup(t *testing.T) {
|
||||
/**sarah := GenerateNewProfile("Sarah")
|
||||
sarah := GenerateNewProfile("Sarah")
|
||||
alice := GenerateNewProfile("Alice")
|
||||
sarah.AddContact("alice.onion", alice.PublicProfile)
|
||||
alice.AddContact("sarah.onion", sarah.PublicProfile)
|
||||
sarah.AddContact(alice.Onion, alice.PublicProfile)
|
||||
alice.AddContact(sarah.Onion, sarah.PublicProfile)
|
||||
|
||||
group := NewGroup("server.onion")
|
||||
alice.AddGroup(group)
|
||||
sarah.AddGroup(group)
|
||||
gid, invite := alice.StartGroup("aaa.onion")
|
||||
gci := &protocol.CwtchPeerPacket{}
|
||||
proto.Unmarshal(invite, gci)
|
||||
sarah.ProcessInvite(gci.GetGroupChatInvite(), alice.Onion)
|
||||
|
||||
group := alice.GetGroupByGroupId(gid)
|
||||
c, s := sarah.EncryptMessageToGroup("Hello World", group.GroupID)
|
||||
ok, gid, onion, message := alice.AttemptDecryption(c, s)
|
||||
alice.AttemptDecryption(c, s)
|
||||
|
||||
if ok && gid == group.GroupID && onion == "sarah.onion" && message == "Hello World" {
|
||||
t.Logf("Success!")
|
||||
} else {
|
||||
t.Errorf("Failed to decrypt group message %v %v %v %v", ok, gid, onion, message)
|
||||
}
|
||||
|
||||
group2 := NewGroup("server2.onion")
|
||||
sarah.AddGroup(group2)
|
||||
alice.AddGroup(group2)
|
||||
gid2, invite2 := alice.StartGroup("bbb.onion")
|
||||
gci2 := &protocol.CwtchPeerPacket{}
|
||||
proto.Unmarshal(invite2, gci2)
|
||||
sarah.ProcessInvite(gci2.GetGroupChatInvite(), alice.Onion)
|
||||
group2 := alice.GetGroupByGroupId(gid2)
|
||||
c2, _ := sarah.EncryptMessageToGroup("Hello World", group2.GroupID)
|
||||
ok, gid, onion, message = alice.AttemptDecryption(c2, s)
|
||||
if onion != "not-verified" {
|
||||
t.Errorf("verification should have failed %v %v %v %v", ok, gid, onion, message)
|
||||
}
|
||||
alice.AttemptDecryption(c2, s)
|
||||
|
||||
bob := GenerateNewProfile("Bob")
|
||||
bob.AddGroup(group)
|
||||
c, s = bob.EncryptMessageToGroup("Hello", group.GroupID)
|
||||
ok, gid, onion, message = alice.AttemptDecryption(c, s)
|
||||
|
||||
if ok && gid == group.GroupID && onion == "not-verified" && message == "Hello" {
|
||||
t.Logf("Success!")
|
||||
} else {
|
||||
t.Errorf("Failed to decrypt unverified group message %v %v %v %v", ok, gid, onion, message)
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -2,21 +2,22 @@ package connections
|
|||
|
||||
import (
|
||||
"git.mascherari.press/cwtch/model"
|
||||
"time"
|
||||
"git.mascherari.press/cwtch/protocol"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
peerConnections map[string]*PeerPeerConnection
|
||||
serverConnections map[string]*PeerServerConnection
|
||||
lock sync.Mutex
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func NewConnectionsManager() *Manager {
|
||||
m := new(Manager)
|
||||
m.peerConnections = make(map[string]*PeerPeerConnection)
|
||||
m.serverConnections = make(map[string]*PeerServerConnection)
|
||||
return m;
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Manager) ManagePeerConnection(host string, profile *model.Profile) {
|
||||
|
@ -28,17 +29,18 @@ func (m *Manager) ManagePeerConnection(host string, profile *model.Profile) {
|
|||
|
||||
}
|
||||
|
||||
func (m *Manager) ManageServerConnection(host string) {
|
||||
func (m *Manager) ManageServerConnection(host string, handler func(string, *protocol.GroupMessage)) {
|
||||
m.lock.Lock()
|
||||
psc := NewPeerServerConnection(host)
|
||||
go psc.Run()
|
||||
psc.GroupMessageHandler = handler
|
||||
m.serverConnections[host] = psc
|
||||
m.lock.Unlock()
|
||||
}
|
||||
|
||||
func (m *Manager) GetPeerPeerConnectionForOnion(host string) (ppc *PeerPeerConnection) {
|
||||
m.lock.Lock()
|
||||
ppc = m.peerConnections[host]
|
||||
ppc = m.peerConnections[host]
|
||||
m.lock.Unlock()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package connections
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.mascherari.press/cwtch/peer/fetch"
|
||||
"git.mascherari.press/cwtch/peer/listen"
|
||||
"git.mascherari.press/cwtch/peer/send"
|
||||
|
@ -10,6 +11,7 @@ import (
|
|||
"github.com/s-rah/go-ricochet/connection"
|
||||
"github.com/s-rah/go-ricochet/identity"
|
||||
"github.com/s-rah/go-ricochet/utils"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -36,6 +38,7 @@ func (psc *PeerServerConnection) GetState() ConnectionState {
|
|||
|
||||
// Run manages the setup and teardown of a peer server connection
|
||||
func (psc *PeerServerConnection) Run() error {
|
||||
log.Printf("Connecting to %v", psc.Server)
|
||||
rc, err := goricochet.Open(psc.Server)
|
||||
if err == nil {
|
||||
rc.TraceLog(true)
|
||||
|
@ -58,7 +61,6 @@ func (psc *PeerServerConnection) Run() error {
|
|||
return nil
|
||||
})
|
||||
}()
|
||||
|
||||
psc.connection.Process(psc)
|
||||
}
|
||||
}
|
||||
|
@ -73,25 +75,42 @@ func (psc *PeerServerConnection) Break() error {
|
|||
}
|
||||
|
||||
func (psc *PeerServerConnection) SendGroupMessage(gm *protocol.GroupMessage) {
|
||||
for psc.state != AUTHENTICATED {
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
log.Printf("Opening a Channel to Send")
|
||||
psc.connection.Do(func() error {
|
||||
psc.connection.RequestOpenChannel("im.cwtch.server.send", &send.CwtchPeerSendChannel{})
|
||||
return nil
|
||||
})
|
||||
log.Printf("Waiting...")
|
||||
// TODO We have to wait to receive the channel result before we can continue
|
||||
// We should have a better mechanism for this kindof interaction
|
||||
time.Sleep(time.Second * 1)
|
||||
psc.connection.Do(func() error {
|
||||
log.Printf("CWTCH PEER Sending...")
|
||||
send:
|
||||
time.Sleep(time.Second * 2)
|
||||
err := psc.connection.Do(func() error {
|
||||
channel := psc.connection.Channel("im.cwtch.server.send", channels.Outbound)
|
||||
if channel != nil {
|
||||
sendchannel, ok := channel.Handler.(*send.CwtchPeerSendChannel)
|
||||
if ok {
|
||||
sendchannel.SendGroupMessage(gm)
|
||||
}
|
||||
if channel == nil {
|
||||
return errors.New("No Channel")
|
||||
}
|
||||
sendchannel, ok := channel.Handler.(*send.CwtchPeerSendChannel)
|
||||
if ok {
|
||||
sendchannel.SendGroupMessage(gm)
|
||||
} else {
|
||||
return errors.New("Failed")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
for err != nil {
|
||||
log.Printf("CHANNEL ERROR %v", err)
|
||||
goto send
|
||||
}
|
||||
|
||||
log.Printf("Done")
|
||||
}
|
||||
|
||||
func (psc *PeerServerConnection) HandleGroupMessage(gm *protocol.GroupMessage) {
|
||||
log.Printf("Received Group Message: %v", gm)
|
||||
psc.GroupMessageHandler(psc.Server, gm)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package peer
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"git.mascherari.press/cwtch/model"
|
||||
"git.mascherari.press/cwtch/peer/connections"
|
||||
"git.mascherari.press/cwtch/peer/peer"
|
||||
|
@ -11,7 +12,6 @@ import (
|
|||
"github.com/s-rah/go-ricochet/connection"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
"errors"
|
||||
)
|
||||
|
||||
/**
|
||||
|
@ -24,12 +24,11 @@ Move CwtchPeerChannel under peer/
|
|||
Write tests for Peer Channel
|
||||
*/
|
||||
|
||||
|
||||
type CwtchPeer struct {
|
||||
connection.AutoConnectionHandler
|
||||
Profile *model.Profile
|
||||
mutex sync.Mutex
|
||||
Log chan string `json:"-"`
|
||||
Profile *model.Profile
|
||||
mutex sync.Mutex
|
||||
Log chan string `json:"-"`
|
||||
connectionsManager *connections.Manager
|
||||
}
|
||||
|
||||
|
@ -64,8 +63,8 @@ func (cp *CwtchPeer) PeerWithOnion(onion string) {
|
|||
|
||||
// InviteOnionToGroup kicks off the invite process
|
||||
func (cp *CwtchPeer) InviteOnionToGroup(onion string, groupid string) error {
|
||||
group:= cp.Profile.GetGroupByGroupId(groupid)
|
||||
if group == nil {
|
||||
group := cp.Profile.GetGroupByGroupId(groupid)
|
||||
if group == nil {
|
||||
invite := group.Invite()
|
||||
ppc := cp.connectionsManager.GetPeerPeerConnectionForOnion(onion)
|
||||
ppc.SendGroupInvite(invite)
|
||||
|
@ -73,15 +72,22 @@ func (cp *CwtchPeer) InviteOnionToGroup(onion string, groupid string) error {
|
|||
return errors.New("group id could not be found")
|
||||
}
|
||||
|
||||
func (cp *CwtchPeer) ReceiveGroupMessage(server string, gm *protocol.GroupMessage) {
|
||||
cp.Profile.AttemptDecryption(gm.Ciphertext)
|
||||
}
|
||||
|
||||
func (cp *CwtchPeer) JoinServer(onion string) {
|
||||
cp.connectionsManager.ManageServerConnection(onion)
|
||||
cp.connectionsManager.ManageServerConnection(onion, cp.ReceiveGroupMessage)
|
||||
}
|
||||
|
||||
func (cp *CwtchPeer) SendMessageToGroup(groupid string, message string) {
|
||||
// Lookup Group
|
||||
// Lookup Sever Connection
|
||||
// If no server connection, spin off server connection
|
||||
// Else group.EncryptMessage(message) and send result to server
|
||||
group := cp.Profile.GetGroupByGroupId(groupid)
|
||||
psc := cp.connectionsManager.GetPeerServerConnectionForOnion(group.GroupServer)
|
||||
ct, _ := cp.Profile.EncryptMessageToGroup(message, groupid)
|
||||
gm := &protocol.GroupMessage{
|
||||
Ciphertext: ct,
|
||||
}
|
||||
psc.SendGroupMessage(gm)
|
||||
}
|
||||
|
||||
func (cp *CwtchPeer) Listen() error {
|
||||
|
@ -110,7 +116,6 @@ func (cp *CwtchPeer) Listen() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
|
||||
type CwtchPeerInstance struct {
|
||||
rai *application.ApplicationInstance
|
||||
ra *application.RicochetApplication
|
||||
|
@ -121,7 +126,6 @@ func (cpi *CwtchPeerInstance) Init(rai *application.ApplicationInstance, ra *app
|
|||
cpi.ra = ra
|
||||
}
|
||||
|
||||
|
||||
type CwtchPeerHandler struct {
|
||||
Onion string
|
||||
Peer *CwtchPeer
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package peer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCwtchPeerIntegration(t *testing.T) {
|
||||
alice := NewCwtchPeer("Alice")
|
||||
id, _ := alice.Profile.StartGroup("ylhbhtypevo4ympq")
|
||||
alice.Profile.AddContact(alice.Profile.Onion, alice.Profile.PublicProfile)
|
||||
alice.JoinServer("ylhbhtypevo4ympq")
|
||||
// time.Sleep(time.Second *5)
|
||||
alice.SendMessageToGroup(id, "Hello")
|
||||
alice.SendMessageToGroup(id, "My")
|
||||
alice.SendMessageToGroup(id, "Name Is")
|
||||
alice.SendMessageToGroup(id, "ALICE!!!")
|
||||
time.Sleep(time.Second * 5)
|
||||
group := alice.Profile.Groups[id]
|
||||
t.Logf("%v", group.Timeline)
|
||||
}
|
|
@ -81,6 +81,7 @@ func (cplc *CwtchPeerSendChannel) SendGroupMessage(gm *protocol.GroupMessage) {
|
|||
}
|
||||
packet, _ := proto.Marshal(csp)
|
||||
cplc.channel.SendMessage(packet)
|
||||
cplc.channel.CloseChannel()
|
||||
}
|
||||
|
||||
// Packet should never be
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: ControlChannel.proto
|
||||
|
||||
/*
|
||||
Package protocol is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
ControlChannel.proto
|
||||
cwtch-profile.proto
|
||||
group_message.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Packet
|
||||
OpenChannel
|
||||
ChannelResult
|
||||
KeepAlive
|
||||
EnableFeatures
|
||||
FeaturesEnabled
|
||||
CwtchPeerPacket
|
||||
CwtchIdentity
|
||||
GroupChatInvite
|
||||
CwtchServerPacket
|
||||
FetchMessage
|
||||
GroupMessage
|
||||
DecryptedGroupMessage
|
||||
*/
|
||||
package protocol
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type ChannelResult_CommonError int32
|
||||
|
||||
const (
|
||||
ChannelResult_GenericError ChannelResult_CommonError = 0
|
||||
ChannelResult_UnknownTypeError ChannelResult_CommonError = 1
|
||||
ChannelResult_UnauthorizedError ChannelResult_CommonError = 2
|
||||
ChannelResult_BadUsageError ChannelResult_CommonError = 3
|
||||
ChannelResult_FailedError ChannelResult_CommonError = 4
|
||||
)
|
||||
|
||||
var ChannelResult_CommonError_name = map[int32]string{
|
||||
0: "GenericError",
|
||||
1: "UnknownTypeError",
|
||||
2: "UnauthorizedError",
|
||||
3: "BadUsageError",
|
||||
4: "FailedError",
|
||||
}
|
||||
var ChannelResult_CommonError_value = map[string]int32{
|
||||
"GenericError": 0,
|
||||
"UnknownTypeError": 1,
|
||||
"UnauthorizedError": 2,
|
||||
"BadUsageError": 3,
|
||||
"FailedError": 4,
|
||||
}
|
||||
|
||||
func (x ChannelResult_CommonError) Enum() *ChannelResult_CommonError {
|
||||
p := new(ChannelResult_CommonError)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
func (x ChannelResult_CommonError) String() string {
|
||||
return proto.EnumName(ChannelResult_CommonError_name, int32(x))
|
||||
}
|
||||
func (x *ChannelResult_CommonError) UnmarshalJSON(data []byte) error {
|
||||
value, err := proto.UnmarshalJSONEnum(ChannelResult_CommonError_value, data, "ChannelResult_CommonError")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = ChannelResult_CommonError(value)
|
||||
return nil
|
||||
}
|
||||
func (ChannelResult_CommonError) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 0} }
|
||||
|
||||
type Packet struct {
|
||||
// Must contain exactly one field
|
||||
OpenChannel *OpenChannel `protobuf:"bytes,1,opt,name=open_channel,json=openChannel" json:"open_channel,omitempty"`
|
||||
ChannelResult *ChannelResult `protobuf:"bytes,2,opt,name=channel_result,json=channelResult" json:"channel_result,omitempty"`
|
||||
KeepAlive *KeepAlive `protobuf:"bytes,3,opt,name=keep_alive,json=keepAlive" json:"keep_alive,omitempty"`
|
||||
EnableFeatures *EnableFeatures `protobuf:"bytes,4,opt,name=enable_features,json=enableFeatures" json:"enable_features,omitempty"`
|
||||
FeaturesEnabled *FeaturesEnabled `protobuf:"bytes,5,opt,name=features_enabled,json=featuresEnabled" json:"features_enabled,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Packet) Reset() { *m = Packet{} }
|
||||
func (m *Packet) String() string { return proto.CompactTextString(m) }
|
||||
func (*Packet) ProtoMessage() {}
|
||||
func (*Packet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func (m *Packet) GetOpenChannel() *OpenChannel {
|
||||
if m != nil {
|
||||
return m.OpenChannel
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Packet) GetChannelResult() *ChannelResult {
|
||||
if m != nil {
|
||||
return m.ChannelResult
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Packet) GetKeepAlive() *KeepAlive {
|
||||
if m != nil {
|
||||
return m.KeepAlive
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Packet) GetEnableFeatures() *EnableFeatures {
|
||||
if m != nil {
|
||||
return m.EnableFeatures
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Packet) GetFeaturesEnabled() *FeaturesEnabled {
|
||||
if m != nil {
|
||||
return m.FeaturesEnabled
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type OpenChannel struct {
|
||||
ChannelIdentifier *int32 `protobuf:"varint,1,req,name=channel_identifier,json=channelIdentifier" json:"channel_identifier,omitempty"`
|
||||
ChannelType *string `protobuf:"bytes,2,req,name=channel_type,json=channelType" json:"channel_type,omitempty"`
|
||||
proto.XXX_InternalExtensions `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *OpenChannel) Reset() { *m = OpenChannel{} }
|
||||
func (m *OpenChannel) String() string { return proto.CompactTextString(m) }
|
||||
func (*OpenChannel) ProtoMessage() {}
|
||||
func (*OpenChannel) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
|
||||
var extRange_OpenChannel = []proto.ExtensionRange{
|
||||
{100, 536870911},
|
||||
}
|
||||
|
||||
func (*OpenChannel) ExtensionRangeArray() []proto.ExtensionRange {
|
||||
return extRange_OpenChannel
|
||||
}
|
||||
|
||||
func (m *OpenChannel) GetChannelIdentifier() int32 {
|
||||
if m != nil && m.ChannelIdentifier != nil {
|
||||
return *m.ChannelIdentifier
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *OpenChannel) GetChannelType() string {
|
||||
if m != nil && m.ChannelType != nil {
|
||||
return *m.ChannelType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ChannelResult struct {
|
||||
ChannelIdentifier *int32 `protobuf:"varint,1,req,name=channel_identifier,json=channelIdentifier" json:"channel_identifier,omitempty"`
|
||||
Opened *bool `protobuf:"varint,2,req,name=opened" json:"opened,omitempty"`
|
||||
CommonError *ChannelResult_CommonError `protobuf:"varint,3,opt,name=common_error,json=commonError,enum=protocol.ChannelResult_CommonError" json:"common_error,omitempty"`
|
||||
proto.XXX_InternalExtensions `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ChannelResult) Reset() { *m = ChannelResult{} }
|
||||
func (m *ChannelResult) String() string { return proto.CompactTextString(m) }
|
||||
func (*ChannelResult) ProtoMessage() {}
|
||||
func (*ChannelResult) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||
|
||||
var extRange_ChannelResult = []proto.ExtensionRange{
|
||||
{100, 536870911},
|
||||
}
|
||||
|
||||
func (*ChannelResult) ExtensionRangeArray() []proto.ExtensionRange {
|
||||
return extRange_ChannelResult
|
||||
}
|
||||
|
||||
func (m *ChannelResult) GetChannelIdentifier() int32 {
|
||||
if m != nil && m.ChannelIdentifier != nil {
|
||||
return *m.ChannelIdentifier
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *ChannelResult) GetOpened() bool {
|
||||
if m != nil && m.Opened != nil {
|
||||
return *m.Opened
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *ChannelResult) GetCommonError() ChannelResult_CommonError {
|
||||
if m != nil && m.CommonError != nil {
|
||||
return *m.CommonError
|
||||
}
|
||||
return ChannelResult_GenericError
|
||||
}
|
||||
|
||||
type KeepAlive struct {
|
||||
ResponseRequested *bool `protobuf:"varint,1,req,name=response_requested,json=responseRequested" json:"response_requested,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *KeepAlive) Reset() { *m = KeepAlive{} }
|
||||
func (m *KeepAlive) String() string { return proto.CompactTextString(m) }
|
||||
func (*KeepAlive) ProtoMessage() {}
|
||||
func (*KeepAlive) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||
|
||||
func (m *KeepAlive) GetResponseRequested() bool {
|
||||
if m != nil && m.ResponseRequested != nil {
|
||||
return *m.ResponseRequested
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EnableFeatures struct {
|
||||
Feature []string `protobuf:"bytes,1,rep,name=feature" json:"feature,omitempty"`
|
||||
proto.XXX_InternalExtensions `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *EnableFeatures) Reset() { *m = EnableFeatures{} }
|
||||
func (m *EnableFeatures) String() string { return proto.CompactTextString(m) }
|
||||
func (*EnableFeatures) ProtoMessage() {}
|
||||
func (*EnableFeatures) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
|
||||
|
||||
var extRange_EnableFeatures = []proto.ExtensionRange{
|
||||
{100, 536870911},
|
||||
}
|
||||
|
||||
func (*EnableFeatures) ExtensionRangeArray() []proto.ExtensionRange {
|
||||
return extRange_EnableFeatures
|
||||
}
|
||||
|
||||
func (m *EnableFeatures) GetFeature() []string {
|
||||
if m != nil {
|
||||
return m.Feature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type FeaturesEnabled struct {
|
||||
Feature []string `protobuf:"bytes,1,rep,name=feature" json:"feature,omitempty"`
|
||||
proto.XXX_InternalExtensions `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *FeaturesEnabled) Reset() { *m = FeaturesEnabled{} }
|
||||
func (m *FeaturesEnabled) String() string { return proto.CompactTextString(m) }
|
||||
func (*FeaturesEnabled) ProtoMessage() {}
|
||||
func (*FeaturesEnabled) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
|
||||
|
||||
var extRange_FeaturesEnabled = []proto.ExtensionRange{
|
||||
{100, 536870911},
|
||||
}
|
||||
|
||||
func (*FeaturesEnabled) ExtensionRangeArray() []proto.ExtensionRange {
|
||||
return extRange_FeaturesEnabled
|
||||
}
|
||||
|
||||
func (m *FeaturesEnabled) GetFeature() []string {
|
||||
if m != nil {
|
||||
return m.Feature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Packet)(nil), "protocol.Packet")
|
||||
proto.RegisterType((*OpenChannel)(nil), "protocol.OpenChannel")
|
||||
proto.RegisterType((*ChannelResult)(nil), "protocol.ChannelResult")
|
||||
proto.RegisterType((*KeepAlive)(nil), "protocol.KeepAlive")
|
||||
proto.RegisterType((*EnableFeatures)(nil), "protocol.EnableFeatures")
|
||||
proto.RegisterType((*FeaturesEnabled)(nil), "protocol.FeaturesEnabled")
|
||||
proto.RegisterEnum("protocol.ChannelResult_CommonError", ChannelResult_CommonError_name, ChannelResult_CommonError_value)
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("ControlChannel.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 461 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x52, 0x4d, 0x8f, 0xd3, 0x30,
|
||||
0x10, 0x25, 0xe9, 0xee, 0x92, 0x4e, 0xfa, 0x91, 0x9a, 0x5d, 0x30, 0xb7, 0x12, 0x2e, 0x15, 0x12,
|
||||
0x3d, 0x54, 0x20, 0x21, 0x0e, 0x48, 0x4b, 0xd9, 0x22, 0xc4, 0x01, 0x64, 0xd1, 0x73, 0x64, 0x92,
|
||||
0x29, 0x1b, 0x35, 0x6b, 0x1b, 0xc7, 0x05, 0x2d, 0xa7, 0xfe, 0x0e, 0xfe, 0x0c, 0x7f, 0x0d, 0xc5,
|
||||
0x89, 0x9b, 0x14, 0x09, 0x09, 0x4e, 0xc9, 0x9b, 0xf7, 0xde, 0x8c, 0xfc, 0x66, 0xe0, 0x7c, 0x29,
|
||||
0x85, 0xd1, 0xb2, 0x58, 0x5e, 0x73, 0x21, 0xb0, 0x98, 0x2b, 0x2d, 0x8d, 0x24, 0x81, 0xfd, 0xa4,
|
||||
0xb2, 0x88, 0x7f, 0xf9, 0x70, 0xf6, 0x91, 0xa7, 0x5b, 0x34, 0xe4, 0x05, 0x0c, 0xa4, 0x42, 0x91,
|
||||
0xa4, 0xb5, 0x94, 0x7a, 0x53, 0x6f, 0x16, 0x2e, 0x2e, 0xe6, 0x4e, 0x3b, 0xff, 0xa0, 0x50, 0x34,
|
||||
0x7d, 0x58, 0x28, 0x5b, 0x40, 0x5e, 0xc1, 0xa8, 0x31, 0x25, 0x1a, 0xcb, 0x5d, 0x61, 0xa8, 0x6f,
|
||||
0xbd, 0x0f, 0x5a, 0xaf, 0xf3, 0x59, 0x9a, 0x0d, 0xd3, 0x2e, 0x24, 0x0b, 0x80, 0x2d, 0xa2, 0x4a,
|
||||
0x78, 0x91, 0x7f, 0x43, 0xda, 0xb3, 0xde, 0x7b, 0xad, 0xf7, 0x3d, 0xa2, 0xba, 0xac, 0x28, 0xd6,
|
||||
0xdf, 0xba, 0x5f, 0x72, 0x09, 0x63, 0x14, 0xfc, 0x73, 0x81, 0xc9, 0x06, 0xb9, 0xd9, 0x69, 0x2c,
|
||||
0xe9, 0x89, 0x35, 0xd2, 0xd6, 0x78, 0x65, 0x05, 0xab, 0x86, 0x67, 0x23, 0x3c, 0xc2, 0xe4, 0x0d,
|
||||
0x44, 0xce, 0x9b, 0xd4, 0x54, 0x46, 0x4f, 0x6d, 0x8f, 0x87, 0x6d, 0x0f, 0xa7, 0xae, 0x7b, 0x65,
|
||||
0x6c, 0xbc, 0x39, 0x2e, 0xc4, 0x39, 0x84, 0x9d, 0x60, 0xc8, 0x53, 0x20, 0x2e, 0x8b, 0x3c, 0x43,
|
||||
0x61, 0xf2, 0x4d, 0x8e, 0x9a, 0x7a, 0x53, 0x7f, 0x76, 0xca, 0x26, 0x0d, 0xf3, 0xee, 0x40, 0x90,
|
||||
0x47, 0x30, 0x70, 0x72, 0x73, 0xab, 0x90, 0xfa, 0x53, 0x7f, 0xd6, 0x67, 0x61, 0x53, 0xfb, 0x74,
|
||||
0xab, 0xf0, 0x49, 0x10, 0x64, 0xd1, 0x7e, 0xbf, 0xdf, 0xfb, 0xf1, 0x4f, 0x1f, 0x86, 0x47, 0x41,
|
||||
0xfe, 0xef, 0xb4, 0xfb, 0x70, 0x56, 0xed, 0x0d, 0x33, 0x3b, 0x27, 0x60, 0x0d, 0x22, 0x2b, 0x18,
|
||||
0xa4, 0xf2, 0xe6, 0x46, 0x8a, 0x04, 0xb5, 0x96, 0xda, 0xae, 0x60, 0xb4, 0x78, 0xfc, 0x97, 0xf5,
|
||||
0xcd, 0x97, 0x56, 0x7b, 0x55, 0x49, 0x59, 0x98, 0xb6, 0x20, 0x56, 0x10, 0x76, 0x38, 0x12, 0xc1,
|
||||
0xe0, 0x2d, 0x0a, 0xd4, 0x79, 0x6a, 0x71, 0x74, 0x87, 0x9c, 0x43, 0xb4, 0x16, 0x5b, 0x21, 0xbf,
|
||||
0x8b, 0xea, 0x69, 0x75, 0xd5, 0x23, 0x17, 0x30, 0x59, 0x0b, 0xbe, 0x33, 0xd7, 0x52, 0xe7, 0x3f,
|
||||
0x30, 0xab, 0xcb, 0x3e, 0x99, 0xc0, 0xf0, 0x35, 0xcf, 0xd6, 0x25, 0xff, 0xd2, 0x28, 0x7b, 0x64,
|
||||
0x0c, 0xe1, 0x8a, 0xe7, 0x85, 0xd3, 0x9c, 0x74, 0xc2, 0x79, 0x09, 0xfd, 0xc3, 0xa1, 0x54, 0xb9,
|
||||
0x68, 0x2c, 0x95, 0x14, 0x25, 0x26, 0x1a, 0xbf, 0xee, 0xb0, 0x34, 0x98, 0xd9, 0x5c, 0x02, 0x36,
|
||||
0x71, 0x0c, 0x73, 0x44, 0xfc, 0x0c, 0x46, 0xc7, 0xb7, 0x42, 0x28, 0xdc, 0x6d, 0x16, 0x4d, 0xbd,
|
||||
0x69, 0x6f, 0xd6, 0x67, 0x0e, 0x76, 0x26, 0x3e, 0x87, 0xf1, 0x1f, 0xd7, 0xf1, 0x2f, 0xb6, 0xdf,
|
||||
0x01, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x32, 0x16, 0x1e, 0x93, 0x03, 0x00, 0x00,
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
syntax = "proto2";
|
||||
package protocol;
|
||||
|
||||
message Packet {
|
||||
// Must contain exactly one field
|
||||
optional OpenChannel open_channel = 1;
|
||||
optional ChannelResult channel_result = 2;
|
||||
optional KeepAlive keep_alive = 3;
|
||||
optional EnableFeatures enable_features = 4;
|
||||
optional FeaturesEnabled features_enabled = 5;
|
||||
}
|
||||
|
||||
message OpenChannel {
|
||||
required int32 channel_identifier = 1; // Arbitrary unique identifier for this channel instance
|
||||
required string channel_type = 2; // String identifying channel type; e.g. im.ricochet.chat
|
||||
|
||||
// It is valid to extend the OpenChannel message to add fields specific
|
||||
// to the requested channel_type.
|
||||
extensions 100 to max;
|
||||
}
|
||||
|
||||
message ChannelResult {
|
||||
required int32 channel_identifier = 1; // Matching the value from OpenChannel
|
||||
required bool opened = 2; // If the channel is now open
|
||||
|
||||
enum CommonError {
|
||||
GenericError = 0;
|
||||
UnknownTypeError = 1;
|
||||
UnauthorizedError = 2;
|
||||
BadUsageError = 3;
|
||||
FailedError = 4;
|
||||
}
|
||||
|
||||
optional CommonError common_error = 3;
|
||||
|
||||
// As with OpenChannel, it is valid to extend this message with fields specific
|
||||
// to the channel type.
|
||||
extensions 100 to max;
|
||||
}
|
||||
|
||||
message KeepAlive {
|
||||
required bool response_requested = 1;
|
||||
}
|
||||
|
||||
message EnableFeatures {
|
||||
repeated string feature = 1;
|
||||
extensions 100 to max;
|
||||
}
|
||||
|
||||
message FeaturesEnabled {
|
||||
repeated string feature = 1;
|
||||
extensions 100 to max;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
cwtchserver "git.mascherari.press/cwtch/server"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
server := new(cwtchserver.Server)
|
||||
log.Printf("starting cwtch server...")
|
||||
|
||||
server.Run("./private_key")
|
||||
}
|
|
@ -64,5 +64,6 @@ func (s *Server) Run(privateKeyFile string) {
|
|||
})
|
||||
|
||||
cwtchserver.Init(pk, af, new(application.AcceptAllContactManager))
|
||||
log.Printf("cwtch server running on cwtch:%s", l.Addr().String()[0:16])
|
||||
cwtchserver.Run(l)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/s-rah/go-ricochet/application"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestServerInstance(t *testing.T) {
|
||||
|
@ -27,4 +28,9 @@ func TestServerInstance(t *testing.T) {
|
|||
if len(res) != 1 {
|
||||
t.Errorf("Expected Group Messages Instead got %v", res)
|
||||
}
|
||||
|
||||
// ra.HandleApplicationInstance(ai)
|
||||
si.HandleGroupMessage(&gm)
|
||||
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue