updated deps
This commit is contained in:
26
vendor/maunium.net/go/mautrix/CHANGELOG.md
generated
vendored
26
vendor/maunium.net/go/mautrix/CHANGELOG.md
generated
vendored
@@ -1,3 +1,29 @@
|
||||
## v0.15.3 (2023-06-16)
|
||||
|
||||
* *(synapseadmin)* Added wrappers for some Synapse admin API endpoints.
|
||||
* *(pushrules)* Implemented new `event_property_is` and `event_property_contains`
|
||||
push rule condition kinds as per MSC3758 and MSC3966.
|
||||
* *(bridge)* Moved websocket code from mautrix-imessage to enable all bridges
|
||||
to use appservice websockets easily.
|
||||
* *(bridge)* Added retrying for appservice pings.
|
||||
* *(types)* Removed unstable field for MSC3952 (intentional mentions).
|
||||
* *(client)* Deprecated `OldEventIgnorer` and added `Client.DontProcessOldEvents`
|
||||
to replace it.
|
||||
* *(client)* Added `MoveInviteState` sync handler for moving state events in
|
||||
the invite section of sync inside the invite event itself.
|
||||
* *(crypto)* Added option to not rotate keys when devices change.
|
||||
* *(crypto)* Added additional duplicate message index check if decryption fails
|
||||
because the keys had been ratcheted forward.
|
||||
* *(client)* Stabilized support for asynchronous uploads.
|
||||
* `UnstableCreateMXC` and `UnstableUploadAsync` were renamed to `CreateMXC`
|
||||
and `UploadAsync` respectively.
|
||||
* *(util/dbutil)* Added option to use a separate database connection pool for
|
||||
read-only transactions.
|
||||
* This is mostly meant for SQLite and it enables read-only transactions that
|
||||
don't lock the database, even when normal transactions are configured to
|
||||
acquire a write lock immediately.
|
||||
* *(util/dbutil)* Enabled caller info in zerolog by default.
|
||||
|
||||
## v0.15.2 (2023-05-16)
|
||||
|
||||
* *(client)* Changed member-fetching methods to clear existing member info in
|
||||
|
||||
81
vendor/maunium.net/go/mautrix/client.go
generated
vendored
81
vendor/maunium.net/go/mautrix/client.go
generated
vendored
@@ -403,7 +403,7 @@ func (cli *Client) MakeFullRequest(params FullRequest) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
if params.Handler == nil {
|
||||
params.Handler = cli.handleNormalResponse
|
||||
params.Handler = handleNormalResponse
|
||||
}
|
||||
req.Header.Set("User-Agent", cli.UserAgent)
|
||||
if len(cli.AccessToken) > 0 {
|
||||
@@ -441,7 +441,7 @@ func (cli *Client) doRetry(req *http.Request, cause error, retries int, backoff
|
||||
return cli.executeCompiledRequest(req, retries-1, backoff*2, responseJSON, handler)
|
||||
}
|
||||
|
||||
func (cli *Client) readRequestBody(req *http.Request, res *http.Response) ([]byte, error) {
|
||||
func readRequestBody(req *http.Request, res *http.Response) ([]byte, error) {
|
||||
contents, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, HTTPError{
|
||||
@@ -463,12 +463,12 @@ func closeTemp(log *zerolog.Logger, file *os.File) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) streamResponse(req *http.Request, res *http.Response, responseJSON interface{}) ([]byte, error) {
|
||||
func streamResponse(req *http.Request, res *http.Response, responseJSON interface{}) ([]byte, error) {
|
||||
log := zerolog.Ctx(req.Context())
|
||||
file, err := os.CreateTemp("", "mautrix-response-")
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("Failed to create temporary file for streaming response")
|
||||
_, err = cli.handleNormalResponse(req, res, responseJSON)
|
||||
_, err = handleNormalResponse(req, res, responseJSON)
|
||||
return nil, err
|
||||
}
|
||||
defer closeTemp(log, file)
|
||||
@@ -483,8 +483,8 @@ func (cli *Client) streamResponse(req *http.Request, res *http.Response, respons
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) handleNormalResponse(req *http.Request, res *http.Response, responseJSON interface{}) ([]byte, error) {
|
||||
if contents, err := cli.readRequestBody(req, res); err != nil {
|
||||
func handleNormalResponse(req *http.Request, res *http.Response, responseJSON interface{}) ([]byte, error) {
|
||||
if contents, err := readRequestBody(req, res); err != nil {
|
||||
return nil, err
|
||||
} else if responseJSON == nil {
|
||||
return contents, nil
|
||||
@@ -502,8 +502,8 @@ func (cli *Client) handleNormalResponse(req *http.Request, res *http.Response, r
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) handleResponseError(req *http.Request, res *http.Response) ([]byte, error) {
|
||||
contents, err := cli.readRequestBody(req, res)
|
||||
func ParseErrorResponse(req *http.Request, res *http.Response) ([]byte, error) {
|
||||
contents, err := readRequestBody(req, res)
|
||||
if err != nil {
|
||||
return contents, err
|
||||
}
|
||||
@@ -522,7 +522,7 @@ func (cli *Client) handleResponseError(req *http.Request, res *http.Response) ([
|
||||
|
||||
// parseBackoffFromResponse extracts the backoff time specified in the Retry-After header if present. See
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After.
|
||||
func (cli *Client) parseBackoffFromResponse(req *http.Request, res *http.Response, now time.Time, fallback time.Duration) time.Duration {
|
||||
func parseBackoffFromResponse(req *http.Request, res *http.Response, now time.Time, fallback time.Duration) time.Duration {
|
||||
retryAfterHeaderValue := res.Header.Get("Retry-After")
|
||||
if retryAfterHeaderValue == "" {
|
||||
return fallback
|
||||
@@ -573,14 +573,14 @@ func (cli *Client) executeCompiledRequest(req *http.Request, retries int, backof
|
||||
|
||||
if retries > 0 && cli.shouldRetry(res) {
|
||||
if res.StatusCode == http.StatusTooManyRequests {
|
||||
backoff = cli.parseBackoffFromResponse(req, res, time.Now(), backoff)
|
||||
backoff = parseBackoffFromResponse(req, res, time.Now(), backoff)
|
||||
}
|
||||
return cli.doRetry(req, fmt.Errorf("HTTP %d", res.StatusCode), retries, backoff, responseJSON, handler)
|
||||
}
|
||||
|
||||
var body []byte
|
||||
if res.StatusCode < 200 || res.StatusCode >= 300 {
|
||||
body, err = cli.handleResponseError(req, res)
|
||||
body, err = ParseErrorResponse(req, res)
|
||||
cli.LogRequestDone(req, res, nil, len(body), duration)
|
||||
} else {
|
||||
body, err = handler(req, res, responseJSON)
|
||||
@@ -657,7 +657,7 @@ func (cli *Client) FullSyncRequest(req ReqSync) (resp *RespSync, err error) {
|
||||
MaxAttempts: 1,
|
||||
}
|
||||
if req.StreamResponse {
|
||||
fullReq.Handler = cli.streamResponse
|
||||
fullReq.Handler = streamResponse
|
||||
}
|
||||
start := time.Now()
|
||||
_, err = cli.MakeFullRequest(fullReq)
|
||||
@@ -1413,10 +1413,11 @@ func (cli *Client) DownloadBytesContext(ctx context.Context, mxcURL id.ContentUR
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
// UnstableCreateMXC creates a blank Matrix content URI to allow uploading the content asynchronously later.
|
||||
// See https://github.com/matrix-org/matrix-spec-proposals/pull/2246
|
||||
func (cli *Client) UnstableCreateMXC() (*RespCreateMXC, error) {
|
||||
u, _ := url.Parse(cli.BuildURL(MediaURLPath{"unstable", "fi.mau.msc2246", "create"}))
|
||||
// CreateMXC creates a blank Matrix content URI to allow uploading the content asynchronously later.
|
||||
//
|
||||
// See https://spec.matrix.org/v1.7/client-server-api/#post_matrixmediav1create
|
||||
func (cli *Client) CreateMXC() (*RespCreateMXC, error) {
|
||||
u, _ := url.Parse(cli.BuildURL(MediaURLPath{"v1", "create"}))
|
||||
var m RespCreateMXC
|
||||
_, err := cli.MakeFullRequest(FullRequest{
|
||||
Method: http.MethodPost,
|
||||
@@ -1426,19 +1427,22 @@ func (cli *Client) UnstableCreateMXC() (*RespCreateMXC, error) {
|
||||
return &m, err
|
||||
}
|
||||
|
||||
// UnstableUploadAsync creates a blank content URI with UnstableCreateMXC, starts uploading the data in the background
|
||||
// and returns the created MXC immediately. See https://github.com/matrix-org/matrix-spec-proposals/pull/2246 for more info.
|
||||
func (cli *Client) UnstableUploadAsync(req ReqUploadMedia) (*RespCreateMXC, error) {
|
||||
resp, err := cli.UnstableCreateMXC()
|
||||
// UploadAsync creates a blank content URI with CreateMXC, starts uploading the data in the background
|
||||
// and returns the created MXC immediately.
|
||||
//
|
||||
// See https://spec.matrix.org/v1.7/client-server-api/#post_matrixmediav1create
|
||||
// and https://spec.matrix.org/v1.7/client-server-api/#put_matrixmediav3uploadservernamemediaid
|
||||
func (cli *Client) UploadAsync(req ReqUploadMedia) (*RespCreateMXC, error) {
|
||||
resp, err := cli.CreateMXC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.UnstableMXC = resp.ContentURI
|
||||
req.UploadURL = resp.UploadURL
|
||||
req.MXC = resp.ContentURI
|
||||
req.UnstableUploadURL = resp.UnstableUploadURL
|
||||
go func() {
|
||||
_, err = cli.UploadMedia(req)
|
||||
if err != nil {
|
||||
cli.Log.Error().Str("mxc", req.UnstableMXC.String()).Err(err).Msg("Async upload of media failed")
|
||||
cli.Log.Error().Str("mxc", req.MXC.String()).Err(err).Msg("Async upload of media failed")
|
||||
}
|
||||
}()
|
||||
return resp, nil
|
||||
@@ -1474,13 +1478,13 @@ type ReqUploadMedia struct {
|
||||
ContentType string
|
||||
FileName string
|
||||
|
||||
// UnstableMXC specifies an existing MXC URI which doesn't have content yet to upload into.
|
||||
// See https://github.com/matrix-org/matrix-spec-proposals/pull/2246 for more info.
|
||||
UnstableMXC id.ContentURI
|
||||
// MXC specifies an existing MXC URI which doesn't have content yet to upload into.
|
||||
// See https://spec.matrix.org/unstable/client-server-api/#put_matrixmediav3uploadservernamemediaid
|
||||
MXC id.ContentURI
|
||||
|
||||
// UploadURL specifies the URL to upload the content to (MSC3870)
|
||||
// UnstableUploadURL specifies the URL to upload the content to. MXC must also be set.
|
||||
// see https://github.com/matrix-org/matrix-spec-proposals/pull/3870 for more info
|
||||
UploadURL string
|
||||
UnstableUploadURL string
|
||||
}
|
||||
|
||||
func (cli *Client) tryUploadMediaToURL(url, contentType string, content io.Reader) (*http.Response, error) {
|
||||
@@ -1508,7 +1512,7 @@ func (cli *Client) uploadMediaToURL(data ReqUploadMedia) (*RespMediaUpload, erro
|
||||
} else {
|
||||
data.Content = nil
|
||||
}
|
||||
resp, err := cli.tryUploadMediaToURL(data.UploadURL, data.ContentType, reader)
|
||||
resp, err := cli.tryUploadMediaToURL(data.UnstableUploadURL, data.ContentType, reader)
|
||||
if err == nil {
|
||||
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
||||
// Everything is fine
|
||||
@@ -1517,10 +1521,12 @@ func (cli *Client) uploadMediaToURL(data ReqUploadMedia) (*RespMediaUpload, erro
|
||||
err = fmt.Errorf("HTTP %d", resp.StatusCode)
|
||||
}
|
||||
if retries <= 0 {
|
||||
cli.Log.Warn().Str("url", data.UploadURL).Err(err).Msg("Error uploading media to external URL, not retrying")
|
||||
cli.Log.Warn().Str("url", data.UnstableUploadURL).Err(err).
|
||||
Msg("Error uploading media to external URL, not retrying")
|
||||
return nil, err
|
||||
}
|
||||
cli.Log.Warn().Str("url", data.UploadURL).Err(err).Msg("Error uploading media to external URL, retrying")
|
||||
cli.Log.Warn().Str("url", data.UnstableUploadURL).Err(err).
|
||||
Msg("Error uploading media to external URL, retrying")
|
||||
retries--
|
||||
}
|
||||
|
||||
@@ -1529,7 +1535,7 @@ func (cli *Client) uploadMediaToURL(data ReqUploadMedia) (*RespMediaUpload, erro
|
||||
query["filename"] = data.FileName
|
||||
}
|
||||
|
||||
notifyURL := cli.BuildURLWithQuery(MediaURLPath{"unstable", "fi.mau.msc2246", "upload", data.UnstableMXC.Homeserver, data.UnstableMXC.FileID, "complete"}, query)
|
||||
notifyURL := cli.BuildURLWithQuery(MediaURLPath{"unstable", "com.beeper.msc3870", "upload", data.MXC.Homeserver, data.MXC.FileID, "complete"}, query)
|
||||
|
||||
var m *RespMediaUpload
|
||||
_, err := cli.MakeFullRequest(FullRequest{
|
||||
@@ -1545,15 +1551,18 @@ func (cli *Client) uploadMediaToURL(data ReqUploadMedia) (*RespMediaUpload, erro
|
||||
}
|
||||
|
||||
// UploadMedia uploads the given data to the content repository and returns an MXC URI.
|
||||
// See https://spec.matrix.org/v1.2/client-server-api/#post_matrixmediav3upload
|
||||
// See https://spec.matrix.org/v1.7/client-server-api/#post_matrixmediav3upload
|
||||
func (cli *Client) UploadMedia(data ReqUploadMedia) (*RespMediaUpload, error) {
|
||||
if data.UploadURL != "" {
|
||||
if data.UnstableUploadURL != "" {
|
||||
if data.MXC.IsEmpty() {
|
||||
return nil, errors.New("MXC must also be set when uploading to external URL")
|
||||
}
|
||||
return cli.uploadMediaToURL(data)
|
||||
}
|
||||
u, _ := url.Parse(cli.BuildURL(MediaURLPath{"v3", "upload"}))
|
||||
method := http.MethodPost
|
||||
if !data.UnstableMXC.IsEmpty() {
|
||||
u, _ = url.Parse(cli.BuildURL(MediaURLPath{"unstable", "fi.mau.msc2246", "upload", data.UnstableMXC.Homeserver, data.UnstableMXC.FileID}))
|
||||
if !data.MXC.IsEmpty() {
|
||||
u, _ = url.Parse(cli.BuildURL(MediaURLPath{"v3", "upload", data.MXC.Homeserver, data.MXC.FileID}))
|
||||
method = http.MethodPut
|
||||
}
|
||||
if len(data.FileName) > 0 {
|
||||
|
||||
2
vendor/maunium.net/go/mautrix/crypto/cryptohelper/cryptohelper.go
generated
vendored
2
vendor/maunium.net/go/mautrix/crypto/cryptohelper/cryptohelper.go
generated
vendored
@@ -189,7 +189,7 @@ func (helper *CryptoHelper) Init() error {
|
||||
|
||||
func (helper *CryptoHelper) Close() error {
|
||||
if helper != nil && helper.dbForManagedStores != nil {
|
||||
err := helper.dbForManagedStores.RawDB.Close()
|
||||
err := helper.dbForManagedStores.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
27
vendor/maunium.net/go/mautrix/crypto/decryptmegolm.go
generated
vendored
27
vendor/maunium.net/go/mautrix/crypto/decryptmegolm.go
generated
vendored
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
@@ -163,6 +164,26 @@ func removeItem(slice []uint, item uint) ([]uint, bool) {
|
||||
|
||||
const missedIndexCutoff = 10
|
||||
|
||||
func (mach *OlmMachine) checkUndecryptableMessageIndexDuplication(ctx context.Context, sess *InboundGroupSession, evt *event.Event, content *event.EncryptedEventContent) (uint, error) {
|
||||
log := *zerolog.Ctx(ctx)
|
||||
messageIndex, decodeErr := parseMessageIndex(content.MegolmCiphertext)
|
||||
if decodeErr != nil {
|
||||
log.Warn().Err(decodeErr).Msg("Failed to parse message index to check if it's a duplicate for message that failed to decrypt")
|
||||
return 0, fmt.Errorf("%w (also failed to parse message index)", olm.UnknownMessageIndex)
|
||||
}
|
||||
firstKnown := sess.Internal.FirstKnownIndex()
|
||||
log = log.With().Uint("message_index", messageIndex).Uint32("first_known_index", firstKnown).Logger()
|
||||
if ok, err := mach.CryptoStore.ValidateMessageIndex(ctx, sess.SenderKey, content.SessionID, evt.ID, messageIndex, evt.Timestamp); err != nil {
|
||||
log.Debug().Err(err).Msg("Failed to check if message index is duplicate")
|
||||
return messageIndex, fmt.Errorf("%w (failed to check if index is duplicate; received: %d, earliest known: %d)", olm.UnknownMessageIndex, messageIndex, firstKnown)
|
||||
} else if !ok {
|
||||
log.Debug().Msg("Failed to decrypt message due to unknown index and found duplicate")
|
||||
return messageIndex, fmt.Errorf("%w %d (also failed to decrypt because earliest known index is %d)", DuplicateMessageIndex, messageIndex, firstKnown)
|
||||
}
|
||||
log.Debug().Msg("Failed to decrypt message due to unknown index, but index is not duplicate")
|
||||
return messageIndex, fmt.Errorf("%w (not duplicate index; received: %d, earliest known: %d)", olm.UnknownMessageIndex, messageIndex, firstKnown)
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) actuallyDecryptMegolmEvent(ctx context.Context, evt *event.Event, encryptionRoomID id.RoomID, content *event.EncryptedEventContent) (*InboundGroupSession, []byte, uint, error) {
|
||||
mach.megolmDecryptLock.Lock()
|
||||
defer mach.megolmDecryptLock.Unlock()
|
||||
@@ -177,11 +198,15 @@ func (mach *OlmMachine) actuallyDecryptMegolmEvent(ctx context.Context, evt *eve
|
||||
}
|
||||
plaintext, messageIndex, err := sess.Internal.Decrypt(content.MegolmCiphertext)
|
||||
if err != nil {
|
||||
if errors.Is(err, olm.UnknownMessageIndex) && mach.RatchetKeysOnDecrypt {
|
||||
messageIndex, err = mach.checkUndecryptableMessageIndexDuplication(ctx, sess, evt, content)
|
||||
return sess, nil, messageIndex, fmt.Errorf("failed to decrypt megolm event: %w", err)
|
||||
}
|
||||
return sess, nil, 0, fmt.Errorf("failed to decrypt megolm event: %w", err)
|
||||
} else if ok, err := mach.CryptoStore.ValidateMessageIndex(ctx, sess.SenderKey, content.SessionID, evt.ID, messageIndex, evt.Timestamp); err != nil {
|
||||
return sess, nil, messageIndex, fmt.Errorf("failed to check if message index is duplicate: %w", err)
|
||||
} else if !ok {
|
||||
return sess, nil, messageIndex, DuplicateMessageIndex
|
||||
return sess, nil, messageIndex, fmt.Errorf("%w %d", DuplicateMessageIndex, messageIndex)
|
||||
}
|
||||
|
||||
expectedMessageIndex := sess.RatchetSafety.NextIndex
|
||||
|
||||
3
vendor/maunium.net/go/mautrix/crypto/devicelist.go
generated
vendored
3
vendor/maunium.net/go/mautrix/crypto/devicelist.go
generated
vendored
@@ -198,6 +198,9 @@ func (mach *OlmMachine) fetchKeys(ctx context.Context, users []id.UserID, sinceT
|
||||
// This is called automatically whenever a device list change is noticed in ProcessSyncResponse and usually does
|
||||
// not need to be called manually.
|
||||
func (mach *OlmMachine) OnDevicesChanged(userID id.UserID) {
|
||||
if mach.DisableDeviceChangeKeyRotation {
|
||||
return
|
||||
}
|
||||
for _, roomID := range mach.StateStore.FindSharedRooms(userID) {
|
||||
mach.Log.Debug().
|
||||
Str("user_id", userID.String()).
|
||||
|
||||
7
vendor/maunium.net/go/mautrix/crypto/encryptmegolm.go
generated
vendored
7
vendor/maunium.net/go/mautrix/crypto/encryptmegolm.go
generated
vendored
@@ -61,7 +61,7 @@ func IsShareError(err error) bool {
|
||||
return err == SessionExpired || err == SessionNotShared || err == NoGroupSession
|
||||
}
|
||||
|
||||
func parseMessageIndex(ciphertext []byte) (uint64, error) {
|
||||
func parseMessageIndex(ciphertext []byte) (uint, error) {
|
||||
decoded := make([]byte, base64.RawStdEncoding.DecodedLen(len(ciphertext)))
|
||||
var err error
|
||||
_, err = base64.RawStdEncoding.Decode(decoded, ciphertext)
|
||||
@@ -74,7 +74,7 @@ func parseMessageIndex(ciphertext []byte) (uint64, error) {
|
||||
if read <= 0 {
|
||||
return 0, fmt.Errorf("failed to decode varint, read value %d", read)
|
||||
}
|
||||
return index, nil
|
||||
return uint(index), nil
|
||||
}
|
||||
|
||||
// EncryptMegolmEvent encrypts data with the m.megolm.v1.aes-sha2 algorithm.
|
||||
@@ -102,6 +102,7 @@ func (mach *OlmMachine) EncryptMegolmEvent(ctx context.Context, roomID id.RoomID
|
||||
Str("event_type", evtType.Type).
|
||||
Str("room_id", roomID.String()).
|
||||
Str("session_id", session.ID().String()).
|
||||
Uint("expected_index", session.Internal.MessageIndex()).
|
||||
Logger()
|
||||
log.Trace().Msg("Encrypting event...")
|
||||
ciphertext, err := session.Encrypt(plaintext)
|
||||
@@ -112,7 +113,7 @@ func (mach *OlmMachine) EncryptMegolmEvent(ctx context.Context, roomID id.RoomID
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("Failed to get megolm message index of encrypted event")
|
||||
} else {
|
||||
log = log.With().Uint64("message_index", idx).Logger()
|
||||
log = log.With().Uint("message_index", idx).Logger()
|
||||
}
|
||||
log.Debug().Msg("Encrypted event successfully")
|
||||
err = mach.CryptoStore.UpdateOutboundGroupSession(session)
|
||||
|
||||
2
vendor/maunium.net/go/mautrix/crypto/machine.go
generated
vendored
2
vendor/maunium.net/go/mautrix/crypto/machine.go
generated
vendored
@@ -73,6 +73,8 @@ type OlmMachine struct {
|
||||
RatchetKeysOnDecrypt bool
|
||||
DeleteFullyUsedKeysOnDecrypt bool
|
||||
DeleteKeysOnDeviceDelete bool
|
||||
|
||||
DisableDeviceChangeKeyRotation bool
|
||||
}
|
||||
|
||||
// StateStore is used by OlmMachine to get room state information that's needed for encryption.
|
||||
|
||||
6
vendor/maunium.net/go/mautrix/crypto/olm/inboundgroupsession.go
generated
vendored
6
vendor/maunium.net/go/mautrix/crypto/olm/inboundgroupsession.go
generated
vendored
@@ -230,12 +230,14 @@ func (s *InboundGroupSession) Decrypt(message []byte) ([]byte, uint, error) {
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
messageCopy := make([]byte, len(message))
|
||||
copy(messageCopy, message)
|
||||
plaintext := make([]byte, decryptMaxPlaintextLen)
|
||||
var messageIndex uint32
|
||||
r := C.olm_group_decrypt(
|
||||
(*C.OlmInboundGroupSession)(s.int),
|
||||
(*C.uint8_t)(&message[0]),
|
||||
C.size_t(len(message)),
|
||||
(*C.uint8_t)(&messageCopy[0]),
|
||||
C.size_t(len(messageCopy)),
|
||||
(*C.uint8_t)(&plaintext[0]),
|
||||
C.size_t(len(plaintext)),
|
||||
(*C.uint32_t)(&messageIndex))
|
||||
|
||||
5
vendor/maunium.net/go/mautrix/crypto/olm/session.go
generated
vendored
5
vendor/maunium.net/go/mautrix/crypto/olm/session.go
generated
vendored
@@ -326,12 +326,13 @@ func (s *Session) Decrypt(message string, msgType id.OlmMsgType) ([]byte, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messageCopy := []byte(message)
|
||||
plaintext := make([]byte, decryptMaxPlaintextLen)
|
||||
r := C.olm_decrypt(
|
||||
(*C.OlmSession)(s.int),
|
||||
C.size_t(msgType),
|
||||
unsafe.Pointer(&([]byte(message))[0]),
|
||||
C.size_t(len(message)),
|
||||
unsafe.Pointer(&(messageCopy)[0]),
|
||||
C.size_t(len(messageCopy)),
|
||||
unsafe.Pointer(&plaintext[0]),
|
||||
C.size_t(len(plaintext)))
|
||||
if r == errorVal() {
|
||||
|
||||
4
vendor/maunium.net/go/mautrix/error.go
generated
vendored
4
vendor/maunium.net/go/mautrix/error.go
generated
vendored
@@ -95,9 +95,9 @@ func (e HTTPError) Error() string {
|
||||
return fmt.Sprintf("failed to %s %s: %s (HTTP %d): %s", e.Request.Method, e.Request.URL.Path,
|
||||
e.RespError.ErrCode, e.Response.StatusCode, e.RespError.Err)
|
||||
} else {
|
||||
msg := fmt.Sprintf("failed to %s %s: %s", e.Request.Method, e.Request.URL.Path, e.Response.Status)
|
||||
msg := fmt.Sprintf("failed to %s %s: HTTP %d", e.Request.Method, e.Request.URL.Path, e.Response.StatusCode)
|
||||
if len(e.ResponseBody) > 0 {
|
||||
msg = fmt.Sprintf("%s\n%s", msg, e.ResponseBody)
|
||||
msg = fmt.Sprintf("%s: %s", msg, e.ResponseBody)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
3
vendor/maunium.net/go/mautrix/event/message.go
generated
vendored
3
vendor/maunium.net/go/mautrix/event/message.go
generated
vendored
@@ -97,8 +97,7 @@ type MessageEventContent struct {
|
||||
|
||||
FileName string `json:"filename,omitempty"`
|
||||
|
||||
Mentions *Mentions `json:"m.mentions,omitempty"`
|
||||
UnstableMentions *Mentions `json:"org.matrix.msc3952.mentions,omitempty"`
|
||||
Mentions *Mentions `json:"m.mentions,omitempty"`
|
||||
|
||||
// Edits and relations
|
||||
NewContent *MessageEventContent `json:"m.new_content,omitempty"`
|
||||
|
||||
118
vendor/maunium.net/go/mautrix/pushrules/condition.go
generated
vendored
118
vendor/maunium.net/go/mautrix/pushrules/condition.go
generated
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2022 Tulir Asokan
|
||||
// Copyright (c) 2023 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
|
||||
@@ -38,9 +38,11 @@ type PushCondKind string
|
||||
|
||||
// The allowed push condition kinds as specified in https://spec.matrix.org/v1.2/client-server-api/#conditions-1
|
||||
const (
|
||||
KindEventMatch PushCondKind = "event_match"
|
||||
KindContainsDisplayName PushCondKind = "contains_display_name"
|
||||
KindRoomMemberCount PushCondKind = "room_member_count"
|
||||
KindEventMatch PushCondKind = "event_match"
|
||||
KindContainsDisplayName PushCondKind = "contains_display_name"
|
||||
KindRoomMemberCount PushCondKind = "room_member_count"
|
||||
KindEventPropertyIs PushCondKind = "event_property_is"
|
||||
KindEventPropertyContains PushCondKind = "event_property_contains"
|
||||
|
||||
// MSC3664: https://github.com/matrix-org/matrix-spec-proposals/pull/3664
|
||||
|
||||
@@ -56,6 +58,8 @@ type PushCondition struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
// The glob-style pattern to match the field against. Only applicable if kind is EventMatch.
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
// The exact value to match the field against. Only applicable if kind is EventPropertyIs or EventPropertyContains.
|
||||
Value any `json:"value,omitempty"`
|
||||
// The condition that needs to be fulfilled for RoomMemberCount-type conditions.
|
||||
// A decimal integer optionally prefixed by ==, <, >, >= or <=. Prefix "==" is assumed if no prefix found.
|
||||
MemberCountCondition string `json:"is,omitempty"`
|
||||
@@ -70,8 +74,8 @@ var MemberCountFilterRegex = regexp.MustCompile("^(==|[<>]=?)?([0-9]+)$")
|
||||
// Match checks if this condition is fulfilled for the given event in the given room.
|
||||
func (cond *PushCondition) Match(room Room, evt *event.Event) bool {
|
||||
switch cond.Kind {
|
||||
case KindEventMatch:
|
||||
return cond.matchValue(room, evt)
|
||||
case KindEventMatch, KindEventPropertyIs, KindEventPropertyContains:
|
||||
return cond.matchValue(evt)
|
||||
case KindRelatedEventMatch, KindUnstableRelatedEventMatch:
|
||||
return cond.matchRelatedEvent(room, evt)
|
||||
case KindContainsDisplayName:
|
||||
@@ -101,13 +105,13 @@ func splitWithEscaping(s string, separator, escape byte) []string {
|
||||
return tokens
|
||||
}
|
||||
|
||||
func hackyNestedGet(data map[string]interface{}, path []string) (interface{}, bool) {
|
||||
func hackyNestedGet(data map[string]any, path []string) (any, bool) {
|
||||
val, ok := data[path[0]]
|
||||
if len(path) == 1 {
|
||||
// We don't have any more path parts, return the value regardless of whether it exists or not.
|
||||
return val, ok
|
||||
} else if ok {
|
||||
if mapVal, ok := val.(map[string]interface{}); ok {
|
||||
if mapVal, ok := val.(map[string]any); ok {
|
||||
val, ok = hackyNestedGet(mapVal, path[1:])
|
||||
if ok {
|
||||
return val, true
|
||||
@@ -138,37 +142,103 @@ func stringifyForPushCondition(val interface{}) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchValue(room Room, evt *event.Event) bool {
|
||||
func (cond *PushCondition) getValue(evt *event.Event) (any, bool) {
|
||||
key, subkey, _ := strings.Cut(cond.Key, ".")
|
||||
|
||||
pattern, err := glob.Compile(cond.Pattern)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch key {
|
||||
case "type":
|
||||
return pattern.MatchString(evt.Type.String())
|
||||
return evt.Type.Type, true
|
||||
case "sender":
|
||||
return pattern.MatchString(string(evt.Sender))
|
||||
return evt.Sender.String(), true
|
||||
case "room_id":
|
||||
return pattern.MatchString(string(evt.RoomID))
|
||||
return evt.RoomID.String(), true
|
||||
case "state_key":
|
||||
if evt.StateKey == nil {
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
return pattern.MatchString(*evt.StateKey)
|
||||
return *evt.StateKey, true
|
||||
case "content":
|
||||
// Split the match key with escaping to implement https://github.com/matrix-org/matrix-spec-proposals/pull/3873
|
||||
splitKey := splitWithEscaping(subkey, '.', '\\')
|
||||
// Then do a hacky nested get that supports combining parts for the backwards-compat part of MSC3873
|
||||
val, ok := hackyNestedGet(evt.Content.Raw, splitKey)
|
||||
if !ok {
|
||||
return cond.Pattern == ""
|
||||
return hackyNestedGet(evt.Content.Raw, splitKey)
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
func numberToInt64(a any) int64 {
|
||||
switch typed := a.(type) {
|
||||
case float64:
|
||||
return int64(typed)
|
||||
case float32:
|
||||
return int64(typed)
|
||||
case int:
|
||||
return int64(typed)
|
||||
case int8:
|
||||
return int64(typed)
|
||||
case int16:
|
||||
return int64(typed)
|
||||
case int32:
|
||||
return int64(typed)
|
||||
case int64:
|
||||
return typed
|
||||
case uint:
|
||||
return int64(typed)
|
||||
case uint8:
|
||||
return int64(typed)
|
||||
case uint16:
|
||||
return int64(typed)
|
||||
case uint32:
|
||||
return int64(typed)
|
||||
case uint64:
|
||||
return int64(typed)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func valueEquals(a, b any) bool {
|
||||
// Convert floats to ints when comparing numbers (the JSON parser generates floats, but Matrix only allows integers)
|
||||
// Also allow other numeric types in case something generates events manually without json
|
||||
switch a.(type) {
|
||||
case float64, float32, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
switch b.(type) {
|
||||
case float64, float32, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
return numberToInt64(a) == numberToInt64(b)
|
||||
}
|
||||
}
|
||||
return a == b
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchValue(evt *event.Event) bool {
|
||||
val, ok := cond.getValue(evt)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
switch cond.Kind {
|
||||
case KindEventMatch, KindRelatedEventMatch, KindUnstableRelatedEventMatch:
|
||||
pattern, err := glob.Compile(cond.Pattern)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return pattern.MatchString(stringifyForPushCondition(val))
|
||||
default:
|
||||
case KindEventPropertyIs:
|
||||
return valueEquals(val, cond.Value)
|
||||
case KindEventPropertyContains:
|
||||
valArr, ok := val.([]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, item := range valArr {
|
||||
if valueEquals(item, cond.Value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
default:
|
||||
panic(fmt.Errorf("matchValue called for unknown condition kind %s", cond.Kind))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +279,7 @@ func (cond *PushCondition) matchRelatedEvent(room Room, evt *event.Event) bool {
|
||||
} else if evt = eventfulRoom.GetEvent(relatesTo.EventID); evt == nil {
|
||||
return false
|
||||
} else {
|
||||
return cond.matchValue(room, evt)
|
||||
return cond.matchValue(evt)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
6
vendor/maunium.net/go/mautrix/pushrules/rule.go
generated
vendored
6
vendor/maunium.net/go/mautrix/pushrules/rule.go
generated
vendored
@@ -134,6 +134,12 @@ func (rule *PushRule) Match(room Room, evt *event.Event) bool {
|
||||
if rule == nil || !rule.Enabled {
|
||||
return false
|
||||
}
|
||||
if rule.RuleID == ".m.rule.contains_display_name" || rule.RuleID == ".m.rule.contains_user_name" || rule.RuleID == ".m.rule.roomnotif" {
|
||||
if _, containsMentions := evt.Content.Raw["m.mentions"]; containsMentions {
|
||||
// Disable legacy mention push rules when the event contains the new mentions key
|
||||
return false
|
||||
}
|
||||
}
|
||||
switch rule.Type {
|
||||
case OverrideRule, UnderrideRule:
|
||||
return rule.matchConditions(room, evt)
|
||||
|
||||
2
vendor/maunium.net/go/mautrix/requests.go
generated
vendored
2
vendor/maunium.net/go/mautrix/requests.go
generated
vendored
@@ -21,6 +21,8 @@ const (
|
||||
AuthTypeToken AuthType = "m.login.token"
|
||||
AuthTypeDummy AuthType = "m.login.dummy"
|
||||
AuthTypeAppservice AuthType = "m.login.application_service"
|
||||
|
||||
AuthTypeSynapseJWT AuthType = "org.matrix.login.jwt"
|
||||
)
|
||||
|
||||
type IdentifierType string
|
||||
|
||||
5
vendor/maunium.net/go/mautrix/responses.go
generated
vendored
5
vendor/maunium.net/go/mautrix/responses.go
generated
vendored
@@ -108,11 +108,12 @@ type RespMediaUpload struct {
|
||||
ContentURI id.ContentURI `json:"content_uri"`
|
||||
}
|
||||
|
||||
// RespCreateMXC is the JSON response for /_matrix/media/v3/create as specified in https://github.com/matrix-org/matrix-spec-proposals/pull/2246
|
||||
// RespCreateMXC is the JSON response for https://spec.matrix.org/v1.7/client-server-api/#post_matrixmediav1create
|
||||
type RespCreateMXC struct {
|
||||
ContentURI id.ContentURI `json:"content_uri"`
|
||||
UnusedExpiresAt int `json:"unused_expires_at,omitempty"`
|
||||
UploadURL string `json:"upload_url,omitempty"`
|
||||
|
||||
UnstableUploadURL string `json:"com.beeper.msc3870.upload_url,omitempty"`
|
||||
}
|
||||
|
||||
// RespPreviewURL is the JSON response for https://spec.matrix.org/v1.2/client-server-api/#get_matrixmediav3preview_url
|
||||
|
||||
61
vendor/maunium.net/go/mautrix/sync.go
generated
vendored
61
vendor/maunium.net/go/mautrix/sync.go
generated
vendored
@@ -62,9 +62,9 @@ func (es EventSource) String() string {
|
||||
case EventSourceLeave:
|
||||
typeName = "left room " + typeName
|
||||
default:
|
||||
return fmt.Sprintf("unknown (%d)", es)
|
||||
return fmt.Sprintf("unknown (%s+%d)", typeName, es)
|
||||
}
|
||||
es &^= roomableTypes
|
||||
es &^= roomSections
|
||||
}
|
||||
if es&encryptableTypes != 0 && es&EventSourceDecrypted != 0 {
|
||||
typeName += " (decrypted)"
|
||||
@@ -72,7 +72,7 @@ func (es EventSource) String() string {
|
||||
}
|
||||
es &^= primaryTypes
|
||||
if es != 0 {
|
||||
return fmt.Sprintf("unknown (%d)", es)
|
||||
return fmt.Sprintf("unknown (%s+%d)", typeName, es)
|
||||
}
|
||||
return typeName
|
||||
}
|
||||
@@ -263,11 +263,9 @@ func (s *DefaultSyncer) GetFilterJSON(userID id.UserID) *Filter {
|
||||
return s.FilterJSON
|
||||
}
|
||||
|
||||
// OldEventIgnorer is an utility struct for bots to ignore events from before the bot joined the room.
|
||||
// OldEventIgnorer is a utility struct for bots to ignore events from before the bot joined the room.
|
||||
//
|
||||
// Create a struct and call Register with your DefaultSyncer to register the sync handler, e.g.:
|
||||
//
|
||||
// (&OldEventIgnorer{UserID: cli.UserID}).Register(cli.Syncer.(mautrix.ExtensibleSyncer))
|
||||
// Deprecated: Use Client.DontProcessOldEvents instead.
|
||||
type OldEventIgnorer struct {
|
||||
UserID id.UserID
|
||||
}
|
||||
@@ -276,9 +274,21 @@ func (oei *OldEventIgnorer) Register(syncer ExtensibleSyncer) {
|
||||
syncer.OnSync(oei.DontProcessOldEvents)
|
||||
}
|
||||
|
||||
// DontProcessOldEvents returns true if a sync response should be processed. May modify the response to remove
|
||||
// stuff that shouldn't be processed.
|
||||
func (oei *OldEventIgnorer) DontProcessOldEvents(resp *RespSync, since string) bool {
|
||||
return dontProcessOldEvents(oei.UserID, resp, since)
|
||||
}
|
||||
|
||||
// DontProcessOldEvents is a sync handler that removes rooms that the user just joined.
|
||||
// It's meant for bots to ignore events from before the bot joined the room.
|
||||
//
|
||||
// To use it, register it with your Syncer, e.g.:
|
||||
//
|
||||
// cli.Syncer.(mautrix.ExtensibleSyncer).OnSync(cli.DontProcessOldEvents)
|
||||
func (cli *Client) DontProcessOldEvents(resp *RespSync, since string) bool {
|
||||
return dontProcessOldEvents(cli.UserID, resp, since)
|
||||
}
|
||||
|
||||
func dontProcessOldEvents(userID id.UserID, resp *RespSync, since string) bool {
|
||||
if since == "" {
|
||||
return false
|
||||
}
|
||||
@@ -292,7 +302,7 @@ func (oei *OldEventIgnorer) DontProcessOldEvents(resp *RespSync, since string) b
|
||||
for roomID, roomData := range resp.Rooms.Join {
|
||||
for i := len(roomData.Timeline.Events) - 1; i >= 0; i-- {
|
||||
evt := roomData.Timeline.Events[i]
|
||||
if evt.Type == event.StateMember && evt.GetStateKey() == string(oei.UserID) {
|
||||
if evt.Type == event.StateMember && evt.GetStateKey() == string(userID) {
|
||||
membership, _ := evt.Content.Raw["membership"].(string)
|
||||
if membership == "join" {
|
||||
_, ok := resp.Rooms.Join[roomID]
|
||||
@@ -308,3 +318,34 @@ func (oei *OldEventIgnorer) DontProcessOldEvents(resp *RespSync, since string) b
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MoveInviteState is a sync handler that moves events from the state event list to the InviteRoomState in the invite event.
|
||||
//
|
||||
// To use it, register it with your Syncer, e.g.:
|
||||
//
|
||||
// cli.Syncer.(mautrix.ExtensibleSyncer).OnSync(cli.MoveInviteState)
|
||||
func (cli *Client) MoveInviteState(resp *RespSync, _ string) bool {
|
||||
for _, meta := range resp.Rooms.Invite {
|
||||
var inviteState []event.StrippedState
|
||||
var inviteEvt *event.Event
|
||||
for _, evt := range meta.State.Events {
|
||||
if evt.Type == event.StateMember && evt.GetStateKey() == cli.UserID.String() {
|
||||
inviteEvt = evt
|
||||
} else {
|
||||
evt.Type.Class = event.StateEventType
|
||||
_ = evt.Content.ParseRaw(evt.Type)
|
||||
inviteState = append(inviteState, event.StrippedState{
|
||||
Content: evt.Content,
|
||||
Type: evt.Type,
|
||||
StateKey: evt.GetStateKey(),
|
||||
Sender: evt.Sender,
|
||||
})
|
||||
}
|
||||
}
|
||||
if inviteEvt != nil {
|
||||
inviteEvt.Unsigned.InviteRoomState = inviteState
|
||||
meta.State.Events = []*event.Event{inviteEvt}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
28
vendor/maunium.net/go/mautrix/url.go
generated
vendored
28
vendor/maunium.net/go/mautrix/url.go
generated
vendored
@@ -31,7 +31,7 @@ func ParseAndNormalizeBaseURL(homeserverURL string) (*url.URL, error) {
|
||||
}
|
||||
|
||||
// BuildURL builds a URL with the given path parts
|
||||
func BuildURL(baseURL *url.URL, path ...interface{}) *url.URL {
|
||||
func BuildURL(baseURL *url.URL, path ...any) *url.URL {
|
||||
createdURL := *baseURL
|
||||
rawParts := make([]string, len(path)+1)
|
||||
rawParts[0] = strings.TrimSuffix(createdURL.RawPath, "/")
|
||||
@@ -62,30 +62,36 @@ func (cli *Client) BuildURL(urlPath PrefixableURLPath) string {
|
||||
|
||||
// BuildClientURL builds a URL with the Client's homeserver and appservice user ID set already.
|
||||
// This method also automatically prepends the client API prefix (/_matrix/client).
|
||||
func (cli *Client) BuildClientURL(urlPath ...interface{}) string {
|
||||
func (cli *Client) BuildClientURL(urlPath ...any) string {
|
||||
return cli.BuildURLWithQuery(ClientURLPath(urlPath), nil)
|
||||
}
|
||||
|
||||
type PrefixableURLPath interface {
|
||||
FullPath() []interface{}
|
||||
FullPath() []any
|
||||
}
|
||||
|
||||
type BaseURLPath []interface{}
|
||||
type BaseURLPath []any
|
||||
|
||||
func (bup BaseURLPath) FullPath() []interface{} {
|
||||
func (bup BaseURLPath) FullPath() []any {
|
||||
return bup
|
||||
}
|
||||
|
||||
type ClientURLPath []interface{}
|
||||
type ClientURLPath []any
|
||||
|
||||
func (cup ClientURLPath) FullPath() []interface{} {
|
||||
return append([]interface{}{"_matrix", "client"}, []interface{}(cup)...)
|
||||
func (cup ClientURLPath) FullPath() []any {
|
||||
return append([]any{"_matrix", "client"}, []any(cup)...)
|
||||
}
|
||||
|
||||
type MediaURLPath []interface{}
|
||||
type MediaURLPath []any
|
||||
|
||||
func (mup MediaURLPath) FullPath() []interface{} {
|
||||
return append([]interface{}{"_matrix", "media"}, []interface{}(mup)...)
|
||||
func (mup MediaURLPath) FullPath() []any {
|
||||
return append([]any{"_matrix", "media"}, []any(mup)...)
|
||||
}
|
||||
|
||||
type SynapseAdminURLPath []any
|
||||
|
||||
func (saup SynapseAdminURLPath) FullPath() []any {
|
||||
return append([]any{"_synapse", "admin"}, []any(saup)...)
|
||||
}
|
||||
|
||||
// BuildURLWithQuery builds a URL with query parameters in addition to the Client's homeserver
|
||||
|
||||
19
vendor/maunium.net/go/mautrix/util/dbutil/connlog.go
generated
vendored
19
vendor/maunium.net/go/mautrix/util/dbutil/connlog.go
generated
vendored
@@ -71,8 +71,12 @@ type loggingDB struct {
|
||||
}
|
||||
|
||||
func (ld *loggingDB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*LoggingTxn, error) {
|
||||
targetDB := ld.db.RawDB
|
||||
if opts != nil && opts.ReadOnly && ld.db.ReadOnlyDB != nil {
|
||||
targetDB = ld.db.ReadOnlyDB
|
||||
}
|
||||
start := time.Now()
|
||||
tx, err := ld.db.RawDB.BeginTx(ctx, opts)
|
||||
tx, err := targetDB.BeginTx(ctx, opts)
|
||||
ld.db.Log.QueryTiming(ctx, "Begin", "", nil, -1, time.Since(start), err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -102,7 +106,10 @@ type LoggingTxn struct {
|
||||
func (lt *LoggingTxn) Commit() error {
|
||||
start := time.Now()
|
||||
err := lt.UnderlyingTx.Commit()
|
||||
lt.endLog()
|
||||
lt.EndTime = time.Now()
|
||||
if !lt.noTotalLog {
|
||||
lt.db.Log.QueryTiming(lt.ctx, "<Transaction>", "", nil, -1, lt.EndTime.Sub(lt.StartTime), nil)
|
||||
}
|
||||
lt.db.Log.QueryTiming(lt.ctx, "Commit", "", nil, -1, time.Since(start), err)
|
||||
return err
|
||||
}
|
||||
@@ -110,16 +117,12 @@ func (lt *LoggingTxn) Commit() error {
|
||||
func (lt *LoggingTxn) Rollback() error {
|
||||
start := time.Now()
|
||||
err := lt.UnderlyingTx.Rollback()
|
||||
lt.endLog()
|
||||
lt.db.Log.QueryTiming(lt.ctx, "Rollback", "", nil, -1, time.Since(start), err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (lt *LoggingTxn) endLog() {
|
||||
lt.EndTime = time.Now()
|
||||
if !lt.noTotalLog {
|
||||
lt.db.Log.QueryTiming(lt.ctx, "<Transaction>", "", nil, -1, lt.EndTime.Sub(lt.StartTime), nil)
|
||||
}
|
||||
lt.db.Log.QueryTiming(lt.ctx, "Rollback", "", nil, -1, time.Since(start), err)
|
||||
return err
|
||||
}
|
||||
|
||||
type LoggingRows struct {
|
||||
|
||||
107
vendor/maunium.net/go/mautrix/util/dbutil/database.go
generated
vendored
107
vendor/maunium.net/go/mautrix/util/dbutil/database.go
generated
vendored
@@ -10,6 +10,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -35,12 +36,13 @@ func (dialect Dialect) String() string {
|
||||
}
|
||||
|
||||
func ParseDialect(engine string) (Dialect, error) {
|
||||
switch strings.ToLower(engine) {
|
||||
case "postgres", "postgresql", "pgx":
|
||||
engine = strings.ToLower(engine)
|
||||
|
||||
if strings.HasPrefix(engine, "postgres") || engine == "pgx" {
|
||||
return Postgres, nil
|
||||
case "sqlite3", "sqlite", "litestream", "sqlite3-fk-wal":
|
||||
} else if strings.HasPrefix(engine, "sqlite") || strings.HasPrefix(engine, "litestream") {
|
||||
return SQLite, nil
|
||||
default:
|
||||
} else {
|
||||
return DialectUnknown, fmt.Errorf("unknown dialect '%s'", engine)
|
||||
}
|
||||
}
|
||||
@@ -109,6 +111,7 @@ var (
|
||||
type Database struct {
|
||||
loggingDB
|
||||
RawDB *sql.DB
|
||||
ReadOnlyDB *sql.DB
|
||||
Owner string
|
||||
VersionTable string
|
||||
Log DatabaseLogger
|
||||
@@ -171,10 +174,11 @@ func NewWithDialect(uri, rawDialect string) (*Database, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewWithDB(db, rawDialect)
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
type PoolConfig struct {
|
||||
Type string `yaml:"type"`
|
||||
URI string `yaml:"uri"`
|
||||
|
||||
@@ -185,54 +189,101 @@ type Config struct {
|
||||
ConnMaxLifetime string `yaml:"conn_max_lifetime"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
PoolConfig `yaml:",inline"`
|
||||
ReadOnlyPool PoolConfig `yaml:"ro_pool"`
|
||||
}
|
||||
|
||||
func (db *Database) Close() error {
|
||||
err := db.RawDB.Close()
|
||||
if db.ReadOnlyDB != nil {
|
||||
err2 := db.ReadOnlyDB.Close()
|
||||
if err == nil {
|
||||
err = fmt.Errorf("closing read-only db failed: %w", err)
|
||||
} else {
|
||||
err = fmt.Errorf("%w (closing read-only db also failed: %v)", err, err2)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Database) Configure(cfg Config) error {
|
||||
db.RawDB.SetMaxOpenConns(cfg.MaxOpenConns)
|
||||
db.RawDB.SetMaxIdleConns(cfg.MaxIdleConns)
|
||||
if err := db.configure(db.ReadOnlyDB, cfg.ReadOnlyPool); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.configure(db.RawDB, cfg.PoolConfig)
|
||||
}
|
||||
|
||||
func (db *Database) configure(rawDB *sql.DB, cfg PoolConfig) error {
|
||||
if rawDB == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
rawDB.SetMaxOpenConns(cfg.MaxOpenConns)
|
||||
rawDB.SetMaxIdleConns(cfg.MaxIdleConns)
|
||||
if len(cfg.ConnMaxIdleTime) > 0 {
|
||||
maxIdleTimeDuration, err := time.ParseDuration(cfg.ConnMaxIdleTime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse max_conn_idle_time: %w", err)
|
||||
}
|
||||
db.RawDB.SetConnMaxIdleTime(maxIdleTimeDuration)
|
||||
rawDB.SetConnMaxIdleTime(maxIdleTimeDuration)
|
||||
}
|
||||
if len(cfg.ConnMaxLifetime) > 0 {
|
||||
maxLifetimeDuration, err := time.ParseDuration(cfg.ConnMaxLifetime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse max_conn_idle_time: %w", err)
|
||||
}
|
||||
db.RawDB.SetConnMaxLifetime(maxLifetimeDuration)
|
||||
rawDB.SetConnMaxLifetime(maxLifetimeDuration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewFromConfig(owner string, cfg Config, logger DatabaseLogger) (*Database, error) {
|
||||
dialect, err := ParseDialect(cfg.Type)
|
||||
wrappedDB, err := NewWithDialect(cfg.URI, cfg.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := sql.Open(cfg.Type, cfg.URI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if logger == nil {
|
||||
logger = NoopLogger
|
||||
}
|
||||
wrappedDB := &Database{
|
||||
RawDB: conn,
|
||||
|
||||
Owner: owner,
|
||||
Dialect: dialect,
|
||||
|
||||
Log: logger,
|
||||
|
||||
IgnoreForeignTables: true,
|
||||
VersionTable: "version",
|
||||
wrappedDB.Owner = owner
|
||||
if logger != nil {
|
||||
wrappedDB.Log = logger
|
||||
}
|
||||
|
||||
if cfg.ReadOnlyPool.MaxOpenConns > 0 {
|
||||
if cfg.ReadOnlyPool.Type == "" {
|
||||
cfg.ReadOnlyPool.Type = cfg.Type
|
||||
}
|
||||
|
||||
roUri := cfg.ReadOnlyPool.URI
|
||||
if roUri == "" {
|
||||
uriParts := strings.Split(cfg.URI, "?")
|
||||
|
||||
var qs url.Values
|
||||
if len(uriParts) == 2 {
|
||||
var err error
|
||||
qs, err = url.ParseQuery(uriParts[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
qs.Del("_txlock")
|
||||
}
|
||||
qs.Set("_query_only", "true")
|
||||
|
||||
roUri = uriParts[0] + "?" + qs.Encode()
|
||||
}
|
||||
|
||||
wrappedDB.ReadOnlyDB, err = sql.Open(cfg.ReadOnlyPool.Type, roUri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = wrappedDB.Configure(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wrappedDB.loggingDB.UnderlyingExecable = conn
|
||||
wrappedDB.loggingDB.db = wrappedDB
|
||||
|
||||
return wrappedDB, nil
|
||||
}
|
||||
|
||||
5
vendor/maunium.net/go/mautrix/util/dbutil/log.go
generated
vendored
5
vendor/maunium.net/go/mautrix/util/dbutil/log.go
generated
vendored
@@ -80,6 +80,11 @@ func ZeroLoggerPtr(log *zerolog.Logger, cfg ...ZeroLogSettings) DatabaseLogger {
|
||||
wrapped := &zeroLogger{l: log}
|
||||
if len(cfg) > 0 {
|
||||
wrapped.ZeroLogSettings = cfg[0]
|
||||
} else {
|
||||
wrapped.ZeroLogSettings = ZeroLogSettings{
|
||||
CallerSkipFrame: 2, // Skip LoggingExecable.ExecContext and zeroLogger.QueryTiming
|
||||
Caller: true,
|
||||
}
|
||||
}
|
||||
return wrapped
|
||||
}
|
||||
|
||||
11
vendor/maunium.net/go/mautrix/util/dbutil/transaction.go
generated
vendored
11
vendor/maunium.net/go/mautrix/util/dbutil/transaction.go
generated
vendored
@@ -80,3 +80,14 @@ func (db *Database) DoTxn(ctx context.Context, opts *sql.TxOptions, fn func(ctx
|
||||
log.Trace().Msg("Commit successful")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) Conn(ctx context.Context) ContextExecable {
|
||||
if ctx == nil {
|
||||
return db
|
||||
}
|
||||
txn, ok := ctx.Value(ContextKeyDatabaseTransaction).(Transaction)
|
||||
if ok {
|
||||
return txn
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
54
vendor/maunium.net/go/mautrix/util/formatduration.go
generated
vendored
Normal file
54
vendor/maunium.net/go/mautrix/util/formatduration.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2023 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 util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var Day = 24 * time.Hour
|
||||
var Week = 7 * Day
|
||||
|
||||
func pluralize(value int, unit string) string {
|
||||
if value == 1 {
|
||||
return "1 " + unit
|
||||
}
|
||||
return fmt.Sprintf("%d %ss", value, unit)
|
||||
}
|
||||
|
||||
func appendDurationPart(time, unit time.Duration, name string, parts *[]string) (remainder time.Duration) {
|
||||
if time < unit {
|
||||
return time
|
||||
}
|
||||
value := int(time / unit)
|
||||
remainder = time % unit
|
||||
*parts = append(*parts, pluralize(value, name))
|
||||
return
|
||||
}
|
||||
|
||||
func FormatDuration(d time.Duration) string {
|
||||
if d < 0 {
|
||||
panic(errors.New("FormatDuration: negative duration"))
|
||||
} else if d < time.Second {
|
||||
return "now"
|
||||
}
|
||||
parts := make([]string, 0, 2)
|
||||
d = appendDurationPart(d, Week, "week", &parts)
|
||||
d = appendDurationPart(d, Day, "day", &parts)
|
||||
d = appendDurationPart(d, time.Hour, "hour", &parts)
|
||||
d = appendDurationPart(d, time.Minute, "minute", &parts)
|
||||
d = appendDurationPart(d, time.Second, "second", &parts)
|
||||
if len(parts) > 2 {
|
||||
parts[0] = strings.Join(parts[:len(parts)-1], ", ")
|
||||
parts[1] = parts[len(parts)-1]
|
||||
parts = parts[:2]
|
||||
}
|
||||
return strings.Join(parts, " and ")
|
||||
}
|
||||
2
vendor/maunium.net/go/mautrix/version.go
generated
vendored
2
vendor/maunium.net/go/mautrix/version.go
generated
vendored
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const Version = "v0.15.2"
|
||||
const Version = "v0.15.3"
|
||||
|
||||
var GoModVersion = ""
|
||||
var Commit = ""
|
||||
|
||||
Reference in New Issue
Block a user