diff --git a/server/channels/app/remote_cluster.go b/server/channels/app/remote_cluster.go index 3aa338a0ee..ca469cc016 100644 --- a/server/channels/app/remote_cluster.go +++ b/server/channels/app/remote_cluster.go @@ -202,6 +202,7 @@ func (a *App) CreateRemoteClusterInvite(remoteId, siteURL, token, password strin RemoteId: remoteId, SiteURL: siteURL, Token: token, + Version: 2, } if err := invite.IsValid(); err != nil { diff --git a/server/platform/services/remotecluster/invitation.go b/server/platform/services/remotecluster/invitation.go index efa1e509d3..a973532790 100644 --- a/server/platform/services/remotecluster/invitation.go +++ b/server/platform/services/remotecluster/invitation.go @@ -13,13 +13,21 @@ import ( // AcceptInvitation is called when accepting an invitation to connect with a remote cluster. func (rcs *Service) AcceptInvitation(invite *model.RemoteClusterInvite, name string, displayName string, creatorId string, siteURL string, defaultTeamId string) (*model.RemoteCluster, error) { + // Generate new token for RemoteToken only if invite version is 2 or greater + var remoteToken string + if invite.Version >= 2 { + remoteToken = model.NewId() // Generate new token for v2+ protocol + } else { + remoteToken = invite.Token // Use the token from the invite for backwards compatibility + } + rc := &model.RemoteCluster{ RemoteId: invite.RemoteId, Name: name, DisplayName: displayName, DefaultTeamId: defaultTeamId, Token: model.NewId(), - RemoteToken: invite.Token, + RemoteToken: remoteToken, SiteURL: invite.SiteURL, CreatorId: creatorId, } @@ -37,6 +45,11 @@ func (rcs *Service) AcceptInvitation(invite *model.RemoteClusterInvite, name str url := fmt.Sprintf("%s/%s", rcSaved.SiteURL, ConfirmInviteURL) + // for the invite confirm message, we need to use the token that + // the originating server sent in the invite instead of the one + // we're storing as a refresh + rc.RemoteToken = invite.Token + resp, err := rcs.sendFrameToRemote(PingTimeout, rc, frame, url) if err != nil { rcs.server.GetStore().RemoteCluster().Delete(rcSaved.RemoteId) @@ -63,9 +76,11 @@ func (rcs *Service) AcceptInvitation(invite *model.RemoteClusterInvite, name str func makeConfirmFrame(rc *model.RemoteCluster, siteURL string) (*model.RemoteClusterFrame, error) { confirm := model.RemoteClusterInvite{ - RemoteId: rc.RemoteId, - SiteURL: siteURL, - Token: rc.Token, + RemoteId: rc.RemoteId, + SiteURL: siteURL, + Token: rc.Token, + RefreshedToken: rc.RemoteToken, + Version: 2, } confirmRaw, err := json.Marshal(confirm) if err != nil { diff --git a/server/platform/services/remotecluster/recv.go b/server/platform/services/remotecluster/recv.go index b98cfa8b31..85fa060b58 100644 --- a/server/platform/services/remotecluster/recv.go +++ b/server/platform/services/remotecluster/recv.go @@ -69,6 +69,11 @@ func (rcs *Service) ReceiveInviteConfirmation(confirm model.RemoteClusterInvite) rc.SiteURL = confirm.SiteURL rc.RemoteToken = confirm.Token + // If the accepting cluster sent a RefreshedToken (its RemoteToken), set it as our Token + if confirm.Version >= 2 && confirm.RefreshedToken != "" { + rc.Token = confirm.RefreshedToken + } + rcUpdated, err := store.Update(rc) if err != nil { return nil, fmt.Errorf("cannot apply invite confirmation for remote %s: %w", confirm.RemoteId, err) diff --git a/server/public/model/remote_cluster.go b/server/public/model/remote_cluster.go index 2dde48b4fd..6d51d12d1a 100644 --- a/server/public/model/remote_cluster.go +++ b/server/public/model/remote_cluster.go @@ -363,10 +363,12 @@ type RemoteClusterPing struct { // RemoteClusterInvite represents an invitation to establish a simple trust with a remote cluster. type RemoteClusterInvite struct { - RemoteId string `json:"remote_id"` - RemoteTeamId string `json:"remote_team_id"` // Deprecated: this field is no longer used. It's only kept for backwards compatibility. - SiteURL string `json:"site_url"` - Token string `json:"token"` + RemoteId string `json:"remote_id"` + RemoteTeamId string `json:"remote_team_id"` // Deprecated: this field is no longer used. It's only kept for backwards compatibility. + SiteURL string `json:"site_url"` + Token string `json:"token"` + RefreshedToken string `json:"refreshed_token,omitempty"` // New token generated by the remote cluster when accepting an invitation + Version int `json:"version,omitempty"` } func (rci *RemoteClusterInvite) IsValid() *AppError { diff --git a/server/public/model/remote_cluster_test.go b/server/public/model/remote_cluster_test.go index 497882ba87..d9689e3295 100644 --- a/server/public/model/remote_cluster_test.go +++ b/server/public/model/remote_cluster_test.go @@ -160,9 +160,11 @@ func TestRemoteClusterInviteEncryption(t *testing.T) { func makeInvite(url string) RemoteClusterInvite { return RemoteClusterInvite{ - RemoteId: NewId(), - SiteURL: url, - Token: NewId(), + RemoteId: NewId(), + SiteURL: url, + Token: NewId(), + RefreshedToken: NewId(), + Version: 2, } }