Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ClientCreationOpts.ExtraOpts and move rust specific options to it #144

Merged
merged 1 commit into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,6 @@ func (c *LoggedClient) logPrefix() string {
return fmt.Sprintf("[%s](%s)", c.UserID(), c.Type())
}

// magic value for EnableCrossProcessRefreshLockProcessName which configures the FFI client
// according to iOS NSE.
const ProcessNameNSE string = "NSE"

// ClientCreationOpts are options to use when creating crypto clients.
//
// This contains a mixture of generic options which can be used across any client, and specific
Expand All @@ -241,13 +237,27 @@ type ClientCreationOpts struct {
// this flag and always use persistence.
PersistentStorage bool

// Rust only. If set, enables the cross process refresh lock on the FFI client with the process name provided.
EnableCrossProcessRefreshLockProcessName string
// A map containing any client-specific creation options, for use for client-specific tests.
// Any options in this map MUST BE SERIALISABLE as they may be sent over RPC boundaries.
ExtraOpts map[string]any

// Rust only. If set with EnableCrossProcessRefreshLockProcessName=ProcessNameNSE, the client will be seeded
// with a logged in session.
AccessToken string
}

// GetExtraOption is a safe way to get an extra option from ExtraOpts, with a default value if the key does not exist.
func (o *ClientCreationOpts) GetExtraOption(key string, defaultValue any) any {
if o.ExtraOpts == nil {
return defaultValue
}
val, ok := o.ExtraOpts[key]
if !ok {
return defaultValue
}
return val
}

func NewClientCreationOpts(c *client.CSAPI) ClientCreationOpts {
return ClientCreationOpts{
BaseURL: c.BaseURL,
Expand All @@ -268,8 +278,13 @@ func (o *ClientCreationOpts) Combine(other *ClientCreationOpts) {
if other.DeviceID != "" {
o.DeviceID = other.DeviceID
}
if other.EnableCrossProcessRefreshLockProcessName != "" {
o.EnableCrossProcessRefreshLockProcessName = other.EnableCrossProcessRefreshLockProcessName
if other.ExtraOpts != nil {
if o.ExtraOpts == nil {
o.ExtraOpts = make(map[string]any)
}
for k, v := range other.ExtraOpts {
o.ExtraOpts[k] = v
}
}
if other.Password != "" {
o.Password = other.Password
Expand Down
22 changes: 16 additions & 6 deletions internal/api/rust/rust.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ func SetupLogs(prefix string) {

var zero uint32

const (
OptionEnableCrossProcessRefreshLockProcessName = "EnableCrossProcessRefreshLockProcessName"
)

// magic value for EnableCrossProcessRefreshLockProcessName which configures the FFI client
// according to iOS NSE.
const ProcessNameNSE string = "NSE"

type RustRoomInfo struct {
stream *matrix_sdk_ffi.TaskHandle
room *matrix_sdk_ffi.Room
Expand Down Expand Up @@ -71,10 +79,11 @@ func NewRustClient(t ct.TestLike, opts api.ClientCreationOpts) (api.Client, erro
SlidingSyncVersionBuilder(slidingSyncVersion).
AutoEnableCrossSigning(true)
var clientSessionDelegate matrix_sdk_ffi.ClientSessionDelegate
if opts.EnableCrossProcessRefreshLockProcessName != "" {
t.Logf("enabling cross process refresh lock with proc name=%s", opts.EnableCrossProcessRefreshLockProcessName)
xprocessName := opts.GetExtraOption(OptionEnableCrossProcessRefreshLockProcessName, "").(string)
if xprocessName != "" {
t.Logf("enabling cross process refresh lock with proc name=%s", xprocessName)
clientSessionDelegate = NewMemoryClientSessionDelegate()
ab = ab.EnableCrossProcessRefreshLock(opts.EnableCrossProcessRefreshLockProcessName, clientSessionDelegate)
ab = ab.EnableCrossProcessRefreshLock(xprocessName, clientSessionDelegate)
}
// @alice:hs1, FOOBAR => alice_hs1_FOOBAR
username := strings.Replace(opts.UserID[1:], ":", "_", -1) + "_" + opts.DeviceID
Expand Down Expand Up @@ -104,7 +113,7 @@ func NewRustClient(t ct.TestLike, opts api.ClientCreationOpts) (api.Client, erro
if err := client.RestoreSession(session); err != nil {
return nil, fmt.Errorf("RestoreSession: %s", err)
}
if opts.EnableCrossProcessRefreshLockProcessName == api.ProcessNameNSE {
if xprocessName == ProcessNameNSE {
clientSessionDelegate.SaveSessionInKeychain(session)
t.Logf("configure NSE client with logged in user: %+v", session)
// We purposefully don't SetDelegate as it appears to be unnecessary.
Expand Down Expand Up @@ -333,8 +342,9 @@ func (c *RustClient) StartSyncing(t ct.TestLike) (stopSyncing func(), err error)
// > thread '<unnamed>' panicked at 'there is no reactor running, must be called from the context of a Tokio 1.x runtime'
// where the stack trace doesn't hit any test code, but does start at a `free_` function.
sb := c.FFIClient.SyncService()
if c.opts.EnableCrossProcessRefreshLockProcessName != "" {
sb2 := sb.WithCrossProcessLock(&c.opts.EnableCrossProcessRefreshLockProcessName)
xprocessName := c.opts.GetExtraOption(OptionEnableCrossProcessRefreshLockProcessName, "").(string)
if xprocessName != "" {
sb2 := sb.WithCrossProcessLock(&xprocessName)
sb.Destroy()
sb = sb2
}
Expand Down
137 changes: 88 additions & 49 deletions tests/rust/notification_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/matrix-org/complement-crypto/internal/api"
"github.com/matrix-org/complement-crypto/internal/api/rust"
"github.com/matrix-org/complement-crypto/internal/cc"
"github.com/matrix-org/complement-crypto/internal/deploy/callback"
"github.com/matrix-org/complement-crypto/internal/deploy/mitm"
Expand Down Expand Up @@ -60,8 +61,10 @@ func testNSEReceive(t *testing.T, numMsgsBefore, numMsgsAfter int) {
alice := tc.MustLoginClient(t, &cc.ClientCreationRequest{
User: tc.Alice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
},
})
alice.Logf(t, "syncing and sending dummy message to ensure e2ee keys are uploaded")
Expand All @@ -83,9 +86,11 @@ func testNSEReceive(t *testing.T, numMsgsBefore, numMsgsAfter int) {
User: tc.Alice,
Multiprocess: true,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: api.ProcessNameNSE,
AccessToken: accessToken,
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: rust.ProcessNameNSE,
},
AccessToken: accessToken,
},
}) // this should login already as we provided an access token
defer client.Close(t)
Expand All @@ -103,8 +108,10 @@ func TestNSEReceiveForNonPreKeyMessage(t *testing.T) {
alice := tc.MustLoginClient(t, &cc.ClientCreationRequest{
User: tc.Alice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
},
})
stopSyncing := alice.MustStartSyncing(t)
Expand All @@ -128,9 +135,11 @@ func TestNSEReceiveForNonPreKeyMessage(t *testing.T) {
client := tc.MustCreateClient(t, &cc.ClientCreationRequest{
User: tc.Alice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: api.ProcessNameNSE,
AccessToken: accessToken,
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: rust.ProcessNameNSE,
},
AccessToken: accessToken,
},
}) // this should login already as we provided an access token
defer client.Close(t)
Expand All @@ -153,8 +162,10 @@ func TestMultiprocessNSE(t *testing.T) {
alice := tc.MustLoginClient(t, &cc.ClientCreationRequest{
User: tc.Alice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
},
})
stopSyncing := alice.MustStartSyncing(t)
Expand Down Expand Up @@ -188,9 +199,11 @@ func TestMultiprocessNSE(t *testing.T) {
alice = tc.MustCreateClient(t, &cc.ClientCreationRequest{
User: tc.Alice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
AccessToken: accessToken,
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
AccessToken: accessToken,
},
}) // this should login already as we provided an access token
stopSyncing = alice.MustStartSyncing(t)
Expand All @@ -206,9 +219,11 @@ func TestMultiprocessNSE(t *testing.T) {
User: tc.Alice,
Multiprocess: true,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
AccessToken: accessToken,
EnableCrossProcessRefreshLockProcessName: api.ProcessNameNSE,
PersistentStorage: true,
AccessToken: accessToken,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
},
}) // this should login already as we provided an access token

Expand Down Expand Up @@ -244,9 +259,11 @@ func TestMultiprocessNSE(t *testing.T) {
User: tc.Alice,
Multiprocess: true,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: api.ProcessNameNSE,
AccessToken: accessToken,
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: rust.ProcessNameNSE,
},
AccessToken: accessToken,
},
})
} // else we reuse the same NSE process for bob's message
Expand Down Expand Up @@ -281,8 +298,10 @@ func TestMultiprocessNSE(t *testing.T) {
alice2 := tc.MustLoginClient(t, &cc.ClientCreationRequest{
User: newDevice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
},
})
alice2.MustLoadBackup(t, recoveryKey)
Expand All @@ -303,8 +322,10 @@ func TestMultiprocessNSEBackupKeyMacError(t *testing.T) {
alice := tc.MustLoginClient(t, &cc.ClientCreationRequest{
User: tc.Alice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
},
})
stopSyncing := alice.MustStartSyncing(t)
Expand Down Expand Up @@ -334,9 +355,11 @@ func TestMultiprocessNSEBackupKeyMacError(t *testing.T) {
alice = tc.MustCreateClient(t, &cc.ClientCreationRequest{
User: tc.Alice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
AccessToken: accessToken,
EnableCrossProcessRefreshLockProcessName: "main",
PersistentStorage: true,
AccessToken: accessToken,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
},
}) // this should login already as we provided an access token
stopSyncing = alice.MustStartSyncing(t)
Expand All @@ -352,9 +375,11 @@ func TestMultiprocessNSEBackupKeyMacError(t *testing.T) {
User: tc.Alice,
Multiprocess: true,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: api.ProcessNameNSE,
AccessToken: accessToken,
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: rust.ProcessNameNSE,
},
AccessToken: accessToken,
},
}) // this should login already as we provided an access token

Expand Down Expand Up @@ -392,8 +417,10 @@ func TestMultiprocessNSEBackupKeyMacError(t *testing.T) {
alice2 := tc.MustLoginClient(t, &cc.ClientCreationRequest{
User: newDevice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
},
})
alice2.MustLoadBackup(t, recoveryKey)
Expand All @@ -414,8 +441,10 @@ func TestMultiprocessNSEOlmSessionWedge(t *testing.T) {
alice := tc.MustLoginClient(t, &cc.ClientCreationRequest{
User: tc.Alice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
},
})
stopSyncing := alice.MustStartSyncing(t)
Expand Down Expand Up @@ -447,9 +476,11 @@ func TestMultiprocessNSEOlmSessionWedge(t *testing.T) {
alice = tc.MustCreateClient(t, &cc.ClientCreationRequest{
User: tc.Alice,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
AccessToken: accessToken,
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
AccessToken: accessToken,
},
}) // this should login already as we provided an access token
stopSyncing = alice.MustStartSyncing(t)
Expand All @@ -469,9 +500,11 @@ func TestMultiprocessNSEOlmSessionWedge(t *testing.T) {
User: tc.Alice,
Multiprocess: true,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
AccessToken: accessToken,
EnableCrossProcessRefreshLockProcessName: api.ProcessNameNSE,
PersistentStorage: true,
AccessToken: accessToken,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: rust.ProcessNameNSE,
},
},
}) // this should login already as we provided an access token

Expand Down Expand Up @@ -604,8 +637,10 @@ func TestMultiprocessInitialE2EESyncDoesntDropDeviceListUpdates(t *testing.T) {
bob := tc.MustLoginClient(t, &cc.ClientCreationRequest{
User: tc.Bob,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
},
})
stopSyncing := bob.MustStartSyncing(t)
Expand Down Expand Up @@ -636,9 +671,11 @@ func TestMultiprocessInitialE2EESyncDoesntDropDeviceListUpdates(t *testing.T) {
bob = tc.MustCreateClient(t, &cc.ClientCreationRequest{
User: tc.Bob,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
EnableCrossProcessRefreshLockProcessName: "main",
AccessToken: accessToken,
PersistentStorage: true,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: "main",
},
AccessToken: accessToken,
},
}) // this should login already as we provided an access token
stopSyncing = bob.MustStartSyncing(t)
Expand All @@ -647,9 +684,11 @@ func TestMultiprocessInitialE2EESyncDoesntDropDeviceListUpdates(t *testing.T) {
User: tc.Bob,
Multiprocess: true,
Opts: api.ClientCreationOpts{
PersistentStorage: true,
AccessToken: accessToken,
EnableCrossProcessRefreshLockProcessName: api.ProcessNameNSE,
PersistentStorage: true,
AccessToken: accessToken,
ExtraOpts: map[string]any{
rust.OptionEnableCrossProcessRefreshLockProcessName: rust.ProcessNameNSE,
},
},
}) // this should login already as we provided an access token

Expand Down
Loading