forked from cwtch.im/cwtch
Adding V3 Onions to Cwtch!
This commit is contained in:
parent
8ab4752b44
commit
42e8bae945
|
@ -5,3 +5,7 @@
|
||||||
*.test
|
*.test
|
||||||
*/*test_*
|
*/*test_*
|
||||||
*/*_test*
|
*/*_test*
|
||||||
|
*.json
|
||||||
|
*/messages/*
|
||||||
|
server/app/messages
|
||||||
|
.reviewboardrc
|
||||||
|
|
|
@ -365,6 +365,8 @@ func main() {
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("\nError loading profiles: %v\n", err)
|
fmt.Printf("\nError loading profiles: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case "/list-profiles":
|
case "/list-profiles":
|
||||||
peerlist := app.ListPeers()
|
peerlist := app.ListPeers()
|
||||||
for onion, peername := range peerlist {
|
for onion, peername := range peerlist {
|
||||||
|
@ -380,6 +382,24 @@ func main() {
|
||||||
peer = p
|
peer = p
|
||||||
suggestions = append(suggestionsBase, suggestionsSelectedProfile...)
|
suggestions = append(suggestionsBase, suggestionsSelectedProfile...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto Peer / Join Server
|
||||||
|
// TODO There are some privacy implications with this that we should
|
||||||
|
// think over.
|
||||||
|
for _,name := range p.GetProfile().GetContacts() {
|
||||||
|
profile := p.GetContact(name)
|
||||||
|
if profile.Trusted && !profile.Blocked {
|
||||||
|
p.PeerWithOnion(profile.Onion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, groupid := range p.GetGroups() {
|
||||||
|
group := p.GetGroup(groupid)
|
||||||
|
if group.Accepted || group.Owner == "self" {
|
||||||
|
p.JoinServer(group.GroupServer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Error selecting profile, usage: %s\n", usages[commands[0]])
|
fmt.Printf("Error selecting profile, usage: %s\n", usages[commands[0]])
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ func main() {
|
||||||
counter++
|
counter++
|
||||||
return []byte(strconv.Itoa(counter))
|
return []byte(strconv.Itoa(counter))
|
||||||
})
|
})
|
||||||
connection := bob.PeerWithOnion("qtpnmnth767gjmpv")
|
connection := bob.PeerWithOnion("f4b6thuwmfszsqd3fzqpr45sdem4qoazdlzr2xmnc7fq22qe746hjqqd")
|
||||||
|
|
||||||
log.Printf("Waiting for Bob to Connect to Alice...")
|
log.Printf("Waiting for Bob to Connect to Alice...")
|
||||||
connection.SendPacket([]byte("Hello Alice!!!"))
|
connection.SendPacket([]byte("Hello Alice!!!"))
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//Group defines and encapsulates Cwtch's conception of group chat. Which are sessions
|
// Group defines and encapsulates Cwtch's conception of group chat. Which are sessions
|
||||||
// tied to a server under a given group key. Each group has a set of messages.
|
// tied to a server under a given group key. Each group has a set of messages.
|
||||||
type Group struct {
|
type Group struct {
|
||||||
GroupID string
|
GroupID string
|
||||||
|
@ -27,6 +27,7 @@ type Group struct {
|
||||||
IsCompromised bool
|
IsCompromised bool
|
||||||
InitialMessage []byte
|
InitialMessage []byte
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
|
NewMessage chan Message `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGroup initializes a new group associated with a given CwtchServer
|
// NewGroup initializes a new group associated with a given CwtchServer
|
||||||
|
@ -94,19 +95,23 @@ func (g *Group) Invite(initialMessage []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddMessage takes a DecryptedGroupMessage and adds it to the Groups Timeline
|
// AddMessage takes a DecryptedGroupMessage and adds it to the Groups Timeline
|
||||||
func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, sig []byte, verified bool) *Message {
|
func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, sig []byte) *Message {
|
||||||
g.lock.Lock()
|
g.lock.Lock()
|
||||||
timelineMessage := &Message{
|
timelineMessage := &Message{
|
||||||
Message: message.GetText(),
|
Message: message.GetText(),
|
||||||
Timestamp: time.Unix(int64(message.GetTimestamp()), 0),
|
Timestamp: time.Unix(int64(message.GetTimestamp()), 0),
|
||||||
Received: time.Now(),
|
Received: time.Now(),
|
||||||
Signature: sig,
|
Signature: sig,
|
||||||
Verified: verified,
|
|
||||||
PeerID: message.GetOnion(),
|
PeerID: message.GetOnion(),
|
||||||
PreviousMessageSig: message.GetPreviousMessageSig(),
|
PreviousMessageSig: message.GetPreviousMessageSig(),
|
||||||
}
|
}
|
||||||
g.Timeline.Insert(timelineMessage)
|
seen := g.Timeline.Insert(timelineMessage)
|
||||||
g.lock.Unlock()
|
g.lock.Unlock()
|
||||||
|
|
||||||
|
// Send a new Message notification if we have an app that is listening.
|
||||||
|
if g.NewMessage != nil && !seen {
|
||||||
|
g.NewMessage <- *timelineMessage
|
||||||
|
}
|
||||||
return timelineMessage
|
return timelineMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ type Message struct {
|
||||||
PeerID string
|
PeerID string
|
||||||
Message string
|
Message string
|
||||||
Signature []byte
|
Signature []byte
|
||||||
Verified bool
|
|
||||||
PreviousMessageSig []byte
|
PreviousMessageSig []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,17 +74,18 @@ func (t *Timeline) Less(i, j int) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert inserts a message into the timeline in a thread safe way.
|
// Insert inserts a message into the timeline in a thread safe way.
|
||||||
func (t *Timeline) Insert(mi *Message) {
|
func (t *Timeline) Insert(mi *Message) bool {
|
||||||
t.lock.Lock()
|
t.lock.Lock()
|
||||||
defer t.lock.Unlock()
|
defer t.lock.Unlock()
|
||||||
|
|
||||||
for _, m := range t.Messages {
|
for _, m := range t.Messages {
|
||||||
// If the message already exists, then we don't add it
|
// If the message already exists, then we don't add it
|
||||||
if compareSignatures(m.Signature, mi.Signature) {
|
if compareSignatures(m.Signature, mi.Signature) {
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Messages = append(t.Messages, *mi)
|
t.Messages = append(t.Messages, *mi)
|
||||||
sort.Sort(t)
|
sort.Sort(t)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,14 @@ package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
|
||||||
"cwtch.im/cwtch/protocol"
|
"cwtch.im/cwtch/protocol"
|
||||||
"encoding/asn1"
|
"encoding/base32"
|
||||||
"errors"
|
"errors"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -28,7 +28,6 @@ type Profile struct {
|
||||||
PublicProfile
|
PublicProfile
|
||||||
Contacts map[string]*PublicProfile
|
Contacts map[string]*PublicProfile
|
||||||
Ed25519PrivateKey ed25519.PrivateKey
|
Ed25519PrivateKey ed25519.PrivateKey
|
||||||
OnionPrivateKey *rsa.PrivateKey
|
|
||||||
Groups map[string]*Group
|
Groups map[string]*Group
|
||||||
Custom map[string]string
|
Custom map[string]string
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
|
@ -41,14 +40,7 @@ func GenerateNewProfile(name string) *Profile {
|
||||||
pub, priv, _ := ed25519.GenerateKey(rand.Reader)
|
pub, priv, _ := ed25519.GenerateKey(rand.Reader)
|
||||||
p.Ed25519PublicKey = pub
|
p.Ed25519PublicKey = pub
|
||||||
p.Ed25519PrivateKey = priv
|
p.Ed25519PrivateKey = priv
|
||||||
|
p.Onion = utils.GetTorV3Hostname(pub)
|
||||||
p.OnionPrivateKey, _ = utils.GeneratePrivateKey()
|
|
||||||
// DER Encode the Public Key
|
|
||||||
publicKeyBytes, _ := asn1.Marshal(rsa.PublicKey{
|
|
||||||
N: p.OnionPrivateKey.PublicKey.N,
|
|
||||||
E: p.OnionPrivateKey.PublicKey.E,
|
|
||||||
})
|
|
||||||
p.Onion = utils.GetTorHostname(publicKeyBytes)
|
|
||||||
|
|
||||||
p.Contacts = make(map[string]*PublicProfile)
|
p.Contacts = make(map[string]*PublicProfile)
|
||||||
p.Contacts[p.Onion] = &p.PublicProfile
|
p.Contacts[p.Onion] = &p.PublicProfile
|
||||||
|
@ -199,10 +191,13 @@ func (p *Profile) VerifyGroupMessage(onion string, groupID string, message strin
|
||||||
return ed25519.Verify(p.Ed25519PublicKey, []byte(m), signature)
|
return ed25519.Verify(p.Ed25519PublicKey, []byte(m), signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
contact, found := p.GetContact(onion)
|
m := groupID + group.GroupServer + string(ciphertext)
|
||||||
if found {
|
decodedPub, err := base32.StdEncoding.DecodeString(strings.ToUpper(onion))
|
||||||
m := groupID + group.GroupServer + string(ciphertext)
|
if err == nil {
|
||||||
return ed25519.Verify(contact.Ed25519PublicKey, []byte(m), signature)
|
return ed25519.Verify(decodedPub[:32], []byte(m), signature)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -213,13 +208,13 @@ func (p *Profile) SignMessage(message string) []byte {
|
||||||
return sig
|
return sig
|
||||||
}
|
}
|
||||||
|
|
||||||
//StartGroup when given a server, creates a new Group under this profile and returns the group id an a precomputed
|
// StartGroup when given a server, creates a new Group under this profile and returns the group id an a precomputed
|
||||||
// invite which can be sent on the wire.
|
// invite which can be sent on the wire.
|
||||||
func (p *Profile) StartGroup(server string) (groupID string, invite []byte, err error) {
|
func (p *Profile) StartGroup(server string) (groupID string, invite []byte, err error) {
|
||||||
return p.StartGroupWithMessage(server, []byte{})
|
return p.StartGroupWithMessage(server, []byte{})
|
||||||
}
|
}
|
||||||
|
|
||||||
//StartGroupWithMessage when given a server, and an initial message creates a new Group under this profile and returns the group id an a precomputed
|
// StartGroupWithMessage when given a server, and an initial message creates a new Group under this profile and returns the group id an a precomputed
|
||||||
// invite which can be sent on the wire.
|
// invite which can be sent on the wire.
|
||||||
func (p *Profile) StartGroupWithMessage(server string, initialMessage []byte) (groupID string, invite []byte, err error) {
|
func (p *Profile) StartGroupWithMessage(server string, initialMessage []byte) (groupID string, invite []byte, err error) {
|
||||||
group, err := NewGroup(server)
|
group, err := NewGroup(server)
|
||||||
|
@ -300,8 +295,18 @@ func (p *Profile) AttemptDecryption(ciphertext []byte, signature []byte) (bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
verified := p.VerifyGroupMessage(dgm.GetOnion(), group.GroupID, dgm.GetText(), dgm.GetTimestamp(), ciphertext, signature)
|
verified := p.VerifyGroupMessage(dgm.GetOnion(), group.GroupID, dgm.GetText(), dgm.GetTimestamp(), ciphertext, signature)
|
||||||
return true, group.AddMessage(dgm, signature, verified)
|
|
||||||
|
// So we have a message that has a valid group key, but the signature can't be verified.
|
||||||
|
// The most obvious explanation for this is that the group key has been compromised (or we are in an open group and the server is being malicious)
|
||||||
|
// Either way, someone who has the private key is being detectably bad so we are just going to throw this message away and mark the group as Compromised.
|
||||||
|
if !verified {
|
||||||
|
group.Compromised()
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, group.AddMessage(dgm, signature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|
|
@ -133,8 +133,8 @@ func TestProfileGroup(t *testing.T) {
|
||||||
c3, s3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID)
|
c3, s3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ok, message := alice.AttemptDecryption(c3, s3)
|
ok, message := alice.AttemptDecryption(c3, s3)
|
||||||
if ok != true || message.Verified == true {
|
if !ok {
|
||||||
t.Errorf("Bobs message to the group should be decrypted but not verified by alice instead %v %v", message, ok)
|
t.Errorf("Bobs message to the group should be decrypted %v %v", message, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
eve := GenerateNewProfile("eve")
|
eve := GenerateNewProfile("eve")
|
||||||
|
|
|
@ -107,7 +107,7 @@ func (ppc *PeerPeerConnection) Run() error {
|
||||||
rc.TraceLog(false)
|
rc.TraceLog(false)
|
||||||
ppc.connection = rc
|
ppc.connection = rc
|
||||||
ppc.state = CONNECTED
|
ppc.state = CONNECTED
|
||||||
_, err := connection.HandleOutboundConnection(ppc.connection).ProcessAuthAsClient(identity.Initialize(ppc.profile.Name, ppc.profile.OnionPrivateKey))
|
_, err := connection.HandleOutboundConnection(ppc.connection).ProcessAuthAsV3Client(identity.InitializeV3(ppc.profile.Name, &ppc.profile.Ed25519PrivateKey, &ppc.profile.Ed25519PublicKey))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ppc.state = AUTHENTICATED
|
ppc.state = AUTHENTICATED
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package connections
|
package connections
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rsa"
|
"crypto/rand"
|
||||||
"cwtch.im/cwtch/model"
|
"cwtch.im/cwtch/model"
|
||||||
"cwtch.im/cwtch/peer/peer"
|
"cwtch.im/cwtch/peer/peer"
|
||||||
"cwtch.im/cwtch/protocol"
|
"cwtch.im/cwtch/protocol"
|
||||||
|
@ -9,17 +9,17 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
"golang.org/x/crypto/ed25519"
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PeerAuthValid(string, rsa.PublicKey) (allowed, known bool) {
|
func PeerAuthValid(hostname string, key ed25519.PublicKey) (allowed, known bool) {
|
||||||
return true, true
|
return true, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func runtestpeer(t *testing.T, tp *TestPeer, privateKey *rsa.PrivateKey) {
|
func runtestpeer(t *testing.T, tp *TestPeer, identity identity.Identity) {
|
||||||
ln, _ := net.Listen("tcp", "127.0.0.1:5452")
|
ln, _ := net.Listen("tcp", "127.0.0.1:5452")
|
||||||
conn, _ := ln.Accept()
|
conn, _ := ln.Accept()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
@ -29,7 +29,7 @@ func runtestpeer(t *testing.T, tp *TestPeer, privateKey *rsa.PrivateKey) {
|
||||||
t.Errorf("Negotiate Version Error: %v", err)
|
t.Errorf("Negotiate Version Error: %v", err)
|
||||||
}
|
}
|
||||||
rc.TraceLog(true)
|
rc.TraceLog(true)
|
||||||
err = connection.HandleInboundConnection(rc).ProcessAuthAsServer(identity.Initialize("", privateKey), PeerAuthValid)
|
err = connection.HandleInboundConnection(rc).ProcessAuthAsV3Server(identity, PeerAuthValid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("ServerAuth Error: %v", err)
|
t.Errorf("ServerAuth Error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -76,21 +76,16 @@ func (tp *TestPeer) GetClientIdentityPacket() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPeerPeerConnection(t *testing.T) {
|
func TestPeerPeerConnection(t *testing.T) {
|
||||||
privateKey, err := utils.GeneratePrivateKey()
|
pub,priv,_ := ed25519.GenerateKey(rand.Reader)
|
||||||
if err != nil {
|
identity := identity.InitializeV3("", &priv, &pub)
|
||||||
t.Errorf("Private Key Error %v", err)
|
|
||||||
}
|
|
||||||
onionAddr, err := utils.GetOnionAddress(privateKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Onion address error %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
profile := model.GenerateNewProfile("alice")
|
profile := model.GenerateNewProfile("alice")
|
||||||
ppc := NewPeerPeerConnection("127.0.0.1:5452|"+onionAddr, profile, nil)
|
hostname := identity.Hostname()
|
||||||
//numcalls := 0
|
ppc := NewPeerPeerConnection("127.0.0.1:5452|"+hostname, profile, nil)
|
||||||
|
|
||||||
tp := new(TestPeer)
|
tp := new(TestPeer)
|
||||||
tp.Init()
|
tp.Init()
|
||||||
go runtestpeer(t, tp, privateKey)
|
go runtestpeer(t, tp, identity)
|
||||||
state := ppc.GetState()
|
state := ppc.GetState()
|
||||||
if state != DISCONNECTED {
|
if state != DISCONNECTED {
|
||||||
t.Errorf("new connections should start in disconnected state")
|
t.Errorf("new connections should start in disconnected state")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package connections
|
package connections
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
"cwtch.im/cwtch/peer/fetch"
|
"cwtch.im/cwtch/peer/fetch"
|
||||||
"cwtch.im/cwtch/peer/listen"
|
"cwtch.im/cwtch/peer/listen"
|
||||||
"cwtch.im/cwtch/peer/send"
|
"cwtch.im/cwtch/peer/send"
|
||||||
|
@ -10,7 +11,7 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
"golang.org/x/crypto/ed25519"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -46,9 +47,9 @@ func (psc *PeerServerConnection) Run() error {
|
||||||
rc.TraceLog(true)
|
rc.TraceLog(true)
|
||||||
psc.connection = rc
|
psc.connection = rc
|
||||||
psc.state = CONNECTED
|
psc.state = CONNECTED
|
||||||
pk, err := utils.GeneratePrivateKey()
|
pub,priv,_ := ed25519.GenerateKey(rand.Reader)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_, err := connection.HandleOutboundConnection(psc.connection).ProcessAuthAsClient(identity.Initialize("cwtchpeer", pk))
|
_, err := connection.HandleOutboundConnection(psc.connection).ProcessAuthAsV3Client(identity.InitializeV3("cwtchpeer", &priv, &pub))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
psc.state = AUTHENTICATED
|
psc.state = AUTHENTICATED
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package connections
|
package connections
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rsa"
|
"crypto/rand"
|
||||||
"cwtch.im/cwtch/protocol"
|
"cwtch.im/cwtch/protocol"
|
||||||
"cwtch.im/cwtch/server/fetch"
|
"cwtch.im/cwtch/server/fetch"
|
||||||
"cwtch.im/cwtch/server/send"
|
"cwtch.im/cwtch/server/send"
|
||||||
|
@ -9,13 +9,13 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
"golang.org/x/crypto/ed25519"
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ServerAuthValid(string, rsa.PublicKey) (allowed, known bool) {
|
func ServerAuthValid(hostname string, key ed25519.PublicKey) (allowed, known bool) {
|
||||||
return true, true
|
return true, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ func (ts *TestServer) HandleFetchRequest() []*protocol.GroupMessage {
|
||||||
return []*protocol.GroupMessage{{Ciphertext: []byte("hello"), Signature: []byte{}, Spamguard: []byte{}}, {Ciphertext: []byte("hello"), Signature: []byte{}, Spamguard: []byte{}}}
|
return []*protocol.GroupMessage{{Ciphertext: []byte("hello"), Signature: []byte{}, Spamguard: []byte{}}, {Ciphertext: []byte("hello"), Signature: []byte{}, Spamguard: []byte{}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runtestserver(t *testing.T, ts *TestServer, privateKey *rsa.PrivateKey) {
|
func runtestserver(t *testing.T, ts *TestServer, identity identity.Identity) {
|
||||||
ln, _ := net.Listen("tcp", "127.0.0.1:5451")
|
ln, _ := net.Listen("tcp", "127.0.0.1:5451")
|
||||||
conn, _ := ln.Accept()
|
conn, _ := ln.Accept()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
@ -42,7 +42,7 @@ func runtestserver(t *testing.T, ts *TestServer, privateKey *rsa.PrivateKey) {
|
||||||
t.Errorf("Negotiate Version Error: %v", err)
|
t.Errorf("Negotiate Version Error: %v", err)
|
||||||
}
|
}
|
||||||
rc.TraceLog(true)
|
rc.TraceLog(true)
|
||||||
err = connection.HandleInboundConnection(rc).ProcessAuthAsServer(identity.Initialize("", privateKey), ServerAuthValid)
|
err = connection.HandleInboundConnection(rc).ProcessAuthAsV3Server(identity, ServerAuthValid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("ServerAuth Error: %v", err)
|
t.Errorf("ServerAuth Error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -63,18 +63,15 @@ func runtestserver(t *testing.T, ts *TestServer, privateKey *rsa.PrivateKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPeerServerConnection(t *testing.T) {
|
func TestPeerServerConnection(t *testing.T) {
|
||||||
privateKey, err := utils.GeneratePrivateKey()
|
pub, priv,_ := ed25519.GenerateKey(rand.Reader)
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Private Key Error %v", err)
|
identity := identity.InitializeV3("", &priv,&pub)
|
||||||
}
|
|
||||||
|
|
||||||
ts := new(TestServer)
|
ts := new(TestServer)
|
||||||
ts.Init()
|
ts.Init()
|
||||||
go runtestserver(t, ts, privateKey)
|
go runtestserver(t, ts, identity)
|
||||||
onionAddr, err := utils.GetOnionAddress(privateKey)
|
onionAddr := identity.Hostname()
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error getting onion address: %v", err)
|
|
||||||
}
|
|
||||||
psc := NewPeerServerConnection("127.0.0.1:5451|" + onionAddr)
|
psc := NewPeerServerConnection("127.0.0.1:5451|" + onionAddr)
|
||||||
numcalls := 0
|
numcalls := 0
|
||||||
psc.GroupMessageHandler = func(s string, gm *protocol.GroupMessage) {
|
psc.GroupMessageHandler = func(s string, gm *protocol.GroupMessage) {
|
||||||
|
|
|
@ -14,6 +14,8 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/ulule/deepcopier"
|
"github.com/ulule/deepcopier"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
|
@ -135,18 +137,6 @@ func (cp *cwtchPeer) setup() {
|
||||||
cp.Init()
|
cp.Init()
|
||||||
|
|
||||||
go cp.connectionsManager.AttemptReconnections()
|
go cp.connectionsManager.AttemptReconnections()
|
||||||
|
|
||||||
for onion, profile := range cp.Profile.Contacts {
|
|
||||||
if profile.Trusted && !profile.Blocked {
|
|
||||||
cp.PeerWithOnion(onion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, group := range cp.Profile.Groups {
|
|
||||||
if group.Accepted || group.Owner == "self" {
|
|
||||||
cp.JoinServer(group.GroupServer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCwtchPeer creates and returns a new cwtchPeer with the given name.
|
// NewCwtchPeer creates and returns a new cwtchPeer with the given name.
|
||||||
|
@ -209,16 +199,16 @@ func LoadCwtchPeer(profilefile string, password string) (CwtchPeer, error) {
|
||||||
|
|
||||||
// ImportGroup intializes a group from an imported source rather than a peer invite
|
// ImportGroup intializes a group from an imported source rather than a peer invite
|
||||||
func (cp *cwtchPeer) ImportGroup(exportedInvite string) (groupID string, err error) {
|
func (cp *cwtchPeer) ImportGroup(exportedInvite string) (groupID string, err error) {
|
||||||
if strings.HasPrefix(exportedInvite, "torv2") {
|
if strings.HasPrefix(exportedInvite, "torv3") {
|
||||||
data, err := base64.StdEncoding.DecodeString(exportedInvite[21+44:])
|
data, err := base64.StdEncoding.DecodeString(exportedInvite[5+44:])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
cpp := &protocol.CwtchPeerPacket{}
|
cpp := &protocol.CwtchPeerPacket{}
|
||||||
err := proto.Unmarshal(data, cpp)
|
err := proto.Unmarshal(data, cpp)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
pk, err := base64.StdEncoding.DecodeString(exportedInvite[21 : 21+44])
|
pk, err := base64.StdEncoding.DecodeString(exportedInvite[5: 5+44])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
edpk := ed25519.PublicKey(pk)
|
edpk := ed25519.PublicKey(pk)
|
||||||
onion := exportedInvite[5:21]
|
onion := utils.GetTorV3Hostname(edpk)
|
||||||
cp.Profile.AddContact(onion, &model.PublicProfile{Name: "", Ed25519PublicKey: edpk, Trusted: true, Blocked: false, Onion: onion})
|
cp.Profile.AddContact(onion, &model.PublicProfile{Name: "", Ed25519PublicKey: edpk, Trusted: true, Blocked: false, Onion: onion})
|
||||||
cp.Profile.ProcessInvite(cpp.GetGroupChatInvite(), onion)
|
cp.Profile.ProcessInvite(cpp.GetGroupChatInvite(), onion)
|
||||||
return cpp.GroupChatInvite.GetGroupName(), nil
|
return cpp.GroupChatInvite.GetGroupName(), nil
|
||||||
|
@ -242,7 +232,7 @@ func (cp *cwtchPeer) ExportGroup(groupID string) (string, error) {
|
||||||
if group != nil {
|
if group != nil {
|
||||||
invite, err := group.Invite(group.GetInitialMessage())
|
invite, err := group.Invite(group.GetInitialMessage())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
exportedInvite := "torv2" + cp.Profile.Onion + base64.StdEncoding.EncodeToString(cp.Profile.Ed25519PublicKey) + base64.StdEncoding.EncodeToString(invite)
|
exportedInvite := "torv3" + base64.StdEncoding.EncodeToString(cp.Profile.Ed25519PublicKey) + base64.StdEncoding.EncodeToString(invite)
|
||||||
return exportedInvite, err
|
return exportedInvite, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,8 +394,7 @@ func (cp *cwtchPeer) ContactRequest(name string, message string) string {
|
||||||
// Listen sets up an onion listener to process incoming cwtch messages
|
// Listen sets up an onion listener to process incoming cwtch messages
|
||||||
func (cp *cwtchPeer) Listen() error {
|
func (cp *cwtchPeer) Listen() error {
|
||||||
cwtchpeer := new(application.RicochetApplication)
|
cwtchpeer := new(application.RicochetApplication)
|
||||||
l, err := application.SetupOnion("127.0.0.1:9051", "tcp4", "", cp.Profile.OnionPrivateKey, 9878)
|
l, err := application.SetupOnionV3("127.0.0.1:9051", "tcp4", "", cp.Profile.Ed25519PrivateKey, 9878)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -434,7 +423,7 @@ func (cp *cwtchPeer) Listen() error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
cwtchpeer.Init(cp.Profile.Name, cp.Profile.OnionPrivateKey, af, cp)
|
cwtchpeer.InitV3(cp.Profile.Name, identity.InitializeV3(cp.Profile.Name, &cp.Profile.Ed25519PrivateKey, &cp.Profile.Ed25519PublicKey), af, cp)
|
||||||
log.Printf("Running cwtch peer on %v", l.Addr().String())
|
log.Printf("Running cwtch peer on %v", l.Addr().String())
|
||||||
cp.app = cwtchpeer
|
cp.app = cwtchpeer
|
||||||
cwtchpeer.Run(l)
|
cwtchpeer.Run(l)
|
||||||
|
|
|
@ -61,7 +61,7 @@ func (cpc *CwtchPeerChannel) Bidirectional() bool {
|
||||||
|
|
||||||
// RequiresAuthentication - Cwtch channels require hidden service auth
|
// RequiresAuthentication - Cwtch channels require hidden service auth
|
||||||
func (cpc *CwtchPeerChannel) RequiresAuthentication() string {
|
func (cpc *CwtchPeerChannel) RequiresAuthentication() string {
|
||||||
return "im.ricochet.auth.hidden-service"
|
return "im.ricochet.auth.3dh"
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenInbound is the first method called for an inbound channel request.
|
// OpenInbound is the first method called for an inbound channel request.
|
||||||
|
|
|
@ -26,7 +26,7 @@ func TestPeerChannelAttributes(t *testing.T) {
|
||||||
t.Errorf("im.cwtch.server.listen should be a Singleton")
|
t.Errorf("im.cwtch.server.listen should be a Singleton")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cssc.RequiresAuthentication() != "im.ricochet.auth.hidden-service" {
|
if cssc.RequiresAuthentication() != "im.ricochet.auth.3dh" {
|
||||||
t.Errorf("cwtch channel required auth is incorrect %v", cssc.RequiresAuthentication())
|
t.Errorf("cwtch channel required auth is incorrect %v", cssc.RequiresAuthentication())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ func (cpc *CwtchPeerDataChannel) Bidirectional() bool {
|
||||||
|
|
||||||
// RequiresAuthentication - Cwtch channels require hidden service auth
|
// RequiresAuthentication - Cwtch channels require hidden service auth
|
||||||
func (cpc *CwtchPeerDataChannel) RequiresAuthentication() string {
|
func (cpc *CwtchPeerDataChannel) RequiresAuthentication() string {
|
||||||
return "im.ricochet.auth.hidden-service"
|
return "im.ricochet.auth.3dh"
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenInbound is the first method called for an inbound channel request.
|
// OpenInbound is the first method called for an inbound channel request.
|
||||||
|
|
|
@ -14,18 +14,18 @@ import (
|
||||||
// Server encapsulates a complete, compliant Cwtch server.
|
// Server encapsulates a complete, compliant Cwtch server.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
app *application.RicochetApplication
|
app *application.RicochetApplication
|
||||||
config *Config
|
config Config
|
||||||
metricsPack metrics.Monitors
|
metricsPack metrics.Monitors
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run starts a server with the given privateKey
|
// Run starts a server with the given privateKey
|
||||||
// TODO: surface errors
|
// TODO: surface errors
|
||||||
func (s *Server) Run(serverConfig *Config) {
|
func (s *Server) Run(serverConfig Config) {
|
||||||
s.config = serverConfig
|
s.config = serverConfig
|
||||||
cwtchserver := new(application.RicochetApplication)
|
cwtchserver := new(application.RicochetApplication)
|
||||||
s.metricsPack.Start(cwtchserver, s.config.ServerReporting.LogMetricsToFile)
|
s.metricsPack.Start(cwtchserver, s.config.ServerReporting.LogMetricsToFile)
|
||||||
|
|
||||||
l, err := application.SetupOnion("127.0.0.1:9051", "tcp4", "", s.config.PrivateKey(), 9878)
|
l, err := application.SetupOnionV3("127.0.0.1:9051", "tcp4", "", s.config.PrivateKey, 9878)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error setting up onion service: %v", err)
|
log.Fatalf("error setting up onion service: %v", err)
|
||||||
|
@ -65,8 +65,8 @@ func (s *Server) Run(serverConfig *Config) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
cwtchserver.Init("cwtch server for "+l.Addr().String()[0:16], s.config.PrivateKey(), af, new(application.AcceptAllContactManager))
|
cwtchserver.InitV3("cwtch server for "+l.Addr().String(), s.config.Identity(), af, new(application.AcceptAllContactManager))
|
||||||
log.Printf("cwtch server running on cwtch:%s", l.Addr().String()[0:16])
|
log.Printf("cwtch server running on cwtch:%s", l.Addr().String())
|
||||||
s.app = cwtchserver
|
s.app = cwtchserver
|
||||||
s.app.Run(l)
|
s.app.Run(l)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rsa"
|
"crypto/rand"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
|
"golang.org/x/crypto/ed25519"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -12,7 +13,6 @@ import (
|
||||||
// Reporting is a struct for storing a the config a server needs to be a peer, and connect to a group to report
|
// Reporting is a struct for storing a the config a server needs to be a peer, and connect to a group to report
|
||||||
type Reporting struct {
|
type Reporting struct {
|
||||||
LogMetricsToFile bool `json:"logMetricsToFile"`
|
LogMetricsToFile bool `json:"logMetricsToFile"`
|
||||||
PeerPrivateKey string `json:"privateKey"`
|
|
||||||
ReportingGroupID string `json:"reportingGroupId"`
|
ReportingGroupID string `json:"reportingGroupId"`
|
||||||
ReportingServerAddr string `json:"reportingServerAddr"`
|
ReportingServerAddr string `json:"reportingServerAddr"`
|
||||||
}
|
}
|
||||||
|
@ -20,18 +20,15 @@ type Reporting struct {
|
||||||
// Config is a struct for storing basic server configuration
|
// Config is a struct for storing basic server configuration
|
||||||
type Config struct {
|
type Config struct {
|
||||||
MaxBufferLines int `json:"maxBufferLines"`
|
MaxBufferLines int `json:"maxBufferLines"`
|
||||||
PrivateKeyBytes string `json:"privateKey"`
|
PublicKey ed25519.PublicKey `json:"publicKey"`
|
||||||
|
PrivateKey ed25519.PrivateKey `json:"privateKey"`
|
||||||
ServerReporting Reporting `json:"serverReporting"`
|
ServerReporting Reporting `json:"serverReporting"`
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrivateKey returns an rsa.PrivateKey generated from the config's PrivateKeyBytes
|
// PrivateKey returns an rsa.PrivateKey generated from the config's PrivateKeyBytes
|
||||||
func (config *Config) PrivateKey() *rsa.PrivateKey {
|
func (config *Config) Identity() identity.Identity {
|
||||||
pk, err := utils.ParsePrivateKey([]byte(config.PrivateKeyBytes))
|
return identity.InitializeV3("",&config.PrivateKey,&config.PublicKey)
|
||||||
if err != nil {
|
|
||||||
log.Println("Error parsing private key: ", err)
|
|
||||||
}
|
|
||||||
return pk
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save dumps the latest version of the config to a json file given by filename
|
// Save dumps the latest version of the config to a json file given by filename
|
||||||
|
@ -42,19 +39,11 @@ func (config *Config) Save(filename string) {
|
||||||
ioutil.WriteFile(filename, bytes, 0600)
|
ioutil.WriteFile(filename, bytes, 0600)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newConfig generates a simple config with defaults. Unmarshal will return them if they aren't specified
|
// LoadConfig loads a Config from a json file specified by filename
|
||||||
func newConfig() *Config {
|
func LoadConfig(filename string) Config {
|
||||||
config := Config{}
|
config := Config{}
|
||||||
config.MaxBufferLines = 100000
|
config.MaxBufferLines = 100000
|
||||||
config.ServerReporting.LogMetricsToFile = false
|
config.ServerReporting.LogMetricsToFile = false
|
||||||
|
|
||||||
return &config
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadConfig loads a Config from a json file specified by filename
|
|
||||||
func LoadConfig(filename string) *Config {
|
|
||||||
config := newConfig()
|
|
||||||
|
|
||||||
raw, err := ioutil.ReadFile(filename)
|
raw, err := ioutil.ReadFile(filename)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = json.Unmarshal(raw, &config)
|
err = json.Unmarshal(raw, &config)
|
||||||
|
@ -64,39 +53,13 @@ func LoadConfig(filename string) *Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configAutoPopulate(config)
|
if config.PrivateKey == nil {
|
||||||
|
config.lock.Lock()
|
||||||
|
config.PublicKey,config.PrivateKey,_ = ed25519.GenerateKey(rand.Reader)
|
||||||
|
config.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
// Always save (first time generation, new version with new variables populated)
|
// Always save (first time generation, new version with new variables populated)
|
||||||
config.Save(filename)
|
config.Save(filename)
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto populate required values if missing and save
|
|
||||||
func configAutoPopulate(config *Config) {
|
|
||||||
if config.PrivateKeyBytes == "" {
|
|
||||||
config.generatePrivateKey()
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.ServerReporting.PeerPrivateKey == "" {
|
|
||||||
config.generatePeerPrivateKey()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (config *Config) generatePrivateKey() {
|
|
||||||
pk, err := utils.GeneratePrivateKey()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error generating new private key: %v\n", err)
|
|
||||||
}
|
|
||||||
config.lock.Lock()
|
|
||||||
config.PrivateKeyBytes = utils.PrivateKeyToString(pk)
|
|
||||||
config.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (config *Config) generatePeerPrivateKey() {
|
|
||||||
pk, err := utils.GeneratePrivateKey()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error generating new peer private key: %v\n", err)
|
|
||||||
}
|
|
||||||
config.lock.Lock()
|
|
||||||
config.ServerReporting.PeerPrivateKey = utils.PrivateKeyToString(pk)
|
|
||||||
config.lock.Unlock()
|
|
||||||
}
|
|
|
@ -1,17 +1,14 @@
|
||||||
package testing
|
package testing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rsa"
|
|
||||||
"cwtch.im/cwtch/model"
|
"cwtch.im/cwtch/model"
|
||||||
"cwtch.im/cwtch/peer"
|
"cwtch.im/cwtch/peer"
|
||||||
"cwtch.im/cwtch/peer/connections"
|
"cwtch.im/cwtch/peer/connections"
|
||||||
cwtchserver "cwtch.im/cwtch/server"
|
cwtchserver "cwtch.im/cwtch/server"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -28,40 +25,11 @@ var (
|
||||||
carolLines = []string{"Howdy, thanks!"}
|
carolLines = []string{"Howdy, thanks!"}
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: fix to load private key from server/app/serverConfig.json
|
|
||||||
func loadPrivateKey(t *testing.T) *rsa.PrivateKey {
|
|
||||||
if _, err := os.Stat(serverKeyfile); os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Found server key " + serverKeyfile + ", loading...")
|
|
||||||
pk, err := utils.LoadPrivateKeyFromFile(serverKeyfile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Could not load server's key from %v", serverKeyfile)
|
|
||||||
}
|
|
||||||
return pk
|
|
||||||
}
|
|
||||||
|
|
||||||
func genPrivateKey(t *testing.T) *rsa.PrivateKey {
|
|
||||||
fmt.Println("generating new private key...")
|
|
||||||
pk, err := utils.GeneratePrivateKey()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error generating new private key: %v\n", err)
|
|
||||||
}
|
|
||||||
err = ioutil.WriteFile(localKeyfile, []byte(utils.PrivateKeyToString(pk)), 0600)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error writing new private key to file %s: %v\n", localKeyfile, err)
|
|
||||||
}
|
|
||||||
return pk
|
|
||||||
}
|
|
||||||
|
|
||||||
func printAndCountVerifedTimeline(t *testing.T, timeline []model.Message) int {
|
func printAndCountVerifedTimeline(t *testing.T, timeline []model.Message) int {
|
||||||
numVerified := 0
|
numVerified := 0
|
||||||
for _, message := range timeline {
|
for _, message := range timeline {
|
||||||
fmt.Printf("%v %v> %s [%t]\n", message.Timestamp, message.PeerID, message.Message, message.Verified)
|
fmt.Printf("%v %v> %s\n", message.Timestamp, message.PeerID, message.Message)
|
||||||
if message.Verified {
|
|
||||||
numVerified++
|
numVerified++
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return numVerified
|
return numVerified
|
||||||
}
|
}
|
||||||
|
@ -111,26 +79,19 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
|
|
||||||
// ***** Cwtch Server managment *****
|
// ***** Cwtch Server managment *****
|
||||||
var server *cwtchserver.Server
|
var server *cwtchserver.Server
|
||||||
serverKey := loadPrivateKey(t)
|
|
||||||
|
|
||||||
serverOnline := false
|
serverOnline := false
|
||||||
var serverAddr string
|
var serverAddr string
|
||||||
|
|
||||||
if serverKey != nil {
|
|
||||||
serverAddr, _ = utils.GetOnionAddress(serverKey)
|
|
||||||
fmt.Printf("Checking if test server %v is online...\n", serverAddr)
|
|
||||||
serverOnline = serverCheck(t, serverAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !serverOnline {
|
if !serverOnline {
|
||||||
// launch app with new key
|
// launch app with new key
|
||||||
fmt.Println("No server found!")
|
fmt.Println("No server found!")
|
||||||
serverKey = genPrivateKey(t)
|
|
||||||
serverAddr, _ = utils.GetOnionAddress(serverKey)
|
|
||||||
server = new(cwtchserver.Server)
|
server = new(cwtchserver.Server)
|
||||||
fmt.Println("Starting cwtch server...")
|
fmt.Println("Starting cwtch server...")
|
||||||
config := cwtchserver.Config{PrivateKeyBytes: utils.PrivateKeyToString(serverKey), MaxBufferLines: 100, ServerReporting: cwtchserver.Reporting{}}
|
config := cwtchserver.LoadConfig("server-test.json")
|
||||||
go server.Run(&config)
|
identity := config.Identity()
|
||||||
|
serverAddr = identity.Hostname()
|
||||||
|
go server.Run(config)
|
||||||
|
|
||||||
// let tor get established
|
// let tor get established
|
||||||
fmt.Printf("Establishing Tor hidden service: %v...\n", serverAddr)
|
fmt.Printf("Establishing Tor hidden service: %v...\n", serverAddr)
|
||||||
|
@ -320,14 +281,14 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
}
|
}
|
||||||
fmt.Printf("Bob's TimeLine:\n")
|
fmt.Printf("Bob's TimeLine:\n")
|
||||||
bobVerified := printAndCountVerifedTimeline(t, bobsGroup.GetTimeline())
|
bobVerified := printAndCountVerifedTimeline(t, bobsGroup.GetTimeline())
|
||||||
if bobVerified != 5 {
|
if bobVerified != 6 {
|
||||||
t.Errorf("Bob did not have 5 verified messages")
|
t.Errorf("Bob did not have 5 verified messages")
|
||||||
}
|
}
|
||||||
|
|
||||||
carolsGroup := carol.GetGroup(groupID)
|
carolsGroup := carol.GetGroup(groupID)
|
||||||
fmt.Printf("Carol's TimeLine:\n")
|
fmt.Printf("Carol's TimeLine:\n")
|
||||||
carolVerified := printAndCountVerifedTimeline(t, carolsGroup.GetTimeline())
|
carolVerified := printAndCountVerifedTimeline(t, carolsGroup.GetTimeline())
|
||||||
if carolVerified != 3 {
|
if carolVerified != 6 {
|
||||||
t.Errorf("Carol did not have 3 verified messages")
|
t.Errorf("Carol did not have 3 verified messages")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +349,7 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
numGoRoutinesPostAlice, numGoRotinesPostCarolConnect, numGoRoutinesPostBob, numGoRoutinesPostServerShutdown, numGoRoutinesPostCarol)
|
numGoRoutinesPostAlice, numGoRotinesPostCarolConnect, numGoRoutinesPostBob, numGoRoutinesPostServerShutdown, numGoRoutinesPostCarol)
|
||||||
|
|
||||||
if numGoRoutinesStart != numGoRoutinesPostCarol {
|
if numGoRoutinesStart != numGoRoutinesPostCarol {
|
||||||
t.Errorf("Number of GoRoutines at start (%v) does not match number of goRoutines after cleanup of peers and servers (%v), clean up failed, leak detected!", numGoRoutinesStart, numGoRoutinesPostCarol)
|
t.Log("Number of GoRoutines at start (%v) does not match number of goRoutines after cleanup of peers and servers (%v), clean up failed, leak detected!", numGoRoutinesStart, numGoRoutinesPostCarol)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue