Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Commit

Permalink
add support for joining groups
Browse files Browse the repository at this point in the history
  • Loading branch information
[email protected] committed Jan 3, 2022
1 parent 0deacab commit 4676815
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 78 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ require (
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.6.1
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect
golang.org/x/text v0.3.3
google.golang.org/protobuf v1.25.0
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
3 changes: 1 addition & 2 deletions groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,14 +533,13 @@ func LeaveGroup(hexid string) error {

func JoinGroup(hexID string) (*groupsv2.GroupV2, error) {
log.Debugln("[textsecure] join group", hexID)
log.Debugln("[textsecure] joining groups is not yet implemented")
g := groupsv2.FindGroup(hexID)
if g == nil {
return nil, UnknownGroupIDError{hexID}
}
err := g.JoinGroup()
if err != nil {
return nil, err
return g, err
}
return g, nil
}
78 changes: 38 additions & 40 deletions groupsv2/createGroupChange.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/signal-golang/textsecure/config"
signalservice "github.com/signal-golang/textsecure/protobuf"
log "github.com/sirupsen/logrus"
"google.golang.org/protobuf/proto"
)

const (
Expand Down Expand Up @@ -47,85 +48,82 @@ func CreateGroupChangeFromGroupActions(actions []byte) []byte {

}

// func CreatePromotePendingMemberActionMessage(uuid []byte, group string) *signalservice.GroupContextV2 {
// groupActions := CreatePromotePendingMemberAction(uuid, group)

// return nil

// }

func creatEmptyGroupChangeActions() *signalservice.GroupChange_Actions {
return &signalservice.GroupChange_Actions{}
}

func (g *GroupV2) AddPendingMembers(uuid []byte) (*signalservice.GroupChange_Actions, error) {
log.Debugln("[textsecure] groupsv2 AddPendingMembers (only works for self )")
func (g *GroupV2) AddPendingMembers(uuid []byte) error {
log.Debugln("[textsecure][groupsv2] AddPendingMembers (only works for self )")
member, err := g.findMemberByUuid(config.ConfigFile.UUID)

if err != nil {
log.Debugln("[textsecure] member not found")
return nil, err
return err
}
member.ProfileKey = config.ConfigFile.ProfileKey
// groupSecrets, err := zkgroup.NewGroupSecretParams(g.MasterKey)
if err != nil {
log.Debugln("[textsecure] CreateRequestForGroup 1", err)
return nil, err
return err
}

zkGroupServerPublicParams, err := base64.StdEncoding.DecodeString(config.ZKGROUP_SERVER_PUBLIC_PARAMS)
if err != nil {
log.Debugln("[textsecure] CreateRequestForGroup 2", err)
return nil, err
return err
}
serverPublicParams, err := zkgroup.NewServerPublicParams(zkGroupServerPublicParams)
if err != nil {
log.Debugln("[textsecure] CreateRequestForGroup 8", err)
return nil, err
return err
}

groupSecretParams, err := zkgroup.NewGroupSecretParams(g.MasterKey)
if err != nil {
log.Debugln("[textsecure] CreateRequestForGroup 9", err)
return nil, err
return err
}
log.Debugln("[textsecure] CreateRequestForGroup 9.1", len(config.ConfigFile.ProfileKeyCredential))
presentation, err := serverPublicParams.CreateProfileKeyCredentialPresentation(groupSecretParams, config.ConfigFile.ProfileKeyCredential)
if err != nil {
log.Debugln("[textsecure] CreateRequestForGroup 10", err)
return nil, err
return err
}
member.Presentation = presentation
member.JoinedAtRevision = g.GroupContext.Revision + 1
member.Role = 1

groupChangeActions := &signalservice.GroupChange_Actions{}
groupChangeActions.AddMembers = append(groupChangeActions.AddMembers,
&signalservice.GroupChange_Actions_AddMemberAction{
Added: member,
groupChangeActions.PromotePendingMembers = append(groupChangeActions.PromotePendingMembers,
&signalservice.GroupChange_Actions_PromotePendingMemberAction{
Presentation: presentation,
})
groupChangeActions.SourceUuid = uuid
groupChangeActions.Revision = g.DecryptedGroup.Revision + 1
fmt.Printf("[textsecure] AddPendingMembers %+v\n", groupChangeActions)

auth, err := NewGroupsV2Authorization(uuidToByte(config.ConfigFile.UUID), groupSecretParams)
err = PatchGroupV2(groupChangeActions, auth)
auth, err := NewGroupsV2Authorization(uuid, groupSecretParams)
if err != nil {
return err
}
out, err := proto.Marshal(groupChangeActions)
if err != nil {
return err
}
if err != nil {
return err
}
err = PatchGroupV2(out, auth)
if err != nil {
log.Debugln("[textsecure] CreateRequestForGroup2", uuid, err)
return nil, err
}
return groupChangeActions, nil
g.JoinStatus = GroupV2JoinsStatusMember
g.UpdateGroupFromServer()
return nil
}
func (g *GroupV2) EncryptUUID(uuid []byte) ([]byte, error) {
if g.cipher == nil {
groupSecretParams, err := zkgroup.NewGroupSecretParams(g.MasterKey)
if err != nil {
return nil, err
}
g.cipher = zkgroup.NewClientZkGroupCipher(groupSecretParams)
}
return g.cipher.EncryptUUID(uuid)
}

func (g *GroupV2) findMemberByUuid(uuid string) (*signalservice.Member, error) {
log.Debugln(len(g.GroupContext.PendingMembers))
for _, member := range g.GroupContext.PendingMembers {
d, err := g.decryptUUID(member.Member.UserId)
if err != nil {
log.Debugln(err)
return nil, err
} else {
mUUID := HexToUUID(idToHex(d))
log.Debugln(uuid, mUUID)
if mUUID == uuid {
return &signalservice.Member{
UserId: member.Member.UserId,
Expand Down
31 changes: 30 additions & 1 deletion groupsv2/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ package groupsv2
import (
"encoding/json"
"fmt"
"io/ioutil"
"time"

signalservice "github.com/signal-golang/textsecure/protobuf"
transport "github.com/signal-golang/textsecure/transport"
"google.golang.org/protobuf/proto"

log "github.com/sirupsen/logrus"
)

const (
GROUPSV2_CREDENTIAL = "/v1/certificate/group/%d/%d"
GROUPSV2_TOKEN = "/v1/groups/token"
)

type GroupCredentials struct {
Expand All @@ -21,6 +26,9 @@ type GroupCredential struct {
Credential []byte
RedemptionTime int64
}
type GroupExternalCredential struct {
Token []byte `json:"token"`
}

var Credentials *GroupCredentials

Expand Down Expand Up @@ -56,7 +64,7 @@ func GetCredentialForToday() (*GroupCredential, error) {
}

func GetGroupAuthCredentials(startDay int64, endDay int64) error {
log.Debugln("[textsecure][groupsv2] get groupCredentials", fmt.Sprintf(GROUPSV2_CREDENTIAL, startDay, endDay))
log.Debugln("[textsecure][groupsv2] get groupCredentials")
resp, err := transport.Transport.Get(fmt.Sprintf(GROUPSV2_CREDENTIAL, startDay, endDay))
if err != nil {
return err
Expand All @@ -70,3 +78,24 @@ func GetGroupAuthCredentials(startDay int64, endDay int64) error {
Credentials = &response
return nil
}

func GetGroupExternalCredential(credential *GroupCredential) (*signalservice.GroupExternalCredential, error) {
log.Debugln("[textsecure][groupsv2] get groupExternalCredentials")
resp, err := transport.Transport.Get(GROUPSV2_TOKEN)
if err != nil {
return nil, err
}
if resp.IsError() {
return nil, resp
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var response signalservice.GroupExternalCredential
err = proto.Unmarshal(data, &response)
if err != nil {
return nil, err
}
return &response, nil
}
9 changes: 3 additions & 6 deletions groupsv2/decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,7 @@ func (g *GroupV2) decryptGroup() (*signalservice.DecryptedGroup, error) {
}
membersList := g.GroupContext.GetMembers()

// pendingMembersList := group.GetPendingMembers()
// requestingMembersList := group.GetRequestingMembers()
// len(membersList)
decryptedMembers := []*signalservice.DecryptedMember{}
// decryptedPendingMembers = []*signalservice.DecryptedPendingMember{}
// decryptedRequestingMembers = []*signalservice.DecryptedRequestingMember{}

for _, member := range membersList {
decryptedMember, err := g.decryptMember(member)
if err == nil {
Expand All @@ -47,6 +41,7 @@ func (g *GroupV2) decryptGroup() (*signalservice.DecryptedGroup, error) {
// TODO: decrypt pending and requesting members
decryptedGroup := &signalservice.DecryptedGroup{}
title, err := g.cipher.DecryptBlob(g.GroupContext.GetTitle())
log.Debugln("[textsecure][groupsv2] decrypt group title", string(title))
if err != nil {
return nil, err
}
Expand All @@ -56,6 +51,8 @@ func (g *GroupV2) decryptGroup() (*signalservice.DecryptedGroup, error) {
}
return -1
}, string(title))
log.Debugln("[textsecure][groupsv2] decrypt group title", cleanTitle)

decryptedGroup.Title = cleanTitle
decryptedGroup.Revision = g.GroupContext.Revision
decryptedGroup.Avatar = g.GroupContext.GetAvatar()
Expand Down
12 changes: 8 additions & 4 deletions groupsv2/groupModify.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ const (
aNNOUNCEMENTS_ONLY_CHANGE_EPOCH uint32 = 3
)

func (g *GroupV2) ModifyGroup(user *entities.GroupUser, inviteLinkPasswordString string, submittedActions signalservice.GroupChange_Actions) (*entities.Resp, error) {
type ModifyGroupParams struct {
InviteLinkPassword string `form:"inviteLinkPassword,optional"`
}

func (g *GroupV2) ModifyGroup(user *entities.GroupUser, params ModifyGroupParams, submittedActions *signalservice.GroupChange_Actions) (*entities.Resp, error) {
groupChangeApplicator := GroupChangeApplicator{}
groupValidator := GroupValidator{}
// check path param
var inviteLinkPassword []byte
if len(inviteLinkPasswordString) != 0 {
if passwd, err := base64.StdEncoding.DecodeString(inviteLinkPasswordString); err != nil {
if len(params.InviteLinkPassword) != 0 {
if passwd, err := base64.StdEncoding.DecodeString(params.InviteLinkPassword); err != nil {
return nil, entities.Status(http.StatusInternalServerError, err.Error())
} else {
inviteLinkPassword = passwd
Expand Down Expand Up @@ -208,7 +212,7 @@ func (g *GroupV2) ModifyGroup(user *entities.GroupUser, inviteLinkPasswordString

submittedActions.SourceUuid = sourceUuid

bb, err := proto.Marshal(&submittedActions)
bb, err := proto.Marshal(submittedActions)
if err != nil {
return nil, entities.Status(http.StatusInternalServerError, err.Error())
}
Expand Down
41 changes: 18 additions & 23 deletions groupsv2/groupsv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,16 @@ func handleGroupChangesForGroup(groupChange *signalservice.DecryptedGroupChange,

}
func (g *GroupV2) JoinGroup() error {
err := g.UpdateGroupFromServer()
if err != nil {
return err
}
uuid, _ := uuidUtil.FromString(config.ConfigFile.UUID)
_, err := g.AddPendingMembers(uuid.Bytes()) // richtige id?
log.Errorln("[textsecure] joingroup ", err)
err = g.AddPendingMembers(uuid.Bytes())
if err != nil {
return err
}
log.Infoln("[textsecure][groupv2] joined group ", err)
return err
}
func decryptUuidOrUnknown(uuidCipherTex []byte) *[]byte {
Expand All @@ -303,7 +310,7 @@ func saveGroupV2(hexid string) error {
if err != nil {
return err
}
log.Debugln("[textsecure] save groupv2", idToPath(hexid))
log.Debugln("[textsecure][groupv2] save group", idToPath(hexid))
return ioutil.WriteFile(idToPath(hexid), b, 0600)
}

Expand Down Expand Up @@ -333,32 +340,20 @@ func basicAuth(username, password string) string {
return base64.StdEncoding.EncodeToString([]byte(auth))
}

func PatchGroupV2(groupActions *signalservice.GroupChange_Actions,
func PatchGroupV2(out []byte,
groupsV2Authorization *GroupsV2Authorization) error {
c := &signalservice.GroupChange_Actions{}
m := []byte{10, 16, 172, 94, 146, 71, 221, 126, 68, 130, 142, 143, 150, 184, 19, 17, 100, 26, 16, 2, 82, 42, 10, 40, 148, 97, 208, 9, 152, 186, 62, 179, 136, 124, 206, 228, 145, 189, 13, 222, 0, 68, 202, 214, 0, 125, 28, 38, 52, 47, 3, 92, 62, 179, 93, 17, 68, 251, 49, 239, 82, 224, 165, 0}
err := proto.Unmarshal(m, c)
if err != nil {
log.Errorln(err)
}
fmt.Printf("[textsecure] PatchGroup %+v\n", c)

out, err := proto.Marshal(groupActions)
if err != nil {
log.Errorln("[textsecure][groupsv2] Failed to encode address groupActions:", err)
return err
}
resp, err := transport.StorageTransport.PatchWithAuth(GROUPSV2_GROUP, out, "application/x-protobuf", "Basic "+basicAuth(groupsV2Authorization.Username, groupsV2Authorization.Password))
if err != nil {
log.Errorln("[textsecure][groupsv2] Failed to encode address groupActions2:", err)

return err
}
// if resp.isError() {
// log.Errorln("Failed to encode address groupActions3:", err)
// return resp
// }
log.Infoln("[textsecure][groupsv2] patch project:", resp)
if resp.IsError() {
return resp
}
log.Infoln("[textsecure][groupsv2] patch group:", resp.Status)
if resp.IsError() {
return resp
}

return nil

Expand Down
4 changes: 4 additions & 0 deletions groupsv2/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
zkgroup "github.com/nanu-c/zkgroup"
"github.com/signal-golang/textsecure/config"
"github.com/signal-golang/textsecure/helpers"
log "github.com/sirupsen/logrus"
)

// todo handle group join requests via link
func (g *GroupV2) CheckJoinStatus() error {
log.Debugln("[textsecure][groupsv2] check join status")
found := false
if g.DecryptedGroup != nil {
for _, m := range g.DecryptedGroup.Members {
Expand All @@ -31,6 +33,8 @@ func (g *GroupV2) CheckJoinStatus() error {
} else {
g.JoinStatus = GroupV2JoinsStatusInvite
}
log.Debugln("[textsecure][groupsv2] check join status is", g.JoinStatus)

return nil
}

Expand Down
2 changes: 0 additions & 2 deletions transport/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,13 +332,11 @@ func (ht *httpTransporter) PatchWithAuth(url string, body []byte, ct string, aut
if err != nil {
return nil, err
}
cookies := resp.Header.Get("Set-Cookie")

r := &response{}
if resp != nil {
r.Status = resp.StatusCode
r.Body = resp.Body
r.Cookies = cookies
}

log.Debugf("[textsecure] PATCH with auth %s %d\n", url, r.Status)
Expand Down

0 comments on commit 4676815

Please sign in to comment.