updated deps; updated healthchecks.io integration
This commit is contained in:
191
vendor/maunium.net/go/mautrix/crypto/sharing.go
generated
vendored
Normal file
191
vendor/maunium.net/go/mautrix/crypto/sharing.go
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
// Copyright (c) 2024 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.mau.fi/util/random"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Callback function to process a received secret.
|
||||
//
|
||||
// Returning true or an error will immediately return from the wait loop, returning false will continue waiting for new responses.
|
||||
type SecretReceiverFunc func(string) (bool, error)
|
||||
|
||||
func (mach *OlmMachine) GetOrRequestSecret(ctx context.Context, name id.Secret, receiver SecretReceiverFunc, timeout time.Duration) (err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
// always offer our stored secret first, if any
|
||||
secret, err := mach.CryptoStore.GetSecret(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if secret != "" {
|
||||
if ok, err := receiver(secret); ok || err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
requestID, secretChan := random.String(64), make(chan string, 5)
|
||||
mach.secretLock.Lock()
|
||||
mach.secretListeners[requestID] = secretChan
|
||||
mach.secretLock.Unlock()
|
||||
defer func() {
|
||||
mach.secretLock.Lock()
|
||||
delete(mach.secretListeners, requestID)
|
||||
mach.secretLock.Unlock()
|
||||
}()
|
||||
|
||||
// request secret from any device
|
||||
err = mach.sendToOneDevice(ctx, mach.Client.UserID, id.DeviceID("*"), event.ToDeviceSecretRequest, &event.SecretRequestEventContent{
|
||||
Action: event.SecretRequestRequest,
|
||||
RequestID: requestID,
|
||||
Name: name,
|
||||
RequestingDeviceID: mach.Client.DeviceID,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// best effort cancel request from all devices when returning
|
||||
defer func() {
|
||||
go mach.sendToOneDevice(context.Background(), mach.Client.UserID, id.DeviceID("*"), event.ToDeviceSecretRequest, &event.SecretRequestEventContent{
|
||||
Action: event.SecretRequestCancellation,
|
||||
RequestID: requestID,
|
||||
RequestingDeviceID: mach.Client.DeviceID,
|
||||
})
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case secret = <-secretChan:
|
||||
if ok, err := receiver(secret); err != nil {
|
||||
return err
|
||||
} else if ok {
|
||||
return mach.CryptoStore.PutSecret(ctx, name, secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) HandleSecretRequest(ctx context.Context, userID id.UserID, content *event.SecretRequestEventContent) {
|
||||
log := mach.machOrContextLog(ctx).With().
|
||||
Stringer("user_id", userID).
|
||||
Stringer("requesting_device_id", content.RequestingDeviceID).
|
||||
Stringer("action", content.Action).
|
||||
Str("request_id", content.RequestID).
|
||||
Stringer("secret", content.Name).
|
||||
Logger()
|
||||
|
||||
log.Trace().Msg("Handling secret request")
|
||||
|
||||
if content.Action == event.SecretRequestCancellation {
|
||||
log.Trace().Msg("Secret request cancellation is unimplemented, ignoring")
|
||||
return
|
||||
} else if content.Action != event.SecretRequestRequest {
|
||||
log.Warn().Msg("Ignoring unknown secret request action")
|
||||
return
|
||||
}
|
||||
|
||||
// immediately ignore requests from other users
|
||||
if userID != mach.Client.UserID || content.RequestingDeviceID == "" {
|
||||
log.Debug().Msg("Secret request was not from our own device, ignoring")
|
||||
return
|
||||
}
|
||||
|
||||
if content.RequestingDeviceID == mach.Client.DeviceID {
|
||||
log.Debug().Msg("Secret request was from this device, ignoring")
|
||||
return
|
||||
}
|
||||
|
||||
keys, err := mach.CryptoStore.GetCrossSigningKeys(ctx, mach.Client.UserID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to get cross signing keys from crypto store")
|
||||
return
|
||||
}
|
||||
|
||||
crossSigningKey, ok := keys[id.XSUsageSelfSigning]
|
||||
if !ok {
|
||||
log.Warn().Msg("Couldn't find self signing key to verify requesting device")
|
||||
return
|
||||
}
|
||||
|
||||
device, err := mach.GetOrFetchDevice(ctx, mach.Client.UserID, content.RequestingDeviceID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to get or fetch requesting device")
|
||||
return
|
||||
}
|
||||
|
||||
verified, err := mach.CryptoStore.IsKeySignedBy(ctx, mach.Client.UserID, device.SigningKey, mach.Client.UserID, crossSigningKey.Key)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to check if requesting device is verified")
|
||||
return
|
||||
}
|
||||
|
||||
if !verified {
|
||||
log.Warn().Msg("Requesting device is not verified, ignoring request")
|
||||
return
|
||||
}
|
||||
|
||||
secret, err := mach.CryptoStore.GetSecret(ctx, content.Name)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to get secret from store")
|
||||
return
|
||||
} else if secret != "" {
|
||||
log.Debug().Msg("Responding to secret request")
|
||||
mach.SendEncryptedToDevice(ctx, device, event.ToDeviceSecretSend, event.Content{
|
||||
Parsed: event.SecretSendEventContent{
|
||||
RequestID: content.RequestID,
|
||||
Secret: secret,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
log.Debug().Msg("No stored secret found, secret request ignored")
|
||||
}
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) receiveSecret(ctx context.Context, evt *DecryptedOlmEvent, content *event.SecretSendEventContent) {
|
||||
log := mach.machOrContextLog(ctx).With().
|
||||
Stringer("sender", evt.Sender).
|
||||
Stringer("sender_device", evt.SenderDevice).
|
||||
Str("request_id", content.RequestID).
|
||||
Logger()
|
||||
|
||||
log.Trace().Msg("Handling secret send request")
|
||||
|
||||
// immediately ignore secrets from other users
|
||||
if evt.Sender != mach.Client.UserID {
|
||||
log.Warn().Msg("Secret send was not from our own device")
|
||||
return
|
||||
} else if content.Secret == "" {
|
||||
log.Warn().Msg("We were sent an empty secret")
|
||||
return
|
||||
}
|
||||
|
||||
mach.secretLock.Lock()
|
||||
secretChan := mach.secretListeners[content.RequestID]
|
||||
mach.secretLock.Unlock()
|
||||
|
||||
if secretChan == nil {
|
||||
log.Warn().Msg("We were sent a secret we didn't request")
|
||||
return
|
||||
}
|
||||
|
||||
// secret channel is buffered and we don't want to block
|
||||
// at worst we drop _some_ of the responses
|
||||
select {
|
||||
case secretChan <- content.Secret:
|
||||
default:
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user