diff --git a/features/groups/group_functionality.go b/features/groups/group_functionality.go new file mode 100644 index 0000000..8ce5f7a --- /dev/null +++ b/features/groups/group_functionality.go @@ -0,0 +1,70 @@ +package groups + +import ( + "cwtch.im/cwtch/peer" + "encoding/base64" + "errors" + "fmt" + "git.openprivacy.ca/openprivacy/log" + "strings" +) + +const ServerPrefix = "server:" +const TofuBundlePrefix = "tofubundle:" +const GroupPrefix = "torv3" +const GroupExperiment = "tapir-groups-experiment" + +type GroupFunctionality struct { +} + +// ExperimentGate returns GroupFunctionality if the experiment is enabled, and an error otherwise. +func ExperimentGate(experimentMap map[string]bool) (*GroupFunctionality, error) { + if experimentMap[GroupExperiment] { + return new(GroupFunctionality), nil + } + return nil, fmt.Errorf("gated by %v", GroupExperiment) +} + +func (gf *GroupFunctionality) SendMessage(peer peer.CwtchPeer, handle string, message string) error { + // TODO this auto accepting behaviour needs some thinking through + if !peer.GetGroup(handle).Accepted { + err := peer.AcceptInvite(handle) + if err != nil { + log.Errorf("tried to mark a nonexistent group as existed. bad!") + return err + } + } + + _, err := peer.SendMessageToGroupTracked(handle, message) + + return err +} + +// ValidPrefix returns true if an import string contains a prefix that indicates it contains information about a +// server or a group +func (gf *GroupFunctionality) ValidPrefix(importString string) bool { + return strings.HasPrefix(importString, TofuBundlePrefix) || strings.HasPrefix(importString, ServerPrefix) || strings.HasPrefix(importString, GroupPrefix) +} + +// HandleImportString handles import strings for groups and servers +func (gf *GroupFunctionality) HandleImportString(peer peer.CwtchPeer, importString string) error { + + if strings.HasPrefix(importString, TofuBundlePrefix) { + bundle := strings.Split(importString, "||") + gf.HandleImportString(peer, bundle[0][11:]) + gf.HandleImportString(peer, bundle[1]) + return nil + } else if strings.HasPrefix(importString, ServerPrefix) { + // Server Key Bundles are prefixed with + bundle, err := base64.StdEncoding.DecodeString(importString[7:]) + if err == nil { + return peer.AddServer(string(bundle)) + } + return err + } else if strings.HasPrefix(importString, GroupPrefix) { + //eg: torv3JFDWkXExBsZLkjvfkkuAxHsiLGZBk0bvoeJID9ItYnU=EsEBCiBhOWJhZDU1OTQ0NWI3YmM2N2YxYTM5YjkzMTNmNTczNRIgpHeNaG+6jy750eDhwLO39UX4f2xs0irK/M3P6mDSYQIaOTJjM2ttb29ibnlnaGoyenc2cHd2N2Q1N3l6bGQ3NTNhdW8zdWdhdWV6enB2ZmFrM2FoYzRiZHlkCiJAdVSSVgsksceIfHe41OJu9ZFHO8Kwv3G6F5OK3Hw4qZ6hn6SiZjtmJlJezoBH0voZlCahOU7jCOg+dsENndZxAA== + return peer.ImportGroup(importString) + } + + return errors.New("invalid_group_invite_prefix") +} diff --git a/features/groups/group_functionality_test.go b/features/groups/group_functionality_test.go new file mode 100644 index 0000000..4a3331a --- /dev/null +++ b/features/groups/group_functionality_test.go @@ -0,0 +1,39 @@ +package groups + +import "testing" + +func TestGroupFunctionality_ValidPrefix(t *testing.T) { + gf, _ := ExperimentGate(map[string]bool{GroupExperiment: true}) + if gf.ValidPrefix("torv3blahblahblah") == false { + t.Fatalf("torv3 should be a valid prefix") + } + if gf.ValidPrefix("tofubundle:32432423||3242342") == false { + t.Fatalf("tofubundle should be a valid prefix") + } + if gf.ValidPrefix("server:23541233t") == false { + t.Fatalf("server should be a valid prefix") + } + if gf.ValidPrefix("alice!24234") == true { + t.Fatalf("alice should be an invalid predix") + } +} + +func TestGroupFunctionality_IsEnabled(t *testing.T) { + + _, err := ExperimentGate(map[string]bool{}) + + if err == nil { + t.Fatalf("group functionality should be disabled") + } + + _, err = ExperimentGate(map[string]bool{GroupExperiment: true}) + + if err != nil { + t.Fatalf("group functionality should be enabled") + } + + _, err = ExperimentGate(map[string]bool{GroupExperiment: false}) + if err == nil { + t.Fatalf("group functionality should be disabled") + } +} diff --git a/lib.go b/lib.go index 364cb0a..ea0ec31 100644 --- a/lib.go +++ b/lib.go @@ -7,7 +7,6 @@ import ( "cwtch.im/cwtch/app" "cwtch.im/cwtch/event" "cwtch.im/cwtch/model/attr" - "cwtch.im/cwtch/peer" "encoding/json" @@ -166,6 +165,12 @@ func SendProfileEvent(onion string, eventJson string) { switch new_event.EventType { case event.SetAttribute: peer.SetAttribute(new_event.Data[event.Key], new_event.Data[event.Data]) + case event.SendMessageToGroup: + // TODO Uncomment and integrate once contacts/messages are loaded. + //groupHandler,err := groups.ExperimentGate(utils.ReadGlobalSettings().Experiments) + //if err == nil { + // err = groupHandler.SendMessage(peer, new_event.Data[event.GroupID], new_event.Data[event.Data]) + //} default: // rebroadcast catch all log.Infof("Received Event %v for %v but no libCwtch handler found, relaying the event directly", new_event, onion)