updated deps; updated healthchecks.io integration
This commit is contained in:
374
vendor/maunium.net/go/maulogger/v2/LICENSE
generated
vendored
374
vendor/maunium.net/go/maulogger/v2/LICENSE
generated
vendored
@@ -1,374 +0,0 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
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/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
||||
6
vendor/maunium.net/go/maulogger/v2/README.md
generated
vendored
6
vendor/maunium.net/go/maulogger/v2/README.md
generated
vendored
@@ -1,6 +0,0 @@
|
||||
# maulogger
|
||||
A logger in Go. Deprecated in favor of [zerolog](https://github.com/rs/zerolog).
|
||||
|
||||
Utilities for migrating gracefully can be found in the maulogadapt package,
|
||||
it includes both wrapping a zerolog in the maulogger interface, and wrapping a
|
||||
maulogger as a zerolog output writer.
|
||||
284
vendor/maunium.net/go/maulogger/v2/defaults.go
generated
vendored
284
vendor/maunium.net/go/maulogger/v2/defaults.go
generated
vendored
@@ -1,284 +0,0 @@
|
||||
// mauLogger - A logger for Go programs
|
||||
// Copyright (c) 2016-2021 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 maulogger
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// DefaultLogger ...
|
||||
var DefaultLogger = Create().(*BasicLogger)
|
||||
|
||||
// SetWriter formats the given parts with fmt.Sprint and logs the result with the SetWriter level
|
||||
func SetWriter(w *os.File) {
|
||||
DefaultLogger.SetWriter(w)
|
||||
}
|
||||
|
||||
// OpenFile formats the given parts with fmt.Sprint and logs the result with the OpenFile level
|
||||
func OpenFile() error {
|
||||
return DefaultLogger.OpenFile()
|
||||
}
|
||||
|
||||
// Close formats the given parts with fmt.Sprint and logs the result with the Close level
|
||||
func Close() error {
|
||||
return DefaultLogger.Close()
|
||||
}
|
||||
|
||||
// Sub creates a Sublogger
|
||||
func Sub(module string) Logger {
|
||||
return DefaultLogger.Sub(module)
|
||||
}
|
||||
|
||||
// Raw formats the given parts with fmt.Sprint and logs the result with the Raw level
|
||||
func Rawm(level Level, metadata map[string]interface{}, module, message string) {
|
||||
DefaultLogger.Raw(level, metadata, module, message)
|
||||
}
|
||||
|
||||
func Raw(level Level, module, message string) {
|
||||
DefaultLogger.Raw(level, map[string]interface{}{}, module, message)
|
||||
}
|
||||
|
||||
// Log formats the given parts with fmt.Sprint and logs the result with the given level
|
||||
func Log(level Level, parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Log(level, parts...)
|
||||
}
|
||||
|
||||
// Logln formats the given parts with fmt.Sprintln and logs the result with the given level
|
||||
func Logln(level Level, parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Logln(level, parts...)
|
||||
}
|
||||
|
||||
// Logf formats the given message and args with fmt.Sprintf and logs the result with the given level
|
||||
func Logf(level Level, message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Logf(level, message, args...)
|
||||
}
|
||||
|
||||
// Logfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the given level
|
||||
func Logfln(level Level, message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Logfln(level, message, args...)
|
||||
}
|
||||
|
||||
// Debug formats the given parts with fmt.Sprint and logs the result with the Debug level
|
||||
func Debug(parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Debug(parts...)
|
||||
}
|
||||
|
||||
// Debugln formats the given parts with fmt.Sprintln and logs the result with the Debug level
|
||||
func Debugln(parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Debugln(parts...)
|
||||
}
|
||||
|
||||
// Debugf formats the given message and args with fmt.Sprintf and logs the result with the Debug level
|
||||
func Debugf(message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Debugf(message, args...)
|
||||
}
|
||||
|
||||
// Debugfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Debug level
|
||||
func Debugfln(message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Debugfln(message, args...)
|
||||
}
|
||||
|
||||
// Info formats the given parts with fmt.Sprint and logs the result with the Info level
|
||||
func Info(parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Info(parts...)
|
||||
}
|
||||
|
||||
// Infoln formats the given parts with fmt.Sprintln and logs the result with the Info level
|
||||
func Infoln(parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Infoln(parts...)
|
||||
}
|
||||
|
||||
// Infof formats the given message and args with fmt.Sprintf and logs the result with the Info level
|
||||
func Infof(message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Infof(message, args...)
|
||||
}
|
||||
|
||||
// Infofln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Info level
|
||||
func Infofln(message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Infofln(message, args...)
|
||||
}
|
||||
|
||||
// Warn formats the given parts with fmt.Sprint and logs the result with the Warn level
|
||||
func Warn(parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Warn(parts...)
|
||||
}
|
||||
|
||||
// Warnln formats the given parts with fmt.Sprintln and logs the result with the Warn level
|
||||
func Warnln(parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Warnln(parts...)
|
||||
}
|
||||
|
||||
// Warnf formats the given message and args with fmt.Sprintf and logs the result with the Warn level
|
||||
func Warnf(message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Warnf(message, args...)
|
||||
}
|
||||
|
||||
// Warnfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Warn level
|
||||
func Warnfln(message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Warnfln(message, args...)
|
||||
}
|
||||
|
||||
// Error formats the given parts with fmt.Sprint and logs the result with the Error level
|
||||
func Error(parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Error(parts...)
|
||||
}
|
||||
|
||||
// Errorln formats the given parts with fmt.Sprintln and logs the result with the Error level
|
||||
func Errorln(parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Errorln(parts...)
|
||||
}
|
||||
|
||||
// Errorf formats the given message and args with fmt.Sprintf and logs the result with the Error level
|
||||
func Errorf(message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Errorf(message, args...)
|
||||
}
|
||||
|
||||
// Errorfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Error level
|
||||
func Errorfln(message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Errorfln(message, args...)
|
||||
}
|
||||
|
||||
// Fatal formats the given parts with fmt.Sprint and logs the result with the Fatal level
|
||||
func Fatal(parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Fatal(parts...)
|
||||
}
|
||||
|
||||
// Fatalln formats the given parts with fmt.Sprintln and logs the result with the Fatal level
|
||||
func Fatalln(parts ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Fatalln(parts...)
|
||||
}
|
||||
|
||||
// Fatalf formats the given message and args with fmt.Sprintf and logs the result with the Fatal level
|
||||
func Fatalf(message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Fatalf(message, args...)
|
||||
}
|
||||
|
||||
// Fatalfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Fatal level
|
||||
func Fatalfln(message string, args ...interface{}) {
|
||||
DefaultLogger.DefaultSub.Fatalfln(message, args...)
|
||||
}
|
||||
|
||||
// Log formats the given parts with fmt.Sprint and logs the result with the given level
|
||||
func (log *BasicLogger) Log(level Level, parts ...interface{}) {
|
||||
log.DefaultSub.Log(level, parts...)
|
||||
}
|
||||
|
||||
// Logln formats the given parts with fmt.Sprintln and logs the result with the given level
|
||||
func (log *BasicLogger) Logln(level Level, parts ...interface{}) {
|
||||
log.DefaultSub.Logln(level, parts...)
|
||||
}
|
||||
|
||||
// Logf formats the given message and args with fmt.Sprintf and logs the result with the given level
|
||||
func (log *BasicLogger) Logf(level Level, message string, args ...interface{}) {
|
||||
log.DefaultSub.Logf(level, message, args...)
|
||||
}
|
||||
|
||||
// Logfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the given level
|
||||
func (log *BasicLogger) Logfln(level Level, message string, args ...interface{}) {
|
||||
log.DefaultSub.Logfln(level, message, args...)
|
||||
}
|
||||
|
||||
// Debug formats the given parts with fmt.Sprint and logs the result with the Debug level
|
||||
func (log *BasicLogger) Debug(parts ...interface{}) {
|
||||
log.DefaultSub.Debug(parts...)
|
||||
}
|
||||
|
||||
// Debugln formats the given parts with fmt.Sprintln and logs the result with the Debug level
|
||||
func (log *BasicLogger) Debugln(parts ...interface{}) {
|
||||
log.DefaultSub.Debugln(parts...)
|
||||
}
|
||||
|
||||
// Debugf formats the given message and args with fmt.Sprintf and logs the result with the Debug level
|
||||
func (log *BasicLogger) Debugf(message string, args ...interface{}) {
|
||||
log.DefaultSub.Debugf(message, args...)
|
||||
}
|
||||
|
||||
// Debugfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Debug level
|
||||
func (log *BasicLogger) Debugfln(message string, args ...interface{}) {
|
||||
log.DefaultSub.Debugfln(message, args...)
|
||||
}
|
||||
|
||||
// Info formats the given parts with fmt.Sprint and logs the result with the Info level
|
||||
func (log *BasicLogger) Info(parts ...interface{}) {
|
||||
log.DefaultSub.Info(parts...)
|
||||
}
|
||||
|
||||
// Infoln formats the given parts with fmt.Sprintln and logs the result with the Info level
|
||||
func (log *BasicLogger) Infoln(parts ...interface{}) {
|
||||
log.DefaultSub.Infoln(parts...)
|
||||
}
|
||||
|
||||
// Infofln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Info level
|
||||
func (log *BasicLogger) Infofln(message string, args ...interface{}) {
|
||||
log.DefaultSub.Infofln(message, args...)
|
||||
}
|
||||
|
||||
// Infof formats the given message and args with fmt.Sprintf and logs the result with the Info level
|
||||
func (log *BasicLogger) Infof(message string, args ...interface{}) {
|
||||
log.DefaultSub.Infof(message, args...)
|
||||
}
|
||||
|
||||
// Warn formats the given parts with fmt.Sprint and logs the result with the Warn level
|
||||
func (log *BasicLogger) Warn(parts ...interface{}) {
|
||||
log.DefaultSub.Warn(parts...)
|
||||
}
|
||||
|
||||
// Warnln formats the given parts with fmt.Sprintln and logs the result with the Warn level
|
||||
func (log *BasicLogger) Warnln(parts ...interface{}) {
|
||||
log.DefaultSub.Warnln(parts...)
|
||||
}
|
||||
|
||||
// Warnfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Warn level
|
||||
func (log *BasicLogger) Warnfln(message string, args ...interface{}) {
|
||||
log.DefaultSub.Warnfln(message, args...)
|
||||
}
|
||||
|
||||
// Warnf formats the given message and args with fmt.Sprintf and logs the result with the Warn level
|
||||
func (log *BasicLogger) Warnf(message string, args ...interface{}) {
|
||||
log.DefaultSub.Warnf(message, args...)
|
||||
}
|
||||
|
||||
// Error formats the given parts with fmt.Sprint and logs the result with the Error level
|
||||
func (log *BasicLogger) Error(parts ...interface{}) {
|
||||
log.DefaultSub.Error(parts...)
|
||||
}
|
||||
|
||||
// Errorln formats the given parts with fmt.Sprintln and logs the result with the Error level
|
||||
func (log *BasicLogger) Errorln(parts ...interface{}) {
|
||||
log.DefaultSub.Errorln(parts...)
|
||||
}
|
||||
|
||||
// Errorf formats the given message and args with fmt.Sprintf and logs the result with the Error level
|
||||
func (log *BasicLogger) Errorf(message string, args ...interface{}) {
|
||||
log.DefaultSub.Errorf(message, args...)
|
||||
}
|
||||
|
||||
// Errorfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Error level
|
||||
func (log *BasicLogger) Errorfln(message string, args ...interface{}) {
|
||||
log.DefaultSub.Errorfln(message, args...)
|
||||
}
|
||||
|
||||
// Fatal formats the given parts with fmt.Sprint and logs the result with the Fatal level
|
||||
func (log *BasicLogger) Fatal(parts ...interface{}) {
|
||||
log.DefaultSub.Fatal(parts...)
|
||||
}
|
||||
|
||||
// Fatalln formats the given parts with fmt.Sprintln and logs the result with the Fatal level
|
||||
func (log *BasicLogger) Fatalln(parts ...interface{}) {
|
||||
log.DefaultSub.Fatalln(parts...)
|
||||
}
|
||||
|
||||
// Fatalf formats the given message and args with fmt.Sprintf and logs the result with the Fatal level
|
||||
func (log *BasicLogger) Fatalf(message string, args ...interface{}) {
|
||||
log.DefaultSub.Fatalf(message, args...)
|
||||
}
|
||||
|
||||
// Fatalfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Fatal level
|
||||
func (log *BasicLogger) Fatalfln(message string, args ...interface{}) {
|
||||
log.DefaultSub.Fatalfln(message, args...)
|
||||
}
|
||||
47
vendor/maunium.net/go/maulogger/v2/level.go
generated
vendored
47
vendor/maunium.net/go/maulogger/v2/level.go
generated
vendored
@@ -1,47 +0,0 @@
|
||||
// mauLogger - A logger for Go programs
|
||||
// Copyright (c) 2016-2021 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 maulogger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Level is the severity level of a log entry.
|
||||
type Level struct {
|
||||
Name string
|
||||
Severity, Color int
|
||||
}
|
||||
|
||||
var (
|
||||
// LevelDebug is the level for debug messages.
|
||||
LevelDebug = Level{Name: "DEBUG", Color: -1, Severity: 0}
|
||||
// LevelInfo is the level for basic log messages.
|
||||
LevelInfo = Level{Name: "INFO", Color: 36, Severity: 10}
|
||||
// LevelWarn is the level saying that something went wrong, but the program will continue operating mostly normally.
|
||||
LevelWarn = Level{Name: "WARN", Color: 33, Severity: 50}
|
||||
// LevelError is the level saying that something went wrong and the program may not operate as expected, but will still continue.
|
||||
LevelError = Level{Name: "ERROR", Color: 31, Severity: 100}
|
||||
// LevelFatal is the level saying that something went wrong and the program will not operate normally.
|
||||
LevelFatal = Level{Name: "FATAL", Color: 35, Severity: 9001}
|
||||
)
|
||||
|
||||
// GetColor gets the ANSI escape color code for the log level.
|
||||
func (lvl Level) GetColor() string {
|
||||
if lvl.Color < 0 {
|
||||
return "\x1b[0m"
|
||||
}
|
||||
return fmt.Sprintf("\x1b[%dm", lvl.Color)
|
||||
}
|
||||
|
||||
// GetReset gets the ANSI escape reset code.
|
||||
func (lvl Level) GetReset() string {
|
||||
if lvl.Color < 0 {
|
||||
return ""
|
||||
}
|
||||
return "\x1b[0m"
|
||||
}
|
||||
224
vendor/maunium.net/go/maulogger/v2/logger.go
generated
vendored
224
vendor/maunium.net/go/maulogger/v2/logger.go
generated
vendored
@@ -1,224 +0,0 @@
|
||||
// mauLogger - A logger for Go programs
|
||||
// Copyright (c) 2016-2021 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 maulogger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LoggerFileFormat ...
|
||||
type LoggerFileFormat func(now string, i int) string
|
||||
|
||||
type BasicLogger struct {
|
||||
PrintLevel int
|
||||
FlushLineThreshold int
|
||||
FileTimeFormat string
|
||||
FileFormat LoggerFileFormat
|
||||
TimeFormat string
|
||||
FileMode os.FileMode
|
||||
DefaultSub Logger
|
||||
|
||||
JSONFile bool
|
||||
JSONStdout bool
|
||||
|
||||
stdoutEncoder *json.Encoder
|
||||
fileEncoder *json.Encoder
|
||||
|
||||
writer *os.File
|
||||
writerLock sync.Mutex
|
||||
StdoutLock sync.Mutex
|
||||
StderrLock sync.Mutex
|
||||
lines int
|
||||
|
||||
metadata map[string]interface{}
|
||||
}
|
||||
|
||||
// Logger contains advanced logging functions
|
||||
type Logger interface {
|
||||
Sub(module string) Logger
|
||||
Subm(module string, metadata map[string]interface{}) Logger
|
||||
WithDefaultLevel(level Level) Logger
|
||||
GetParent() Logger
|
||||
|
||||
Writer(level Level) io.WriteCloser
|
||||
|
||||
Log(level Level, parts ...interface{})
|
||||
Logln(level Level, parts ...interface{})
|
||||
Logf(level Level, message string, args ...interface{})
|
||||
Logfln(level Level, message string, args ...interface{})
|
||||
|
||||
Debug(parts ...interface{})
|
||||
Debugln(parts ...interface{})
|
||||
Debugf(message string, args ...interface{})
|
||||
Debugfln(message string, args ...interface{})
|
||||
Info(parts ...interface{})
|
||||
Infoln(parts ...interface{})
|
||||
Infof(message string, args ...interface{})
|
||||
Infofln(message string, args ...interface{})
|
||||
Warn(parts ...interface{})
|
||||
Warnln(parts ...interface{})
|
||||
Warnf(message string, args ...interface{})
|
||||
Warnfln(message string, args ...interface{})
|
||||
Error(parts ...interface{})
|
||||
Errorln(parts ...interface{})
|
||||
Errorf(message string, args ...interface{})
|
||||
Errorfln(message string, args ...interface{})
|
||||
Fatal(parts ...interface{})
|
||||
Fatalln(parts ...interface{})
|
||||
Fatalf(message string, args ...interface{})
|
||||
Fatalfln(message string, args ...interface{})
|
||||
}
|
||||
|
||||
// Create a Logger
|
||||
func Createm(metadata map[string]interface{}) Logger {
|
||||
var log = &BasicLogger{
|
||||
PrintLevel: 10,
|
||||
FileTimeFormat: "2006-01-02",
|
||||
FileFormat: func(now string, i int) string { return fmt.Sprintf("%[1]s-%02[2]d.log", now, i) },
|
||||
TimeFormat: "15:04:05 02.01.2006",
|
||||
FileMode: 0600,
|
||||
FlushLineThreshold: 5,
|
||||
lines: 0,
|
||||
metadata: metadata,
|
||||
}
|
||||
log.DefaultSub = log.Sub("")
|
||||
return log
|
||||
}
|
||||
|
||||
func Create() Logger {
|
||||
return Createm(map[string]interface{}{})
|
||||
}
|
||||
|
||||
func (log *BasicLogger) EnableJSONStdout() {
|
||||
log.JSONStdout = true
|
||||
log.stdoutEncoder = json.NewEncoder(os.Stdout)
|
||||
}
|
||||
|
||||
func (log *BasicLogger) GetParent() Logger {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWriter formats the given parts with fmt.Sprint and logs the result with the SetWriter level
|
||||
func (log *BasicLogger) SetWriter(w *os.File) {
|
||||
log.writer = w
|
||||
if log.JSONFile {
|
||||
log.fileEncoder = json.NewEncoder(w)
|
||||
}
|
||||
}
|
||||
|
||||
// OpenFile formats the given parts with fmt.Sprint and logs the result with the OpenFile level
|
||||
func (log *BasicLogger) OpenFile() error {
|
||||
now := time.Now().Format(log.FileTimeFormat)
|
||||
i := 1
|
||||
for ; ; i++ {
|
||||
if _, err := os.Stat(log.FileFormat(now, i)); os.IsNotExist(err) {
|
||||
break
|
||||
}
|
||||
}
|
||||
writer, err := os.OpenFile(log.FileFormat(now, i), os.O_WRONLY|os.O_CREATE|os.O_APPEND, log.FileMode)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if writer == nil {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
log.SetWriter(writer)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close formats the given parts with fmt.Sprint and logs the result with the Close level
|
||||
func (log *BasicLogger) Close() error {
|
||||
if log.writer != nil {
|
||||
return log.writer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type logLine struct {
|
||||
log *BasicLogger
|
||||
|
||||
Command string `json:"command"`
|
||||
Time time.Time `json:"time"`
|
||||
Level string `json:"level"`
|
||||
Module string `json:"module"`
|
||||
Message string `json:"message"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
}
|
||||
|
||||
func (ll logLine) String() string {
|
||||
if len(ll.Module) == 0 {
|
||||
return fmt.Sprintf("[%s] [%s] %s", ll.Time.Format(ll.log.TimeFormat), ll.Level, ll.Message)
|
||||
} else {
|
||||
return fmt.Sprintf("[%s] [%s/%s] %s", ll.Time.Format(ll.log.TimeFormat), ll.Module, ll.Level, ll.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func reduceItem(m1, m2 map[string]interface{}) map[string]interface{} {
|
||||
m3 := map[string]interface{}{}
|
||||
|
||||
_merge := func(m map[string]interface{}) {
|
||||
for ia, va := range m {
|
||||
m3[ia] = va
|
||||
}
|
||||
}
|
||||
|
||||
_merge(m1)
|
||||
_merge(m2)
|
||||
|
||||
return m3
|
||||
}
|
||||
|
||||
// Raw formats the given parts with fmt.Sprint and logs the result with the Raw level
|
||||
func (log *BasicLogger) Raw(level Level, extraMetadata map[string]interface{}, module, origMessage string) {
|
||||
message := logLine{log, "log", time.Now(), level.Name, module, strings.TrimSpace(origMessage), reduceItem(log.metadata, extraMetadata)}
|
||||
|
||||
if log.writer != nil {
|
||||
log.writerLock.Lock()
|
||||
var err error
|
||||
if log.JSONFile {
|
||||
err = log.fileEncoder.Encode(&message)
|
||||
} else {
|
||||
_, err = log.writer.WriteString(message.String())
|
||||
_, _ = log.writer.WriteString("\n")
|
||||
}
|
||||
log.writerLock.Unlock()
|
||||
if err != nil {
|
||||
log.StderrLock.Lock()
|
||||
_, _ = os.Stderr.WriteString("Failed to write to log file:")
|
||||
_, _ = os.Stderr.WriteString(err.Error())
|
||||
log.StderrLock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
if level.Severity >= log.PrintLevel {
|
||||
if log.JSONStdout {
|
||||
log.StdoutLock.Lock()
|
||||
_ = log.stdoutEncoder.Encode(&message)
|
||||
log.StdoutLock.Unlock()
|
||||
} else if level.Severity >= LevelError.Severity {
|
||||
log.StderrLock.Lock()
|
||||
_, _ = os.Stderr.WriteString(level.GetColor())
|
||||
_, _ = os.Stderr.WriteString(message.String())
|
||||
_, _ = os.Stderr.WriteString(level.GetReset())
|
||||
_, _ = os.Stderr.WriteString("\n")
|
||||
log.StderrLock.Unlock()
|
||||
} else {
|
||||
log.StdoutLock.Lock()
|
||||
_, _ = os.Stdout.WriteString(level.GetColor())
|
||||
_, _ = os.Stdout.WriteString(message.String())
|
||||
_, _ = os.Stdout.WriteString(level.GetReset())
|
||||
_, _ = os.Stdout.WriteString("\n")
|
||||
log.StdoutLock.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
185
vendor/maunium.net/go/maulogger/v2/maulogadapt/mauzerolog.go
generated
vendored
185
vendor/maunium.net/go/maulogger/v2/maulogadapt/mauzerolog.go
generated
vendored
@@ -1,185 +0,0 @@
|
||||
// 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 maulogadapt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"maunium.net/go/maulogger/v2"
|
||||
)
|
||||
|
||||
type MauZeroLog struct {
|
||||
*zerolog.Logger
|
||||
orig *zerolog.Logger
|
||||
mod string
|
||||
}
|
||||
|
||||
func ZeroAsMau(log *zerolog.Logger) maulogger.Logger {
|
||||
return MauZeroLog{log, log, ""}
|
||||
}
|
||||
|
||||
var _ maulogger.Logger = (*MauZeroLog)(nil)
|
||||
|
||||
func (m MauZeroLog) Sub(module string) maulogger.Logger {
|
||||
return m.Subm(module, map[string]interface{}{})
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Subm(module string, metadata map[string]interface{}) maulogger.Logger {
|
||||
if m.mod != "" {
|
||||
module = fmt.Sprintf("%s/%s", m.mod, module)
|
||||
}
|
||||
var orig zerolog.Logger
|
||||
if m.orig != nil {
|
||||
orig = *m.orig
|
||||
} else {
|
||||
orig = *m.Logger
|
||||
}
|
||||
if len(metadata) > 0 {
|
||||
with := m.orig.With()
|
||||
for key, value := range metadata {
|
||||
with = with.Interface(key, value)
|
||||
}
|
||||
orig = with.Logger()
|
||||
}
|
||||
log := orig.With().Str("module", module).Logger()
|
||||
return MauZeroLog{&log, &orig, module}
|
||||
}
|
||||
|
||||
func (m MauZeroLog) WithDefaultLevel(_ maulogger.Level) maulogger.Logger {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m MauZeroLog) GetParent() maulogger.Logger {
|
||||
return nil
|
||||
}
|
||||
|
||||
type nopWriteCloser struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (nopWriteCloser) Close() error { return nil }
|
||||
|
||||
func (m MauZeroLog) Writer(level maulogger.Level) io.WriteCloser {
|
||||
return nopWriteCloser{m.Logger.With().Str(zerolog.LevelFieldName, zerolog.LevelFieldMarshalFunc(mauToZeroLevel(level))).Logger()}
|
||||
}
|
||||
|
||||
func mauToZeroLevel(level maulogger.Level) zerolog.Level {
|
||||
switch level {
|
||||
case maulogger.LevelDebug:
|
||||
return zerolog.DebugLevel
|
||||
case maulogger.LevelInfo:
|
||||
return zerolog.InfoLevel
|
||||
case maulogger.LevelWarn:
|
||||
return zerolog.WarnLevel
|
||||
case maulogger.LevelError:
|
||||
return zerolog.ErrorLevel
|
||||
case maulogger.LevelFatal:
|
||||
return zerolog.FatalLevel
|
||||
default:
|
||||
return zerolog.TraceLevel
|
||||
}
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Log(level maulogger.Level, parts ...interface{}) {
|
||||
m.Logger.WithLevel(mauToZeroLevel(level)).Msg(fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Logln(level maulogger.Level, parts ...interface{}) {
|
||||
m.Logger.WithLevel(mauToZeroLevel(level)).Msg(strings.TrimSuffix(fmt.Sprintln(parts...), "\n"))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Logf(level maulogger.Level, message string, args ...interface{}) {
|
||||
m.Logger.WithLevel(mauToZeroLevel(level)).Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Logfln(level maulogger.Level, message string, args ...interface{}) {
|
||||
m.Logger.WithLevel(mauToZeroLevel(level)).Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Debug(parts ...interface{}) {
|
||||
m.Logger.Debug().Msg(fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Debugln(parts ...interface{}) {
|
||||
m.Logger.Debug().Msg(strings.TrimSuffix(fmt.Sprintln(parts...), "\n"))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Debugf(message string, args ...interface{}) {
|
||||
m.Logger.Debug().Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Debugfln(message string, args ...interface{}) {
|
||||
m.Logger.Debug().Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Info(parts ...interface{}) {
|
||||
m.Logger.Info().Msg(fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Infoln(parts ...interface{}) {
|
||||
m.Logger.Info().Msg(strings.TrimSuffix(fmt.Sprintln(parts...), "\n"))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Infof(message string, args ...interface{}) {
|
||||
m.Logger.Info().Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Infofln(message string, args ...interface{}) {
|
||||
m.Logger.Info().Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Warn(parts ...interface{}) {
|
||||
m.Logger.Warn().Msg(fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Warnln(parts ...interface{}) {
|
||||
m.Logger.Warn().Msg(strings.TrimSuffix(fmt.Sprintln(parts...), "\n"))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Warnf(message string, args ...interface{}) {
|
||||
m.Logger.Warn().Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Warnfln(message string, args ...interface{}) {
|
||||
m.Logger.Warn().Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Error(parts ...interface{}) {
|
||||
m.Logger.Error().Msg(fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Errorln(parts ...interface{}) {
|
||||
m.Logger.Error().Msg(strings.TrimSuffix(fmt.Sprintln(parts...), "\n"))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Errorf(message string, args ...interface{}) {
|
||||
m.Logger.Error().Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Errorfln(message string, args ...interface{}) {
|
||||
m.Logger.Error().Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Fatal(parts ...interface{}) {
|
||||
m.Logger.WithLevel(zerolog.FatalLevel).Msg(fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Fatalln(parts ...interface{}) {
|
||||
m.Logger.WithLevel(zerolog.FatalLevel).Msg(strings.TrimSuffix(fmt.Sprintln(parts...), "\n"))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Fatalf(message string, args ...interface{}) {
|
||||
m.Logger.WithLevel(zerolog.FatalLevel).Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
func (m MauZeroLog) Fatalfln(message string, args ...interface{}) {
|
||||
m.Logger.WithLevel(zerolog.FatalLevel).Msg(fmt.Sprintf(message, args...))
|
||||
}
|
||||
73
vendor/maunium.net/go/maulogger/v2/maulogadapt/zeromaulog.go
generated
vendored
73
vendor/maunium.net/go/maulogger/v2/maulogadapt/zeromaulog.go
generated
vendored
@@ -1,73 +0,0 @@
|
||||
// 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 maulogadapt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
|
||||
"maunium.net/go/maulogger/v2"
|
||||
)
|
||||
|
||||
// ZeroMauLog is a simple wrapper for a maulogger that can be set as the output writer for zerolog.
|
||||
type ZeroMauLog struct {
|
||||
maulogger.Logger
|
||||
}
|
||||
|
||||
func MauAsZero(log maulogger.Logger) *zerolog.Logger {
|
||||
zero := zerolog.New(&ZeroMauLog{log})
|
||||
return &zero
|
||||
}
|
||||
|
||||
var _ zerolog.LevelWriter = (*ZeroMauLog)(nil)
|
||||
|
||||
func (z *ZeroMauLog) Write(p []byte) (n int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (z *ZeroMauLog) WriteLevel(level zerolog.Level, p []byte) (n int, err error) {
|
||||
var mauLevel maulogger.Level
|
||||
switch level {
|
||||
case zerolog.DebugLevel:
|
||||
mauLevel = maulogger.LevelDebug
|
||||
case zerolog.InfoLevel, zerolog.NoLevel:
|
||||
mauLevel = maulogger.LevelInfo
|
||||
case zerolog.WarnLevel:
|
||||
mauLevel = maulogger.LevelWarn
|
||||
case zerolog.ErrorLevel:
|
||||
mauLevel = maulogger.LevelError
|
||||
case zerolog.FatalLevel, zerolog.PanicLevel:
|
||||
mauLevel = maulogger.LevelFatal
|
||||
case zerolog.Disabled, zerolog.TraceLevel:
|
||||
fallthrough
|
||||
default:
|
||||
return 0, nil
|
||||
}
|
||||
p = bytes.TrimSuffix(p, []byte{'\n'})
|
||||
msg := gjson.GetBytes(p, zerolog.MessageFieldName).Str
|
||||
|
||||
p, err = sjson.DeleteBytes(p, zerolog.MessageFieldName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p, err = sjson.DeleteBytes(p, zerolog.LevelFieldName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p, err = sjson.DeleteBytes(p, zerolog.TimestampFieldName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(p) > 2 {
|
||||
msg += " " + string(p)
|
||||
}
|
||||
z.Log(mauLevel, msg)
|
||||
return len(p), nil
|
||||
}
|
||||
216
vendor/maunium.net/go/maulogger/v2/sublogger.go
generated
vendored
216
vendor/maunium.net/go/maulogger/v2/sublogger.go
generated
vendored
@@ -1,216 +0,0 @@
|
||||
// mauLogger - A logger for Go programs
|
||||
// Copyright (c) 2016-2021 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 maulogger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Sublogger struct {
|
||||
topLevel *BasicLogger
|
||||
parent Logger
|
||||
Module string
|
||||
DefaultLevel Level
|
||||
metadata map[string]interface{}
|
||||
}
|
||||
|
||||
// Subm creates a Sublogger
|
||||
func (log *BasicLogger) Subm(module string, metadata map[string]interface{}) Logger {
|
||||
return &Sublogger{
|
||||
topLevel: log,
|
||||
parent: log,
|
||||
Module: module,
|
||||
DefaultLevel: LevelInfo,
|
||||
metadata: metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func (log *BasicLogger) Sub(module string) Logger {
|
||||
return log.Subm(module, map[string]interface{}{})
|
||||
}
|
||||
|
||||
// WithDefaultLevel creates a Sublogger with the same Module but different DefaultLevel
|
||||
func (log *BasicLogger) WithDefaultLevel(lvl Level) Logger {
|
||||
return log.DefaultSub.WithDefaultLevel(lvl)
|
||||
}
|
||||
|
||||
func (log *Sublogger) GetParent() Logger {
|
||||
return log.parent
|
||||
}
|
||||
|
||||
// Sub creates a Sublogger
|
||||
func (log *Sublogger) Subm(module string, metadata map[string]interface{}) Logger {
|
||||
if len(module) > 0 {
|
||||
module = fmt.Sprintf("%s/%s", log.Module, module)
|
||||
} else {
|
||||
module = log.Module
|
||||
}
|
||||
|
||||
return &Sublogger{
|
||||
topLevel: log.topLevel,
|
||||
parent: log,
|
||||
Module: module,
|
||||
DefaultLevel: log.DefaultLevel,
|
||||
metadata: metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func (log *Sublogger) Sub(module string) Logger {
|
||||
return log.Subm(module, map[string]interface{}{})
|
||||
}
|
||||
|
||||
// WithDefaultLevel creates a Sublogger with the same Module but different DefaultLevel
|
||||
func (log *Sublogger) WithDefaultLevel(lvl Level) Logger {
|
||||
return &Sublogger{
|
||||
topLevel: log.topLevel,
|
||||
parent: log.parent,
|
||||
Module: log.Module,
|
||||
DefaultLevel: lvl,
|
||||
}
|
||||
}
|
||||
|
||||
// SetModule changes the module name of this Sublogger
|
||||
func (log *Sublogger) SetModule(mod string) {
|
||||
log.Module = mod
|
||||
}
|
||||
|
||||
// SetDefaultLevel changes the default logging level of this Sublogger
|
||||
func (log *Sublogger) SetDefaultLevel(lvl Level) {
|
||||
log.DefaultLevel = lvl
|
||||
}
|
||||
|
||||
// SetParent changes the parent of this Sublogger
|
||||
func (log *Sublogger) SetParent(parent *BasicLogger) {
|
||||
log.topLevel = parent
|
||||
}
|
||||
|
||||
//Write ...
|
||||
func (log *Sublogger) Write(p []byte) (n int, err error) {
|
||||
log.topLevel.Raw(log.DefaultLevel, log.metadata, log.Module, string(p))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Log formats the given parts with fmt.Sprint and logs the result with the given level
|
||||
func (log *Sublogger) Log(level Level, parts ...interface{}) {
|
||||
log.topLevel.Raw(level, log.metadata, log.Module, fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
// Logln formats the given parts with fmt.Sprintln and logs the result with the given level
|
||||
func (log *Sublogger) Logln(level Level, parts ...interface{}) {
|
||||
log.topLevel.Raw(level, log.metadata, log.Module, fmt.Sprintln(parts...))
|
||||
}
|
||||
|
||||
// Logf formats the given message and args with fmt.Sprintf and logs the result with the given level
|
||||
func (log *Sublogger) Logf(level Level, message string, args ...interface{}) {
|
||||
log.topLevel.Raw(level, log.metadata, log.Module, fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
// Logfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the given level
|
||||
func (log *Sublogger) Logfln(level Level, message string, args ...interface{}) {
|
||||
log.topLevel.Raw(level, log.metadata, log.Module, fmt.Sprintf(message+"\n", args...))
|
||||
}
|
||||
|
||||
// Debug formats the given parts with fmt.Sprint and logs the result with the Debug level
|
||||
func (log *Sublogger) Debug(parts ...interface{}) {
|
||||
log.topLevel.Raw(LevelDebug, log.metadata, log.Module, fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
// Debugln formats the given parts with fmt.Sprintln and logs the result with the Debug level
|
||||
func (log *Sublogger) Debugln(parts ...interface{}) {
|
||||
log.topLevel.Raw(LevelDebug, log.metadata, log.Module, fmt.Sprintln(parts...))
|
||||
}
|
||||
|
||||
// Debugf formats the given message and args with fmt.Sprintf and logs the result with the Debug level
|
||||
func (log *Sublogger) Debugf(message string, args ...interface{}) {
|
||||
log.topLevel.Raw(LevelDebug, log.metadata, log.Module, fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
// Debugfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Debug level
|
||||
func (log *Sublogger) Debugfln(message string, args ...interface{}) {
|
||||
log.topLevel.Raw(LevelDebug, log.metadata, log.Module, fmt.Sprintf(message+"\n", args...))
|
||||
}
|
||||
|
||||
// Info formats the given parts with fmt.Sprint and logs the result with the Info level
|
||||
func (log *Sublogger) Info(parts ...interface{}) {
|
||||
log.topLevel.Raw(LevelInfo, log.metadata, log.Module, fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
// Infoln formats the given parts with fmt.Sprintln and logs the result with the Info level
|
||||
func (log *Sublogger) Infoln(parts ...interface{}) {
|
||||
log.topLevel.Raw(LevelInfo, log.metadata, log.Module, fmt.Sprintln(parts...))
|
||||
}
|
||||
|
||||
// Infof formats the given message and args with fmt.Sprintf and logs the result with the Info level
|
||||
func (log *Sublogger) Infof(message string, args ...interface{}) {
|
||||
log.topLevel.Raw(LevelInfo, log.metadata, log.Module, fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
// Infofln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Info level
|
||||
func (log *Sublogger) Infofln(message string, args ...interface{}) {
|
||||
log.topLevel.Raw(LevelInfo, log.metadata, log.Module, fmt.Sprintf(message+"\n", args...))
|
||||
}
|
||||
|
||||
// Warn formats the given parts with fmt.Sprint and logs the result with the Warn level
|
||||
func (log *Sublogger) Warn(parts ...interface{}) {
|
||||
log.topLevel.Raw(LevelWarn, log.metadata, log.Module, fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
// Warnln formats the given parts with fmt.Sprintln and logs the result with the Warn level
|
||||
func (log *Sublogger) Warnln(parts ...interface{}) {
|
||||
log.topLevel.Raw(LevelWarn, log.metadata, log.Module, fmt.Sprintln(parts...))
|
||||
}
|
||||
|
||||
// Warnf formats the given message and args with fmt.Sprintf and logs the result with the Warn level
|
||||
func (log *Sublogger) Warnf(message string, args ...interface{}) {
|
||||
log.topLevel.Raw(LevelWarn, log.metadata, log.Module, fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
// Warnfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Warn level
|
||||
func (log *Sublogger) Warnfln(message string, args ...interface{}) {
|
||||
log.topLevel.Raw(LevelWarn, log.metadata, log.Module, fmt.Sprintf(message+"\n", args...))
|
||||
}
|
||||
|
||||
// Error formats the given parts with fmt.Sprint and logs the result with the Error level
|
||||
func (log *Sublogger) Error(parts ...interface{}) {
|
||||
log.topLevel.Raw(LevelError, log.metadata, log.Module, fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
// Errorln formats the given parts with fmt.Sprintln and logs the result with the Error level
|
||||
func (log *Sublogger) Errorln(parts ...interface{}) {
|
||||
log.topLevel.Raw(LevelError, log.metadata, log.Module, fmt.Sprintln(parts...))
|
||||
}
|
||||
|
||||
// Errorf formats the given message and args with fmt.Sprintf and logs the result with the Error level
|
||||
func (log *Sublogger) Errorf(message string, args ...interface{}) {
|
||||
log.topLevel.Raw(LevelError, log.metadata, log.Module, fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
// Errorfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Error level
|
||||
func (log *Sublogger) Errorfln(message string, args ...interface{}) {
|
||||
log.topLevel.Raw(LevelError, log.metadata, log.Module, fmt.Sprintf(message+"\n", args...))
|
||||
}
|
||||
|
||||
// Fatal formats the given parts with fmt.Sprint and logs the result with the Fatal level
|
||||
func (log *Sublogger) Fatal(parts ...interface{}) {
|
||||
log.topLevel.Raw(LevelFatal, log.metadata, log.Module, fmt.Sprint(parts...))
|
||||
}
|
||||
|
||||
// Fatalln formats the given parts with fmt.Sprintln and logs the result with the Fatal level
|
||||
func (log *Sublogger) Fatalln(parts ...interface{}) {
|
||||
log.topLevel.Raw(LevelFatal, log.metadata, log.Module, fmt.Sprintln(parts...))
|
||||
}
|
||||
|
||||
// Fatalf formats the given message and args with fmt.Sprintf and logs the result with the Fatal level
|
||||
func (log *Sublogger) Fatalf(message string, args ...interface{}) {
|
||||
log.topLevel.Raw(LevelFatal, log.metadata, log.Module, fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
// Fatalfln formats the given message and args with fmt.Sprintf, appends a newline and logs the result with the Fatal level
|
||||
func (log *Sublogger) Fatalfln(message string, args ...interface{}) {
|
||||
log.topLevel.Raw(LevelFatal, log.metadata, log.Module, fmt.Sprintf(message+"\n", args...))
|
||||
}
|
||||
78
vendor/maunium.net/go/maulogger/v2/writer.go
generated
vendored
78
vendor/maunium.net/go/maulogger/v2/writer.go
generated
vendored
@@ -1,78 +0,0 @@
|
||||
// mauLogger - A logger for Go programs
|
||||
// Copyright (c) 2021 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 maulogger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// LogWriter is a buffered io.Writer that writes lines to a Logger.
|
||||
type LogWriter struct {
|
||||
log Logger
|
||||
lock sync.Mutex
|
||||
level Level
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
func (log *BasicLogger) Writer(level Level) io.WriteCloser {
|
||||
return &LogWriter{
|
||||
log: log,
|
||||
level: level,
|
||||
}
|
||||
}
|
||||
|
||||
func (log *Sublogger) Writer(level Level) io.WriteCloser {
|
||||
return &LogWriter{
|
||||
log: log,
|
||||
level: level,
|
||||
}
|
||||
}
|
||||
|
||||
func (lw *LogWriter) writeLine(data []byte) {
|
||||
if lw.buf.Len() == 0 {
|
||||
if len(data) == 0 {
|
||||
return
|
||||
}
|
||||
lw.log.Logln(lw.level, string(data))
|
||||
} else {
|
||||
lw.buf.Write(data)
|
||||
lw.log.Logln(lw.level, lw.buf.String())
|
||||
lw.buf.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
// Write will write lines from the given data to the buffer. If the data doesn't end with a line break,
|
||||
// everything after the last line break will be buffered until the next Write or Close call.
|
||||
func (lw *LogWriter) Write(data []byte) (int, error) {
|
||||
lw.lock.Lock()
|
||||
newline := bytes.IndexByte(data, '\n')
|
||||
if newline == len(data)-1 {
|
||||
lw.writeLine(data[:len(data)-1])
|
||||
} else if newline < 0 {
|
||||
lw.buf.Write(data)
|
||||
} else {
|
||||
lines := bytes.Split(data, []byte("\n"))
|
||||
for _, line := range lines[:len(lines)-1] {
|
||||
lw.writeLine(line)
|
||||
}
|
||||
lw.buf.Write(lines[len(lines)-1])
|
||||
}
|
||||
lw.lock.Unlock()
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// Close will flush remaining data in the buffer into the logger.
|
||||
func (lw *LogWriter) Close() error {
|
||||
lw.lock.Lock()
|
||||
lw.log.Logln(lw.level, lw.buf.String())
|
||||
lw.buf.Reset()
|
||||
lw.lock.Unlock()
|
||||
return nil
|
||||
}
|
||||
5
vendor/maunium.net/go/mautrix/.pre-commit-config.yaml
generated
vendored
5
vendor/maunium.net/go/mautrix/.pre-commit-config.yaml
generated
vendored
@@ -17,3 +17,8 @@ repos:
|
||||
- "maunium.net/go/mautrix"
|
||||
- "-w"
|
||||
- id: go-vet-repo-mod
|
||||
|
||||
- repo: https://github.com/beeper/pre-commit-go
|
||||
rev: v0.3.1
|
||||
hooks:
|
||||
- id: prevent-literal-http-methods
|
||||
|
||||
50
vendor/maunium.net/go/mautrix/CHANGELOG.md
generated
vendored
50
vendor/maunium.net/go/mautrix/CHANGELOG.md
generated
vendored
@@ -1,9 +1,59 @@
|
||||
## v0.18.0 (2024-03-16)
|
||||
|
||||
* **Breaking change *(client, bridge, appservice)*** Dropped support for
|
||||
maulogger. Only zerolog loggers are now provided by default.
|
||||
* *(bridge)* Fixed upload size limit not having a default if the server
|
||||
returned no value.
|
||||
* *(synapseadmin)* Added wrappers for some room and user admin APIs.
|
||||
(thanks to [@grvn-ht] in [#181]).
|
||||
* *(crypto/verificationhelper)* Fixed bugs.
|
||||
* *(crypto)* Fixed key backup uploading doing too much base64.
|
||||
* *(crypto)* Changed `EncryptMegolmEvent` to return an error if persisting the
|
||||
megolm session fails. This ensures that database errors won't cause messages
|
||||
to be sent with duplicate indexes.
|
||||
* *(crypto)* Changed `GetOrRequestSecret` to use a callback instead of returning
|
||||
the value directly. This allows validating the value in order to ignore
|
||||
invalid secrets.
|
||||
* *(id)* Added `ParseCommonIdentifier` function to parse any Matrix identifier
|
||||
in the [Common Identifier Format].
|
||||
* *(federation)* Added simple key server that passes the federation tester.
|
||||
|
||||
[@grvn-ht]: https://github.com/grvn-ht
|
||||
[#181]: https://github.com/mautrix/go/pull/181
|
||||
[Common Identifier Format]: https://spec.matrix.org/v1.9/appendices/#common-identifier-format
|
||||
|
||||
### beta.1 (2024-02-16)
|
||||
|
||||
* Bumped minimum Go version to 1.21.
|
||||
* *(bridge)* Bumped minimum Matrix spec version to v1.4.
|
||||
* **Breaking change *(crypto)*** Deleted old half-broken interactive
|
||||
verification code and replaced it with a new `verificationhelper`.
|
||||
* The new verification helper is still experimental.
|
||||
* Both QR and emoji verification are supported (in theory).
|
||||
* *(crypto)* Added support for server-side key backup.
|
||||
* *(crypto)* Added support for receiving and sending secrets like cross-signing
|
||||
private keys via secret sharing.
|
||||
* *(crypto)* Added support for tracking which devices megolm sessions were
|
||||
initially shared to, and allowing re-sharing the keys to those sessions.
|
||||
* *(client)* Changed cross-signing key upload method to accept a callback for
|
||||
user-interactive auth instead of only hardcoding password support.
|
||||
* *(appservice)* Dropped support for legacy non-prefixed appservice paths
|
||||
(e.g. `/transactions` instead of `/_matrix/app/v1/transactions`).
|
||||
* *(appservice)* Dropped support for legacy `access_token` authorization in
|
||||
appservice endpoints.
|
||||
* *(bridge)* Fixed `RawArgs` field in command events of command state callbacks.
|
||||
* *(appservice)* Added `CreateFull` helper function for creating an `AppService`
|
||||
instance with all the mandatory fields set.
|
||||
|
||||
## v0.17.0 (2024-01-16)
|
||||
|
||||
* **Breaking change *(bridge)*** Added raw event to portal membership handling
|
||||
functions.
|
||||
* **Breaking change *(everything)*** Added context parameters to all functions
|
||||
(started by [@recht] in [#144]).
|
||||
* **Breaking change *(client)*** Moved event source from sync event handler
|
||||
function parameters to the `Mautrix.EventSource` field inside the event
|
||||
struct.
|
||||
* **Breaking change *(client)*** Moved `EventSource` to `event.Source`.
|
||||
* *(client)* Removed deprecated `OldEventIgnorer`. The non-deprecated version
|
||||
(`Client.DontProcessOldEvents`) is still available.
|
||||
|
||||
344
vendor/maunium.net/go/mautrix/client.go
generated
vendored
344
vendor/maunium.net/go/mautrix/client.go
generated
vendored
@@ -19,8 +19,8 @@ import (
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"go.mau.fi/util/retryafter"
|
||||
"maunium.net/go/maulogger/v2/maulogadapt"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/backup"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
"maunium.net/go/mautrix/pushrules"
|
||||
@@ -34,15 +34,18 @@ type CryptoHelper interface {
|
||||
Init(context.Context) error
|
||||
}
|
||||
|
||||
// Deprecated: switch to zerolog
|
||||
type Logger interface {
|
||||
Debugfln(message string, args ...interface{})
|
||||
}
|
||||
type VerificationHelper interface {
|
||||
Init(context.Context) error
|
||||
StartVerification(ctx context.Context, to id.UserID) (id.VerificationTransactionID, error)
|
||||
StartInRoomVerification(ctx context.Context, roomID id.RoomID, to id.UserID) (id.VerificationTransactionID, error)
|
||||
AcceptVerification(ctx context.Context, txnID id.VerificationTransactionID) error
|
||||
CancelVerification(ctx context.Context, txnID id.VerificationTransactionID, code event.VerificationCancelCode, reason string) error
|
||||
|
||||
// Deprecated: switch to zerolog
|
||||
type WarnLogger interface {
|
||||
Logger
|
||||
Warnfln(message string, args ...interface{})
|
||||
HandleScannedQRData(ctx context.Context, data []byte) error
|
||||
ConfirmQRCodeScanned(ctx context.Context, txnID id.VerificationTransactionID) error
|
||||
|
||||
StartSAS(ctx context.Context, txnID id.VerificationTransactionID) error
|
||||
ConfirmSAS(ctx context.Context, txnID id.VerificationTransactionID) error
|
||||
}
|
||||
|
||||
// Client represents a Matrix client.
|
||||
@@ -57,10 +60,9 @@ type Client struct {
|
||||
Store SyncStore // The thing which can store tokens/ids
|
||||
StateStore StateStore
|
||||
Crypto CryptoHelper
|
||||
Verification VerificationHelper
|
||||
|
||||
Log zerolog.Logger
|
||||
// Deprecated: switch to the zerolog instance in Log
|
||||
Logger Logger
|
||||
|
||||
RequestHook func(req *http.Request)
|
||||
ResponseHook func(req *http.Request, resp *http.Response, duration time.Duration)
|
||||
@@ -107,7 +109,7 @@ func DiscoverClientAPI(ctx context.Context, serverName string) (*ClientWellKnown
|
||||
Path: "/.well-known/matrix/client",
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", wellKnownURL.String(), nil)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, wellKnownURL.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -576,14 +578,14 @@ func (cli *Client) executeCompiledRequest(req *http.Request, retries int, backof
|
||||
func (cli *Client) Whoami(ctx context.Context) (resp *RespWhoami, err error) {
|
||||
|
||||
urlPath := cli.BuildClientURL("v3", "account", "whoami")
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateFilter makes an HTTP request according to https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3useruseridfilter
|
||||
func (cli *Client) CreateFilter(ctx context.Context, filter *Filter) (resp *RespCreateFilter, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "user", cli.UserID, "filter")
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, filter, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, filter, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -764,7 +766,7 @@ func (cli *Client) RegisterDummy(ctx context.Context, req *ReqRegister) (*RespRe
|
||||
// GetLoginFlows fetches the login flows that the homeserver supports using https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3login
|
||||
func (cli *Client) GetLoginFlows(ctx context.Context) (resp *RespLoginFlows, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "login")
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -808,7 +810,7 @@ func (cli *Client) Login(ctx context.Context, req *ReqLogin) (resp *RespLogin, e
|
||||
// This does not clear the credentials from the client instance. See ClearCredentials() instead.
|
||||
func (cli *Client) Logout(ctx context.Context) (resp *RespLogout, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "logout")
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -816,21 +818,21 @@ func (cli *Client) Logout(ctx context.Context) (resp *RespLogout, err error) {
|
||||
// This does not clear the credentials from the client instance. See ClearCredentials() instead.
|
||||
func (cli *Client) LogoutAll(ctx context.Context) (resp *RespLogout, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "logout", "all")
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// Versions returns the list of supported Matrix versions on this homeserver. See https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientversions
|
||||
func (cli *Client) Versions(ctx context.Context) (resp *RespVersions, err error) {
|
||||
urlPath := cli.BuildClientURL("versions")
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// Capabilities returns capabilities on this homeserver. See https://spec.matrix.org/v1.3/client-server-api/#capabilities-negotiation
|
||||
func (cli *Client) Capabilities(ctx context.Context) (resp *RespCapabilities, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "capabilities")
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -847,7 +849,7 @@ func (cli *Client) JoinRoom(ctx context.Context, roomIDorAlias, serverName strin
|
||||
} else {
|
||||
urlPath = cli.BuildClientURL("v3", "join", roomIDorAlias)
|
||||
}
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, content, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, content, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
err = cli.StateStore.SetMembership(ctx, resp.RoomID, cli.UserID, event.MembershipJoin)
|
||||
if err != nil {
|
||||
@@ -862,7 +864,7 @@ func (cli *Client) JoinRoom(ctx context.Context, roomIDorAlias, serverName strin
|
||||
// Unlike JoinRoom, this method can only be used to join rooms that the server already knows about.
|
||||
// It's mostly intended for bridges and other things where it's already certain that the server is in the room.
|
||||
func (cli *Client) JoinRoomByID(ctx context.Context, roomID id.RoomID) (resp *RespJoinRoom, err error) {
|
||||
_, err = cli.MakeRequest(ctx, "POST", cli.BuildClientURL("v3", "rooms", roomID, "join"), nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, cli.BuildClientURL("v3", "rooms", roomID, "join"), nil, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
err = cli.StateStore.SetMembership(ctx, resp.RoomID, cli.UserID, event.MembershipJoin)
|
||||
if err != nil {
|
||||
@@ -874,14 +876,14 @@ func (cli *Client) JoinRoomByID(ctx context.Context, roomID id.RoomID) (resp *Re
|
||||
|
||||
func (cli *Client) GetProfile(ctx context.Context, mxid id.UserID) (resp *RespUserProfile, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "profile", mxid)
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// GetDisplayName returns the display name of the user with the specified MXID. See https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3profileuseriddisplayname
|
||||
func (cli *Client) GetDisplayName(ctx context.Context, mxid id.UserID) (resp *RespUserDisplayName, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "profile", mxid, "displayname")
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -896,7 +898,7 @@ func (cli *Client) SetDisplayName(ctx context.Context, displayName string) (err
|
||||
s := struct {
|
||||
DisplayName string `json:"displayname"`
|
||||
}{displayName}
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, &s, nil)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, &s, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -907,7 +909,7 @@ func (cli *Client) GetAvatarURL(ctx context.Context, mxid id.UserID) (url id.Con
|
||||
AvatarURL id.ContentURI `json:"avatar_url"`
|
||||
}{}
|
||||
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &s)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &s)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -926,7 +928,7 @@ func (cli *Client) SetAvatarURL(ctx context.Context, url id.ContentURI) (err err
|
||||
s := struct {
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
}{url.String()}
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, &s, nil)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, &s, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -937,21 +939,21 @@ func (cli *Client) SetAvatarURL(ctx context.Context, url id.ContentURI) (err err
|
||||
// BeeperUpdateProfile sets custom fields in the user's profile.
|
||||
func (cli *Client) BeeperUpdateProfile(ctx context.Context, data map[string]any) (err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "profile", cli.UserID)
|
||||
_, err = cli.MakeRequest(ctx, "PATCH", urlPath, &data, nil)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPatch, urlPath, &data, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// GetAccountData gets the user's account data of this type. See https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3useruseridaccount_datatype
|
||||
func (cli *Client) GetAccountData(ctx context.Context, name string, output interface{}) (err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "user", cli.UserID, "account_data", name)
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, output)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, output)
|
||||
return
|
||||
}
|
||||
|
||||
// SetAccountData sets the user's account data of this type. See https://spec.matrix.org/v1.2/client-server-api/#put_matrixclientv3useruseridaccount_datatype
|
||||
func (cli *Client) SetAccountData(ctx context.Context, name string, data interface{}) (err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "user", cli.UserID, "account_data", name)
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, data, nil)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, data, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -962,14 +964,14 @@ func (cli *Client) SetAccountData(ctx context.Context, name string, data interfa
|
||||
// GetRoomAccountData gets the user's account data of this type in a specific room. See https://spec.matrix.org/v1.2/client-server-api/#put_matrixclientv3useruseridaccount_datatype
|
||||
func (cli *Client) GetRoomAccountData(ctx context.Context, roomID id.RoomID, name string, output interface{}) (err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "user", cli.UserID, "rooms", roomID, "account_data", name)
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, output)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, output)
|
||||
return
|
||||
}
|
||||
|
||||
// SetRoomAccountData sets the user's account data of this type in a specific room. See https://spec.matrix.org/v1.2/client-server-api/#put_matrixclientv3useruseridroomsroomidaccount_datatype
|
||||
func (cli *Client) SetRoomAccountData(ctx context.Context, roomID id.RoomID, name string, data interface{}) (err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "user", cli.UserID, "rooms", roomID, "account_data", name)
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, data, nil)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, data, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1027,7 +1029,7 @@ func (cli *Client) SendMessageEvent(ctx context.Context, roomID id.RoomID, event
|
||||
|
||||
urlData := ClientURLPath{"v3", "rooms", roomID, "send", eventType.String(), txnID}
|
||||
urlPath := cli.BuildURLWithQuery(urlData, queryParams)
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, contentJSON, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, contentJSON, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1035,7 +1037,7 @@ func (cli *Client) SendMessageEvent(ctx context.Context, roomID id.RoomID, event
|
||||
// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
|
||||
func (cli *Client) SendStateEvent(ctx context.Context, roomID id.RoomID, eventType event.Type, stateKey string, contentJSON interface{}) (resp *RespSendEvent, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "rooms", roomID, "state", eventType.String(), stateKey)
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, contentJSON, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, contentJSON, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
cli.updateStoreWithOutgoingEvent(ctx, roomID, eventType, stateKey, contentJSON)
|
||||
}
|
||||
@@ -1048,7 +1050,7 @@ func (cli *Client) SendMassagedStateEvent(ctx context.Context, roomID id.RoomID,
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "rooms", roomID, "state", eventType.String(), stateKey}, map[string]string{
|
||||
"ts": strconv.FormatInt(ts, 10),
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, contentJSON, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, contentJSON, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
cli.updateStoreWithOutgoingEvent(ctx, roomID, eventType, stateKey, contentJSON)
|
||||
}
|
||||
@@ -1102,7 +1104,7 @@ func (cli *Client) RedactEvent(ctx context.Context, roomID id.RoomID, eventID id
|
||||
txnID = cli.TxnID()
|
||||
}
|
||||
urlPath := cli.BuildClientURL("v3", "rooms", roomID, "redact", eventID, txnID)
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, req.Extra, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, req.Extra, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1114,7 +1116,7 @@ func (cli *Client) RedactEvent(ctx context.Context, roomID id.RoomID, eventID id
|
||||
// fmt.Println("Room:", resp.RoomID)
|
||||
func (cli *Client) CreateRoom(ctx context.Context, req *ReqCreateRoom) (resp *RespCreateRoom, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "createRoom")
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, req, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
storeErr := cli.StateStore.SetMembership(ctx, resp.RoomID, cli.UserID, event.MembershipJoin)
|
||||
if storeErr != nil {
|
||||
@@ -1153,7 +1155,7 @@ func (cli *Client) LeaveRoom(ctx context.Context, roomID id.RoomID, optionalReq
|
||||
panic("invalid number of arguments to LeaveRoom")
|
||||
}
|
||||
u := cli.BuildClientURL("v3", "rooms", roomID, "leave")
|
||||
_, err = cli.MakeRequest(ctx, "POST", u, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, u, req, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
err = cli.StateStore.SetMembership(ctx, roomID, cli.UserID, event.MembershipLeave)
|
||||
if err != nil {
|
||||
@@ -1166,14 +1168,14 @@ func (cli *Client) LeaveRoom(ctx context.Context, roomID id.RoomID, optionalReq
|
||||
// ForgetRoom forgets a room entirely. See https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3roomsroomidforget
|
||||
func (cli *Client) ForgetRoom(ctx context.Context, roomID id.RoomID) (resp *RespForgetRoom, err error) {
|
||||
u := cli.BuildClientURL("v3", "rooms", roomID, "forget")
|
||||
_, err = cli.MakeRequest(ctx, "POST", u, struct{}{}, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, u, struct{}{}, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// InviteUser invites a user to a room. See https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3roomsroomidinvite
|
||||
func (cli *Client) InviteUser(ctx context.Context, roomID id.RoomID, req *ReqInviteUser) (resp *RespInviteUser, err error) {
|
||||
u := cli.BuildClientURL("v3", "rooms", roomID, "invite")
|
||||
_, err = cli.MakeRequest(ctx, "POST", u, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, u, req, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
err = cli.StateStore.SetMembership(ctx, roomID, req.UserID, event.MembershipInvite)
|
||||
if err != nil {
|
||||
@@ -1186,14 +1188,14 @@ func (cli *Client) InviteUser(ctx context.Context, roomID id.RoomID, req *ReqInv
|
||||
// InviteUserByThirdParty invites a third-party identifier to a room. See https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3roomsroomidinvite-1
|
||||
func (cli *Client) InviteUserByThirdParty(ctx context.Context, roomID id.RoomID, req *ReqInvite3PID) (resp *RespInviteUser, err error) {
|
||||
u := cli.BuildClientURL("v3", "rooms", roomID, "invite")
|
||||
_, err = cli.MakeRequest(ctx, "POST", u, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, u, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// KickUser kicks a user from a room. See https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3roomsroomidkick
|
||||
func (cli *Client) KickUser(ctx context.Context, roomID id.RoomID, req *ReqKickUser) (resp *RespKickUser, err error) {
|
||||
u := cli.BuildClientURL("v3", "rooms", roomID, "kick")
|
||||
_, err = cli.MakeRequest(ctx, "POST", u, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, u, req, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
err = cli.StateStore.SetMembership(ctx, roomID, req.UserID, event.MembershipLeave)
|
||||
if err != nil {
|
||||
@@ -1206,7 +1208,7 @@ func (cli *Client) KickUser(ctx context.Context, roomID id.RoomID, req *ReqKickU
|
||||
// BanUser bans a user from a room. See https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3roomsroomidban
|
||||
func (cli *Client) BanUser(ctx context.Context, roomID id.RoomID, req *ReqBanUser) (resp *RespBanUser, err error) {
|
||||
u := cli.BuildClientURL("v3", "rooms", roomID, "ban")
|
||||
_, err = cli.MakeRequest(ctx, "POST", u, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, u, req, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
err = cli.StateStore.SetMembership(ctx, roomID, req.UserID, event.MembershipBan)
|
||||
if err != nil {
|
||||
@@ -1219,7 +1221,7 @@ func (cli *Client) BanUser(ctx context.Context, roomID id.RoomID, req *ReqBanUse
|
||||
// UnbanUser unbans a user from a room. See https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3roomsroomidunban
|
||||
func (cli *Client) UnbanUser(ctx context.Context, roomID id.RoomID, req *ReqUnbanUser) (resp *RespUnbanUser, err error) {
|
||||
u := cli.BuildClientURL("v3", "rooms", roomID, "unban")
|
||||
_, err = cli.MakeRequest(ctx, "POST", u, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, u, req, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
err = cli.StateStore.SetMembership(ctx, roomID, req.UserID, event.MembershipLeave)
|
||||
if err != nil {
|
||||
@@ -1233,7 +1235,7 @@ func (cli *Client) UnbanUser(ctx context.Context, roomID id.RoomID, req *ReqUnba
|
||||
func (cli *Client) UserTyping(ctx context.Context, roomID id.RoomID, typing bool, timeout time.Duration) (resp *RespTyping, err error) {
|
||||
req := ReqTyping{Typing: typing, Timeout: timeout.Milliseconds()}
|
||||
u := cli.BuildClientURL("v3", "rooms", roomID, "typing", cli.UserID)
|
||||
_, err = cli.MakeRequest(ctx, "PUT", u, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, u, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1241,7 +1243,7 @@ func (cli *Client) UserTyping(ctx context.Context, roomID id.RoomID, typing bool
|
||||
func (cli *Client) GetPresence(ctx context.Context, userID id.UserID) (resp *RespPresence, err error) {
|
||||
resp = new(RespPresence)
|
||||
u := cli.BuildClientURL("v3", "presence", userID, "status")
|
||||
_, err = cli.MakeRequest(ctx, "GET", u, nil, resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, u, nil, resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1253,7 +1255,7 @@ func (cli *Client) GetOwnPresence(ctx context.Context) (resp *RespPresence, err
|
||||
func (cli *Client) SetPresence(ctx context.Context, status event.Presence) (err error) {
|
||||
req := ReqPresence{Presence: status}
|
||||
u := cli.BuildClientURL("v3", "presence", cli.UserID, "status")
|
||||
_, err = cli.MakeRequest(ctx, "PUT", u, req, nil)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, u, req, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1295,7 +1297,7 @@ func (cli *Client) updateStoreWithOutgoingEvent(ctx context.Context, roomID id.R
|
||||
// See https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3roomsroomidstateeventtypestatekey
|
||||
func (cli *Client) StateEvent(ctx context.Context, roomID id.RoomID, eventType event.Type, stateKey string, outContent interface{}) (err error) {
|
||||
u := cli.BuildClientURL("v3", "rooms", roomID, "state", eventType.String(), stateKey)
|
||||
_, err = cli.MakeRequest(ctx, "GET", u, nil, outContent)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, u, nil, outContent)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
cli.updateStoreWithOutgoingEvent(ctx, roomID, eventType, stateKey, outContent)
|
||||
}
|
||||
@@ -1367,13 +1369,13 @@ func (cli *Client) State(ctx context.Context, roomID id.RoomID) (stateMap RoomSt
|
||||
// GetMediaConfig fetches the configuration of the content repository, such as upload limitations.
|
||||
func (cli *Client) GetMediaConfig(ctx context.Context) (resp *RespMediaConfig, err error) {
|
||||
u := cli.BuildURL(MediaURLPath{"v3", "config"})
|
||||
_, err = cli.MakeRequest(ctx, "GET", u, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, u, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// UploadLink uploads an HTTP URL and then returns an MXC URI.
|
||||
func (cli *Client) UploadLink(ctx context.Context, link string) (*RespMediaUpload, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", link, nil)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, link, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1672,12 +1674,14 @@ func (cli *Client) GetURLPreview(ctx context.Context, url string) (*RespPreviewU
|
||||
// This API is primarily designed for application services which may want to efficiently look up joined members in a room.
|
||||
func (cli *Client) JoinedMembers(ctx context.Context, roomID id.RoomID) (resp *RespJoinedMembers, err error) {
|
||||
u := cli.BuildClientURL("v3", "rooms", roomID, "joined_members")
|
||||
_, err = cli.MakeRequest(ctx, "GET", u, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, u, nil, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
clearErr := cli.StateStore.ClearCachedMembers(ctx, roomID, event.MembershipJoin)
|
||||
cli.cliOrContextLog(ctx).Warn().Err(clearErr).
|
||||
Stringer("room_id", roomID).
|
||||
Msg("Failed to clear cached member list after fetching joined members")
|
||||
if clearErr != nil {
|
||||
cli.cliOrContextLog(ctx).Warn().Err(clearErr).
|
||||
Stringer("room_id", roomID).
|
||||
Msg("Failed to clear cached member list after fetching joined members")
|
||||
}
|
||||
for userID, member := range resp.Joined {
|
||||
updateErr := cli.StateStore.SetMember(ctx, roomID, userID, &event.MemberEventContent{
|
||||
Membership: event.MembershipJoin,
|
||||
@@ -1685,7 +1689,7 @@ func (cli *Client) JoinedMembers(ctx context.Context, roomID id.RoomID) (resp *R
|
||||
Displayname: member.DisplayName,
|
||||
})
|
||||
if updateErr != nil {
|
||||
cli.cliOrContextLog(ctx).Warn().Err(clearErr).
|
||||
cli.cliOrContextLog(ctx).Warn().Err(updateErr).
|
||||
Stringer("room_id", roomID).
|
||||
Stringer("user_id", userID).
|
||||
Msg("Failed to update membership in state store after fetching joined members")
|
||||
@@ -1711,7 +1715,7 @@ func (cli *Client) Members(ctx context.Context, roomID id.RoomID, req ...ReqMemb
|
||||
query["not_membership"] = string(extra.NotMembership)
|
||||
}
|
||||
u := cli.BuildURLWithQuery(ClientURLPath{"v3", "rooms", roomID, "members"}, query)
|
||||
_, err = cli.MakeRequest(ctx, "GET", u, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, u, nil, &resp)
|
||||
if err == nil && cli.StateStore != nil {
|
||||
var clearMemberships []event.Membership
|
||||
if extra.Membership != "" {
|
||||
@@ -1719,9 +1723,11 @@ func (cli *Client) Members(ctx context.Context, roomID id.RoomID, req ...ReqMemb
|
||||
}
|
||||
if extra.NotMembership == "" {
|
||||
clearErr := cli.StateStore.ClearCachedMembers(ctx, roomID, clearMemberships...)
|
||||
cli.cliOrContextLog(ctx).Warn().Err(clearErr).
|
||||
Stringer("room_id", roomID).
|
||||
Msg("Failed to clear cached member list after fetching joined members")
|
||||
if clearErr != nil {
|
||||
cli.cliOrContextLog(ctx).Warn().Err(clearErr).
|
||||
Stringer("room_id", roomID).
|
||||
Msg("Failed to clear cached member list after fetching joined members")
|
||||
}
|
||||
}
|
||||
for _, evt := range resp.Chunk {
|
||||
UpdateStateStore(ctx, cli.StateStore, evt)
|
||||
@@ -1736,7 +1742,7 @@ func (cli *Client) Members(ctx context.Context, roomID id.RoomID, req ...ReqMemb
|
||||
// This API is primarily designed for application services which may want to efficiently look up joined rooms.
|
||||
func (cli *Client) JoinedRooms(ctx context.Context) (resp *RespJoinedRooms, err error) {
|
||||
u := cli.BuildClientURL("v3", "joined_rooms")
|
||||
_, err = cli.MakeRequest(ctx, "GET", u, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, u, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1775,7 +1781,7 @@ func (cli *Client) Messages(ctx context.Context, roomID id.RoomID, from, to stri
|
||||
}
|
||||
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "rooms", roomID, "messages"}, query)
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1810,13 +1816,13 @@ func (cli *Client) Context(ctx context.Context, roomID id.RoomID, eventID id.Eve
|
||||
}
|
||||
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "rooms", roomID, "context", eventID}, query)
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) GetEvent(ctx context.Context, roomID id.RoomID, eventID id.EventID) (resp *event.Event, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "rooms", roomID, "event", eventID)
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1837,13 +1843,13 @@ func (cli *Client) MarkReadWithContent(ctx context.Context, roomID id.RoomID, ev
|
||||
// To mark a message in a specific thread as read, use pass a ReqSendReceipt as the content.
|
||||
func (cli *Client) SendReceipt(ctx context.Context, roomID id.RoomID, eventID id.EventID, receiptType event.ReceiptType, content interface{}) (err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "rooms", roomID, "receipt", receiptType, eventID)
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, content, nil)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, content, nil)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) SetReadMarkers(ctx context.Context, roomID id.RoomID, content interface{}) (err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "rooms", roomID, "read_markers")
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, content, nil)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, content, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1857,7 +1863,7 @@ func (cli *Client) AddTag(ctx context.Context, roomID id.RoomID, tag string, ord
|
||||
|
||||
func (cli *Client) AddTagWithCustomData(ctx context.Context, roomID id.RoomID, tag string, data interface{}) (err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "user", cli.UserID, "rooms", roomID, "tags", tag)
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, data, nil)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, data, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1868,13 +1874,13 @@ func (cli *Client) GetTags(ctx context.Context, roomID id.RoomID) (tags event.Ta
|
||||
|
||||
func (cli *Client) GetTagsWithCustomData(ctx context.Context, roomID id.RoomID, resp interface{}) (err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "user", cli.UserID, "rooms", roomID, "tags")
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) RemoveTag(ctx context.Context, roomID id.RoomID, tag string) (err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "user", cli.UserID, "rooms", roomID, "tags", tag)
|
||||
_, err = cli.MakeRequest(ctx, "DELETE", urlPath, nil, nil)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodDelete, urlPath, nil, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1889,49 +1895,49 @@ func (cli *Client) SetTags(ctx context.Context, roomID id.RoomID, tags event.Tag
|
||||
// See https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3voipturnserver
|
||||
func (cli *Client) TurnServer(ctx context.Context) (resp *RespTurnServer, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "voip", "turnServer")
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) CreateAlias(ctx context.Context, alias id.RoomAlias, roomID id.RoomID) (resp *RespAliasCreate, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "directory", "room", alias)
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, &ReqAliasCreate{RoomID: roomID}, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, &ReqAliasCreate{RoomID: roomID}, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) ResolveAlias(ctx context.Context, alias id.RoomAlias) (resp *RespAliasResolve, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "directory", "room", alias)
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) DeleteAlias(ctx context.Context, alias id.RoomAlias) (resp *RespAliasDelete, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "directory", "room", alias)
|
||||
_, err = cli.MakeRequest(ctx, "DELETE", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodDelete, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) GetAliases(ctx context.Context, roomID id.RoomID) (resp *RespAliasList, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "rooms", roomID, "aliases")
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) UploadKeys(ctx context.Context, req *ReqUploadKeys) (resp *RespUploadKeys, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "keys", "upload")
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) QueryKeys(ctx context.Context, req *ReqQueryKeys) (resp *RespQueryKeys, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "keys", "query")
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) ClaimKeys(ctx context.Context, req *ReqClaimKeys) (resp *RespClaimKeys, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "keys", "claim")
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1940,43 +1946,195 @@ func (cli *Client) GetKeyChanges(ctx context.Context, from, to string) (resp *Re
|
||||
"from": from,
|
||||
"to": to,
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// GetKeyBackup retrieves the keys from the backup.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3room_keyskeys
|
||||
func (cli *Client) GetKeyBackup(ctx context.Context, version id.KeyBackupVersion) (resp *RespRoomKeys[backup.EncryptedSessionData[backup.MegolmSessionData]], err error) {
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "room_keys", "keys"}, map[string]string{
|
||||
"version": string(version),
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// PutKeysInBackup stores several keys in the backup.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#put_matrixclientv3room_keyskeys
|
||||
func (cli *Client) PutKeysInBackup(ctx context.Context, version id.KeyBackupVersion, req *ReqKeyBackup) (resp *RespRoomKeysUpdate, err error) {
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "room_keys", "keys"}, map[string]string{
|
||||
"version": string(version),
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteKeyBackup deletes all keys from the backup.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#delete_matrixclientv3room_keyskeys
|
||||
func (cli *Client) DeleteKeyBackup(ctx context.Context, version id.KeyBackupVersion) (resp *RespRoomKeysUpdate, err error) {
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "room_keys", "keys"}, map[string]string{
|
||||
"version": string(version),
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, http.MethodDelete, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// GetKeyBackupForRoom retrieves the keys from the backup for the given room.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3room_keyskeysroomid
|
||||
func (cli *Client) GetKeyBackupForRoom(
|
||||
ctx context.Context, version id.KeyBackupVersion, roomID id.RoomID,
|
||||
) (resp *RespRoomKeyBackup[backup.EncryptedSessionData[backup.MegolmSessionData]], err error) {
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "room_keys", "keys", roomID.String()}, map[string]string{
|
||||
"version": string(version),
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// PutKeysInBackupForRoom stores several keys in the backup for the given room.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#put_matrixclientv3room_keyskeysroomid
|
||||
func (cli *Client) PutKeysInBackupForRoom(ctx context.Context, version id.KeyBackupVersion, roomID id.RoomID, req *ReqRoomKeyBackup) (resp *RespRoomKeysUpdate, err error) {
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "room_keys", "keys", roomID.String()}, map[string]string{
|
||||
"version": string(version),
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteKeysFromBackupForRoom deletes all the keys in the backup for the given
|
||||
// room.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#delete_matrixclientv3room_keyskeysroomid
|
||||
func (cli *Client) DeleteKeysFromBackupForRoom(ctx context.Context, version id.KeyBackupVersion, roomID id.RoomID) (resp *RespRoomKeysUpdate, err error) {
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "room_keys", "keys", roomID.String()}, map[string]string{
|
||||
"version": string(version),
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, http.MethodDelete, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// GetKeyBackupForRoomAndSession retrieves a key from the backup.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3room_keyskeysroomidsessionid
|
||||
func (cli *Client) GetKeyBackupForRoomAndSession(
|
||||
ctx context.Context, version id.KeyBackupVersion, roomID id.RoomID, sessionID id.SessionID,
|
||||
) (resp *RespKeyBackupData[backup.EncryptedSessionData[backup.MegolmSessionData]], err error) {
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "room_keys", "keys", roomID.String(), sessionID.String()}, map[string]string{
|
||||
"version": string(version),
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// PutKeysInBackupForRoomAndSession stores a key in the backup.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#put_matrixclientv3room_keyskeysroomidsessionid
|
||||
func (cli *Client) PutKeysInBackupForRoomAndSession(ctx context.Context, version id.KeyBackupVersion, roomID id.RoomID, sessionID id.SessionID, req *ReqKeyBackupData) (resp *RespRoomKeysUpdate, err error) {
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "room_keys", "keys", roomID.String(), sessionID.String()}, map[string]string{
|
||||
"version": string(version),
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteKeysInBackupForRoomAndSession deletes a key from the backup.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#delete_matrixclientv3room_keyskeysroomidsessionid
|
||||
func (cli *Client) DeleteKeysInBackupForRoomAndSession(ctx context.Context, version id.KeyBackupVersion, roomID id.RoomID, sessionID id.SessionID) (resp *RespRoomKeysUpdate, err error) {
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "room_keys", "keys", roomID.String(), sessionID.String()}, map[string]string{
|
||||
"version": string(version),
|
||||
})
|
||||
_, err = cli.MakeRequest(ctx, http.MethodDelete, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// GetKeyBackupLatestVersion returns information about the latest backup version.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3room_keysversion
|
||||
func (cli *Client) GetKeyBackupLatestVersion(ctx context.Context) (resp *RespRoomKeysVersion[backup.MegolmAuthData], err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "room_keys", "version")
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateKeyBackupVersion creates a new key backup.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#post_matrixclientv3room_keysversion
|
||||
func (cli *Client) CreateKeyBackupVersion(ctx context.Context, req *ReqRoomKeysVersionCreate[backup.MegolmAuthData]) (resp *RespRoomKeysVersionCreate, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "room_keys", "version")
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// GetKeyBackupVersion returns information about an existing key backup.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3room_keysversionversion
|
||||
func (cli *Client) GetKeyBackupVersion(ctx context.Context, version id.KeyBackupVersion) (resp *RespRoomKeysVersion[backup.MegolmAuthData], err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "room_keys", "version", version)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateKeyBackupVersion updates information about an existing key backup. Only
|
||||
// the auth_data can be modified.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.9/client-server-api/#put_matrixclientv3room_keysversionversion
|
||||
func (cli *Client) UpdateKeyBackupVersion(ctx context.Context, version id.KeyBackupVersion, req *ReqRoomKeysVersionUpdate[backup.MegolmAuthData]) error {
|
||||
urlPath := cli.BuildClientURL("v3", "room_keys", "version", version)
|
||||
_, err := cli.MakeRequest(ctx, http.MethodPut, urlPath, nil, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteKeyBackupVersion deletes an existing key backup. Both the information
|
||||
// about the backup, as well as all key data related to the backup will be
|
||||
// deleted.
|
||||
//
|
||||
// See: https://spec.matrix.org/v1.1/client-server-api/#delete_matrixclientv3room_keysversionversion
|
||||
func (cli *Client) DeleteKeyBackupVersion(ctx context.Context, version id.KeyBackupVersion) error {
|
||||
urlPath := cli.BuildClientURL("v3", "room_keys", "version", version)
|
||||
_, err := cli.MakeRequest(ctx, http.MethodDelete, urlPath, nil, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (cli *Client) SendToDevice(ctx context.Context, eventType event.Type, req *ReqSendToDevice) (resp *RespSendToDevice, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "sendToDevice", eventType.String(), cli.TxnID())
|
||||
_, err = cli.MakeRequest(ctx, "PUT", urlPath, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPut, urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) GetDevicesInfo(ctx context.Context) (resp *RespDevicesInfo, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "devices")
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) GetDeviceInfo(ctx context.Context, deviceID id.DeviceID) (resp *RespDeviceInfo, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "devices", deviceID)
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) SetDeviceInfo(ctx context.Context, deviceID id.DeviceID, req *ReqDeviceInfo) error {
|
||||
urlPath := cli.BuildClientURL("v3", "devices", deviceID)
|
||||
_, err := cli.MakeRequest(ctx, "PUT", urlPath, req, nil)
|
||||
_, err := cli.MakeRequest(ctx, http.MethodPut, urlPath, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (cli *Client) DeleteDevice(ctx context.Context, deviceID id.DeviceID, req *ReqDeleteDevice) error {
|
||||
urlPath := cli.BuildClientURL("v3", "devices", deviceID)
|
||||
_, err := cli.MakeRequest(ctx, "DELETE", urlPath, req, nil)
|
||||
_, err := cli.MakeRequest(ctx, http.MethodDelete, urlPath, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (cli *Client) DeleteDevices(ctx context.Context, req *ReqDeleteDevices) error {
|
||||
urlPath := cli.BuildClientURL("v3", "delete_devices")
|
||||
_, err := cli.MakeRequest(ctx, "DELETE", urlPath, req, nil)
|
||||
_, err := cli.MakeRequest(ctx, http.MethodDelete, urlPath, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1992,7 +2150,7 @@ func (cli *Client) UploadCrossSigningKeys(ctx context.Context, keys *UploadCross
|
||||
RequestJSON: keys,
|
||||
SensitiveContent: keys.Auth != nil,
|
||||
})
|
||||
if respErr, ok := err.(HTTPError); ok && respErr.IsStatus(http.StatusUnauthorized) {
|
||||
if respErr, ok := err.(HTTPError); ok && respErr.IsStatus(http.StatusUnauthorized) && uiaCallback != nil {
|
||||
// try again with UI auth
|
||||
var uiAuthResp RespUserInteractive
|
||||
if err := json.Unmarshal(content, &uiAuthResp); err != nil {
|
||||
@@ -2001,7 +2159,7 @@ func (cli *Client) UploadCrossSigningKeys(ctx context.Context, keys *UploadCross
|
||||
auth := uiaCallback(&uiAuthResp)
|
||||
if auth != nil {
|
||||
keys.Auth = auth
|
||||
return cli.UploadCrossSigningKeys(ctx, keys, uiaCallback)
|
||||
return cli.UploadCrossSigningKeys(ctx, keys, nil)
|
||||
}
|
||||
}
|
||||
return err
|
||||
@@ -2009,7 +2167,7 @@ func (cli *Client) UploadCrossSigningKeys(ctx context.Context, keys *UploadCross
|
||||
|
||||
func (cli *Client) UploadSignatures(ctx context.Context, req *ReqUploadSignatures) (resp *RespUploadSignatures, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "keys", "signatures", "upload")
|
||||
_, err = cli.MakeRequest(ctx, "POST", urlPath, req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2023,13 +2181,13 @@ func (cli *Client) GetScopedPushRules(ctx context.Context, scope string) (resp *
|
||||
u, _ := url.Parse(cli.BuildClientURL("v3", "pushrules", scope))
|
||||
// client.BuildURL returns the URL without a trailing slash, but the pushrules endpoint requires the slash.
|
||||
u.Path += "/"
|
||||
_, err = cli.MakeRequest(ctx, "GET", u.String(), nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, u.String(), nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) GetPushRule(ctx context.Context, scope string, kind pushrules.PushRuleType, ruleID string) (resp *pushrules.PushRule, err error) {
|
||||
urlPath := cli.BuildClientURL("v3", "pushrules", scope, kind, ruleID)
|
||||
_, err = cli.MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodGet, urlPath, nil, &resp)
|
||||
if resp != nil {
|
||||
resp.Type = kind
|
||||
}
|
||||
@@ -2038,7 +2196,7 @@ func (cli *Client) GetPushRule(ctx context.Context, scope string, kind pushrules
|
||||
|
||||
func (cli *Client) DeletePushRule(ctx context.Context, scope string, kind pushrules.PushRuleType, ruleID string) error {
|
||||
urlPath := cli.BuildClientURL("v3", "pushrules", scope, kind, ruleID)
|
||||
_, err := cli.MakeRequest(ctx, "DELETE", urlPath, nil, nil)
|
||||
_, err := cli.MakeRequest(ctx, http.MethodDelete, urlPath, nil, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2051,7 +2209,7 @@ func (cli *Client) PutPushRule(ctx context.Context, scope string, kind pushrules
|
||||
query["before"] = req.Before
|
||||
}
|
||||
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v3", "pushrules", scope, kind, ruleID}, query)
|
||||
_, err := cli.MakeRequest(ctx, "PUT", urlPath, req, nil)
|
||||
_, err := cli.MakeRequest(ctx, http.MethodPut, urlPath, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2072,7 +2230,7 @@ func (cli *Client) BatchSend(ctx context.Context, roomID id.RoomID, req *ReqBatc
|
||||
if len(req.BatchID) > 0 {
|
||||
query["batch_id"] = req.BatchID.String()
|
||||
}
|
||||
_, err = cli.MakeRequest(ctx, "POST", cli.BuildURLWithQuery(path, query), req, &resp)
|
||||
_, err = cli.MakeRequest(ctx, http.MethodPost, cli.BuildURLWithQuery(path, query), req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2123,7 +2281,7 @@ func NewClient(homeserverURL string, userID id.UserID, accessToken string) (*Cli
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cli := &Client{
|
||||
return &Client{
|
||||
AccessToken: accessToken,
|
||||
UserAgent: DefaultUserAgent,
|
||||
HomeserverURL: hsURL,
|
||||
@@ -2135,7 +2293,5 @@ func NewClient(homeserverURL string, userID id.UserID, accessToken string) (*Cli
|
||||
// The client will work with this storer: it just won't remember across restarts.
|
||||
// In practice, a database backend should be used.
|
||||
Store: NewMemorySyncStore(),
|
||||
}
|
||||
cli.Logger = maulogadapt.ZeroAsMau(&cli.Log)
|
||||
return cli, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
22
vendor/maunium.net/go/mautrix/crypto/account.go
generated
vendored
22
vendor/maunium.net/go/mautrix/crypto/account.go
generated
vendored
@@ -9,14 +9,16 @@ package crypto
|
||||
import (
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type OlmAccount struct {
|
||||
Internal olm.Account
|
||||
signingKey id.SigningKey
|
||||
identityKey id.IdentityKey
|
||||
Shared bool
|
||||
Internal olm.Account
|
||||
signingKey id.SigningKey
|
||||
identityKey id.IdentityKey
|
||||
Shared bool
|
||||
KeyBackupVersion id.KeyBackupVersion
|
||||
}
|
||||
|
||||
func NewOlmAccount() *OlmAccount {
|
||||
@@ -62,11 +64,7 @@ func (account *OlmAccount) getInitialKeys(userID id.UserID, deviceID id.DeviceID
|
||||
panic(err)
|
||||
}
|
||||
|
||||
deviceKeys.Signatures = mautrix.Signatures{
|
||||
userID: {
|
||||
id.NewKeyID(id.KeyAlgorithmEd25519, deviceID.String()): signature,
|
||||
},
|
||||
}
|
||||
deviceKeys.Signatures = signatures.NewSingleSignature(userID, id.KeyAlgorithmEd25519, deviceID.String(), signature)
|
||||
return deviceKeys
|
||||
}
|
||||
|
||||
@@ -79,11 +77,7 @@ func (account *OlmAccount) getOneTimeKeys(userID id.UserID, deviceID id.DeviceID
|
||||
for keyID, key := range account.Internal.OneTimeKeys() {
|
||||
key := mautrix.OneTimeKey{Key: key}
|
||||
signature, _ := account.Internal.SignJSON(key)
|
||||
key.Signatures = mautrix.Signatures{
|
||||
userID: {
|
||||
id.NewKeyID(id.KeyAlgorithmEd25519, deviceID.String()): signature,
|
||||
},
|
||||
}
|
||||
key.Signatures = signatures.NewSingleSignature(userID, id.KeyAlgorithmEd25519, deviceID.String(), signature)
|
||||
key.IsSigned = true
|
||||
oneTimeKeys[id.NewKeyID(id.KeyAlgorithmSignedCurve25519, keyID)] = key
|
||||
}
|
||||
|
||||
60
vendor/maunium.net/go/mautrix/crypto/aescbc/aes_cbc.go
generated
vendored
Normal file
60
vendor/maunium.net/go/mautrix/crypto/aescbc/aes_cbc.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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 aescbc
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/pkcs7"
|
||||
)
|
||||
|
||||
// Encrypt encrypts the plaintext with the key and IV. The IV length must be
|
||||
// equal to the AES block size.
|
||||
//
|
||||
// This function might mutate the plaintext.
|
||||
func Encrypt(key, iv, plaintext []byte) ([]byte, error) {
|
||||
if len(key) == 0 {
|
||||
return nil, ErrNoKeyProvided
|
||||
}
|
||||
if len(iv) != aes.BlockSize {
|
||||
return nil, ErrIVNotBlockSize
|
||||
}
|
||||
plaintext = pkcs7.Pad(plaintext, aes.BlockSize)
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cipher.NewCBCEncrypter(block, iv).CryptBlocks(plaintext, plaintext)
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
// Decrypt decrypts the ciphertext with the key and IV. The IV length must be
|
||||
// equal to the block size.
|
||||
//
|
||||
// This function mutates the ciphertext.
|
||||
func Decrypt(key, iv, ciphertext []byte) ([]byte, error) {
|
||||
if len(key) == 0 {
|
||||
return nil, ErrNoKeyProvided
|
||||
}
|
||||
if len(iv) != aes.BlockSize {
|
||||
return nil, ErrIVNotBlockSize
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ciphertext) < aes.BlockSize {
|
||||
return nil, ErrNotMultipleBlockSize
|
||||
}
|
||||
|
||||
cipher.NewCBCDecrypter(block, iv).CryptBlocks(ciphertext, ciphertext)
|
||||
return pkcs7.Unpad(ciphertext), nil
|
||||
}
|
||||
15
vendor/maunium.net/go/mautrix/crypto/aescbc/errors.go
generated
vendored
Normal file
15
vendor/maunium.net/go/mautrix/crypto/aescbc/errors.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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 aescbc
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrNoKeyProvided = errors.New("no key")
|
||||
ErrIVNotBlockSize = errors.New("IV length does not match AES block size")
|
||||
ErrNotMultipleBlockSize = errors.New("ciphertext length is not a multiple of the AES block size")
|
||||
)
|
||||
137
vendor/maunium.net/go/mautrix/crypto/backup/encryptedsessiondata.go
generated
vendored
Normal file
137
vendor/maunium.net/go/mautrix/crypto/backup/encryptedsessiondata.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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 backup
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdh"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"go.mau.fi/util/jsonbytes"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/aescbc"
|
||||
)
|
||||
|
||||
var ErrInvalidMAC = errors.New("invalid MAC")
|
||||
|
||||
// EncryptedSessionData is the encrypted session_data field of a key backup as
|
||||
// defined in [Section 11.12.3.2.2 of the Spec].
|
||||
//
|
||||
// The type parameter T represents the format of the session data contained in
|
||||
// the encrypted payload.
|
||||
//
|
||||
// [Section 11.12.3.2.2 of the Spec]: https://spec.matrix.org/v1.9/client-server-api/#backup-algorithm-mmegolm_backupv1curve25519-aes-sha2
|
||||
type EncryptedSessionData[T any] struct {
|
||||
Ciphertext jsonbytes.UnpaddedBytes `json:"ciphertext"`
|
||||
Ephemeral EphemeralKey `json:"ephemeral"`
|
||||
MAC jsonbytes.UnpaddedBytes `json:"mac"`
|
||||
}
|
||||
|
||||
func calculateEncryptionParameters(sharedSecret []byte) (key, macKey, iv []byte, err error) {
|
||||
hkdfReader := hkdf.New(sha256.New, sharedSecret, nil, nil)
|
||||
encryptionParams := make([]byte, 80)
|
||||
_, err = hkdfReader.Read(encryptionParams)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
return encryptionParams[:32], encryptionParams[32:64], encryptionParams[64:], nil
|
||||
}
|
||||
|
||||
// calculateCompatMAC calculates the MAC for compatibility with Olm and
|
||||
// Vodozemac which do not actually write the ciphertext when computing the MAC.
|
||||
//
|
||||
// Deprecated: Use [calculateMAC] instead.
|
||||
func calculateCompatMAC(macKey []byte) []byte {
|
||||
hash := hmac.New(sha256.New, macKey)
|
||||
return hash.Sum(nil)[:8]
|
||||
}
|
||||
|
||||
// calculateMAC calculates the MAC as described in step 5 of according to
|
||||
// [Section 11.12.3.2.2] of the Spec.
|
||||
//
|
||||
// [Section 11.12.3.2.2]: https://spec.matrix.org/v1.9/client-server-api/#backup-algorithm-mmegolm_backupv1curve25519-aes-sha2
|
||||
func calculateMAC(macKey, ciphertext []byte) []byte {
|
||||
hash := hmac.New(sha256.New, macKey)
|
||||
_, err := hash.Write(ciphertext)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return hash.Sum(nil)[:8]
|
||||
}
|
||||
|
||||
// EncryptSessionData encrypts the given session data with the given recovery
|
||||
// key as defined in [Section 11.12.3.2.2 of the Spec].
|
||||
//
|
||||
// [Section 11.12.3.2.2 of the Spec]: https://spec.matrix.org/v1.9/client-server-api/#backup-algorithm-mmegolm_backupv1curve25519-aes-sha2
|
||||
func EncryptSessionData[T any](backupKey *MegolmBackupKey, sessionData T) (*EncryptedSessionData[T], error) {
|
||||
sessionJSON, err := json.Marshal(sessionData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ephemeralKey, err := ecdh.X25519().GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sharedSecret, err := ephemeralKey.ECDH(backupKey.PublicKey())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, macKey, iv, err := calculateEncryptionParameters(sharedSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ciphertext, err := aescbc.Encrypt(key, iv, sessionJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EncryptedSessionData[T]{
|
||||
Ciphertext: ciphertext,
|
||||
Ephemeral: EphemeralKey{ephemeralKey.PublicKey()},
|
||||
MAC: calculateCompatMAC(macKey),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Decrypt decrypts the [EncryptedSessionData] into a *T using the recovery key
|
||||
// by reversing the process described in [Section 11.12.3.2.2 of the Spec].
|
||||
//
|
||||
// [Section 11.12.3.2.2 of the Spec]: https://spec.matrix.org/v1.9/client-server-api/#backup-algorithm-mmegolm_backupv1curve25519-aes-sha2
|
||||
func (esd *EncryptedSessionData[T]) Decrypt(backupKey *MegolmBackupKey) (*T, error) {
|
||||
sharedSecret, err := backupKey.ECDH(esd.Ephemeral.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, macKey, iv, err := calculateEncryptionParameters(sharedSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify the MAC before decrypting.
|
||||
if !bytes.Equal(calculateCompatMAC(macKey), esd.MAC) {
|
||||
return nil, ErrInvalidMAC
|
||||
}
|
||||
|
||||
plaintext, err := aescbc.Decrypt(key, iv, esd.Ciphertext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sessionData T
|
||||
err = json.Unmarshal(plaintext, &sessionData)
|
||||
return &sessionData, err
|
||||
}
|
||||
41
vendor/maunium.net/go/mautrix/crypto/backup/ephemeralkey.go
generated
vendored
Normal file
41
vendor/maunium.net/go/mautrix/crypto/backup/ephemeralkey.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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 backup
|
||||
|
||||
import (
|
||||
"crypto/ecdh"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// EphemeralKey is a wrapper around an ECDH X25519 public key that implements
|
||||
// JSON marshalling and unmarshalling.
|
||||
type EphemeralKey struct {
|
||||
*ecdh.PublicKey
|
||||
}
|
||||
|
||||
func (k *EphemeralKey) MarshalJSON() ([]byte, error) {
|
||||
if k == nil || k.PublicKey == nil {
|
||||
return json.Marshal(nil)
|
||||
}
|
||||
return json.Marshal(base64.RawStdEncoding.EncodeToString(k.Bytes()))
|
||||
}
|
||||
|
||||
func (k *EphemeralKey) UnmarshalJSON(data []byte) error {
|
||||
var keyStr string
|
||||
err := json.Unmarshal(data, &keyStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keyBytes, err := base64.RawStdEncoding.DecodeString(keyStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k.PublicKey, err = ecdh.X25519().NewPublicKey(keyBytes)
|
||||
return err
|
||||
}
|
||||
39
vendor/maunium.net/go/mautrix/crypto/backup/megolmbackup.go
generated
vendored
Normal file
39
vendor/maunium.net/go/mautrix/crypto/backup/megolmbackup.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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 backup
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// MegolmAuthData is the auth_data when the key backup is created with
|
||||
// the [id.KeyBackupAlgorithmMegolmBackupV1] algorithm as defined in
|
||||
// [Section 11.12.3.2.2 of the Spec].
|
||||
//
|
||||
// [Section 11.12.3.2.2 of the Spec]: https://spec.matrix.org/v1.9/client-server-api/#backup-algorithm-mmegolm_backupv1curve25519-aes-sha2
|
||||
type MegolmAuthData struct {
|
||||
PublicKey id.Ed25519 `json:"public_key"`
|
||||
Signatures signatures.Signatures `json:"signatures"`
|
||||
}
|
||||
|
||||
type SenderClaimedKeys struct {
|
||||
Ed25519 id.Ed25519 `json:"ed25519"`
|
||||
}
|
||||
|
||||
// MegolmSessionData is the decrypted session_data when the key backup is created
|
||||
// with the [id.KeyBackupAlgorithmMegolmBackupV1] algorithm as defined in
|
||||
// [Section 11.12.3.2.2 of the Spec].
|
||||
//
|
||||
// [Section 11.12.3.2.2 of the Spec]: https://spec.matrix.org/v1.9/client-server-api/#backup-algorithm-mmegolm_backupv1curve25519-aes-sha2
|
||||
type MegolmSessionData struct {
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
ForwardingKeyChain []string `json:"forwarding_curve25519_key_chain"`
|
||||
SenderClaimedKeys SenderClaimedKeys `json:"sender_claimed_keys"`
|
||||
SenderKey id.SenderKey `json:"sender_key"`
|
||||
SessionKey string `json:"session_key"`
|
||||
}
|
||||
34
vendor/maunium.net/go/mautrix/crypto/backup/megolmbackupkey.go
generated
vendored
Normal file
34
vendor/maunium.net/go/mautrix/crypto/backup/megolmbackupkey.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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 backup
|
||||
|
||||
import (
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
// MegolmBackupKey is a wrapper around an ECDH X25519 private key that is used
|
||||
// to decrypt a megolm key backup.
|
||||
type MegolmBackupKey struct {
|
||||
*ecdh.PrivateKey
|
||||
}
|
||||
|
||||
func NewMegolmBackupKey() (*MegolmBackupKey, error) {
|
||||
key, err := ecdh.X25519().GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &MegolmBackupKey{key}, nil
|
||||
}
|
||||
|
||||
func MegolmBackupKeyFromBytes(bytes []byte) (*MegolmBackupKey, error) {
|
||||
key, err := ecdh.X25519().NewPrivateKey(bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &MegolmBackupKey{key}, nil
|
||||
}
|
||||
68
vendor/maunium.net/go/mautrix/crypto/cross_sign_key.go
generated
vendored
68
vendor/maunium.net/go/mautrix/crypto/cross_sign_key.go
generated
vendored
@@ -13,21 +13,22 @@ import (
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// CrossSigningKeysCache holds the three cross-signing keys for the current user.
|
||||
type CrossSigningKeysCache struct {
|
||||
MasterKey *olm.PkSigning
|
||||
SelfSigningKey *olm.PkSigning
|
||||
UserSigningKey *olm.PkSigning
|
||||
MasterKey olm.PKSigning
|
||||
SelfSigningKey olm.PKSigning
|
||||
UserSigningKey olm.PKSigning
|
||||
}
|
||||
|
||||
func (cskc *CrossSigningKeysCache) PublicKeys() *CrossSigningPublicKeysCache {
|
||||
return &CrossSigningPublicKeysCache{
|
||||
MasterKey: cskc.MasterKey.PublicKey,
|
||||
SelfSigningKey: cskc.SelfSigningKey.PublicKey,
|
||||
UserSigningKey: cskc.UserSigningKey.PublicKey,
|
||||
MasterKey: cskc.MasterKey.PublicKey(),
|
||||
SelfSigningKey: cskc.SelfSigningKey.PublicKey(),
|
||||
UserSigningKey: cskc.UserSigningKey.PublicKey(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,28 +40,28 @@ type CrossSigningSeeds struct {
|
||||
|
||||
func (mach *OlmMachine) ExportCrossSigningKeys() CrossSigningSeeds {
|
||||
return CrossSigningSeeds{
|
||||
MasterKey: mach.CrossSigningKeys.MasterKey.Seed,
|
||||
SelfSigningKey: mach.CrossSigningKeys.SelfSigningKey.Seed,
|
||||
UserSigningKey: mach.CrossSigningKeys.UserSigningKey.Seed,
|
||||
MasterKey: mach.CrossSigningKeys.MasterKey.Seed(),
|
||||
SelfSigningKey: mach.CrossSigningKeys.SelfSigningKey.Seed(),
|
||||
UserSigningKey: mach.CrossSigningKeys.UserSigningKey.Seed(),
|
||||
}
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) ImportCrossSigningKeys(keys CrossSigningSeeds) (err error) {
|
||||
var keysCache CrossSigningKeysCache
|
||||
if keysCache.MasterKey, err = olm.NewPkSigningFromSeed(keys.MasterKey); err != nil {
|
||||
if keysCache.MasterKey, err = olm.NewPKSigningFromSeed(keys.MasterKey); err != nil {
|
||||
return
|
||||
}
|
||||
if keysCache.SelfSigningKey, err = olm.NewPkSigningFromSeed(keys.SelfSigningKey); err != nil {
|
||||
if keysCache.SelfSigningKey, err = olm.NewPKSigningFromSeed(keys.SelfSigningKey); err != nil {
|
||||
return
|
||||
}
|
||||
if keysCache.UserSigningKey, err = olm.NewPkSigningFromSeed(keys.UserSigningKey); err != nil {
|
||||
if keysCache.UserSigningKey, err = olm.NewPKSigningFromSeed(keys.UserSigningKey); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
mach.Log.Debug().
|
||||
Str("master", keysCache.MasterKey.PublicKey.String()).
|
||||
Str("self_signing", keysCache.SelfSigningKey.PublicKey.String()).
|
||||
Str("user_signing", keysCache.UserSigningKey.PublicKey.String()).
|
||||
Str("master", keysCache.MasterKey.PublicKey().String()).
|
||||
Str("self_signing", keysCache.SelfSigningKey.PublicKey().String()).
|
||||
Str("user_signing", keysCache.UserSigningKey.PublicKey().String()).
|
||||
Msg("Imported own cross-signing keys")
|
||||
|
||||
mach.CrossSigningKeys = &keysCache
|
||||
@@ -72,19 +73,19 @@ func (mach *OlmMachine) ImportCrossSigningKeys(keys CrossSigningSeeds) (err erro
|
||||
func (mach *OlmMachine) GenerateCrossSigningKeys() (*CrossSigningKeysCache, error) {
|
||||
var keysCache CrossSigningKeysCache
|
||||
var err error
|
||||
if keysCache.MasterKey, err = olm.NewPkSigning(); err != nil {
|
||||
if keysCache.MasterKey, err = olm.NewPKSigning(); err != nil {
|
||||
return nil, fmt.Errorf("failed to generate master key: %w", err)
|
||||
}
|
||||
if keysCache.SelfSigningKey, err = olm.NewPkSigning(); err != nil {
|
||||
if keysCache.SelfSigningKey, err = olm.NewPKSigning(); err != nil {
|
||||
return nil, fmt.Errorf("failed to generate self-signing key: %w", err)
|
||||
}
|
||||
if keysCache.UserSigningKey, err = olm.NewPkSigning(); err != nil {
|
||||
if keysCache.UserSigningKey, err = olm.NewPKSigning(); err != nil {
|
||||
return nil, fmt.Errorf("failed to generate user-signing key: %w", err)
|
||||
}
|
||||
mach.Log.Debug().
|
||||
Str("master", keysCache.MasterKey.PublicKey.String()).
|
||||
Str("self_signing", keysCache.SelfSigningKey.PublicKey.String()).
|
||||
Str("user_signing", keysCache.UserSigningKey.PublicKey.String()).
|
||||
Str("master", keysCache.MasterKey.PublicKey().String()).
|
||||
Str("self_signing", keysCache.SelfSigningKey.PublicKey().String()).
|
||||
Str("user_signing", keysCache.UserSigningKey.PublicKey().String()).
|
||||
Msg("Generated cross-signing keys")
|
||||
return &keysCache, nil
|
||||
}
|
||||
@@ -92,48 +93,45 @@ func (mach *OlmMachine) GenerateCrossSigningKeys() (*CrossSigningKeysCache, erro
|
||||
// PublishCrossSigningKeys signs and uploads the public keys of the given cross-signing keys to the server.
|
||||
func (mach *OlmMachine) PublishCrossSigningKeys(ctx context.Context, keys *CrossSigningKeysCache, uiaCallback mautrix.UIACallback) error {
|
||||
userID := mach.Client.UserID
|
||||
masterKeyID := id.NewKeyID(id.KeyAlgorithmEd25519, keys.MasterKey.PublicKey.String())
|
||||
masterKeyID := id.NewKeyID(id.KeyAlgorithmEd25519, keys.MasterKey.PublicKey().String())
|
||||
masterKey := mautrix.CrossSigningKeys{
|
||||
UserID: userID,
|
||||
Usage: []id.CrossSigningUsage{id.XSUsageMaster},
|
||||
Keys: map[id.KeyID]id.Ed25519{
|
||||
masterKeyID: keys.MasterKey.PublicKey,
|
||||
masterKeyID: keys.MasterKey.PublicKey(),
|
||||
},
|
||||
}
|
||||
masterSig, err := mach.account.Internal.SignJSON(masterKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sign master key: %w", err)
|
||||
}
|
||||
masterKey.Signatures = signatures.NewSingleSignature(userID, id.KeyAlgorithmEd25519, mach.Client.DeviceID.String(), masterSig)
|
||||
|
||||
selfKey := mautrix.CrossSigningKeys{
|
||||
UserID: userID,
|
||||
Usage: []id.CrossSigningUsage{id.XSUsageSelfSigning},
|
||||
Keys: map[id.KeyID]id.Ed25519{
|
||||
id.NewKeyID(id.KeyAlgorithmEd25519, keys.SelfSigningKey.PublicKey.String()): keys.SelfSigningKey.PublicKey,
|
||||
id.NewKeyID(id.KeyAlgorithmEd25519, keys.SelfSigningKey.PublicKey().String()): keys.SelfSigningKey.PublicKey(),
|
||||
},
|
||||
}
|
||||
selfSig, err := keys.MasterKey.SignJSON(selfKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sign self-signing key: %w", err)
|
||||
}
|
||||
selfKey.Signatures = map[id.UserID]map[id.KeyID]string{
|
||||
userID: {
|
||||
masterKeyID: selfSig,
|
||||
},
|
||||
}
|
||||
selfKey.Signatures = signatures.NewSingleSignature(userID, id.KeyAlgorithmEd25519, keys.MasterKey.PublicKey().String(), selfSig)
|
||||
|
||||
userKey := mautrix.CrossSigningKeys{
|
||||
UserID: userID,
|
||||
Usage: []id.CrossSigningUsage{id.XSUsageUserSigning},
|
||||
Keys: map[id.KeyID]id.Ed25519{
|
||||
id.NewKeyID(id.KeyAlgorithmEd25519, keys.UserSigningKey.PublicKey.String()): keys.UserSigningKey.PublicKey,
|
||||
id.NewKeyID(id.KeyAlgorithmEd25519, keys.UserSigningKey.PublicKey().String()): keys.UserSigningKey.PublicKey(),
|
||||
},
|
||||
}
|
||||
userSig, err := keys.MasterKey.SignJSON(userKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sign user-signing key: %w", err)
|
||||
}
|
||||
userKey.Signatures = map[id.UserID]map[id.KeyID]string{
|
||||
userID: {
|
||||
masterKeyID: userSig,
|
||||
},
|
||||
}
|
||||
userKey.Signatures = signatures.NewSingleSignature(userID, id.KeyAlgorithmEd25519, keys.MasterKey.PublicKey().String(), userSig)
|
||||
|
||||
err = mach.Client.UploadCrossSigningKeys(ctx, &mautrix.UploadCrossSigningKeysReq{
|
||||
Master: masterKey,
|
||||
|
||||
47
vendor/maunium.net/go/mautrix/crypto/cross_sign_signing.go
generated
vendored
47
vendor/maunium.net/go/mautrix/crypto/cross_sign_signing.go
generated
vendored
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
@@ -34,31 +34,6 @@ var (
|
||||
ErrMismatchingMasterKeyMAC = errors.New("mismatching cross-signing master key MAC")
|
||||
)
|
||||
|
||||
func (mach *OlmMachine) fetchMasterKey(ctx context.Context, device *id.Device, content *event.VerificationMacEventContent, verState *verificationState, transactionID string) (id.Ed25519, error) {
|
||||
crossSignKeys, err := mach.CryptoStore.GetCrossSigningKeys(ctx, device.UserID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to fetch cross-signing keys: %w", err)
|
||||
}
|
||||
masterKey, ok := crossSignKeys[id.XSUsageMaster]
|
||||
if !ok {
|
||||
return "", ErrCrossSigningMasterKeyNotFound
|
||||
}
|
||||
masterKeyID := id.NewKeyID(id.KeyAlgorithmEd25519, masterKey.Key.String())
|
||||
masterKeyMAC, ok := content.Mac[masterKeyID]
|
||||
if !ok {
|
||||
return masterKey.Key, ErrMasterKeyMACNotFound
|
||||
}
|
||||
expectedMasterKeyMAC, _, err := mach.getPKAndKeysMAC(verState.sas, device.UserID, device.DeviceID,
|
||||
mach.Client.UserID, mach.Client.DeviceID, transactionID, masterKey.Key, masterKeyID, content.Mac)
|
||||
if err != nil {
|
||||
return masterKey.Key, fmt.Errorf("failed to calculate expected MAC for master key: %w", err)
|
||||
}
|
||||
if masterKeyMAC != expectedMasterKeyMAC {
|
||||
err = fmt.Errorf("%w: expected %s, got %s", ErrMismatchingMasterKeyMAC, expectedMasterKeyMAC, masterKeyMAC)
|
||||
}
|
||||
return masterKey.Key, err
|
||||
}
|
||||
|
||||
// SignUser creates a cross-signing signature for a user, stores it and uploads it to the server.
|
||||
func (mach *OlmMachine) SignUser(ctx context.Context, userID id.UserID, masterKey id.Ed25519) error {
|
||||
if userID == mach.Client.UserID {
|
||||
@@ -85,7 +60,7 @@ func (mach *OlmMachine) SignUser(ctx context.Context, userID id.UserID, masterKe
|
||||
Str("signature", signature).
|
||||
Msg("Signed master key of user with our user-signing key")
|
||||
|
||||
if err := mach.CryptoStore.PutSignature(ctx, userID, masterKey, mach.Client.UserID, mach.CrossSigningKeys.UserSigningKey.PublicKey, signature); err != nil {
|
||||
if err := mach.CryptoStore.PutSignature(ctx, userID, masterKey, mach.Client.UserID, mach.CrossSigningKeys.UserSigningKey.PublicKey(), signature); err != nil {
|
||||
return fmt.Errorf("error storing signature in crypto store: %w", err)
|
||||
}
|
||||
|
||||
@@ -102,7 +77,7 @@ func (mach *OlmMachine) SignOwnMasterKey(ctx context.Context) error {
|
||||
|
||||
userID := mach.Client.UserID
|
||||
deviceID := mach.Client.DeviceID
|
||||
masterKey := mach.CrossSigningKeys.MasterKey.PublicKey
|
||||
masterKey := mach.CrossSigningKeys.MasterKey.PublicKey()
|
||||
|
||||
masterKeyObj := mautrix.ReqKeysSignatures{
|
||||
UserID: userID,
|
||||
@@ -115,11 +90,7 @@ func (mach *OlmMachine) SignOwnMasterKey(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sign JSON: %w", err)
|
||||
}
|
||||
masterKeyObj.Signatures = mautrix.Signatures{
|
||||
userID: map[id.KeyID]string{
|
||||
id.NewKeyID(id.KeyAlgorithmEd25519, deviceID.String()): signature,
|
||||
},
|
||||
}
|
||||
masterKeyObj.Signatures = signatures.NewSingleSignature(userID, id.KeyAlgorithmEd25519, deviceID.String(), signature)
|
||||
mach.Log.Debug().
|
||||
Str("device_id", deviceID.String()).
|
||||
Str("signature", signature).
|
||||
@@ -178,7 +149,7 @@ func (mach *OlmMachine) SignOwnDevice(ctx context.Context, device *id.Device) er
|
||||
Str("signature", signature).
|
||||
Msg("Signed own device key with self-signing key")
|
||||
|
||||
if err := mach.CryptoStore.PutSignature(ctx, device.UserID, device.SigningKey, mach.Client.UserID, mach.CrossSigningKeys.SelfSigningKey.PublicKey, signature); err != nil {
|
||||
if err := mach.CryptoStore.PutSignature(ctx, device.UserID, device.SigningKey, mach.Client.UserID, mach.CrossSigningKeys.SelfSigningKey.PublicKey(), signature); err != nil {
|
||||
return fmt.Errorf("error storing signature in crypto store: %w", err)
|
||||
}
|
||||
|
||||
@@ -209,16 +180,12 @@ func (mach *OlmMachine) getFullDeviceKeys(ctx context.Context, device *id.Device
|
||||
}
|
||||
|
||||
// signAndUpload signs the given key signatures object and uploads it to the server.
|
||||
func (mach *OlmMachine) signAndUpload(ctx context.Context, req mautrix.ReqKeysSignatures, userID id.UserID, signedThing string, key *olm.PkSigning) (string, error) {
|
||||
func (mach *OlmMachine) signAndUpload(ctx context.Context, req mautrix.ReqKeysSignatures, userID id.UserID, signedThing string, key olm.PKSigning) (string, error) {
|
||||
signature, err := key.SignJSON(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to sign JSON: %w", err)
|
||||
}
|
||||
req.Signatures = mautrix.Signatures{
|
||||
mach.Client.UserID: map[id.KeyID]string{
|
||||
id.NewKeyID(id.KeyAlgorithmEd25519, key.PublicKey.String()): signature,
|
||||
},
|
||||
}
|
||||
req.Signatures = signatures.NewSingleSignature(mach.Client.UserID, id.KeyAlgorithmEd25519, key.PublicKey().String(), signature)
|
||||
|
||||
resp, err := mach.Client.UploadSignatures(ctx, &mautrix.ReqUploadSignatures{
|
||||
userID: map[string]mautrix.ReqKeysSignatures{
|
||||
|
||||
83
vendor/maunium.net/go/mautrix/crypto/cross_sign_ssss.go
generated
vendored
83
vendor/maunium.net/go/mautrix/crypto/cross_sign_ssss.go
generated
vendored
@@ -14,6 +14,7 @@ import (
|
||||
"maunium.net/go/mautrix/crypto/ssss"
|
||||
"maunium.net/go/mautrix/crypto/utils"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// FetchCrossSigningKeysFromSSSS fetches all the cross-signing keys from SSSS, decrypts them using the given key and stores them in the olm machine.
|
||||
@@ -57,33 +58,8 @@ func (mach *OlmMachine) retrieveDecryptXSigningKey(ctx context.Context, keyName
|
||||
return decryptedKey, nil
|
||||
}
|
||||
|
||||
// GenerateAndUploadCrossSigningKeys generates a new key with all corresponding cross-signing keys.
|
||||
//
|
||||
// A passphrase can be provided to generate the SSSS key. If the passphrase is empty, a random key
|
||||
// is used. The base58-formatted recovery key is the first return parameter.
|
||||
//
|
||||
// The account password of the user is required for uploading keys to the server.
|
||||
func (mach *OlmMachine) GenerateAndUploadCrossSigningKeys(ctx context.Context, userPassword, passphrase string) (string, error) {
|
||||
key, err := mach.SSSS.GenerateAndUploadKey(ctx, passphrase)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to generate and upload SSSS key: %w", err)
|
||||
}
|
||||
|
||||
// generate the three cross-signing keys
|
||||
keysCache, err := mach.GenerateCrossSigningKeys()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
recoveryKey := key.RecoveryKey()
|
||||
|
||||
// Store the private keys in SSSS
|
||||
if err := mach.UploadCrossSigningKeysToSSSS(ctx, key, keysCache); err != nil {
|
||||
return recoveryKey, fmt.Errorf("failed to upload cross-signing keys to SSSS: %w", err)
|
||||
}
|
||||
|
||||
// Publish cross-signing keys
|
||||
err = mach.PublishCrossSigningKeys(ctx, keysCache, func(uiResp *mautrix.RespUserInteractive) interface{} {
|
||||
func (mach *OlmMachine) GenerateAndUploadCrossSigningKeysWithPassword(ctx context.Context, userPassword, passphrase string) (string, *CrossSigningKeysCache, error) {
|
||||
return mach.GenerateAndUploadCrossSigningKeys(ctx, func(uiResp *mautrix.RespUserInteractive) interface{} {
|
||||
return &mautrix.ReqUIAuthLogin{
|
||||
BaseAuthData: mautrix.BaseAuthData{
|
||||
Type: mautrix.AuthTypePassword,
|
||||
@@ -92,29 +68,68 @@ func (mach *OlmMachine) GenerateAndUploadCrossSigningKeys(ctx context.Context, u
|
||||
User: mach.Client.UserID.String(),
|
||||
Password: userPassword,
|
||||
}
|
||||
})
|
||||
}, passphrase)
|
||||
}
|
||||
|
||||
// GenerateAndUploadCrossSigningKeys generates a new key with all corresponding cross-signing keys.
|
||||
//
|
||||
// A passphrase can be provided to generate the SSSS key. If the passphrase is empty, a random key
|
||||
// is used. The base58-formatted recovery key is the first return parameter.
|
||||
//
|
||||
// The account password of the user is required for uploading keys to the server.
|
||||
func (mach *OlmMachine) GenerateAndUploadCrossSigningKeys(ctx context.Context, uiaCallback mautrix.UIACallback, passphrase string) (string, *CrossSigningKeysCache, error) {
|
||||
key, err := mach.SSSS.GenerateAndUploadKey(ctx, passphrase)
|
||||
if err != nil {
|
||||
return recoveryKey, fmt.Errorf("failed to publish cross-signing keys: %w", err)
|
||||
return "", nil, fmt.Errorf("failed to generate and upload SSSS key: %w", err)
|
||||
}
|
||||
|
||||
// generate the three cross-signing keys
|
||||
keysCache, err := mach.GenerateCrossSigningKeys()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// Store the private keys in SSSS
|
||||
if err := mach.UploadCrossSigningKeysToSSSS(ctx, key, keysCache); err != nil {
|
||||
return "", nil, fmt.Errorf("failed to upload cross-signing keys to SSSS: %w", err)
|
||||
}
|
||||
|
||||
// Publish cross-signing keys
|
||||
err = mach.PublishCrossSigningKeys(ctx, keysCache, uiaCallback)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to publish cross-signing keys: %w", err)
|
||||
}
|
||||
|
||||
err = mach.SSSS.SetDefaultKeyID(ctx, key.ID)
|
||||
if err != nil {
|
||||
return recoveryKey, fmt.Errorf("failed to mark %s as the default key: %w", key.ID, err)
|
||||
return "", nil, fmt.Errorf("failed to mark %s as the default key: %w", key.ID, err)
|
||||
}
|
||||
|
||||
return recoveryKey, nil
|
||||
return key.RecoveryKey(), keysCache, nil
|
||||
}
|
||||
|
||||
// UploadCrossSigningKeysToSSSS stores the given cross-signing keys on the server encrypted with the given key.
|
||||
func (mach *OlmMachine) UploadCrossSigningKeysToSSSS(ctx context.Context, key *ssss.Key, keys *CrossSigningKeysCache) error {
|
||||
if err := mach.SSSS.SetEncryptedAccountData(ctx, event.AccountDataCrossSigningMaster, keys.MasterKey.Seed, key); err != nil {
|
||||
if err := mach.SSSS.SetEncryptedAccountData(ctx, event.AccountDataCrossSigningMaster, keys.MasterKey.Seed(), key); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mach.SSSS.SetEncryptedAccountData(ctx, event.AccountDataCrossSigningSelf, keys.SelfSigningKey.Seed, key); err != nil {
|
||||
if err := mach.SSSS.SetEncryptedAccountData(ctx, event.AccountDataCrossSigningSelf, keys.SelfSigningKey.Seed(), key); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mach.SSSS.SetEncryptedAccountData(ctx, event.AccountDataCrossSigningUser, keys.UserSigningKey.Seed, key); err != nil {
|
||||
if err := mach.SSSS.SetEncryptedAccountData(ctx, event.AccountDataCrossSigningUser, keys.UserSigningKey.Seed(), key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Also store these locally
|
||||
if err := mach.CryptoStore.PutCrossSigningKey(ctx, mach.Client.UserID, id.XSUsageMaster, keys.MasterKey.PublicKey()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mach.CryptoStore.PutCrossSigningKey(ctx, mach.Client.UserID, id.XSUsageSelfSigning, keys.SelfSigningKey.PublicKey()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mach.CryptoStore.PutCrossSigningKey(ctx, mach.Client.UserID, id.XSUsageUserSigning, keys.UserSigningKey.PublicKey()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
4
vendor/maunium.net/go/mautrix/crypto/cross_sign_store.go
generated
vendored
4
vendor/maunium.net/go/mautrix/crypto/cross_sign_store.go
generated
vendored
@@ -11,7 +11,7 @@ import (
|
||||
"context"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
@@ -80,7 +80,7 @@ func (mach *OlmMachine) storeCrossSigningKeys(ctx context.Context, crossSigningK
|
||||
}
|
||||
|
||||
log.Debug().Msg("Verifying cross-signing key signature")
|
||||
if verified, err := olm.VerifySignatureJSON(userKeys, signUserID, signKeyName, signingKey); err != nil {
|
||||
if verified, err := signatures.VerifySignatureJSON(userKeys, signUserID, signKeyName, signingKey); err != nil {
|
||||
log.Warn().Err(err).Msg("Error verifying cross-signing key signature")
|
||||
} else {
|
||||
if verified {
|
||||
|
||||
6
vendor/maunium.net/go/mautrix/crypto/decryptmegolm.go
generated
vendored
6
vendor/maunium.net/go/mautrix/crypto/decryptmegolm.go
generated
vendored
@@ -72,7 +72,11 @@ func (mach *OlmMachine) DecryptMegolmEvent(ctx context.Context, evt *event.Event
|
||||
if sess.SigningKey == ownSigningKey && sess.SenderKey == ownIdentityKey && len(sess.ForwardingChains) == 0 {
|
||||
trustLevel = id.TrustStateVerified
|
||||
} else {
|
||||
device, err = mach.GetOrFetchDeviceByKey(ctx, evt.Sender, sess.SenderKey)
|
||||
if mach.DisableDecryptKeyFetching {
|
||||
device, err = mach.CryptoStore.FindDeviceByKey(ctx, evt.Sender, sess.SenderKey)
|
||||
} else {
|
||||
device, err = mach.GetOrFetchDeviceByKey(ctx, evt.Sender, sess.SenderKey)
|
||||
}
|
||||
if err != nil {
|
||||
// We don't want to throw these errors as the message can still be decrypted.
|
||||
log.Debug().Err(err).Msg("Failed to get device to verify session")
|
||||
|
||||
9
vendor/maunium.net/go/mautrix/crypto/decryptolm.go
generated
vendored
9
vendor/maunium.net/go/mautrix/crypto/decryptolm.go
generated
vendored
@@ -57,7 +57,7 @@ func (mach *OlmMachine) decryptOlmEvent(ctx context.Context, evt *event.Event) (
|
||||
if !ok {
|
||||
return nil, NotEncryptedForMe
|
||||
}
|
||||
decrypted, err := mach.decryptAndParseOlmCiphertext(ctx, evt.Sender, content.SenderKey, ownContent.Type, ownContent.Body)
|
||||
decrypted, err := mach.decryptAndParseOlmCiphertext(ctx, evt, content.SenderKey, ownContent.Type, ownContent.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -69,13 +69,13 @@ type OlmEventKeys struct {
|
||||
Ed25519 id.Ed25519 `json:"ed25519"`
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) decryptAndParseOlmCiphertext(ctx context.Context, sender id.UserID, senderKey id.SenderKey, olmType id.OlmMsgType, ciphertext string) (*DecryptedOlmEvent, error) {
|
||||
func (mach *OlmMachine) decryptAndParseOlmCiphertext(ctx context.Context, evt *event.Event, senderKey id.SenderKey, olmType id.OlmMsgType, ciphertext string) (*DecryptedOlmEvent, error) {
|
||||
if olmType != id.OlmMsgTypePreKey && olmType != id.OlmMsgTypeMsg {
|
||||
return nil, UnsupportedOlmMessageType
|
||||
}
|
||||
|
||||
endTimeTrace := mach.timeTrace(ctx, "decrypting olm ciphertext", 5*time.Second)
|
||||
plaintext, err := mach.tryDecryptOlmCiphertext(ctx, sender, senderKey, olmType, ciphertext)
|
||||
plaintext, err := mach.tryDecryptOlmCiphertext(ctx, evt.Sender, senderKey, olmType, ciphertext)
|
||||
endTimeTrace()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -88,7 +88,8 @@ func (mach *OlmMachine) decryptAndParseOlmCiphertext(ctx context.Context, sender
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse olm payload: %w", err)
|
||||
}
|
||||
if sender != olmEvt.Sender {
|
||||
olmEvt.Type.Class = evt.Type.Class
|
||||
if evt.Sender != olmEvt.Sender {
|
||||
return nil, SenderMismatch
|
||||
} else if mach.Client.UserID != olmEvt.Recipient {
|
||||
return nil, RecipientMismatch
|
||||
|
||||
6
vendor/maunium.net/go/mautrix/crypto/devicelist.go
generated
vendored
6
vendor/maunium.net/go/mautrix/crypto/devicelist.go
generated
vendored
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
@@ -52,7 +52,7 @@ func (mach *OlmMachine) storeDeviceSelfSignatures(ctx context.Context, userID id
|
||||
} else if _, ok := selfSigs[id.NewKeyID(id.KeyAlgorithmEd25519, pubKey.String())]; !ok {
|
||||
continue
|
||||
}
|
||||
if verified, err := olm.VerifySignatureJSON(deviceKeys, signerUserID, pubKey.String(), pubKey); verified {
|
||||
if verified, err := signatures.VerifySignatureJSON(deviceKeys, signerUserID, pubKey.String(), pubKey); verified {
|
||||
if signKey, ok := deviceKeys.Keys[id.DeviceKeyID(signerKey)]; ok {
|
||||
signature := deviceKeys.Signatures[signerUserID][id.NewKeyID(id.KeyAlgorithmEd25519, pubKey.String())]
|
||||
log.Trace().Err(err).
|
||||
@@ -245,7 +245,7 @@ func (mach *OlmMachine) validateDevice(userID id.UserID, deviceID id.DeviceID, d
|
||||
return existing, fmt.Errorf("%w (expected %s, got %s)", MismatchingSigningKey, existing.SigningKey, signingKey)
|
||||
}
|
||||
|
||||
ok, err := olm.VerifySignatureJSON(deviceKeys, userID, deviceID.String(), signingKey)
|
||||
ok, err := signatures.VerifySignatureJSON(deviceKeys, userID, deviceID.String(), signingKey)
|
||||
if err != nil {
|
||||
return existing, fmt.Errorf("failed to verify signature: %w", err)
|
||||
} else if !ok {
|
||||
|
||||
13
vendor/maunium.net/go/mautrix/crypto/encryptmegolm.go
generated
vendored
13
vendor/maunium.net/go/mautrix/crypto/encryptmegolm.go
generated
vendored
@@ -118,7 +118,7 @@ func (mach *OlmMachine) EncryptMegolmEvent(ctx context.Context, roomID id.RoomID
|
||||
log.Debug().Msg("Encrypted event successfully")
|
||||
err = mach.CryptoStore.UpdateOutboundGroupSession(ctx, session)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("Failed to update megolm session in crypto store after encrypting")
|
||||
return nil, fmt.Errorf("failed to update outbound group session after encrypting: %w", err)
|
||||
}
|
||||
encrypted := &event.EncryptedEventContent{
|
||||
Algorithm: id.AlgorithmMegolmV1,
|
||||
@@ -330,6 +330,17 @@ func (mach *OlmMachine) encryptAndSendGroupSession(ctx context.Context, session
|
||||
Str("target_user_id", userID.String()).
|
||||
Str("target_device_id", deviceID.String()).
|
||||
Msg("Encrypted group session for device")
|
||||
if !mach.DisableSharedGroupSessionTracking {
|
||||
err := mach.CryptoStore.MarkOutboundGroupSessionShared(ctx, userID, device.identity.IdentityKey, session.id)
|
||||
if err != nil {
|
||||
log.Warn().
|
||||
Err(err).
|
||||
Str("target_user_id", userID.String()).
|
||||
Str("target_device_id", deviceID.String()).
|
||||
Stringer("target_session_id", session.id).
|
||||
Msg("Failed to mark outbound group session shared")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
vendor/maunium.net/go/mautrix/crypto/encryptolm.go
generated
vendored
4
vendor/maunium.net/go/mautrix/crypto/encryptolm.go
generated
vendored
@@ -12,7 +12,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
@@ -109,7 +109,7 @@ func (mach *OlmMachine) createOutboundSessions(ctx context.Context, input map[id
|
||||
continue
|
||||
}
|
||||
identity := input[userID][deviceID]
|
||||
if ok, err := olm.VerifySignatureJSON(oneTimeKey.RawData, userID, deviceID.String(), identity.SigningKey); err != nil {
|
||||
if ok, err := signatures.VerifySignatureJSON(oneTimeKey.RawData, userID, deviceID.String(), identity.SigningKey); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to verify signature of one-time key")
|
||||
} else if !ok {
|
||||
log.Warn().Msg("One-time key has invalid signature from device")
|
||||
|
||||
5
vendor/maunium.net/go/mautrix/crypto/goolm/account/account.go
generated
vendored
5
vendor/maunium.net/go/mautrix/crypto/goolm/account/account.go
generated
vendored
@@ -110,12 +110,13 @@ func (a Account) IdentityKeys() (id.Ed25519, id.Curve25519) {
|
||||
return ed25519, curve25519
|
||||
}
|
||||
|
||||
// Sign returns the signature of a message using the Ed25519 key for this Account.
|
||||
// Sign returns the base64-encoded signature of a message using the Ed25519 key
|
||||
// for this Account.
|
||||
func (a Account) Sign(message []byte) ([]byte, error) {
|
||||
if len(message) == 0 {
|
||||
return nil, fmt.Errorf("sign: %w", goolm.ErrEmptyInput)
|
||||
}
|
||||
return goolm.Base64Encode(a.IdKeys.Ed25519.Sign(message)), nil
|
||||
return []byte(base64.RawStdEncoding.EncodeToString(a.IdKeys.Ed25519.Sign(message))), nil
|
||||
}
|
||||
|
||||
// OneTimeKeys returns the public parts of the unpublished one time keys of the Account.
|
||||
|
||||
8
vendor/maunium.net/go/mautrix/crypto/goolm/cipher/aes_sha256.go
generated
vendored
8
vendor/maunium.net/go/mautrix/crypto/goolm/cipher/aes_sha256.go
generated
vendored
@@ -2,8 +2,10 @@ package cipher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"io"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/aescbc"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
)
|
||||
|
||||
@@ -36,7 +38,7 @@ func deriveAESKeys(kdfInfo []byte, key []byte) (*derivedAESKeys, error) {
|
||||
|
||||
// AESSha512BlockSize resturns the blocksize of the cipher AESSHA256.
|
||||
func AESSha512BlockSize() int {
|
||||
return crypto.AESCBCBlocksize()
|
||||
return aes.BlockSize
|
||||
}
|
||||
|
||||
// AESSHA256 is a valid cipher using AES with CBC and HKDFSha256.
|
||||
@@ -57,7 +59,7 @@ func (c AESSHA256) Encrypt(key, plaintext []byte) (ciphertext []byte, err error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ciphertext, err = crypto.AESCBCEncrypt(keys.key, keys.iv, plaintext)
|
||||
ciphertext, err = aescbc.Encrypt(keys.key, keys.iv, plaintext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -70,7 +72,7 @@ func (c AESSHA256) Decrypt(key, ciphertext []byte) (plaintext []byte, err error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plaintext, err = crypto.AESCBCDecrypt(keys.key, keys.iv, ciphertext)
|
||||
plaintext, err = aescbc.Decrypt(keys.key, keys.iv, ciphertext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// cipher provides the methods and structs to do encryptions for olm/megolm.
|
||||
// Package cipher provides the methods and structs to do encryptions for
|
||||
// olm/megolm.
|
||||
package cipher
|
||||
|
||||
// Cipher defines a valid cipher.
|
||||
75
vendor/maunium.net/go/mautrix/crypto/goolm/crypto/aes_cbc.go
generated
vendored
75
vendor/maunium.net/go/mautrix/crypto/goolm/crypto/aes_cbc.go
generated
vendored
@@ -1,75 +0,0 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/goolm"
|
||||
)
|
||||
|
||||
// AESCBCBlocksize returns the blocksize of the encryption method
|
||||
func AESCBCBlocksize() int {
|
||||
return aes.BlockSize
|
||||
}
|
||||
|
||||
// AESCBCEncrypt encrypts the plaintext with the key and iv. len(iv) must be equal to the blocksize!
|
||||
func AESCBCEncrypt(key, iv, plaintext []byte) ([]byte, error) {
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("AESCBCEncrypt: %w", goolm.ErrNoKeyProvided)
|
||||
}
|
||||
if len(iv) != AESCBCBlocksize() {
|
||||
return nil, fmt.Errorf("iv: %w", goolm.ErrNotBlocksize)
|
||||
}
|
||||
var cipherText []byte
|
||||
plaintext = pkcs5Padding(plaintext, AESCBCBlocksize())
|
||||
if len(plaintext)%AESCBCBlocksize() != 0 {
|
||||
return nil, fmt.Errorf("message: %w", goolm.ErrNotMultipleBlocksize)
|
||||
}
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cipherText = make([]byte, len(plaintext))
|
||||
cbc := cipher.NewCBCEncrypter(block, iv)
|
||||
cbc.CryptBlocks(cipherText, plaintext)
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
// AESCBCDecrypt decrypts the ciphertext with the key and iv. len(iv) must be equal to the blocksize!
|
||||
func AESCBCDecrypt(key, iv, ciphertext []byte) ([]byte, error) {
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("AESCBCEncrypt: %w", goolm.ErrNoKeyProvided)
|
||||
}
|
||||
if len(iv) != AESCBCBlocksize() {
|
||||
return nil, fmt.Errorf("iv: %w", goolm.ErrNotBlocksize)
|
||||
}
|
||||
var block cipher.Block
|
||||
var err error
|
||||
block, err = aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ciphertext) < AESCBCBlocksize() {
|
||||
return nil, fmt.Errorf("ciphertext: %w", goolm.ErrNotMultipleBlocksize)
|
||||
}
|
||||
|
||||
cbc := cipher.NewCBCDecrypter(block, iv)
|
||||
cbc.CryptBlocks(ciphertext, ciphertext)
|
||||
return pkcs5Unpadding(ciphertext), nil
|
||||
}
|
||||
|
||||
// pkcs5Padding paddes the plaintext to be used in the AESCBC encryption.
|
||||
func pkcs5Padding(plaintext []byte, blockSize int) []byte {
|
||||
padding := (blockSize - len(plaintext)%blockSize)
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(plaintext, padtext...)
|
||||
}
|
||||
|
||||
// pkcs5Unpadding undoes the padding to the plaintext after AESCBC decryption.
|
||||
func pkcs5Unpadding(plaintext []byte) []byte {
|
||||
length := len(plaintext)
|
||||
unpadding := int(plaintext[length-1])
|
||||
return plaintext[:(length - unpadding)]
|
||||
}
|
||||
2
vendor/maunium.net/go/mautrix/crypto/goolm/crypto/doc.go
generated
vendored
Normal file
2
vendor/maunium.net/go/mautrix/crypto/goolm/crypto/doc.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package crpyto provides the nessesary encryption methods for olm/megolm
|
||||
package crypto
|
||||
2
vendor/maunium.net/go/mautrix/crypto/goolm/crypto/main.go
generated
vendored
2
vendor/maunium.net/go/mautrix/crypto/goolm/crypto/main.go
generated
vendored
@@ -1,2 +0,0 @@
|
||||
// crpyto provides the nessesary encryption methods for olm/megolm
|
||||
package crypto
|
||||
2
vendor/maunium.net/go/mautrix/crypto/goolm/errors.go
generated
vendored
2
vendor/maunium.net/go/mautrix/crypto/goolm/errors.go
generated
vendored
@@ -21,8 +21,6 @@ var (
|
||||
ErrChainTooHigh = errors.New("chain index too high")
|
||||
ErrBadInput = errors.New("bad input")
|
||||
ErrBadVersion = errors.New("wrong version")
|
||||
ErrNotBlocksize = errors.New("length != blocksize")
|
||||
ErrNotMultipleBlocksize = errors.New("length not a multiple of the blocksize")
|
||||
ErrWrongPickleVersion = errors.New("wrong pickle version")
|
||||
ErrValueTooShort = errors.New("value too short")
|
||||
ErrInputToSmall = errors.New("input too small (truncated?)")
|
||||
|
||||
4
vendor/maunium.net/go/mautrix/crypto/goolm/pk/decryption.go
generated
vendored
4
vendor/maunium.net/go/mautrix/crypto/goolm/pk/decryption.go
generated
vendored
@@ -45,8 +45,8 @@ func NewDecryptionFromPrivate(privateKey crypto.Curve25519PrivateKey) (*Decrypti
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// PubKey returns the public key base 64 encoded.
|
||||
func (s Decryption) PubKey() id.Curve25519 {
|
||||
// PublicKey returns the public key base 64 encoded.
|
||||
func (s Decryption) PublicKey() id.Curve25519 {
|
||||
return s.KeyPair.B64Encoded()
|
||||
}
|
||||
|
||||
|
||||
43
vendor/maunium.net/go/mautrix/crypto/goolm/pk/signing.go
generated
vendored
43
vendor/maunium.net/go/mautrix/crypto/goolm/pk/signing.go
generated
vendored
@@ -2,7 +2,11 @@ package pk
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/tidwall/sjson"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/crypto/goolm"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
"maunium.net/go/mautrix/id"
|
||||
@@ -10,15 +14,15 @@ import (
|
||||
|
||||
// Signing is used for signing a pk
|
||||
type Signing struct {
|
||||
KeyPair crypto.Ed25519KeyPair `json:"key_pair"`
|
||||
Seed []byte `json:"seed"`
|
||||
keyPair crypto.Ed25519KeyPair
|
||||
seed []byte
|
||||
}
|
||||
|
||||
// NewSigningFromSeed constructs a new Signing based on a seed.
|
||||
func NewSigningFromSeed(seed []byte) (*Signing, error) {
|
||||
s := &Signing{}
|
||||
s.Seed = seed
|
||||
s.KeyPair = crypto.Ed25519GenerateFromSeed(seed)
|
||||
s.seed = seed
|
||||
s.keyPair = crypto.Ed25519GenerateFromSeed(seed)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@@ -32,13 +36,34 @@ func NewSigning() (*Signing, error) {
|
||||
return NewSigningFromSeed(seed)
|
||||
}
|
||||
|
||||
// Sign returns the signature of the message base64 encoded.
|
||||
func (s Signing) Sign(message []byte) []byte {
|
||||
signature := s.KeyPair.Sign(message)
|
||||
return goolm.Base64Encode(signature)
|
||||
// Seed returns the seed of the key pair.
|
||||
func (s Signing) Seed() []byte {
|
||||
return s.seed
|
||||
}
|
||||
|
||||
// PublicKey returns the public key of the key pair base 64 encoded.
|
||||
func (s Signing) PublicKey() id.Ed25519 {
|
||||
return s.KeyPair.B64Encoded()
|
||||
return s.keyPair.B64Encoded()
|
||||
}
|
||||
|
||||
// Sign returns the signature of the message base64 encoded.
|
||||
func (s Signing) Sign(message []byte) ([]byte, error) {
|
||||
signature := s.keyPair.Sign(message)
|
||||
return goolm.Base64Encode(signature), nil
|
||||
}
|
||||
|
||||
// SignJSON creates a signature for the given object after encoding it to
|
||||
// canonical JSON.
|
||||
func (s Signing) SignJSON(obj any) (string, error) {
|
||||
objJSON, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
objJSON, _ = sjson.DeleteBytes(objJSON, "unsigned")
|
||||
objJSON, _ = sjson.DeleteBytes(objJSON, "signatures")
|
||||
signature, err := s.Sign(canonicaljson.CanonicalJSONAssumeValid(objJSON))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(signature), nil
|
||||
}
|
||||
|
||||
76
vendor/maunium.net/go/mautrix/crypto/goolm/sas/main.go
generated
vendored
76
vendor/maunium.net/go/mautrix/crypto/goolm/sas/main.go
generated
vendored
@@ -1,76 +0,0 @@
|
||||
// sas provides the means to do SAS between keys
|
||||
package sas
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/goolm"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
)
|
||||
|
||||
// SAS contains the key pair and secret for SAS.
|
||||
type SAS struct {
|
||||
KeyPair crypto.Curve25519KeyPair
|
||||
Secret []byte
|
||||
}
|
||||
|
||||
// New creates a new SAS with a new key pair.
|
||||
func New() (*SAS, error) {
|
||||
kp, err := crypto.Curve25519GenerateKey(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &SAS{
|
||||
KeyPair: kp,
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// GetPubkey returns the public key of the key pair base64 encoded
|
||||
func (s SAS) GetPubkey() []byte {
|
||||
return goolm.Base64Encode(s.KeyPair.PublicKey)
|
||||
}
|
||||
|
||||
// SetTheirKey sets the key of the other party and computes the shared secret.
|
||||
func (s *SAS) SetTheirKey(key []byte) error {
|
||||
keyDecoded, err := goolm.Base64Decode(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sharedSecret, err := s.KeyPair.SharedSecret(keyDecoded)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Secret = sharedSecret
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateBytes creates length bytes from the shared secret and info.
|
||||
func (s SAS) GenerateBytes(info []byte, length uint) ([]byte, error) {
|
||||
byteReader := crypto.HKDFSHA256(s.Secret, nil, info)
|
||||
output := make([]byte, length)
|
||||
if _, err := io.ReadFull(byteReader, output); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// calculateMAC returns a base64 encoded MAC of input.
|
||||
func (s *SAS) calculateMAC(input, info []byte, length uint) ([]byte, error) {
|
||||
key, err := s.GenerateBytes(info, length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mac := crypto.HMACSHA256(key, input)
|
||||
return goolm.Base64Encode(mac), nil
|
||||
}
|
||||
|
||||
// CalculateMACFixes returns a base64 encoded, 32 byte long MAC of input.
|
||||
func (s SAS) CalculateMAC(input, info []byte) ([]byte, error) {
|
||||
return s.calculateMAC(input, info, 32)
|
||||
}
|
||||
|
||||
// CalculateMACLongKDF returns a base64 encoded, 256 byte long MAC of input.
|
||||
func (s SAS) CalculateMACLongKDF(input, info []byte) ([]byte, error) {
|
||||
return s.calculateMAC(input, info, 256)
|
||||
}
|
||||
3
vendor/maunium.net/go/mautrix/crypto/goolm/session/doc.go
generated
vendored
Normal file
3
vendor/maunium.net/go/mautrix/crypto/goolm/session/doc.go
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package session provides the different types of sessions for en/decrypting
|
||||
// of messages
|
||||
package session
|
||||
2
vendor/maunium.net/go/mautrix/crypto/goolm/session/main.go
generated
vendored
2
vendor/maunium.net/go/mautrix/crypto/goolm/session/main.go
generated
vendored
@@ -1,2 +0,0 @@
|
||||
// session provides the different types of sessions for en/decrypting of messages
|
||||
package session
|
||||
23
vendor/maunium.net/go/mautrix/crypto/goolm/utilities/main.go
generated
vendored
23
vendor/maunium.net/go/mautrix/crypto/goolm/utilities/main.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
package utilities
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/goolm"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// VerifySignature verifies an ed25519 signature.
|
||||
func VerifySignature(message []byte, key id.Ed25519, signature []byte) (ok bool, err error) {
|
||||
keyDecoded, err := base64.RawStdEncoding.DecodeString(string(key))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
signatureDecoded, err := goolm.Base64Decode(signature)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
publicKey := crypto.Ed25519PublicKey(keyDecoded)
|
||||
return publicKey.Verify(message, signatureDecoded), nil
|
||||
}
|
||||
184
vendor/maunium.net/go/mautrix/crypto/keybackup.go
generated
vendored
Normal file
184
vendor/maunium.net/go/mautrix/crypto/keybackup.go
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/backup"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
func (mach *OlmMachine) DownloadAndStoreLatestKeyBackup(ctx context.Context, megolmBackupKey *backup.MegolmBackupKey) (id.KeyBackupVersion, error) {
|
||||
log := mach.machOrContextLog(ctx).With().
|
||||
Str("action", "download and store latest key backup").
|
||||
Logger()
|
||||
|
||||
ctx = log.WithContext(ctx)
|
||||
|
||||
versionInfo, err := mach.GetAndVerifyLatestKeyBackupVersion(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if versionInfo == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
err = mach.GetAndStoreKeyBackup(ctx, versionInfo.Version, megolmBackupKey)
|
||||
return versionInfo.Version, err
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) GetAndVerifyLatestKeyBackupVersion(ctx context.Context) (*mautrix.RespRoomKeysVersion[backup.MegolmAuthData], error) {
|
||||
versionInfo, err := mach.Client.GetKeyBackupLatestVersion(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if versionInfo.Algorithm != id.KeyBackupAlgorithmMegolmBackupV1 {
|
||||
return nil, fmt.Errorf("unsupported key backup algorithm: %s", versionInfo.Algorithm)
|
||||
}
|
||||
|
||||
log := mach.machOrContextLog(ctx).With().
|
||||
Int("count", versionInfo.Count).
|
||||
Str("etag", versionInfo.ETag).
|
||||
Stringer("key_backup_version", versionInfo.Version).
|
||||
Logger()
|
||||
|
||||
userSignatures, ok := versionInfo.AuthData.Signatures[mach.Client.UserID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no signature from user %s found in key backup", mach.Client.UserID)
|
||||
}
|
||||
|
||||
crossSigningPubkeys := mach.GetOwnCrossSigningPublicKeys(ctx)
|
||||
|
||||
signatureVerified := false
|
||||
for keyID := range userSignatures {
|
||||
keyAlg, keyName := keyID.Parse()
|
||||
if keyAlg != id.KeyAlgorithmEd25519 {
|
||||
continue
|
||||
}
|
||||
log := log.With().Str("key_name", keyName).Logger()
|
||||
|
||||
var key id.Ed25519
|
||||
if keyName == crossSigningPubkeys.MasterKey.String() {
|
||||
key = crossSigningPubkeys.MasterKey
|
||||
} else if device, err := mach.GetOrFetchDevice(ctx, mach.Client.UserID, id.DeviceID(keyName)); err != nil {
|
||||
log.Warn().Err(err).Msg("Failed to fetch device")
|
||||
continue
|
||||
} else if !mach.IsDeviceTrusted(device) {
|
||||
log.Warn().Err(err).Msg("Device is not trusted")
|
||||
continue
|
||||
} else {
|
||||
key = device.SigningKey
|
||||
}
|
||||
|
||||
ok, err = signatures.VerifySignatureJSON(versionInfo.AuthData, mach.Client.UserID, keyName, key)
|
||||
if err != nil || !ok {
|
||||
log.Warn().Err(err).Stringer("key_id", keyID).Msg("Signature verification failed")
|
||||
continue
|
||||
} else {
|
||||
// One of the signatures is valid, break from the loop.
|
||||
signatureVerified = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !signatureVerified {
|
||||
return nil, fmt.Errorf("no valid signature from user %s found in key backup", mach.Client.UserID)
|
||||
}
|
||||
|
||||
return versionInfo, nil
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) GetAndStoreKeyBackup(ctx context.Context, version id.KeyBackupVersion, megolmBackupKey *backup.MegolmBackupKey) error {
|
||||
keys, err := mach.Client.GetKeyBackup(ctx, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log := zerolog.Ctx(ctx)
|
||||
|
||||
var count, failedCount int
|
||||
|
||||
for roomID, backup := range keys.Rooms {
|
||||
for sessionID, keyBackupData := range backup.Sessions {
|
||||
sessionData, err := keyBackupData.SessionData.Decrypt(megolmBackupKey)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("Failed to decrypt session data")
|
||||
failedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
err = mach.ImportRoomKeyFromBackup(ctx, version, roomID, sessionID, sessionData)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("Failed to import room key from backup")
|
||||
failedCount++
|
||||
continue
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Int("count", count).
|
||||
Int("failed_count", failedCount).
|
||||
Msg("successfully imported sessions from backup")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) ImportRoomKeyFromBackup(ctx context.Context, version id.KeyBackupVersion, roomID id.RoomID, sessionID id.SessionID, keyBackupData *backup.MegolmSessionData) error {
|
||||
log := zerolog.Ctx(ctx).With().
|
||||
Str("room_id", roomID.String()).
|
||||
Str("session_id", sessionID.String()).
|
||||
Logger()
|
||||
if keyBackupData.Algorithm != id.AlgorithmMegolmV1 {
|
||||
return fmt.Errorf("ignoring room key in backup with weird algorithm %s", keyBackupData.Algorithm)
|
||||
}
|
||||
|
||||
igsInternal, err := olm.InboundGroupSessionImport([]byte(keyBackupData.SessionKey))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to import inbound group session: %w", err)
|
||||
} else if igsInternal.ID() != sessionID {
|
||||
log.Warn().
|
||||
Stringer("actual_session_id", igsInternal.ID()).
|
||||
Msg("Mismatched session ID while creating inbound group session from key backup")
|
||||
return fmt.Errorf("mismatched session ID while creating inbound group session from key backup")
|
||||
}
|
||||
|
||||
var maxAge time.Duration
|
||||
var maxMessages int
|
||||
if config, err := mach.StateStore.GetEncryptionEvent(ctx, roomID); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get encryption event for room")
|
||||
} else if config != nil {
|
||||
maxAge = time.Duration(config.RotationPeriodMillis) * time.Millisecond
|
||||
maxMessages = config.RotationPeriodMessages
|
||||
}
|
||||
|
||||
if firstKnownIndex := igsInternal.FirstKnownIndex(); firstKnownIndex > 0 {
|
||||
log.Warn().Uint32("first_known_index", firstKnownIndex).Msg("Importing partial session")
|
||||
}
|
||||
|
||||
igs := &InboundGroupSession{
|
||||
Internal: *igsInternal,
|
||||
SigningKey: keyBackupData.SenderClaimedKeys.Ed25519,
|
||||
SenderKey: keyBackupData.SenderKey,
|
||||
RoomID: roomID,
|
||||
ForwardingChains: append(keyBackupData.ForwardingKeyChain, keyBackupData.SenderKey.String()),
|
||||
id: sessionID,
|
||||
|
||||
ReceivedAt: time.Now().UTC(),
|
||||
MaxAge: maxAge.Milliseconds(),
|
||||
MaxMessages: maxMessages,
|
||||
KeyBackupVersion: version,
|
||||
}
|
||||
err = mach.CryptoStore.PutGroupSession(ctx, roomID, keyBackupData.SenderKey, sessionID, igs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to store new inbound group session: %w", err)
|
||||
}
|
||||
mach.markSessionReceived(ctx, sessionID)
|
||||
return nil
|
||||
}
|
||||
2
vendor/maunium.net/go/mautrix/crypto/keyimport.go
generated
vendored
2
vendor/maunium.net/go/mautrix/crypto/keyimport.go
generated
vendored
@@ -122,7 +122,7 @@ func (mach *OlmMachine) importExportedRoomKey(ctx context.Context, session Expor
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to store imported session: %w", err)
|
||||
}
|
||||
mach.markSessionReceived(igs.ID())
|
||||
mach.markSessionReceived(ctx, igs.ID())
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
||||
38
vendor/maunium.net/go/mautrix/crypto/keysharing.go
generated
vendored
38
vendor/maunium.net/go/mautrix/crypto/keysharing.go
generated
vendored
@@ -168,6 +168,9 @@ func (mach *OlmMachine) importForwardedRoomKey(ctx context.Context, evt *Decrypt
|
||||
if content.MaxMessages != 0 {
|
||||
maxMessages = content.MaxMessages
|
||||
}
|
||||
if firstKnownIndex := igsInternal.FirstKnownIndex(); firstKnownIndex > 0 {
|
||||
log.Warn().Uint32("first_known_index", firstKnownIndex).Msg("Importing partial session")
|
||||
}
|
||||
igs := &InboundGroupSession{
|
||||
Internal: *igsInternal,
|
||||
SigningKey: evt.Keys.Ed25519,
|
||||
@@ -186,7 +189,7 @@ func (mach *OlmMachine) importForwardedRoomKey(ctx context.Context, evt *Decrypt
|
||||
log.Error().Err(err).Msg("Failed to store new inbound group session")
|
||||
return false
|
||||
}
|
||||
mach.markSessionReceived(content.SessionID)
|
||||
mach.markSessionReceived(ctx, content.SessionID)
|
||||
log.Debug().Msg("Received forwarded inbound group session")
|
||||
return true
|
||||
}
|
||||
@@ -222,11 +225,34 @@ func (mach *OlmMachine) rejectKeyRequest(ctx context.Context, rejection KeyShare
|
||||
}
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) defaultAllowKeyShare(ctx context.Context, device *id.Device, _ event.RequestedKeyInfo) *KeyShareRejection {
|
||||
// sendToOneDevice sends a to-device event to a single device.
|
||||
func (mach *OlmMachine) sendToOneDevice(ctx context.Context, userID id.UserID, deviceID id.DeviceID, eventType event.Type, content interface{}) error {
|
||||
_, err := mach.Client.SendToDevice(ctx, eventType, &mautrix.ReqSendToDevice{
|
||||
Messages: map[id.UserID]map[id.DeviceID]*event.Content{
|
||||
userID: {
|
||||
deviceID: {
|
||||
Parsed: content,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) defaultAllowKeyShare(ctx context.Context, device *id.Device, evt event.RequestedKeyInfo) *KeyShareRejection {
|
||||
log := mach.machOrContextLog(ctx)
|
||||
if mach.Client.UserID != device.UserID {
|
||||
log.Debug().Msg("Rejecting key request from a different user")
|
||||
return &KeyShareRejectOtherUser
|
||||
isShared, err := mach.CryptoStore.IsOutboundGroupSessionShared(ctx, device.UserID, device.IdentityKey, evt.SessionID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Rejecting key request due to internal error when checking session sharing")
|
||||
return &KeyShareRejectNoResponse
|
||||
} else if !isShared {
|
||||
log.Debug().Msg("Rejecting key request for unshared session")
|
||||
return &KeyShareRejectOtherUser
|
||||
}
|
||||
log.Debug().Msg("Accepting key request for shared session")
|
||||
return nil
|
||||
} else if mach.Client.DeviceID == device.DeviceID {
|
||||
log.Debug().Msg("Ignoring key request from ourselves")
|
||||
return &KeyShareRejectNoResponse
|
||||
@@ -248,7 +274,7 @@ func (mach *OlmMachine) defaultAllowKeyShare(ctx context.Context, device *id.Dev
|
||||
}
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) handleRoomKeyRequest(ctx context.Context, sender id.UserID, content *event.RoomKeyRequestEventContent) {
|
||||
func (mach *OlmMachine) HandleRoomKeyRequest(ctx context.Context, sender id.UserID, content *event.RoomKeyRequestEventContent) {
|
||||
log := zerolog.Ctx(ctx).With().
|
||||
Str("request_id", content.RequestID).
|
||||
Str("device_id", content.RequestingDeviceID.String()).
|
||||
@@ -327,7 +353,7 @@ func (mach *OlmMachine) handleRoomKeyRequest(ctx context.Context, sender id.User
|
||||
}
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) handleBeeperRoomKeyAck(ctx context.Context, sender id.UserID, content *event.BeeperRoomKeyAckEventContent) {
|
||||
func (mach *OlmMachine) HandleBeeperRoomKeyAck(ctx context.Context, sender id.UserID, content *event.BeeperRoomKeyAckEventContent) {
|
||||
log := mach.machOrContextLog(ctx).With().
|
||||
Str("room_id", content.RoomID.String()).
|
||||
Str("session_id", content.SessionID.String()).
|
||||
|
||||
159
vendor/maunium.net/go/mautrix/crypto/machine.go
generated
vendored
159
vendor/maunium.net/go/mautrix/crypto/machine.go
generated
vendored
@@ -33,18 +33,17 @@ type OlmMachine struct {
|
||||
|
||||
PlaintextMentions bool
|
||||
|
||||
// Never ask the server for keys automatically as a side effect.
|
||||
DisableKeyFetching bool
|
||||
// Never ask the server for keys automatically as a side effect during Megolm decryption.
|
||||
DisableDecryptKeyFetching bool
|
||||
|
||||
// Don't mark outbound Olm sessions as shared for devices they were initially sent to.
|
||||
DisableSharedGroupSessionTracking bool
|
||||
|
||||
SendKeysMinTrust id.TrustState
|
||||
ShareKeysMinTrust id.TrustState
|
||||
|
||||
AllowKeyShare func(context.Context, *id.Device, event.RequestedKeyInfo) *KeyShareRejection
|
||||
|
||||
DefaultSASTimeout time.Duration
|
||||
// AcceptVerificationFrom determines whether the machine will accept verification requests from this device.
|
||||
AcceptVerificationFrom func(string, *id.Device, id.RoomID) (VerificationRequestResponse, VerificationHooks)
|
||||
|
||||
account *OlmAccount
|
||||
|
||||
roomKeyRequestFilled *sync.Map
|
||||
@@ -53,6 +52,9 @@ type OlmMachine struct {
|
||||
keyWaiters map[id.SessionID]chan struct{}
|
||||
keyWaitersLock sync.Mutex
|
||||
|
||||
// Optional callback which is called when we save a session to store
|
||||
SessionReceived func(context.Context, id.SessionID)
|
||||
|
||||
devicesToUnwedge map[id.IdentityKey]bool
|
||||
devicesToUnwedgeLock sync.Mutex
|
||||
recentlyUnwedged map[id.IdentityKey]time.Time
|
||||
@@ -78,6 +80,9 @@ type OlmMachine struct {
|
||||
DeleteKeysOnDeviceDelete bool
|
||||
|
||||
DisableDeviceChangeKeyRotation bool
|
||||
|
||||
secretLock sync.Mutex
|
||||
secretListeners map[string]chan<- string
|
||||
}
|
||||
|
||||
// StateStore is used by OlmMachine to get room state information that's needed for encryption.
|
||||
@@ -106,12 +111,6 @@ func NewOlmMachine(client *mautrix.Client, log *zerolog.Logger, cryptoStore Stor
|
||||
SendKeysMinTrust: id.TrustStateUnset,
|
||||
ShareKeysMinTrust: id.TrustStateCrossSignedTOFU,
|
||||
|
||||
DefaultSASTimeout: 10 * time.Minute,
|
||||
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
|
||||
},
|
||||
|
||||
roomKeyRequestFilled: &sync.Map{},
|
||||
keyVerificationTransactionState: &sync.Map{},
|
||||
|
||||
@@ -119,6 +118,7 @@ func NewOlmMachine(client *mautrix.Client, log *zerolog.Logger, cryptoStore Stor
|
||||
|
||||
devicesToUnwedge: make(map[id.IdentityKey]bool),
|
||||
recentlyUnwedged: make(map[id.IdentityKey]time.Time),
|
||||
secretListeners: make(map[string]chan<- string),
|
||||
}
|
||||
mach.AllowKeyShare = mach.defaultAllowKeyShare
|
||||
return mach
|
||||
@@ -145,11 +145,21 @@ func (mach *OlmMachine) Load(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) saveAccount(ctx context.Context) {
|
||||
func (mach *OlmMachine) saveAccount(ctx context.Context) error {
|
||||
err := mach.CryptoStore.PutAccount(ctx, mach.account)
|
||||
if err != nil {
|
||||
mach.Log.Error().Err(err).Msg("Failed to save account")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) KeyBackupVersion() id.KeyBackupVersion {
|
||||
return mach.account.KeyBackupVersion
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) SetKeyBackupVersion(ctx context.Context, version id.KeyBackupVersion) error {
|
||||
mach.account.KeyBackupVersion = version
|
||||
return mach.saveAccount(ctx)
|
||||
}
|
||||
|
||||
// FlushStore calls the Flush method of the CryptoStore.
|
||||
@@ -227,11 +237,7 @@ func (mach *OlmMachine) HandleDeviceLists(ctx context.Context, dl *mautrix.Devic
|
||||
Str("trace_id", traceID).
|
||||
Interface("changes", dl.Changed).
|
||||
Msg("Device list changes in /sync")
|
||||
if mach.DisableKeyFetching {
|
||||
mach.CryptoStore.MarkTrackedUsersOutdated(ctx, dl.Changed)
|
||||
} else {
|
||||
mach.FetchKeys(ctx, dl.Changed, false)
|
||||
}
|
||||
mach.FetchKeys(ctx, dl.Changed, false)
|
||||
mach.Log.Debug().Str("trace_id", traceID).Msg("Finished handling device list changes")
|
||||
}
|
||||
}
|
||||
@@ -328,6 +334,47 @@ func (mach *OlmMachine) HandleMemberEvent(ctx context.Context, evt *event.Event)
|
||||
}
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) HandleEncryptedEvent(ctx context.Context, evt *event.Event) {
|
||||
if _, ok := evt.Content.Parsed.(*event.EncryptedEventContent); !ok {
|
||||
mach.machOrContextLog(ctx).Warn().Msg("Passed invalid event to encrypted handler")
|
||||
return
|
||||
}
|
||||
|
||||
decryptedEvt, err := mach.decryptOlmEvent(ctx, evt)
|
||||
if err != nil {
|
||||
mach.machOrContextLog(ctx).Error().Err(err).Msg("Failed to decrypt to-device event")
|
||||
return
|
||||
}
|
||||
|
||||
log := mach.machOrContextLog(ctx).With().
|
||||
Str("decrypted_type", decryptedEvt.Type.Type).
|
||||
Str("sender_device", decryptedEvt.SenderDevice.String()).
|
||||
Str("sender_signing_key", decryptedEvt.Keys.Ed25519.String()).
|
||||
Logger()
|
||||
log.Trace().Msg("Successfully decrypted to-device event")
|
||||
|
||||
switch decryptedContent := decryptedEvt.Content.Parsed.(type) {
|
||||
case *event.RoomKeyEventContent:
|
||||
mach.receiveRoomKey(ctx, decryptedEvt, decryptedContent)
|
||||
log.Trace().Msg("Handled room key event")
|
||||
case *event.ForwardedRoomKeyEventContent:
|
||||
if mach.importForwardedRoomKey(ctx, decryptedEvt, decryptedContent) {
|
||||
if ch, ok := mach.roomKeyRequestFilled.Load(decryptedContent.SessionID); ok {
|
||||
// close channel to notify listener that the key was received
|
||||
close(ch.(chan struct{}))
|
||||
}
|
||||
}
|
||||
log.Trace().Msg("Handled forwarded room key event")
|
||||
case *event.DummyEventContent:
|
||||
log.Debug().Msg("Received encrypted dummy event")
|
||||
case *event.SecretSendEventContent:
|
||||
mach.receiveSecret(ctx, decryptedEvt, decryptedContent)
|
||||
log.Trace().Msg("Handled secret send event")
|
||||
default:
|
||||
log.Debug().Msg("Unhandled encrypted to-device event")
|
||||
}
|
||||
}
|
||||
|
||||
// HandleToDeviceEvent handles a single to-device event. This is automatically called by ProcessSyncResponse, so you
|
||||
// don't need to add any custom handlers if you use that method.
|
||||
func (mach *OlmMachine) HandleToDeviceEvent(ctx context.Context, evt *event.Event) {
|
||||
@@ -352,60 +399,19 @@ func (mach *OlmMachine) HandleToDeviceEvent(ctx context.Context, evt *event.Even
|
||||
}
|
||||
switch content := evt.Content.Parsed.(type) {
|
||||
case *event.EncryptedEventContent:
|
||||
log = log.With().
|
||||
Str("sender_key", content.SenderKey.String()).
|
||||
Logger()
|
||||
log.Debug().Msg("Handling encrypted to-device event")
|
||||
ctx = log.WithContext(ctx)
|
||||
decryptedEvt, err := mach.decryptOlmEvent(ctx, evt)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to decrypt to-device event")
|
||||
return
|
||||
}
|
||||
log = log.With().
|
||||
Str("decrypted_type", decryptedEvt.Type.Type).
|
||||
Str("sender_device", decryptedEvt.SenderDevice.String()).
|
||||
Str("sender_signing_key", decryptedEvt.Keys.Ed25519.String()).
|
||||
Logger()
|
||||
log.Trace().Msg("Successfully decrypted to-device event")
|
||||
|
||||
switch decryptedContent := decryptedEvt.Content.Parsed.(type) {
|
||||
case *event.RoomKeyEventContent:
|
||||
mach.receiveRoomKey(ctx, decryptedEvt, decryptedContent)
|
||||
log.Trace().Msg("Handled room key event")
|
||||
case *event.ForwardedRoomKeyEventContent:
|
||||
if mach.importForwardedRoomKey(ctx, decryptedEvt, decryptedContent) {
|
||||
if ch, ok := mach.roomKeyRequestFilled.Load(decryptedContent.SessionID); ok {
|
||||
// close channel to notify listener that the key was received
|
||||
close(ch.(chan struct{}))
|
||||
}
|
||||
}
|
||||
log.Trace().Msg("Handled forwarded room key event")
|
||||
case *event.DummyEventContent:
|
||||
log.Debug().Msg("Received encrypted dummy event")
|
||||
default:
|
||||
log.Debug().Msg("Unhandled encrypted to-device event")
|
||||
}
|
||||
mach.HandleEncryptedEvent(ctx, evt)
|
||||
return
|
||||
case *event.RoomKeyRequestEventContent:
|
||||
go mach.handleRoomKeyRequest(ctx, evt.Sender, content)
|
||||
go mach.HandleRoomKeyRequest(ctx, evt.Sender, content)
|
||||
case *event.BeeperRoomKeyAckEventContent:
|
||||
mach.handleBeeperRoomKeyAck(ctx, evt.Sender, content)
|
||||
// verification cases
|
||||
case *event.VerificationStartEventContent:
|
||||
mach.handleVerificationStart(ctx, evt.Sender, content, content.TransactionID, 10*time.Minute, "")
|
||||
case *event.VerificationAcceptEventContent:
|
||||
mach.handleVerificationAccept(ctx, evt.Sender, content, content.TransactionID)
|
||||
case *event.VerificationKeyEventContent:
|
||||
mach.handleVerificationKey(ctx, evt.Sender, content, content.TransactionID)
|
||||
case *event.VerificationMacEventContent:
|
||||
mach.handleVerificationMAC(ctx, evt.Sender, content, content.TransactionID)
|
||||
case *event.VerificationCancelEventContent:
|
||||
mach.handleVerificationCancel(evt.Sender, content, content.TransactionID)
|
||||
case *event.VerificationRequestEventContent:
|
||||
mach.handleVerificationRequest(ctx, evt.Sender, content, content.TransactionID, "")
|
||||
mach.HandleBeeperRoomKeyAck(ctx, evt.Sender, content)
|
||||
case *event.RoomKeyWithheldEventContent:
|
||||
mach.handleRoomKeyWithheld(ctx, content)
|
||||
mach.HandleRoomKeyWithheld(ctx, content)
|
||||
case *event.SecretRequestEventContent:
|
||||
if content.Action == event.SecretRequestRequest {
|
||||
mach.HandleSecretRequest(ctx, evt.Sender, content)
|
||||
log.Trace().Msg("Handled secret request event")
|
||||
}
|
||||
default:
|
||||
deviceID, _ := evt.Content.Raw["device_id"].(string)
|
||||
log.Debug().Str("maybe_device_id", deviceID).Msg("Unhandled to-device event")
|
||||
@@ -420,7 +426,7 @@ func (mach *OlmMachine) GetOrFetchDevice(ctx context.Context, userID id.UserID,
|
||||
device, err := mach.CryptoStore.GetDevice(ctx, userID, deviceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get sender device from store: %w", err)
|
||||
} else if device != nil || mach.DisableKeyFetching {
|
||||
} else if device != nil {
|
||||
return device, nil
|
||||
}
|
||||
if usersToDevices, err := mach.FetchKeys(ctx, []id.UserID{userID}, true); err != nil {
|
||||
@@ -439,7 +445,7 @@ func (mach *OlmMachine) GetOrFetchDevice(ctx context.Context, userID id.UserID,
|
||||
// the given identity key.
|
||||
func (mach *OlmMachine) GetOrFetchDeviceByKey(ctx context.Context, userID id.UserID, identityKey id.IdentityKey) (*id.Device, error) {
|
||||
deviceIdentity, err := mach.CryptoStore.FindDeviceByKey(ctx, userID, identityKey)
|
||||
if err != nil || deviceIdentity != nil || mach.DisableKeyFetching {
|
||||
if err != nil || deviceIdentity != nil {
|
||||
return deviceIdentity, err
|
||||
}
|
||||
mach.machOrContextLog(ctx).Debug().
|
||||
@@ -517,7 +523,7 @@ func (mach *OlmMachine) createGroupSession(ctx context.Context, senderKey id.Sen
|
||||
log.Error().Err(err).Str("session_id", sessionID.String()).Msg("Failed to store new inbound group session")
|
||||
return
|
||||
}
|
||||
mach.markSessionReceived(sessionID)
|
||||
mach.markSessionReceived(ctx, sessionID)
|
||||
log.Debug().
|
||||
Str("session_id", sessionID.String()).
|
||||
Str("sender_key", senderKey.String()).
|
||||
@@ -527,7 +533,11 @@ func (mach *OlmMachine) createGroupSession(ctx context.Context, senderKey id.Sen
|
||||
Msg("Received inbound group session")
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) markSessionReceived(id id.SessionID) {
|
||||
func (mach *OlmMachine) markSessionReceived(ctx context.Context, id id.SessionID) {
|
||||
if mach.SessionReceived != nil {
|
||||
mach.SessionReceived(ctx, id)
|
||||
}
|
||||
|
||||
mach.keyWaitersLock.Lock()
|
||||
ch, ok := mach.keyWaiters[id]
|
||||
if ok {
|
||||
@@ -619,7 +629,7 @@ func (mach *OlmMachine) receiveRoomKey(ctx context.Context, evt *DecryptedOlmEve
|
||||
mach.createGroupSession(ctx, evt.SenderKey, evt.Keys.Ed25519, content.RoomID, content.SessionID, content.SessionKey, maxAge, maxMessages, content.IsScheduled)
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) handleRoomKeyWithheld(ctx context.Context, content *event.RoomKeyWithheldEventContent) {
|
||||
func (mach *OlmMachine) HandleRoomKeyWithheld(ctx context.Context, content *event.RoomKeyWithheldEventContent) {
|
||||
if content.Algorithm != id.AlgorithmMegolmV1 {
|
||||
zerolog.Ctx(ctx).Debug().Interface("content", content).Msg("Non-megolm room key withheld event")
|
||||
return
|
||||
@@ -682,8 +692,7 @@ func (mach *OlmMachine) ShareKeys(ctx context.Context, currentOTKCount int) erro
|
||||
}
|
||||
mach.lastOTKUpload = time.Now()
|
||||
mach.account.Shared = true
|
||||
mach.saveAccount(ctx)
|
||||
return nil
|
||||
return mach.saveAccount(ctx)
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) ExpiredKeyDeleteLoop(ctx context.Context) {
|
||||
|
||||
80
vendor/maunium.net/go/mautrix/crypto/olm/pk_goolm.go
generated
vendored
80
vendor/maunium.net/go/mautrix/crypto/olm/pk_goolm.go
generated
vendored
@@ -1,71 +1,29 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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/.
|
||||
|
||||
// When the goolm build flag is enabled, this file will make [PKSigning]
|
||||
// constructors use the goolm constuctors.
|
||||
|
||||
//go:build goolm
|
||||
|
||||
package olm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
import "maunium.net/go/mautrix/crypto/goolm/pk"
|
||||
|
||||
"github.com/tidwall/sjson"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/crypto/goolm/pk"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// PkSigning stores a key pair for signing messages.
|
||||
type PkSigning struct {
|
||||
pk.Signing
|
||||
PublicKey id.Ed25519
|
||||
Seed []byte
|
||||
// NewPKSigningFromSeed creates a new PKSigning object using the given seed.
|
||||
func NewPKSigningFromSeed(seed []byte) (PKSigning, error) {
|
||||
return pk.NewSigningFromSeed(seed)
|
||||
}
|
||||
|
||||
// Clear clears the underlying memory of a PkSigning object.
|
||||
func (p *PkSigning) Clear() {
|
||||
p.Signing = pk.Signing{}
|
||||
// NewPKSigning creates a new [PKSigning] object, containing a key pair for
|
||||
// signing messages.
|
||||
func NewPKSigning() (PKSigning, error) {
|
||||
return pk.NewSigning()
|
||||
}
|
||||
|
||||
// NewPkSigningFromSeed creates a new PkSigning object using the given seed.
|
||||
func NewPkSigningFromSeed(seed []byte) (*PkSigning, error) {
|
||||
p := &PkSigning{}
|
||||
signing, err := pk.NewSigningFromSeed(seed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Signing = *signing
|
||||
p.Seed = seed
|
||||
p.PublicKey = p.Signing.PublicKey()
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// NewPkSigning creates a new PkSigning object, containing a key pair for signing messages.
|
||||
func NewPkSigning() (*PkSigning, error) {
|
||||
p := &PkSigning{}
|
||||
signing, err := pk.NewSigning()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Signing = *signing
|
||||
p.Seed = signing.Seed
|
||||
p.PublicKey = p.Signing.PublicKey()
|
||||
return p, err
|
||||
}
|
||||
|
||||
// Sign creates a signature for the given message using this key.
|
||||
func (p *PkSigning) Sign(message []byte) ([]byte, error) {
|
||||
return p.Signing.Sign(message), nil
|
||||
}
|
||||
|
||||
// SignJSON creates a signature for the given object after encoding it to canonical JSON.
|
||||
func (p *PkSigning) SignJSON(obj interface{}) (string, error) {
|
||||
objJSON, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
objJSON, _ = sjson.DeleteBytes(objJSON, "unsigned")
|
||||
objJSON, _ = sjson.DeleteBytes(objJSON, "signatures")
|
||||
signature, err := p.Sign(canonicaljson.CanonicalJSONAssumeValid(objJSON))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(signature), nil
|
||||
func NewPKDecryption(privateKey []byte) (PKDecryption, error) {
|
||||
return pk.NewDecryption()
|
||||
}
|
||||
|
||||
41
vendor/maunium.net/go/mautrix/crypto/olm/pk_interface.go
generated
vendored
Normal file
41
vendor/maunium.net/go/mautrix/crypto/olm/pk_interface.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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 olm
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/crypto/goolm/pk"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// PKSigning is an interface for signing messages.
|
||||
type PKSigning interface {
|
||||
// Seed returns the seed of the key.
|
||||
Seed() []byte
|
||||
|
||||
// PublicKey returns the public key.
|
||||
PublicKey() id.Ed25519
|
||||
|
||||
// Sign creates a signature for the given message using this key.
|
||||
Sign(message []byte) ([]byte, error)
|
||||
|
||||
// SignJSON creates a signature for the given object after encoding it to
|
||||
// canonical JSON.
|
||||
SignJSON(obj any) (string, error)
|
||||
}
|
||||
|
||||
var _ PKSigning = (*pk.Signing)(nil)
|
||||
|
||||
// PKDecryption is an interface for decrypting messages.
|
||||
type PKDecryption interface {
|
||||
// PublicKey returns the public key.
|
||||
PublicKey() id.Curve25519
|
||||
|
||||
// Decrypt verifies and decrypts the given message.
|
||||
Decrypt(ciphertext, mac []byte, key id.Curve25519) ([]byte, error)
|
||||
}
|
||||
|
||||
var _ PKDecryption = (*pk.Decryption)(nil)
|
||||
@@ -1,3 +1,9 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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/.
|
||||
|
||||
//go:build !goolm
|
||||
|
||||
package olm
|
||||
@@ -18,14 +24,17 @@ import (
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// PkSigning stores a key pair for signing messages.
|
||||
type PkSigning struct {
|
||||
// LibOlmPKSigning stores a key pair for signing messages.
|
||||
type LibOlmPKSigning struct {
|
||||
int *C.OlmPkSigning
|
||||
mem []byte
|
||||
PublicKey id.Ed25519
|
||||
Seed []byte
|
||||
publicKey id.Ed25519
|
||||
seed []byte
|
||||
}
|
||||
|
||||
// Ensure that LibOlmPKSigning implements PKSigning.
|
||||
var _ PKSigning = (*LibOlmPKSigning)(nil)
|
||||
|
||||
func pkSigningSize() uint {
|
||||
return uint(C.olm_pk_signing_size())
|
||||
}
|
||||
@@ -42,48 +51,57 @@ func pkSigningSignatureLength() uint {
|
||||
return uint(C.olm_pk_signature_length())
|
||||
}
|
||||
|
||||
func NewBlankPkSigning() *PkSigning {
|
||||
func newBlankPKSigning() *LibOlmPKSigning {
|
||||
memory := make([]byte, pkSigningSize())
|
||||
return &PkSigning{
|
||||
return &LibOlmPKSigning{
|
||||
int: C.olm_pk_signing(unsafe.Pointer(&memory[0])),
|
||||
mem: memory,
|
||||
}
|
||||
}
|
||||
|
||||
// Clear clears the underlying memory of a PkSigning object.
|
||||
func (p *PkSigning) Clear() {
|
||||
C.olm_clear_pk_signing((*C.OlmPkSigning)(p.int))
|
||||
}
|
||||
|
||||
// NewPkSigningFromSeed creates a new PkSigning object using the given seed.
|
||||
func NewPkSigningFromSeed(seed []byte) (*PkSigning, error) {
|
||||
p := NewBlankPkSigning()
|
||||
p.Clear()
|
||||
// NewPKSigningFromSeed creates a new [PKSigning] object using the given seed.
|
||||
func NewPKSigningFromSeed(seed []byte) (PKSigning, error) {
|
||||
p := newBlankPKSigning()
|
||||
p.clear()
|
||||
pubKey := make([]byte, pkSigningPublicKeyLength())
|
||||
if C.olm_pk_signing_key_from_seed((*C.OlmPkSigning)(p.int),
|
||||
unsafe.Pointer(&pubKey[0]), C.size_t(len(pubKey)),
|
||||
unsafe.Pointer(&seed[0]), C.size_t(len(seed))) == errorVal() {
|
||||
return nil, p.lastError()
|
||||
}
|
||||
p.PublicKey = id.Ed25519(pubKey)
|
||||
p.Seed = seed
|
||||
p.publicKey = id.Ed25519(pubKey)
|
||||
p.seed = seed
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// NewPkSigning creates a new PkSigning object, containing a key pair for signing messages.
|
||||
func NewPkSigning() (*PkSigning, error) {
|
||||
// NewPKSigning creates a new LibOlmPKSigning object, containing a key pair for
|
||||
// signing messages.
|
||||
func NewPKSigning() (PKSigning, error) {
|
||||
// Generate the seed
|
||||
seed := make([]byte, pkSigningSeedLength())
|
||||
_, err := rand.Read(seed)
|
||||
if err != nil {
|
||||
panic(NotEnoughGoRandom)
|
||||
}
|
||||
pk, err := NewPkSigningFromSeed(seed)
|
||||
pk, err := NewPKSigningFromSeed(seed)
|
||||
return pk, err
|
||||
}
|
||||
|
||||
func (p *LibOlmPKSigning) PublicKey() id.Ed25519 {
|
||||
return p.publicKey
|
||||
}
|
||||
|
||||
func (p *LibOlmPKSigning) Seed() []byte {
|
||||
return p.seed
|
||||
}
|
||||
|
||||
// clear clears the underlying memory of a LibOlmPKSigning object.
|
||||
func (p *LibOlmPKSigning) clear() {
|
||||
C.olm_clear_pk_signing((*C.OlmPkSigning)(p.int))
|
||||
}
|
||||
|
||||
// Sign creates a signature for the given message using this key.
|
||||
func (p *PkSigning) Sign(message []byte) ([]byte, error) {
|
||||
func (p *LibOlmPKSigning) Sign(message []byte) ([]byte, error) {
|
||||
signature := make([]byte, pkSigningSignatureLength())
|
||||
if C.olm_pk_sign((*C.OlmPkSigning)(p.int), (*C.uint8_t)(unsafe.Pointer(&message[0])), C.size_t(len(message)),
|
||||
(*C.uint8_t)(unsafe.Pointer(&signature[0])), C.size_t(len(signature))) == errorVal() {
|
||||
@@ -93,7 +111,7 @@ func (p *PkSigning) Sign(message []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
// SignJSON creates a signature for the given object after encoding it to canonical JSON.
|
||||
func (p *PkSigning) SignJSON(obj interface{}) (string, error) {
|
||||
func (p *LibOlmPKSigning) SignJSON(obj interface{}) (string, error) {
|
||||
objJSON, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -107,12 +125,13 @@ func (p *PkSigning) SignJSON(obj interface{}) (string, error) {
|
||||
return string(signature), nil
|
||||
}
|
||||
|
||||
// lastError returns the last error that happened in relation to this PkSigning object.
|
||||
func (p *PkSigning) lastError() error {
|
||||
// lastError returns the last error that happened in relation to this
|
||||
// LibOlmPKSigning object.
|
||||
func (p *LibOlmPKSigning) lastError() error {
|
||||
return convertError(C.GoString(C.olm_pk_signing_last_error((*C.OlmPkSigning)(p.int))))
|
||||
}
|
||||
|
||||
type PkDecryption struct {
|
||||
type LibOlmPKDecryption struct {
|
||||
int *C.OlmPkDecryption
|
||||
mem []byte
|
||||
PublicKey []byte
|
||||
@@ -126,13 +145,13 @@ func pkDecryptionPublicKeySize() uint {
|
||||
return uint(C.olm_pk_key_length())
|
||||
}
|
||||
|
||||
func NewPkDecryption(privateKey []byte) (*PkDecryption, error) {
|
||||
func NewPkDecryption(privateKey []byte) (*LibOlmPKDecryption, error) {
|
||||
memory := make([]byte, pkDecryptionSize())
|
||||
p := &PkDecryption{
|
||||
p := &LibOlmPKDecryption{
|
||||
int: C.olm_pk_decryption(unsafe.Pointer(&memory[0])),
|
||||
mem: memory,
|
||||
}
|
||||
p.Clear()
|
||||
p.clear()
|
||||
pubKey := make([]byte, pkDecryptionPublicKeySize())
|
||||
|
||||
if C.olm_pk_key_from_private((*C.OlmPkDecryption)(p.int),
|
||||
@@ -145,7 +164,7 @@ func NewPkDecryption(privateKey []byte) (*PkDecryption, error) {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *PkDecryption) Decrypt(ephemeralKey []byte, mac []byte, ciphertext []byte) ([]byte, error) {
|
||||
func (p *LibOlmPKDecryption) Decrypt(ephemeralKey []byte, mac []byte, ciphertext []byte) ([]byte, error) {
|
||||
maxPlaintextLength := uint(C.olm_pk_max_plaintext_length((*C.OlmPkDecryption)(p.int), C.size_t(len(ciphertext))))
|
||||
plaintext := make([]byte, maxPlaintextLength)
|
||||
|
||||
@@ -162,11 +181,12 @@ func (p *PkDecryption) Decrypt(ephemeralKey []byte, mac []byte, ciphertext []byt
|
||||
}
|
||||
|
||||
// Clear clears the underlying memory of a PkDecryption object.
|
||||
func (p *PkDecryption) Clear() {
|
||||
func (p *LibOlmPKDecryption) clear() {
|
||||
C.olm_clear_pk_decryption((*C.OlmPkDecryption)(p.int))
|
||||
}
|
||||
|
||||
// lastError returns the last error that happened in relation to this PkDecryption object.
|
||||
func (p *PkDecryption) lastError() error {
|
||||
// lastError returns the last error that happened in relation to this
|
||||
// LibOlmPKDecryption object.
|
||||
func (p *LibOlmPKDecryption) lastError() error {
|
||||
return convertError(C.GoString(C.olm_pk_decryption_last_error((*C.OlmPkDecryption)(p.int))))
|
||||
}
|
||||
146
vendor/maunium.net/go/mautrix/crypto/olm/utility.go
generated
vendored
146
vendor/maunium.net/go/mautrix/crypto/olm/utility.go
generated
vendored
@@ -1,146 +0,0 @@
|
||||
//go:build !goolm
|
||||
|
||||
package olm
|
||||
|
||||
// #cgo LDFLAGS: -lolm -lstdc++
|
||||
// #include <olm/olm.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
"go.mau.fi/util/exgjson"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Utility stores the necessary state to perform hash and signature
|
||||
// verification operations.
|
||||
type Utility struct {
|
||||
int *C.OlmUtility
|
||||
mem []byte
|
||||
}
|
||||
|
||||
// utilitySize returns the size of a utility object in bytes.
|
||||
func utilitySize() uint {
|
||||
return uint(C.olm_utility_size())
|
||||
}
|
||||
|
||||
// sha256Len returns the length of the buffer needed to hold the SHA-256 hash.
|
||||
func (u *Utility) sha256Len() uint {
|
||||
return uint(C.olm_sha256_length((*C.OlmUtility)(u.int)))
|
||||
}
|
||||
|
||||
// lastError returns an error describing the most recent error to happen to a
|
||||
// utility.
|
||||
func (u *Utility) lastError() error {
|
||||
return convertError(C.GoString(C.olm_utility_last_error((*C.OlmUtility)(u.int))))
|
||||
}
|
||||
|
||||
// Clear clears the memory used to back this utility.
|
||||
func (u *Utility) Clear() error {
|
||||
r := C.olm_clear_utility((*C.OlmUtility)(u.int))
|
||||
if r == errorVal() {
|
||||
return u.lastError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewUtility creates a new utility.
|
||||
func NewUtility() *Utility {
|
||||
memory := make([]byte, utilitySize())
|
||||
return &Utility{
|
||||
int: C.olm_utility(unsafe.Pointer(&memory[0])),
|
||||
mem: memory,
|
||||
}
|
||||
}
|
||||
|
||||
// Sha256 calculates the SHA-256 hash of the input and encodes it as base64.
|
||||
func (u *Utility) Sha256(input string) string {
|
||||
if len(input) == 0 {
|
||||
panic(EmptyInput)
|
||||
}
|
||||
output := make([]byte, u.sha256Len())
|
||||
r := C.olm_sha256(
|
||||
(*C.OlmUtility)(u.int),
|
||||
unsafe.Pointer(&([]byte(input)[0])),
|
||||
C.size_t(len(input)),
|
||||
unsafe.Pointer(&(output[0])),
|
||||
C.size_t(len(output)))
|
||||
if r == errorVal() {
|
||||
panic(u.lastError())
|
||||
}
|
||||
return string(output)
|
||||
}
|
||||
|
||||
// VerifySignature verifies an ed25519 signature. Returns true if the verification
|
||||
// suceeds or false otherwise. Returns error on failure. If the key was too
|
||||
// small then the error will be "INVALID_BASE64".
|
||||
func (u *Utility) VerifySignature(message string, key id.Ed25519, signature string) (ok bool, err error) {
|
||||
if len(message) == 0 || len(key) == 0 || len(signature) == 0 {
|
||||
return false, EmptyInput
|
||||
}
|
||||
r := C.olm_ed25519_verify(
|
||||
(*C.OlmUtility)(u.int),
|
||||
unsafe.Pointer(&([]byte(key)[0])),
|
||||
C.size_t(len(key)),
|
||||
unsafe.Pointer(&([]byte(message)[0])),
|
||||
C.size_t(len(message)),
|
||||
unsafe.Pointer(&([]byte(signature)[0])),
|
||||
C.size_t(len(signature)))
|
||||
if r == errorVal() {
|
||||
err = u.lastError()
|
||||
if err == BadMessageMAC {
|
||||
err = nil
|
||||
}
|
||||
} else {
|
||||
ok = true
|
||||
}
|
||||
return ok, err
|
||||
}
|
||||
|
||||
// VerifySignatureJSON verifies the signature in the JSON object _obj following
|
||||
// the Matrix specification:
|
||||
// https://matrix.org/speculator/spec/drafts%2Fe2e/appendices.html#signing-json
|
||||
// If the _obj is a struct, the `json` tags will be honored.
|
||||
func (u *Utility) VerifySignatureJSON(obj interface{}, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
|
||||
var err error
|
||||
objJSON, ok := obj.(json.RawMessage)
|
||||
if !ok {
|
||||
objJSON, err = json.Marshal(obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
sig := gjson.GetBytes(objJSON, exgjson.Path("signatures", string(userID), fmt.Sprintf("ed25519:%s", keyName)))
|
||||
if !sig.Exists() || sig.Type != gjson.String {
|
||||
return false, SignatureNotFound
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "unsigned")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "signatures")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSONString := string(canonicaljson.CanonicalJSONAssumeValid(objJSON))
|
||||
return u.VerifySignature(objJSONString, key, sig.Str)
|
||||
}
|
||||
|
||||
// VerifySignatureJSON verifies the signature in the JSON object _obj following
|
||||
// the Matrix specification:
|
||||
// https://matrix.org/speculator/spec/drafts%2Fe2e/appendices.html#signing-json
|
||||
// This function is a wrapper over Utility.VerifySignatureJSON that creates and
|
||||
// destroys the Utility object transparently.
|
||||
// If the _obj is a struct, the `json` tags will be honored.
|
||||
func VerifySignatureJSON(obj interface{}, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
|
||||
u := NewUtility()
|
||||
defer u.Clear()
|
||||
return u.VerifySignatureJSON(obj, userID, keyName, key)
|
||||
}
|
||||
92
vendor/maunium.net/go/mautrix/crypto/olm/utility_goolm.go
generated
vendored
92
vendor/maunium.net/go/mautrix/crypto/olm/utility_goolm.go
generated
vendored
@@ -1,92 +0,0 @@
|
||||
//go:build goolm
|
||||
|
||||
package olm
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
"go.mau.fi/util/exgjson"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/crypto/goolm/utilities"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Utility stores the necessary state to perform hash and signature
|
||||
// verification operations.
|
||||
type Utility struct{}
|
||||
|
||||
// Clear clears the memory used to back this utility.
|
||||
func (u *Utility) Clear() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewUtility creates a new utility.
|
||||
func NewUtility() *Utility {
|
||||
return &Utility{}
|
||||
}
|
||||
|
||||
// Sha256 calculates the SHA-256 hash of the input and encodes it as base64.
|
||||
func (u *Utility) Sha256(input string) string {
|
||||
if len(input) == 0 {
|
||||
panic(EmptyInput)
|
||||
}
|
||||
hash := sha256.Sum256([]byte(input))
|
||||
return base64.RawStdEncoding.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
// VerifySignature verifies an ed25519 signature. Returns true if the verification
|
||||
// suceeds or false otherwise. Returns error on failure. If the key was too
|
||||
// small then the error will be "INVALID_BASE64".
|
||||
func (u *Utility) VerifySignature(message string, key id.Ed25519, signature string) (ok bool, err error) {
|
||||
if len(message) == 0 || len(key) == 0 || len(signature) == 0 {
|
||||
return false, EmptyInput
|
||||
}
|
||||
return utilities.VerifySignature([]byte(message), key, []byte(signature))
|
||||
}
|
||||
|
||||
// VerifySignatureJSON verifies the signature in the JSON object _obj following
|
||||
// the Matrix specification:
|
||||
// https://matrix.org/speculator/spec/drafts%2Fe2e/appendices.html#signing-json
|
||||
// If the _obj is a struct, the `json` tags will be honored.
|
||||
func (u *Utility) VerifySignatureJSON(obj interface{}, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
|
||||
var err error
|
||||
objJSON, ok := obj.(json.RawMessage)
|
||||
if !ok {
|
||||
objJSON, err = json.Marshal(obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
sig := gjson.GetBytes(objJSON, exgjson.Path("signatures", string(userID), fmt.Sprintf("ed25519:%s", keyName)))
|
||||
if !sig.Exists() || sig.Type != gjson.String {
|
||||
return false, SignatureNotFound
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "unsigned")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "signatures")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSONString := string(canonicaljson.CanonicalJSONAssumeValid(objJSON))
|
||||
return u.VerifySignature(objJSONString, key, sig.Str)
|
||||
}
|
||||
|
||||
// VerifySignatureJSON verifies the signature in the JSON object _obj following
|
||||
// the Matrix specification:
|
||||
// https://matrix.org/speculator/spec/drafts%2Fe2e/appendices.html#signing-json
|
||||
// This function is a wrapper over Utility.VerifySignatureJSON that creates and
|
||||
// destroys the Utility object transparently.
|
||||
// If the _obj is a struct, the `json` tags will be honored.
|
||||
func VerifySignatureJSON(obj interface{}, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
|
||||
u := NewUtility()
|
||||
defer u.Clear()
|
||||
return u.VerifySignatureJSON(obj, userID, keyName, key)
|
||||
}
|
||||
142
vendor/maunium.net/go/mautrix/crypto/olm/verification.go
generated
vendored
142
vendor/maunium.net/go/mautrix/crypto/olm/verification.go
generated
vendored
@@ -1,142 +0,0 @@
|
||||
//go:build !nosas && !goolm
|
||||
|
||||
package olm
|
||||
|
||||
// #cgo LDFLAGS: -lolm -lstdc++
|
||||
// #include <olm/olm.h>
|
||||
// #include <olm/sas.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// SAS stores an Olm Short Authentication String (SAS) object.
|
||||
type SAS struct {
|
||||
int *C.OlmSAS
|
||||
mem []byte
|
||||
}
|
||||
|
||||
// NewBlankSAS initializes an empty SAS object.
|
||||
func NewBlankSAS() *SAS {
|
||||
memory := make([]byte, sasSize())
|
||||
return &SAS{
|
||||
int: C.olm_sas(unsafe.Pointer(&memory[0])),
|
||||
mem: memory,
|
||||
}
|
||||
}
|
||||
|
||||
// sasSize is the size of a SAS object in bytes.
|
||||
func sasSize() uint {
|
||||
return uint(C.olm_sas_size())
|
||||
}
|
||||
|
||||
// sasRandomLength is the number of random bytes needed to create an SAS object.
|
||||
func (sas *SAS) sasRandomLength() uint {
|
||||
return uint(C.olm_create_sas_random_length(sas.int))
|
||||
}
|
||||
|
||||
// NewSAS creates a new SAS object.
|
||||
func NewSAS() *SAS {
|
||||
sas := NewBlankSAS()
|
||||
random := make([]byte, sas.sasRandomLength()+1)
|
||||
_, err := rand.Read(random)
|
||||
if err != nil {
|
||||
panic(NotEnoughGoRandom)
|
||||
}
|
||||
r := C.olm_create_sas(
|
||||
(*C.OlmSAS)(sas.int),
|
||||
unsafe.Pointer(&random[0]),
|
||||
C.size_t(len(random)))
|
||||
if r == errorVal() {
|
||||
panic(sas.lastError())
|
||||
} else {
|
||||
return sas
|
||||
}
|
||||
}
|
||||
|
||||
// clear clears the memory used to back an SAS object.
|
||||
func (sas *SAS) clear() uint {
|
||||
return uint(C.olm_clear_sas(sas.int))
|
||||
}
|
||||
|
||||
// lastError returns the most recent error to happen to an SAS object.
|
||||
func (sas *SAS) lastError() error {
|
||||
return convertError(C.GoString(C.olm_sas_last_error(sas.int)))
|
||||
}
|
||||
|
||||
// pubkeyLength is the size of a public key in bytes.
|
||||
func (sas *SAS) pubkeyLength() uint {
|
||||
return uint(C.olm_sas_pubkey_length((*C.OlmSAS)(sas.int)))
|
||||
}
|
||||
|
||||
// GetPubkey gets the public key for the SAS object.
|
||||
func (sas *SAS) GetPubkey() []byte {
|
||||
pubkey := make([]byte, sas.pubkeyLength())
|
||||
r := C.olm_sas_get_pubkey(
|
||||
(*C.OlmSAS)(sas.int),
|
||||
unsafe.Pointer(&pubkey[0]),
|
||||
C.size_t(len(pubkey)))
|
||||
if r == errorVal() {
|
||||
panic(sas.lastError())
|
||||
}
|
||||
return pubkey
|
||||
}
|
||||
|
||||
// SetTheirKey sets the public key of the other user.
|
||||
func (sas *SAS) SetTheirKey(theirKey []byte) error {
|
||||
theirKeyCopy := make([]byte, len(theirKey))
|
||||
copy(theirKeyCopy, theirKey)
|
||||
r := C.olm_sas_set_their_key(
|
||||
(*C.OlmSAS)(sas.int),
|
||||
unsafe.Pointer(&theirKeyCopy[0]),
|
||||
C.size_t(len(theirKeyCopy)))
|
||||
if r == errorVal() {
|
||||
return sas.lastError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateBytes generates bytes to use for the short authentication string.
|
||||
func (sas *SAS) GenerateBytes(info []byte, count uint) ([]byte, error) {
|
||||
infoCopy := make([]byte, len(info))
|
||||
copy(infoCopy, info)
|
||||
output := make([]byte, count)
|
||||
r := C.olm_sas_generate_bytes(
|
||||
(*C.OlmSAS)(sas.int),
|
||||
unsafe.Pointer(&infoCopy[0]),
|
||||
C.size_t(len(infoCopy)),
|
||||
unsafe.Pointer(&output[0]),
|
||||
C.size_t(len(output)))
|
||||
if r == errorVal() {
|
||||
return nil, sas.lastError()
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// macLength is the size of a message authentication code generated by olm_sas_calculate_mac.
|
||||
func (sas *SAS) macLength() uint {
|
||||
return uint(C.olm_sas_mac_length((*C.OlmSAS)(sas.int)))
|
||||
}
|
||||
|
||||
// CalculateMAC generates a message authentication code (MAC) based on the shared secret.
|
||||
func (sas *SAS) CalculateMAC(input []byte, info []byte) ([]byte, error) {
|
||||
inputCopy := make([]byte, len(input))
|
||||
copy(inputCopy, input)
|
||||
infoCopy := make([]byte, len(info))
|
||||
copy(infoCopy, info)
|
||||
mac := make([]byte, sas.macLength())
|
||||
r := C.olm_sas_calculate_mac(
|
||||
(*C.OlmSAS)(sas.int),
|
||||
unsafe.Pointer(&inputCopy[0]),
|
||||
C.size_t(len(inputCopy)),
|
||||
unsafe.Pointer(&infoCopy[0]),
|
||||
C.size_t(len(infoCopy)),
|
||||
unsafe.Pointer(&mac[0]),
|
||||
C.size_t(len(mac)))
|
||||
if r == errorVal() {
|
||||
return nil, sas.lastError()
|
||||
}
|
||||
return mac, nil
|
||||
}
|
||||
23
vendor/maunium.net/go/mautrix/crypto/olm/verification_goolm.go
generated
vendored
23
vendor/maunium.net/go/mautrix/crypto/olm/verification_goolm.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
//go:build !nosas && goolm
|
||||
|
||||
package olm
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/crypto/goolm/sas"
|
||||
)
|
||||
|
||||
// SAS stores an Olm Short Authentication String (SAS) object.
|
||||
type SAS struct {
|
||||
sas.SAS
|
||||
}
|
||||
|
||||
// NewSAS creates a new SAS object.
|
||||
func NewSAS() *SAS {
|
||||
newSAS, err := sas.New()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &SAS{
|
||||
SAS: *newSAS,
|
||||
}
|
||||
}
|
||||
30
vendor/maunium.net/go/mautrix/crypto/pkcs7/pkcs7.go
generated
vendored
Normal file
30
vendor/maunium.net/go/mautrix/crypto/pkcs7/pkcs7.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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 pkcs7
|
||||
|
||||
import "bytes"
|
||||
|
||||
// Pad implements PKCS#7 padding as defined in [RFC2315]. It pads the plaintext
|
||||
// to the given blockSize in the range [1, 255]. This is normally used in
|
||||
// AES-CBC encryption.
|
||||
//
|
||||
// [RFC2315]: https://www.ietf.org/rfc/rfc2315.txt
|
||||
func Pad(plaintext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(plaintext)%blockSize
|
||||
return append(plaintext, bytes.Repeat([]byte{byte(padding)}, padding)...)
|
||||
}
|
||||
|
||||
// Unpad implements PKCS#7 unpadding as defined in [RFC2315]. It unpads the
|
||||
// plaintext by reading the padding amount from the last byte of the plaintext.
|
||||
// This is normally used in AES-CBC decryption.
|
||||
//
|
||||
// [RFC2315]: https://www.ietf.org/rfc/rfc2315.txt
|
||||
func Unpad(plaintext []byte) []byte {
|
||||
length := len(plaintext)
|
||||
unpadding := int(plaintext[length-1])
|
||||
return plaintext[:length-unpadding]
|
||||
}
|
||||
9
vendor/maunium.net/go/mautrix/crypto/sessions.go
generated
vendored
9
vendor/maunium.net/go/mautrix/crypto/sessions.go
generated
vendored
@@ -105,10 +105,11 @@ type InboundGroupSession struct {
|
||||
ForwardingChains []string
|
||||
RatchetSafety RatchetSafety
|
||||
|
||||
ReceivedAt time.Time
|
||||
MaxAge int64
|
||||
MaxMessages int
|
||||
IsScheduled bool
|
||||
ReceivedAt time.Time
|
||||
MaxAge int64
|
||||
MaxMessages int
|
||||
IsScheduled bool
|
||||
KeyBackupVersion id.KeyBackupVersion
|
||||
|
||||
id id.SessionID
|
||||
}
|
||||
|
||||
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:
|
||||
}
|
||||
}
|
||||
94
vendor/maunium.net/go/mautrix/crypto/signatures/signatures.go
generated
vendored
Normal file
94
vendor/maunium.net/go/mautrix/crypto/signatures/signatures.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// 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 signatures
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
"go.mau.fi/util/exgjson"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEmptyInput = errors.New("empty input")
|
||||
ErrSignatureNotFound = errors.New("input JSON doesn't contain signature from specified device")
|
||||
)
|
||||
|
||||
// Signatures represents a set of signatures for some data from multiple users
|
||||
// and keys.
|
||||
type Signatures map[id.UserID]map[id.KeyID]string
|
||||
|
||||
// NewSingleSignature creates a new [Signatures] object with a single
|
||||
// signature.
|
||||
func NewSingleSignature(userID id.UserID, algorithm id.KeyAlgorithm, keyID string, signature string) Signatures {
|
||||
return Signatures{
|
||||
userID: {
|
||||
id.NewKeyID(algorithm, keyID): signature,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// VerifySignature verifies an Ed25519 signature.
|
||||
func VerifySignature(message []byte, key id.Ed25519, signature []byte) (ok bool, err error) {
|
||||
if len(message) == 0 || len(key) == 0 || len(signature) == 0 {
|
||||
return false, ErrEmptyInput
|
||||
}
|
||||
keyDecoded, err := base64.RawStdEncoding.DecodeString(key.String())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
publicKey := crypto.Ed25519PublicKey(keyDecoded)
|
||||
return publicKey.Verify(message, signature), nil
|
||||
}
|
||||
|
||||
// VerifySignatureJSON verifies the signature in the given JSON object "obj"
|
||||
// as described in [Appendix 3] of the Matrix Spec.
|
||||
//
|
||||
// This function is a wrapper over [Utility.VerifySignatureJSON] that creates
|
||||
// and destroys the [Utility] object transparently.
|
||||
//
|
||||
// If the "obj" is not already a [json.RawMessage], it will re-encoded as JSON
|
||||
// for the verification, so "json" tags will be honored.
|
||||
//
|
||||
// [Appendix 3]: https://spec.matrix.org/v1.9/appendices/#signing-json
|
||||
func VerifySignatureJSON(obj any, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
|
||||
var err error
|
||||
objJSON, ok := obj.(json.RawMessage)
|
||||
if !ok {
|
||||
objJSON, err = json.Marshal(obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
sig := gjson.GetBytes(objJSON, exgjson.Path("signatures", string(userID), fmt.Sprintf("ed25519:%s", keyName)))
|
||||
if !sig.Exists() || sig.Type != gjson.String {
|
||||
return false, ErrSignatureNotFound
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "unsigned")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "signatures")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSONString := canonicaljson.CanonicalJSONAssumeValid(objJSON)
|
||||
sigBytes, err := base64.RawStdEncoding.DecodeString(sig.Str)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return VerifySignature(objJSONString, key, sigBytes)
|
||||
}
|
||||
103
vendor/maunium.net/go/mautrix/crypto/sql_store.go
generated
vendored
103
vendor/maunium.net/go/mautrix/crypto/sql_store.go
generated
vendored
@@ -21,6 +21,7 @@ import (
|
||||
"go.mau.fi/util/dbutil"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/goolm/cipher"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/crypto/sql_store_upgrade"
|
||||
"maunium.net/go/mautrix/event"
|
||||
@@ -124,20 +125,21 @@ func (store *SQLCryptoStore) PutAccount(ctx context.Context, account *OlmAccount
|
||||
store.Account = account
|
||||
bytes := account.Internal.Pickle(store.PickleKey)
|
||||
_, err := store.DB.Exec(ctx, `
|
||||
INSERT INTO crypto_account (device_id, shared, sync_token, account, account_id) VALUES ($1, $2, $3, $4, $5)
|
||||
INSERT INTO crypto_account (device_id, shared, sync_token, account, account_id, key_backup_version) VALUES ($1, $2, $3, $4, $5, $6)
|
||||
ON CONFLICT (account_id) DO UPDATE SET shared=excluded.shared, sync_token=excluded.sync_token,
|
||||
account=excluded.account, account_id=excluded.account_id
|
||||
`, store.DeviceID, account.Shared, store.SyncToken, bytes, store.AccountID)
|
||||
account=excluded.account, account_id=excluded.account_id,
|
||||
key_backup_version=excluded.key_backup_version
|
||||
`, store.DeviceID, account.Shared, store.SyncToken, bytes, store.AccountID, account.KeyBackupVersion)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetAccount retrieves an OlmAccount from the database.
|
||||
func (store *SQLCryptoStore) GetAccount(ctx context.Context) (*OlmAccount, error) {
|
||||
if store.Account == nil {
|
||||
row := store.DB.QueryRow(ctx, "SELECT shared, sync_token, account FROM crypto_account WHERE account_id=$1", store.AccountID)
|
||||
row := store.DB.QueryRow(ctx, "SELECT shared, sync_token, account, key_backup_version FROM crypto_account WHERE account_id=$1", store.AccountID)
|
||||
acc := &OlmAccount{Internal: *olm.NewBlankAccount()}
|
||||
var accountBytes []byte
|
||||
err := row.Scan(&acc.Shared, &store.SyncToken, &accountBytes)
|
||||
err := row.Scan(&acc.Shared, &store.SyncToken, &accountBytes, &acc.KeyBackupVersion)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
@@ -284,17 +286,18 @@ func (store *SQLCryptoStore) PutGroupSession(ctx context.Context, roomID id.Room
|
||||
_, err = store.DB.Exec(ctx, `
|
||||
INSERT INTO crypto_megolm_inbound_session (
|
||||
session_id, sender_key, signing_key, room_id, session, forwarding_chains,
|
||||
ratchet_safety, received_at, max_age, max_messages, is_scheduled, account_id
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
||||
ratchet_safety, received_at, max_age, max_messages, is_scheduled, key_backup_version, account_id
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
||||
ON CONFLICT (session_id, account_id) DO UPDATE
|
||||
SET withheld_code=NULL, withheld_reason=NULL, sender_key=excluded.sender_key, signing_key=excluded.signing_key,
|
||||
room_id=excluded.room_id, session=excluded.session, forwarding_chains=excluded.forwarding_chains,
|
||||
ratchet_safety=excluded.ratchet_safety, received_at=excluded.received_at,
|
||||
max_age=excluded.max_age, max_messages=excluded.max_messages, is_scheduled=excluded.is_scheduled
|
||||
max_age=excluded.max_age, max_messages=excluded.max_messages, is_scheduled=excluded.is_scheduled,
|
||||
key_backup_version=excluded.key_backup_version
|
||||
`,
|
||||
sessionID, senderKey, session.SigningKey, roomID, sessionBytes, forwardingChains,
|
||||
ratchetSafety, datePtr(session.ReceivedAt), intishPtr(session.MaxAge), intishPtr(session.MaxMessages),
|
||||
session.IsScheduled, store.AccountID,
|
||||
session.IsScheduled, session.KeyBackupVersion, store.AccountID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@@ -306,12 +309,13 @@ func (store *SQLCryptoStore) GetGroupSession(ctx context.Context, roomID id.Room
|
||||
var receivedAt sql.NullTime
|
||||
var maxAge, maxMessages sql.NullInt64
|
||||
var isScheduled bool
|
||||
var version id.KeyBackupVersion
|
||||
err := store.DB.QueryRow(ctx, `
|
||||
SELECT sender_key, signing_key, session, forwarding_chains, withheld_code, withheld_reason, ratchet_safety, received_at, max_age, max_messages, is_scheduled
|
||||
SELECT sender_key, signing_key, session, forwarding_chains, withheld_code, withheld_reason, ratchet_safety, received_at, max_age, max_messages, is_scheduled, key_backup_version
|
||||
FROM crypto_megolm_inbound_session
|
||||
WHERE room_id=$1 AND (sender_key=$2 OR $2 = '') AND session_id=$3 AND account_id=$4`,
|
||||
roomID, senderKey, sessionID, store.AccountID,
|
||||
).Scan(&senderKeyDB, &signingKey, &sessionBytes, &forwardingChains, &withheldCode, &withheldReason, &ratchetSafetyBytes, &receivedAt, &maxAge, &maxMessages, &isScheduled)
|
||||
).Scan(&senderKeyDB, &signingKey, &sessionBytes, &forwardingChains, &withheldCode, &withheldReason, &ratchetSafetyBytes, &receivedAt, &maxAge, &maxMessages, &isScheduled, &version)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
@@ -341,6 +345,7 @@ func (store *SQLCryptoStore) GetGroupSession(ctx context.Context, roomID id.Room
|
||||
MaxAge: maxAge.Int64,
|
||||
MaxMessages: int(maxMessages.Int64),
|
||||
IsScheduled: isScheduled,
|
||||
KeyBackupVersion: version,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -468,7 +473,8 @@ func (store *SQLCryptoStore) scanInboundGroupSession(rows dbutil.Scannable) (*In
|
||||
var receivedAt sql.NullTime
|
||||
var maxAge, maxMessages sql.NullInt64
|
||||
var isScheduled bool
|
||||
err := rows.Scan(&roomID, &senderKey, &signingKey, &sessionBytes, &forwardingChains, &ratchetSafetyBytes, &receivedAt, &maxAge, &maxMessages, &isScheduled)
|
||||
var version id.KeyBackupVersion
|
||||
err := rows.Scan(&roomID, &senderKey, &signingKey, &sessionBytes, &forwardingChains, &ratchetSafetyBytes, &receivedAt, &maxAge, &maxMessages, &isScheduled, &version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -484,31 +490,35 @@ func (store *SQLCryptoStore) scanInboundGroupSession(rows dbutil.Scannable) (*In
|
||||
MaxAge: maxAge.Int64,
|
||||
MaxMessages: int(maxMessages.Int64),
|
||||
IsScheduled: isScheduled,
|
||||
KeyBackupVersion: version,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (store *SQLCryptoStore) GetGroupSessionsForRoom(ctx context.Context, roomID id.RoomID) ([]*InboundGroupSession, error) {
|
||||
func (store *SQLCryptoStore) GetGroupSessionsForRoom(ctx context.Context, roomID id.RoomID) dbutil.RowIter[*InboundGroupSession] {
|
||||
rows, err := store.DB.Query(ctx, `
|
||||
SELECT room_id, sender_key, signing_key, session, forwarding_chains, withheld_code, withheld_reason, ratchet_safety, received_at, max_age, max_messages, is_scheduled
|
||||
SELECT room_id, sender_key, signing_key, session, forwarding_chains, ratchet_safety, received_at, max_age, max_messages, is_scheduled, key_backup_version
|
||||
FROM crypto_megolm_inbound_session WHERE room_id=$1 AND account_id=$2 AND session IS NOT NULL`,
|
||||
roomID, store.AccountID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dbutil.NewRowIter(rows, store.scanInboundGroupSession).AsList()
|
||||
return dbutil.NewRowIterWithError(rows, store.scanInboundGroupSession, err)
|
||||
}
|
||||
|
||||
func (store *SQLCryptoStore) GetAllGroupSessions(ctx context.Context) ([]*InboundGroupSession, error) {
|
||||
func (store *SQLCryptoStore) GetAllGroupSessions(ctx context.Context) dbutil.RowIter[*InboundGroupSession] {
|
||||
rows, err := store.DB.Query(ctx, `
|
||||
SELECT room_id, sender_key, signing_key, session, forwarding_chains, withheld_code, withheld_reason, ratchet_safety, received_at, max_age, max_messages, is_scheduled
|
||||
FROM crypto_megolm_inbound_session WHERE account_id=$2 AND session IS NOT NULL`,
|
||||
SELECT room_id, sender_key, signing_key, session, forwarding_chains, ratchet_safety, received_at, max_age, max_messages, is_scheduled, key_backup_version
|
||||
FROM crypto_megolm_inbound_session WHERE account_id=$1 AND session IS NOT NULL`,
|
||||
store.AccountID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dbutil.NewRowIter(rows, store.scanInboundGroupSession).AsList()
|
||||
return dbutil.NewRowIterWithError(rows, store.scanInboundGroupSession, err)
|
||||
}
|
||||
|
||||
func (store *SQLCryptoStore) GetGroupSessionsWithoutKeyBackupVersion(ctx context.Context, version id.KeyBackupVersion) dbutil.RowIter[*InboundGroupSession] {
|
||||
rows, err := store.DB.Query(ctx, `
|
||||
SELECT room_id, sender_key, signing_key, session, forwarding_chains, ratchet_safety, received_at, max_age, max_messages, is_scheduled, key_backup_version
|
||||
FROM crypto_megolm_inbound_session WHERE account_id=$1 AND session IS NOT NULL AND key_backup_version != $2`,
|
||||
store.AccountID, version,
|
||||
)
|
||||
return dbutil.NewRowIterWithError(rows, store.scanInboundGroupSession, err)
|
||||
}
|
||||
|
||||
// AddOutboundGroupSession stores an outbound Megolm session, along with the information about the room and involved devices.
|
||||
@@ -568,6 +578,20 @@ func (store *SQLCryptoStore) RemoveOutboundGroupSession(ctx context.Context, roo
|
||||
return err
|
||||
}
|
||||
|
||||
func (store *SQLCryptoStore) MarkOutboundGroupSessionShared(ctx context.Context, userID id.UserID, identityKey id.IdentityKey, sessionID id.SessionID) error {
|
||||
_, err := store.DB.Exec(ctx, "INSERT INTO crypto_megolm_outbound_session_shared (user_id, identity_key, session_id) VALUES ($1, $2, $3)", userID, identityKey, sessionID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (store *SQLCryptoStore) IsOutboundGroupSessionShared(ctx context.Context, userID id.UserID, identityKey id.IdentityKey, sessionID id.SessionID) (shared bool, err error) {
|
||||
err = store.DB.QueryRow(ctx, `SELECT TRUE FROM crypto_megolm_outbound_session_shared WHERE user_id=$1 AND identity_key=$2 AND session_id=$3`,
|
||||
userID, identityKey, sessionID).Scan(&shared)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ValidateMessageIndex returns whether the given event information match the ones stored in the database
|
||||
// for the given sender key, session ID and index. If the index hasn't been stored, this will store it.
|
||||
func (store *SQLCryptoStore) ValidateMessageIndex(ctx context.Context, senderKey id.SenderKey, sessionID id.SessionID, eventID id.EventID, index uint, timestamp int64) (bool, error) {
|
||||
@@ -845,3 +869,32 @@ func (store *SQLCryptoStore) DropSignaturesByKey(ctx context.Context, userID id.
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (store *SQLCryptoStore) PutSecret(ctx context.Context, name id.Secret, value string) error {
|
||||
bytes, err := cipher.Pickle(store.PickleKey, []byte(value))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = store.DB.Exec(ctx, `
|
||||
INSERT INTO crypto_secrets (name, secret) VALUES ($1, $2)
|
||||
ON CONFLICT (name) DO UPDATE SET secret=excluded.secret
|
||||
`, name, bytes)
|
||||
return err
|
||||
}
|
||||
|
||||
func (store *SQLCryptoStore) GetSecret(ctx context.Context, name id.Secret) (value string, err error) {
|
||||
var bytes []byte
|
||||
err = store.DB.QueryRow(ctx, `SELECT secret FROM crypto_secrets WHERE name=$1`, name).Scan(&bytes)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return "", nil
|
||||
} else if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bytes, err = cipher.Unpickle(store.PickleKey, bytes)
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
func (store *SQLCryptoStore) DeleteSecret(ctx context.Context, name id.Secret) (err error) {
|
||||
_, err = store.DB.Exec(ctx, "DELETE FROM crypto_secrets WHERE name=$1", name)
|
||||
return
|
||||
}
|
||||
|
||||
55
vendor/maunium.net/go/mautrix/crypto/sql_store_upgrade/00-latest-revision.sql
generated
vendored
55
vendor/maunium.net/go/mautrix/crypto/sql_store_upgrade/00-latest-revision.sql
generated
vendored
@@ -1,10 +1,11 @@
|
||||
-- v0 -> v11: Latest revision
|
||||
-- v0 -> v14 (compatible with v9+): Latest revision
|
||||
CREATE TABLE IF NOT EXISTS crypto_account (
|
||||
account_id TEXT PRIMARY KEY,
|
||||
device_id TEXT NOT NULL,
|
||||
shared BOOLEAN NOT NULL,
|
||||
sync_token TEXT NOT NULL,
|
||||
account bytea NOT NULL
|
||||
account_id TEXT PRIMARY KEY,
|
||||
device_id TEXT NOT NULL,
|
||||
shared BOOLEAN NOT NULL,
|
||||
sync_token TEXT NOT NULL,
|
||||
account bytea NOT NULL,
|
||||
key_backup_version TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS crypto_message_index (
|
||||
@@ -44,20 +45,21 @@ CREATE TABLE IF NOT EXISTS crypto_olm_session (
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS crypto_megolm_inbound_session (
|
||||
account_id TEXT,
|
||||
session_id CHAR(43),
|
||||
sender_key CHAR(43) NOT NULL,
|
||||
signing_key CHAR(43),
|
||||
room_id TEXT NOT NULL,
|
||||
session bytea,
|
||||
forwarding_chains bytea,
|
||||
withheld_code TEXT,
|
||||
withheld_reason TEXT,
|
||||
ratchet_safety jsonb,
|
||||
received_at timestamp,
|
||||
max_age BIGINT,
|
||||
max_messages INTEGER,
|
||||
is_scheduled BOOLEAN NOT NULL DEFAULT false,
|
||||
account_id TEXT,
|
||||
session_id CHAR(43),
|
||||
sender_key CHAR(43) NOT NULL,
|
||||
signing_key CHAR(43),
|
||||
room_id TEXT NOT NULL,
|
||||
session bytea,
|
||||
forwarding_chains bytea,
|
||||
withheld_code TEXT,
|
||||
withheld_reason TEXT,
|
||||
ratchet_safety jsonb,
|
||||
received_at timestamp,
|
||||
max_age BIGINT,
|
||||
max_messages INTEGER,
|
||||
is_scheduled BOOLEAN NOT NULL DEFAULT false,
|
||||
key_backup_version TEXT NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (account_id, session_id)
|
||||
);
|
||||
|
||||
@@ -75,6 +77,14 @@ CREATE TABLE IF NOT EXISTS crypto_megolm_outbound_session (
|
||||
PRIMARY KEY (account_id, room_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS crypto_megolm_outbound_session_shared (
|
||||
user_id TEXT NOT NULL,
|
||||
identity_key CHAR(43) NOT NULL,
|
||||
session_id CHAR(43) NOT NULL,
|
||||
|
||||
PRIMARY KEY (user_id, identity_key, session_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS crypto_cross_signing_keys (
|
||||
user_id TEXT,
|
||||
usage TEXT,
|
||||
@@ -93,3 +103,8 @@ CREATE TABLE IF NOT EXISTS crypto_cross_signing_signatures (
|
||||
signature CHAR(88) NOT NULL,
|
||||
PRIMARY KEY (signed_user_id, signed_key, signer_user_id, signer_key)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS crypto_secrets (
|
||||
name TEXT PRIMARY KEY NOT NULL,
|
||||
secret bytea NOT NULL
|
||||
);
|
||||
|
||||
5
vendor/maunium.net/go/mautrix/crypto/sql_store_upgrade/12-secrets.sql
generated
vendored
Normal file
5
vendor/maunium.net/go/mautrix/crypto/sql_store_upgrade/12-secrets.sql
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
-- v12 (compatible with v9+): Add crypto_secrets table
|
||||
CREATE TABLE IF NOT EXISTS crypto_secrets (
|
||||
name TEXT PRIMARY KEY NOT NULL,
|
||||
secret bytea NOT NULL
|
||||
);
|
||||
9
vendor/maunium.net/go/mautrix/crypto/sql_store_upgrade/13-megolm-session-sharing.sql
generated
vendored
Normal file
9
vendor/maunium.net/go/mautrix/crypto/sql_store_upgrade/13-megolm-session-sharing.sql
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
-- v13 (compatible with v9+): Add crypto_megolm_outbound_session_shared table
|
||||
|
||||
CREATE TABLE IF NOT EXISTS crypto_megolm_outbound_session_shared (
|
||||
user_id TEXT NOT NULL,
|
||||
identity_key CHAR(43) NOT NULL,
|
||||
session_id CHAR(43) NOT NULL,
|
||||
|
||||
PRIMARY KEY (user_id, identity_key, session_id)
|
||||
);
|
||||
4
vendor/maunium.net/go/mautrix/crypto/sql_store_upgrade/14-account-key-backup-version.sql
generated
vendored
Normal file
4
vendor/maunium.net/go/mautrix/crypto/sql_store_upgrade/14-account-key-backup-version.sql
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
-- v14 (compatible with v9+): Add key_backup_version column to account and igs
|
||||
|
||||
ALTER TABLE crypto_account ADD COLUMN key_backup_version TEXT NOT NULL DEFAULT '';
|
||||
ALTER TABLE crypto_megolm_inbound_session ADD COLUMN key_backup_version TEXT NOT NULL DEFAULT '';
|
||||
3
vendor/maunium.net/go/mautrix/crypto/ssss/client.go
generated
vendored
3
vendor/maunium.net/go/mautrix/crypto/ssss/client.go
generated
vendored
@@ -8,6 +8,7 @@ package ssss
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
@@ -34,7 +35,7 @@ func (mach *Machine) GetDefaultKeyID(ctx context.Context) (string, error) {
|
||||
var data DefaultSecretStorageKeyContent
|
||||
err := mach.Client.GetAccountData(ctx, event.AccountDataSecretStorageDefaultKey.Type, &data)
|
||||
if err != nil {
|
||||
if httpErr, ok := err.(mautrix.HTTPError); ok && httpErr.RespError != nil && httpErr.RespError.ErrCode == "M_NOT_FOUND" {
|
||||
if httpErr, ok := err.(mautrix.HTTPError); ok && errors.Is(httpErr.RespError, mautrix.MNotFound) {
|
||||
return "", ErrNoDefaultKeyAccountDataEvent
|
||||
}
|
||||
return "", fmt.Errorf("failed to get default key account data from server: %w", err)
|
||||
|
||||
25
vendor/maunium.net/go/mautrix/crypto/ssss/key.go
generated
vendored
25
vendor/maunium.net/go/mautrix/crypto/ssss/key.go
generated
vendored
@@ -67,12 +67,12 @@ func NewKey(passphrase string) (*Key, error) {
|
||||
if _, err := rand.Read(ivBytes[:]); err != nil {
|
||||
return nil, fmt.Errorf("failed to get random bytes for IV: %w", err)
|
||||
}
|
||||
keyData.IV = base64.StdEncoding.EncodeToString(ivBytes[:])
|
||||
keyData.IV = base64.RawStdEncoding.EncodeToString(ivBytes[:])
|
||||
keyData.MAC = keyData.calculateHash(ssssKey)
|
||||
|
||||
return &Key{
|
||||
Key: ssssKey,
|
||||
ID: base64.StdEncoding.EncodeToString(keyIDBytes),
|
||||
ID: base64.RawStdEncoding.EncodeToString(keyIDBytes),
|
||||
Metadata: &keyData,
|
||||
}, nil
|
||||
}
|
||||
@@ -87,13 +87,18 @@ func (key *Key) Encrypt(eventType string, data []byte) EncryptedKeyData {
|
||||
aesKey, hmacKey := utils.DeriveKeysSHA256(key.Key, eventType)
|
||||
|
||||
iv := utils.GenA256CTRIV()
|
||||
payload := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
|
||||
base64.StdEncoding.Encode(payload, data)
|
||||
// For some reason, keys in secret storage are base64 encoded before encrypting.
|
||||
// Even more confusingly, it's a part of each key type's spec rather than the secrets spec.
|
||||
// Key backup (`m.megolm_backup.v1`): https://spec.matrix.org/v1.9/client-server-api/#recovery-key
|
||||
// Cross-signing (master, etc): https://spec.matrix.org/v1.9/client-server-api/#cross-signing (the very last paragraph)
|
||||
// It's also not clear whether unpadded base64 is the right option, but assuming it is because everything else is unpadded.
|
||||
payload := make([]byte, base64.RawStdEncoding.EncodedLen(len(data)))
|
||||
base64.RawStdEncoding.Encode(payload, data)
|
||||
utils.XorA256CTR(payload, aesKey, iv)
|
||||
|
||||
return EncryptedKeyData{
|
||||
Ciphertext: base64.StdEncoding.EncodeToString(payload),
|
||||
IV: base64.StdEncoding.EncodeToString(iv[:]),
|
||||
Ciphertext: base64.RawStdEncoding.EncodeToString(payload),
|
||||
IV: base64.RawStdEncoding.EncodeToString(iv[:]),
|
||||
MAC: utils.HMACSHA256B64(payload, hmacKey),
|
||||
}
|
||||
}
|
||||
@@ -101,10 +106,10 @@ func (key *Key) Encrypt(eventType string, data []byte) EncryptedKeyData {
|
||||
// Decrypt decrypts the given encrypted data with this key.
|
||||
func (key *Key) Decrypt(eventType string, data EncryptedKeyData) ([]byte, error) {
|
||||
var ivBytes [utils.AESCTRIVLength]byte
|
||||
decodedIV, _ := base64.StdEncoding.DecodeString(data.IV)
|
||||
decodedIV, _ := base64.RawStdEncoding.DecodeString(strings.TrimRight(data.IV, "="))
|
||||
copy(ivBytes[:], decodedIV)
|
||||
|
||||
payload, err := base64.StdEncoding.DecodeString(data.Ciphertext)
|
||||
payload, err := base64.RawStdEncoding.DecodeString(strings.TrimRight(data.Ciphertext, "="))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -114,11 +119,11 @@ func (key *Key) Decrypt(eventType string, data EncryptedKeyData) ([]byte, error)
|
||||
|
||||
// compare the stored MAC with the one we calculated from the ciphertext
|
||||
calcMac := utils.HMACSHA256B64(payload, hmacKey)
|
||||
if strings.ReplaceAll(data.MAC, "=", "") != strings.ReplaceAll(calcMac, "=", "") {
|
||||
if strings.TrimRight(data.MAC, "=") != calcMac {
|
||||
return nil, ErrKeyDataMACMismatch
|
||||
}
|
||||
|
||||
utils.XorA256CTR(payload, aesKey, ivBytes)
|
||||
decryptedDecoded, err := base64.StdEncoding.DecodeString(string(payload))
|
||||
decryptedDecoded, err := base64.RawStdEncoding.DecodeString(strings.TrimRight(string(payload), "="))
|
||||
return decryptedDecoded, err
|
||||
}
|
||||
|
||||
15
vendor/maunium.net/go/mautrix/crypto/ssss/meta.go
generated
vendored
15
vendor/maunium.net/go/mautrix/crypto/ssss/meta.go
generated
vendored
@@ -19,9 +19,14 @@ import (
|
||||
type KeyMetadata struct {
|
||||
id string
|
||||
|
||||
Algorithm Algorithm `json:"algorithm"`
|
||||
IV string `json:"iv"`
|
||||
MAC string `json:"mac"`
|
||||
Name string `json:"name"`
|
||||
Algorithm Algorithm `json:"algorithm"`
|
||||
|
||||
// Note: as per https://spec.matrix.org/v1.9/client-server-api/#msecret_storagev1aes-hmac-sha2,
|
||||
// these fields are "maybe padded" base64, so both unpadded and padded values must be supported.
|
||||
IV string `json:"iv"`
|
||||
MAC string `json:"mac"`
|
||||
|
||||
Passphrase *PassphraseMetadata `json:"passphrase,omitempty"`
|
||||
}
|
||||
|
||||
@@ -59,7 +64,7 @@ func (kd *KeyMetadata) VerifyRecoveryKey(recoverKey string) (*Key, error) {
|
||||
|
||||
// VerifyKey verifies the SSSS key is valid by calculating and comparing its MAC.
|
||||
func (kd *KeyMetadata) VerifyKey(key []byte) bool {
|
||||
return strings.ReplaceAll(kd.MAC, "=", "") == strings.ReplaceAll(kd.calculateHash(key), "=", "")
|
||||
return strings.TrimRight(kd.MAC, "=") == kd.calculateHash(key)
|
||||
}
|
||||
|
||||
// calculateHash calculates the hash used for checking if the key is entered correctly as described
|
||||
@@ -68,7 +73,7 @@ func (kd *KeyMetadata) calculateHash(key []byte) string {
|
||||
aesKey, hmacKey := utils.DeriveKeysSHA256(key, "")
|
||||
|
||||
var ivBytes [utils.AESCTRIVLength]byte
|
||||
_, _ = base64.StdEncoding.Decode(ivBytes[:], []byte(kd.IV))
|
||||
_, _ = base64.RawStdEncoding.Decode(ivBytes[:], []byte(strings.TrimRight(kd.IV, "=")))
|
||||
|
||||
cipher := utils.XorA256CTR(make([]byte, utils.AESCTRKeyLength), aesKey, ivBytes)
|
||||
|
||||
|
||||
3
vendor/maunium.net/go/mautrix/crypto/ssss/types.go
generated
vendored
3
vendor/maunium.net/go/mautrix/crypto/ssss/types.go
generated
vendored
@@ -47,6 +47,8 @@ const (
|
||||
)
|
||||
|
||||
type EncryptedKeyData struct {
|
||||
// Note: as per https://spec.matrix.org/v1.9/client-server-api/#msecret_storagev1aes-hmac-sha2-1,
|
||||
// these fields are "maybe padded" base64, so both unpadded and padded values must be supported.
|
||||
Ciphertext string `json:"ciphertext"`
|
||||
IV string `json:"iv"`
|
||||
MAC string `json:"mac"`
|
||||
@@ -72,4 +74,5 @@ func init() {
|
||||
event.TypeMap[event.AccountDataCrossSigningUser] = encryptedContent
|
||||
event.TypeMap[event.AccountDataSecretStorageDefaultKey] = reflect.TypeOf(&DefaultSecretStorageKeyContent{})
|
||||
event.TypeMap[event.AccountDataSecretStorageKey] = reflect.TypeOf(&KeyMetadata{})
|
||||
event.TypeMap[event.AccountDataMegolmBackupKey] = reflect.TypeOf(&EncryptedAccountDataEventContent{})
|
||||
}
|
||||
|
||||
105
vendor/maunium.net/go/mautrix/crypto/store.go
generated
vendored
105
vendor/maunium.net/go/mautrix/crypto/store.go
generated
vendored
@@ -12,6 +12,8 @@ import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"go.mau.fi/util/dbutil"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
@@ -68,10 +70,12 @@ type Store interface {
|
||||
|
||||
// GetGroupSessionsForRoom gets all the inbound Megolm sessions for a specific room. This is used for creating key
|
||||
// export files. Unlike GetGroupSession, this should not return any errors about withheld keys.
|
||||
GetGroupSessionsForRoom(context.Context, id.RoomID) ([]*InboundGroupSession, error)
|
||||
GetGroupSessionsForRoom(context.Context, id.RoomID) dbutil.RowIter[*InboundGroupSession]
|
||||
// GetAllGroupSessions gets all the inbound Megolm sessions in the store. This is used for creating key export
|
||||
// files. Unlike GetGroupSession, this should not return any errors about withheld keys.
|
||||
GetAllGroupSessions(context.Context) ([]*InboundGroupSession, error)
|
||||
GetAllGroupSessions(context.Context) dbutil.RowIter[*InboundGroupSession]
|
||||
// GetGroupSessionsWithoutKeyBackupVersion gets all the inbound Megolm sessions in the store that do not match given key backup version.
|
||||
GetGroupSessionsWithoutKeyBackupVersion(context.Context, id.KeyBackupVersion) dbutil.RowIter[*InboundGroupSession]
|
||||
|
||||
// AddOutboundGroupSession inserts the given outbound Megolm session into the store.
|
||||
//
|
||||
@@ -84,6 +88,10 @@ type Store interface {
|
||||
GetOutboundGroupSession(context.Context, id.RoomID) (*OutboundGroupSession, error)
|
||||
// RemoveOutboundGroupSession removes the stored outbound Megolm session for the given room ID.
|
||||
RemoveOutboundGroupSession(context.Context, id.RoomID) error
|
||||
// MarkOutboutGroupSessionShared flags that the currently known device has been shared the keys for the specified session.
|
||||
MarkOutboundGroupSessionShared(context.Context, id.UserID, id.IdentityKey, id.SessionID) error
|
||||
// IsOutboutGroupSessionShared checks if the specified session has been shared with the device.
|
||||
IsOutboundGroupSessionShared(context.Context, id.UserID, id.IdentityKey, id.SessionID) (bool, error)
|
||||
|
||||
// ValidateMessageIndex validates that the given message details aren't from a replay attack.
|
||||
//
|
||||
@@ -123,6 +131,13 @@ type Store interface {
|
||||
IsKeySignedBy(ctx context.Context, userID id.UserID, key id.Ed25519, signedByUser id.UserID, signedByKey id.Ed25519) (bool, error)
|
||||
// DropSignaturesByKey deletes the signatures made by the given user and key from the store. It returns the number of signatures deleted.
|
||||
DropSignaturesByKey(context.Context, id.UserID, id.Ed25519) (int64, error)
|
||||
|
||||
// PutSecret stores a named secret, replacing it if it exists already.
|
||||
PutSecret(context.Context, id.Secret, string) error
|
||||
// GetSecret returns a named secret.
|
||||
GetSecret(context.Context, id.Secret) (string, error)
|
||||
// DeleteSecret removes a named secret.
|
||||
DeleteSecret(context.Context, id.Secret) error
|
||||
}
|
||||
|
||||
type messageIndexKey struct {
|
||||
@@ -148,11 +163,13 @@ type MemoryStore struct {
|
||||
GroupSessions map[id.RoomID]map[id.SenderKey]map[id.SessionID]*InboundGroupSession
|
||||
WithheldGroupSessions map[id.RoomID]map[id.SenderKey]map[id.SessionID]*event.RoomKeyWithheldEventContent
|
||||
OutGroupSessions map[id.RoomID]*OutboundGroupSession
|
||||
SharedGroupSessions map[id.UserID]map[id.IdentityKey]map[id.SessionID]struct{}
|
||||
MessageIndices map[messageIndexKey]messageIndexValue
|
||||
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
|
||||
OutdatedUsers map[id.UserID]struct{}
|
||||
Secrets map[id.Secret]string
|
||||
}
|
||||
|
||||
var _ Store = (*MemoryStore)(nil)
|
||||
@@ -168,11 +185,13 @@ func NewMemoryStore(saveCallback func() error) *MemoryStore {
|
||||
GroupSessions: make(map[id.RoomID]map[id.SenderKey]map[id.SessionID]*InboundGroupSession),
|
||||
WithheldGroupSessions: make(map[id.RoomID]map[id.SenderKey]map[id.SessionID]*event.RoomKeyWithheldEventContent),
|
||||
OutGroupSessions: make(map[id.RoomID]*OutboundGroupSession),
|
||||
SharedGroupSessions: make(map[id.UserID]map[id.IdentityKey]map[id.SessionID]struct{}),
|
||||
MessageIndices: make(map[messageIndexKey]messageIndexValue),
|
||||
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),
|
||||
OutdatedUsers: make(map[id.UserID]struct{}),
|
||||
Secrets: make(map[id.Secret]string),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,12 +380,12 @@ func (gs *MemoryStore) GetWithheldGroupSession(_ context.Context, roomID id.Room
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (gs *MemoryStore) GetGroupSessionsForRoom(_ context.Context, roomID id.RoomID) ([]*InboundGroupSession, error) {
|
||||
func (gs *MemoryStore) GetGroupSessionsForRoom(_ context.Context, roomID id.RoomID) dbutil.RowIter[*InboundGroupSession] {
|
||||
gs.lock.Lock()
|
||||
defer gs.lock.Unlock()
|
||||
room, ok := gs.GroupSessions[roomID]
|
||||
if !ok {
|
||||
return []*InboundGroupSession{}, nil
|
||||
return nil
|
||||
}
|
||||
var result []*InboundGroupSession
|
||||
for _, sessions := range room {
|
||||
@@ -374,10 +393,10 @@ func (gs *MemoryStore) GetGroupSessionsForRoom(_ context.Context, roomID id.Room
|
||||
result = append(result, session)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
return dbutil.NewSliceIter[*InboundGroupSession](result)
|
||||
}
|
||||
|
||||
func (gs *MemoryStore) GetAllGroupSessions(_ context.Context) ([]*InboundGroupSession, error) {
|
||||
func (gs *MemoryStore) GetAllGroupSessions(_ context.Context) dbutil.RowIter[*InboundGroupSession] {
|
||||
gs.lock.Lock()
|
||||
var result []*InboundGroupSession
|
||||
for _, room := range gs.GroupSessions {
|
||||
@@ -388,7 +407,23 @@ func (gs *MemoryStore) GetAllGroupSessions(_ context.Context) ([]*InboundGroupSe
|
||||
}
|
||||
}
|
||||
gs.lock.Unlock()
|
||||
return result, nil
|
||||
return dbutil.NewSliceIter[*InboundGroupSession](result)
|
||||
}
|
||||
|
||||
func (gs *MemoryStore) GetGroupSessionsWithoutKeyBackupVersion(_ context.Context, version id.KeyBackupVersion) dbutil.RowIter[*InboundGroupSession] {
|
||||
gs.lock.Lock()
|
||||
var result []*InboundGroupSession
|
||||
for _, room := range gs.GroupSessions {
|
||||
for _, sessions := range room {
|
||||
for _, session := range sessions {
|
||||
if session.KeyBackupVersion != version {
|
||||
result = append(result, session)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gs.lock.Unlock()
|
||||
return dbutil.NewSliceIter[*InboundGroupSession](result)
|
||||
}
|
||||
|
||||
func (gs *MemoryStore) AddOutboundGroupSession(_ context.Context, session *OutboundGroupSession) error {
|
||||
@@ -426,6 +461,41 @@ func (gs *MemoryStore) RemoveOutboundGroupSession(_ context.Context, roomID id.R
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gs *MemoryStore) MarkOutboundGroupSessionShared(_ context.Context, userID id.UserID, identityKey id.IdentityKey, sessionID id.SessionID) error {
|
||||
gs.lock.Lock()
|
||||
|
||||
if _, ok := gs.SharedGroupSessions[userID]; !ok {
|
||||
gs.SharedGroupSessions[userID] = make(map[id.IdentityKey]map[id.SessionID]struct{})
|
||||
}
|
||||
identities := gs.SharedGroupSessions[userID]
|
||||
|
||||
if _, ok := identities[identityKey]; !ok {
|
||||
identities[identityKey] = make(map[id.SessionID]struct{})
|
||||
}
|
||||
|
||||
identities[identityKey][sessionID] = struct{}{}
|
||||
|
||||
gs.lock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gs *MemoryStore) IsOutboundGroupSessionShared(_ context.Context, userID id.UserID, identityKey id.IdentityKey, sessionID id.SessionID) (isShared bool, err error) {
|
||||
gs.lock.Lock()
|
||||
defer gs.lock.Unlock()
|
||||
|
||||
if _, ok := gs.SharedGroupSessions[userID]; !ok {
|
||||
return
|
||||
}
|
||||
identities := gs.SharedGroupSessions[userID]
|
||||
|
||||
if _, ok := identities[identityKey]; !ok {
|
||||
return
|
||||
}
|
||||
|
||||
_, isShared = identities[identityKey][sessionID]
|
||||
return
|
||||
}
|
||||
|
||||
func (gs *MemoryStore) ValidateMessageIndex(_ context.Context, senderKey id.SenderKey, sessionID id.SessionID, eventID id.EventID, index uint, timestamp int64) (bool, error) {
|
||||
gs.lock.Lock()
|
||||
defer gs.lock.Unlock()
|
||||
@@ -645,3 +715,24 @@ func (gs *MemoryStore) DropSignaturesByKey(_ context.Context, userID id.UserID,
|
||||
gs.lock.RUnlock()
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (gs *MemoryStore) PutSecret(_ context.Context, name id.Secret, value string) error {
|
||||
gs.lock.Lock()
|
||||
gs.Secrets[name] = value
|
||||
gs.lock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gs *MemoryStore) GetSecret(_ context.Context, name id.Secret) (value string, _ error) {
|
||||
gs.lock.RLock()
|
||||
value = gs.Secrets[name]
|
||||
gs.lock.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (gs *MemoryStore) DeleteSecret(_ context.Context, name id.Secret) error {
|
||||
gs.lock.Lock()
|
||||
delete(gs.Secrets, name)
|
||||
gs.lock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
4
vendor/maunium.net/go/mautrix/crypto/utils/utils.go
generated
vendored
4
vendor/maunium.net/go/mautrix/crypto/utils/utils.go
generated
vendored
@@ -124,9 +124,9 @@ func EncodeBase58RecoveryKey(key []byte) string {
|
||||
return spacedKey
|
||||
}
|
||||
|
||||
// HMACSHA256B64 calculates the base64 of the SHA256 hmac of the input with the given key.
|
||||
// HMACSHA256B64 calculates the unpadded base64 of the SHA256 hmac of the input with the given key.
|
||||
func HMACSHA256B64(input []byte, hmacKey [HMACKeyLength]byte) string {
|
||||
h := hmac.New(sha256.New, hmacKey[:])
|
||||
h.Write(input)
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
return base64.RawStdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
801
vendor/maunium.net/go/mautrix/crypto/verification.go
generated
vendored
801
vendor/maunium.net/go/mautrix/crypto/verification.go
generated
vendored
@@ -1,801 +0,0 @@
|
||||
// Copyright (c) 2020 Nikos Filippakis
|
||||
//
|
||||
// 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"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnknownUserForTransaction = errors.New("unknown user for transaction")
|
||||
ErrTransactionAlreadyExists = errors.New("transaction already exists")
|
||||
// ErrUnknownTransaction is returned when a key verification message is received with an unknown transaction ID.
|
||||
ErrUnknownTransaction = errors.New("unknown transaction")
|
||||
// ErrUnknownVerificationMethod is returned when the verification method in a received m.key.verification.start is unknown.
|
||||
ErrUnknownVerificationMethod = errors.New("unknown verification method")
|
||||
)
|
||||
|
||||
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 *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
|
||||
OnCancel(cancelledByUs bool, reason string, reasonCode event.VerificationCancelCode)
|
||||
OnSuccess()
|
||||
}
|
||||
|
||||
type VerificationRequestResponse int
|
||||
|
||||
const (
|
||||
AcceptRequest VerificationRequestResponse = iota
|
||||
RejectRequest
|
||||
IgnoreRequest
|
||||
)
|
||||
|
||||
// sendToOneDevice sends a to-device event to a single device.
|
||||
func (mach *OlmMachine) sendToOneDevice(ctx context.Context, userID id.UserID, deviceID id.DeviceID, eventType event.Type, content interface{}) error {
|
||||
_, err := mach.Client.SendToDevice(ctx, eventType, &mautrix.ReqSendToDevice{
|
||||
Messages: map[id.UserID]map[id.DeviceID]*event.Content{
|
||||
userID: {
|
||||
deviceID: {
|
||||
Parsed: content,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) getPKAndKeysMAC(sas *olm.SAS, sendingUser id.UserID, sendingDevice id.DeviceID, receivingUser id.UserID, receivingDevice id.DeviceID,
|
||||
transactionID string, signingKey id.SigningKey, mainKeyID id.KeyID, keys map[id.KeyID]string) (string, string, error) {
|
||||
sasInfo := "MATRIX_KEY_VERIFICATION_MAC" +
|
||||
sendingUser.String() + sendingDevice.String() +
|
||||
receivingUser.String() + receivingDevice.String() +
|
||||
transactionID
|
||||
|
||||
// get key IDs from key map
|
||||
keyIDStrings := make([]string, len(keys))
|
||||
i := 0
|
||||
for keyID := range keys {
|
||||
keyIDStrings[i] = keyID.String()
|
||||
i++
|
||||
}
|
||||
sort.Sort(sort.StringSlice(keyIDStrings))
|
||||
keyIDString := strings.Join(keyIDStrings, ",")
|
||||
|
||||
pubKeyMac, err := sas.CalculateMAC([]byte(signingKey), []byte(sasInfo+mainKeyID.String()))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
mach.Log.Trace().Msgf("sas.CalculateMAC(\"%s\", \"%s\") -> \"%s\"", signingKey, sasInfo+mainKeyID.String(), string(pubKeyMac))
|
||||
|
||||
keysMac, err := sas.CalculateMAC([]byte(keyIDString), []byte(sasInfo+"KEY_IDS"))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
mach.Log.Trace().Msgf("sas.CalculateMAC(\"%s\", \"%s\") -> \"%s\"", keyIDString, sasInfo+"KEY_IDS", string(keysMac))
|
||||
|
||||
return string(pubKeyMac), string(keysMac), nil
|
||||
}
|
||||
|
||||
// verificationState holds all the information needed for the state of a SAS verification with another device.
|
||||
type verificationState struct {
|
||||
sas *olm.SAS
|
||||
otherDevice *id.Device
|
||||
initiatedByUs bool
|
||||
verificationStarted bool
|
||||
keyReceived bool
|
||||
sasMatched chan bool
|
||||
commitment string
|
||||
startEventCanonical string
|
||||
chosenSASMethod VerificationMethod
|
||||
hooks VerificationHooks
|
||||
extendTimeout context.CancelFunc
|
||||
inRoomID id.RoomID
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// getTransactionState retrieves the given transaction's state, or cancels the transaction if it cannot be found or there is a mismatch.
|
||||
func (mach *OlmMachine) getTransactionState(ctx context.Context, transactionID string, userID id.UserID) (*verificationState, error) {
|
||||
verStateInterface, ok := mach.keyVerificationTransactionState.Load(userID.String() + ":" + transactionID)
|
||||
if !ok {
|
||||
_ = mach.SendSASVerificationCancel(ctx, userID, id.DeviceID("*"), transactionID, "Unknown transaction: "+transactionID, event.VerificationCancelUnknownTransaction)
|
||||
return nil, ErrUnknownTransaction
|
||||
}
|
||||
verState := verStateInterface.(*verificationState)
|
||||
if verState.otherDevice.UserID != userID {
|
||||
reason := fmt.Sprintf("Unknown user for transaction %v: %v", transactionID, userID)
|
||||
if verState.inRoomID == "" {
|
||||
_ = mach.SendSASVerificationCancel(ctx, userID, id.DeviceID("*"), transactionID, reason, event.VerificationCancelUserMismatch)
|
||||
} else {
|
||||
_ = mach.SendInRoomSASVerificationCancel(ctx, verState.inRoomID, userID, transactionID, reason, event.VerificationCancelUserMismatch)
|
||||
}
|
||||
mach.keyVerificationTransactionState.Delete(userID.String() + ":" + transactionID)
|
||||
return nil, fmt.Errorf("%w %s: %s", ErrUnknownUserForTransaction, transactionID, userID)
|
||||
}
|
||||
return verState, nil
|
||||
}
|
||||
|
||||
// handleVerificationStart handles an incoming m.key.verification.start message.
|
||||
// It initializes the state for this SAS verification process and stores it.
|
||||
func (mach *OlmMachine) handleVerificationStart(ctx context.Context, userID id.UserID, content *event.VerificationStartEventContent, transactionID string, timeout time.Duration, inRoomID id.RoomID) {
|
||||
mach.Log.Debug().Msgf("Received verification start from %v", content.FromDevice)
|
||||
otherDevice, err := mach.GetOrFetchDevice(ctx, userID, content.FromDevice)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Could not find device %v of user %v", content.FromDevice, userID)
|
||||
return
|
||||
}
|
||||
warnAndCancel := func(logReason, cancelReason string) {
|
||||
mach.Log.Warn().Msgf("Canceling verification transaction %v as it %s", transactionID, logReason)
|
||||
if inRoomID == "" {
|
||||
_ = mach.SendSASVerificationCancel(ctx, otherDevice.UserID, otherDevice.DeviceID, transactionID, cancelReason, event.VerificationCancelUnknownMethod)
|
||||
} else {
|
||||
_ = mach.SendInRoomSASVerificationCancel(ctx, inRoomID, otherDevice.UserID, transactionID, cancelReason, event.VerificationCancelUnknownMethod)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case content.Method != event.VerificationMethodSAS:
|
||||
warnAndCancel("is not SAS", "Only SAS method is supported")
|
||||
case !content.SupportsKeyAgreementProtocol(event.KeyAgreementCurve25519HKDFSHA256):
|
||||
warnAndCancel("does not support key agreement protocol curve25519-hkdf-sha256",
|
||||
"Only curve25519-hkdf-sha256 key agreement protocol is supported")
|
||||
case !content.SupportsHashMethod(event.VerificationHashSHA256):
|
||||
warnAndCancel("does not support SHA256 hashing", "Only SHA256 hashing is supported")
|
||||
case !content.SupportsMACMethod(event.HKDFHMACSHA256):
|
||||
warnAndCancel("does not support MAC method hkdf-hmac-sha256", "Only hkdf-hmac-sha256 MAC method is supported")
|
||||
case !content.SupportsSASMethod(event.SASDecimal):
|
||||
warnAndCancel("does not support decimal SAS", "Decimal SAS method must be supported")
|
||||
default:
|
||||
mach.actuallyStartVerification(ctx, userID, content, otherDevice, transactionID, timeout, inRoomID)
|
||||
}
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) actuallyStartVerification(ctx context.Context, userID id.UserID, content *event.VerificationStartEventContent, otherDevice *id.Device, transactionID string, timeout time.Duration, inRoomID id.RoomID) {
|
||||
if inRoomID != "" && transactionID != "" {
|
||||
verState, err := mach.getTransactionState(ctx, transactionID, userID)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Failed to get transaction state for in-room verification %s start: %v", transactionID, err)
|
||||
_ = mach.SendInRoomSASVerificationCancel(ctx, inRoomID, otherDevice.UserID, transactionID, "Internal state error in gomuks :(", "net.maunium.internal_error")
|
||||
return
|
||||
}
|
||||
mach.timeoutAfter(ctx, verState, transactionID, timeout)
|
||||
sasMethods := commonSASMethods(verState.hooks, content.ShortAuthenticationString)
|
||||
err = mach.SendInRoomSASVerificationAccept(ctx, inRoomID, userID, content, transactionID, verState.sas.GetPubkey(), sasMethods)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error accepting in-room SAS verification: %v", err)
|
||||
}
|
||||
verState.chosenSASMethod = sasMethods[0]
|
||||
verState.verificationStarted = true
|
||||
return
|
||||
}
|
||||
resp, hooks := mach.AcceptVerificationFrom(transactionID, otherDevice, inRoomID)
|
||||
if resp == AcceptRequest {
|
||||
sasMethods := commonSASMethods(hooks, content.ShortAuthenticationString)
|
||||
if len(sasMethods) == 0 {
|
||||
mach.Log.Error().Msgf("No common SAS methods: %v", content.ShortAuthenticationString)
|
||||
if inRoomID == "" {
|
||||
_ = mach.SendSASVerificationCancel(ctx, otherDevice.UserID, otherDevice.DeviceID, transactionID, "No common SAS methods", event.VerificationCancelUnknownMethod)
|
||||
} else {
|
||||
_ = mach.SendInRoomSASVerificationCancel(ctx, inRoomID, otherDevice.UserID, transactionID, "No common SAS methods", event.VerificationCancelUnknownMethod)
|
||||
}
|
||||
return
|
||||
}
|
||||
verState := &verificationState{
|
||||
sas: olm.NewSAS(),
|
||||
otherDevice: otherDevice,
|
||||
initiatedByUs: false,
|
||||
verificationStarted: true,
|
||||
keyReceived: false,
|
||||
sasMatched: make(chan bool, 1),
|
||||
hooks: hooks,
|
||||
chosenSASMethod: sasMethods[0],
|
||||
inRoomID: inRoomID,
|
||||
}
|
||||
verState.lock.Lock()
|
||||
defer verState.lock.Unlock()
|
||||
|
||||
_, loaded := mach.keyVerificationTransactionState.LoadOrStore(userID.String()+":"+transactionID, verState)
|
||||
if loaded {
|
||||
// transaction already exists
|
||||
mach.Log.Error().Msgf("Transaction %v already exists, canceling", transactionID)
|
||||
if inRoomID == "" {
|
||||
_ = mach.SendSASVerificationCancel(ctx, otherDevice.UserID, otherDevice.DeviceID, transactionID, "Transaction already exists", event.VerificationCancelUnexpectedMessage)
|
||||
} else {
|
||||
_ = mach.SendInRoomSASVerificationCancel(ctx, inRoomID, otherDevice.UserID, transactionID, "Transaction already exists", event.VerificationCancelUnexpectedMessage)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
mach.timeoutAfter(ctx, verState, transactionID, timeout)
|
||||
|
||||
var err error
|
||||
if inRoomID == "" {
|
||||
err = mach.SendSASVerificationAccept(ctx, userID, content, verState.sas.GetPubkey(), sasMethods)
|
||||
} else {
|
||||
err = mach.SendInRoomSASVerificationAccept(ctx, inRoomID, userID, content, transactionID, verState.sas.GetPubkey(), sasMethods)
|
||||
}
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error accepting SAS verification: %v", err)
|
||||
}
|
||||
} else if resp == RejectRequest {
|
||||
mach.Log.Debug().Msgf("Not accepting SAS verification %v from %v of user %v", transactionID, otherDevice.DeviceID, otherDevice.UserID)
|
||||
var err error
|
||||
if inRoomID == "" {
|
||||
err = mach.SendSASVerificationCancel(ctx, otherDevice.UserID, otherDevice.DeviceID, transactionID, "Not accepted by user", event.VerificationCancelByUser)
|
||||
} else {
|
||||
err = mach.SendInRoomSASVerificationCancel(ctx, inRoomID, otherDevice.UserID, transactionID, "Not accepted by user", event.VerificationCancelByUser)
|
||||
}
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error canceling SAS verification: %v", err)
|
||||
}
|
||||
} else {
|
||||
mach.Log.Debug().Msgf("Ignoring SAS verification %v from %v of user %v", transactionID, otherDevice.DeviceID, otherDevice.UserID)
|
||||
}
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) timeoutAfter(ctx context.Context, verState *verificationState, transactionID string, timeout time.Duration) {
|
||||
timeoutCtx, timeoutCancel := context.WithTimeout(ctx, timeout)
|
||||
verState.extendTimeout = timeoutCancel
|
||||
go func() {
|
||||
mapKey := verState.otherDevice.UserID.String() + ":" + transactionID
|
||||
for {
|
||||
<-timeoutCtx.Done()
|
||||
// when timeout context is done
|
||||
verState.lock.Lock()
|
||||
// if transaction not active anymore, return
|
||||
if _, ok := mach.keyVerificationTransactionState.Load(mapKey); !ok {
|
||||
verState.lock.Unlock()
|
||||
return
|
||||
}
|
||||
if timeoutCtx.Err() == context.DeadlineExceeded {
|
||||
// if deadline exceeded cancel due to timeout
|
||||
mach.keyVerificationTransactionState.Delete(mapKey)
|
||||
_ = mach.callbackAndCancelSASVerification(ctx, verState, transactionID, "Timed out", event.VerificationCancelByTimeout)
|
||||
mach.Log.Warn().Msgf("Verification transaction %v is canceled due to timing out", transactionID)
|
||||
verState.lock.Unlock()
|
||||
return
|
||||
}
|
||||
// otherwise the cancel func was called, so the timeout is reset
|
||||
mach.Log.Debug().Msgf("Extending timeout for transaction %v", transactionID)
|
||||
timeoutCtx, timeoutCancel = context.WithTimeout(context.Background(), timeout)
|
||||
verState.extendTimeout = timeoutCancel
|
||||
verState.lock.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// handleVerificationAccept handles an incoming m.key.verification.accept message.
|
||||
// It continues the SAS verification process by sending the SAS key message to the other device.
|
||||
func (mach *OlmMachine) handleVerificationAccept(ctx context.Context, userID id.UserID, content *event.VerificationAcceptEventContent, transactionID string) {
|
||||
mach.Log.Debug().Msgf("Received verification accept for transaction %v", transactionID)
|
||||
verState, err := mach.getTransactionState(ctx, transactionID, userID)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error getting transaction state: %v", err)
|
||||
return
|
||||
}
|
||||
verState.lock.Lock()
|
||||
defer verState.lock.Unlock()
|
||||
verState.extendTimeout()
|
||||
|
||||
if !verState.initiatedByUs || verState.verificationStarted {
|
||||
// unexpected accept at this point
|
||||
mach.Log.Warn().Msgf("Unexpected verification accept message for transaction %v", transactionID)
|
||||
mach.keyVerificationTransactionState.Delete(userID.String() + ":" + transactionID)
|
||||
_ = mach.callbackAndCancelSASVerification(ctx, verState, transactionID, "Unexpected accept message", event.VerificationCancelUnexpectedMessage)
|
||||
return
|
||||
}
|
||||
|
||||
sasMethods := commonSASMethods(verState.hooks, content.ShortAuthenticationString)
|
||||
if content.KeyAgreementProtocol != event.KeyAgreementCurve25519HKDFSHA256 ||
|
||||
content.Hash != event.VerificationHashSHA256 ||
|
||||
content.MessageAuthenticationCode != event.HKDFHMACSHA256 ||
|
||||
len(sasMethods) == 0 {
|
||||
|
||||
mach.Log.Warn().Msgf("Canceling verification transaction %v due to unknown parameter", transactionID)
|
||||
mach.keyVerificationTransactionState.Delete(userID.String() + ":" + transactionID)
|
||||
_ = mach.callbackAndCancelSASVerification(ctx, verState, transactionID, "Verification uses unknown method", event.VerificationCancelUnknownMethod)
|
||||
return
|
||||
}
|
||||
|
||||
key := verState.sas.GetPubkey()
|
||||
verState.commitment = content.Commitment
|
||||
verState.chosenSASMethod = sasMethods[0]
|
||||
verState.verificationStarted = true
|
||||
|
||||
if verState.inRoomID == "" {
|
||||
err = mach.SendSASVerificationKey(ctx, userID, verState.otherDevice.DeviceID, transactionID, string(key))
|
||||
} else {
|
||||
err = mach.SendInRoomSASVerificationKey(ctx, verState.inRoomID, userID, transactionID, string(key))
|
||||
}
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error sending SAS key to other device: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleVerificationKey handles an incoming m.key.verification.key message.
|
||||
// It stores the other device's public key in order to acquire the SAS shared secret.
|
||||
func (mach *OlmMachine) handleVerificationKey(ctx context.Context, userID id.UserID, content *event.VerificationKeyEventContent, transactionID string) {
|
||||
mach.Log.Debug().Msgf("Got verification key for transaction %v: %v", transactionID, content.Key)
|
||||
verState, err := mach.getTransactionState(ctx, transactionID, userID)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error getting transaction state: %v", err)
|
||||
return
|
||||
}
|
||||
verState.lock.Lock()
|
||||
defer verState.lock.Unlock()
|
||||
verState.extendTimeout()
|
||||
|
||||
device := verState.otherDevice
|
||||
|
||||
if !verState.verificationStarted || verState.keyReceived {
|
||||
// unexpected key at this point
|
||||
mach.Log.Warn().Msgf("Unexpected verification key message for transaction %v", transactionID)
|
||||
mach.keyVerificationTransactionState.Delete(userID.String() + ":" + transactionID)
|
||||
_ = mach.callbackAndCancelSASVerification(ctx, verState, transactionID, "Unexpected key message", event.VerificationCancelUnexpectedMessage)
|
||||
return
|
||||
}
|
||||
|
||||
if err := verState.sas.SetTheirKey([]byte(content.Key)); err != nil {
|
||||
mach.Log.Error().Msgf("Error setting other device's key: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
verState.keyReceived = true
|
||||
|
||||
if verState.initiatedByUs {
|
||||
// verify commitment string from accept message now
|
||||
expectedCommitment := olm.NewUtility().Sha256(content.Key + verState.startEventCanonical)
|
||||
mach.Log.Debug().Msgf("Received commitment: %v Expected: %v", verState.commitment, expectedCommitment)
|
||||
if expectedCommitment != verState.commitment {
|
||||
mach.Log.Warn().Msgf("Canceling verification transaction %v due to commitment mismatch", transactionID)
|
||||
mach.keyVerificationTransactionState.Delete(userID.String() + ":" + transactionID)
|
||||
_ = mach.callbackAndCancelSASVerification(ctx, verState, transactionID, "Commitment mismatch", event.VerificationCancelCommitmentMismatch)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// if verification was initiated by other device, send out our key now
|
||||
key := verState.sas.GetPubkey()
|
||||
|
||||
if verState.inRoomID == "" {
|
||||
err = mach.SendSASVerificationKey(ctx, userID, device.DeviceID, transactionID, string(key))
|
||||
} else {
|
||||
err = mach.SendInRoomSASVerificationKey(ctx, verState.inRoomID, userID, transactionID, string(key))
|
||||
}
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error sending SAS key to other device: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// compare the SAS keys in a new goroutine and, when the verification is complete, send out the MAC
|
||||
var initUserID, acceptUserID id.UserID
|
||||
var initDeviceID, acceptDeviceID id.DeviceID
|
||||
var initKey, acceptKey string
|
||||
if verState.initiatedByUs {
|
||||
initUserID = mach.Client.UserID
|
||||
initDeviceID = mach.Client.DeviceID
|
||||
initKey = string(verState.sas.GetPubkey())
|
||||
acceptUserID = device.UserID
|
||||
acceptDeviceID = device.DeviceID
|
||||
acceptKey = content.Key
|
||||
} else {
|
||||
initUserID = device.UserID
|
||||
initDeviceID = device.DeviceID
|
||||
initKey = content.Key
|
||||
acceptUserID = mach.Client.UserID
|
||||
acceptDeviceID = mach.Client.DeviceID
|
||||
acceptKey = string(verState.sas.GetPubkey())
|
||||
}
|
||||
// use the prefered SAS method to generate a SAS
|
||||
sasMethod := verState.chosenSASMethod
|
||||
sas, err := sasMethod.GetVerificationSAS(initUserID, initDeviceID, initKey, acceptUserID, acceptDeviceID, acceptKey, transactionID, verState.sas)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error generating SAS (method %v): %v", sasMethod.Type(), err)
|
||||
return
|
||||
}
|
||||
mach.Log.Debug().Msgf("Generated SAS (%v): %v", sasMethod.Type(), sas)
|
||||
go func() {
|
||||
result := verState.hooks.VerifySASMatch(device, sas)
|
||||
mach.sasCompared(ctx, result, transactionID, verState)
|
||||
}()
|
||||
}
|
||||
|
||||
// sasCompared is called asynchronously. It waits for the SAS to be compared for the verification to proceed.
|
||||
// If the SAS match, then our MAC is sent out. Otherwise the transaction is canceled.
|
||||
func (mach *OlmMachine) sasCompared(ctx context.Context, didMatch bool, transactionID string, verState *verificationState) {
|
||||
verState.lock.Lock()
|
||||
defer verState.lock.Unlock()
|
||||
verState.extendTimeout()
|
||||
if didMatch {
|
||||
verState.sasMatched <- true
|
||||
var err error
|
||||
if verState.inRoomID == "" {
|
||||
err = mach.SendSASVerificationMAC(ctx, verState.otherDevice.UserID, verState.otherDevice.DeviceID, transactionID, verState.sas)
|
||||
} else {
|
||||
err = mach.SendInRoomSASVerificationMAC(ctx, verState.inRoomID, verState.otherDevice.UserID, verState.otherDevice.DeviceID, transactionID, verState.sas)
|
||||
}
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error sending verification MAC to other device: %v", err)
|
||||
}
|
||||
} else {
|
||||
verState.sasMatched <- false
|
||||
}
|
||||
}
|
||||
|
||||
// handleVerificationMAC handles an incoming m.key.verification.mac message.
|
||||
// It verifies the other device's MAC and if the MAC is valid it marks the device as trusted.
|
||||
func (mach *OlmMachine) handleVerificationMAC(ctx context.Context, userID id.UserID, content *event.VerificationMacEventContent, transactionID string) {
|
||||
mach.Log.Debug().Msgf("Got MAC for verification %v: %v, MAC for keys: %v", transactionID, content.Mac, content.Keys)
|
||||
verState, err := mach.getTransactionState(ctx, transactionID, userID)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error getting transaction state: %v", err)
|
||||
return
|
||||
}
|
||||
verState.lock.Lock()
|
||||
defer verState.lock.Unlock()
|
||||
verState.extendTimeout()
|
||||
|
||||
device := verState.otherDevice
|
||||
|
||||
// we are done with this SAS verification in all cases so we forget about it
|
||||
mach.keyVerificationTransactionState.Delete(userID.String() + ":" + transactionID)
|
||||
|
||||
if !verState.verificationStarted || !verState.keyReceived {
|
||||
// unexpected MAC at this point
|
||||
mach.Log.Warn().Msgf("Unexpected MAC message for transaction %v", transactionID)
|
||||
_ = mach.callbackAndCancelSASVerification(ctx, verState, transactionID, "Unexpected MAC message", event.VerificationCancelUnexpectedMessage)
|
||||
return
|
||||
}
|
||||
|
||||
// do this in another goroutine as the match result might take a long time to arrive
|
||||
go func() {
|
||||
matched := <-verState.sasMatched
|
||||
verState.lock.Lock()
|
||||
defer verState.lock.Unlock()
|
||||
|
||||
if !matched {
|
||||
mach.Log.Warn().Msgf("SAS do not match! Canceling transaction %v", transactionID)
|
||||
_ = mach.callbackAndCancelSASVerification(ctx, verState, transactionID, "SAS do not match", event.VerificationCancelSASMismatch)
|
||||
return
|
||||
}
|
||||
|
||||
keyID := id.NewKeyID(id.KeyAlgorithmEd25519, device.DeviceID.String())
|
||||
|
||||
expectedPKMAC, expectedKeysMAC, err := mach.getPKAndKeysMAC(verState.sas, device.UserID, device.DeviceID,
|
||||
mach.Client.UserID, mach.Client.DeviceID, transactionID, device.SigningKey, keyID, content.Mac)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error generating MAC to match with received MAC: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mach.Log.Debug().Msgf("Expected %s keys MAC, got %s", expectedKeysMAC, content.Keys)
|
||||
if content.Keys != expectedKeysMAC {
|
||||
mach.Log.Warn().Msgf("Canceling verification transaction %v due to mismatched keys MAC", transactionID)
|
||||
_ = mach.callbackAndCancelSASVerification(ctx, verState, transactionID, "Mismatched keys MACs", event.VerificationCancelKeyMismatch)
|
||||
return
|
||||
}
|
||||
|
||||
mach.Log.Debug().Msgf("Expected %s PK MAC, got %s", expectedPKMAC, content.Mac[keyID])
|
||||
if content.Mac[keyID] != expectedPKMAC {
|
||||
mach.Log.Warn().Msgf("Canceling verification transaction %v due to mismatched PK MAC", transactionID)
|
||||
_ = mach.callbackAndCancelSASVerification(ctx, verState, transactionID, "Mismatched PK MACs", event.VerificationCancelKeyMismatch)
|
||||
return
|
||||
}
|
||||
|
||||
// we can finally trust this device
|
||||
device.Trust = id.TrustStateVerified
|
||||
err = mach.CryptoStore.PutDevice(ctx, device.UserID, device)
|
||||
if err != nil {
|
||||
mach.Log.Warn().Msgf("Failed to put device after verifying: %v", err)
|
||||
}
|
||||
|
||||
if mach.CrossSigningKeys != nil {
|
||||
if device.UserID == mach.Client.UserID {
|
||||
err := mach.SignOwnDevice(ctx, device)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Failed to cross-sign own device %s: %v", device.DeviceID, err)
|
||||
} else {
|
||||
mach.Log.Debug().Msgf("Cross-signed own device %v after SAS verification", device.DeviceID)
|
||||
}
|
||||
} else {
|
||||
masterKey, err := mach.fetchMasterKey(ctx, device, content, verState, transactionID)
|
||||
if err != nil {
|
||||
mach.Log.Warn().Msgf("Failed to fetch %s's master key: %v", device.UserID, err)
|
||||
} else {
|
||||
if err := mach.SignUser(ctx, device.UserID, masterKey); err != nil {
|
||||
mach.Log.Error().Msgf("Failed to cross-sign master key of %s: %v", device.UserID, err)
|
||||
} else {
|
||||
mach.Log.Debug().Msgf("Cross-signed master key of %v after SAS verification", device.UserID)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO ask user to unlock cross-signing keys?
|
||||
mach.Log.Debug().Msgf("Cross-signing keys not cached, not signing %s/%s", device.UserID, device.DeviceID)
|
||||
}
|
||||
|
||||
mach.Log.Debug().Msgf("Device %v of user %v verified successfully!", device.DeviceID, device.UserID)
|
||||
|
||||
verState.hooks.OnSuccess()
|
||||
}()
|
||||
}
|
||||
|
||||
// handleVerificationCancel handles an incoming m.key.verification.cancel message.
|
||||
// It cancels the verification process for the given reason.
|
||||
func (mach *OlmMachine) handleVerificationCancel(userID id.UserID, content *event.VerificationCancelEventContent, transactionID string) {
|
||||
// make sure to not reply with a cancel to not cause a loop of cancel messages
|
||||
// this verification will get canceled even if the senders do not match
|
||||
verStateInterface, ok := mach.keyVerificationTransactionState.Load(userID.String() + ":" + transactionID)
|
||||
if ok {
|
||||
go verStateInterface.(*verificationState).hooks.OnCancel(false, content.Reason, content.Code)
|
||||
}
|
||||
|
||||
mach.keyVerificationTransactionState.Delete(userID.String() + ":" + transactionID)
|
||||
mach.Log.Warn().Msgf("SAS verification %v was canceled by %v with reason: %v (%v)",
|
||||
transactionID, userID, content.Reason, content.Code)
|
||||
}
|
||||
|
||||
// handleVerificationRequest handles an incoming m.key.verification.request message.
|
||||
func (mach *OlmMachine) handleVerificationRequest(ctx context.Context, userID id.UserID, content *event.VerificationRequestEventContent, transactionID string, inRoomID id.RoomID) {
|
||||
mach.Log.Debug().Msgf("Received verification request from %v", content.FromDevice)
|
||||
otherDevice, err := mach.GetOrFetchDevice(ctx, userID, content.FromDevice)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Could not find device %v of user %v", content.FromDevice, userID)
|
||||
return
|
||||
}
|
||||
if !content.SupportsVerificationMethod(event.VerificationMethodSAS) {
|
||||
mach.Log.Warn().Msgf("Canceling verification transaction %v as SAS is not supported", transactionID)
|
||||
if inRoomID == "" {
|
||||
_ = mach.SendSASVerificationCancel(ctx, otherDevice.UserID, otherDevice.DeviceID, transactionID, "Only SAS method is supported", event.VerificationCancelUnknownMethod)
|
||||
} else {
|
||||
_ = mach.SendInRoomSASVerificationCancel(ctx, inRoomID, otherDevice.UserID, transactionID, "Only SAS method is supported", event.VerificationCancelUnknownMethod)
|
||||
}
|
||||
return
|
||||
}
|
||||
resp, hooks := mach.AcceptVerificationFrom(transactionID, otherDevice, inRoomID)
|
||||
if resp == AcceptRequest {
|
||||
mach.Log.Debug().Msgf("Accepting SAS verification %v from %v of user %v", transactionID, otherDevice.DeviceID, otherDevice.UserID)
|
||||
if inRoomID == "" {
|
||||
_, err = mach.NewSASVerificationWith(ctx, otherDevice, hooks, transactionID, mach.DefaultSASTimeout)
|
||||
} else {
|
||||
if err := mach.SendInRoomSASVerificationReady(ctx, inRoomID, transactionID); err != nil {
|
||||
mach.Log.Error().Msgf("Error sending in-room SAS verification ready: %v", err)
|
||||
}
|
||||
if mach.Client.UserID < otherDevice.UserID {
|
||||
// up to us to send the start message
|
||||
_, err = mach.newInRoomSASVerificationWithInner(ctx, inRoomID, otherDevice, hooks, transactionID, mach.DefaultSASTimeout)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error accepting SAS verification request: %v", err)
|
||||
}
|
||||
} else if resp == RejectRequest {
|
||||
mach.Log.Debug().Msgf("Rejecting SAS verification %v from %v of user %v", transactionID, otherDevice.DeviceID, otherDevice.UserID)
|
||||
if inRoomID == "" {
|
||||
_ = mach.SendSASVerificationCancel(ctx, otherDevice.UserID, otherDevice.DeviceID, transactionID, "Not accepted by user", event.VerificationCancelByUser)
|
||||
} else {
|
||||
_ = mach.SendInRoomSASVerificationCancel(ctx, inRoomID, otherDevice.UserID, transactionID, "Not accepted by user", event.VerificationCancelByUser)
|
||||
}
|
||||
} else {
|
||||
mach.Log.Debug().Msgf("Ignoring SAS verification %v from %v of user %v", transactionID, otherDevice.DeviceID, otherDevice.UserID)
|
||||
}
|
||||
}
|
||||
|
||||
// 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(ctx context.Context, device *id.Device, hooks VerificationHooks) (string, error) {
|
||||
return mach.NewSASVerificationWith(ctx, 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(ctx context.Context, device *id.Device, hooks VerificationHooks, transactionID string, timeout time.Duration) (string, error) {
|
||||
if transactionID == "" {
|
||||
transactionID = strconv.Itoa(rand.Int())
|
||||
}
|
||||
mach.Log.Debug().Msgf("Starting new verification transaction %v with device %v of user %v", transactionID, device.DeviceID, device.UserID)
|
||||
|
||||
verState := &verificationState{
|
||||
sas: olm.NewSAS(),
|
||||
otherDevice: device,
|
||||
initiatedByUs: true,
|
||||
verificationStarted: false,
|
||||
keyReceived: false,
|
||||
sasMatched: make(chan bool, 1),
|
||||
hooks: hooks,
|
||||
}
|
||||
verState.lock.Lock()
|
||||
defer verState.lock.Unlock()
|
||||
|
||||
startEvent, err := mach.SendSASVerificationStart(ctx, device.UserID, device.DeviceID, transactionID, hooks.VerificationMethods())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(startEvent)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
canonical, err := canonicaljson.CanonicalJSON(payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
verState.startEventCanonical = string(canonical)
|
||||
_, loaded := mach.keyVerificationTransactionState.LoadOrStore(device.UserID.String()+":"+transactionID, verState)
|
||||
if loaded {
|
||||
return "", ErrTransactionAlreadyExists
|
||||
}
|
||||
|
||||
mach.timeoutAfter(ctx, verState, transactionID, timeout)
|
||||
|
||||
return transactionID, nil
|
||||
}
|
||||
|
||||
// CancelSASVerification is used by the user to cancel a SAS verification process with the given reason.
|
||||
func (mach *OlmMachine) CancelSASVerification(ctx context.Context, userID id.UserID, transactionID, reason string) error {
|
||||
mapKey := userID.String() + ":" + transactionID
|
||||
verStateInterface, ok := mach.keyVerificationTransactionState.Load(mapKey)
|
||||
if !ok {
|
||||
return ErrUnknownTransaction
|
||||
}
|
||||
verState := verStateInterface.(*verificationState)
|
||||
verState.lock.Lock()
|
||||
defer verState.lock.Unlock()
|
||||
mach.Log.Trace().Msgf("User canceled verification transaction %v with reason: %v", transactionID, reason)
|
||||
mach.keyVerificationTransactionState.Delete(mapKey)
|
||||
return mach.callbackAndCancelSASVerification(ctx, verState, transactionID, reason, event.VerificationCancelByUser)
|
||||
}
|
||||
|
||||
// SendSASVerificationCancel is used to manually send a SAS cancel message process with the given reason and cancellation code.
|
||||
func (mach *OlmMachine) SendSASVerificationCancel(ctx context.Context, userID id.UserID, deviceID id.DeviceID, transactionID string, reason string, code event.VerificationCancelCode) error {
|
||||
content := &event.VerificationCancelEventContent{
|
||||
TransactionID: transactionID,
|
||||
Reason: reason,
|
||||
Code: code,
|
||||
}
|
||||
return mach.sendToOneDevice(ctx, userID, deviceID, event.ToDeviceVerificationCancel, content)
|
||||
}
|
||||
|
||||
// SendSASVerificationStart is used to manually send the SAS verification start message to another device.
|
||||
func (mach *OlmMachine) SendSASVerificationStart(ctx context.Context, toUserID id.UserID, toDeviceID id.DeviceID, transactionID string, methods []VerificationMethod) (*event.VerificationStartEventContent, error) {
|
||||
sasMethods := make([]event.SASMethod, len(methods))
|
||||
for i, method := range methods {
|
||||
sasMethods[i] = method.Type()
|
||||
}
|
||||
content := &event.VerificationStartEventContent{
|
||||
FromDevice: mach.Client.DeviceID,
|
||||
TransactionID: transactionID,
|
||||
Method: event.VerificationMethodSAS,
|
||||
KeyAgreementProtocols: []event.KeyAgreementProtocol{event.KeyAgreementCurve25519HKDFSHA256},
|
||||
Hashes: []event.VerificationHashMethod{event.VerificationHashSHA256},
|
||||
MessageAuthenticationCodes: []event.MACMethod{event.HKDFHMACSHA256},
|
||||
ShortAuthenticationString: sasMethods,
|
||||
}
|
||||
return content, mach.sendToOneDevice(ctx, toUserID, toDeviceID, event.ToDeviceVerificationStart, content)
|
||||
}
|
||||
|
||||
// SendSASVerificationAccept is used to manually send an accept for a SAS verification process from a received m.key.verification.start event.
|
||||
func (mach *OlmMachine) SendSASVerificationAccept(ctx context.Context, fromUser id.UserID, startEvent *event.VerificationStartEventContent, publicKey []byte, methods []VerificationMethod) error {
|
||||
if startEvent.Method != event.VerificationMethodSAS {
|
||||
reason := "Unknown verification method: " + string(startEvent.Method)
|
||||
if err := mach.SendSASVerificationCancel(ctx, fromUser, startEvent.FromDevice, startEvent.TransactionID, reason, event.VerificationCancelUnknownMethod); err != nil {
|
||||
return err
|
||||
}
|
||||
return ErrUnknownVerificationMethod
|
||||
}
|
||||
payload, err := json.Marshal(startEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
canonical, err := canonicaljson.CanonicalJSON(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash := olm.NewUtility().Sha256(string(publicKey) + string(canonical))
|
||||
sasMethods := make([]event.SASMethod, len(methods))
|
||||
for i, method := range methods {
|
||||
sasMethods[i] = method.Type()
|
||||
}
|
||||
content := &event.VerificationAcceptEventContent{
|
||||
TransactionID: startEvent.TransactionID,
|
||||
Method: event.VerificationMethodSAS,
|
||||
KeyAgreementProtocol: event.KeyAgreementCurve25519HKDFSHA256,
|
||||
Hash: event.VerificationHashSHA256,
|
||||
MessageAuthenticationCode: event.HKDFHMACSHA256,
|
||||
ShortAuthenticationString: sasMethods,
|
||||
Commitment: hash,
|
||||
}
|
||||
return mach.sendToOneDevice(ctx, fromUser, startEvent.FromDevice, event.ToDeviceVerificationAccept, content)
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) callbackAndCancelSASVerification(ctx context.Context, verState *verificationState, transactionID, reason string, code event.VerificationCancelCode) error {
|
||||
go verState.hooks.OnCancel(true, reason, code)
|
||||
return mach.SendSASVerificationCancel(ctx, verState.otherDevice.UserID, verState.otherDevice.DeviceID, transactionID, reason, code)
|
||||
}
|
||||
|
||||
// SendSASVerificationKey sends the ephemeral public key for a device to the partner device.
|
||||
func (mach *OlmMachine) SendSASVerificationKey(ctx context.Context, userID id.UserID, deviceID id.DeviceID, transactionID string, key string) error {
|
||||
content := &event.VerificationKeyEventContent{
|
||||
TransactionID: transactionID,
|
||||
Key: key,
|
||||
}
|
||||
return mach.sendToOneDevice(ctx, userID, deviceID, event.ToDeviceVerificationKey, content)
|
||||
}
|
||||
|
||||
// SendSASVerificationMAC is use the MAC of a device's key to the partner device.
|
||||
func (mach *OlmMachine) SendSASVerificationMAC(ctx context.Context, userID id.UserID, deviceID id.DeviceID, transactionID string, sas *olm.SAS) error {
|
||||
keyID := id.NewKeyID(id.KeyAlgorithmEd25519, mach.Client.DeviceID.String())
|
||||
|
||||
signingKey := mach.account.SigningKey()
|
||||
keyIDsMap := map[id.KeyID]string{keyID: ""}
|
||||
macMap := make(map[id.KeyID]string)
|
||||
|
||||
if mach.CrossSigningKeys != nil {
|
||||
masterKey := mach.CrossSigningKeys.MasterKey.PublicKey
|
||||
masterKeyID := id.NewKeyID(id.KeyAlgorithmEd25519, masterKey.String())
|
||||
// add master key ID to key map
|
||||
keyIDsMap[masterKeyID] = ""
|
||||
masterKeyMAC, _, err := mach.getPKAndKeysMAC(sas, mach.Client.UserID, mach.Client.DeviceID,
|
||||
userID, deviceID, transactionID, masterKey, masterKeyID, keyIDsMap)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error generating master key MAC: %v", err)
|
||||
} else {
|
||||
mach.Log.Debug().Msgf("Generated master key `%v` MAC: %v", masterKey, masterKeyMAC)
|
||||
macMap[masterKeyID] = masterKeyMAC
|
||||
}
|
||||
}
|
||||
|
||||
pubKeyMac, keysMac, err := mach.getPKAndKeysMAC(sas, mach.Client.UserID, mach.Client.DeviceID, userID, deviceID, transactionID, signingKey, keyID, keyIDsMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mach.Log.Debug().Msgf("MAC of key %s is: %s", signingKey, pubKeyMac)
|
||||
mach.Log.Debug().Msgf("MAC of key ID(s) %s is: %s", keyID, keysMac)
|
||||
macMap[keyID] = pubKeyMac
|
||||
|
||||
content := &event.VerificationMacEventContent{
|
||||
TransactionID: transactionID,
|
||||
Keys: keysMac,
|
||||
Mac: macMap,
|
||||
}
|
||||
|
||||
return mach.sendToOneDevice(ctx, userID, deviceID, event.ToDeviceVerificationMAC, content)
|
||||
}
|
||||
|
||||
func commonSASMethods(hooks VerificationHooks, otherDeviceMethods []event.SASMethod) []VerificationMethod {
|
||||
methods := make([]VerificationMethod, 0)
|
||||
for _, hookMethod := range hooks.VerificationMethods() {
|
||||
for _, otherMethod := range otherDeviceMethods {
|
||||
if hookMethod.Type() == otherMethod {
|
||||
methods = append(methods, hookMethod)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return methods
|
||||
}
|
||||
334
vendor/maunium.net/go/mautrix/crypto/verification_in_room.go
generated
vendored
334
vendor/maunium.net/go/mautrix/crypto/verification_in_room.go
generated
vendored
@@ -1,334 +0,0 @@
|
||||
// Copyright (c) 2020 Nikos Filippakis
|
||||
//
|
||||
// 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"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoVerificationFromDevice = errors.New("from_device field is empty")
|
||||
ErrNoVerificationMethods = errors.New("verification method list is empty")
|
||||
ErrNoRelatesTo = errors.New("missing m.relates_to info")
|
||||
)
|
||||
|
||||
// ProcessInRoomVerification is a callback that is to be called when a client receives a message
|
||||
// related to in-room verification.
|
||||
//
|
||||
// Currently this is not automatically called, so you must add the listener yourself.
|
||||
// Note that in-room verification events are wrapped in m.room.encrypted, but this expects the decrypted events.
|
||||
func (mach *OlmMachine) ProcessInRoomVerification(evt *event.Event) error {
|
||||
if evt.Sender == mach.Client.UserID {
|
||||
// nothing to do if the message is our own
|
||||
return nil
|
||||
}
|
||||
if relatable, ok := evt.Content.Parsed.(event.Relatable); !ok || relatable.OptionalGetRelatesTo() == nil {
|
||||
return ErrNoRelatesTo
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
switch content := evt.Content.Parsed.(type) {
|
||||
case *event.MessageEventContent:
|
||||
if content.MsgType == event.MsgVerificationRequest {
|
||||
if content.FromDevice == "" {
|
||||
return ErrNoVerificationFromDevice
|
||||
}
|
||||
if content.Methods == nil {
|
||||
return ErrNoVerificationMethods
|
||||
}
|
||||
|
||||
newContent := &event.VerificationRequestEventContent{
|
||||
FromDevice: content.FromDevice,
|
||||
Methods: content.Methods,
|
||||
Timestamp: evt.Timestamp,
|
||||
TransactionID: evt.ID.String(),
|
||||
}
|
||||
mach.handleVerificationRequest(ctx, evt.Sender, newContent, evt.ID.String(), evt.RoomID)
|
||||
}
|
||||
case *event.VerificationStartEventContent:
|
||||
mach.handleVerificationStart(ctx, evt.Sender, content, content.RelatesTo.EventID.String(), 10*time.Minute, evt.RoomID)
|
||||
case *event.VerificationReadyEventContent:
|
||||
mach.handleInRoomVerificationReady(ctx, evt.Sender, evt.RoomID, content, content.RelatesTo.EventID.String())
|
||||
case *event.VerificationAcceptEventContent:
|
||||
mach.handleVerificationAccept(ctx, evt.Sender, content, content.RelatesTo.EventID.String())
|
||||
case *event.VerificationKeyEventContent:
|
||||
mach.handleVerificationKey(ctx, evt.Sender, content, content.RelatesTo.EventID.String())
|
||||
case *event.VerificationMacEventContent:
|
||||
mach.handleVerificationMAC(ctx, evt.Sender, content, content.RelatesTo.EventID.String())
|
||||
case *event.VerificationCancelEventContent:
|
||||
mach.handleVerificationCancel(evt.Sender, content, content.RelatesTo.EventID.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationCancel is used to manually send an in-room SAS cancel message process with the given reason and cancellation code.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationCancel(ctx context.Context, roomID id.RoomID, userID id.UserID, transactionID string, reason string, code event.VerificationCancelCode) error {
|
||||
content := &event.VerificationCancelEventContent{
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
Reason: reason,
|
||||
Code: code,
|
||||
To: userID,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(ctx, roomID, event.InRoomVerificationCancel, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encrypted)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationRequest is used to manually send an in-room SAS verification request message to another user.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationRequest(ctx context.Context, roomID id.RoomID, toUserID id.UserID, methods []VerificationMethod) (string, error) {
|
||||
content := &event.MessageEventContent{
|
||||
MsgType: event.MsgVerificationRequest,
|
||||
FromDevice: mach.Client.DeviceID,
|
||||
Methods: []event.VerificationMethod{event.VerificationMethodSAS},
|
||||
To: toUserID,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(ctx, roomID, event.EventMessage, content)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp, err := mach.Client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encrypted)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return resp.EventID.String(), nil
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationReady is used to manually send an in-room SAS verification ready message to another user.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationReady(ctx context.Context, roomID id.RoomID, transactionID string) error {
|
||||
content := &event.VerificationReadyEventContent{
|
||||
FromDevice: mach.Client.DeviceID,
|
||||
Methods: []event.VerificationMethod{event.VerificationMethodSAS},
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(ctx, roomID, event.InRoomVerificationReady, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encrypted)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationStart is used to manually send the in-room SAS verification start message to another user.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationStart(ctx context.Context, roomID id.RoomID, toUserID id.UserID, transactionID string, methods []VerificationMethod) (*event.VerificationStartEventContent, error) {
|
||||
sasMethods := make([]event.SASMethod, len(methods))
|
||||
for i, method := range methods {
|
||||
sasMethods[i] = method.Type()
|
||||
}
|
||||
content := &event.VerificationStartEventContent{
|
||||
FromDevice: mach.Client.DeviceID,
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
Method: event.VerificationMethodSAS,
|
||||
KeyAgreementProtocols: []event.KeyAgreementProtocol{event.KeyAgreementCurve25519HKDFSHA256},
|
||||
Hashes: []event.VerificationHashMethod{event.VerificationHashSHA256},
|
||||
MessageAuthenticationCodes: []event.MACMethod{event.HKDFHMACSHA256},
|
||||
ShortAuthenticationString: sasMethods,
|
||||
To: toUserID,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(ctx, roomID, event.InRoomVerificationStart, content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encrypted)
|
||||
return content, err
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationAccept is used to manually send an accept for an in-room SAS verification process from a received m.key.verification.start event.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationAccept(ctx context.Context, roomID id.RoomID, fromUser id.UserID, startEvent *event.VerificationStartEventContent, transactionID string, publicKey []byte, methods []VerificationMethod) error {
|
||||
if startEvent.Method != event.VerificationMethodSAS {
|
||||
reason := "Unknown verification method: " + string(startEvent.Method)
|
||||
if err := mach.SendInRoomSASVerificationCancel(ctx, roomID, fromUser, transactionID, reason, event.VerificationCancelUnknownMethod); err != nil {
|
||||
return err
|
||||
}
|
||||
return ErrUnknownVerificationMethod
|
||||
}
|
||||
payload, err := json.Marshal(startEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
canonical, err := canonicaljson.CanonicalJSON(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash := olm.NewUtility().Sha256(string(publicKey) + string(canonical))
|
||||
sasMethods := make([]event.SASMethod, len(methods))
|
||||
for i, method := range methods {
|
||||
sasMethods[i] = method.Type()
|
||||
}
|
||||
content := &event.VerificationAcceptEventContent{
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
Method: event.VerificationMethodSAS,
|
||||
KeyAgreementProtocol: event.KeyAgreementCurve25519HKDFSHA256,
|
||||
Hash: event.VerificationHashSHA256,
|
||||
MessageAuthenticationCode: event.HKDFHMACSHA256,
|
||||
ShortAuthenticationString: sasMethods,
|
||||
Commitment: hash,
|
||||
To: fromUser,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(ctx, roomID, event.InRoomVerificationAccept, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encrypted)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationKey sends the ephemeral public key for a device to the partner device for an in-room verification.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationKey(ctx context.Context, roomID id.RoomID, userID id.UserID, transactionID string, key string) error {
|
||||
content := &event.VerificationKeyEventContent{
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
Key: key,
|
||||
To: userID,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(ctx, roomID, event.InRoomVerificationKey, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encrypted)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationMAC sends the MAC of a device's key to the partner device for an in-room verification.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationMAC(ctx context.Context, roomID id.RoomID, userID id.UserID, deviceID id.DeviceID, transactionID string, sas *olm.SAS) error {
|
||||
keyID := id.NewKeyID(id.KeyAlgorithmEd25519, mach.Client.DeviceID.String())
|
||||
|
||||
signingKey := mach.account.SigningKey()
|
||||
keyIDsMap := map[id.KeyID]string{keyID: ""}
|
||||
macMap := make(map[id.KeyID]string)
|
||||
|
||||
if mach.CrossSigningKeys != nil {
|
||||
masterKey := mach.CrossSigningKeys.MasterKey.PublicKey
|
||||
masterKeyID := id.NewKeyID(id.KeyAlgorithmEd25519, masterKey.String())
|
||||
// add master key ID to key map
|
||||
keyIDsMap[masterKeyID] = ""
|
||||
masterKeyMAC, _, err := mach.getPKAndKeysMAC(sas, mach.Client.UserID, mach.Client.DeviceID,
|
||||
userID, deviceID, transactionID, masterKey, masterKeyID, keyIDsMap)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error generating master key MAC: %v", err)
|
||||
} else {
|
||||
mach.Log.Debug().Msgf("Generated master key `%v` MAC: %v", masterKey, masterKeyMAC)
|
||||
macMap[masterKeyID] = masterKeyMAC
|
||||
}
|
||||
}
|
||||
|
||||
pubKeyMac, keysMac, err := mach.getPKAndKeysMAC(sas, mach.Client.UserID, mach.Client.DeviceID, userID, deviceID, transactionID, signingKey, keyID, keyIDsMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mach.Log.Debug().Msgf("MAC of key %s is: %s", signingKey, pubKeyMac)
|
||||
mach.Log.Debug().Msgf("MAC of key ID(s) %s is: %s", keyID, keysMac)
|
||||
macMap[keyID] = pubKeyMac
|
||||
|
||||
content := &event.VerificationMacEventContent{
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
Keys: keysMac,
|
||||
Mac: macMap,
|
||||
To: userID,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(ctx, roomID, event.InRoomVerificationMAC, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encrypted)
|
||||
return err
|
||||
}
|
||||
|
||||
// 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(ctx context.Context, inRoomID id.RoomID, userID id.UserID, hooks VerificationHooks, timeout time.Duration) (string, error) {
|
||||
return mach.newInRoomSASVerificationWithInner(ctx, inRoomID, &id.Device{UserID: userID}, hooks, "", timeout)
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) newInRoomSASVerificationWithInner(ctx context.Context, inRoomID id.RoomID, device *id.Device, hooks VerificationHooks, transactionID string, timeout time.Duration) (string, error) {
|
||||
mach.Log.Debug().Msgf("Starting new in-room verification transaction user %v", device.UserID)
|
||||
|
||||
request := transactionID == ""
|
||||
if request {
|
||||
var err error
|
||||
// get new transaction ID from the request message event ID
|
||||
transactionID, err = mach.SendInRoomSASVerificationRequest(ctx, inRoomID, device.UserID, hooks.VerificationMethods())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
verState := &verificationState{
|
||||
sas: olm.NewSAS(),
|
||||
otherDevice: device,
|
||||
initiatedByUs: true,
|
||||
verificationStarted: false,
|
||||
keyReceived: false,
|
||||
sasMatched: make(chan bool, 1),
|
||||
hooks: hooks,
|
||||
inRoomID: inRoomID,
|
||||
}
|
||||
verState.lock.Lock()
|
||||
defer verState.lock.Unlock()
|
||||
|
||||
if !request {
|
||||
// start in-room verification
|
||||
startEvent, err := mach.SendInRoomSASVerificationStart(ctx, inRoomID, device.UserID, transactionID, hooks.VerificationMethods())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(startEvent)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
canonical, err := canonicaljson.CanonicalJSON(payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
verState.startEventCanonical = string(canonical)
|
||||
}
|
||||
|
||||
mach.keyVerificationTransactionState.Store(device.UserID.String()+":"+transactionID, verState)
|
||||
|
||||
mach.timeoutAfter(ctx, verState, transactionID, timeout)
|
||||
|
||||
return transactionID, nil
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) handleInRoomVerificationReady(ctx context.Context, userID id.UserID, roomID id.RoomID, content *event.VerificationReadyEventContent, transactionID string) {
|
||||
device, err := mach.GetOrFetchDevice(ctx, userID, content.FromDevice)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error fetching device %v of user %v: %v", content.FromDevice, userID, err)
|
||||
return
|
||||
}
|
||||
|
||||
verState, err := mach.getTransactionState(ctx, transactionID, userID)
|
||||
if err != nil {
|
||||
mach.Log.Error().Msgf("Error getting transaction state: %v", err)
|
||||
return
|
||||
}
|
||||
//mach.keyVerificationTransactionState.Delete(userID.String() + ":" + transactionID)
|
||||
|
||||
if mach.Client.UserID < userID {
|
||||
// up to us to send the start message
|
||||
verState.lock.Lock()
|
||||
mach.newInRoomSASVerificationWithInner(ctx, roomID, device, verState.hooks, transactionID, 10*time.Minute)
|
||||
verState.lock.Unlock()
|
||||
}
|
||||
}
|
||||
201
vendor/maunium.net/go/mautrix/crypto/verification_sas_methods.go
generated
vendored
201
vendor/maunium.net/go/mautrix/crypto/verification_sas_methods.go
generated
vendored
@@ -1,201 +0,0 @@
|
||||
// Copyright (c) 2020 Nikos Filippakis
|
||||
//
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// SASData contains the data that users need to verify.
|
||||
type SASData interface {
|
||||
Type() event.SASMethod
|
||||
}
|
||||
|
||||
// VerificationMethod describes a method for generating a SAS.
|
||||
type VerificationMethod interface {
|
||||
// GetVerificationSAS uses the user, device ID and key of the user who initiated the verification transaction,
|
||||
// the user, device ID and key of the user who accepted, the transaction ID and the SAS object to generate a SAS.
|
||||
// The SAS can be any type, such as an array of numbers or emojis.
|
||||
GetVerificationSAS(initUserID id.UserID, initDeviceID id.DeviceID, initKey string,
|
||||
acceptUserID id.UserID, acceptDeviceID id.DeviceID, acceptKey string,
|
||||
transactionID string, sas *olm.SAS) (SASData, error)
|
||||
// Type returns the type of this SAS method
|
||||
Type() event.SASMethod
|
||||
}
|
||||
|
||||
const sasInfoFormat = "MATRIX_KEY_VERIFICATION_SAS|%s|%s|%s|%s|%s|%s|%s"
|
||||
|
||||
// VerificationMethodDecimal describes the decimal SAS method.
|
||||
type VerificationMethodDecimal struct{}
|
||||
|
||||
// DecimalSASData contains the verification numbers for the decimal SAS method.
|
||||
type DecimalSASData [3]uint
|
||||
|
||||
// Type returns the decimal SAS method type.
|
||||
func (DecimalSASData) Type() event.SASMethod {
|
||||
return event.SASDecimal
|
||||
}
|
||||
|
||||
// GetVerificationSAS generates the three numbers that need to match with the other device for a verification to be valid.
|
||||
func (VerificationMethodDecimal) GetVerificationSAS(initUserID id.UserID, initDeviceID id.DeviceID, initKey string,
|
||||
acceptUserID id.UserID, acceptDeviceID id.DeviceID, acceptKey string,
|
||||
transactionID string, sas *olm.SAS) (SASData, error) {
|
||||
|
||||
sasInfo := fmt.Sprintf(sasInfoFormat,
|
||||
initUserID, initDeviceID, initKey,
|
||||
acceptUserID, acceptDeviceID, acceptKey,
|
||||
transactionID)
|
||||
|
||||
sasBytes, err := sas.GenerateBytes([]byte(sasInfo), 5)
|
||||
if err != nil {
|
||||
return DecimalSASData{0, 0, 0}, err
|
||||
}
|
||||
|
||||
numbers := DecimalSASData{
|
||||
(uint(sasBytes[0])<<5 | uint(sasBytes[1])>>3) + 1000,
|
||||
(uint(sasBytes[1]&0x7)<<10 | uint(sasBytes[2])<<2 | uint(sasBytes[3]>>6)) + 1000,
|
||||
(uint(sasBytes[3]&0x3F)<<7 | uint(sasBytes[4])>>1) + 1000,
|
||||
}
|
||||
|
||||
return numbers, nil
|
||||
}
|
||||
|
||||
// Type returns the decimal SAS method type.
|
||||
func (VerificationMethodDecimal) Type() event.SASMethod {
|
||||
return event.SASDecimal
|
||||
}
|
||||
|
||||
var allEmojis = [...]VerificationEmoji{
|
||||
{'🐶', "Dog"},
|
||||
{'🐱', "Cat"},
|
||||
{'🦁', "Lion"},
|
||||
{'🐎', "Horse"},
|
||||
{'🦄', "Unicorn"},
|
||||
{'🐷', "Pig"},
|
||||
{'🐘', "Elephant"},
|
||||
{'🐰', "Rabbit"},
|
||||
{'🐼', "Panda"},
|
||||
{'🐓', "Rooster"},
|
||||
{'🐧', "Penguin"},
|
||||
{'🐢', "Turtle"},
|
||||
{'🐟', "Fish"},
|
||||
{'🐙', "Octopus"},
|
||||
{'🦋', "Butterfly"},
|
||||
{'🌷', "Flower"},
|
||||
{'🌳', "Tree"},
|
||||
{'🌵', "Cactus"},
|
||||
{'🍄', "Mushroom"},
|
||||
{'🌏', "Globe"},
|
||||
{'🌙', "Moon"},
|
||||
{'☁', "Cloud"},
|
||||
{'🔥', "Fire"},
|
||||
{'🍌', "Banana"},
|
||||
{'🍎', "Apple"},
|
||||
{'🍓', "Strawberry"},
|
||||
{'🌽', "Corn"},
|
||||
{'🍕', "Pizza"},
|
||||
{'🎂', "Cake"},
|
||||
{'❤', "Heart"},
|
||||
{'😀', "Smiley"},
|
||||
{'🤖', "Robot"},
|
||||
{'🎩', "Hat"},
|
||||
{'👓', "Glasses"},
|
||||
{'🔧', "Spanner"},
|
||||
{'🎅', "Santa"},
|
||||
{'👍', "Thumbs Up"},
|
||||
{'☂', "Umbrella"},
|
||||
{'⌛', "Hourglass"},
|
||||
{'⏰', "Clock"},
|
||||
{'🎁', "Gift"},
|
||||
{'💡', "Light Bulb"},
|
||||
{'📕', "Book"},
|
||||
{'✏', "Pencil"},
|
||||
{'📎', "Paperclip"},
|
||||
{'✂', "Scissors"},
|
||||
{'🔒', "Lock"},
|
||||
{'🔑', "Key"},
|
||||
{'🔨', "Hammer"},
|
||||
{'☎', "Telephone"},
|
||||
{'🏁', "Flag"},
|
||||
{'🚂', "Train"},
|
||||
{'🚲', "Bicycle"},
|
||||
{'✈', "Aeroplane"},
|
||||
{'🚀', "Rocket"},
|
||||
{'🏆', "Trophy"},
|
||||
{'⚽', "Ball"},
|
||||
{'🎸', "Guitar"},
|
||||
{'🎺', "Trumpet"},
|
||||
{'🔔', "Bell"},
|
||||
{'⚓', "Anchor"},
|
||||
{'🎧', "Headphones"},
|
||||
{'📁', "Folder"},
|
||||
{'📌', "Pin"},
|
||||
}
|
||||
|
||||
// VerificationEmoji describes an emoji that might be sent for verifying devices.
|
||||
type VerificationEmoji struct {
|
||||
Emoji rune
|
||||
Description string
|
||||
}
|
||||
|
||||
func (vm VerificationEmoji) GetEmoji() rune {
|
||||
return vm.Emoji
|
||||
}
|
||||
|
||||
func (vm VerificationEmoji) GetDescription() string {
|
||||
return vm.Description
|
||||
}
|
||||
|
||||
// EmojiSASData contains the verification emojis for the emoji SAS method.
|
||||
type EmojiSASData [7]VerificationEmoji
|
||||
|
||||
// Type returns the emoji SAS method type.
|
||||
func (EmojiSASData) Type() event.SASMethod {
|
||||
return event.SASEmoji
|
||||
}
|
||||
|
||||
// VerificationMethodEmoji describes the emoji SAS method.
|
||||
type VerificationMethodEmoji struct{}
|
||||
|
||||
// GetVerificationSAS generates the three numbers that need to match with the other device for a verification to be valid.
|
||||
func (VerificationMethodEmoji) GetVerificationSAS(initUserID id.UserID, initDeviceID id.DeviceID, initKey string,
|
||||
acceptUserID id.UserID, acceptDeviceID id.DeviceID, acceptKey string,
|
||||
transactionID string, sas *olm.SAS) (SASData, error) {
|
||||
|
||||
sasInfo := fmt.Sprintf(sasInfoFormat,
|
||||
initUserID, initDeviceID, initKey,
|
||||
acceptUserID, acceptDeviceID, acceptKey,
|
||||
transactionID)
|
||||
|
||||
var emojis EmojiSASData
|
||||
sasBytes, err := sas.GenerateBytes([]byte(sasInfo), 6)
|
||||
|
||||
if err != nil {
|
||||
return emojis, err
|
||||
}
|
||||
|
||||
sasNum := uint64(sasBytes[0])<<40 | uint64(sasBytes[1])<<32 | uint64(sasBytes[2])<<24 |
|
||||
uint64(sasBytes[3])<<16 | uint64(sasBytes[4])<<8 | uint64(sasBytes[5])
|
||||
|
||||
for i := 0; i < len(emojis); i++ {
|
||||
// take nth group of 6 bits
|
||||
emojiIdx := (sasNum >> uint(48-(i+1)*6)) & 0x3F
|
||||
emoji := allEmojis[emojiIdx]
|
||||
emojis[i] = emoji
|
||||
}
|
||||
|
||||
return emojis, nil
|
||||
}
|
||||
|
||||
// Type returns the emoji SAS method type.
|
||||
func (VerificationMethodEmoji) Type() event.SASMethod {
|
||||
return event.SASEmoji
|
||||
}
|
||||
24
vendor/maunium.net/go/mautrix/event/beeper.go
generated
vendored
24
vendor/maunium.net/go/mautrix/event/beeper.go
generated
vendored
@@ -61,3 +61,27 @@ type BeeperRoomKeyAckEventContent struct {
|
||||
SessionID id.SessionID `json:"session_id"`
|
||||
FirstMessageIndex int `json:"first_message_index"`
|
||||
}
|
||||
|
||||
type LinkPreview struct {
|
||||
CanonicalURL string `json:"og:url,omitempty"`
|
||||
Title string `json:"og:title,omitempty"`
|
||||
Type string `json:"og:type,omitempty"`
|
||||
Description string `json:"og:description,omitempty"`
|
||||
|
||||
ImageURL id.ContentURIString `json:"og:image,omitempty"`
|
||||
|
||||
ImageSize int `json:"matrix:image:size,omitempty"`
|
||||
ImageWidth int `json:"og:image:width,omitempty"`
|
||||
ImageHeight int `json:"og:image:height,omitempty"`
|
||||
ImageType string `json:"og:image:type,omitempty"`
|
||||
}
|
||||
|
||||
// BeeperLinkPreview contains the data for a bundled URL preview as specified in MSC4095
|
||||
//
|
||||
// https://github.com/matrix-org/matrix-spec-proposals/pull/4095
|
||||
type BeeperLinkPreview struct {
|
||||
LinkPreview
|
||||
|
||||
MatchedURL string `json:"matched_url,omitempty"`
|
||||
ImageEncryption *EncryptedFileInfo `json:"beeper:image:encryption,omitempty"`
|
||||
}
|
||||
|
||||
79
vendor/maunium.net/go/mautrix/event/content.go
generated
vendored
79
vendor/maunium.net/go/mautrix/event/content.go
generated
vendored
@@ -57,26 +57,33 @@ var TypeMap = map[Type]reflect.Type{
|
||||
EphemeralEventReceipt: reflect.TypeOf(ReceiptEventContent{}),
|
||||
EphemeralEventPresence: reflect.TypeOf(PresenceEventContent{}),
|
||||
|
||||
InRoomVerificationStart: reflect.TypeOf(VerificationStartEventContent{}),
|
||||
InRoomVerificationReady: reflect.TypeOf(VerificationReadyEventContent{}),
|
||||
InRoomVerificationStart: reflect.TypeOf(VerificationStartEventContent{}),
|
||||
InRoomVerificationDone: reflect.TypeOf(VerificationDoneEventContent{}),
|
||||
InRoomVerificationCancel: reflect.TypeOf(VerificationCancelEventContent{}),
|
||||
|
||||
InRoomVerificationAccept: reflect.TypeOf(VerificationAcceptEventContent{}),
|
||||
InRoomVerificationKey: reflect.TypeOf(VerificationKeyEventContent{}),
|
||||
InRoomVerificationMAC: reflect.TypeOf(VerificationMacEventContent{}),
|
||||
InRoomVerificationCancel: reflect.TypeOf(VerificationCancelEventContent{}),
|
||||
InRoomVerificationMAC: reflect.TypeOf(VerificationMACEventContent{}),
|
||||
|
||||
ToDeviceRoomKey: reflect.TypeOf(RoomKeyEventContent{}),
|
||||
ToDeviceForwardedRoomKey: reflect.TypeOf(ForwardedRoomKeyEventContent{}),
|
||||
ToDeviceRoomKeyRequest: reflect.TypeOf(RoomKeyRequestEventContent{}),
|
||||
ToDeviceEncrypted: reflect.TypeOf(EncryptedEventContent{}),
|
||||
ToDeviceRoomKeyWithheld: reflect.TypeOf(RoomKeyWithheldEventContent{}),
|
||||
ToDeviceSecretRequest: reflect.TypeOf(SecretRequestEventContent{}),
|
||||
ToDeviceSecretSend: reflect.TypeOf(SecretSendEventContent{}),
|
||||
ToDeviceDummy: reflect.TypeOf(DummyEventContent{}),
|
||||
|
||||
ToDeviceVerificationStart: reflect.TypeOf(VerificationStartEventContent{}),
|
||||
ToDeviceVerificationAccept: reflect.TypeOf(VerificationAcceptEventContent{}),
|
||||
ToDeviceVerificationKey: reflect.TypeOf(VerificationKeyEventContent{}),
|
||||
ToDeviceVerificationMAC: reflect.TypeOf(VerificationMacEventContent{}),
|
||||
ToDeviceVerificationCancel: reflect.TypeOf(VerificationCancelEventContent{}),
|
||||
ToDeviceVerificationRequest: reflect.TypeOf(VerificationRequestEventContent{}),
|
||||
ToDeviceVerificationReady: reflect.TypeOf(VerificationReadyEventContent{}),
|
||||
ToDeviceVerificationStart: reflect.TypeOf(VerificationStartEventContent{}),
|
||||
ToDeviceVerificationDone: reflect.TypeOf(VerificationDoneEventContent{}),
|
||||
ToDeviceVerificationCancel: reflect.TypeOf(VerificationCancelEventContent{}),
|
||||
|
||||
ToDeviceVerificationAccept: reflect.TypeOf(VerificationAcceptEventContent{}),
|
||||
ToDeviceVerificationKey: reflect.TypeOf(VerificationKeyEventContent{}),
|
||||
ToDeviceVerificationMAC: reflect.TypeOf(VerificationMACEventContent{}),
|
||||
|
||||
ToDeviceOrgMatrixRoomKeyWithheld: reflect.TypeOf(RoomKeyWithheldEventContent{}),
|
||||
|
||||
@@ -506,3 +513,59 @@ func (content *Content) AsModPolicy() *ModPolicyContent {
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsVerificationRequest() *VerificationRequestEventContent {
|
||||
casted, ok := content.Parsed.(*VerificationRequestEventContent)
|
||||
if !ok {
|
||||
return &VerificationRequestEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsVerificationReady() *VerificationReadyEventContent {
|
||||
casted, ok := content.Parsed.(*VerificationReadyEventContent)
|
||||
if !ok {
|
||||
return &VerificationReadyEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsVerificationStart() *VerificationStartEventContent {
|
||||
casted, ok := content.Parsed.(*VerificationStartEventContent)
|
||||
if !ok {
|
||||
return &VerificationStartEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsVerificationDone() *VerificationDoneEventContent {
|
||||
casted, ok := content.Parsed.(*VerificationDoneEventContent)
|
||||
if !ok {
|
||||
return &VerificationDoneEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsVerificationCancel() *VerificationCancelEventContent {
|
||||
casted, ok := content.Parsed.(*VerificationCancelEventContent)
|
||||
if !ok {
|
||||
return &VerificationCancelEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsVerificationAccept() *VerificationAcceptEventContent {
|
||||
casted, ok := content.Parsed.(*VerificationAcceptEventContent)
|
||||
if !ok {
|
||||
return &VerificationAcceptEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsVerificationKey() *VerificationKeyEventContent {
|
||||
casted, ok := content.Parsed.(*VerificationKeyEventContent)
|
||||
if !ok {
|
||||
return &VerificationKeyEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsVerificationMAC() *VerificationMACEventContent {
|
||||
casted, ok := content.Parsed.(*VerificationMACEventContent)
|
||||
if !ok {
|
||||
return &VerificationMACEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
|
||||
23
vendor/maunium.net/go/mautrix/event/encryption.go
generated
vendored
23
vendor/maunium.net/go/mautrix/event/encryption.go
generated
vendored
@@ -176,4 +176,27 @@ func (withheld *RoomKeyWithheldEventContent) Is(other error) bool {
|
||||
return withheld.Code == "" || otherWithheld.Code == "" || withheld.Code == otherWithheld.Code
|
||||
}
|
||||
|
||||
type SecretRequestAction string
|
||||
|
||||
func (a SecretRequestAction) String() string {
|
||||
return string(a)
|
||||
}
|
||||
|
||||
const (
|
||||
SecretRequestRequest = "request"
|
||||
SecretRequestCancellation = "request_cancellation"
|
||||
)
|
||||
|
||||
type SecretRequestEventContent struct {
|
||||
Name id.Secret `json:"name,omitempty"`
|
||||
Action SecretRequestAction `json:"action"`
|
||||
RequestingDeviceID id.DeviceID `json:"requesting_device_id"`
|
||||
RequestID string `json:"request_id"`
|
||||
}
|
||||
|
||||
type SecretSendEventContent struct {
|
||||
RequestID string `json:"request_id"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
type DummyEventContent struct{}
|
||||
|
||||
2
vendor/maunium.net/go/mautrix/event/message.go
generated
vendored
2
vendor/maunium.net/go/mautrix/event/message.go
generated
vendored
@@ -116,6 +116,8 @@ type MessageEventContent struct {
|
||||
BeeperGalleryImages []*MessageEventContent `json:"com.beeper.gallery.images,omitempty"`
|
||||
BeeperGalleryCaption string `json:"com.beeper.gallery.caption,omitempty"`
|
||||
BeeperGalleryCaptionHTML string `json:"com.beeper.gallery.caption_html,omitempty"`
|
||||
|
||||
BeeperLinkPreviews []*BeeperLinkPreview `json:"com.beeper.linkpreviews,omitempty"`
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) GetRelatesTo() *RelatesTo {
|
||||
|
||||
44
vendor/maunium.net/go/mautrix/event/type.go
generated
vendored
44
vendor/maunium.net/go/mautrix/event/type.go
generated
vendored
@@ -10,6 +10,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type RoomType string
|
||||
@@ -116,7 +118,8 @@ func (et *Type) GuessClass() TypeClass {
|
||||
return EphemeralEventType
|
||||
case AccountDataDirectChats.Type, AccountDataPushRules.Type, AccountDataRoomTags.Type,
|
||||
AccountDataSecretStorageKey.Type, AccountDataSecretStorageDefaultKey.Type,
|
||||
AccountDataCrossSigningMaster.Type, AccountDataCrossSigningSelf.Type, AccountDataCrossSigningUser.Type:
|
||||
AccountDataCrossSigningMaster.Type, AccountDataCrossSigningSelf.Type, AccountDataCrossSigningUser.Type,
|
||||
AccountDataFullyRead.Type, AccountDataMegolmBackupKey.Type:
|
||||
return AccountDataEventType
|
||||
case EventRedaction.Type, EventMessage.Type, EventEncrypted.Type, EventReaction.Type, EventSticker.Type,
|
||||
InRoomVerificationStart.Type, InRoomVerificationReady.Type, InRoomVerificationAccept.Type,
|
||||
@@ -200,12 +203,15 @@ var (
|
||||
EventReaction = Type{"m.reaction", MessageEventType}
|
||||
EventSticker = Type{"m.sticker", MessageEventType}
|
||||
|
||||
InRoomVerificationStart = Type{"m.key.verification.start", MessageEventType}
|
||||
InRoomVerificationReady = Type{"m.key.verification.ready", MessageEventType}
|
||||
InRoomVerificationStart = Type{"m.key.verification.start", MessageEventType}
|
||||
InRoomVerificationDone = Type{"m.key.verification.done", MessageEventType}
|
||||
InRoomVerificationCancel = Type{"m.key.verification.cancel", MessageEventType}
|
||||
|
||||
// SAS Verification Events
|
||||
InRoomVerificationAccept = Type{"m.key.verification.accept", MessageEventType}
|
||||
InRoomVerificationKey = Type{"m.key.verification.key", MessageEventType}
|
||||
InRoomVerificationMAC = Type{"m.key.verification.mac", MessageEventType}
|
||||
InRoomVerificationCancel = Type{"m.key.verification.cancel", MessageEventType}
|
||||
|
||||
CallInvite = Type{"m.call.invite", MessageEventType}
|
||||
CallCandidates = Type{"m.call.candidates", MessageEventType}
|
||||
@@ -235,26 +241,34 @@ var (
|
||||
|
||||
AccountDataSecretStorageDefaultKey = Type{"m.secret_storage.default_key", AccountDataEventType}
|
||||
AccountDataSecretStorageKey = Type{"m.secret_storage.key", AccountDataEventType}
|
||||
AccountDataCrossSigningMaster = Type{"m.cross_signing.master", AccountDataEventType}
|
||||
AccountDataCrossSigningUser = Type{"m.cross_signing.user_signing", AccountDataEventType}
|
||||
AccountDataCrossSigningSelf = Type{"m.cross_signing.self_signing", AccountDataEventType}
|
||||
AccountDataCrossSigningMaster = Type{string(id.SecretXSMaster), AccountDataEventType}
|
||||
AccountDataCrossSigningUser = Type{string(id.SecretXSUserSigning), AccountDataEventType}
|
||||
AccountDataCrossSigningSelf = Type{string(id.SecretXSSelfSigning), AccountDataEventType}
|
||||
AccountDataMegolmBackupKey = Type{"m.megolm_backup.v1", AccountDataEventType}
|
||||
)
|
||||
|
||||
// Device-to-device events
|
||||
var (
|
||||
ToDeviceRoomKey = Type{"m.room_key", ToDeviceEventType}
|
||||
ToDeviceRoomKeyRequest = Type{"m.room_key_request", ToDeviceEventType}
|
||||
ToDeviceForwardedRoomKey = Type{"m.forwarded_room_key", ToDeviceEventType}
|
||||
ToDeviceEncrypted = Type{"m.room.encrypted", ToDeviceEventType}
|
||||
ToDeviceRoomKeyWithheld = Type{"m.room_key.withheld", ToDeviceEventType}
|
||||
ToDeviceDummy = Type{"m.dummy", ToDeviceEventType}
|
||||
ToDeviceRoomKey = Type{"m.room_key", ToDeviceEventType}
|
||||
ToDeviceRoomKeyRequest = Type{"m.room_key_request", ToDeviceEventType}
|
||||
ToDeviceForwardedRoomKey = Type{"m.forwarded_room_key", ToDeviceEventType}
|
||||
ToDeviceEncrypted = Type{"m.room.encrypted", ToDeviceEventType}
|
||||
ToDeviceRoomKeyWithheld = Type{"m.room_key.withheld", ToDeviceEventType}
|
||||
ToDeviceSecretRequest = Type{"m.secret.request", ToDeviceEventType}
|
||||
ToDeviceSecretSend = Type{"m.secret.send", ToDeviceEventType}
|
||||
ToDeviceDummy = Type{"m.dummy", ToDeviceEventType}
|
||||
|
||||
ToDeviceVerificationRequest = Type{"m.key.verification.request", ToDeviceEventType}
|
||||
ToDeviceVerificationReady = Type{"m.key.verification.ready", ToDeviceEventType}
|
||||
ToDeviceVerificationStart = Type{"m.key.verification.start", ToDeviceEventType}
|
||||
ToDeviceVerificationAccept = Type{"m.key.verification.accept", ToDeviceEventType}
|
||||
ToDeviceVerificationKey = Type{"m.key.verification.key", ToDeviceEventType}
|
||||
ToDeviceVerificationMAC = Type{"m.key.verification.mac", ToDeviceEventType}
|
||||
ToDeviceVerificationDone = Type{"m.key.verification.done", ToDeviceEventType}
|
||||
ToDeviceVerificationCancel = Type{"m.key.verification.cancel", ToDeviceEventType}
|
||||
|
||||
// SAS Verification Events
|
||||
ToDeviceVerificationAccept = Type{"m.key.verification.accept", ToDeviceEventType}
|
||||
ToDeviceVerificationKey = Type{"m.key.verification.key", ToDeviceEventType}
|
||||
ToDeviceVerificationMAC = Type{"m.key.verification.mac", ToDeviceEventType}
|
||||
|
||||
ToDeviceOrgMatrixRoomKeyWithheld = Type{"org.matrix.room_key.withheld", ToDeviceEventType}
|
||||
|
||||
ToDeviceBeeperRoomKeyAck = Type{"com.beeper.room_key.ack", ToDeviceEventType}
|
||||
|
||||
491
vendor/maunium.net/go/mautrix/event/verification.go
generated
vendored
491
vendor/maunium.net/go/mautrix/event/verification.go
generated
vendored
@@ -7,301 +7,298 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"go.mau.fi/util/jsonbytes"
|
||||
"go.mau.fi/util/jsontime"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type VerificationMethod string
|
||||
|
||||
const VerificationMethodSAS VerificationMethod = "m.sas.v1"
|
||||
const (
|
||||
VerificationMethodSAS VerificationMethod = "m.sas.v1"
|
||||
|
||||
// VerificationRequestEventContent represents the content of a m.key.verification.request to_device event.
|
||||
// https://spec.matrix.org/v1.2/client-server-api/#mkeyverificationrequest
|
||||
type VerificationRequestEventContent struct {
|
||||
// The device ID which is initiating the request.
|
||||
FromDevice id.DeviceID `json:"from_device"`
|
||||
// An opaque identifier for the verification request. Must be unique with respect to the devices involved.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// The verification methods supported by the sender.
|
||||
Methods []VerificationMethod `json:"methods"`
|
||||
// The POSIX timestamp in milliseconds for when the request was made.
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
VerificationMethodReciprocate VerificationMethod = "m.reciprocate.v1"
|
||||
VerificationMethodQRCodeShow VerificationMethod = "m.qr_code.show.v1"
|
||||
VerificationMethodQRCodeScan VerificationMethod = "m.qr_code.scan.v1"
|
||||
)
|
||||
|
||||
type VerificationTransactionable interface {
|
||||
GetTransactionID() id.VerificationTransactionID
|
||||
SetTransactionID(id.VerificationTransactionID)
|
||||
}
|
||||
|
||||
// ToDeviceVerificationEvent contains the fields common to all to-device
|
||||
// verification events.
|
||||
type ToDeviceVerificationEvent struct {
|
||||
// TransactionID is an opaque identifier for the verification request. Must
|
||||
// be unique with respect to the devices involved.
|
||||
TransactionID id.VerificationTransactionID `json:"transaction_id,omitempty"`
|
||||
}
|
||||
|
||||
var _ VerificationTransactionable = (*ToDeviceVerificationEvent)(nil)
|
||||
|
||||
func (ve *ToDeviceVerificationEvent) GetTransactionID() id.VerificationTransactionID {
|
||||
return ve.TransactionID
|
||||
}
|
||||
|
||||
func (ve *ToDeviceVerificationEvent) SetTransactionID(id id.VerificationTransactionID) {
|
||||
ve.TransactionID = id
|
||||
}
|
||||
|
||||
// InRoomVerificationEvent contains the fields common to all in-room
|
||||
// verification events.
|
||||
type InRoomVerificationEvent struct {
|
||||
// RelatesTo indicates the m.key.verification.request that this message is
|
||||
// related to. Note that for encrypted messages, this property should be in
|
||||
// the unencrypted portion of the event.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vrec *VerificationRequestEventContent) SupportsVerificationMethod(meth VerificationMethod) bool {
|
||||
for _, supportedMeth := range vrec.Methods {
|
||||
if supportedMeth == meth {
|
||||
return true
|
||||
}
|
||||
var _ Relatable = (*InRoomVerificationEvent)(nil)
|
||||
|
||||
func (ve *InRoomVerificationEvent) GetRelatesTo() *RelatesTo {
|
||||
if ve.RelatesTo == nil {
|
||||
ve.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return false
|
||||
return ve.RelatesTo
|
||||
}
|
||||
|
||||
func (ve *InRoomVerificationEvent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return ve.RelatesTo
|
||||
}
|
||||
|
||||
func (ve *InRoomVerificationEvent) SetRelatesTo(rel *RelatesTo) {
|
||||
ve.RelatesTo = rel
|
||||
}
|
||||
|
||||
// VerificationRequestEventContent represents the content of an
|
||||
// [m.key.verification.request] to-device event as described in [Section
|
||||
// 11.12.2.1] of the Spec.
|
||||
//
|
||||
// For the in-room version, use a standard [MessageEventContent] struct.
|
||||
//
|
||||
// [m.key.verification.request]: https://spec.matrix.org/v1.9/client-server-api/#mkeyverificationrequest
|
||||
// [Section 11.12.2.1]: https://spec.matrix.org/v1.9/client-server-api/#key-verification-framework
|
||||
type VerificationRequestEventContent struct {
|
||||
ToDeviceVerificationEvent
|
||||
// FromDevice is the device ID which is initiating the request.
|
||||
FromDevice id.DeviceID `json:"from_device"`
|
||||
// Methods is a list of the verification methods supported by the sender.
|
||||
Methods []VerificationMethod `json:"methods"`
|
||||
// Timestamp is the time at which the request was made.
|
||||
Timestamp jsontime.UnixMilli `json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
// VerificationRequestEventContentFromMessage converts an in-room verification
|
||||
// request message event to a [VerificationRequestEventContent].
|
||||
func VerificationRequestEventContentFromMessage(evt *Event) *VerificationRequestEventContent {
|
||||
content := evt.Content.AsMessage()
|
||||
return &VerificationRequestEventContent{
|
||||
ToDeviceVerificationEvent: ToDeviceVerificationEvent{
|
||||
TransactionID: id.VerificationTransactionID(evt.ID),
|
||||
},
|
||||
Timestamp: jsontime.UMInt(evt.Timestamp),
|
||||
FromDevice: content.FromDevice,
|
||||
Methods: content.Methods,
|
||||
}
|
||||
}
|
||||
|
||||
// VerificationReadyEventContent represents the content of an
|
||||
// [m.key.verification.ready] event (both the to-device and the in-room
|
||||
// version) as described in [Section 11.12.2.1] of the Spec.
|
||||
//
|
||||
// [m.key.verification.ready]: https://spec.matrix.org/v1.9/client-server-api/#mkeyverificationready
|
||||
// [Section 11.12.2.1]: https://spec.matrix.org/v1.9/client-server-api/#key-verification-framework
|
||||
type VerificationReadyEventContent struct {
|
||||
ToDeviceVerificationEvent
|
||||
InRoomVerificationEvent
|
||||
|
||||
// FromDevice is the device ID which is initiating the request.
|
||||
FromDevice id.DeviceID `json:"from_device"`
|
||||
// Methods is a list of the verification methods supported by the sender.
|
||||
Methods []VerificationMethod `json:"methods"`
|
||||
}
|
||||
|
||||
type KeyAgreementProtocol string
|
||||
|
||||
const (
|
||||
KeyAgreementCurve25519 KeyAgreementProtocol = "curve25519"
|
||||
KeyAgreementCurve25519HKDFSHA256 KeyAgreementProtocol = "curve25519-hkdf-sha256"
|
||||
KeyAgreementProtocolCurve25519 KeyAgreementProtocol = "curve25519"
|
||||
KeyAgreementProtocolCurve25519HKDFSHA256 KeyAgreementProtocol = "curve25519-hkdf-sha256"
|
||||
)
|
||||
|
||||
type VerificationHashMethod string
|
||||
|
||||
const VerificationHashSHA256 VerificationHashMethod = "sha256"
|
||||
const VerificationHashMethodSHA256 VerificationHashMethod = "sha256"
|
||||
|
||||
type MACMethod string
|
||||
|
||||
const HKDFHMACSHA256 MACMethod = "hkdf-hmac-sha256"
|
||||
const (
|
||||
MACMethodHKDFHMACSHA256 MACMethod = "hkdf-hmac-sha256"
|
||||
MACMethodHKDFHMACSHA256V2 MACMethod = "hkdf-hmac-sha256.v2"
|
||||
)
|
||||
|
||||
type SASMethod string
|
||||
|
||||
const (
|
||||
SASDecimal SASMethod = "decimal"
|
||||
SASEmoji SASMethod = "emoji"
|
||||
SASMethodDecimal SASMethod = "decimal"
|
||||
SASMethodEmoji SASMethod = "emoji"
|
||||
)
|
||||
|
||||
// VerificationStartEventContent represents the content of a m.key.verification.start to_device event.
|
||||
// https://spec.matrix.org/v1.2/client-server-api/#mkeyverificationstartmsasv1
|
||||
// VerificationStartEventContent represents the content of an
|
||||
// [m.key.verification.start] event (both the to-device and the in-room
|
||||
// version) as described in [Section 11.12.2.1] of the Spec.
|
||||
//
|
||||
// This struct also contains the fields for an [m.key.verification.start] event
|
||||
// using the [VerificationMethodSAS] method as described in [Section
|
||||
// 11.12.2.2.2] and an [m.key.verification.start] using
|
||||
// [VerificationMethodReciprocate] as described in [Section 11.12.2.4.2].
|
||||
//
|
||||
// [m.key.verification.start]: https://spec.matrix.org/v1.9/client-server-api/#mkeyverificationstart
|
||||
// [Section 11.12.2.1]: https://spec.matrix.org/v1.9/client-server-api/#key-verification-framework
|
||||
// [Section 11.12.2.2.2]: https://spec.matrix.org/v1.9/client-server-api/#verification-messages-specific-to-sas
|
||||
// [Section 11.12.2.4.2]: https://spec.matrix.org/v1.9/client-server-api/#verification-messages-specific-to-qr-codes
|
||||
type VerificationStartEventContent struct {
|
||||
// The device ID which is initiating the process.
|
||||
ToDeviceVerificationEvent
|
||||
InRoomVerificationEvent
|
||||
|
||||
// FromDevice is the device ID which is initiating the request.
|
||||
FromDevice id.DeviceID `json:"from_device"`
|
||||
// An opaque identifier for the verification process. Must be unique with respect to the devices involved.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// The verification method to use.
|
||||
// Method is the verification method to use.
|
||||
Method VerificationMethod `json:"method"`
|
||||
// The key agreement protocols the sending device understands.
|
||||
KeyAgreementProtocols []KeyAgreementProtocol `json:"key_agreement_protocols"`
|
||||
// The hash methods the sending device understands.
|
||||
Hashes []VerificationHashMethod `json:"hashes"`
|
||||
// The message authentication codes that the sending device understands.
|
||||
// NextMethod is an optional method to use to verify the other user's key.
|
||||
// Applicable when the method chosen only verifies one user’s key. This
|
||||
// field will never be present if the method verifies keys both ways.
|
||||
NextMethod VerificationMethod `json:"next_method,omitempty"`
|
||||
|
||||
// Hashes are the hash methods the sending device understands. This field
|
||||
// is only applicable when the method is m.sas.v1.
|
||||
Hashes []VerificationHashMethod `json:"hashes,omitempty"`
|
||||
// KeyAgreementProtocols is the list of key agreement protocols the sending
|
||||
// device understands. This field is only applicable when the method is
|
||||
// m.sas.v1.
|
||||
KeyAgreementProtocols []KeyAgreementProtocol `json:"key_agreement_protocols,omitempty"`
|
||||
// MessageAuthenticationCodes is a list of the MAC methods that the sending
|
||||
// device understands. This field is only applicable when the method is
|
||||
// m.sas.v1.
|
||||
MessageAuthenticationCodes []MACMethod `json:"message_authentication_codes"`
|
||||
// The SAS methods the sending device (and the sending device's user) understands.
|
||||
// ShortAuthenticationString is a list of SAS methods the sending device
|
||||
// (and the sending device's user) understands. This field is only
|
||||
// applicable when the method is m.sas.v1.
|
||||
ShortAuthenticationString []SASMethod `json:"short_authentication_string"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
|
||||
// Secret is the shared secret from the QR code. This field is only
|
||||
// applicable when the method is m.reciprocate.v1.
|
||||
Secret jsonbytes.UnpaddedBytes `json:"secret,omitempty"`
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) SupportsKeyAgreementProtocol(proto KeyAgreementProtocol) bool {
|
||||
for _, supportedProto := range vsec.KeyAgreementProtocols {
|
||||
if supportedProto == proto {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) SupportsHashMethod(alg VerificationHashMethod) bool {
|
||||
for _, supportedAlg := range vsec.Hashes {
|
||||
if supportedAlg == alg {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) SupportsMACMethod(meth MACMethod) bool {
|
||||
for _, supportedMeth := range vsec.MessageAuthenticationCodes {
|
||||
if supportedMeth == meth {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) SupportsSASMethod(meth SASMethod) bool {
|
||||
for _, supportedMeth := range vsec.ShortAuthenticationString {
|
||||
if supportedMeth == meth {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vsec.RelatesTo == nil {
|
||||
vsec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vsec.RelatesTo
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vsec.RelatesTo
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vsec.RelatesTo = rel
|
||||
}
|
||||
|
||||
// VerificationReadyEventContent represents the content of a m.key.verification.ready event.
|
||||
// https://spec.matrix.org/v1.2/client-server-api/#mkeyverificationready
|
||||
type VerificationReadyEventContent struct {
|
||||
// The device ID which accepted the process.
|
||||
FromDevice id.DeviceID `json:"from_device"`
|
||||
// The verification methods supported by the sender.
|
||||
Methods []VerificationMethod `json:"methods"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
var _ Relatable = (*VerificationReadyEventContent)(nil)
|
||||
|
||||
func (vrec *VerificationReadyEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vrec.RelatesTo == nil {
|
||||
vrec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vrec.RelatesTo
|
||||
}
|
||||
|
||||
func (vrec *VerificationReadyEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vrec.RelatesTo
|
||||
}
|
||||
|
||||
func (vrec *VerificationReadyEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vrec.RelatesTo = rel
|
||||
}
|
||||
|
||||
// VerificationAcceptEventContent represents the content of a m.key.verification.accept to_device event.
|
||||
// https://spec.matrix.org/v1.2/client-server-api/#mkeyverificationaccept
|
||||
type VerificationAcceptEventContent struct {
|
||||
// An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// The verification method to use.
|
||||
Method VerificationMethod `json:"method"`
|
||||
// The key agreement protocol the device is choosing to use, out of the options in the m.key.verification.start message.
|
||||
KeyAgreementProtocol KeyAgreementProtocol `json:"key_agreement_protocol"`
|
||||
// The hash method the device is choosing to use, out of the options in the m.key.verification.start message.
|
||||
Hash VerificationHashMethod `json:"hash"`
|
||||
// The message authentication code the device is choosing to use, out of the options in the m.key.verification.start message.
|
||||
MessageAuthenticationCode MACMethod `json:"message_authentication_code"`
|
||||
// The SAS methods both devices involved in the verification process understand. Must be a subset of the options in the m.key.verification.start message.
|
||||
ShortAuthenticationString []SASMethod `json:"short_authentication_string"`
|
||||
// The hash (encoded as unpadded base64) of the concatenation of the device's ephemeral public key (encoded as unpadded base64) and the canonical JSON representation of the m.key.verification.start message.
|
||||
Commitment string `json:"commitment"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vaec *VerificationAcceptEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vaec.RelatesTo == nil {
|
||||
vaec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vaec.RelatesTo
|
||||
}
|
||||
|
||||
func (vaec *VerificationAcceptEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vaec.RelatesTo
|
||||
}
|
||||
|
||||
func (vaec *VerificationAcceptEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vaec.RelatesTo = rel
|
||||
}
|
||||
|
||||
// VerificationKeyEventContent represents the content of a m.key.verification.key to_device event.
|
||||
// https://spec.matrix.org/v1.2/client-server-api/#mkeyverificationkey
|
||||
type VerificationKeyEventContent struct {
|
||||
// An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// The device's ephemeral public key, encoded as unpadded base64.
|
||||
Key string `json:"key"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vkec *VerificationKeyEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vkec.RelatesTo == nil {
|
||||
vkec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vkec.RelatesTo
|
||||
}
|
||||
|
||||
func (vkec *VerificationKeyEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vkec.RelatesTo
|
||||
}
|
||||
|
||||
func (vkec *VerificationKeyEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vkec.RelatesTo = rel
|
||||
}
|
||||
|
||||
// VerificationMacEventContent represents the content of a m.key.verification.mac to_device event.
|
||||
// https://spec.matrix.org/v1.2/client-server-api/#mkeyverificationmac
|
||||
type VerificationMacEventContent struct {
|
||||
// An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// A map of the key ID to the MAC of the key, using the algorithm in the verification process. The MAC is encoded as unpadded base64.
|
||||
Mac map[id.KeyID]string `json:"mac"`
|
||||
// The MAC of the comma-separated, sorted, list of key IDs given in the mac property, encoded as unpadded base64.
|
||||
Keys string `json:"keys"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vmec *VerificationMacEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vmec.RelatesTo == nil {
|
||||
vmec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vmec.RelatesTo
|
||||
}
|
||||
|
||||
func (vmec *VerificationMacEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vmec.RelatesTo
|
||||
}
|
||||
|
||||
func (vmec *VerificationMacEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vmec.RelatesTo = rel
|
||||
// VerificationDoneEventContent represents the content of an
|
||||
// [m.key.verification.done] event (both the to-device and the in-room version)
|
||||
// as described in [Section 11.12.2.1] of the Spec.
|
||||
//
|
||||
// This type is an alias for [VerificationRelatable] since there are no
|
||||
// additional fields defined by the spec.
|
||||
//
|
||||
// [m.key.verification.done]: https://spec.matrix.org/v1.9/client-server-api/#mkeyverificationdone
|
||||
// [Section 11.12.2.1]: https://spec.matrix.org/v1.9/client-server-api/#mkeyverificationdone
|
||||
type VerificationDoneEventContent struct {
|
||||
ToDeviceVerificationEvent
|
||||
InRoomVerificationEvent
|
||||
}
|
||||
|
||||
type VerificationCancelCode string
|
||||
|
||||
const (
|
||||
VerificationCancelByUser VerificationCancelCode = "m.user"
|
||||
VerificationCancelByTimeout VerificationCancelCode = "m.timeout"
|
||||
VerificationCancelUnknownTransaction VerificationCancelCode = "m.unknown_transaction"
|
||||
VerificationCancelUnknownMethod VerificationCancelCode = "m.unknown_method"
|
||||
VerificationCancelUnexpectedMessage VerificationCancelCode = "m.unexpected_message"
|
||||
VerificationCancelKeyMismatch VerificationCancelCode = "m.key_mismatch"
|
||||
VerificationCancelUserMismatch VerificationCancelCode = "m.user_mismatch"
|
||||
VerificationCancelInvalidMessage VerificationCancelCode = "m.invalid_message"
|
||||
VerificationCancelAccepted VerificationCancelCode = "m.accepted"
|
||||
VerificationCancelSASMismatch VerificationCancelCode = "m.mismatched_sas"
|
||||
VerificationCancelCommitmentMismatch VerificationCancelCode = "m.mismatched_commitment"
|
||||
VerificationCancelCodeUser VerificationCancelCode = "m.user"
|
||||
VerificationCancelCodeTimeout VerificationCancelCode = "m.timeout"
|
||||
VerificationCancelCodeUnknownTransaction VerificationCancelCode = "m.unknown_transaction"
|
||||
VerificationCancelCodeUnknownMethod VerificationCancelCode = "m.unknown_method"
|
||||
VerificationCancelCodeUnexpectedMessage VerificationCancelCode = "m.unexpected_message"
|
||||
VerificationCancelCodeKeyMismatch VerificationCancelCode = "m.key_mismatch"
|
||||
VerificationCancelCodeUserMismatch VerificationCancelCode = "m.user_mismatch"
|
||||
VerificationCancelCodeInvalidMessage VerificationCancelCode = "m.invalid_message"
|
||||
VerificationCancelCodeAccepted VerificationCancelCode = "m.accepted"
|
||||
VerificationCancelCodeSASMismatch VerificationCancelCode = "m.mismatched_sas"
|
||||
VerificationCancelCodeCommitmentMismatch VerificationCancelCode = "m.mismatched_commitment"
|
||||
)
|
||||
|
||||
// VerificationCancelEventContent represents the content of a m.key.verification.cancel to_device event.
|
||||
// https://spec.matrix.org/v1.2/client-server-api/#mkeyverificationcancel
|
||||
// VerificationCancelEventContent represents the content of an
|
||||
// [m.key.verification.cancel] event (both the to-device and the in-room
|
||||
// version) as described in [Section 11.12.2.1] of the Spec.
|
||||
//
|
||||
// [m.key.verification.cancel]: https://spec.matrix.org/v1.9/client-server-api/#mkeyverificationcancel
|
||||
// [Section 11.12.2.1]: https://spec.matrix.org/v1.9/client-server-api/#mkeyverificationdone
|
||||
type VerificationCancelEventContent struct {
|
||||
// The opaque identifier for the verification process/request.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// A human readable description of the code. The client should only rely on this string if it does not understand the code.
|
||||
Reason string `json:"reason"`
|
||||
// The error code for why the process/request was cancelled by the user.
|
||||
ToDeviceVerificationEvent
|
||||
InRoomVerificationEvent
|
||||
|
||||
// Code is the error code for why the process/request was cancelled by the
|
||||
// user.
|
||||
Code VerificationCancelCode `json:"code"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
// Reason is a human readable description of the code. The client should
|
||||
// only rely on this string if it does not understand the code.
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
func (vcec *VerificationCancelEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vcec.RelatesTo == nil {
|
||||
vcec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vcec.RelatesTo
|
||||
// VerificationAcceptEventContent represents the content of an
|
||||
// [m.key.verification.accept] event (both the to-device and the in-room
|
||||
// version) as described in [Section 11.12.2.2.2] of the Spec.
|
||||
//
|
||||
// [m.key.verification.accept]: https://spec.matrix.org/v1.9/client-server-api/#mkeyverificationaccept
|
||||
// [Section 11.12.2.2.2]: https://spec.matrix.org/v1.9/client-server-api/#verification-messages-specific-to-sas
|
||||
type VerificationAcceptEventContent struct {
|
||||
ToDeviceVerificationEvent
|
||||
InRoomVerificationEvent
|
||||
|
||||
// Commitment is the hash of the concatenation of the device's ephemeral
|
||||
// public key (encoded as unpadded base64) and the canonical JSON
|
||||
// representation of the m.key.verification.start message.
|
||||
Commitment jsonbytes.UnpaddedBytes `json:"commitment"`
|
||||
// Hash is the hash method the device is choosing to use, out of the
|
||||
// options in the m.key.verification.start message.
|
||||
Hash VerificationHashMethod `json:"hash"`
|
||||
// KeyAgreementProtocol is the key agreement protocol the device is
|
||||
// choosing to use, out of the options in the m.key.verification.start
|
||||
// message.
|
||||
KeyAgreementProtocol KeyAgreementProtocol `json:"key_agreement_protocol"`
|
||||
// MessageAuthenticationCode is the message authentication code the device
|
||||
// is choosing to use, out of the options in the m.key.verification.start
|
||||
// message.
|
||||
MessageAuthenticationCode MACMethod `json:"message_authentication_code"`
|
||||
// ShortAuthenticationString is a list of SAS methods both devices involved
|
||||
// in the verification process understand. Must be a subset of the options
|
||||
// in the m.key.verification.start message.
|
||||
ShortAuthenticationString []SASMethod `json:"short_authentication_string"`
|
||||
}
|
||||
|
||||
func (vcec *VerificationCancelEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vcec.RelatesTo
|
||||
// VerificationKeyEventContent represents the content of an
|
||||
// [m.key.verification.key] event (both the to-device and the in-room version)
|
||||
// as described in [Section 11.12.2.2.2] of the Spec.
|
||||
//
|
||||
// [m.key.verification.key]: https://spec.matrix.org/v1.9/client-server-api/#mkeyverificationkey
|
||||
// [Section 11.12.2.2.2]: https://spec.matrix.org/v1.9/client-server-api/#verification-messages-specific-to-sas
|
||||
type VerificationKeyEventContent struct {
|
||||
ToDeviceVerificationEvent
|
||||
InRoomVerificationEvent
|
||||
|
||||
// Key is the device’s ephemeral public key.
|
||||
Key jsonbytes.UnpaddedBytes `json:"key"`
|
||||
}
|
||||
|
||||
func (vcec *VerificationCancelEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vcec.RelatesTo = rel
|
||||
// VerificationMACEventContent represents the content of an
|
||||
// [m.key.verification.mac] event (both the to-device and the in-room version)
|
||||
// as described in [Section 11.12.2.2.2] of the Spec.
|
||||
//
|
||||
// [m.key.verification.mac]: https://spec.matrix.org/v1.9/client-server-api/#mkeyverificationmac
|
||||
// [Section 11.12.2.2.2]: https://spec.matrix.org/v1.9/client-server-api/#verification-messages-specific-to-sas
|
||||
type VerificationMACEventContent struct {
|
||||
ToDeviceVerificationEvent
|
||||
InRoomVerificationEvent
|
||||
|
||||
// Keys is the MAC of the comma-separated, sorted, list of key IDs given in
|
||||
// the MAC property.
|
||||
Keys jsonbytes.UnpaddedBytes `json:"keys"`
|
||||
// MAC is a map of the key ID to the MAC of the key, using the algorithm in
|
||||
// the verification process.
|
||||
MAC map[id.KeyID]jsonbytes.UnpaddedBytes `json:"mac"`
|
||||
}
|
||||
|
||||
54
vendor/maunium.net/go/mautrix/id/crypto.go
generated
vendored
54
vendor/maunium.net/go/mautrix/id/crypto.go
generated
vendored
@@ -7,8 +7,11 @@
|
||||
package id
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go.mau.fi/util/random"
|
||||
)
|
||||
|
||||
// OlmMsgType is an Olm message type
|
||||
@@ -44,6 +47,19 @@ const (
|
||||
XSUsageUserSigning CrossSigningUsage = "user_signing"
|
||||
)
|
||||
|
||||
type KeyBackupAlgorithm string
|
||||
|
||||
const (
|
||||
KeyBackupAlgorithmMegolmBackupV1 KeyBackupAlgorithm = "m.megolm_backup.v1.curve25519-aes-sha2"
|
||||
)
|
||||
|
||||
// BackupVersion is an arbitrary string that identifies a server side key backup.
|
||||
type KeyBackupVersion string
|
||||
|
||||
func (version KeyBackupVersion) String() string {
|
||||
return string(version)
|
||||
}
|
||||
|
||||
// A SessionID is an arbitrary string that identifies an Olm or Megolm session.
|
||||
type SessionID string
|
||||
|
||||
@@ -59,6 +75,12 @@ func (ed25519 Ed25519) String() string {
|
||||
return string(ed25519)
|
||||
}
|
||||
|
||||
func (ed25519 Ed25519) Bytes() []byte {
|
||||
val, _ := base64.RawStdEncoding.DecodeString(string(ed25519))
|
||||
// TODO handle errors
|
||||
return val
|
||||
}
|
||||
|
||||
func (ed25519 Ed25519) Fingerprint() string {
|
||||
spacedSigningKey := make([]byte, len(ed25519)+(len(ed25519)-1)/4)
|
||||
var ptr = 0
|
||||
@@ -82,6 +104,12 @@ func (curve25519 Curve25519) String() string {
|
||||
return string(curve25519)
|
||||
}
|
||||
|
||||
func (curve25519 Curve25519) Bytes() []byte {
|
||||
val, _ := base64.RawStdEncoding.DecodeString(string(curve25519))
|
||||
// TODO handle errors
|
||||
return val
|
||||
}
|
||||
|
||||
// A DeviceID is an arbitrary string that references a specific device.
|
||||
type DeviceID string
|
||||
|
||||
@@ -147,3 +175,29 @@ type CrossSigningKey struct {
|
||||
Key Ed25519
|
||||
First Ed25519
|
||||
}
|
||||
|
||||
// Secret storage keys
|
||||
type Secret string
|
||||
|
||||
func (s Secret) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
const (
|
||||
SecretXSMaster Secret = "m.cross_signing.master"
|
||||
SecretXSSelfSigning Secret = "m.cross_signing.self_signing"
|
||||
SecretXSUserSigning Secret = "m.cross_signing.user_signing"
|
||||
SecretMegolmBackupV1 Secret = "m.megolm_backup.v1"
|
||||
)
|
||||
|
||||
// VerificationTransactionID is a unique identifier for a verification
|
||||
// transaction.
|
||||
type VerificationTransactionID string
|
||||
|
||||
func NewVerificationTransactionID() VerificationTransactionID {
|
||||
return VerificationTransactionID(random.String(32))
|
||||
}
|
||||
|
||||
func (t VerificationTransactionID) String() string {
|
||||
return string(t)
|
||||
}
|
||||
|
||||
25
vendor/maunium.net/go/mautrix/id/userid.go
generated
vendored
25
vendor/maunium.net/go/mautrix/id/userid.go
generated
vendored
@@ -36,19 +36,34 @@ var (
|
||||
ErrEmptyLocalpart = errors.New("empty localparts are not allowed")
|
||||
)
|
||||
|
||||
// ParseCommonIdentifier parses a common identifier according to https://spec.matrix.org/v1.9/appendices/#common-identifier-format
|
||||
func ParseCommonIdentifier[Stringish ~string](identifier Stringish) (sigil byte, localpart, homeserver string) {
|
||||
if len(identifier) == 0 {
|
||||
return
|
||||
}
|
||||
sigil = identifier[0]
|
||||
strIdentifier := string(identifier)
|
||||
if strings.ContainsRune(strIdentifier, ':') {
|
||||
parts := strings.SplitN(strIdentifier, ":", 2)
|
||||
localpart = parts[0][1:]
|
||||
homeserver = parts[1]
|
||||
} else {
|
||||
localpart = strIdentifier[1:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Parse parses the user ID into the localpart and server name.
|
||||
//
|
||||
// Note that this only enforces very basic user ID formatting requirements: user IDs start with
|
||||
// a @, and contain a : after the @. If you want to enforce localpart validity, see the
|
||||
// ParseAndValidate and ValidateUserLocalpart functions.
|
||||
func (userID UserID) Parse() (localpart, homeserver string, err error) {
|
||||
if len(userID) == 0 || userID[0] != '@' || !strings.ContainsRune(string(userID), ':') {
|
||||
// This error wrapping lets you use errors.Is() nicely even though the message contains the user ID
|
||||
var sigil byte
|
||||
sigil, localpart, homeserver = ParseCommonIdentifier(userID)
|
||||
if sigil != '@' || homeserver == "" {
|
||||
err = fmt.Errorf("'%s' %w", userID, ErrInvalidUserID)
|
||||
return
|
||||
}
|
||||
parts := strings.SplitN(string(userID), ":", 2)
|
||||
localpart, homeserver = strings.TrimPrefix(parts[0], "@"), parts[1]
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
52
vendor/maunium.net/go/mautrix/requests.go
generated
vendored
52
vendor/maunium.net/go/mautrix/requests.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
"maunium.net/go/mautrix/pushrules"
|
||||
@@ -96,8 +97,9 @@ type ReqUIAuthFallback struct {
|
||||
|
||||
type ReqUIAuthLogin struct {
|
||||
BaseAuthData
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
User string `json:"user,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
// ReqCreateRoom is the JSON request for https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3createroom
|
||||
@@ -184,11 +186,11 @@ type ReqAliasCreate struct {
|
||||
}
|
||||
|
||||
type OneTimeKey struct {
|
||||
Key id.Curve25519 `json:"key"`
|
||||
Fallback bool `json:"fallback,omitempty"`
|
||||
Signatures Signatures `json:"signatures,omitempty"`
|
||||
Unsigned map[string]any `json:"unsigned,omitempty"`
|
||||
IsSigned bool `json:"-"`
|
||||
Key id.Curve25519 `json:"key"`
|
||||
Fallback bool `json:"fallback,omitempty"`
|
||||
Signatures signatures.Signatures `json:"signatures,omitempty"`
|
||||
Unsigned map[string]any `json:"unsigned,omitempty"`
|
||||
IsSigned bool `json:"-"`
|
||||
|
||||
// Raw data in the one-time key. This must be used for signature verification to ensure unrecognized fields
|
||||
// aren't thrown away (because that would invalidate the signature).
|
||||
@@ -230,7 +232,7 @@ type ReqKeysSignatures struct {
|
||||
Algorithms []id.Algorithm `json:"algorithms,omitempty"`
|
||||
Usage []id.CrossSigningUsage `json:"usage,omitempty"`
|
||||
Keys map[id.KeyID]string `json:"keys"`
|
||||
Signatures Signatures `json:"signatures"`
|
||||
Signatures signatures.Signatures `json:"signatures"`
|
||||
}
|
||||
|
||||
type ReqUploadSignatures map[id.UserID]map[string]ReqKeysSignatures
|
||||
@@ -240,15 +242,15 @@ type DeviceKeys struct {
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
Algorithms []id.Algorithm `json:"algorithms"`
|
||||
Keys KeyMap `json:"keys"`
|
||||
Signatures Signatures `json:"signatures"`
|
||||
Signatures signatures.Signatures `json:"signatures"`
|
||||
Unsigned map[string]interface{} `json:"unsigned,omitempty"`
|
||||
}
|
||||
|
||||
type CrossSigningKeys struct {
|
||||
UserID id.UserID `json:"user_id"`
|
||||
Usage []id.CrossSigningUsage `json:"usage"`
|
||||
Keys map[id.KeyID]id.Ed25519 `json:"keys"`
|
||||
Signatures map[id.UserID]map[id.KeyID]string `json:"signatures,omitempty"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
Usage []id.CrossSigningUsage `json:"usage"`
|
||||
Keys map[id.KeyID]id.Ed25519 `json:"keys"`
|
||||
Signatures signatures.Signatures `json:"signatures,omitempty"`
|
||||
}
|
||||
|
||||
func (csk *CrossSigningKeys) FirstKey() id.Ed25519 {
|
||||
@@ -283,8 +285,6 @@ func (km KeyMap) GetCurve25519(deviceID id.DeviceID) id.Curve25519 {
|
||||
return id.Curve25519(val)
|
||||
}
|
||||
|
||||
type Signatures map[id.UserID]map[id.KeyID]string
|
||||
|
||||
type ReqQueryKeys struct {
|
||||
DeviceKeys DeviceKeysRequest `json:"device_keys"`
|
||||
Timeout int64 `json:"timeout,omitempty"`
|
||||
@@ -429,20 +429,26 @@ type ReqBeeperSplitRoom struct {
|
||||
Parts []BeeperSplitRoomPart `json:"parts"`
|
||||
}
|
||||
|
||||
type ReqRoomKeysVersionCreate struct {
|
||||
Algorithm string `json:"algorithm"`
|
||||
AuthData json.RawMessage `json:"auth_data"`
|
||||
type ReqRoomKeysVersionCreate[A any] struct {
|
||||
Algorithm id.KeyBackupAlgorithm `json:"algorithm"`
|
||||
AuthData A `json:"auth_data"`
|
||||
}
|
||||
|
||||
type ReqRoomKeysUpdate struct {
|
||||
Rooms map[id.RoomID]ReqRoomKeysRoomUpdate `json:"rooms"`
|
||||
type ReqRoomKeysVersionUpdate[A any] struct {
|
||||
Algorithm id.KeyBackupAlgorithm `json:"algorithm"`
|
||||
AuthData A `json:"auth_data"`
|
||||
Version id.KeyBackupVersion `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
type ReqRoomKeysRoomUpdate struct {
|
||||
Sessions map[id.SessionID]ReqRoomKeysSessionUpdate `json:"sessions"`
|
||||
type ReqKeyBackup struct {
|
||||
Rooms map[id.RoomID]ReqRoomKeyBackup `json:"rooms"`
|
||||
}
|
||||
|
||||
type ReqRoomKeysSessionUpdate struct {
|
||||
type ReqRoomKeyBackup struct {
|
||||
Sessions map[id.SessionID]ReqKeyBackupData `json:"sessions"`
|
||||
}
|
||||
|
||||
type ReqKeyBackupData struct {
|
||||
FirstMessageIndex int `json:"first_message_index"`
|
||||
ForwardedCount int `json:"forwarded_count"`
|
||||
IsVerified bool `json:"is_verified"`
|
||||
|
||||
54
vendor/maunium.net/go/mautrix/responses.go
generated
vendored
54
vendor/maunium.net/go/mautrix/responses.go
generated
vendored
@@ -118,19 +118,7 @@ type RespCreateMXC struct {
|
||||
}
|
||||
|
||||
// RespPreviewURL is the JSON response for https://spec.matrix.org/v1.2/client-server-api/#get_matrixmediav3preview_url
|
||||
type RespPreviewURL struct {
|
||||
CanonicalURL string `json:"og:url,omitempty"`
|
||||
Title string `json:"og:title,omitempty"`
|
||||
Type string `json:"og:type,omitempty"`
|
||||
Description string `json:"og:description,omitempty"`
|
||||
|
||||
ImageURL id.ContentURIString `json:"og:image,omitempty"`
|
||||
|
||||
ImageSize int `json:"matrix:image:size,omitempty"`
|
||||
ImageWidth int `json:"og:image:width,omitempty"`
|
||||
ImageHeight int `json:"og:image:height,omitempty"`
|
||||
ImageType string `json:"og:image:type,omitempty"`
|
||||
}
|
||||
type RespPreviewURL = event.LinkPreview
|
||||
|
||||
// RespUserInteractive is the JSON response for https://spec.matrix.org/v1.2/client-server-api/#user-interactive-authentication-api
|
||||
type RespUserInteractive struct {
|
||||
@@ -321,6 +309,12 @@ func (slr SyncLeftRoom) MarshalJSON() ([]byte, error) {
|
||||
return marshalAndDeleteEmpty((marshalableSyncLeftRoom)(slr), syncLeftRoomPathsToDelete)
|
||||
}
|
||||
|
||||
type BeeperInboxPreviewEvent struct {
|
||||
EventID id.EventID `json:"event_id"`
|
||||
Timestamp jsontime.UnixMilli `json:"origin_server_ts"`
|
||||
Event *event.Event `json:"event,omitempty"`
|
||||
}
|
||||
|
||||
type SyncJoinedRoom struct {
|
||||
Summary LazyLoadSummary `json:"summary"`
|
||||
State SyncEventsList `json:"state"`
|
||||
@@ -331,6 +325,8 @@ type SyncJoinedRoom struct {
|
||||
UnreadNotifications *UnreadNotificationCounts `json:"unread_notifications,omitempty"`
|
||||
// https://github.com/matrix-org/matrix-spec-proposals/pull/2654
|
||||
MSC2654UnreadCount *int `json:"org.matrix.msc2654.unread_count,omitempty"`
|
||||
// Beeper extension
|
||||
BeeperInboxPreview *BeeperInboxPreviewEvent `json:"com.beeper.inbox.preview,omitempty"`
|
||||
}
|
||||
|
||||
type UnreadNotificationCounts struct {
|
||||
@@ -593,30 +589,30 @@ type RespTimestampToEvent struct {
|
||||
}
|
||||
|
||||
type RespRoomKeysVersionCreate struct {
|
||||
Version string `json:"version"`
|
||||
Version id.KeyBackupVersion `json:"version"`
|
||||
}
|
||||
|
||||
type RespRoomKeysVersion struct {
|
||||
Algorithm string `json:"algorithm"`
|
||||
AuthData json.RawMessage `json:"auth_data"`
|
||||
Count int `json:"count"`
|
||||
ETag string `json:"etag"`
|
||||
Version string `json:"version"`
|
||||
type RespRoomKeysVersion[A any] struct {
|
||||
Algorithm id.KeyBackupAlgorithm `json:"algorithm"`
|
||||
AuthData A `json:"auth_data"`
|
||||
Count int `json:"count"`
|
||||
ETag string `json:"etag"`
|
||||
Version id.KeyBackupVersion `json:"version"`
|
||||
}
|
||||
|
||||
type RespRoomKeys struct {
|
||||
Rooms map[id.RoomID]RespRoomKeysRoom `json:"rooms"`
|
||||
type RespRoomKeys[S any] struct {
|
||||
Rooms map[id.RoomID]RespRoomKeyBackup[S] `json:"rooms"`
|
||||
}
|
||||
|
||||
type RespRoomKeysRoom struct {
|
||||
Sessions map[id.SessionID]RespRoomKeysSession `json:"sessions"`
|
||||
type RespRoomKeyBackup[S any] struct {
|
||||
Sessions map[id.SessionID]RespKeyBackupData[S] `json:"sessions"`
|
||||
}
|
||||
|
||||
type RespRoomKeysSession struct {
|
||||
FirstMessageIndex int `json:"first_message_index"`
|
||||
ForwardedCount int `json:"forwarded_count"`
|
||||
IsVerified bool `json:"is_verified"`
|
||||
SessionData json.RawMessage `json:"session_data"`
|
||||
type RespKeyBackupData[S any] struct {
|
||||
FirstMessageIndex int `json:"first_message_index"`
|
||||
ForwardedCount int `json:"forwarded_count"`
|
||||
IsVerified bool `json:"is_verified"`
|
||||
SessionData S `json:"session_data"`
|
||||
}
|
||||
|
||||
type RespRoomKeysUpdate struct {
|
||||
|
||||
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.17.0"
|
||||
const Version = "v0.18.0"
|
||||
|
||||
var GoModVersion = ""
|
||||
var Commit = ""
|
||||
|
||||
Reference in New Issue
Block a user