diff --git a/model/message_test.go b/model/message_test.go index b440b8e..958b050 100644 --- a/model/message_test.go +++ b/model/message_test.go @@ -47,6 +47,9 @@ func TestTranscriptConsistency(t *testing.T) { sarah.AddContact(alice.Onion, &alice.PublicProfile) alice.AddContact(sarah.Onion, &sarah.PublicProfile) + // The lightest weight server entry possible (usually we would import a key bundle...) + sarah.AddContact("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd", &PublicProfile{Attributes: map[string]string{string(KeyTypeServerOnion): "2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd"}}) + gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd") sarah.ProcessInvite(invite) diff --git a/model/profile.go b/model/profile.go index f434ae5..be05f55 100644 --- a/model/profile.go +++ b/model/profile.go @@ -8,6 +8,7 @@ import ( "encoding/hex" "encoding/json" "errors" + "fmt" "git.openprivacy.ca/openprivacy/connectivity/tor" "golang.org/x/crypto/ed25519" "io" @@ -390,6 +391,9 @@ func (p *Profile) GetGroup(groupID string) (g *Group) { func (p *Profile) ProcessInvite(invite string) (string, error) { gci, err := ValidateInvite(invite) if err == nil { + if server, exists := p.GetContact(gci.ServerHost); !exists || !server.IsServer() { + return "", fmt.Errorf("unknown server. a server key bundle needs to be imported before this group can be verified") + } group := new(Group) group.Version = CurrentGroupVersion group.GroupID = gci.GroupID diff --git a/model/profile_test.go b/model/profile_test.go index 0dba56e..2cd8ae5 100644 --- a/model/profile_test.go +++ b/model/profile_test.go @@ -62,6 +62,8 @@ func TestRejectGroupInvite(t *testing.T) { alice := GenerateNewProfile("Alice") sarah.AddContact(alice.Onion, &alice.PublicProfile) alice.AddContact(sarah.Onion, &sarah.PublicProfile) + // The lightest weight server entry possible (usually we would import a key bundle...) + sarah.AddContact("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd", &PublicProfile{Attributes: map[string]string{string(KeyTypeServerOnion): "2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd"}}) gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd") sarah.ProcessInvite(invite) @@ -86,6 +88,9 @@ func TestProfileGroup(t *testing.T) { alice.AddContact(sarah.Onion, &sarah.PublicProfile) gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd") + + // The lightest weight server entry possible (usually we would import a key bundle...) + sarah.AddContact("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd", &PublicProfile{Attributes: map[string]string{string(KeyTypeServerOnion): "2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd"}}) sarah.ProcessInvite(invite) if len(sarah.GetGroups()) != 1 { t.Errorf("sarah should only be in 1 group instead: %v", sarah.GetGroups()) @@ -109,6 +114,9 @@ func TestProfileGroup(t *testing.T) { bob := GenerateNewProfile("bob") bob.AddContact(alice.Onion, &alice.PublicProfile) + // The lightest weight server entry possible (usually we would import a key bundle...) + bob.AddContact("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd", &PublicProfile{Attributes: map[string]string{string(KeyTypeServerOnion): "2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd"}}) + bob.ProcessInvite(invite2) c3, s3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID) if err == nil { diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index 2dab063..8e924ac 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -811,6 +811,10 @@ func (cp *cwtchPeer) eventHandler() { cp.mutex.Unlock() case event.ServerStateChange: cp.mutex.Lock() + // We update both the server contact status, as well as the groups the server belongs to + cp.Profile.Contacts[ev.Data[event.GroupServer]].State = ev.Data[event.ConnectionState] + + // TODO deprecate this, the UI should consult the server contact entry instead (it's far more efficient) for _, group := range cp.Profile.Groups { if group.GroupServer == ev.Data[event.GroupServer] { group.State = ev.Data[event.ConnectionState] diff --git a/storage/profile_store_test.go b/storage/profile_store_test.go index e9f8a44..fcec0a3 100644 --- a/storage/profile_store_test.go +++ b/storage/profile_store_test.go @@ -4,6 +4,7 @@ package storage import ( "cwtch.im/cwtch/event" + "cwtch.im/cwtch/model" "cwtch.im/cwtch/storage/v0" "fmt" "git.openprivacy.ca/openprivacy/log" @@ -32,6 +33,8 @@ func TestProfileStoreUpgradeV0toV1(t *testing.T) { fmt.Println("Creating and initializing v0 profile and store...") profile := NewProfile(testProfileName) + profile.AddContact("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd", &model.PublicProfile{Attributes: map[string]string{string(model.KeyTypeServerOnion): "2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd"}}) + ps1 := v0.NewProfileWriterStore(eventBus, testingDir, password, profile) groupid, invite, err := profile.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd") diff --git a/storage/v1/profile_store_test.go b/storage/v1/profile_store_test.go index ae23fd3..1fb8133 100644 --- a/storage/v1/profile_store_test.go +++ b/storage/v1/profile_store_test.go @@ -4,6 +4,7 @@ package v1 import ( "cwtch.im/cwtch/event" + "cwtch.im/cwtch/model" "fmt" "log" "os" @@ -22,6 +23,9 @@ func TestProfileStoreWriteRead(t *testing.T) { os.RemoveAll(testingDir) eventBus := event.NewEventManager() profile := NewProfile(testProfileName) + // The lightest weight server entry possible (usually we would import a key bundle...) + profile.AddContact("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd", &model.PublicProfile{Attributes: map[string]string{string(model.KeyTypeServerOnion): "2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd"}}) + ps1 := CreateProfileWriterStore(eventBus, testingDir, password, profile) eventBus.Publish(event.NewEvent(event.SetAttribute, map[event.Field]string{event.Key: testKey, event.Data: testVal})) @@ -79,6 +83,8 @@ func TestProfileStoreChangePassword(t *testing.T) { eventBus.Subscribe(event.ChangePasswordSuccess, queue) profile := NewProfile(testProfileName) + profile.AddContact("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd", &model.PublicProfile{Attributes: map[string]string{string(model.KeyTypeServerOnion): "2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd"}}) + ps1 := CreateProfileWriterStore(eventBus, testingDir, password, profile) groupid, invite, err := profile.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")