add vendoring
This commit is contained in:
158
vendor/maunium.net/go/mautrix/id/contenturi.go
generated
vendored
Normal file
158
vendor/maunium.net/go/mautrix/id/contenturi.go
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
// Copyright (c) 2020 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 id
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
InvalidContentURI = errors.New("invalid Matrix content URI")
|
||||
InputNotJSONString = errors.New("input doesn't look like a JSON string")
|
||||
)
|
||||
|
||||
// ContentURIString is a string that's expected to be a Matrix content URI.
|
||||
// It's useful for delaying the parsing of the content URI to move errors from the event content
|
||||
// JSON parsing step to a later step where more appropriate errors can be produced.
|
||||
type ContentURIString string
|
||||
|
||||
func (uriString ContentURIString) Parse() (ContentURI, error) {
|
||||
return ParseContentURI(string(uriString))
|
||||
}
|
||||
|
||||
func (uriString ContentURIString) ParseOrIgnore() ContentURI {
|
||||
parsed, _ := ParseContentURI(string(uriString))
|
||||
return parsed
|
||||
}
|
||||
|
||||
// ContentURI represents a Matrix content URI.
|
||||
// https://spec.matrix.org/v1.2/client-server-api/#matrix-content-mxc-uris
|
||||
type ContentURI struct {
|
||||
Homeserver string
|
||||
FileID string
|
||||
}
|
||||
|
||||
func MustParseContentURI(uri string) ContentURI {
|
||||
parsed, err := ParseContentURI(uri)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// ParseContentURI parses a Matrix content URI.
|
||||
func ParseContentURI(uri string) (parsed ContentURI, err error) {
|
||||
if len(uri) == 0 {
|
||||
return
|
||||
} else if !strings.HasPrefix(uri, "mxc://") {
|
||||
err = InvalidContentURI
|
||||
} else if index := strings.IndexRune(uri[6:], '/'); index == -1 || index == len(uri)-7 {
|
||||
err = InvalidContentURI
|
||||
} else {
|
||||
parsed.Homeserver = uri[6 : 6+index]
|
||||
parsed.FileID = uri[6+index+1:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var mxcBytes = []byte("mxc://")
|
||||
|
||||
func ParseContentURIBytes(uri []byte) (parsed ContentURI, err error) {
|
||||
if len(uri) == 0 {
|
||||
return
|
||||
} else if !bytes.HasPrefix(uri, mxcBytes) {
|
||||
err = InvalidContentURI
|
||||
} else if index := bytes.IndexRune(uri[6:], '/'); index == -1 || index == len(uri)-7 {
|
||||
err = InvalidContentURI
|
||||
} else {
|
||||
parsed.Homeserver = string(uri[6 : 6+index])
|
||||
parsed.FileID = string(uri[6+index+1:])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (uri *ContentURI) UnmarshalJSON(raw []byte) (err error) {
|
||||
if string(raw) == "null" {
|
||||
*uri = ContentURI{}
|
||||
return nil
|
||||
} else if len(raw) < 2 || raw[0] != '"' || raw[len(raw)-1] != '"' {
|
||||
return InputNotJSONString
|
||||
}
|
||||
parsed, err := ParseContentURIBytes(raw[1 : len(raw)-1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*uri = parsed
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uri *ContentURI) MarshalJSON() ([]byte, error) {
|
||||
if uri == nil || uri.IsEmpty() {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return json.Marshal(uri.String())
|
||||
}
|
||||
|
||||
func (uri *ContentURI) UnmarshalText(raw []byte) (err error) {
|
||||
parsed, err := ParseContentURIBytes(raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*uri = parsed
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uri ContentURI) MarshalText() ([]byte, error) {
|
||||
return []byte(uri.String()), nil
|
||||
}
|
||||
|
||||
func (uri *ContentURI) Scan(i interface{}) error {
|
||||
var parsed ContentURI
|
||||
var err error
|
||||
switch value := i.(type) {
|
||||
case nil:
|
||||
// don't do anything, set uri to empty
|
||||
case []byte:
|
||||
parsed, err = ParseContentURIBytes(value)
|
||||
case string:
|
||||
parsed, err = ParseContentURI(value)
|
||||
default:
|
||||
return fmt.Errorf("invalid type %T for ContentURI.Scan", i)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*uri = parsed
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uri *ContentURI) Value() (driver.Value, error) {
|
||||
if uri == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return uri.String(), nil
|
||||
}
|
||||
|
||||
func (uri ContentURI) String() string {
|
||||
if uri.IsEmpty() {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("mxc://%s/%s", uri.Homeserver, uri.FileID)
|
||||
}
|
||||
|
||||
func (uri ContentURI) CUString() ContentURIString {
|
||||
return ContentURIString(uri.String())
|
||||
}
|
||||
|
||||
func (uri ContentURI) IsEmpty() bool {
|
||||
return len(uri.Homeserver) == 0 || len(uri.FileID) == 0
|
||||
}
|
||||
149
vendor/maunium.net/go/mautrix/id/crypto.go
generated
vendored
Normal file
149
vendor/maunium.net/go/mautrix/id/crypto.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright (c) 2020 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 id
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// OlmMsgType is an Olm message type
|
||||
type OlmMsgType int
|
||||
|
||||
const (
|
||||
OlmMsgTypePreKey OlmMsgType = 0
|
||||
OlmMsgTypeMsg OlmMsgType = 1
|
||||
)
|
||||
|
||||
// Algorithm is a Matrix message encryption algorithm.
|
||||
// https://spec.matrix.org/v1.2/client-server-api/#messaging-algorithm-names
|
||||
type Algorithm string
|
||||
|
||||
const (
|
||||
AlgorithmOlmV1 Algorithm = "m.olm.v1.curve25519-aes-sha2"
|
||||
AlgorithmMegolmV1 Algorithm = "m.megolm.v1.aes-sha2"
|
||||
)
|
||||
|
||||
type KeyAlgorithm string
|
||||
|
||||
const (
|
||||
KeyAlgorithmCurve25519 KeyAlgorithm = "curve25519"
|
||||
KeyAlgorithmEd25519 KeyAlgorithm = "ed25519"
|
||||
KeyAlgorithmSignedCurve25519 KeyAlgorithm = "signed_curve25519"
|
||||
)
|
||||
|
||||
type CrossSigningUsage string
|
||||
|
||||
const (
|
||||
XSUsageMaster CrossSigningUsage = "master"
|
||||
XSUsageSelfSigning CrossSigningUsage = "self_signing"
|
||||
XSUsageUserSigning CrossSigningUsage = "user_signing"
|
||||
)
|
||||
|
||||
// A SessionID is an arbitrary string that identifies an Olm or Megolm session.
|
||||
type SessionID string
|
||||
|
||||
func (sessionID SessionID) String() string {
|
||||
return string(sessionID)
|
||||
}
|
||||
|
||||
// Ed25519 is the base64 representation of an Ed25519 public key
|
||||
type Ed25519 string
|
||||
type SigningKey = Ed25519
|
||||
|
||||
func (ed25519 Ed25519) String() string {
|
||||
return string(ed25519)
|
||||
}
|
||||
|
||||
func (ed25519 Ed25519) Fingerprint() string {
|
||||
spacedSigningKey := make([]byte, len(ed25519)+(len(ed25519)-1)/4)
|
||||
var ptr = 0
|
||||
for i, chr := range ed25519 {
|
||||
spacedSigningKey[ptr] = byte(chr)
|
||||
ptr++
|
||||
if i%4 == 3 {
|
||||
spacedSigningKey[ptr] = ' '
|
||||
ptr++
|
||||
}
|
||||
}
|
||||
return string(spacedSigningKey)
|
||||
}
|
||||
|
||||
// Curve25519 is the base64 representation of an Curve25519 public key
|
||||
type Curve25519 string
|
||||
type SenderKey = Curve25519
|
||||
type IdentityKey = Curve25519
|
||||
|
||||
func (curve25519 Curve25519) String() string {
|
||||
return string(curve25519)
|
||||
}
|
||||
|
||||
// A DeviceID is an arbitrary string that references a specific device.
|
||||
type DeviceID string
|
||||
|
||||
func (deviceID DeviceID) String() string {
|
||||
return string(deviceID)
|
||||
}
|
||||
|
||||
// A DeviceKeyID is a string formatted as <algorithm>:<device_id> that is used as the key in deviceid-key mappings.
|
||||
type DeviceKeyID string
|
||||
|
||||
func NewDeviceKeyID(algorithm KeyAlgorithm, deviceID DeviceID) DeviceKeyID {
|
||||
return DeviceKeyID(fmt.Sprintf("%s:%s", algorithm, deviceID))
|
||||
}
|
||||
|
||||
func (deviceKeyID DeviceKeyID) String() string {
|
||||
return string(deviceKeyID)
|
||||
}
|
||||
|
||||
func (deviceKeyID DeviceKeyID) Parse() (Algorithm, DeviceID) {
|
||||
index := strings.IndexRune(string(deviceKeyID), ':')
|
||||
if index < 0 || len(deviceKeyID) <= index+1 {
|
||||
return "", ""
|
||||
}
|
||||
return Algorithm(deviceKeyID[:index]), DeviceID(deviceKeyID[index+1:])
|
||||
}
|
||||
|
||||
// A KeyID a string formatted as <keyalgorithm>:<key_id> that is used as the key in one-time-key mappings.
|
||||
type KeyID string
|
||||
|
||||
func NewKeyID(algorithm KeyAlgorithm, keyID string) KeyID {
|
||||
return KeyID(fmt.Sprintf("%s:%s", algorithm, keyID))
|
||||
}
|
||||
|
||||
func (keyID KeyID) String() string {
|
||||
return string(keyID)
|
||||
}
|
||||
|
||||
func (keyID KeyID) Parse() (KeyAlgorithm, string) {
|
||||
index := strings.IndexRune(string(keyID), ':')
|
||||
if index < 0 || len(keyID) <= index+1 {
|
||||
return "", ""
|
||||
}
|
||||
return KeyAlgorithm(keyID[:index]), string(keyID[index+1:])
|
||||
}
|
||||
|
||||
// Device contains the identity details of a device and some additional info.
|
||||
type Device struct {
|
||||
UserID UserID
|
||||
DeviceID DeviceID
|
||||
IdentityKey Curve25519
|
||||
SigningKey Ed25519
|
||||
|
||||
Trust TrustState
|
||||
Deleted bool
|
||||
Name string
|
||||
}
|
||||
|
||||
func (device *Device) Fingerprint() string {
|
||||
return device.SigningKey.Fingerprint()
|
||||
}
|
||||
|
||||
type CrossSigningKey struct {
|
||||
Key Ed25519
|
||||
First Ed25519
|
||||
}
|
||||
293
vendor/maunium.net/go/mautrix/id/matrixuri.go
generated
vendored
Normal file
293
vendor/maunium.net/go/mautrix/id/matrixuri.go
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
// 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 id
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Errors that can happen when parsing matrix: URIs
|
||||
var (
|
||||
ErrInvalidScheme = errors.New("matrix URI scheme must be exactly 'matrix'")
|
||||
ErrInvalidPartCount = errors.New("matrix URIs must have exactly 2 or 4 segments")
|
||||
ErrInvalidFirstSegment = errors.New("invalid identifier in first segment of matrix URI")
|
||||
ErrEmptySecondSegment = errors.New("the second segment of the matrix URI must not be empty")
|
||||
ErrInvalidThirdSegment = errors.New("invalid identifier in third segment of matrix URI")
|
||||
ErrEmptyFourthSegment = errors.New("the fourth segment of the matrix URI must not be empty when the third segment is present")
|
||||
)
|
||||
|
||||
// Errors that can happen when parsing matrix.to URLs
|
||||
var (
|
||||
ErrNotMatrixTo = errors.New("that URL is not a matrix.to URL")
|
||||
ErrInvalidMatrixToPartCount = errors.New("matrix.to URLs must have exactly 1 or 2 segments")
|
||||
ErrEmptyMatrixToPrimaryIdentifier = errors.New("the primary identifier in the matrix.to URL is empty")
|
||||
ErrInvalidMatrixToPrimaryIdentifier = errors.New("the primary identifier in the matrix.to URL has an invalid sigil")
|
||||
ErrInvalidMatrixToSecondaryIdentifier = errors.New("the secondary identifier in the matrix.to URL has an invalid sigil")
|
||||
)
|
||||
|
||||
var ErrNotMatrixToOrMatrixURI = errors.New("that URL is not a matrix.to URL nor matrix: URI")
|
||||
|
||||
// MatrixURI contains the result of parsing a matrix: URI using ParseMatrixURI
|
||||
type MatrixURI struct {
|
||||
Sigil1 rune
|
||||
Sigil2 rune
|
||||
MXID1 string
|
||||
MXID2 string
|
||||
Via []string
|
||||
Action string
|
||||
}
|
||||
|
||||
// SigilToPathSegment contains a mapping from Matrix identifier sigils to matrix: URI path segments.
|
||||
var SigilToPathSegment = map[rune]string{
|
||||
'$': "e",
|
||||
'#': "r",
|
||||
'!': "roomid",
|
||||
'@': "u",
|
||||
}
|
||||
|
||||
func (uri *MatrixURI) getQuery() url.Values {
|
||||
q := make(url.Values)
|
||||
if uri.Via != nil && len(uri.Via) > 0 {
|
||||
q["via"] = uri.Via
|
||||
}
|
||||
if len(uri.Action) > 0 {
|
||||
q.Set("action", uri.Action)
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
// String converts the parsed matrix: URI back into the string representation.
|
||||
func (uri *MatrixURI) String() string {
|
||||
parts := []string{
|
||||
SigilToPathSegment[uri.Sigil1],
|
||||
uri.MXID1,
|
||||
}
|
||||
if uri.Sigil2 != 0 {
|
||||
parts = append(parts, SigilToPathSegment[uri.Sigil2], uri.MXID2)
|
||||
}
|
||||
return (&url.URL{
|
||||
Scheme: "matrix",
|
||||
Opaque: strings.Join(parts, "/"),
|
||||
RawQuery: uri.getQuery().Encode(),
|
||||
}).String()
|
||||
}
|
||||
|
||||
// MatrixToURL converts to parsed matrix: URI into a matrix.to URL
|
||||
func (uri *MatrixURI) MatrixToURL() string {
|
||||
fragment := fmt.Sprintf("#/%s", url.QueryEscape(uri.PrimaryIdentifier()))
|
||||
if uri.Sigil2 != 0 {
|
||||
fragment = fmt.Sprintf("%s/%s", fragment, url.QueryEscape(uri.SecondaryIdentifier()))
|
||||
}
|
||||
query := uri.getQuery().Encode()
|
||||
if len(query) > 0 {
|
||||
fragment = fmt.Sprintf("%s?%s", fragment, query)
|
||||
}
|
||||
// It would be nice to use URL{...}.String() here, but figuring out the Fragment vs RawFragment stuff is a pain
|
||||
return fmt.Sprintf("https://matrix.to/%s", fragment)
|
||||
}
|
||||
|
||||
// PrimaryIdentifier returns the first Matrix identifier in the URI.
|
||||
// Currently room IDs, room aliases and user IDs can be in the primary identifier slot.
|
||||
func (uri *MatrixURI) PrimaryIdentifier() string {
|
||||
return fmt.Sprintf("%c%s", uri.Sigil1, uri.MXID1)
|
||||
}
|
||||
|
||||
// SecondaryIdentifier returns the second Matrix identifier in the URI.
|
||||
// Currently only event IDs can be in the secondary identifier slot.
|
||||
func (uri *MatrixURI) SecondaryIdentifier() string {
|
||||
if uri.Sigil2 == 0 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%c%s", uri.Sigil2, uri.MXID2)
|
||||
}
|
||||
|
||||
// UserID returns the user ID from the URI if the primary identifier is a user ID.
|
||||
func (uri *MatrixURI) UserID() UserID {
|
||||
if uri.Sigil1 == '@' {
|
||||
return UserID(uri.PrimaryIdentifier())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// RoomID returns the room ID from the URI if the primary identifier is a room ID.
|
||||
func (uri *MatrixURI) RoomID() RoomID {
|
||||
if uri.Sigil1 == '!' {
|
||||
return RoomID(uri.PrimaryIdentifier())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// RoomAlias returns the room alias from the URI if the primary identifier is a room alias.
|
||||
func (uri *MatrixURI) RoomAlias() RoomAlias {
|
||||
if uri.Sigil1 == '#' {
|
||||
return RoomAlias(uri.PrimaryIdentifier())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// EventID returns the event ID from the URI if the primary identifier is a room ID or alias and the secondary identifier is an event ID.
|
||||
func (uri *MatrixURI) EventID() EventID {
|
||||
if (uri.Sigil1 == '!' || uri.Sigil1 == '#') && uri.Sigil2 == '$' {
|
||||
return EventID(uri.SecondaryIdentifier())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ParseMatrixURIOrMatrixToURL parses the given matrix.to URL or matrix: URI into a unified representation.
|
||||
func ParseMatrixURIOrMatrixToURL(uri string) (*MatrixURI, error) {
|
||||
parsed, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse URI: %w", err)
|
||||
}
|
||||
if parsed.Scheme == "matrix" {
|
||||
return ProcessMatrixURI(parsed)
|
||||
} else if strings.HasSuffix(parsed.Hostname(), "matrix.to") {
|
||||
return ProcessMatrixToURL(parsed)
|
||||
} else {
|
||||
return nil, ErrNotMatrixToOrMatrixURI
|
||||
}
|
||||
}
|
||||
|
||||
// ParseMatrixURI implements the matrix: URI parsing algorithm.
|
||||
//
|
||||
// Currently specified in https://github.com/matrix-org/matrix-doc/blob/master/proposals/2312-matrix-uri.md#uri-parsing-algorithm
|
||||
func ParseMatrixURI(uri string) (*MatrixURI, error) {
|
||||
// Step 1: parse the URI according to RFC 3986
|
||||
parsed, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse URI: %w", err)
|
||||
}
|
||||
return ProcessMatrixURI(parsed)
|
||||
}
|
||||
|
||||
// ProcessMatrixURI implements steps 2-7 of the matrix: URI parsing algorithm
|
||||
// (i.e. everything except parsing the URI itself, which is done with url.Parse or ParseMatrixURI)
|
||||
func ProcessMatrixURI(uri *url.URL) (*MatrixURI, error) {
|
||||
// Step 2: check that scheme is exactly `matrix`
|
||||
if uri.Scheme != "matrix" {
|
||||
return nil, ErrInvalidScheme
|
||||
}
|
||||
|
||||
// Step 3: split the path into segments separated by /
|
||||
parts := strings.Split(uri.Opaque, "/")
|
||||
|
||||
// Step 4: Check that the URI contains either 2 or 4 segments
|
||||
if len(parts) != 2 && len(parts) != 4 {
|
||||
return nil, ErrInvalidPartCount
|
||||
}
|
||||
|
||||
var parsed MatrixURI
|
||||
|
||||
// Step 5: Construct the top-level Matrix identifier
|
||||
// a: find the sigil from the first segment
|
||||
switch parts[0] {
|
||||
case "u", "user":
|
||||
parsed.Sigil1 = '@'
|
||||
case "r", "room":
|
||||
parsed.Sigil1 = '#'
|
||||
case "roomid":
|
||||
parsed.Sigil1 = '!'
|
||||
default:
|
||||
return nil, fmt.Errorf("%w: '%s'", ErrInvalidFirstSegment, parts[0])
|
||||
}
|
||||
// b: find the identifier from the second segment
|
||||
if len(parts[1]) == 0 {
|
||||
return nil, ErrEmptySecondSegment
|
||||
}
|
||||
parsed.MXID1 = parts[1]
|
||||
|
||||
// Step 6: if the first part is a room and the URI has 4 segments, construct a second level identifier
|
||||
if (parsed.Sigil1 == '!' || parsed.Sigil1 == '#') && len(parts) == 4 {
|
||||
// a: find the sigil from the third segment
|
||||
switch parts[2] {
|
||||
case "e", "event":
|
||||
parsed.Sigil2 = '$'
|
||||
default:
|
||||
return nil, fmt.Errorf("%w: '%s'", ErrInvalidThirdSegment, parts[0])
|
||||
}
|
||||
|
||||
// b: find the identifier from the fourth segment
|
||||
if len(parts[3]) == 0 {
|
||||
return nil, ErrEmptyFourthSegment
|
||||
}
|
||||
parsed.MXID2 = parts[3]
|
||||
}
|
||||
|
||||
// Step 7: parse the query and extract via and action items
|
||||
via, ok := uri.Query()["via"]
|
||||
if ok && len(via) > 0 {
|
||||
parsed.Via = via
|
||||
}
|
||||
action, ok := uri.Query()["action"]
|
||||
if ok && len(action) > 0 {
|
||||
parsed.Action = action[len(action)-1]
|
||||
}
|
||||
|
||||
return &parsed, nil
|
||||
}
|
||||
|
||||
// ParseMatrixToURL parses a matrix.to URL into the same container as ParseMatrixURI parses matrix: URIs.
|
||||
func ParseMatrixToURL(uri string) (*MatrixURI, error) {
|
||||
parsed, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse URL: %w", err)
|
||||
}
|
||||
return ProcessMatrixToURL(parsed)
|
||||
}
|
||||
|
||||
// ProcessMatrixToURL is the equivalent of ProcessMatrixURI for matrix.to URLs.
|
||||
func ProcessMatrixToURL(uri *url.URL) (*MatrixURI, error) {
|
||||
if !strings.HasSuffix(uri.Hostname(), "matrix.to") {
|
||||
return nil, ErrNotMatrixTo
|
||||
}
|
||||
|
||||
initialSplit := strings.SplitN(uri.Fragment, "?", 2)
|
||||
parts := strings.Split(initialSplit[0], "/")
|
||||
if len(initialSplit) > 1 {
|
||||
uri.RawQuery = initialSplit[1]
|
||||
}
|
||||
|
||||
if len(parts) < 2 || len(parts) > 3 {
|
||||
return nil, ErrInvalidMatrixToPartCount
|
||||
}
|
||||
|
||||
if len(parts[1]) == 0 {
|
||||
return nil, ErrEmptyMatrixToPrimaryIdentifier
|
||||
}
|
||||
|
||||
var parsed MatrixURI
|
||||
|
||||
parsed.Sigil1 = rune(parts[1][0])
|
||||
parsed.MXID1 = parts[1][1:]
|
||||
_, isKnown := SigilToPathSegment[parsed.Sigil1]
|
||||
if !isKnown {
|
||||
return nil, ErrInvalidMatrixToPrimaryIdentifier
|
||||
}
|
||||
|
||||
if len(parts) == 3 && len(parts[2]) > 0 {
|
||||
parsed.Sigil2 = rune(parts[2][0])
|
||||
parsed.MXID2 = parts[2][1:]
|
||||
_, isKnown = SigilToPathSegment[parsed.Sigil2]
|
||||
if !isKnown {
|
||||
return nil, ErrInvalidMatrixToSecondaryIdentifier
|
||||
}
|
||||
}
|
||||
|
||||
via, ok := uri.Query()["via"]
|
||||
if ok && len(via) > 0 {
|
||||
parsed.Via = via
|
||||
}
|
||||
action, ok := uri.Query()["action"]
|
||||
if ok && len(action) > 0 {
|
||||
parsed.Action = action[len(action)-1]
|
||||
}
|
||||
|
||||
return &parsed, nil
|
||||
}
|
||||
83
vendor/maunium.net/go/mautrix/id/opaque.go
generated
vendored
Normal file
83
vendor/maunium.net/go/mautrix/id/opaque.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2020 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 id
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A RoomID is a string starting with ! that references a specific room.
|
||||
// https://matrix.org/docs/spec/appendices#room-ids-and-event-ids
|
||||
type RoomID string
|
||||
|
||||
// A RoomAlias is a string starting with # that can be resolved into.
|
||||
// https://matrix.org/docs/spec/appendices#room-aliases
|
||||
type RoomAlias string
|
||||
|
||||
func NewRoomAlias(localpart, server string) RoomAlias {
|
||||
return RoomAlias(fmt.Sprintf("#%s:%s", localpart, server))
|
||||
}
|
||||
|
||||
// An EventID is a string starting with $ that references a specific event.
|
||||
//
|
||||
// https://matrix.org/docs/spec/appendices#room-ids-and-event-ids
|
||||
// https://matrix.org/docs/spec/rooms/v4#event-ids
|
||||
type EventID string
|
||||
|
||||
// A BatchID is a string identifying a batch of events being backfilled to a room.
|
||||
// https://github.com/matrix-org/matrix-doc/pull/2716
|
||||
type BatchID string
|
||||
|
||||
func (roomID RoomID) String() string {
|
||||
return string(roomID)
|
||||
}
|
||||
|
||||
func (roomID RoomID) URI(via ...string) *MatrixURI {
|
||||
return &MatrixURI{
|
||||
Sigil1: '!',
|
||||
MXID1: string(roomID)[1:],
|
||||
Via: via,
|
||||
}
|
||||
}
|
||||
|
||||
func (roomID RoomID) EventURI(eventID EventID, via ...string) *MatrixURI {
|
||||
return &MatrixURI{
|
||||
Sigil1: '!',
|
||||
MXID1: string(roomID)[1:],
|
||||
Sigil2: '$',
|
||||
MXID2: string(eventID)[1:],
|
||||
Via: via,
|
||||
}
|
||||
}
|
||||
|
||||
func (roomAlias RoomAlias) String() string {
|
||||
return string(roomAlias)
|
||||
}
|
||||
|
||||
func (roomAlias RoomAlias) URI() *MatrixURI {
|
||||
return &MatrixURI{
|
||||
Sigil1: '#',
|
||||
MXID1: string(roomAlias)[1:],
|
||||
}
|
||||
}
|
||||
|
||||
func (roomAlias RoomAlias) EventURI(eventID EventID) *MatrixURI {
|
||||
return &MatrixURI{
|
||||
Sigil1: '#',
|
||||
MXID1: string(roomAlias)[1:],
|
||||
Sigil2: '$',
|
||||
MXID2: string(eventID)[1:],
|
||||
}
|
||||
}
|
||||
|
||||
func (eventID EventID) String() string {
|
||||
return string(eventID)
|
||||
}
|
||||
|
||||
func (batchID BatchID) String() string {
|
||||
return string(batchID)
|
||||
}
|
||||
87
vendor/maunium.net/go/mautrix/id/trust.go
generated
vendored
Normal file
87
vendor/maunium.net/go/mautrix/id/trust.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) 2022 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 id
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TrustState determines how trusted a device is.
|
||||
type TrustState int
|
||||
|
||||
const (
|
||||
TrustStateBlacklisted TrustState = -100
|
||||
TrustStateUnset TrustState = 0
|
||||
TrustStateUnknownDevice TrustState = 10
|
||||
TrustStateForwarded TrustState = 20
|
||||
TrustStateCrossSignedUntrusted TrustState = 50
|
||||
TrustStateCrossSignedTOFU TrustState = 100
|
||||
TrustStateCrossSignedVerified TrustState = 200
|
||||
TrustStateVerified TrustState = 300
|
||||
TrustStateInvalid TrustState = (1 << 31) - 1
|
||||
)
|
||||
|
||||
func (ts *TrustState) UnmarshalText(data []byte) error {
|
||||
strData := string(data)
|
||||
state := ParseTrustState(strData)
|
||||
if state == TrustStateInvalid {
|
||||
return fmt.Errorf("invalid trust state %q", strData)
|
||||
}
|
||||
*ts = state
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ts *TrustState) MarshalText() ([]byte, error) {
|
||||
return []byte(ts.String()), nil
|
||||
}
|
||||
|
||||
func ParseTrustState(val string) TrustState {
|
||||
switch strings.ToLower(val) {
|
||||
case "blacklisted":
|
||||
return TrustStateBlacklisted
|
||||
case "unverified":
|
||||
return TrustStateUnset
|
||||
case "cross-signed-untrusted":
|
||||
return TrustStateCrossSignedUntrusted
|
||||
case "unknown-device":
|
||||
return TrustStateUnknownDevice
|
||||
case "forwarded":
|
||||
return TrustStateForwarded
|
||||
case "cross-signed-tofu", "cross-signed":
|
||||
return TrustStateCrossSignedTOFU
|
||||
case "cross-signed-verified", "cross-signed-trusted":
|
||||
return TrustStateCrossSignedVerified
|
||||
case "verified":
|
||||
return TrustStateVerified
|
||||
default:
|
||||
return TrustStateInvalid
|
||||
}
|
||||
}
|
||||
|
||||
func (ts TrustState) String() string {
|
||||
switch ts {
|
||||
case TrustStateBlacklisted:
|
||||
return "blacklisted"
|
||||
case TrustStateUnset:
|
||||
return "unverified"
|
||||
case TrustStateCrossSignedUntrusted:
|
||||
return "cross-signed-untrusted"
|
||||
case TrustStateUnknownDevice:
|
||||
return "unknown-device"
|
||||
case TrustStateForwarded:
|
||||
return "forwarded"
|
||||
case TrustStateCrossSignedTOFU:
|
||||
return "cross-signed-tofu"
|
||||
case TrustStateCrossSignedVerified:
|
||||
return "cross-signed-verified"
|
||||
case TrustStateVerified:
|
||||
return "verified"
|
||||
default:
|
||||
return "invalid"
|
||||
}
|
||||
}
|
||||
224
vendor/maunium.net/go/mautrix/id/userid.go
generated
vendored
Normal file
224
vendor/maunium.net/go/mautrix/id/userid.go
generated
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
// 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 id
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UserID represents a Matrix user ID.
|
||||
// https://matrix.org/docs/spec/appendices#user-identifiers
|
||||
type UserID string
|
||||
|
||||
const UserIDMaxLength = 255
|
||||
|
||||
func NewUserID(localpart, homeserver string) UserID {
|
||||
return UserID(fmt.Sprintf("@%s:%s", localpart, homeserver))
|
||||
}
|
||||
|
||||
func NewEncodedUserID(localpart, homeserver string) UserID {
|
||||
return NewUserID(EncodeUserLocalpart(localpart), homeserver)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidUserID = errors.New("is not a valid user ID")
|
||||
ErrNoncompliantLocalpart = errors.New("contains characters that are not allowed")
|
||||
ErrUserIDTooLong = errors.New("the given user ID is longer than 255 characters")
|
||||
ErrEmptyLocalpart = errors.New("empty localparts are not allowed")
|
||||
)
|
||||
|
||||
// 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
|
||||
err = fmt.Errorf("'%s' %w", userID, ErrInvalidUserID)
|
||||
return
|
||||
}
|
||||
parts := strings.SplitN(string(userID), ":", 2)
|
||||
localpart, homeserver = strings.TrimPrefix(parts[0], "@"), parts[1]
|
||||
return
|
||||
}
|
||||
|
||||
func (userID UserID) Localpart() string {
|
||||
localpart, _, _ := userID.Parse()
|
||||
return localpart
|
||||
}
|
||||
|
||||
func (userID UserID) Homeserver() string {
|
||||
_, homeserver, _ := userID.Parse()
|
||||
return homeserver
|
||||
}
|
||||
|
||||
// URI returns the user ID as a MatrixURI struct, which can then be stringified into a matrix: URI or a matrix.to URL.
|
||||
//
|
||||
// This does not parse or validate the user ID. Use the ParseAndValidate method if you want to ensure the user ID is valid first.
|
||||
func (userID UserID) URI() *MatrixURI {
|
||||
return &MatrixURI{
|
||||
Sigil1: '@',
|
||||
MXID1: string(userID)[1:],
|
||||
}
|
||||
}
|
||||
|
||||
var ValidLocalpartRegex = regexp.MustCompile("^[0-9a-z-.=_/]+$")
|
||||
|
||||
// ValidateUserLocalpart validates a Matrix user ID localpart using the grammar
|
||||
// in https://matrix.org/docs/spec/appendices#user-identifier
|
||||
func ValidateUserLocalpart(localpart string) error {
|
||||
if len(localpart) == 0 {
|
||||
return ErrEmptyLocalpart
|
||||
} else if !ValidLocalpartRegex.MatchString(localpart) {
|
||||
return fmt.Errorf("'%s' %w", localpart, ErrNoncompliantLocalpart)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseAndValidate parses the user ID into the localpart and server name like Parse,
|
||||
// and also validates that the localpart is allowed according to the user identifiers spec.
|
||||
func (userID UserID) ParseAndValidate() (localpart, homeserver string, err error) {
|
||||
localpart, homeserver, err = userID.Parse()
|
||||
if err == nil {
|
||||
err = ValidateUserLocalpart(localpart)
|
||||
}
|
||||
if err == nil && len(userID) > UserIDMaxLength {
|
||||
err = ErrUserIDTooLong
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (userID UserID) ParseAndDecode() (localpart, homeserver string, err error) {
|
||||
localpart, homeserver, err = userID.ParseAndValidate()
|
||||
if err == nil {
|
||||
localpart, err = DecodeUserLocalpart(localpart)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (userID UserID) String() string {
|
||||
return string(userID)
|
||||
}
|
||||
|
||||
const lowerhex = "0123456789abcdef"
|
||||
|
||||
// encode the given byte using quoted-printable encoding (e.g "=2f")
|
||||
// and writes it to the buffer
|
||||
// See https://golang.org/src/mime/quotedprintable/writer.go
|
||||
func encode(buf *bytes.Buffer, b byte) {
|
||||
buf.WriteByte('=')
|
||||
buf.WriteByte(lowerhex[b>>4])
|
||||
buf.WriteByte(lowerhex[b&0x0f])
|
||||
}
|
||||
|
||||
// escape the given alpha character and writes it to the buffer
|
||||
func escape(buf *bytes.Buffer, b byte) {
|
||||
buf.WriteByte('_')
|
||||
if b == '_' {
|
||||
buf.WriteByte('_') // another _
|
||||
} else {
|
||||
buf.WriteByte(b + 0x20) // ASCII shift A-Z to a-z
|
||||
}
|
||||
}
|
||||
|
||||
func shouldEncode(b byte) bool {
|
||||
return b != '-' && b != '.' && b != '_' && !(b >= '0' && b <= '9') && !(b >= 'a' && b <= 'z') && !(b >= 'A' && b <= 'Z')
|
||||
}
|
||||
|
||||
func shouldEscape(b byte) bool {
|
||||
return (b >= 'A' && b <= 'Z') || b == '_'
|
||||
}
|
||||
|
||||
func isValidByte(b byte) bool {
|
||||
return isValidEscapedChar(b) || (b >= '0' && b <= '9') || b == '.' || b == '=' || b == '-'
|
||||
}
|
||||
|
||||
func isValidEscapedChar(b byte) bool {
|
||||
return b == '_' || (b >= 'a' && b <= 'z')
|
||||
}
|
||||
|
||||
// EncodeUserLocalpart encodes the given string into Matrix-compliant user ID localpart form.
|
||||
// See https://spec.matrix.org/v1.2/appendices/#mapping-from-other-character-sets
|
||||
//
|
||||
// This returns a string with only the characters "a-z0-9._=-". The uppercase range A-Z
|
||||
// are encoded using leading underscores ("_"). Characters outside the aforementioned ranges
|
||||
// (including literal underscores ("_") and equals ("=")) are encoded as UTF8 code points (NOT NCRs)
|
||||
// and converted to lower-case hex with a leading "=". For example:
|
||||
//
|
||||
// Alph@Bet_50up => _alph=40_bet=5f50up
|
||||
func EncodeUserLocalpart(str string) string {
|
||||
strBytes := []byte(str)
|
||||
var outputBuffer bytes.Buffer
|
||||
for _, b := range strBytes {
|
||||
if shouldEncode(b) {
|
||||
encode(&outputBuffer, b)
|
||||
} else if shouldEscape(b) {
|
||||
escape(&outputBuffer, b)
|
||||
} else {
|
||||
outputBuffer.WriteByte(b)
|
||||
}
|
||||
}
|
||||
return outputBuffer.String()
|
||||
}
|
||||
|
||||
// DecodeUserLocalpart decodes the given string back into the original input string.
|
||||
// Returns an error if the given string is not a valid user ID localpart encoding.
|
||||
// See https://spec.matrix.org/v1.2/appendices/#mapping-from-other-character-sets
|
||||
//
|
||||
// This decodes quoted-printable bytes back into UTF8, and unescapes casing. For
|
||||
// example:
|
||||
//
|
||||
// _alph=40_bet=5f50up => Alph@Bet_50up
|
||||
//
|
||||
// Returns an error if the input string contains characters outside the
|
||||
// range "a-z0-9._=-", has an invalid quote-printable byte (e.g. not hex), or has
|
||||
// an invalid _ escaped byte (e.g. "_5").
|
||||
func DecodeUserLocalpart(str string) (string, error) {
|
||||
strBytes := []byte(str)
|
||||
var outputBuffer bytes.Buffer
|
||||
for i := 0; i < len(strBytes); i++ {
|
||||
b := strBytes[i]
|
||||
if !isValidByte(b) {
|
||||
return "", fmt.Errorf("Byte pos %d: Invalid byte", i)
|
||||
}
|
||||
|
||||
if b == '_' { // next byte is a-z and should be upper-case or is another _ and should be a literal _
|
||||
if i+1 >= len(strBytes) {
|
||||
return "", fmt.Errorf("Byte pos %d: expected _[a-z_] encoding but ran out of string", i)
|
||||
}
|
||||
if !isValidEscapedChar(strBytes[i+1]) { // invalid escaping
|
||||
return "", fmt.Errorf("Byte pos %d: expected _[a-z_] encoding", i)
|
||||
}
|
||||
if strBytes[i+1] == '_' {
|
||||
outputBuffer.WriteByte('_')
|
||||
} else {
|
||||
outputBuffer.WriteByte(strBytes[i+1] - 0x20) // ASCII shift a-z to A-Z
|
||||
}
|
||||
i++ // skip next byte since we just handled it
|
||||
} else if b == '=' { // next 2 bytes are hex and should be buffered ready to be read as utf8
|
||||
if i+2 >= len(strBytes) {
|
||||
return "", fmt.Errorf("Byte pos: %d: expected quote-printable encoding but ran out of string", i)
|
||||
}
|
||||
dst := make([]byte, 1)
|
||||
_, err := hex.Decode(dst, strBytes[i+1:i+3])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
outputBuffer.WriteByte(dst[0])
|
||||
i += 2 // skip next 2 bytes since we just handled it
|
||||
} else { // pass through
|
||||
outputBuffer.WriteByte(b)
|
||||
}
|
||||
}
|
||||
return outputBuffer.String(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user