Move DeviceIdentity and Fingerprint to id package

This commit is contained in:
Tulir Asokan 2022-07-05 11:56:45 +03:00
commit d1d7f999f7
18 changed files with 119 additions and 111 deletions

View file

@ -93,7 +93,7 @@ func (helper *CryptoHelper) Init() error {
return helper.mach.Load()
}
func (helper *CryptoHelper) allowKeyShare(device *crypto.DeviceIdentity, info event.RequestedKeyInfo) *crypto.KeyShareRejection {
func (helper *CryptoHelper) allowKeyShare(device *id.Device, info event.RequestedKeyInfo) *crypto.KeyShareRejection {
cfg := helper.bridge.Config.Bridge.GetEncryptionConfig()
if !cfg.AllowKeySharing {
return &crypto.KeyShareRejectNoResponse

View file

@ -33,7 +33,7 @@ var (
ErrMismatchingMasterKeyMAC = errors.New("mismatching cross-signing master key MAC")
)
func (mach *OlmMachine) fetchMasterKey(device *DeviceIdentity, content *event.VerificationMacEventContent, verState *verificationState, transactionID string) (id.Ed25519, error) {
func (mach *OlmMachine) fetchMasterKey(device *id.Device, content *event.VerificationMacEventContent, verState *verificationState, transactionID string) (id.Ed25519, error) {
crossSignKeys, err := mach.CryptoStore.GetCrossSigningKeys(device.UserID)
if err != nil {
return "", fmt.Errorf("failed to fetch cross-signing keys: %w", err)
@ -138,7 +138,7 @@ func (mach *OlmMachine) SignOwnMasterKey() error {
}
// SignOwnDevice creates a cross-signing signature for a device belonging to the current user and uploads it to the server.
func (mach *OlmMachine) SignOwnDevice(device *DeviceIdentity) error {
func (mach *OlmMachine) SignOwnDevice(device *id.Device) error {
if device.UserID != mach.Client.UserID {
return ErrCantSignOtherDevice
} else if mach.CrossSigningKeys == nil || mach.CrossSigningKeys.SelfSigningKey == nil {
@ -176,7 +176,7 @@ func (mach *OlmMachine) SignOwnDevice(device *DeviceIdentity) error {
// getFullDeviceKeys gets the full device keys object for the given device.
// This is used because we don't cache some of the details like list of algorithms and unsupported key types.
func (mach *OlmMachine) getFullDeviceKeys(device *DeviceIdentity) (*mautrix.DeviceKeys, error) {
func (mach *OlmMachine) getFullDeviceKeys(device *id.Device) (*mautrix.DeviceKeys, error) {
devicesKeys, err := mach.Client.QueryKeys(&mautrix.ReqQueryKeys{
DeviceKeys: mautrix.DeviceKeysRequest{
device.UserID: mautrix.DeviceIDList{device.DeviceID},

View file

@ -55,7 +55,7 @@ func getOlmMachine(t *testing.T) *OlmMachine {
func TestTrustOwnDevice(t *testing.T) {
m := getOlmMachine(t)
ownDevice := &DeviceIdentity{
ownDevice := &id.Device{
UserID: m.Client.UserID,
DeviceID: "device",
SigningKey: id.Ed25519("deviceKey"),
@ -109,7 +109,7 @@ func TestTrustOtherUser(t *testing.T) {
func TestTrustOtherDevice(t *testing.T) {
m := getOlmMachine(t)
otherUser := id.UserID("@user")
theirDevice := &DeviceIdentity{
theirDevice := &id.Device{
UserID: otherUser,
DeviceID: "theirDevice",
SigningKey: id.Ed25519("theirDeviceKey"),

View file

@ -12,7 +12,7 @@ import (
)
// ResolveTrust resolves the trust state of the device from cross-signing.
func (mach *OlmMachine) ResolveTrust(device *DeviceIdentity) id.TrustState {
func (mach *OlmMachine) ResolveTrust(device *id.Device) id.TrustState {
if device.Trust == id.TrustStateVerified || device.Trust == id.TrustStateBlacklisted {
return device.Trust
}
@ -57,7 +57,7 @@ func (mach *OlmMachine) ResolveTrust(device *DeviceIdentity) id.TrustState {
}
// IsDeviceTrusted returns whether a device has been determined to be trusted either through verification or cross-signing.
func (mach *OlmMachine) IsDeviceTrusted(device *DeviceIdentity) bool {
func (mach *OlmMachine) IsDeviceTrusted(device *id.Device) bool {
switch mach.ResolveTrust(device) {
case id.TrustStateVerified, id.TrustStateCrossSignedTOFU, id.TrustStateCrossSignedVerified:
return true

View file

@ -55,7 +55,7 @@ func (mach *OlmMachine) DecryptMegolmEvent(evt *event.Event) (*event.Event, erro
var trustLevel id.TrustState
var forwardedKeys bool
var device *DeviceIdentity
var device *id.Device
ownSigningKey, ownIdentityKey := mach.account.Keys()
if sess.SigningKey == ownSigningKey && sess.SenderKey == ownIdentityKey && len(sess.ForwardingChains) == 0 {
trustLevel = id.TrustStateVerified

View file

@ -24,7 +24,7 @@ var (
InvalidKeySignature = errors.New("invalid signature on device keys")
)
func (mach *OlmMachine) LoadDevices(user id.UserID) map[id.DeviceID]*DeviceIdentity {
func (mach *OlmMachine) LoadDevices(user id.UserID) map[id.DeviceID]*id.Device {
return mach.fetchKeys([]id.UserID{user}, "", true)[user]
}
@ -65,7 +65,7 @@ func (mach *OlmMachine) storeDeviceSelfSignatures(userID id.UserID, deviceID id.
}
}
func (mach *OlmMachine) fetchKeys(users []id.UserID, sinceToken string, includeUntracked bool) (data map[id.UserID]map[id.DeviceID]*DeviceIdentity) {
func (mach *OlmMachine) fetchKeys(users []id.UserID, sinceToken string, includeUntracked bool) (data map[id.UserID]map[id.DeviceID]*id.Device) {
req := &mautrix.ReqQueryKeys{
DeviceKeys: mautrix.DeviceKeysRequest{},
Timeout: 10 * 1000,
@ -90,15 +90,15 @@ func (mach *OlmMachine) fetchKeys(users []id.UserID, sinceToken string, includeU
mach.Log.Warn("Query keys failure for %s: %v", server, err)
}
mach.Log.Trace("Query key result received with %d users", len(resp.DeviceKeys))
data = make(map[id.UserID]map[id.DeviceID]*DeviceIdentity)
data = make(map[id.UserID]map[id.DeviceID]*id.Device)
for userID, devices := range resp.DeviceKeys {
delete(req.DeviceKeys, userID)
newDevices := make(map[id.DeviceID]*DeviceIdentity)
newDevices := make(map[id.DeviceID]*id.Device)
existingDevices, err := mach.CryptoStore.GetDevices(userID)
if err != nil {
mach.Log.Warn("Failed to get existing devices for %s: %v", userID, err)
existingDevices = make(map[id.DeviceID]*DeviceIdentity)
existingDevices = make(map[id.DeviceID]*id.Device)
}
mach.Log.Trace("Updating devices for %s, got %d devices, have %d in store", userID, len(devices), len(existingDevices))
changed := false
@ -154,7 +154,7 @@ func (mach *OlmMachine) OnDevicesChanged(userID id.UserID) {
}
}
func (mach *OlmMachine) validateDevice(userID id.UserID, deviceID id.DeviceID, deviceKeys mautrix.DeviceKeys, existing *DeviceIdentity) (*DeviceIdentity, error) {
func (mach *OlmMachine) validateDevice(userID id.UserID, deviceID id.DeviceID, deviceKeys mautrix.DeviceKeys, existing *id.Device) (*id.Device, error) {
if deviceID != deviceKeys.DeviceID {
return nil, MismatchingDeviceID
} else if userID != deviceKeys.UserID {
@ -185,7 +185,7 @@ func (mach *OlmMachine) validateDevice(userID id.UserID, deviceID id.DeviceID, d
name = string(deviceID)
}
return &DeviceIdentity{
return &id.Device{
UserID: userID,
DeviceID: deviceID,
IdentityKey: identityKey,

View file

@ -93,7 +93,7 @@ func (mach *OlmMachine) newOutboundGroupSession(roomID id.RoomID) *OutboundGroup
type deviceSessionWrapper struct {
session *OlmSession
identity *DeviceIdentity
identity *id.Device
}
// ShareGroupSession shares a group session for a specific room with all the devices of the given user list.
@ -115,8 +115,8 @@ func (mach *OlmMachine) ShareGroupSession(roomID id.RoomID, users []id.UserID) e
withheldCount := 0
toDeviceWithheld := &mautrix.ReqSendToDevice{Messages: make(map[id.UserID]map[id.DeviceID]*event.Content)}
olmSessions := make(map[id.UserID]map[id.DeviceID]deviceSessionWrapper)
missingSessions := make(map[id.UserID]map[id.DeviceID]*DeviceIdentity)
missingUserSessions := make(map[id.DeviceID]*DeviceIdentity)
missingSessions := make(map[id.UserID]map[id.DeviceID]*id.Device)
missingUserSessions := make(map[id.DeviceID]*id.Device)
var fetchKeys []id.UserID
for _, userID := range users {
@ -137,7 +137,7 @@ func (mach *OlmMachine) ShareGroupSession(roomID id.RoomID, users []id.UserID) e
withheldCount += len(toDeviceWithheld.Messages[userID])
if len(missingUserSessions) > 0 {
missingSessions[userID] = missingUserSessions
missingUserSessions = make(map[id.DeviceID]*DeviceIdentity)
missingUserSessions = make(map[id.DeviceID]*id.Device)
}
if len(toDeviceWithheld.Messages[userID]) == 0 {
delete(toDeviceWithheld.Messages, userID)
@ -234,7 +234,7 @@ func (mach *OlmMachine) encryptAndSendGroupSession(session *OutboundGroupSession
return err
}
func (mach *OlmMachine) findOlmSessionsForUser(session *OutboundGroupSession, userID id.UserID, devices map[id.DeviceID]*DeviceIdentity, output map[id.DeviceID]deviceSessionWrapper, withheld map[id.DeviceID]*event.Content, missingOutput map[id.DeviceID]*DeviceIdentity) {
func (mach *OlmMachine) findOlmSessionsForUser(session *OutboundGroupSession, userID id.UserID, devices map[id.DeviceID]*id.Device, output map[id.DeviceID]deviceSessionWrapper, withheld map[id.DeviceID]*event.Content, missingOutput map[id.DeviceID]*id.Device) {
for deviceID, device := range devices {
userKey := UserDevice{UserID: userID, DeviceID: deviceID}
if state := session.Users[userKey]; state != OGSNotShared {

View file

@ -16,7 +16,7 @@ import (
"maunium.net/go/mautrix/id"
)
func (mach *OlmMachine) encryptOlmEvent(session *OlmSession, recipient *DeviceIdentity, evtType event.Type, content event.Content) *event.EncryptedEventContent {
func (mach *OlmMachine) encryptOlmEvent(session *OlmSession, recipient *id.Device, evtType event.Type, content event.Content) *event.EncryptedEventContent {
evt := &DecryptedOlmEvent{
Sender: mach.Client.UserID,
SenderDevice: mach.Client.DeviceID,
@ -61,7 +61,7 @@ func (mach *OlmMachine) shouldCreateNewSession(identityKey id.IdentityKey) bool
return shouldUnwedge
}
func (mach *OlmMachine) createOutboundSessions(input map[id.UserID]map[id.DeviceID]*DeviceIdentity) error {
func (mach *OlmMachine) createOutboundSessions(input map[id.UserID]map[id.DeviceID]*id.Device) error {
request := make(mautrix.OneTimeKeysRequest)
for userID, devices := range input {
request[userID] = make(map[id.DeviceID]id.KeyAlgorithm)

View file

@ -160,7 +160,7 @@ func (mach *OlmMachine) importForwardedRoomKey(evt *DecryptedOlmEvent, content *
return true
}
func (mach *OlmMachine) rejectKeyRequest(rejection KeyShareRejection, device *DeviceIdentity, request event.RequestedKeyInfo) {
func (mach *OlmMachine) rejectKeyRequest(rejection KeyShareRejection, device *id.Device, request event.RequestedKeyInfo) {
if rejection.Code == "" {
// If the rejection code is empty, it means don't share keys, but also don't tell the requester.
return
@ -183,7 +183,7 @@ func (mach *OlmMachine) rejectKeyRequest(rejection KeyShareRejection, device *De
}
}
func (mach *OlmMachine) defaultAllowKeyShare(device *DeviceIdentity, _ event.RequestedKeyInfo) *KeyShareRejection {
func (mach *OlmMachine) defaultAllowKeyShare(device *id.Device, _ event.RequestedKeyInfo) *KeyShareRejection {
if mach.Client.UserID != device.UserID {
mach.Log.Debug("Ignoring key request from a different user (%s)", device.UserID)
return &KeyShareRejectOtherUser

View file

@ -41,11 +41,11 @@ type OlmMachine struct {
SendKeysMinTrust id.TrustState
ShareKeysMinTrust id.TrustState
AllowKeyShare func(*DeviceIdentity, event.RequestedKeyInfo) *KeyShareRejection
AllowKeyShare func(*id.Device, event.RequestedKeyInfo) *KeyShareRejection
DefaultSASTimeout time.Duration
// AcceptVerificationFrom determines whether the machine will accept verification requests from this device.
AcceptVerificationFrom func(string, *DeviceIdentity, id.RoomID) (VerificationRequestResponse, VerificationHooks)
AcceptVerificationFrom func(string, *id.Device, id.RoomID) (VerificationRequestResponse, VerificationHooks)
account *OlmAccount
@ -91,7 +91,7 @@ func NewOlmMachine(client *mautrix.Client, log Logger, cryptoStore Store, stateS
ShareKeysMinTrust: id.TrustStateCrossSignedTOFU,
DefaultSASTimeout: 10 * time.Minute,
AcceptVerificationFrom: func(string, *DeviceIdentity, id.RoomID) (VerificationRequestResponse, VerificationHooks) {
AcceptVerificationFrom: func(string, *id.Device, id.RoomID) (VerificationRequestResponse, VerificationHooks) {
// Reject requests by default. Users need to override this to return appropriate verification hooks.
return RejectRequest, nil
},
@ -143,28 +143,19 @@ func (mach *OlmMachine) timeTrace(thing, trace string, expectedDuration time.Dur
}
}
func Fingerprint(signingKey id.SigningKey) string {
spacedSigningKey := make([]byte, len(signingKey)+(len(signingKey)-1)/4)
var ptr = 0
for i, chr := range signingKey {
spacedSigningKey[ptr] = byte(chr)
ptr++
if i%4 == 3 {
spacedSigningKey[ptr] = ' '
ptr++
}
}
return string(spacedSigningKey)
// Deprecated: moved to SigningKey.Fingerprint
func Fingerprint(key id.SigningKey) string {
return key.Fingerprint()
}
// Fingerprint returns the fingerprint of the Olm account that can be used for non-interactive verification.
func (mach *OlmMachine) Fingerprint() string {
return Fingerprint(mach.account.SigningKey())
return mach.account.SigningKey().Fingerprint()
}
// OwnIdentity returns this device's DeviceIdentity struct
func (mach *OlmMachine) OwnIdentity() *DeviceIdentity {
return &DeviceIdentity{
func (mach *OlmMachine) OwnIdentity() *id.Device {
return &id.Device{
UserID: mach.Client.UserID,
DeviceID: mach.Client.DeviceID,
IdentityKey: mach.account.IdentityKey(),
@ -343,7 +334,7 @@ func (mach *OlmMachine) HandleToDeviceEvent(evt *event.Event) {
// GetOrFetchDevice attempts to retrieve the device identity for the given device from the store
// and if it's not found it asks the server for it.
func (mach *OlmMachine) GetOrFetchDevice(userID id.UserID, deviceID id.DeviceID) (*DeviceIdentity, error) {
func (mach *OlmMachine) GetOrFetchDevice(userID id.UserID, deviceID id.DeviceID) (*id.Device, error) {
// get device identity
device, err := mach.CryptoStore.GetDevice(userID, deviceID)
if err != nil {
@ -365,7 +356,7 @@ func (mach *OlmMachine) GetOrFetchDevice(userID id.UserID, deviceID id.DeviceID)
// GetOrFetchDeviceByKey attempts to retrieve the device identity for the device with the given identity key from the
// store and if it's not found it asks the server for it. This returns nil if the server doesn't return a device with
// the given identity key.
func (mach *OlmMachine) GetOrFetchDeviceByKey(userID id.UserID, identityKey id.IdentityKey) (*DeviceIdentity, error) {
func (mach *OlmMachine) GetOrFetchDeviceByKey(userID id.UserID, identityKey id.IdentityKey) (*id.Device, error) {
deviceIdentity, err := mach.CryptoStore.FindDeviceByKey(userID, identityKey)
if err != nil || deviceIdentity != nil {
return deviceIdentity, err
@ -381,8 +372,8 @@ func (mach *OlmMachine) GetOrFetchDeviceByKey(userID id.UserID, identityKey id.I
}
// SendEncryptedToDevice sends an Olm-encrypted event to the given user device.
func (mach *OlmMachine) SendEncryptedToDevice(device *DeviceIdentity, evtType event.Type, content event.Content) error {
if err := mach.createOutboundSessions(map[id.UserID]map[id.DeviceID]*DeviceIdentity{
func (mach *OlmMachine) SendEncryptedToDevice(device *id.Device, evtType event.Type, content event.Content) error {
if err := mach.createOutboundSessions(map[id.UserID]map[id.DeviceID]*id.Device{
device.UserID: {
device.DeviceID: device,
},

View file

@ -83,7 +83,7 @@ func TestOlmMachineOlmMegolmSessions(t *testing.T) {
}
// store sender device identity in receiving machine store
machineIn.CryptoStore.PutDevices("user1", map[id.DeviceID]*DeviceIdentity{
machineIn.CryptoStore.PutDevices("user1", map[id.DeviceID]*id.Device{
"device1": {
UserID: "user1",
DeviceID: "device1",
@ -98,7 +98,7 @@ func TestOlmMachineOlmMegolmSessions(t *testing.T) {
machineOut.CryptoStore.AddOutboundGroupSession(megolmOutSession)
// encrypt m.room_key event with olm session
deviceIdentity := &DeviceIdentity{
deviceIdentity := &id.Device{
UserID: "user2",
DeviceID: "device2",
IdentityKey: machineIn.account.IdentityKey(),

View file

@ -445,7 +445,7 @@ func (store *SQLCryptoStore) ValidateMessageIndex(senderKey id.SenderKey, sessio
}
// GetDevices returns a map of device IDs to device identities, including the identity and signing keys, for a given user ID.
func (store *SQLCryptoStore) GetDevices(userID id.UserID) (map[id.DeviceID]*DeviceIdentity, error) {
func (store *SQLCryptoStore) GetDevices(userID id.UserID) (map[id.DeviceID]*id.Device, error) {
var ignore id.UserID
err := store.DB.QueryRow("SELECT user_id FROM crypto_tracked_user WHERE user_id=$1", userID).Scan(&ignore)
if err == sql.ErrNoRows {
@ -458,9 +458,9 @@ func (store *SQLCryptoStore) GetDevices(userID id.UserID) (map[id.DeviceID]*Devi
if err != nil {
return nil, err
}
data := make(map[id.DeviceID]*DeviceIdentity)
data := make(map[id.DeviceID]*id.Device)
for rows.Next() {
var identity DeviceIdentity
var identity id.Device
err := rows.Scan(&identity.DeviceID, &identity.IdentityKey, &identity.SigningKey, &identity.Trust, &identity.Deleted, &identity.Name)
if err != nil {
return nil, err
@ -472,8 +472,8 @@ func (store *SQLCryptoStore) GetDevices(userID id.UserID) (map[id.DeviceID]*Devi
}
// GetDevice returns the device dentity for a given user and device ID.
func (store *SQLCryptoStore) GetDevice(userID id.UserID, deviceID id.DeviceID) (*DeviceIdentity, error) {
var identity DeviceIdentity
func (store *SQLCryptoStore) GetDevice(userID id.UserID, deviceID id.DeviceID) (*id.Device, error) {
var identity id.Device
err := store.DB.QueryRow(`
SELECT identity_key, signing_key, trust, deleted, name
FROM crypto_device WHERE user_id=$1 AND device_id=$2`,
@ -491,8 +491,8 @@ func (store *SQLCryptoStore) GetDevice(userID id.UserID, deviceID id.DeviceID) (
}
// FindDeviceByKey finds a specific device by its sender key.
func (store *SQLCryptoStore) FindDeviceByKey(userID id.UserID, identityKey id.IdentityKey) (*DeviceIdentity, error) {
var identity DeviceIdentity
func (store *SQLCryptoStore) FindDeviceByKey(userID id.UserID, identityKey id.IdentityKey) (*id.Device, error) {
var identity id.Device
err := store.DB.QueryRow(`
SELECT device_id, signing_key, trust, deleted, name
FROM crypto_device WHERE user_id=$1 AND identity_key=$2`,
@ -519,14 +519,14 @@ ON CONFLICT (user_id, device_id) DO UPDATE
var deviceMassInsertTemplate = strings.ReplaceAll(deviceInsertQuery, "($1, $2, $3, $4, $5, $6, $7)", "%s")
// PutDevice stores a single device for a user, replacing it if it exists already.
func (store *SQLCryptoStore) PutDevice(userID id.UserID, device *DeviceIdentity) error {
func (store *SQLCryptoStore) PutDevice(userID id.UserID, device *id.Device) error {
_, err := store.DB.Exec(deviceInsertQuery,
userID, device.DeviceID, device.IdentityKey, device.SigningKey, device.Trust, device.Deleted, device.Name)
return err
}
// PutDevices stores the device identity information for the given user ID.
func (store *SQLCryptoStore) PutDevices(userID id.UserID, devices map[id.DeviceID]*DeviceIdentity) error {
func (store *SQLCryptoStore) PutDevices(userID id.UserID, devices map[id.DeviceID]*id.Device) error {
tx, err := store.DB.Begin()
if err != nil {
return err
@ -630,12 +630,12 @@ func (store *SQLCryptoStore) PutCrossSigningKey(userID id.UserID, usage id.Cross
}
// GetCrossSigningKeys retrieves a user's stored cross-signing keys.
func (store *SQLCryptoStore) GetCrossSigningKeys(userID id.UserID) (map[id.CrossSigningUsage]CrossSigningKey, error) {
func (store *SQLCryptoStore) GetCrossSigningKeys(userID id.UserID) (map[id.CrossSigningUsage]id.CrossSigningKey, error) {
rows, err := store.DB.Query("SELECT usage, key, first_seen_key FROM crypto_cross_signing_keys WHERE user_id=$1", userID)
if err != nil {
return nil, err
}
data := make(map[id.CrossSigningUsage]CrossSigningKey)
data := make(map[id.CrossSigningUsage]id.CrossSigningKey)
for rows.Next() {
var usage id.CrossSigningUsage
var key, first id.Ed25519
@ -643,7 +643,7 @@ func (store *SQLCryptoStore) GetCrossSigningKeys(userID id.UserID) (map[id.Cross
if err != nil {
return nil, err
}
data[usage] = CrossSigningKey{key, first}
data[usage] = id.CrossSigningKey{key, first}
}
return data, nil

View file

@ -18,26 +18,8 @@ import (
"maunium.net/go/mautrix/id"
)
// DeviceIdentity contains the identity details of a device and some additional info.
type DeviceIdentity struct {
UserID id.UserID
DeviceID id.DeviceID
IdentityKey id.Curve25519
SigningKey id.Ed25519
Trust id.TrustState
Deleted bool
Name string
}
func (device *DeviceIdentity) Fingerprint() string {
return Fingerprint(device.SigningKey)
}
type CrossSigningKey struct {
Key id.Ed25519
First id.Ed25519
}
// Deprecated: moved to id.Device
type DeviceIdentity = id.Device
var ErrGroupSessionWithheld = errors.New("group session has been withheld")
@ -111,15 +93,15 @@ type Store interface {
ValidateMessageIndex(senderKey id.SenderKey, sessionID id.SessionID, eventID id.EventID, index uint, timestamp int64) bool
// GetDevices returns a map from device ID to DeviceIdentity containing all devices of a given user.
GetDevices(id.UserID) (map[id.DeviceID]*DeviceIdentity, error)
GetDevices(id.UserID) (map[id.DeviceID]*id.Device, error)
// GetDevice returns a specific device of a given user.
GetDevice(id.UserID, id.DeviceID) (*DeviceIdentity, error)
GetDevice(id.UserID, id.DeviceID) (*id.Device, error)
// PutDevice stores a single device for a user, replacing it if it exists already.
PutDevice(id.UserID, *DeviceIdentity) error
PutDevice(id.UserID, *id.Device) error
// PutDevices overrides the stored device list for the given user with the given list.
PutDevices(id.UserID, map[id.DeviceID]*DeviceIdentity) error
PutDevices(id.UserID, map[id.DeviceID]*id.Device) error
// FindDeviceByKey finds a specific device by its identity key.
FindDeviceByKey(id.UserID, id.IdentityKey) (*DeviceIdentity, error)
FindDeviceByKey(id.UserID, id.IdentityKey) (*id.Device, error)
// FilterTrackedUsers returns a filtered version of the given list that only includes user IDs whose device lists
// have been stored with PutDevices. A user is considered tracked even if the PutDevices list was empty.
FilterTrackedUsers([]id.UserID) []id.UserID
@ -127,7 +109,7 @@ type Store interface {
// PutCrossSigningKey stores a cross-signing key of some user along with its usage.
PutCrossSigningKey(id.UserID, id.CrossSigningUsage, id.Ed25519) error
// GetCrossSigningKeys retrieves a user's stored cross-signing keys.
GetCrossSigningKeys(id.UserID) (map[id.CrossSigningUsage]CrossSigningKey, error)
GetCrossSigningKeys(id.UserID) (map[id.CrossSigningUsage]id.CrossSigningKey, error)
// PutSignature stores a signature of a cross-signing or device key along with the signer's user ID and key.
PutSignature(signedUser id.UserID, signedKey id.Ed25519, signerUser id.UserID, signerKey id.Ed25519, signature string) error
// IsKeySignedBy returns whether a cross-signing or device key is signed by the given signer.
@ -160,8 +142,8 @@ type GobStore struct {
WithheldGroupSessions map[id.RoomID]map[id.SenderKey]map[id.SessionID]*event.RoomKeyWithheldEventContent
OutGroupSessions map[id.RoomID]*OutboundGroupSession
MessageIndices map[messageIndexKey]messageIndexValue
Devices map[id.UserID]map[id.DeviceID]*DeviceIdentity
CrossSigningKeys map[id.UserID]map[id.CrossSigningUsage]CrossSigningKey
Devices map[id.UserID]map[id.DeviceID]*id.Device
CrossSigningKeys map[id.UserID]map[id.CrossSigningUsage]id.CrossSigningKey
KeySignatures map[id.UserID]map[id.Ed25519]map[id.UserID]map[id.Ed25519]string
}
@ -178,8 +160,8 @@ func NewGobStore(path string) (*GobStore, error) {
WithheldGroupSessions: make(map[id.RoomID]map[id.SenderKey]map[id.SessionID]*event.RoomKeyWithheldEventContent),
OutGroupSessions: make(map[id.RoomID]*OutboundGroupSession),
MessageIndices: make(map[messageIndexKey]messageIndexValue),
Devices: make(map[id.UserID]map[id.DeviceID]*DeviceIdentity),
CrossSigningKeys: make(map[id.UserID]map[id.CrossSigningUsage]CrossSigningKey),
Devices: make(map[id.UserID]map[id.DeviceID]*id.Device),
CrossSigningKeys: make(map[id.UserID]map[id.CrossSigningUsage]id.CrossSigningKey),
KeySignatures: make(map[id.UserID]map[id.Ed25519]map[id.UserID]map[id.Ed25519]string),
}
return gs, gs.load()
@ -427,7 +409,7 @@ func (gs *GobStore) ValidateMessageIndex(senderKey id.SenderKey, sessionID id.Se
return true
}
func (gs *GobStore) GetDevices(userID id.UserID) (map[id.DeviceID]*DeviceIdentity, error) {
func (gs *GobStore) GetDevices(userID id.UserID) (map[id.DeviceID]*id.Device, error) {
gs.lock.RLock()
devices, ok := gs.Devices[userID]
if !ok {
@ -437,7 +419,7 @@ func (gs *GobStore) GetDevices(userID id.UserID) (map[id.DeviceID]*DeviceIdentit
return devices, nil
}
func (gs *GobStore) GetDevice(userID id.UserID, deviceID id.DeviceID) (*DeviceIdentity, error) {
func (gs *GobStore) GetDevice(userID id.UserID, deviceID id.DeviceID) (*id.Device, error) {
gs.lock.RLock()
defer gs.lock.RUnlock()
devices, ok := gs.Devices[userID]
@ -451,7 +433,7 @@ func (gs *GobStore) GetDevice(userID id.UserID, deviceID id.DeviceID) (*DeviceId
return device, nil
}
func (gs *GobStore) FindDeviceByKey(userID id.UserID, identityKey id.IdentityKey) (*DeviceIdentity, error) {
func (gs *GobStore) FindDeviceByKey(userID id.UserID, identityKey id.IdentityKey) (*id.Device, error) {
gs.lock.RLock()
defer gs.lock.RUnlock()
devices, ok := gs.Devices[userID]
@ -466,11 +448,11 @@ func (gs *GobStore) FindDeviceByKey(userID id.UserID, identityKey id.IdentityKey
return nil, nil
}
func (gs *GobStore) PutDevice(userID id.UserID, device *DeviceIdentity) error {
func (gs *GobStore) PutDevice(userID id.UserID, device *id.Device) error {
gs.lock.Lock()
devices, ok := gs.Devices[userID]
if !ok {
devices = make(map[id.DeviceID]*DeviceIdentity)
devices = make(map[id.DeviceID]*id.Device)
gs.Devices[userID] = devices
}
devices[device.DeviceID] = device
@ -479,7 +461,7 @@ func (gs *GobStore) PutDevice(userID id.UserID, device *DeviceIdentity) error {
return err
}
func (gs *GobStore) PutDevices(userID id.UserID, devices map[id.DeviceID]*DeviceIdentity) error {
func (gs *GobStore) PutDevices(userID id.UserID, devices map[id.DeviceID]*id.Device) error {
gs.lock.Lock()
gs.Devices[userID] = devices
err := gs.save()
@ -505,7 +487,7 @@ func (gs *GobStore) PutCrossSigningKey(userID id.UserID, usage id.CrossSigningUs
gs.lock.RLock()
userKeys, ok := gs.CrossSigningKeys[userID]
if !ok {
userKeys = make(map[id.CrossSigningUsage]CrossSigningKey)
userKeys = make(map[id.CrossSigningUsage]id.CrossSigningKey)
gs.CrossSigningKeys[userID] = userKeys
}
existing, ok := userKeys[usage]
@ -513,7 +495,7 @@ func (gs *GobStore) PutCrossSigningKey(userID id.UserID, usage id.CrossSigningUs
existing.Key = key
userKeys[usage] = existing
} else {
userKeys[usage] = CrossSigningKey{
userKeys[usage] = id.CrossSigningKey{
Key: key,
First: key,
}
@ -523,12 +505,12 @@ func (gs *GobStore) PutCrossSigningKey(userID id.UserID, usage id.CrossSigningUs
return err
}
func (gs *GobStore) GetCrossSigningKeys(userID id.UserID) (map[id.CrossSigningUsage]CrossSigningKey, error) {
func (gs *GobStore) GetCrossSigningKeys(userID id.UserID) (map[id.CrossSigningUsage]id.CrossSigningKey, error) {
gs.lock.RLock()
defer gs.lock.RUnlock()
keys, ok := gs.CrossSigningKeys[userID]
if !ok {
return map[id.CrossSigningUsage]CrossSigningKey{}, nil
return map[id.CrossSigningUsage]id.CrossSigningKey{}, nil
}
return keys, nil
}

View file

@ -231,11 +231,11 @@ func TestStoreDevices(t *testing.T) {
defer cleanup()
for storeName, store := range stores {
t.Run(storeName, func(t *testing.T) {
deviceMap := make(map[id.DeviceID]*DeviceIdentity)
deviceMap := make(map[id.DeviceID]*id.Device)
for i := 0; i < 17; i++ {
iStr := strconv.Itoa(i)
acc := NewOlmAccount()
deviceMap[id.DeviceID("dev"+iStr)] = &DeviceIdentity{
deviceMap[id.DeviceID("dev"+iStr)] = &id.Device{
UserID: "user1",
DeviceID: id.DeviceID("dev" + iStr),
IdentityKey: acc.IdentityKey(),

View file

@ -40,7 +40,7 @@ var (
type VerificationHooks interface {
// VerifySASMatch receives the generated SAS and its method, as well as the device that is being verified.
// It returns whether the given SAS match with the SAS displayed on other device.
VerifySASMatch(otherDevice *DeviceIdentity, sas SASData) bool
VerifySASMatch(otherDevice *id.Device, sas SASData) bool
// VerificationMethods returns the list of supported verification methods in order of preference.
// It must contain at least the decimal method.
VerificationMethods() []VerificationMethod
@ -106,7 +106,7 @@ func (mach *OlmMachine) getPKAndKeysMAC(sas *olm.SAS, sendingUser id.UserID, sen
// verificationState holds all the information needed for the state of a SAS verification with another device.
type verificationState struct {
sas *olm.SAS
otherDevice *DeviceIdentity
otherDevice *id.Device
initiatedByUs bool
verificationStarted bool
keyReceived bool
@ -175,7 +175,7 @@ func (mach *OlmMachine) handleVerificationStart(userID id.UserID, content *event
}
}
func (mach *OlmMachine) actuallyStartVerification(userID id.UserID, content *event.VerificationStartEventContent, otherDevice *DeviceIdentity, transactionID string, timeout time.Duration, inRoomID id.RoomID) {
func (mach *OlmMachine) actuallyStartVerification(userID id.UserID, content *event.VerificationStartEventContent, otherDevice *id.Device, transactionID string, timeout time.Duration, inRoomID id.RoomID) {
if inRoomID != "" && transactionID != "" {
verState, err := mach.getTransactionState(transactionID, userID)
if err != nil {
@ -609,14 +609,14 @@ func (mach *OlmMachine) handleVerificationRequest(userID id.UserID, content *eve
// NewSimpleSASVerificationWith starts the SAS verification process with another device with a default timeout,
// a generated transaction ID and support for both emoji and decimal SAS methods.
func (mach *OlmMachine) NewSimpleSASVerificationWith(device *DeviceIdentity, hooks VerificationHooks) (string, error) {
func (mach *OlmMachine) NewSimpleSASVerificationWith(device *id.Device, hooks VerificationHooks) (string, error) {
return mach.NewSASVerificationWith(device, hooks, "", mach.DefaultSASTimeout)
}
// NewSASVerificationWith starts the SAS verification process with another device.
// If the other device accepts the verification transaction, the methods in `hooks` will be used to verify the SAS match and to complete the transaction..
// If the transaction ID is empty, a new one is generated.
func (mach *OlmMachine) NewSASVerificationWith(device *DeviceIdentity, hooks VerificationHooks, transactionID string, timeout time.Duration) (string, error) {
func (mach *OlmMachine) NewSASVerificationWith(device *id.Device, hooks VerificationHooks, transactionID string, timeout time.Duration) (string, error) {
if transactionID == "" {
transactionID = strconv.Itoa(rand.Int())
}

View file

@ -255,10 +255,10 @@ func (mach *OlmMachine) SendInRoomSASVerificationMAC(roomID id.RoomID, userID id
// NewInRoomSASVerificationWith starts the in-room SAS verification process with another user in the given room.
// It returns the generated transaction ID.
func (mach *OlmMachine) NewInRoomSASVerificationWith(inRoomID id.RoomID, userID id.UserID, hooks VerificationHooks, timeout time.Duration) (string, error) {
return mach.newInRoomSASVerificationWithInner(inRoomID, &DeviceIdentity{UserID: userID}, hooks, "", timeout)
return mach.newInRoomSASVerificationWithInner(inRoomID, &id.Device{UserID: userID}, hooks, "", timeout)
}
func (mach *OlmMachine) newInRoomSASVerificationWithInner(inRoomID id.RoomID, device *DeviceIdentity, hooks VerificationHooks, transactionID string, timeout time.Duration) (string, error) {
func (mach *OlmMachine) newInRoomSASVerificationWithInner(inRoomID id.RoomID, device *id.Device, hooks VerificationHooks, transactionID string, timeout time.Duration) (string, error) {
mach.Log.Debug("Starting new in-room verification transaction user %v", device.UserID)
request := transactionID == ""

View file

@ -107,7 +107,7 @@ type MautrixInfo struct {
TrustState id.TrustState
ForwardedKeys bool
WasEncrypted bool
TrustSource interface{}
TrustSource *id.Device
CheckpointSent bool
}

View file

@ -59,6 +59,20 @@ func (ed25519 Ed25519) String() string {
return string(ed25519)
}
func (ed25519 Ed25519) Fingerprint() string {
spacedSigningKey := make([]byte, len(ed25519)+(len(ed25519)-1)/4)
var ptr = 0
for i, chr := range ed25519 {
spacedSigningKey[ptr] = byte(chr)
ptr++
if i%4 == 3 {
spacedSigningKey[ptr] = ' '
ptr++
}
}
return string(spacedSigningKey)
}
// Curve25519 is the base64 representation of an Curve25519 public key
type Curve25519 string
type SenderKey = Curve25519
@ -112,3 +126,24 @@ func (keyID KeyID) Parse() (KeyAlgorithm, string) {
}
return KeyAlgorithm(keyID[:index]), string(keyID[index+1:])
}
// Device contains the identity details of a device and some additional info.
type Device struct {
UserID UserID
DeviceID DeviceID
IdentityKey Curve25519
SigningKey Ed25519
Trust TrustState
Deleted bool
Name string
}
func (device *Device) Fingerprint() string {
return device.SigningKey.Fingerprint()
}
type CrossSigningKey struct {
Key Ed25519
First Ed25519
}