C-bindings for the Go Cwtch Library https://cwtch.im
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
4.9 KiB

  1. package groups
  2. import (
  3. "cwtch.im/cwtch/event"
  4. "cwtch.im/cwtch/model"
  5. "cwtch.im/cwtch/peer"
  6. "encoding/base64"
  7. "fmt"
  8. "git.openprivacy.ca/cwtch.im/libcwtch-go/features"
  9. "git.openprivacy.ca/openprivacy/log"
  10. "strings"
  11. )
  12. const serverPrefix = "server:"
  13. const tofuBundlePrefix = "tofubundle:"
  14. const groupPrefix = "torv3"
  15. const groupExperiment = "tapir-groups-experiment"
  16. const importBundlePrefix = "importBundle"
  17. const (
  18. // ServerList is a json encoded list of servers
  19. ServerList = event.Field("ServerList")
  20. )
  21. const (
  22. // UpdateServerInfo is an event containing a ProfileOnion and a ServerList
  23. UpdateServerInfo = event.Type("UpdateServerInfo")
  24. )
  25. // ReadServerInfo is a meta-interface for reading information about servers..
  26. type ReadServerInfo interface {
  27. peer.ReadContacts
  28. peer.ReadServers
  29. }
  30. // GroupFunctionality provides experiment gated server functionality
  31. type GroupFunctionality struct {
  32. }
  33. // ExperimentGate returns GroupFunctionality if the experiment is enabled, and an error otherwise.
  34. func ExperimentGate(experimentMap map[string]bool) (*GroupFunctionality, error) {
  35. if experimentMap[groupExperiment] {
  36. return new(GroupFunctionality), nil
  37. }
  38. return nil, fmt.Errorf("gated by %v", groupExperiment)
  39. }
  40. // SendMessage is a deprecated api
  41. func (gf *GroupFunctionality) SendMessage(peer peer.CwtchPeer, handle string, message string) (string, error) {
  42. // TODO this auto accepting behaviour needs some thinking through
  43. if !peer.GetGroup(handle).Accepted {
  44. err := peer.AcceptInvite(handle)
  45. if err != nil {
  46. log.Errorf("tried to mark a nonexistent group as existed. bad!")
  47. return "", err
  48. }
  49. }
  50. return peer.SendMessageToGroupTracked(handle, message)
  51. }
  52. // ValidPrefix returns true if an import string contains a prefix that indicates it contains information about a
  53. // server or a group
  54. func (gf *GroupFunctionality) ValidPrefix(importString string) bool {
  55. return strings.HasPrefix(importString, tofuBundlePrefix) || strings.HasPrefix(importString, serverPrefix) || strings.HasPrefix(importString, groupPrefix)
  56. }
  57. // GetServerInfoList compiles all the information the UI might need regarding all servers..
  58. func (gf *GroupFunctionality) GetServerInfoList(profile ReadServerInfo) []Server {
  59. var servers []Server
  60. for _, server := range profile.GetServers() {
  61. servers = append(servers, gf.GetServerInfo(server, profile))
  62. }
  63. return servers
  64. }
  65. // GetServerInfo compiles all the information the UI might need regarding a particular server including any verified
  66. // cryptographic keys
  67. func (gf *GroupFunctionality) GetServerInfo(serverOnion string, profile peer.ReadContacts) Server {
  68. serverInfo := profile.GetContact(serverOnion)
  69. keyTypes := []model.KeyType{model.KeyTypeServerOnion, model.KeyTypeTokenOnion, model.KeyTypePrivacyPass}
  70. var serverKeys []ServerKey
  71. for _, keyType := range keyTypes {
  72. if key, has := serverInfo.GetAttribute(string(keyType)); has {
  73. serverKeys = append(serverKeys, ServerKey{Type: string(keyType), Key: key})
  74. }
  75. }
  76. return Server{Onion: serverOnion, Status: serverInfo.State, Keys: serverKeys}
  77. }
  78. // HandleImportString handles import strings for groups and servers
  79. func (gf *GroupFunctionality) HandleImportString(peer peer.CwtchPeer, importString string) error {
  80. if strings.HasPrefix(importString, tofuBundlePrefix) {
  81. bundle := strings.Split(importString, "||")
  82. if len(bundle) == 2 {
  83. err := gf.HandleImportString(peer, bundle[0][len(tofuBundlePrefix):])
  84. // if the server import failed then abort the whole process..
  85. if !strings.HasSuffix(err.Error(), "success") {
  86. return features.ConstructResponse(importBundlePrefix, err.Error())
  87. }
  88. return gf.HandleImportString(peer, bundle[1])
  89. }
  90. } else if strings.HasPrefix(importString, serverPrefix) {
  91. // Server Key Bundles are prefixed with
  92. bundle, err := base64.StdEncoding.DecodeString(importString[len(serverPrefix):])
  93. if err == nil {
  94. if err = peer.AddServer(string(bundle)); err != nil {
  95. return features.ConstructResponse(importBundlePrefix, err.Error())
  96. }
  97. return features.ConstructResponse(importBundlePrefix, "success")
  98. }
  99. return features.ConstructResponse(importBundlePrefix, err.Error())
  100. } else if strings.HasPrefix(importString, groupPrefix) {
  101. //eg: torv3JFDWkXExBsZLkjvfkkuAxHsiLGZBk0bvoeJID9ItYnU=EsEBCiBhOWJhZDU1OTQ0NWI3YmM2N2YxYTM5YjkzMTNmNTczNRIgpHeNaG+6jy750eDhwLO39UX4f2xs0irK/M3P6mDSYQIaOTJjM2ttb29ibnlnaGoyenc2cHd2N2Q1N3l6bGQ3NTNhdW8zdWdhdWV6enB2ZmFrM2FoYzRiZHlkCiJAdVSSVgsksceIfHe41OJu9ZFHO8Kwv3G6F5OK3Hw4qZ6hn6SiZjtmJlJezoBH0voZlCahOU7jCOg+dsENndZxAA==
  102. if gid, err := peer.ImportGroup(importString); err != nil {
  103. return features.ConstructResponse(importBundlePrefix, err.Error())
  104. } else {
  105. // Auto accept the group here.
  106. if peer.AcceptInvite(gid) != nil {
  107. log.Errorf("Error accepting invite: %v", err)
  108. }
  109. return features.ConstructResponse(importBundlePrefix, "success")
  110. }
  111. }
  112. return features.ConstructResponse(importBundlePrefix, "invalid_group_invite_prefix")
  113. }