mirror of
https://gitlab.com/etke.cc/emm.git
synced 2025-02-08 16:25:47 +00:00
init
This commit is contained in:
commit
eac249819d
55
Makefile
Normal file
55
Makefile
Normal file
@ -0,0 +1,55 @@
|
||||
BUILDFLAGS = -buildmode=pie
|
||||
### CI vars
|
||||
CI_LOGIN_COMMAND = @echo "Not a CI, skip login"
|
||||
CI_REGISTRY_IMAGE ?= registry.gitlab.com/etke.cc/honoroit
|
||||
CI_COMMIT_TAG ?= latest
|
||||
# for main branch it must be set explicitly
|
||||
ifeq ($(CI_COMMIT_TAG), main)
|
||||
CI_COMMIT_TAG = latest
|
||||
endif
|
||||
# login command
|
||||
ifdef CI_JOB_TOKEN
|
||||
CI_LOGIN_COMMAND = @docker login -u gitlab-ci-token -p $(CI_JOB_TOKEN) $(CI_REGISTRY)
|
||||
endif
|
||||
|
||||
# update go dependencies
|
||||
update:
|
||||
go get ./cmd
|
||||
go mod tidy
|
||||
go mod vendor
|
||||
|
||||
mock:
|
||||
-@rm -rf mocks
|
||||
@mockery --all
|
||||
|
||||
# run linter
|
||||
lint:
|
||||
golangci-lint run ./...
|
||||
|
||||
# run linter and fix issues if possible
|
||||
lintfix:
|
||||
golangci-lint run --fix ./...
|
||||
|
||||
# run unit tests
|
||||
test:
|
||||
@go test ${BUILDFLAGS} -coverprofile=cover.out ./...
|
||||
@go tool cover -func=cover.out
|
||||
-@rm -f cover.out
|
||||
|
||||
# run honoroit, note: make doesn't understand exit code 130 and sets it == 1
|
||||
run:
|
||||
@go run ${BUILDFLAGS} ./cmd || exit 0
|
||||
|
||||
# build honoroit
|
||||
build:
|
||||
go build ${BUILDFLAGS} -v -o honoroit -ldflags "-X main.version=${CI_COMMIT_TAG}" ./cmd
|
||||
|
||||
# CI: docker login
|
||||
login:
|
||||
@echo "trying to login to docker registry..."
|
||||
$(CI_LOGIN_COMMAND)
|
||||
|
||||
# docker build
|
||||
docker:
|
||||
docker buildx create --use
|
||||
docker buildx build --platform linux/arm/v7,linux/arm64/v8,linux/amd64 --push -t ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} .
|
14
README.md
Normal file
14
README.md
Normal file
@ -0,0 +1,14 @@
|
||||
# emm: Export Matrix Messages
|
||||
|
||||
A CLI tool that joins the room and exports last N messages to the file you specified.
|
||||
|
||||
## TODO
|
||||
|
||||
* setup the repo properly
|
||||
* add docs
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
emm -hs hs.url -u user -p pass -r "#room:hs.url" -t contrib/hugo-post-template.md -o /tmp/%s.md
|
||||
```
|
53
cmd/cmd.go
Normal file
53
cmd/cmd.go
Normal file
@ -0,0 +1,53 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"gitlab.com/etke.cc/emm/export"
|
||||
"gitlab.com/etke.cc/emm/flags"
|
||||
"gitlab.com/etke.cc/emm/matrix"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
var cfg *flags.Config
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
cfg, err = flags.Parse()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resolve()
|
||||
|
||||
err = matrix.Init(*cfg.HS, *cfg.Login, *cfg.Password, cfg.RoomID, cfg.RoomAlias)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
messages, err := matrix.Messages(*cfg.Limit)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = export.Run(*cfg.Template, *cfg.Output, messages)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func resolve() {
|
||||
// Resolve homeserver
|
||||
hs, err := matrix.ResolveServer(*cfg.HS)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cfg.HS = &hs
|
||||
|
||||
// Resolve room type
|
||||
alias, err := matrix.IsRoom(*cfg.Room)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if alias {
|
||||
cfg.RoomAlias = id.RoomAlias(*cfg.Room)
|
||||
} else {
|
||||
cfg.RoomID = id.RoomID(*cfg.Room)
|
||||
}
|
||||
}
|
9
contrib/hugo-post-template.md
Normal file
9
contrib/hugo-post-template.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
id: '{{ .ID }}'
|
||||
date: '{{ .CreatedAt }}'
|
||||
title: '{{ .CreatedAt }}'
|
||||
author: '{{ .Author }}'
|
||||
draft: false
|
||||
---
|
||||
|
||||
{{ .Text }}
|
41
export/export.go
Normal file
41
export/export.go
Normal file
@ -0,0 +1,41 @@
|
||||
package export
|
||||
|
||||
import (
|
||||
"text/template"
|
||||
|
||||
"gitlab.com/etke.cc/emm/matrix"
|
||||
)
|
||||
|
||||
// DefaultTemplate text
|
||||
const DefaultTemplate = `
|
||||
id={{ .ID }}
|
||||
author={{ .Author }}
|
||||
text={{ .Text }}
|
||||
html={{ .HTML }}
|
||||
created_at={{ .CreatedAt }}
|
||||
`
|
||||
|
||||
// Run export
|
||||
func Run(templatePath string, output string, messages []*matrix.Message) error {
|
||||
tpl, err := createTemplate(templatePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, message := range messages {
|
||||
err = save(tpl, output, message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func save(tpl *template.Template, path string, message *matrix.Message) error {
|
||||
file, err := getOutput(path, message.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tpl.Execute(file, message)
|
||||
}
|
37
export/output.go
Normal file
37
export/output.go
Normal file
@ -0,0 +1,37 @@
|
||||
package export
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
var outputFileSingle *os.File
|
||||
|
||||
func getOutput(output string, eventID id.EventID) (*os.File, error) {
|
||||
if isMulti(output) {
|
||||
return getOutputMulti(fmt.Sprintf(output, eventID))
|
||||
}
|
||||
|
||||
return getOutputSingle(output)
|
||||
}
|
||||
|
||||
// isMulti check if output is a single file
|
||||
func isMulti(output string) bool {
|
||||
return strings.Contains(output, "%s")
|
||||
}
|
||||
|
||||
func getOutputSingle(output string) (*os.File, error) {
|
||||
var err error
|
||||
if outputFileSingle == nil {
|
||||
outputFileSingle, err = os.OpenFile(output, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||
}
|
||||
|
||||
return outputFileSingle, err
|
||||
}
|
||||
|
||||
func getOutputMulti(output string) (*os.File, error) {
|
||||
return os.OpenFile(output, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
}
|
28
export/template.go
Normal file
28
export/template.go
Normal file
@ -0,0 +1,28 @@
|
||||
package export
|
||||
|
||||
import (
|
||||
"os"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func createTemplate(templatePath string) (*template.Template, error) {
|
||||
var err error
|
||||
templateContent := DefaultTemplate
|
||||
if templatePath != "" {
|
||||
templateContent, err = loadTemplate(templatePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return template.New("emm").Parse(templateContent)
|
||||
}
|
||||
|
||||
func loadTemplate(path string) (string, error) {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(content), nil
|
||||
}
|
75
flags/flags.go
Normal file
75
flags/flags.go
Normal file
@ -0,0 +1,75 @@
|
||||
// Package flags manages command line arguments and flags
|
||||
package flags
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Config from the command line args and flags
|
||||
type Config struct {
|
||||
// HS is matrix homeserver (supports delegation)
|
||||
HS *string
|
||||
// Login is matrix user login
|
||||
Login *string
|
||||
// Password is matrix user password
|
||||
Password *string
|
||||
// Room id or alias (raw)
|
||||
Room *string
|
||||
// Room ID
|
||||
RoomID id.RoomID
|
||||
// RoomAlias
|
||||
RoomAlias id.RoomAlias
|
||||
// Limit of messages
|
||||
Limit *int
|
||||
// Template file
|
||||
Template *string
|
||||
// Output file name. If filename contains %s it will be replaced with event ID (in case of one file per message)
|
||||
Output *string
|
||||
}
|
||||
|
||||
func (cfg *Config) validate() error {
|
||||
if cfg.HS == nil || *cfg.HS == "" {
|
||||
return errors.New("-hs is not set. You must specify homeserver URL")
|
||||
}
|
||||
if cfg.Login == nil || *cfg.Login == "" {
|
||||
return errors.New("-u is not set. You must specify username/login of the matrix user")
|
||||
}
|
||||
if cfg.Password == nil || *cfg.Password == "" {
|
||||
return errors.New("-p is not set. You must specify password of the matrix user")
|
||||
}
|
||||
if cfg.Room == nil || *cfg.Room == "" {
|
||||
return errors.New("-r is not set. You must specify room id or alias")
|
||||
}
|
||||
if cfg.Output == nil || *cfg.Output == "" {
|
||||
return errors.New("-o is not set. You must specify output filename")
|
||||
}
|
||||
if cfg.Limit == nil || *cfg.Limit < 0 {
|
||||
limit := 0
|
||||
cfg.Limit = &limit
|
||||
}
|
||||
if cfg.Template == nil {
|
||||
empty := ""
|
||||
cfg.Template = &empty
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parse command line arguments and flags
|
||||
func Parse() (*Config, error) {
|
||||
cfg := &Config{
|
||||
HS: flag.String("hs", "", "Homeserver URL (supports delegation)"),
|
||||
Login: flag.String("u", "", "Username/Login of the matrix user"),
|
||||
Password: flag.String("p", "", "Password of the matrix user"),
|
||||
Room: flag.String("r", "", "Room ID or alias"),
|
||||
Limit: flag.Int("l", 0, "Messages limit"),
|
||||
Template: flag.String("t", "", "Template file. Default is JSON message struct"),
|
||||
Output: flag.String("o", "", "Output filename. If it contains %s, it will be replaced with event ID (one message per file)"),
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
return cfg, cfg.validate()
|
||||
}
|
11
go.mod
Normal file
11
go.mod
Normal file
@ -0,0 +1,11 @@
|
||||
module gitlab.com/etke.cc/emm
|
||||
|
||||
go 1.17
|
||||
|
||||
require maunium.net/go/mautrix v0.10.9
|
||||
|
||||
require (
|
||||
github.com/btcsuite/btcutil v1.0.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
|
||||
)
|
67
go.sum
Normal file
67
go.sum
Normal file
@ -0,0 +1,67 @@
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
|
||||
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
||||
maunium.net/go/mautrix v0.10.9 h1:Xb2lBpjSoMazsSlvsDEqJnuHZDJpYpxwza2N0w60UV0=
|
||||
maunium.net/go/mautrix v0.10.9/go.mod h1:4XljZZGZiIlpfbQ+Tt2ykjapskJ8a7Z2i9y/+YaceF8=
|
40
matrix/client.go
Normal file
40
matrix/client.go
Normal file
@ -0,0 +1,40 @@
|
||||
package matrix
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
var client *mautrix.Client
|
||||
var room id.RoomID
|
||||
|
||||
// Init matrix client
|
||||
func Init(hs string, login string, password string, roomID id.RoomID, alias id.RoomAlias) error {
|
||||
var err error
|
||||
client, err = mautrix.NewClient(hs, "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = client.Login(&mautrix.ReqLogin{
|
||||
Type: "m.login.password",
|
||||
Identifier: mautrix.UserIdentifier{
|
||||
Type: mautrix.IdentifierTypeUser,
|
||||
User: login,
|
||||
},
|
||||
Password: password,
|
||||
StoreCredentials: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if roomID == "" {
|
||||
roomID, err = resolveAlias(alias)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
room = roomID
|
||||
|
||||
return nil
|
||||
}
|
70
matrix/messages.go
Normal file
70
matrix/messages.go
Normal file
@ -0,0 +1,70 @@
|
||||
package matrix
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Message struct
|
||||
type Message struct {
|
||||
// ID is a matrix event id of the message
|
||||
ID id.EventID
|
||||
// Author is a matrix id of the sender
|
||||
Author id.UserID
|
||||
// Text is the message body in plaintext/markdown format
|
||||
Text string
|
||||
// HTML is the message body in html format
|
||||
HTML string
|
||||
// CreatedAt is a timestamp
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
// Messages of the room
|
||||
// Note on limit - the output slice may be less size than limit you sent in the following cases:
|
||||
// * room contains less messages than limit
|
||||
// * some room messages don't contain body/formatted body
|
||||
func Messages(limit int) ([]*Message, error) {
|
||||
var messages []*Message
|
||||
filter := &mautrix.FilterPart{
|
||||
Types: []event.Type{event.EventMessage},
|
||||
NotTypes: []event.Type{event.EventRedaction, event.EventReaction, event.StateMember},
|
||||
}
|
||||
|
||||
chunks, err := client.Messages(room, "", "", 'b', filter, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, chunk := range chunks.Chunk {
|
||||
message := parseMessage(chunk)
|
||||
if message == nil {
|
||||
continue
|
||||
}
|
||||
messages = append(messages, message)
|
||||
}
|
||||
|
||||
return messages, nil
|
||||
}
|
||||
|
||||
func parseMessage(evt *event.Event) *Message {
|
||||
err := evt.Content.ParseRaw(event.EventMessage)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
content := evt.Content.AsMessage()
|
||||
if content.Body == "" && content.FormattedBody == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Message{
|
||||
ID: evt.ID,
|
||||
Author: evt.Sender,
|
||||
Text: content.Body,
|
||||
HTML: content.FormattedBody,
|
||||
CreatedAt: time.UnixMilli(evt.Timestamp),
|
||||
}
|
||||
}
|
48
matrix/resolve.go
Normal file
48
matrix/resolve.go
Normal file
@ -0,0 +1,48 @@
|
||||
package matrix
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// ResolveServer resolves actual homeserver URL from possible delegated host
|
||||
func ResolveServer(homeserver string) (string, error) {
|
||||
discover, err := mautrix.DiscoverClientAPI(homeserver)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return discover.Homeserver.BaseURL, nil
|
||||
}
|
||||
|
||||
// IsRoom checks if room is valid room alias or room ID. True = alias, False = room ID
|
||||
func IsRoom(room string) (bool, error) {
|
||||
if room == "" {
|
||||
return false, errors.New("room is not set")
|
||||
}
|
||||
|
||||
if strings.LastIndex(room, ":") == -1 {
|
||||
return false, errors.New("not a valid room id or alias")
|
||||
}
|
||||
|
||||
if strings.HasPrefix(room, "#") {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(room, "!") {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, errors.New("not a valid room id or alias")
|
||||
}
|
||||
|
||||
func resolveAlias(alias id.RoomAlias) (id.RoomID, error) {
|
||||
resp, err := client.ResolveAlias(alias)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.RoomID, err
|
||||
}
|
16
vendor/github.com/btcsuite/btcutil/LICENSE
generated
vendored
Normal file
16
vendor/github.com/btcsuite/btcutil/LICENSE
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2013-2017 The btcsuite developers
|
||||
Copyright (c) 2016-2017 The Lightning Network Developers
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
34
vendor/github.com/btcsuite/btcutil/base58/README.md
generated
vendored
Normal file
34
vendor/github.com/btcsuite/btcutil/base58/README.md
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
base58
|
||||
==========
|
||||
|
||||
[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)](https://travis-ci.org/btcsuite/btcutil)
|
||||
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcutil/base58)
|
||||
|
||||
Package base58 provides an API for encoding and decoding to and from the
|
||||
modified base58 encoding. It also provides an API to do Base58Check encoding,
|
||||
as described [here](https://en.bitcoin.it/wiki/Base58Check_encoding).
|
||||
|
||||
A comprehensive suite of tests is provided to ensure proper functionality.
|
||||
|
||||
## Installation and Updating
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcutil/base58
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* [Decode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-Decode)
|
||||
Demonstrates how to decode modified base58 encoded data.
|
||||
* [Encode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-Encode)
|
||||
Demonstrates how to encode data using the modified base58 encoding scheme.
|
||||
* [CheckDecode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-CheckDecode)
|
||||
Demonstrates how to decode Base58Check encoded data.
|
||||
* [CheckEncode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-CheckEncode)
|
||||
Demonstrates how to encode data using the Base58Check encoding scheme.
|
||||
|
||||
## License
|
||||
|
||||
Package base58 is licensed under the [copyfree](http://copyfree.org) ISC
|
||||
License.
|
49
vendor/github.com/btcsuite/btcutil/base58/alphabet.go
generated
vendored
Normal file
49
vendor/github.com/btcsuite/btcutil/base58/alphabet.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// AUTOGENERATED by genalphabet.go; do not edit.
|
||||
|
||||
package base58
|
||||
|
||||
const (
|
||||
// alphabet is the modified base58 alphabet used by Bitcoin.
|
||||
alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
|
||||
alphabetIdx0 = '1'
|
||||
)
|
||||
|
||||
var b58 = [256]byte{
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 255, 255, 255, 255, 255, 255,
|
||||
255, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 255, 17, 18, 19, 20, 21, 255,
|
||||
22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 255, 255, 255, 255, 255,
|
||||
255, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 255, 44, 45, 46,
|
||||
47, 48, 49, 50, 51, 52, 53, 54,
|
||||
55, 56, 57, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
}
|
75
vendor/github.com/btcsuite/btcutil/base58/base58.go
generated
vendored
Normal file
75
vendor/github.com/btcsuite/btcutil/base58/base58.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2013-2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
//go:generate go run genalphabet.go
|
||||
|
||||
var bigRadix = big.NewInt(58)
|
||||
var bigZero = big.NewInt(0)
|
||||
|
||||
// Decode decodes a modified base58 string to a byte slice.
|
||||
func Decode(b string) []byte {
|
||||
answer := big.NewInt(0)
|
||||
j := big.NewInt(1)
|
||||
|
||||
scratch := new(big.Int)
|
||||
for i := len(b) - 1; i >= 0; i-- {
|
||||
tmp := b58[b[i]]
|
||||
if tmp == 255 {
|
||||
return []byte("")
|
||||
}
|
||||
scratch.SetInt64(int64(tmp))
|
||||
scratch.Mul(j, scratch)
|
||||
answer.Add(answer, scratch)
|
||||
j.Mul(j, bigRadix)
|
||||
}
|
||||
|
||||
tmpval := answer.Bytes()
|
||||
|
||||
var numZeros int
|
||||
for numZeros = 0; numZeros < len(b); numZeros++ {
|
||||
if b[numZeros] != alphabetIdx0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
flen := numZeros + len(tmpval)
|
||||
val := make([]byte, flen)
|
||||
copy(val[numZeros:], tmpval)
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
// Encode encodes a byte slice to a modified base58 string.
|
||||
func Encode(b []byte) string {
|
||||
x := new(big.Int)
|
||||
x.SetBytes(b)
|
||||
|
||||
answer := make([]byte, 0, len(b)*136/100)
|
||||
for x.Cmp(bigZero) > 0 {
|
||||
mod := new(big.Int)
|
||||
x.DivMod(x, bigRadix, mod)
|
||||
answer = append(answer, alphabet[mod.Int64()])
|
||||
}
|
||||
|
||||
// leading zero bytes
|
||||
for _, i := range b {
|
||||
if i != 0 {
|
||||
break
|
||||
}
|
||||
answer = append(answer, alphabetIdx0)
|
||||
}
|
||||
|
||||
// reverse
|
||||
alen := len(answer)
|
||||
for i := 0; i < alen/2; i++ {
|
||||
answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
|
||||
}
|
||||
|
||||
return string(answer)
|
||||
}
|
52
vendor/github.com/btcsuite/btcutil/base58/base58check.go
generated
vendored
Normal file
52
vendor/github.com/btcsuite/btcutil/base58/base58check.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2013-2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// ErrChecksum indicates that the checksum of a check-encoded string does not verify against
|
||||
// the checksum.
|
||||
var ErrChecksum = errors.New("checksum error")
|
||||
|
||||
// ErrInvalidFormat indicates that the check-encoded string has an invalid format.
|
||||
var ErrInvalidFormat = errors.New("invalid format: version and/or checksum bytes missing")
|
||||
|
||||
// checksum: first four bytes of sha256^2
|
||||
func checksum(input []byte) (cksum [4]byte) {
|
||||
h := sha256.Sum256(input)
|
||||
h2 := sha256.Sum256(h[:])
|
||||
copy(cksum[:], h2[:4])
|
||||
return
|
||||
}
|
||||
|
||||
// CheckEncode prepends a version byte and appends a four byte checksum.
|
||||
func CheckEncode(input []byte, version byte) string {
|
||||
b := make([]byte, 0, 1+len(input)+4)
|
||||
b = append(b, version)
|
||||
b = append(b, input[:]...)
|
||||
cksum := checksum(b)
|
||||
b = append(b, cksum[:]...)
|
||||
return Encode(b)
|
||||
}
|
||||
|
||||
// CheckDecode decodes a string that was encoded with CheckEncode and verifies the checksum.
|
||||
func CheckDecode(input string) (result []byte, version byte, err error) {
|
||||
decoded := Decode(input)
|
||||
if len(decoded) < 5 {
|
||||
return nil, 0, ErrInvalidFormat
|
||||
}
|
||||
version = decoded[0]
|
||||
var cksum [4]byte
|
||||
copy(cksum[:], decoded[len(decoded)-4:])
|
||||
if checksum(decoded[:len(decoded)-4]) != cksum {
|
||||
return nil, 0, ErrChecksum
|
||||
}
|
||||
payload := decoded[1 : len(decoded)-4]
|
||||
result = append(result, payload...)
|
||||
return
|
||||
}
|
17
vendor/github.com/btcsuite/btcutil/base58/cov_report.sh
generated
vendored
Normal file
17
vendor/github.com/btcsuite/btcutil/base58/cov_report.sh
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script uses gocov to generate a test coverage report.
|
||||
# The gocov tool my be obtained with the following command:
|
||||
# go get github.com/axw/gocov/gocov
|
||||
#
|
||||
# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
|
||||
|
||||
# Check for gocov.
|
||||
type gocov >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo >&2 "This script requires the gocov tool."
|
||||
echo >&2 "You may obtain it with the following command:"
|
||||
echo >&2 "go get github.com/axw/gocov/gocov"
|
||||
exit 1
|
||||
fi
|
||||
gocov test | gocov report
|
29
vendor/github.com/btcsuite/btcutil/base58/doc.go
generated
vendored
Normal file
29
vendor/github.com/btcsuite/btcutil/base58/doc.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package base58 provides an API for working with modified base58 and Base58Check
|
||||
encodings.
|
||||
|
||||
Modified Base58 Encoding
|
||||
|
||||
Standard base58 encoding is similar to standard base64 encoding except, as the
|
||||
name implies, it uses a 58 character alphabet which results in an alphanumeric
|
||||
string and allows some characters which are problematic for humans to be
|
||||
excluded. Due to this, there can be various base58 alphabets.
|
||||
|
||||
The modified base58 alphabet used by Bitcoin, and hence this package, omits the
|
||||
0, O, I, and l characters that look the same in many fonts and are therefore
|
||||
hard to humans to distinguish.
|
||||
|
||||
Base58Check Encoding Scheme
|
||||
|
||||
The Base58Check encoding scheme is primarily used for Bitcoin addresses at the
|
||||
time of this writing, however it can be used to generically encode arbitrary
|
||||
byte arrays into human-readable strings along with a version byte that can be
|
||||
used to differentiate the same payload. For Bitcoin addresses, the extra
|
||||
version is used to differentiate the network of otherwise identical public keys
|
||||
which helps prevent using an address intended for one network on another.
|
||||
*/
|
||||
package base58
|
3
vendor/golang.org/x/crypto/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/crypto/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at https://tip.golang.org/AUTHORS.
|
3
vendor/golang.org/x/crypto/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/crypto/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at https://tip.golang.org/CONTRIBUTORS.
|
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
93
vendor/golang.org/x/crypto/hkdf/hkdf.go
generated
vendored
Normal file
93
vendor/golang.org/x/crypto/hkdf/hkdf.go
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package hkdf implements the HMAC-based Extract-and-Expand Key Derivation
|
||||
// Function (HKDF) as defined in RFC 5869.
|
||||
//
|
||||
// HKDF is a cryptographic key derivation function (KDF) with the goal of
|
||||
// expanding limited input keying material into one or more cryptographically
|
||||
// strong secret keys.
|
||||
package hkdf // import "golang.org/x/crypto/hkdf"
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"errors"
|
||||
"hash"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Extract generates a pseudorandom key for use with Expand from an input secret
|
||||
// and an optional independent salt.
|
||||
//
|
||||
// Only use this function if you need to reuse the extracted key with multiple
|
||||
// Expand invocations and different context values. Most common scenarios,
|
||||
// including the generation of multiple keys, should use New instead.
|
||||
func Extract(hash func() hash.Hash, secret, salt []byte) []byte {
|
||||
if salt == nil {
|
||||
salt = make([]byte, hash().Size())
|
||||
}
|
||||
extractor := hmac.New(hash, salt)
|
||||
extractor.Write(secret)
|
||||
return extractor.Sum(nil)
|
||||
}
|
||||
|
||||
type hkdf struct {
|
||||
expander hash.Hash
|
||||
size int
|
||||
|
||||
info []byte
|
||||
counter byte
|
||||
|
||||
prev []byte
|
||||
buf []byte
|
||||
}
|
||||
|
||||
func (f *hkdf) Read(p []byte) (int, error) {
|
||||
// Check whether enough data can be generated
|
||||
need := len(p)
|
||||
remains := len(f.buf) + int(255-f.counter+1)*f.size
|
||||
if remains < need {
|
||||
return 0, errors.New("hkdf: entropy limit reached")
|
||||
}
|
||||
// Read any leftover from the buffer
|
||||
n := copy(p, f.buf)
|
||||
p = p[n:]
|
||||
|
||||
// Fill the rest of the buffer
|
||||
for len(p) > 0 {
|
||||
f.expander.Reset()
|
||||
f.expander.Write(f.prev)
|
||||
f.expander.Write(f.info)
|
||||
f.expander.Write([]byte{f.counter})
|
||||
f.prev = f.expander.Sum(f.prev[:0])
|
||||
f.counter++
|
||||
|
||||
// Copy the new batch into p
|
||||
f.buf = f.prev
|
||||
n = copy(p, f.buf)
|
||||
p = p[n:]
|
||||
}
|
||||
// Save leftovers for next run
|
||||
f.buf = f.buf[n:]
|
||||
|
||||
return need, nil
|
||||
}
|
||||
|
||||
// Expand returns a Reader, from which keys can be read, using the given
|
||||
// pseudorandom key and optional context info, skipping the extraction step.
|
||||
//
|
||||
// The pseudorandomKey should have been generated by Extract, or be a uniformly
|
||||
// random or pseudorandom cryptographically strong key. See RFC 5869, Section
|
||||
// 3.3. Most common scenarios will want to use New instead.
|
||||
func Expand(hash func() hash.Hash, pseudorandomKey, info []byte) io.Reader {
|
||||
expander := hmac.New(hash, pseudorandomKey)
|
||||
return &hkdf{expander, expander.Size(), info, 1, nil, nil}
|
||||
}
|
||||
|
||||
// New returns a Reader, from which keys can be read, using the given hash,
|
||||
// secret, salt and context info. Salt and info can be nil.
|
||||
func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader {
|
||||
prk := Extract(hash, secret, salt)
|
||||
return Expand(hash, prk, info)
|
||||
}
|
77
vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
generated
vendored
Normal file
77
vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC
|
||||
2898 / PKCS #5 v2.0.
|
||||
|
||||
A key derivation function is useful when encrypting data based on a password
|
||||
or any other not-fully-random data. It uses a pseudorandom function to derive
|
||||
a secure encryption key based on the password.
|
||||
|
||||
While v2.0 of the standard defines only one pseudorandom function to use,
|
||||
HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved
|
||||
Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
|
||||
choose, you can pass the `New` functions from the different SHA packages to
|
||||
pbkdf2.Key.
|
||||
*/
|
||||
package pbkdf2 // import "golang.org/x/crypto/pbkdf2"
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Key derives a key from the password, salt and iteration count, returning a
|
||||
// []byte of length keylen that can be used as cryptographic key. The key is
|
||||
// derived based on the method described as PBKDF2 with the HMAC variant using
|
||||
// the supplied hash function.
|
||||
//
|
||||
// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you
|
||||
// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
|
||||
// doing:
|
||||
//
|
||||
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
|
||||
//
|
||||
// Remember to get a good random salt. At least 8 bytes is recommended by the
|
||||
// RFC.
|
||||
//
|
||||
// Using a higher iteration count will increase the cost of an exhaustive
|
||||
// search but will also make derivation proportionally slower.
|
||||
func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
|
||||
prf := hmac.New(h, password)
|
||||
hashLen := prf.Size()
|
||||
numBlocks := (keyLen + hashLen - 1) / hashLen
|
||||
|
||||
var buf [4]byte
|
||||
dk := make([]byte, 0, numBlocks*hashLen)
|
||||
U := make([]byte, hashLen)
|
||||
for block := 1; block <= numBlocks; block++ {
|
||||
// N.B.: || means concatenation, ^ means XOR
|
||||
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
|
||||
// U_1 = PRF(password, salt || uint(i))
|
||||
prf.Reset()
|
||||
prf.Write(salt)
|
||||
buf[0] = byte(block >> 24)
|
||||
buf[1] = byte(block >> 16)
|
||||
buf[2] = byte(block >> 8)
|
||||
buf[3] = byte(block)
|
||||
prf.Write(buf[:4])
|
||||
dk = prf.Sum(dk)
|
||||
T := dk[len(dk)-hashLen:]
|
||||
copy(U, T)
|
||||
|
||||
// U_n = PRF(password, U_(n-1))
|
||||
for n := 2; n <= iter; n++ {
|
||||
prf.Reset()
|
||||
prf.Write(U)
|
||||
U = U[:0]
|
||||
U = prf.Sum(U)
|
||||
for x := range U {
|
||||
T[x] ^= U[x]
|
||||
}
|
||||
}
|
||||
}
|
||||
return dk[:keyLen]
|
||||
}
|
3
vendor/golang.org/x/net/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/net/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
3
vendor/golang.org/x/net/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/net/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
27
vendor/golang.org/x/net/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/net/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
vendor/golang.org/x/net/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/net/PATENTS
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
78
vendor/golang.org/x/net/html/atom/atom.go
generated
vendored
Normal file
78
vendor/golang.org/x/net/html/atom/atom.go
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package atom provides integer codes (also known as atoms) for a fixed set of
|
||||
// frequently occurring HTML strings: tag names and attribute keys such as "p"
|
||||
// and "id".
|
||||
//
|
||||
// Sharing an atom's name between all elements with the same tag can result in
|
||||
// fewer string allocations when tokenizing and parsing HTML. Integer
|
||||
// comparisons are also generally faster than string comparisons.
|
||||
//
|
||||
// The value of an atom's particular code is not guaranteed to stay the same
|
||||
// between versions of this package. Neither is any ordering guaranteed:
|
||||
// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to
|
||||
// be dense. The only guarantees are that e.g. looking up "div" will yield
|
||||
// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0.
|
||||
package atom // import "golang.org/x/net/html/atom"
|
||||
|
||||
// Atom is an integer code for a string. The zero value maps to "".
|
||||
type Atom uint32
|
||||
|
||||
// String returns the atom's name.
|
||||
func (a Atom) String() string {
|
||||
start := uint32(a >> 8)
|
||||
n := uint32(a & 0xff)
|
||||
if start+n > uint32(len(atomText)) {
|
||||
return ""
|
||||
}
|
||||
return atomText[start : start+n]
|
||||
}
|
||||
|
||||
func (a Atom) string() string {
|
||||
return atomText[a>>8 : a>>8+a&0xff]
|
||||
}
|
||||
|
||||
// fnv computes the FNV hash with an arbitrary starting value h.
|
||||
func fnv(h uint32, s []byte) uint32 {
|
||||
for i := range s {
|
||||
h ^= uint32(s[i])
|
||||
h *= 16777619
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func match(s string, t []byte) bool {
|
||||
for i, c := range t {
|
||||
if s[i] != c {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Lookup returns the atom whose name is s. It returns zero if there is no
|
||||
// such atom. The lookup is case sensitive.
|
||||
func Lookup(s []byte) Atom {
|
||||
if len(s) == 0 || len(s) > maxAtomLen {
|
||||
return 0
|
||||
}
|
||||
h := fnv(hash0, s)
|
||||
if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
|
||||
return a
|
||||
}
|
||||
if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
|
||||
return a
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// String returns a string whose contents are equal to s. In that sense, it is
|
||||
// equivalent to string(s) but may be more efficient.
|
||||
func String(s []byte) string {
|
||||
if a := Lookup(s); a != 0 {
|
||||
return a.String()
|
||||
}
|
||||
return string(s)
|
||||
}
|
783
vendor/golang.org/x/net/html/atom/table.go
generated
vendored
Normal file
783
vendor/golang.org/x/net/html/atom/table.go
generated
vendored
Normal file
@ -0,0 +1,783 @@
|
||||
// Code generated by go generate gen.go; DO NOT EDIT.
|
||||
|
||||
//go:generate go run gen.go
|
||||
|
||||
package atom
|
||||
|
||||
const (
|
||||
A Atom = 0x1
|
||||
Abbr Atom = 0x4
|
||||
Accept Atom = 0x1a06
|
||||
AcceptCharset Atom = 0x1a0e
|
||||
Accesskey Atom = 0x2c09
|
||||
Acronym Atom = 0xaa07
|
||||
Action Atom = 0x27206
|
||||
Address Atom = 0x6f307
|
||||
Align Atom = 0xb105
|
||||
Allowfullscreen Atom = 0x2080f
|
||||
Allowpaymentrequest Atom = 0xc113
|
||||
Allowusermedia Atom = 0xdd0e
|
||||
Alt Atom = 0xf303
|
||||
Annotation Atom = 0x1c90a
|
||||
AnnotationXml Atom = 0x1c90e
|
||||
Applet Atom = 0x31906
|
||||
Area Atom = 0x35604
|
||||
Article Atom = 0x3fc07
|
||||
As Atom = 0x3c02
|
||||
Aside Atom = 0x10705
|
||||
Async Atom = 0xff05
|
||||
Audio Atom = 0x11505
|
||||
Autocomplete Atom = 0x2780c
|
||||
Autofocus Atom = 0x12109
|
||||
Autoplay Atom = 0x13c08
|
||||
B Atom = 0x101
|
||||
Base Atom = 0x3b04
|
||||
Basefont Atom = 0x3b08
|
||||
Bdi Atom = 0xba03
|
||||
Bdo Atom = 0x14b03
|
||||
Bgsound Atom = 0x15e07
|
||||
Big Atom = 0x17003
|
||||
Blink Atom = 0x17305
|
||||
Blockquote Atom = 0x1870a
|
||||
Body Atom = 0x2804
|
||||
Br Atom = 0x202
|
||||
Button Atom = 0x19106
|
||||
Canvas Atom = 0x10306
|
||||
Caption Atom = 0x23107
|
||||
Center Atom = 0x22006
|
||||
Challenge Atom = 0x29b09
|
||||
Charset Atom = 0x2107
|
||||
Checked Atom = 0x47907
|
||||
Cite Atom = 0x19c04
|
||||
Class Atom = 0x56405
|
||||
Code Atom = 0x5c504
|
||||
Col Atom = 0x1ab03
|
||||
Colgroup Atom = 0x1ab08
|
||||
Color Atom = 0x1bf05
|
||||
Cols Atom = 0x1c404
|
||||
Colspan Atom = 0x1c407
|
||||
Command Atom = 0x1d707
|
||||
Content Atom = 0x58b07
|
||||
Contenteditable Atom = 0x58b0f
|
||||
Contextmenu Atom = 0x3800b
|
||||
Controls Atom = 0x1de08
|
||||
Coords Atom = 0x1ea06
|
||||
Crossorigin Atom = 0x1fb0b
|
||||
Data Atom = 0x4a504
|
||||
Datalist Atom = 0x4a508
|
||||
Datetime Atom = 0x2b808
|
||||
Dd Atom = 0x2d702
|
||||
Default Atom = 0x10a07
|
||||
Defer Atom = 0x5c705
|
||||
Del Atom = 0x45203
|
||||
Desc Atom = 0x56104
|
||||
Details Atom = 0x7207
|
||||
Dfn Atom = 0x8703
|
||||
Dialog Atom = 0xbb06
|
||||
Dir Atom = 0x9303
|
||||
Dirname Atom = 0x9307
|
||||
Disabled Atom = 0x16408
|
||||
Div Atom = 0x16b03
|
||||
Dl Atom = 0x5e602
|
||||
Download Atom = 0x46308
|
||||
Draggable Atom = 0x17a09
|
||||
Dropzone Atom = 0x40508
|
||||
Dt Atom = 0x64b02
|
||||
Em Atom = 0x6e02
|
||||
Embed Atom = 0x6e05
|
||||
Enctype Atom = 0x28d07
|
||||
Face Atom = 0x21e04
|
||||
Fieldset Atom = 0x22608
|
||||
Figcaption Atom = 0x22e0a
|
||||
Figure Atom = 0x24806
|
||||
Font Atom = 0x3f04
|
||||
Footer Atom = 0xf606
|
||||
For Atom = 0x25403
|
||||
ForeignObject Atom = 0x2540d
|
||||
Foreignobject Atom = 0x2610d
|
||||
Form Atom = 0x26e04
|
||||
Formaction Atom = 0x26e0a
|
||||
Formenctype Atom = 0x2890b
|
||||
Formmethod Atom = 0x2a40a
|
||||
Formnovalidate Atom = 0x2ae0e
|
||||
Formtarget Atom = 0x2c00a
|
||||
Frame Atom = 0x8b05
|
||||
Frameset Atom = 0x8b08
|
||||
H1 Atom = 0x15c02
|
||||
H2 Atom = 0x2de02
|
||||
H3 Atom = 0x30d02
|
||||
H4 Atom = 0x34502
|
||||
H5 Atom = 0x34f02
|
||||
H6 Atom = 0x64d02
|
||||
Head Atom = 0x33104
|
||||
Header Atom = 0x33106
|
||||
Headers Atom = 0x33107
|
||||
Height Atom = 0x5206
|
||||
Hgroup Atom = 0x2ca06
|
||||
Hidden Atom = 0x2d506
|
||||
High Atom = 0x2db04
|
||||
Hr Atom = 0x15702
|
||||
Href Atom = 0x2e004
|
||||
Hreflang Atom = 0x2e008
|
||||
Html Atom = 0x5604
|
||||
HttpEquiv Atom = 0x2e80a
|
||||
I Atom = 0x601
|
||||
Icon Atom = 0x58a04
|
||||
Id Atom = 0x10902
|
||||
Iframe Atom = 0x2fc06
|
||||
Image Atom = 0x30205
|
||||
Img Atom = 0x30703
|
||||
Input Atom = 0x44b05
|
||||
Inputmode Atom = 0x44b09
|
||||
Ins Atom = 0x20403
|
||||
Integrity Atom = 0x23f09
|
||||
Is Atom = 0x16502
|
||||
Isindex Atom = 0x30f07
|
||||
Ismap Atom = 0x31605
|
||||
Itemid Atom = 0x38b06
|
||||
Itemprop Atom = 0x19d08
|
||||
Itemref Atom = 0x3cd07
|
||||
Itemscope Atom = 0x67109
|
||||
Itemtype Atom = 0x31f08
|
||||
Kbd Atom = 0xb903
|
||||
Keygen Atom = 0x3206
|
||||
Keytype Atom = 0xd607
|
||||
Kind Atom = 0x17704
|
||||
Label Atom = 0x5905
|
||||
Lang Atom = 0x2e404
|
||||
Legend Atom = 0x18106
|
||||
Li Atom = 0xb202
|
||||
Link Atom = 0x17404
|
||||
List Atom = 0x4a904
|
||||
Listing Atom = 0x4a907
|
||||
Loop Atom = 0x5d04
|
||||
Low Atom = 0xc303
|
||||
Main Atom = 0x1004
|
||||
Malignmark Atom = 0xb00a
|
||||
Manifest Atom = 0x6d708
|
||||
Map Atom = 0x31803
|
||||
Mark Atom = 0xb604
|
||||
Marquee Atom = 0x32707
|
||||
Math Atom = 0x32e04
|
||||
Max Atom = 0x33d03
|
||||
Maxlength Atom = 0x33d09
|
||||
Media Atom = 0xe605
|
||||
Mediagroup Atom = 0xe60a
|
||||
Menu Atom = 0x38704
|
||||
Menuitem Atom = 0x38708
|
||||
Meta Atom = 0x4b804
|
||||
Meter Atom = 0x9805
|
||||
Method Atom = 0x2a806
|
||||
Mglyph Atom = 0x30806
|
||||
Mi Atom = 0x34702
|
||||
Min Atom = 0x34703
|
||||
Minlength Atom = 0x34709
|
||||
Mn Atom = 0x2b102
|
||||
Mo Atom = 0xa402
|
||||
Ms Atom = 0x67402
|
||||
Mtext Atom = 0x35105
|
||||
Multiple Atom = 0x35f08
|
||||
Muted Atom = 0x36705
|
||||
Name Atom = 0x9604
|
||||
Nav Atom = 0x1303
|
||||
Nobr Atom = 0x3704
|
||||
Noembed Atom = 0x6c07
|
||||
Noframes Atom = 0x8908
|
||||
Nomodule Atom = 0xa208
|
||||
Nonce Atom = 0x1a605
|
||||
Noscript Atom = 0x21608
|
||||
Novalidate Atom = 0x2b20a
|
||||
Object Atom = 0x26806
|
||||
Ol Atom = 0x13702
|
||||
Onabort Atom = 0x19507
|
||||
Onafterprint Atom = 0x2360c
|
||||
Onautocomplete Atom = 0x2760e
|
||||
Onautocompleteerror Atom = 0x27613
|
||||
Onauxclick Atom = 0x61f0a
|
||||
Onbeforeprint Atom = 0x69e0d
|
||||
Onbeforeunload Atom = 0x6e70e
|
||||
Onblur Atom = 0x56d06
|
||||
Oncancel Atom = 0x11908
|
||||
Oncanplay Atom = 0x14d09
|
||||
Oncanplaythrough Atom = 0x14d10
|
||||
Onchange Atom = 0x41b08
|
||||
Onclick Atom = 0x2f507
|
||||
Onclose Atom = 0x36c07
|
||||
Oncontextmenu Atom = 0x37e0d
|
||||
Oncopy Atom = 0x39106
|
||||
Oncuechange Atom = 0x3970b
|
||||
Oncut Atom = 0x3a205
|
||||
Ondblclick Atom = 0x3a70a
|
||||
Ondrag Atom = 0x3b106
|
||||
Ondragend Atom = 0x3b109
|
||||
Ondragenter Atom = 0x3ba0b
|
||||
Ondragexit Atom = 0x3c50a
|
||||
Ondragleave Atom = 0x3df0b
|
||||
Ondragover Atom = 0x3ea0a
|
||||
Ondragstart Atom = 0x3f40b
|
||||
Ondrop Atom = 0x40306
|
||||
Ondurationchange Atom = 0x41310
|
||||
Onemptied Atom = 0x40a09
|
||||
Onended Atom = 0x42307
|
||||
Onerror Atom = 0x42a07
|
||||
Onfocus Atom = 0x43107
|
||||
Onhashchange Atom = 0x43d0c
|
||||
Oninput Atom = 0x44907
|
||||
Oninvalid Atom = 0x45509
|
||||
Onkeydown Atom = 0x45e09
|
||||
Onkeypress Atom = 0x46b0a
|
||||
Onkeyup Atom = 0x48007
|
||||
Onlanguagechange Atom = 0x48d10
|
||||
Onload Atom = 0x49d06
|
||||
Onloadeddata Atom = 0x49d0c
|
||||
Onloadedmetadata Atom = 0x4b010
|
||||
Onloadend Atom = 0x4c609
|
||||
Onloadstart Atom = 0x4cf0b
|
||||
Onmessage Atom = 0x4da09
|
||||
Onmessageerror Atom = 0x4da0e
|
||||
Onmousedown Atom = 0x4e80b
|
||||
Onmouseenter Atom = 0x4f30c
|
||||
Onmouseleave Atom = 0x4ff0c
|
||||
Onmousemove Atom = 0x50b0b
|
||||
Onmouseout Atom = 0x5160a
|
||||
Onmouseover Atom = 0x5230b
|
||||
Onmouseup Atom = 0x52e09
|
||||
Onmousewheel Atom = 0x53c0c
|
||||
Onoffline Atom = 0x54809
|
||||
Ononline Atom = 0x55108
|
||||
Onpagehide Atom = 0x5590a
|
||||
Onpageshow Atom = 0x5730a
|
||||
Onpaste Atom = 0x57f07
|
||||
Onpause Atom = 0x59a07
|
||||
Onplay Atom = 0x5a406
|
||||
Onplaying Atom = 0x5a409
|
||||
Onpopstate Atom = 0x5ad0a
|
||||
Onprogress Atom = 0x5b70a
|
||||
Onratechange Atom = 0x5cc0c
|
||||
Onrejectionhandled Atom = 0x5d812
|
||||
Onreset Atom = 0x5ea07
|
||||
Onresize Atom = 0x5f108
|
||||
Onscroll Atom = 0x60008
|
||||
Onsecuritypolicyviolation Atom = 0x60819
|
||||
Onseeked Atom = 0x62908
|
||||
Onseeking Atom = 0x63109
|
||||
Onselect Atom = 0x63a08
|
||||
Onshow Atom = 0x64406
|
||||
Onsort Atom = 0x64f06
|
||||
Onstalled Atom = 0x65909
|
||||
Onstorage Atom = 0x66209
|
||||
Onsubmit Atom = 0x66b08
|
||||
Onsuspend Atom = 0x67b09
|
||||
Ontimeupdate Atom = 0x400c
|
||||
Ontoggle Atom = 0x68408
|
||||
Onunhandledrejection Atom = 0x68c14
|
||||
Onunload Atom = 0x6ab08
|
||||
Onvolumechange Atom = 0x6b30e
|
||||
Onwaiting Atom = 0x6c109
|
||||
Onwheel Atom = 0x6ca07
|
||||
Open Atom = 0x1a304
|
||||
Optgroup Atom = 0x5f08
|
||||
Optimum Atom = 0x6d107
|
||||
Option Atom = 0x6e306
|
||||
Output Atom = 0x51d06
|
||||
P Atom = 0xc01
|
||||
Param Atom = 0xc05
|
||||
Pattern Atom = 0x6607
|
||||
Picture Atom = 0x7b07
|
||||
Ping Atom = 0xef04
|
||||
Placeholder Atom = 0x1310b
|
||||
Plaintext Atom = 0x1b209
|
||||
Playsinline Atom = 0x1400b
|
||||
Poster Atom = 0x2cf06
|
||||
Pre Atom = 0x47003
|
||||
Preload Atom = 0x48607
|
||||
Progress Atom = 0x5b908
|
||||
Prompt Atom = 0x53606
|
||||
Public Atom = 0x58606
|
||||
Q Atom = 0xcf01
|
||||
Radiogroup Atom = 0x30a
|
||||
Rb Atom = 0x3a02
|
||||
Readonly Atom = 0x35708
|
||||
Referrerpolicy Atom = 0x3d10e
|
||||
Rel Atom = 0x48703
|
||||
Required Atom = 0x24c08
|
||||
Reversed Atom = 0x8008
|
||||
Rows Atom = 0x9c04
|
||||
Rowspan Atom = 0x9c07
|
||||
Rp Atom = 0x23c02
|
||||
Rt Atom = 0x19a02
|
||||
Rtc Atom = 0x19a03
|
||||
Ruby Atom = 0xfb04
|
||||
S Atom = 0x2501
|
||||
Samp Atom = 0x7804
|
||||
Sandbox Atom = 0x12907
|
||||
Scope Atom = 0x67505
|
||||
Scoped Atom = 0x67506
|
||||
Script Atom = 0x21806
|
||||
Seamless Atom = 0x37108
|
||||
Section Atom = 0x56807
|
||||
Select Atom = 0x63c06
|
||||
Selected Atom = 0x63c08
|
||||
Shape Atom = 0x1e505
|
||||
Size Atom = 0x5f504
|
||||
Sizes Atom = 0x5f505
|
||||
Slot Atom = 0x1ef04
|
||||
Small Atom = 0x20605
|
||||
Sortable Atom = 0x65108
|
||||
Sorted Atom = 0x33706
|
||||
Source Atom = 0x37806
|
||||
Spacer Atom = 0x43706
|
||||
Span Atom = 0x9f04
|
||||
Spellcheck Atom = 0x4740a
|
||||
Src Atom = 0x5c003
|
||||
Srcdoc Atom = 0x5c006
|
||||
Srclang Atom = 0x5f907
|
||||
Srcset Atom = 0x6f906
|
||||
Start Atom = 0x3fa05
|
||||
Step Atom = 0x58304
|
||||
Strike Atom = 0xd206
|
||||
Strong Atom = 0x6dd06
|
||||
Style Atom = 0x6ff05
|
||||
Sub Atom = 0x66d03
|
||||
Summary Atom = 0x70407
|
||||
Sup Atom = 0x70b03
|
||||
Svg Atom = 0x70e03
|
||||
System Atom = 0x71106
|
||||
Tabindex Atom = 0x4be08
|
||||
Table Atom = 0x59505
|
||||
Target Atom = 0x2c406
|
||||
Tbody Atom = 0x2705
|
||||
Td Atom = 0x9202
|
||||
Template Atom = 0x71408
|
||||
Textarea Atom = 0x35208
|
||||
Tfoot Atom = 0xf505
|
||||
Th Atom = 0x15602
|
||||
Thead Atom = 0x33005
|
||||
Time Atom = 0x4204
|
||||
Title Atom = 0x11005
|
||||
Tr Atom = 0xcc02
|
||||
Track Atom = 0x1ba05
|
||||
Translate Atom = 0x1f209
|
||||
Tt Atom = 0x6802
|
||||
Type Atom = 0xd904
|
||||
Typemustmatch Atom = 0x2900d
|
||||
U Atom = 0xb01
|
||||
Ul Atom = 0xa702
|
||||
Updateviacache Atom = 0x460e
|
||||
Usemap Atom = 0x59e06
|
||||
Value Atom = 0x1505
|
||||
Var Atom = 0x16d03
|
||||
Video Atom = 0x2f105
|
||||
Wbr Atom = 0x57c03
|
||||
Width Atom = 0x64905
|
||||
Workertype Atom = 0x71c0a
|
||||
Wrap Atom = 0x72604
|
||||
Xmp Atom = 0x12f03
|
||||
)
|
||||
|
||||
const hash0 = 0x81cdf10e
|
||||
|
||||
const maxAtomLen = 25
|
||||
|
||||
var table = [1 << 9]Atom{
|
||||
0x1: 0xe60a, // mediagroup
|
||||
0x2: 0x2e404, // lang
|
||||
0x4: 0x2c09, // accesskey
|
||||
0x5: 0x8b08, // frameset
|
||||
0x7: 0x63a08, // onselect
|
||||
0x8: 0x71106, // system
|
||||
0xa: 0x64905, // width
|
||||
0xc: 0x2890b, // formenctype
|
||||
0xd: 0x13702, // ol
|
||||
0xe: 0x3970b, // oncuechange
|
||||
0x10: 0x14b03, // bdo
|
||||
0x11: 0x11505, // audio
|
||||
0x12: 0x17a09, // draggable
|
||||
0x14: 0x2f105, // video
|
||||
0x15: 0x2b102, // mn
|
||||
0x16: 0x38704, // menu
|
||||
0x17: 0x2cf06, // poster
|
||||
0x19: 0xf606, // footer
|
||||
0x1a: 0x2a806, // method
|
||||
0x1b: 0x2b808, // datetime
|
||||
0x1c: 0x19507, // onabort
|
||||
0x1d: 0x460e, // updateviacache
|
||||
0x1e: 0xff05, // async
|
||||
0x1f: 0x49d06, // onload
|
||||
0x21: 0x11908, // oncancel
|
||||
0x22: 0x62908, // onseeked
|
||||
0x23: 0x30205, // image
|
||||
0x24: 0x5d812, // onrejectionhandled
|
||||
0x26: 0x17404, // link
|
||||
0x27: 0x51d06, // output
|
||||
0x28: 0x33104, // head
|
||||
0x29: 0x4ff0c, // onmouseleave
|
||||
0x2a: 0x57f07, // onpaste
|
||||
0x2b: 0x5a409, // onplaying
|
||||
0x2c: 0x1c407, // colspan
|
||||
0x2f: 0x1bf05, // color
|
||||
0x30: 0x5f504, // size
|
||||
0x31: 0x2e80a, // http-equiv
|
||||
0x33: 0x601, // i
|
||||
0x34: 0x5590a, // onpagehide
|
||||
0x35: 0x68c14, // onunhandledrejection
|
||||
0x37: 0x42a07, // onerror
|
||||
0x3a: 0x3b08, // basefont
|
||||
0x3f: 0x1303, // nav
|
||||
0x40: 0x17704, // kind
|
||||
0x41: 0x35708, // readonly
|
||||
0x42: 0x30806, // mglyph
|
||||
0x44: 0xb202, // li
|
||||
0x46: 0x2d506, // hidden
|
||||
0x47: 0x70e03, // svg
|
||||
0x48: 0x58304, // step
|
||||
0x49: 0x23f09, // integrity
|
||||
0x4a: 0x58606, // public
|
||||
0x4c: 0x1ab03, // col
|
||||
0x4d: 0x1870a, // blockquote
|
||||
0x4e: 0x34f02, // h5
|
||||
0x50: 0x5b908, // progress
|
||||
0x51: 0x5f505, // sizes
|
||||
0x52: 0x34502, // h4
|
||||
0x56: 0x33005, // thead
|
||||
0x57: 0xd607, // keytype
|
||||
0x58: 0x5b70a, // onprogress
|
||||
0x59: 0x44b09, // inputmode
|
||||
0x5a: 0x3b109, // ondragend
|
||||
0x5d: 0x3a205, // oncut
|
||||
0x5e: 0x43706, // spacer
|
||||
0x5f: 0x1ab08, // colgroup
|
||||
0x62: 0x16502, // is
|
||||
0x65: 0x3c02, // as
|
||||
0x66: 0x54809, // onoffline
|
||||
0x67: 0x33706, // sorted
|
||||
0x69: 0x48d10, // onlanguagechange
|
||||
0x6c: 0x43d0c, // onhashchange
|
||||
0x6d: 0x9604, // name
|
||||
0x6e: 0xf505, // tfoot
|
||||
0x6f: 0x56104, // desc
|
||||
0x70: 0x33d03, // max
|
||||
0x72: 0x1ea06, // coords
|
||||
0x73: 0x30d02, // h3
|
||||
0x74: 0x6e70e, // onbeforeunload
|
||||
0x75: 0x9c04, // rows
|
||||
0x76: 0x63c06, // select
|
||||
0x77: 0x9805, // meter
|
||||
0x78: 0x38b06, // itemid
|
||||
0x79: 0x53c0c, // onmousewheel
|
||||
0x7a: 0x5c006, // srcdoc
|
||||
0x7d: 0x1ba05, // track
|
||||
0x7f: 0x31f08, // itemtype
|
||||
0x82: 0xa402, // mo
|
||||
0x83: 0x41b08, // onchange
|
||||
0x84: 0x33107, // headers
|
||||
0x85: 0x5cc0c, // onratechange
|
||||
0x86: 0x60819, // onsecuritypolicyviolation
|
||||
0x88: 0x4a508, // datalist
|
||||
0x89: 0x4e80b, // onmousedown
|
||||
0x8a: 0x1ef04, // slot
|
||||
0x8b: 0x4b010, // onloadedmetadata
|
||||
0x8c: 0x1a06, // accept
|
||||
0x8d: 0x26806, // object
|
||||
0x91: 0x6b30e, // onvolumechange
|
||||
0x92: 0x2107, // charset
|
||||
0x93: 0x27613, // onautocompleteerror
|
||||
0x94: 0xc113, // allowpaymentrequest
|
||||
0x95: 0x2804, // body
|
||||
0x96: 0x10a07, // default
|
||||
0x97: 0x63c08, // selected
|
||||
0x98: 0x21e04, // face
|
||||
0x99: 0x1e505, // shape
|
||||
0x9b: 0x68408, // ontoggle
|
||||
0x9e: 0x64b02, // dt
|
||||
0x9f: 0xb604, // mark
|
||||
0xa1: 0xb01, // u
|
||||
0xa4: 0x6ab08, // onunload
|
||||
0xa5: 0x5d04, // loop
|
||||
0xa6: 0x16408, // disabled
|
||||
0xaa: 0x42307, // onended
|
||||
0xab: 0xb00a, // malignmark
|
||||
0xad: 0x67b09, // onsuspend
|
||||
0xae: 0x35105, // mtext
|
||||
0xaf: 0x64f06, // onsort
|
||||
0xb0: 0x19d08, // itemprop
|
||||
0xb3: 0x67109, // itemscope
|
||||
0xb4: 0x17305, // blink
|
||||
0xb6: 0x3b106, // ondrag
|
||||
0xb7: 0xa702, // ul
|
||||
0xb8: 0x26e04, // form
|
||||
0xb9: 0x12907, // sandbox
|
||||
0xba: 0x8b05, // frame
|
||||
0xbb: 0x1505, // value
|
||||
0xbc: 0x66209, // onstorage
|
||||
0xbf: 0xaa07, // acronym
|
||||
0xc0: 0x19a02, // rt
|
||||
0xc2: 0x202, // br
|
||||
0xc3: 0x22608, // fieldset
|
||||
0xc4: 0x2900d, // typemustmatch
|
||||
0xc5: 0xa208, // nomodule
|
||||
0xc6: 0x6c07, // noembed
|
||||
0xc7: 0x69e0d, // onbeforeprint
|
||||
0xc8: 0x19106, // button
|
||||
0xc9: 0x2f507, // onclick
|
||||
0xca: 0x70407, // summary
|
||||
0xcd: 0xfb04, // ruby
|
||||
0xce: 0x56405, // class
|
||||
0xcf: 0x3f40b, // ondragstart
|
||||
0xd0: 0x23107, // caption
|
||||
0xd4: 0xdd0e, // allowusermedia
|
||||
0xd5: 0x4cf0b, // onloadstart
|
||||
0xd9: 0x16b03, // div
|
||||
0xda: 0x4a904, // list
|
||||
0xdb: 0x32e04, // math
|
||||
0xdc: 0x44b05, // input
|
||||
0xdf: 0x3ea0a, // ondragover
|
||||
0xe0: 0x2de02, // h2
|
||||
0xe2: 0x1b209, // plaintext
|
||||
0xe4: 0x4f30c, // onmouseenter
|
||||
0xe7: 0x47907, // checked
|
||||
0xe8: 0x47003, // pre
|
||||
0xea: 0x35f08, // multiple
|
||||
0xeb: 0xba03, // bdi
|
||||
0xec: 0x33d09, // maxlength
|
||||
0xed: 0xcf01, // q
|
||||
0xee: 0x61f0a, // onauxclick
|
||||
0xf0: 0x57c03, // wbr
|
||||
0xf2: 0x3b04, // base
|
||||
0xf3: 0x6e306, // option
|
||||
0xf5: 0x41310, // ondurationchange
|
||||
0xf7: 0x8908, // noframes
|
||||
0xf9: 0x40508, // dropzone
|
||||
0xfb: 0x67505, // scope
|
||||
0xfc: 0x8008, // reversed
|
||||
0xfd: 0x3ba0b, // ondragenter
|
||||
0xfe: 0x3fa05, // start
|
||||
0xff: 0x12f03, // xmp
|
||||
0x100: 0x5f907, // srclang
|
||||
0x101: 0x30703, // img
|
||||
0x104: 0x101, // b
|
||||
0x105: 0x25403, // for
|
||||
0x106: 0x10705, // aside
|
||||
0x107: 0x44907, // oninput
|
||||
0x108: 0x35604, // area
|
||||
0x109: 0x2a40a, // formmethod
|
||||
0x10a: 0x72604, // wrap
|
||||
0x10c: 0x23c02, // rp
|
||||
0x10d: 0x46b0a, // onkeypress
|
||||
0x10e: 0x6802, // tt
|
||||
0x110: 0x34702, // mi
|
||||
0x111: 0x36705, // muted
|
||||
0x112: 0xf303, // alt
|
||||
0x113: 0x5c504, // code
|
||||
0x114: 0x6e02, // em
|
||||
0x115: 0x3c50a, // ondragexit
|
||||
0x117: 0x9f04, // span
|
||||
0x119: 0x6d708, // manifest
|
||||
0x11a: 0x38708, // menuitem
|
||||
0x11b: 0x58b07, // content
|
||||
0x11d: 0x6c109, // onwaiting
|
||||
0x11f: 0x4c609, // onloadend
|
||||
0x121: 0x37e0d, // oncontextmenu
|
||||
0x123: 0x56d06, // onblur
|
||||
0x124: 0x3fc07, // article
|
||||
0x125: 0x9303, // dir
|
||||
0x126: 0xef04, // ping
|
||||
0x127: 0x24c08, // required
|
||||
0x128: 0x45509, // oninvalid
|
||||
0x129: 0xb105, // align
|
||||
0x12b: 0x58a04, // icon
|
||||
0x12c: 0x64d02, // h6
|
||||
0x12d: 0x1c404, // cols
|
||||
0x12e: 0x22e0a, // figcaption
|
||||
0x12f: 0x45e09, // onkeydown
|
||||
0x130: 0x66b08, // onsubmit
|
||||
0x131: 0x14d09, // oncanplay
|
||||
0x132: 0x70b03, // sup
|
||||
0x133: 0xc01, // p
|
||||
0x135: 0x40a09, // onemptied
|
||||
0x136: 0x39106, // oncopy
|
||||
0x137: 0x19c04, // cite
|
||||
0x138: 0x3a70a, // ondblclick
|
||||
0x13a: 0x50b0b, // onmousemove
|
||||
0x13c: 0x66d03, // sub
|
||||
0x13d: 0x48703, // rel
|
||||
0x13e: 0x5f08, // optgroup
|
||||
0x142: 0x9c07, // rowspan
|
||||
0x143: 0x37806, // source
|
||||
0x144: 0x21608, // noscript
|
||||
0x145: 0x1a304, // open
|
||||
0x146: 0x20403, // ins
|
||||
0x147: 0x2540d, // foreignObject
|
||||
0x148: 0x5ad0a, // onpopstate
|
||||
0x14a: 0x28d07, // enctype
|
||||
0x14b: 0x2760e, // onautocomplete
|
||||
0x14c: 0x35208, // textarea
|
||||
0x14e: 0x2780c, // autocomplete
|
||||
0x14f: 0x15702, // hr
|
||||
0x150: 0x1de08, // controls
|
||||
0x151: 0x10902, // id
|
||||
0x153: 0x2360c, // onafterprint
|
||||
0x155: 0x2610d, // foreignobject
|
||||
0x156: 0x32707, // marquee
|
||||
0x157: 0x59a07, // onpause
|
||||
0x158: 0x5e602, // dl
|
||||
0x159: 0x5206, // height
|
||||
0x15a: 0x34703, // min
|
||||
0x15b: 0x9307, // dirname
|
||||
0x15c: 0x1f209, // translate
|
||||
0x15d: 0x5604, // html
|
||||
0x15e: 0x34709, // minlength
|
||||
0x15f: 0x48607, // preload
|
||||
0x160: 0x71408, // template
|
||||
0x161: 0x3df0b, // ondragleave
|
||||
0x162: 0x3a02, // rb
|
||||
0x164: 0x5c003, // src
|
||||
0x165: 0x6dd06, // strong
|
||||
0x167: 0x7804, // samp
|
||||
0x168: 0x6f307, // address
|
||||
0x169: 0x55108, // ononline
|
||||
0x16b: 0x1310b, // placeholder
|
||||
0x16c: 0x2c406, // target
|
||||
0x16d: 0x20605, // small
|
||||
0x16e: 0x6ca07, // onwheel
|
||||
0x16f: 0x1c90a, // annotation
|
||||
0x170: 0x4740a, // spellcheck
|
||||
0x171: 0x7207, // details
|
||||
0x172: 0x10306, // canvas
|
||||
0x173: 0x12109, // autofocus
|
||||
0x174: 0xc05, // param
|
||||
0x176: 0x46308, // download
|
||||
0x177: 0x45203, // del
|
||||
0x178: 0x36c07, // onclose
|
||||
0x179: 0xb903, // kbd
|
||||
0x17a: 0x31906, // applet
|
||||
0x17b: 0x2e004, // href
|
||||
0x17c: 0x5f108, // onresize
|
||||
0x17e: 0x49d0c, // onloadeddata
|
||||
0x180: 0xcc02, // tr
|
||||
0x181: 0x2c00a, // formtarget
|
||||
0x182: 0x11005, // title
|
||||
0x183: 0x6ff05, // style
|
||||
0x184: 0xd206, // strike
|
||||
0x185: 0x59e06, // usemap
|
||||
0x186: 0x2fc06, // iframe
|
||||
0x187: 0x1004, // main
|
||||
0x189: 0x7b07, // picture
|
||||
0x18c: 0x31605, // ismap
|
||||
0x18e: 0x4a504, // data
|
||||
0x18f: 0x5905, // label
|
||||
0x191: 0x3d10e, // referrerpolicy
|
||||
0x192: 0x15602, // th
|
||||
0x194: 0x53606, // prompt
|
||||
0x195: 0x56807, // section
|
||||
0x197: 0x6d107, // optimum
|
||||
0x198: 0x2db04, // high
|
||||
0x199: 0x15c02, // h1
|
||||
0x19a: 0x65909, // onstalled
|
||||
0x19b: 0x16d03, // var
|
||||
0x19c: 0x4204, // time
|
||||
0x19e: 0x67402, // ms
|
||||
0x19f: 0x33106, // header
|
||||
0x1a0: 0x4da09, // onmessage
|
||||
0x1a1: 0x1a605, // nonce
|
||||
0x1a2: 0x26e0a, // formaction
|
||||
0x1a3: 0x22006, // center
|
||||
0x1a4: 0x3704, // nobr
|
||||
0x1a5: 0x59505, // table
|
||||
0x1a6: 0x4a907, // listing
|
||||
0x1a7: 0x18106, // legend
|
||||
0x1a9: 0x29b09, // challenge
|
||||
0x1aa: 0x24806, // figure
|
||||
0x1ab: 0xe605, // media
|
||||
0x1ae: 0xd904, // type
|
||||
0x1af: 0x3f04, // font
|
||||
0x1b0: 0x4da0e, // onmessageerror
|
||||
0x1b1: 0x37108, // seamless
|
||||
0x1b2: 0x8703, // dfn
|
||||
0x1b3: 0x5c705, // defer
|
||||
0x1b4: 0xc303, // low
|
||||
0x1b5: 0x19a03, // rtc
|
||||
0x1b6: 0x5230b, // onmouseover
|
||||
0x1b7: 0x2b20a, // novalidate
|
||||
0x1b8: 0x71c0a, // workertype
|
||||
0x1ba: 0x3cd07, // itemref
|
||||
0x1bd: 0x1, // a
|
||||
0x1be: 0x31803, // map
|
||||
0x1bf: 0x400c, // ontimeupdate
|
||||
0x1c0: 0x15e07, // bgsound
|
||||
0x1c1: 0x3206, // keygen
|
||||
0x1c2: 0x2705, // tbody
|
||||
0x1c5: 0x64406, // onshow
|
||||
0x1c7: 0x2501, // s
|
||||
0x1c8: 0x6607, // pattern
|
||||
0x1cc: 0x14d10, // oncanplaythrough
|
||||
0x1ce: 0x2d702, // dd
|
||||
0x1cf: 0x6f906, // srcset
|
||||
0x1d0: 0x17003, // big
|
||||
0x1d2: 0x65108, // sortable
|
||||
0x1d3: 0x48007, // onkeyup
|
||||
0x1d5: 0x5a406, // onplay
|
||||
0x1d7: 0x4b804, // meta
|
||||
0x1d8: 0x40306, // ondrop
|
||||
0x1da: 0x60008, // onscroll
|
||||
0x1db: 0x1fb0b, // crossorigin
|
||||
0x1dc: 0x5730a, // onpageshow
|
||||
0x1dd: 0x4, // abbr
|
||||
0x1de: 0x9202, // td
|
||||
0x1df: 0x58b0f, // contenteditable
|
||||
0x1e0: 0x27206, // action
|
||||
0x1e1: 0x1400b, // playsinline
|
||||
0x1e2: 0x43107, // onfocus
|
||||
0x1e3: 0x2e008, // hreflang
|
||||
0x1e5: 0x5160a, // onmouseout
|
||||
0x1e6: 0x5ea07, // onreset
|
||||
0x1e7: 0x13c08, // autoplay
|
||||
0x1e8: 0x63109, // onseeking
|
||||
0x1ea: 0x67506, // scoped
|
||||
0x1ec: 0x30a, // radiogroup
|
||||
0x1ee: 0x3800b, // contextmenu
|
||||
0x1ef: 0x52e09, // onmouseup
|
||||
0x1f1: 0x2ca06, // hgroup
|
||||
0x1f2: 0x2080f, // allowfullscreen
|
||||
0x1f3: 0x4be08, // tabindex
|
||||
0x1f6: 0x30f07, // isindex
|
||||
0x1f7: 0x1a0e, // accept-charset
|
||||
0x1f8: 0x2ae0e, // formnovalidate
|
||||
0x1fb: 0x1c90e, // annotation-xml
|
||||
0x1fc: 0x6e05, // embed
|
||||
0x1fd: 0x21806, // script
|
||||
0x1fe: 0xbb06, // dialog
|
||||
0x1ff: 0x1d707, // command
|
||||
}
|
||||
|
||||
const atomText = "abbradiogrouparamainavalueaccept-charsetbodyaccesskeygenobrb" +
|
||||
"asefontimeupdateviacacheightmlabelooptgroupatternoembedetail" +
|
||||
"sampictureversedfnoframesetdirnameterowspanomoduleacronymali" +
|
||||
"gnmarkbdialogallowpaymentrequestrikeytypeallowusermediagroup" +
|
||||
"ingaltfooterubyasyncanvasidefaultitleaudioncancelautofocusan" +
|
||||
"dboxmplaceholderautoplaysinlinebdoncanplaythrough1bgsoundisa" +
|
||||
"bledivarbigblinkindraggablegendblockquotebuttonabortcitempro" +
|
||||
"penoncecolgrouplaintextrackcolorcolspannotation-xmlcommandco" +
|
||||
"ntrolshapecoordslotranslatecrossoriginsmallowfullscreenoscri" +
|
||||
"ptfacenterfieldsetfigcaptionafterprintegrityfigurequiredfore" +
|
||||
"ignObjectforeignobjectformactionautocompleteerrorformenctype" +
|
||||
"mustmatchallengeformmethodformnovalidatetimeformtargethgroup" +
|
||||
"osterhiddenhigh2hreflanghttp-equivideonclickiframeimageimgly" +
|
||||
"ph3isindexismappletitemtypemarqueematheadersortedmaxlength4m" +
|
||||
"inlength5mtextareadonlymultiplemutedoncloseamlessourceoncont" +
|
||||
"extmenuitemidoncopyoncuechangeoncutondblclickondragendondrag" +
|
||||
"enterondragexitemreferrerpolicyondragleaveondragoverondragst" +
|
||||
"articleondropzonemptiedondurationchangeonendedonerroronfocus" +
|
||||
"paceronhashchangeoninputmodeloninvalidonkeydownloadonkeypres" +
|
||||
"spellcheckedonkeyupreloadonlanguagechangeonloadeddatalisting" +
|
||||
"onloadedmetadatabindexonloadendonloadstartonmessageerroronmo" +
|
||||
"usedownonmouseenteronmouseleaveonmousemoveonmouseoutputonmou" +
|
||||
"seoveronmouseupromptonmousewheelonofflineononlineonpagehides" +
|
||||
"classectionbluronpageshowbronpastepublicontenteditableonpaus" +
|
||||
"emaponplayingonpopstateonprogressrcdocodeferonratechangeonre" +
|
||||
"jectionhandledonresetonresizesrclangonscrollonsecuritypolicy" +
|
||||
"violationauxclickonseekedonseekingonselectedonshowidth6onsor" +
|
||||
"tableonstalledonstorageonsubmitemscopedonsuspendontoggleonun" +
|
||||
"handledrejectionbeforeprintonunloadonvolumechangeonwaitingon" +
|
||||
"wheeloptimumanifestrongoptionbeforeunloaddressrcsetstylesumm" +
|
||||
"arysupsvgsystemplateworkertypewrap"
|
111
vendor/golang.org/x/net/html/const.go
generated
vendored
Normal file
111
vendor/golang.org/x/net/html/const.go
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package html
|
||||
|
||||
// Section 12.2.4.2 of the HTML5 specification says "The following elements
|
||||
// have varying levels of special parsing rules".
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
|
||||
var isSpecialElementMap = map[string]bool{
|
||||
"address": true,
|
||||
"applet": true,
|
||||
"area": true,
|
||||
"article": true,
|
||||
"aside": true,
|
||||
"base": true,
|
||||
"basefont": true,
|
||||
"bgsound": true,
|
||||
"blockquote": true,
|
||||
"body": true,
|
||||
"br": true,
|
||||
"button": true,
|
||||
"caption": true,
|
||||
"center": true,
|
||||
"col": true,
|
||||
"colgroup": true,
|
||||
"dd": true,
|
||||
"details": true,
|
||||
"dir": true,
|
||||
"div": true,
|
||||
"dl": true,
|
||||
"dt": true,
|
||||
"embed": true,
|
||||
"fieldset": true,
|
||||
"figcaption": true,
|
||||
"figure": true,
|
||||
"footer": true,
|
||||
"form": true,
|
||||
"frame": true,
|
||||
"frameset": true,
|
||||
"h1": true,
|
||||
"h2": true,
|
||||
"h3": true,
|
||||
"h4": true,
|
||||
"h5": true,
|
||||
"h6": true,
|
||||
"head": true,
|
||||
"header": true,
|
||||
"hgroup": true,
|
||||
"hr": true,
|
||||
"html": true,
|
||||
"iframe": true,
|
||||
"img": true,
|
||||
"input": true,
|
||||
"keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
|
||||
"li": true,
|
||||
"link": true,
|
||||
"listing": true,
|
||||
"main": true,
|
||||
"marquee": true,
|
||||
"menu": true,
|
||||
"meta": true,
|
||||
"nav": true,
|
||||
"noembed": true,
|
||||
"noframes": true,
|
||||
"noscript": true,
|
||||
"object": true,
|
||||
"ol": true,
|
||||
"p": true,
|
||||
"param": true,
|
||||
"plaintext": true,
|
||||
"pre": true,
|
||||
"script": true,
|
||||
"section": true,
|
||||
"select": true,
|
||||
"source": true,
|
||||
"style": true,
|
||||
"summary": true,
|
||||
"table": true,
|
||||
"tbody": true,
|
||||
"td": true,
|
||||
"template": true,
|
||||
"textarea": true,
|
||||
"tfoot": true,
|
||||
"th": true,
|
||||
"thead": true,
|
||||
"title": true,
|
||||
"tr": true,
|
||||
"track": true,
|
||||
"ul": true,
|
||||
"wbr": true,
|
||||
"xmp": true,
|
||||
}
|
||||
|
||||
func isSpecialElement(element *Node) bool {
|
||||
switch element.Namespace {
|
||||
case "", "html":
|
||||
return isSpecialElementMap[element.Data]
|
||||
case "math":
|
||||
switch element.Data {
|
||||
case "mi", "mo", "mn", "ms", "mtext", "annotation-xml":
|
||||
return true
|
||||
}
|
||||
case "svg":
|
||||
switch element.Data {
|
||||
case "foreignObject", "desc", "title":
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
106
vendor/golang.org/x/net/html/doc.go
generated
vendored
Normal file
106
vendor/golang.org/x/net/html/doc.go
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package html implements an HTML5-compliant tokenizer and parser.
|
||||
|
||||
Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
|
||||
caller's responsibility to ensure that r provides UTF-8 encoded HTML.
|
||||
|
||||
z := html.NewTokenizer(r)
|
||||
|
||||
Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
|
||||
which parses the next token and returns its type, or an error:
|
||||
|
||||
for {
|
||||
tt := z.Next()
|
||||
if tt == html.ErrorToken {
|
||||
// ...
|
||||
return ...
|
||||
}
|
||||
// Process the current token.
|
||||
}
|
||||
|
||||
There are two APIs for retrieving the current token. The high-level API is to
|
||||
call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
|
||||
allow optionally calling Raw after Next but before Token, Text, TagName, or
|
||||
TagAttr. In EBNF notation, the valid call sequence per token is:
|
||||
|
||||
Next {Raw} [ Token | Text | TagName {TagAttr} ]
|
||||
|
||||
Token returns an independent data structure that completely describes a token.
|
||||
Entities (such as "<") are unescaped, tag names and attribute keys are
|
||||
lower-cased, and attributes are collected into a []Attribute. For example:
|
||||
|
||||
for {
|
||||
if z.Next() == html.ErrorToken {
|
||||
// Returning io.EOF indicates success.
|
||||
return z.Err()
|
||||
}
|
||||
emitToken(z.Token())
|
||||
}
|
||||
|
||||
The low-level API performs fewer allocations and copies, but the contents of
|
||||
the []byte values returned by Text, TagName and TagAttr may change on the next
|
||||
call to Next. For example, to extract an HTML page's anchor text:
|
||||
|
||||
depth := 0
|
||||
for {
|
||||
tt := z.Next()
|
||||
switch tt {
|
||||
case html.ErrorToken:
|
||||
return z.Err()
|
||||
case html.TextToken:
|
||||
if depth > 0 {
|
||||
// emitBytes should copy the []byte it receives,
|
||||
// if it doesn't process it immediately.
|
||||
emitBytes(z.Text())
|
||||
}
|
||||
case html.StartTagToken, html.EndTagToken:
|
||||
tn, _ := z.TagName()
|
||||
if len(tn) == 1 && tn[0] == 'a' {
|
||||
if tt == html.StartTagToken {
|
||||
depth++
|
||||
} else {
|
||||
depth--
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Parsing is done by calling Parse with an io.Reader, which returns the root of
|
||||
the parse tree (the document element) as a *Node. It is the caller's
|
||||
responsibility to ensure that the Reader provides UTF-8 encoded HTML. For
|
||||
example, to process each anchor node in depth-first order:
|
||||
|
||||
doc, err := html.Parse(r)
|
||||
if err != nil {
|
||||
// ...
|
||||
}
|
||||
var f func(*html.Node)
|
||||
f = func(n *html.Node) {
|
||||
if n.Type == html.ElementNode && n.Data == "a" {
|
||||
// Do something with n...
|
||||
}
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
f(c)
|
||||
}
|
||||
}
|
||||
f(doc)
|
||||
|
||||
The relevant specifications include:
|
||||
https://html.spec.whatwg.org/multipage/syntax.html and
|
||||
https://html.spec.whatwg.org/multipage/syntax.html#tokenization
|
||||
*/
|
||||
package html // import "golang.org/x/net/html"
|
||||
|
||||
// The tokenization algorithm implemented by this package is not a line-by-line
|
||||
// transliteration of the relatively verbose state-machine in the WHATWG
|
||||
// specification. A more direct approach is used instead, where the program
|
||||
// counter implies the state, such as whether it is tokenizing a tag or a text
|
||||
// node. Specification compliance is verified by checking expected and actual
|
||||
// outputs over a test suite rather than aiming for algorithmic fidelity.
|
||||
|
||||
// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
|
||||
// TODO(nigeltao): How does parsing interact with a JavaScript engine?
|
156
vendor/golang.org/x/net/html/doctype.go
generated
vendored
Normal file
156
vendor/golang.org/x/net/html/doctype.go
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package html
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// parseDoctype parses the data from a DoctypeToken into a name,
|
||||
// public identifier, and system identifier. It returns a Node whose Type
|
||||
// is DoctypeNode, whose Data is the name, and which has attributes
|
||||
// named "system" and "public" for the two identifiers if they were present.
|
||||
// quirks is whether the document should be parsed in "quirks mode".
|
||||
func parseDoctype(s string) (n *Node, quirks bool) {
|
||||
n = &Node{Type: DoctypeNode}
|
||||
|
||||
// Find the name.
|
||||
space := strings.IndexAny(s, whitespace)
|
||||
if space == -1 {
|
||||
space = len(s)
|
||||
}
|
||||
n.Data = s[:space]
|
||||
// The comparison to "html" is case-sensitive.
|
||||
if n.Data != "html" {
|
||||
quirks = true
|
||||
}
|
||||
n.Data = strings.ToLower(n.Data)
|
||||
s = strings.TrimLeft(s[space:], whitespace)
|
||||
|
||||
if len(s) < 6 {
|
||||
// It can't start with "PUBLIC" or "SYSTEM".
|
||||
// Ignore the rest of the string.
|
||||
return n, quirks || s != ""
|
||||
}
|
||||
|
||||
key := strings.ToLower(s[:6])
|
||||
s = s[6:]
|
||||
for key == "public" || key == "system" {
|
||||
s = strings.TrimLeft(s, whitespace)
|
||||
if s == "" {
|
||||
break
|
||||
}
|
||||
quote := s[0]
|
||||
if quote != '"' && quote != '\'' {
|
||||
break
|
||||
}
|
||||
s = s[1:]
|
||||
q := strings.IndexRune(s, rune(quote))
|
||||
var id string
|
||||
if q == -1 {
|
||||
id = s
|
||||
s = ""
|
||||
} else {
|
||||
id = s[:q]
|
||||
s = s[q+1:]
|
||||
}
|
||||
n.Attr = append(n.Attr, Attribute{Key: key, Val: id})
|
||||
if key == "public" {
|
||||
key = "system"
|
||||
} else {
|
||||
key = ""
|
||||
}
|
||||
}
|
||||
|
||||
if key != "" || s != "" {
|
||||
quirks = true
|
||||
} else if len(n.Attr) > 0 {
|
||||
if n.Attr[0].Key == "public" {
|
||||
public := strings.ToLower(n.Attr[0].Val)
|
||||
switch public {
|
||||
case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html":
|
||||
quirks = true
|
||||
default:
|
||||
for _, q := range quirkyIDs {
|
||||
if strings.HasPrefix(public, q) {
|
||||
quirks = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// The following two public IDs only cause quirks mode if there is no system ID.
|
||||
if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") ||
|
||||
strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) {
|
||||
quirks = true
|
||||
}
|
||||
}
|
||||
if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" &&
|
||||
strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" {
|
||||
quirks = true
|
||||
}
|
||||
}
|
||||
|
||||
return n, quirks
|
||||
}
|
||||
|
||||
// quirkyIDs is a list of public doctype identifiers that cause a document
|
||||
// to be interpreted in quirks mode. The identifiers should be in lower case.
|
||||
var quirkyIDs = []string{
|
||||
"+//silmaril//dtd html pro v0r11 19970101//",
|
||||
"-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
|
||||
"-//as//dtd html 3.0 aswedit + extensions//",
|
||||
"-//ietf//dtd html 2.0 level 1//",
|
||||
"-//ietf//dtd html 2.0 level 2//",
|
||||
"-//ietf//dtd html 2.0 strict level 1//",
|
||||
"-//ietf//dtd html 2.0 strict level 2//",
|
||||
"-//ietf//dtd html 2.0 strict//",
|
||||
"-//ietf//dtd html 2.0//",
|
||||
"-//ietf//dtd html 2.1e//",
|
||||
"-//ietf//dtd html 3.0//",
|
||||
"-//ietf//dtd html 3.2 final//",
|
||||
"-//ietf//dtd html 3.2//",
|
||||
"-//ietf//dtd html 3//",
|
||||
"-//ietf//dtd html level 0//",
|
||||
"-//ietf//dtd html level 1//",
|
||||
"-//ietf//dtd html level 2//",
|
||||
"-//ietf//dtd html level 3//",
|
||||
"-//ietf//dtd html strict level 0//",
|
||||
"-//ietf//dtd html strict level 1//",
|
||||
"-//ietf//dtd html strict level 2//",
|
||||
"-//ietf//dtd html strict level 3//",
|
||||
"-//ietf//dtd html strict//",
|
||||
"-//ietf//dtd html//",
|
||||
"-//metrius//dtd metrius presentational//",
|
||||
"-//microsoft//dtd internet explorer 2.0 html strict//",
|
||||
"-//microsoft//dtd internet explorer 2.0 html//",
|
||||
"-//microsoft//dtd internet explorer 2.0 tables//",
|
||||
"-//microsoft//dtd internet explorer 3.0 html strict//",
|
||||
"-//microsoft//dtd internet explorer 3.0 html//",
|
||||
"-//microsoft//dtd internet explorer 3.0 tables//",
|
||||
"-//netscape comm. corp.//dtd html//",
|
||||
"-//netscape comm. corp.//dtd strict html//",
|
||||
"-//o'reilly and associates//dtd html 2.0//",
|
||||
"-//o'reilly and associates//dtd html extended 1.0//",
|
||||
"-//o'reilly and associates//dtd html extended relaxed 1.0//",
|
||||
"-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
|
||||
"-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
|
||||
"-//spyglass//dtd html 2.0 extended//",
|
||||
"-//sq//dtd html 2.0 hotmetal + extensions//",
|
||||
"-//sun microsystems corp.//dtd hotjava html//",
|
||||
"-//sun microsystems corp.//dtd hotjava strict html//",
|
||||
"-//w3c//dtd html 3 1995-03-24//",
|
||||
"-//w3c//dtd html 3.2 draft//",
|
||||
"-//w3c//dtd html 3.2 final//",
|
||||
"-//w3c//dtd html 3.2//",
|
||||
"-//w3c//dtd html 3.2s draft//",
|
||||
"-//w3c//dtd html 4.0 frameset//",
|
||||
"-//w3c//dtd html 4.0 transitional//",
|
||||
"-//w3c//dtd html experimental 19960712//",
|
||||
"-//w3c//dtd html experimental 970421//",
|
||||
"-//w3c//dtd w3 html//",
|
||||
"-//w3o//dtd w3 html 3.0//",
|
||||
"-//webtechs//dtd mozilla html 2.0//",
|
||||
"-//webtechs//dtd mozilla html//",
|
||||
}
|
2253
vendor/golang.org/x/net/html/entity.go
generated
vendored
Normal file
2253
vendor/golang.org/x/net/html/entity.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
258
vendor/golang.org/x/net/html/escape.go
generated
vendored
Normal file
258
vendor/golang.org/x/net/html/escape.go
generated
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package html
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// These replacements permit compatibility with old numeric entities that
|
||||
// assumed Windows-1252 encoding.
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
|
||||
var replacementTable = [...]rune{
|
||||
'\u20AC', // First entry is what 0x80 should be replaced with.
|
||||
'\u0081',
|
||||
'\u201A',
|
||||
'\u0192',
|
||||
'\u201E',
|
||||
'\u2026',
|
||||
'\u2020',
|
||||
'\u2021',
|
||||
'\u02C6',
|
||||
'\u2030',
|
||||
'\u0160',
|
||||
'\u2039',
|
||||
'\u0152',
|
||||
'\u008D',
|
||||
'\u017D',
|
||||
'\u008F',
|
||||
'\u0090',
|
||||
'\u2018',
|
||||
'\u2019',
|
||||
'\u201C',
|
||||
'\u201D',
|
||||
'\u2022',
|
||||
'\u2013',
|
||||
'\u2014',
|
||||
'\u02DC',
|
||||
'\u2122',
|
||||
'\u0161',
|
||||
'\u203A',
|
||||
'\u0153',
|
||||
'\u009D',
|
||||
'\u017E',
|
||||
'\u0178', // Last entry is 0x9F.
|
||||
// 0x00->'\uFFFD' is handled programmatically.
|
||||
// 0x0D->'\u000D' is a no-op.
|
||||
}
|
||||
|
||||
// unescapeEntity reads an entity like "<" from b[src:] and writes the
|
||||
// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
|
||||
// Precondition: b[src] == '&' && dst <= src.
|
||||
// attribute should be true if parsing an attribute value.
|
||||
func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
|
||||
|
||||
// i starts at 1 because we already know that s[0] == '&'.
|
||||
i, s := 1, b[src:]
|
||||
|
||||
if len(s) <= 1 {
|
||||
b[dst] = b[src]
|
||||
return dst + 1, src + 1
|
||||
}
|
||||
|
||||
if s[i] == '#' {
|
||||
if len(s) <= 3 { // We need to have at least "&#.".
|
||||
b[dst] = b[src]
|
||||
return dst + 1, src + 1
|
||||
}
|
||||
i++
|
||||
c := s[i]
|
||||
hex := false
|
||||
if c == 'x' || c == 'X' {
|
||||
hex = true
|
||||
i++
|
||||
}
|
||||
|
||||
x := '\x00'
|
||||
for i < len(s) {
|
||||
c = s[i]
|
||||
i++
|
||||
if hex {
|
||||
if '0' <= c && c <= '9' {
|
||||
x = 16*x + rune(c) - '0'
|
||||
continue
|
||||
} else if 'a' <= c && c <= 'f' {
|
||||
x = 16*x + rune(c) - 'a' + 10
|
||||
continue
|
||||
} else if 'A' <= c && c <= 'F' {
|
||||
x = 16*x + rune(c) - 'A' + 10
|
||||
continue
|
||||
}
|
||||
} else if '0' <= c && c <= '9' {
|
||||
x = 10*x + rune(c) - '0'
|
||||
continue
|
||||
}
|
||||
if c != ';' {
|
||||
i--
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if i <= 3 { // No characters matched.
|
||||
b[dst] = b[src]
|
||||
return dst + 1, src + 1
|
||||
}
|
||||
|
||||
if 0x80 <= x && x <= 0x9F {
|
||||
// Replace characters from Windows-1252 with UTF-8 equivalents.
|
||||
x = replacementTable[x-0x80]
|
||||
} else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF {
|
||||
// Replace invalid characters with the replacement character.
|
||||
x = '\uFFFD'
|
||||
}
|
||||
|
||||
return dst + utf8.EncodeRune(b[dst:], x), src + i
|
||||
}
|
||||
|
||||
// Consume the maximum number of characters possible, with the
|
||||
// consumed characters matching one of the named references.
|
||||
|
||||
for i < len(s) {
|
||||
c := s[i]
|
||||
i++
|
||||
// Lower-cased characters are more common in entities, so we check for them first.
|
||||
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
|
||||
continue
|
||||
}
|
||||
if c != ';' {
|
||||
i--
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
entityName := string(s[1:i])
|
||||
if entityName == "" {
|
||||
// No-op.
|
||||
} else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
|
||||
// No-op.
|
||||
} else if x := entity[entityName]; x != 0 {
|
||||
return dst + utf8.EncodeRune(b[dst:], x), src + i
|
||||
} else if x := entity2[entityName]; x[0] != 0 {
|
||||
dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
|
||||
return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
|
||||
} else if !attribute {
|
||||
maxLen := len(entityName) - 1
|
||||
if maxLen > longestEntityWithoutSemicolon {
|
||||
maxLen = longestEntityWithoutSemicolon
|
||||
}
|
||||
for j := maxLen; j > 1; j-- {
|
||||
if x := entity[entityName[:j]]; x != 0 {
|
||||
return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dst1, src1 = dst+i, src+i
|
||||
copy(b[dst:dst1], b[src:src1])
|
||||
return dst1, src1
|
||||
}
|
||||
|
||||
// unescape unescapes b's entities in-place, so that "a<b" becomes "a<b".
|
||||
// attribute should be true if parsing an attribute value.
|
||||
func unescape(b []byte, attribute bool) []byte {
|
||||
for i, c := range b {
|
||||
if c == '&' {
|
||||
dst, src := unescapeEntity(b, i, i, attribute)
|
||||
for src < len(b) {
|
||||
c := b[src]
|
||||
if c == '&' {
|
||||
dst, src = unescapeEntity(b, dst, src, attribute)
|
||||
} else {
|
||||
b[dst] = c
|
||||
dst, src = dst+1, src+1
|
||||
}
|
||||
}
|
||||
return b[0:dst]
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// lower lower-cases the A-Z bytes in b in-place, so that "aBc" becomes "abc".
|
||||
func lower(b []byte) []byte {
|
||||
for i, c := range b {
|
||||
if 'A' <= c && c <= 'Z' {
|
||||
b[i] = c + 'a' - 'A'
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
const escapedChars = "&'<>\"\r"
|
||||
|
||||
func escape(w writer, s string) error {
|
||||
i := strings.IndexAny(s, escapedChars)
|
||||
for i != -1 {
|
||||
if _, err := w.WriteString(s[:i]); err != nil {
|
||||
return err
|
||||
}
|
||||
var esc string
|
||||
switch s[i] {
|
||||
case '&':
|
||||
esc = "&"
|
||||
case '\'':
|
||||
// "'" is shorter than "'" and apos was not in HTML until HTML5.
|
||||
esc = "'"
|
||||
case '<':
|
||||
esc = "<"
|
||||
case '>':
|
||||
esc = ">"
|
||||
case '"':
|
||||
// """ is shorter than """.
|
||||
esc = """
|
||||
case '\r':
|
||||
esc = " "
|
||||
default:
|
||||
panic("unrecognized escape character")
|
||||
}
|
||||
s = s[i+1:]
|
||||
if _, err := w.WriteString(esc); err != nil {
|
||||
return err
|
||||
}
|
||||
i = strings.IndexAny(s, escapedChars)
|
||||
}
|
||||
_, err := w.WriteString(s)
|
||||
return err
|
||||
}
|
||||
|
||||
// EscapeString escapes special characters like "<" to become "<". It
|
||||
// escapes only five such characters: <, >, &, ' and ".
|
||||
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
|
||||
// always true.
|
||||
func EscapeString(s string) string {
|
||||
if strings.IndexAny(s, escapedChars) == -1 {
|
||||
return s
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
escape(&buf, s)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// UnescapeString unescapes entities like "<" to become "<". It unescapes a
|
||||
// larger range of entities than EscapeString escapes. For example, "á"
|
||||
// unescapes to "á", as does "á" and "&xE1;".
|
||||
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
|
||||
// always true.
|
||||
func UnescapeString(s string) string {
|
||||
for _, c := range s {
|
||||
if c == '&' {
|
||||
return string(unescape([]byte(s), false))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
222
vendor/golang.org/x/net/html/foreign.go
generated
vendored
Normal file
222
vendor/golang.org/x/net/html/foreign.go
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package html
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func adjustAttributeNames(aa []Attribute, nameMap map[string]string) {
|
||||
for i := range aa {
|
||||
if newName, ok := nameMap[aa[i].Key]; ok {
|
||||
aa[i].Key = newName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func adjustForeignAttributes(aa []Attribute) {
|
||||
for i, a := range aa {
|
||||
if a.Key == "" || a.Key[0] != 'x' {
|
||||
continue
|
||||
}
|
||||
switch a.Key {
|
||||
case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show",
|
||||
"xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink":
|
||||
j := strings.Index(a.Key, ":")
|
||||
aa[i].Namespace = a.Key[:j]
|
||||
aa[i].Key = a.Key[j+1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func htmlIntegrationPoint(n *Node) bool {
|
||||
if n.Type != ElementNode {
|
||||
return false
|
||||
}
|
||||
switch n.Namespace {
|
||||
case "math":
|
||||
if n.Data == "annotation-xml" {
|
||||
for _, a := range n.Attr {
|
||||
if a.Key == "encoding" {
|
||||
val := strings.ToLower(a.Val)
|
||||
if val == "text/html" || val == "application/xhtml+xml" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case "svg":
|
||||
switch n.Data {
|
||||
case "desc", "foreignObject", "title":
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func mathMLTextIntegrationPoint(n *Node) bool {
|
||||
if n.Namespace != "math" {
|
||||
return false
|
||||
}
|
||||
switch n.Data {
|
||||
case "mi", "mo", "mn", "ms", "mtext":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Section 12.2.6.5.
|
||||
var breakout = map[string]bool{
|
||||
"b": true,
|
||||
"big": true,
|
||||
"blockquote": true,
|
||||
"body": true,
|
||||
"br": true,
|
||||
"center": true,
|
||||
"code": true,
|
||||
"dd": true,
|
||||
"div": true,
|
||||
"dl": true,
|
||||
"dt": true,
|
||||
"em": true,
|
||||
"embed": true,
|
||||
"h1": true,
|
||||
"h2": true,
|
||||
"h3": true,
|
||||
"h4": true,
|
||||
"h5": true,
|
||||
"h6": true,
|
||||
"head": true,
|
||||
"hr": true,
|
||||
"i": true,
|
||||
"img": true,
|
||||
"li": true,
|
||||
"listing": true,
|
||||
"menu": true,
|
||||
"meta": true,
|
||||
"nobr": true,
|
||||
"ol": true,
|
||||
"p": true,
|
||||
"pre": true,
|
||||
"ruby": true,
|
||||
"s": true,
|
||||
"small": true,
|
||||
"span": true,
|
||||
"strong": true,
|
||||
"strike": true,
|
||||
"sub": true,
|
||||
"sup": true,
|
||||
"table": true,
|
||||
"tt": true,
|
||||
"u": true,
|
||||
"ul": true,
|
||||
"var": true,
|
||||
}
|
||||
|
||||
// Section 12.2.6.5.
|
||||
var svgTagNameAdjustments = map[string]string{
|
||||
"altglyph": "altGlyph",
|
||||
"altglyphdef": "altGlyphDef",
|
||||
"altglyphitem": "altGlyphItem",
|
||||
"animatecolor": "animateColor",
|
||||
"animatemotion": "animateMotion",
|
||||
"animatetransform": "animateTransform",
|
||||
"clippath": "clipPath",
|
||||
"feblend": "feBlend",
|
||||
"fecolormatrix": "feColorMatrix",
|
||||
"fecomponenttransfer": "feComponentTransfer",
|
||||
"fecomposite": "feComposite",
|
||||
"feconvolvematrix": "feConvolveMatrix",
|
||||
"fediffuselighting": "feDiffuseLighting",
|
||||
"fedisplacementmap": "feDisplacementMap",
|
||||
"fedistantlight": "feDistantLight",
|
||||
"feflood": "feFlood",
|
||||
"fefunca": "feFuncA",
|
||||
"fefuncb": "feFuncB",
|
||||
"fefuncg": "feFuncG",
|
||||
"fefuncr": "feFuncR",
|
||||
"fegaussianblur": "feGaussianBlur",
|
||||
"feimage": "feImage",
|
||||
"femerge": "feMerge",
|
||||
"femergenode": "feMergeNode",
|
||||
"femorphology": "feMorphology",
|
||||
"feoffset": "feOffset",
|
||||
"fepointlight": "fePointLight",
|
||||
"fespecularlighting": "feSpecularLighting",
|
||||
"fespotlight": "feSpotLight",
|
||||
"fetile": "feTile",
|
||||
"feturbulence": "feTurbulence",
|
||||
"foreignobject": "foreignObject",
|
||||
"glyphref": "glyphRef",
|
||||
"lineargradient": "linearGradient",
|
||||
"radialgradient": "radialGradient",
|
||||
"textpath": "textPath",
|
||||
}
|
||||
|
||||
// Section 12.2.6.1
|
||||
var mathMLAttributeAdjustments = map[string]string{
|
||||
"definitionurl": "definitionURL",
|
||||
}
|
||||
|
||||
var svgAttributeAdjustments = map[string]string{
|
||||
"attributename": "attributeName",
|
||||
"attributetype": "attributeType",
|
||||
"basefrequency": "baseFrequency",
|
||||
"baseprofile": "baseProfile",
|
||||
"calcmode": "calcMode",
|
||||
"clippathunits": "clipPathUnits",
|
||||
"diffuseconstant": "diffuseConstant",
|
||||
"edgemode": "edgeMode",
|
||||
"filterunits": "filterUnits",
|
||||
"glyphref": "glyphRef",
|
||||
"gradienttransform": "gradientTransform",
|
||||
"gradientunits": "gradientUnits",
|
||||
"kernelmatrix": "kernelMatrix",
|
||||
"kernelunitlength": "kernelUnitLength",
|
||||
"keypoints": "keyPoints",
|
||||
"keysplines": "keySplines",
|
||||
"keytimes": "keyTimes",
|
||||
"lengthadjust": "lengthAdjust",
|
||||
"limitingconeangle": "limitingConeAngle",
|
||||
"markerheight": "markerHeight",
|
||||
"markerunits": "markerUnits",
|
||||
"markerwidth": "markerWidth",
|
||||
"maskcontentunits": "maskContentUnits",
|
||||
"maskunits": "maskUnits",
|
||||
"numoctaves": "numOctaves",
|
||||
"pathlength": "pathLength",
|
||||
"patterncontentunits": "patternContentUnits",
|
||||
"patterntransform": "patternTransform",
|
||||
"patternunits": "patternUnits",
|
||||
"pointsatx": "pointsAtX",
|
||||
"pointsaty": "pointsAtY",
|
||||
"pointsatz": "pointsAtZ",
|
||||
"preservealpha": "preserveAlpha",
|
||||
"preserveaspectratio": "preserveAspectRatio",
|
||||
"primitiveunits": "primitiveUnits",
|
||||
"refx": "refX",
|
||||
"refy": "refY",
|
||||
"repeatcount": "repeatCount",
|
||||
"repeatdur": "repeatDur",
|
||||
"requiredextensions": "requiredExtensions",
|
||||
"requiredfeatures": "requiredFeatures",
|
||||
"specularconstant": "specularConstant",
|
||||
"specularexponent": "specularExponent",
|
||||
"spreadmethod": "spreadMethod",
|
||||
"startoffset": "startOffset",
|
||||
"stddeviation": "stdDeviation",
|
||||
"stitchtiles": "stitchTiles",
|
||||
"surfacescale": "surfaceScale",
|
||||
"systemlanguage": "systemLanguage",
|
||||
"tablevalues": "tableValues",
|
||||
"targetx": "targetX",
|
||||
"targety": "targetY",
|
||||
"textlength": "textLength",
|
||||
"viewbox": "viewBox",
|
||||
"viewtarget": "viewTarget",
|
||||
"xchannelselector": "xChannelSelector",
|
||||
"ychannelselector": "yChannelSelector",
|
||||
"zoomandpan": "zoomAndPan",
|
||||
}
|
225
vendor/golang.org/x/net/html/node.go
generated
vendored
Normal file
225
vendor/golang.org/x/net/html/node.go
generated
vendored
Normal file
@ -0,0 +1,225 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package html
|
||||
|
||||
import (
|
||||
"golang.org/x/net/html/atom"
|
||||
)
|
||||
|
||||
// A NodeType is the type of a Node.
|
||||
type NodeType uint32
|
||||
|
||||
const (
|
||||
ErrorNode NodeType = iota
|
||||
TextNode
|
||||
DocumentNode
|
||||
ElementNode
|
||||
CommentNode
|
||||
DoctypeNode
|
||||
// RawNode nodes are not returned by the parser, but can be part of the
|
||||
// Node tree passed to func Render to insert raw HTML (without escaping).
|
||||
// If so, this package makes no guarantee that the rendered HTML is secure
|
||||
// (from e.g. Cross Site Scripting attacks) or well-formed.
|
||||
RawNode
|
||||
scopeMarkerNode
|
||||
)
|
||||
|
||||
// Section 12.2.4.3 says "The markers are inserted when entering applet,
|
||||
// object, marquee, template, td, th, and caption elements, and are used
|
||||
// to prevent formatting from "leaking" into applet, object, marquee,
|
||||
// template, td, th, and caption elements".
|
||||
var scopeMarker = Node{Type: scopeMarkerNode}
|
||||
|
||||
// A Node consists of a NodeType and some Data (tag name for element nodes,
|
||||
// content for text) and are part of a tree of Nodes. Element nodes may also
|
||||
// have a Namespace and contain a slice of Attributes. Data is unescaped, so
|
||||
// that it looks like "a<b" rather than "a<b". For element nodes, DataAtom
|
||||
// is the atom for Data, or zero if Data is not a known tag name.
|
||||
//
|
||||
// An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace.
|
||||
// Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and
|
||||
// "svg" is short for "http://www.w3.org/2000/svg".
|
||||
type Node struct {
|
||||
Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node
|
||||
|
||||
Type NodeType
|
||||
DataAtom atom.Atom
|
||||
Data string
|
||||
Namespace string
|
||||
Attr []Attribute
|
||||
}
|
||||
|
||||
// InsertBefore inserts newChild as a child of n, immediately before oldChild
|
||||
// in the sequence of n's children. oldChild may be nil, in which case newChild
|
||||
// is appended to the end of n's children.
|
||||
//
|
||||
// It will panic if newChild already has a parent or siblings.
|
||||
func (n *Node) InsertBefore(newChild, oldChild *Node) {
|
||||
if newChild.Parent != nil || newChild.PrevSibling != nil || newChild.NextSibling != nil {
|
||||
panic("html: InsertBefore called for an attached child Node")
|
||||
}
|
||||
var prev, next *Node
|
||||
if oldChild != nil {
|
||||
prev, next = oldChild.PrevSibling, oldChild
|
||||
} else {
|
||||
prev = n.LastChild
|
||||
}
|
||||
if prev != nil {
|
||||
prev.NextSibling = newChild
|
||||
} else {
|
||||
n.FirstChild = newChild
|
||||
}
|
||||
if next != nil {
|
||||
next.PrevSibling = newChild
|
||||
} else {
|
||||
n.LastChild = newChild
|
||||
}
|
||||
newChild.Parent = n
|
||||
newChild.PrevSibling = prev
|
||||
newChild.NextSibling = next
|
||||
}
|
||||
|
||||
// AppendChild adds a node c as a child of n.
|
||||
//
|
||||
// It will panic if c already has a parent or siblings.
|
||||
func (n *Node) AppendChild(c *Node) {
|
||||
if c.Parent != nil || c.PrevSibling != nil || c.NextSibling != nil {
|
||||
panic("html: AppendChild called for an attached child Node")
|
||||
}
|
||||
last := n.LastChild
|
||||
if last != nil {
|
||||
last.NextSibling = c
|
||||
} else {
|
||||
n.FirstChild = c
|
||||
}
|
||||
n.LastChild = c
|
||||
c.Parent = n
|
||||
c.PrevSibling = last
|
||||
}
|
||||
|
||||
// RemoveChild removes a node c that is a child of n. Afterwards, c will have
|
||||
// no parent and no siblings.
|
||||
//
|
||||
// It will panic if c's parent is not n.
|
||||
func (n *Node) RemoveChild(c *Node) {
|
||||
if c.Parent != n {
|
||||
panic("html: RemoveChild called for a non-child Node")
|
||||
}
|
||||
if n.FirstChild == c {
|
||||
n.FirstChild = c.NextSibling
|
||||
}
|
||||
if c.NextSibling != nil {
|
||||
c.NextSibling.PrevSibling = c.PrevSibling
|
||||
}
|
||||
if n.LastChild == c {
|
||||
n.LastChild = c.PrevSibling
|
||||
}
|
||||
if c.PrevSibling != nil {
|
||||
c.PrevSibling.NextSibling = c.NextSibling
|
||||
}
|
||||
c.Parent = nil
|
||||
c.PrevSibling = nil
|
||||
c.NextSibling = nil
|
||||
}
|
||||
|
||||
// reparentChildren reparents all of src's child nodes to dst.
|
||||
func reparentChildren(dst, src *Node) {
|
||||
for {
|
||||
child := src.FirstChild
|
||||
if child == nil {
|
||||
break
|
||||
}
|
||||
src.RemoveChild(child)
|
||||
dst.AppendChild(child)
|
||||
}
|
||||
}
|
||||
|
||||
// clone returns a new node with the same type, data and attributes.
|
||||
// The clone has no parent, no siblings and no children.
|
||||
func (n *Node) clone() *Node {
|
||||
m := &Node{
|
||||
Type: n.Type,
|
||||
DataAtom: n.DataAtom,
|
||||
Data: n.Data,
|
||||
Attr: make([]Attribute, len(n.Attr)),
|
||||
}
|
||||
copy(m.Attr, n.Attr)
|
||||
return m
|
||||
}
|
||||
|
||||
// nodeStack is a stack of nodes.
|
||||
type nodeStack []*Node
|
||||
|
||||
// pop pops the stack. It will panic if s is empty.
|
||||
func (s *nodeStack) pop() *Node {
|
||||
i := len(*s)
|
||||
n := (*s)[i-1]
|
||||
*s = (*s)[:i-1]
|
||||
return n
|
||||
}
|
||||
|
||||
// top returns the most recently pushed node, or nil if s is empty.
|
||||
func (s *nodeStack) top() *Node {
|
||||
if i := len(*s); i > 0 {
|
||||
return (*s)[i-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// index returns the index of the top-most occurrence of n in the stack, or -1
|
||||
// if n is not present.
|
||||
func (s *nodeStack) index(n *Node) int {
|
||||
for i := len(*s) - 1; i >= 0; i-- {
|
||||
if (*s)[i] == n {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// contains returns whether a is within s.
|
||||
func (s *nodeStack) contains(a atom.Atom) bool {
|
||||
for _, n := range *s {
|
||||
if n.DataAtom == a && n.Namespace == "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// insert inserts a node at the given index.
|
||||
func (s *nodeStack) insert(i int, n *Node) {
|
||||
(*s) = append(*s, nil)
|
||||
copy((*s)[i+1:], (*s)[i:])
|
||||
(*s)[i] = n
|
||||
}
|
||||
|
||||
// remove removes a node from the stack. It is a no-op if n is not present.
|
||||
func (s *nodeStack) remove(n *Node) {
|
||||
i := s.index(n)
|
||||
if i == -1 {
|
||||
return
|
||||
}
|
||||
copy((*s)[i:], (*s)[i+1:])
|
||||
j := len(*s) - 1
|
||||
(*s)[j] = nil
|
||||
*s = (*s)[:j]
|
||||
}
|
||||
|
||||
type insertionModeStack []insertionMode
|
||||
|
||||
func (s *insertionModeStack) pop() (im insertionMode) {
|
||||
i := len(*s)
|
||||
im = (*s)[i-1]
|
||||
*s = (*s)[:i-1]
|
||||
return im
|
||||
}
|
||||
|
||||
func (s *insertionModeStack) top() insertionMode {
|
||||
if i := len(*s); i > 0 {
|
||||
return (*s)[i-1]
|
||||
}
|
||||
return nil
|
||||
}
|
2460
vendor/golang.org/x/net/html/parse.go
generated
vendored
Normal file
2460
vendor/golang.org/x/net/html/parse.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
273
vendor/golang.org/x/net/html/render.go
generated
vendored
Normal file
273
vendor/golang.org/x/net/html/render.go
generated
vendored
Normal file
@ -0,0 +1,273 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package html
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type writer interface {
|
||||
io.Writer
|
||||
io.ByteWriter
|
||||
WriteString(string) (int, error)
|
||||
}
|
||||
|
||||
// Render renders the parse tree n to the given writer.
|
||||
//
|
||||
// Rendering is done on a 'best effort' basis: calling Parse on the output of
|
||||
// Render will always result in something similar to the original tree, but it
|
||||
// is not necessarily an exact clone unless the original tree was 'well-formed'.
|
||||
// 'Well-formed' is not easily specified; the HTML5 specification is
|
||||
// complicated.
|
||||
//
|
||||
// Calling Parse on arbitrary input typically results in a 'well-formed' parse
|
||||
// tree. However, it is possible for Parse to yield a 'badly-formed' parse tree.
|
||||
// For example, in a 'well-formed' parse tree, no <a> element is a child of
|
||||
// another <a> element: parsing "<a><a>" results in two sibling elements.
|
||||
// Similarly, in a 'well-formed' parse tree, no <a> element is a child of a
|
||||
// <table> element: parsing "<p><table><a>" results in a <p> with two sibling
|
||||
// children; the <a> is reparented to the <table>'s parent. However, calling
|
||||
// Parse on "<a><table><a>" does not return an error, but the result has an <a>
|
||||
// element with an <a> child, and is therefore not 'well-formed'.
|
||||
//
|
||||
// Programmatically constructed trees are typically also 'well-formed', but it
|
||||
// is possible to construct a tree that looks innocuous but, when rendered and
|
||||
// re-parsed, results in a different tree. A simple example is that a solitary
|
||||
// text node would become a tree containing <html>, <head> and <body> elements.
|
||||
// Another example is that the programmatic equivalent of "a<head>b</head>c"
|
||||
// becomes "<html><head><head/><body>abc</body></html>".
|
||||
func Render(w io.Writer, n *Node) error {
|
||||
if x, ok := w.(writer); ok {
|
||||
return render(x, n)
|
||||
}
|
||||
buf := bufio.NewWriter(w)
|
||||
if err := render(buf, n); err != nil {
|
||||
return err
|
||||
}
|
||||
return buf.Flush()
|
||||
}
|
||||
|
||||
// plaintextAbort is returned from render1 when a <plaintext> element
|
||||
// has been rendered. No more end tags should be rendered after that.
|
||||
var plaintextAbort = errors.New("html: internal error (plaintext abort)")
|
||||
|
||||
func render(w writer, n *Node) error {
|
||||
err := render1(w, n)
|
||||
if err == plaintextAbort {
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func render1(w writer, n *Node) error {
|
||||
// Render non-element nodes; these are the easy cases.
|
||||
switch n.Type {
|
||||
case ErrorNode:
|
||||
return errors.New("html: cannot render an ErrorNode node")
|
||||
case TextNode:
|
||||
return escape(w, n.Data)
|
||||
case DocumentNode:
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if err := render1(w, c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case ElementNode:
|
||||
// No-op.
|
||||
case CommentNode:
|
||||
if _, err := w.WriteString("<!--"); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(n.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString("-->"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
case DoctypeNode:
|
||||
if _, err := w.WriteString("<!DOCTYPE "); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(n.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
if n.Attr != nil {
|
||||
var p, s string
|
||||
for _, a := range n.Attr {
|
||||
switch a.Key {
|
||||
case "public":
|
||||
p = a.Val
|
||||
case "system":
|
||||
s = a.Val
|
||||
}
|
||||
}
|
||||
if p != "" {
|
||||
if _, err := w.WriteString(" PUBLIC "); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeQuoted(w, p); err != nil {
|
||||
return err
|
||||
}
|
||||
if s != "" {
|
||||
if err := w.WriteByte(' '); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeQuoted(w, s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if s != "" {
|
||||
if _, err := w.WriteString(" SYSTEM "); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeQuoted(w, s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return w.WriteByte('>')
|
||||
case RawNode:
|
||||
_, err := w.WriteString(n.Data)
|
||||
return err
|
||||
default:
|
||||
return errors.New("html: unknown node type")
|
||||
}
|
||||
|
||||
// Render the <xxx> opening tag.
|
||||
if err := w.WriteByte('<'); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(n.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, a := range n.Attr {
|
||||
if err := w.WriteByte(' '); err != nil {
|
||||
return err
|
||||
}
|
||||
if a.Namespace != "" {
|
||||
if _, err := w.WriteString(a.Namespace); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte(':'); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := w.WriteString(a.Key); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(`="`); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := escape(w, a.Val); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte('"'); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if voidElements[n.Data] {
|
||||
if n.FirstChild != nil {
|
||||
return fmt.Errorf("html: void element <%s> has child nodes", n.Data)
|
||||
}
|
||||
_, err := w.WriteString("/>")
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte('>'); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add initial newline where there is danger of a newline beging ignored.
|
||||
if c := n.FirstChild; c != nil && c.Type == TextNode && strings.HasPrefix(c.Data, "\n") {
|
||||
switch n.Data {
|
||||
case "pre", "listing", "textarea":
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render any child nodes.
|
||||
switch n.Data {
|
||||
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if c.Type == TextNode {
|
||||
if _, err := w.WriteString(c.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := render1(w, c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if n.Data == "plaintext" {
|
||||
// Don't render anything else. <plaintext> must be the
|
||||
// last element in the file, with no closing tag.
|
||||
return plaintextAbort
|
||||
}
|
||||
default:
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if err := render1(w, c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render the </xxx> closing tag.
|
||||
if _, err := w.WriteString("</"); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(n.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.WriteByte('>')
|
||||
}
|
||||
|
||||
// writeQuoted writes s to w surrounded by quotes. Normally it will use double
|
||||
// quotes, but if s contains a double quote, it will use single quotes.
|
||||
// It is used for writing the identifiers in a doctype declaration.
|
||||
// In valid HTML, they can't contain both types of quotes.
|
||||
func writeQuoted(w writer, s string) error {
|
||||
var q byte = '"'
|
||||
if strings.Contains(s, `"`) {
|
||||
q = '\''
|
||||
}
|
||||
if err := w.WriteByte(q); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte(q); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Section 12.1.2, "Elements", gives this list of void elements. Void elements
|
||||
// are those that can't have any contents.
|
||||
var voidElements = map[string]bool{
|
||||
"area": true,
|
||||
"base": true,
|
||||
"br": true,
|
||||
"col": true,
|
||||
"embed": true,
|
||||
"hr": true,
|
||||
"img": true,
|
||||
"input": true,
|
||||
"keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
|
||||
"link": true,
|
||||
"meta": true,
|
||||
"param": true,
|
||||
"source": true,
|
||||
"track": true,
|
||||
"wbr": true,
|
||||
}
|
1224
vendor/golang.org/x/net/html/token.go
generated
vendored
Normal file
1224
vendor/golang.org/x/net/html/token.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
12
vendor/maunium.net/go/mautrix/.editorconfig
generated
vendored
Normal file
12
vendor/maunium.net/go/mautrix/.editorconfig
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{yaml,yml}]
|
||||
indent_style = space
|
2
vendor/maunium.net/go/mautrix/.gitignore
generated
vendored
Normal file
2
vendor/maunium.net/go/mautrix/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.idea/
|
||||
.vscode/
|
374
vendor/maunium.net/go/mautrix/LICENSE
generated
vendored
Normal file
374
vendor/maunium.net/go/mautrix/LICENSE
generated
vendored
Normal file
@ -0,0 +1,374 @@
|
||||
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.
|
||||
|
24
vendor/maunium.net/go/mautrix/README.md
generated
vendored
Normal file
24
vendor/maunium.net/go/mautrix/README.md
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# mautrix-go
|
||||
[![GoDoc](https://godoc.org/maunium.net/go/mautrix?status.svg)](https://godoc.org/maunium.net/go/mautrix)
|
||||
|
||||
A Golang Matrix framework. Used by [gomuks](https://matrix.org/docs/projects/client/gomuks),
|
||||
[go-neb](https://github.com/matrix-org/go-neb), [mautrix-whatsapp](https://github.com/tulir/mautrix-whatsapp)
|
||||
and others.
|
||||
|
||||
Matrix room: [`#maunium:maunium.net`](https://matrix.to/#/#maunium:maunium.net)
|
||||
|
||||
This project is based on [matrix-org/gomatrix](https://github.com/matrix-org/gomatrix).
|
||||
The original project is licensed under [Apache 2.0](https://github.com/matrix-org/gomatrix/blob/master/LICENSE).
|
||||
|
||||
In addition to the basic client API features the original project has, this framework also has:
|
||||
|
||||
* Appservice support (Intent API like mautrix-python, room state storage, etc)
|
||||
* End-to-end encryption support (incl. interactive SAS verification)
|
||||
* Structs for parsing event content
|
||||
* Helpers for parsing and generating Matrix HTML
|
||||
* Helpers for handling push rules
|
||||
|
||||
This project contains modules that are licensed under Apache 2.0:
|
||||
|
||||
* [maunium.net/go/mautrix/crypto/canonicaljson](crypto/canonicaljson)
|
||||
* [maunium.net/go/mautrix/crypto/olm](crypto/olm)
|
1596
vendor/maunium.net/go/mautrix/client.go
generated
vendored
Normal file
1596
vendor/maunium.net/go/mautrix/client.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
171
vendor/maunium.net/go/mautrix/crypto/attachment/attachments.go
generated
vendored
Normal file
171
vendor/maunium.net/go/mautrix/crypto/attachment/attachments.go
generated
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
// 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 attachment
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"hash"
|
||||
"io"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
HashMismatch = errors.New("mismatching SHA-256 digest")
|
||||
UnsupportedVersion = errors.New("unsupported Matrix file encryption version")
|
||||
UnsupportedAlgorithm = errors.New("unsupported JWK encryption algorithm")
|
||||
InvalidKey = errors.New("failed to decode key")
|
||||
InvalidInitVector = errors.New("failed to decode initialization vector")
|
||||
ReaderClosed = errors.New("encrypting reader was already closed")
|
||||
)
|
||||
|
||||
var (
|
||||
keyBase64Length = base64.RawURLEncoding.EncodedLen(utils.AESCTRKeyLength)
|
||||
ivBase64Length = base64.RawStdEncoding.EncodedLen(utils.AESCTRIVLength)
|
||||
hashBase64Length = base64.RawStdEncoding.EncodedLen(utils.SHAHashLength)
|
||||
)
|
||||
|
||||
type JSONWebKey struct {
|
||||
Key string `json:"k"`
|
||||
Algorithm string `json:"alg"`
|
||||
Extractable bool `json:"ext"`
|
||||
KeyType string `json:"kty"`
|
||||
KeyOps []string `json:"key_ops"`
|
||||
}
|
||||
|
||||
type EncryptedFileHashes struct {
|
||||
SHA256 string `json:"sha256"`
|
||||
}
|
||||
|
||||
type decodedKeys struct {
|
||||
key [utils.AESCTRKeyLength]byte
|
||||
iv [utils.AESCTRIVLength]byte
|
||||
}
|
||||
|
||||
type EncryptedFile struct {
|
||||
Key JSONWebKey `json:"key"`
|
||||
InitVector string `json:"iv"`
|
||||
Hashes EncryptedFileHashes `json:"hashes"`
|
||||
Version string `json:"v"`
|
||||
|
||||
decoded *decodedKeys `json:"-"`
|
||||
}
|
||||
|
||||
func NewEncryptedFile() *EncryptedFile {
|
||||
key, iv := utils.GenAttachmentA256CTR()
|
||||
return &EncryptedFile{
|
||||
Key: JSONWebKey{
|
||||
Key: base64.RawURLEncoding.EncodeToString(key[:]),
|
||||
Algorithm: "A256CTR",
|
||||
Extractable: true,
|
||||
KeyType: "oct",
|
||||
KeyOps: []string{"encrypt", "decrypt"},
|
||||
},
|
||||
InitVector: base64.RawStdEncoding.EncodeToString(iv[:]),
|
||||
Version: "v2",
|
||||
|
||||
decoded: &decodedKeys{key, iv},
|
||||
}
|
||||
}
|
||||
|
||||
func (ef *EncryptedFile) decodeKeys() error {
|
||||
if ef.decoded != nil {
|
||||
return nil
|
||||
} else if len(ef.Key.Key) != keyBase64Length {
|
||||
return InvalidKey
|
||||
} else if len(ef.InitVector) != ivBase64Length {
|
||||
return InvalidInitVector
|
||||
}
|
||||
ef.decoded = &decodedKeys{}
|
||||
_, err := base64.RawURLEncoding.Decode(ef.decoded.key[:], []byte(ef.Key.Key))
|
||||
if err != nil {
|
||||
return InvalidKey
|
||||
}
|
||||
_, err = base64.RawStdEncoding.Decode(ef.decoded.iv[:], []byte(ef.InitVector))
|
||||
if err != nil {
|
||||
return InvalidInitVector
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ef *EncryptedFile) Encrypt(plaintext []byte) []byte {
|
||||
ef.decodeKeys()
|
||||
ciphertext := utils.XorA256CTR(plaintext, ef.decoded.key, ef.decoded.iv)
|
||||
checksum := sha256.Sum256(ciphertext)
|
||||
ef.Hashes.SHA256 = base64.RawStdEncoding.EncodeToString(checksum[:])
|
||||
return ciphertext
|
||||
}
|
||||
|
||||
// encryptingReader is a variation of cipher.StreamReader that also hashes the content.
|
||||
type encryptingReader struct {
|
||||
stream cipher.Stream
|
||||
hash hash.Hash
|
||||
source io.Reader
|
||||
file *EncryptedFile
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (r *encryptingReader) Read(dst []byte) (n int, err error) {
|
||||
if r.closed {
|
||||
return 0, ReaderClosed
|
||||
}
|
||||
n, err = r.source.Read(dst)
|
||||
r.stream.XORKeyStream(dst[:n], dst[:n])
|
||||
r.hash.Write(dst[:n])
|
||||
return
|
||||
}
|
||||
|
||||
func (r *encryptingReader) Close() (err error) {
|
||||
closer, ok := r.source.(io.ReadCloser)
|
||||
if ok {
|
||||
err = closer.Close()
|
||||
}
|
||||
r.file.Hashes.SHA256 = base64.RawStdEncoding.EncodeToString(r.hash.Sum(nil))
|
||||
r.closed = true
|
||||
return
|
||||
}
|
||||
|
||||
func (ef *EncryptedFile) EncryptStream(reader io.Reader) io.ReadCloser {
|
||||
ef.decodeKeys()
|
||||
block, _ := aes.NewCipher(ef.decoded.key[:])
|
||||
return &encryptingReader{
|
||||
stream: cipher.NewCTR(block, ef.decoded.iv[:]),
|
||||
hash: sha256.New(),
|
||||
source: reader,
|
||||
file: ef,
|
||||
}
|
||||
}
|
||||
|
||||
func (ef *EncryptedFile) checkHash(ciphertext []byte) bool {
|
||||
if len(ef.Hashes.SHA256) != hashBase64Length {
|
||||
return false
|
||||
}
|
||||
var checksum [utils.SHAHashLength]byte
|
||||
_, err := base64.RawStdEncoding.Decode(checksum[:], []byte(ef.Hashes.SHA256))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return checksum == sha256.Sum256(ciphertext)
|
||||
}
|
||||
|
||||
func (ef *EncryptedFile) Decrypt(ciphertext []byte) ([]byte, error) {
|
||||
if ef.Version != "v2" {
|
||||
return nil, UnsupportedVersion
|
||||
} else if ef.Key.Algorithm != "A256CTR" {
|
||||
return nil, UnsupportedAlgorithm
|
||||
} else if !ef.checkHash(ciphertext) {
|
||||
return nil, HashMismatch
|
||||
} else if err := ef.decodeKeys(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return utils.XorA256CTR(ciphertext, ef.decoded.key, ef.decoded.iv), nil
|
||||
}
|
||||
}
|
133
vendor/maunium.net/go/mautrix/crypto/utils/utils.go
generated
vendored
Normal file
133
vendor/maunium.net/go/mautrix/crypto/utils/utils.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
// 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 utils
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
"github.com/btcsuite/btcutil/base58"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
const (
|
||||
// AESCTRKeyLength is the length of the AES256-CTR key used.
|
||||
AESCTRKeyLength = 32
|
||||
// AESCTRIVLength is the length of the AES256-CTR IV used.
|
||||
AESCTRIVLength = 16
|
||||
// HMACKeyLength is the length of the HMAC key used.
|
||||
HMACKeyLength = 32
|
||||
// SHAHashLength is the length of the SHA hash used.
|
||||
SHAHashLength = 32
|
||||
)
|
||||
|
||||
// XorA256CTR encrypts the input with the keystream generated by the AES256-CTR algorithm with the given arguments.
|
||||
func XorA256CTR(source []byte, key [AESCTRKeyLength]byte, iv [AESCTRIVLength]byte) []byte {
|
||||
block, _ := aes.NewCipher(key[:])
|
||||
result := make([]byte, len(source))
|
||||
cipher.NewCTR(block, iv[:]).XORKeyStream(result, source)
|
||||
return result
|
||||
}
|
||||
|
||||
// GenAttachmentA256CTR generates a new random AES256-CTR key and IV suitable for encrypting attachments.
|
||||
func GenAttachmentA256CTR() (key [AESCTRKeyLength]byte, iv [AESCTRIVLength]byte) {
|
||||
_, err := rand.Read(key[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The last 8 bytes of the IV act as the counter in AES-CTR, which means they're left empty here
|
||||
_, err = rand.Read(iv[:8])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GenA256CTRIV generates a random IV for AES256-CTR with the last bit set to zero.
|
||||
func GenA256CTRIV() (iv [AESCTRIVLength]byte) {
|
||||
_, err := rand.Read(iv[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
iv[8] &= 0x7F
|
||||
return
|
||||
}
|
||||
|
||||
// DeriveKeysSHA256 derives an AES and a HMAC key from the given recovery key.
|
||||
func DeriveKeysSHA256(key []byte, name string) ([AESCTRKeyLength]byte, [HMACKeyLength]byte) {
|
||||
var zeroBytes [32]byte
|
||||
|
||||
derivedHkdf := hkdf.New(sha256.New, key[:], zeroBytes[:], []byte(name))
|
||||
|
||||
var aesKey [AESCTRKeyLength]byte
|
||||
var hmacKey [HMACKeyLength]byte
|
||||
derivedHkdf.Read(aesKey[:])
|
||||
derivedHkdf.Read(hmacKey[:])
|
||||
|
||||
return aesKey, hmacKey
|
||||
}
|
||||
|
||||
// PBKDF2SHA512 generates a key of the given bit-length using the given passphrase, salt and iteration count.
|
||||
func PBKDF2SHA512(password []byte, salt []byte, iters int, keyLenBits int) []byte {
|
||||
return pbkdf2.Key(password, salt, iters, keyLenBits/8, sha512.New)
|
||||
}
|
||||
|
||||
// DecodeBase58RecoveryKey recovers the secret storage from a recovery key.
|
||||
func DecodeBase58RecoveryKey(recoveryKey string) []byte {
|
||||
noSpaces := strings.ReplaceAll(recoveryKey, " ", "")
|
||||
decoded := base58.Decode(noSpaces)
|
||||
if len(decoded) != AESCTRKeyLength+3 { // AESCTRKeyLength bytes key and 3 bytes prefix / parity
|
||||
return nil
|
||||
}
|
||||
var parity byte
|
||||
for _, b := range decoded[:34] {
|
||||
parity ^= b
|
||||
}
|
||||
if parity != decoded[34] || decoded[0] != 0x8B || decoded[1] != 1 {
|
||||
return nil
|
||||
}
|
||||
return decoded[2:34]
|
||||
}
|
||||
|
||||
// EncodeBase58RecoveryKey recovers the secret storage from a recovery key.
|
||||
func EncodeBase58RecoveryKey(key []byte) string {
|
||||
var inputBytes [35]byte
|
||||
copy(inputBytes[2:34], key[:])
|
||||
inputBytes[0] = 0x8B
|
||||
inputBytes[1] = 1
|
||||
|
||||
var parity byte
|
||||
for _, b := range inputBytes[:34] {
|
||||
parity ^= b
|
||||
}
|
||||
inputBytes[34] = parity
|
||||
recoveryKey := base58.Encode(inputBytes[:])
|
||||
|
||||
var spacedKey string
|
||||
for i, c := range recoveryKey {
|
||||
if i > 0 && i%4 == 0 {
|
||||
spacedKey += " "
|
||||
}
|
||||
spacedKey += string(c)
|
||||
}
|
||||
return spacedKey
|
||||
}
|
||||
|
||||
// HMACSHA256B64 calculates the 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))
|
||||
}
|
144
vendor/maunium.net/go/mautrix/error.go
generated
vendored
Normal file
144
vendor/maunium.net/go/mautrix/error.go
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
// 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 mautrix
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Common error codes from https://matrix.org/docs/spec/client_server/latest#api-standards
|
||||
//
|
||||
// Can be used with errors.Is() to check the response code without casting the error:
|
||||
// err := client.Sync()
|
||||
// if errors.Is(err, MUnknownToken) {
|
||||
// // logout
|
||||
// }
|
||||
var (
|
||||
// Forbidden access, e.g. joining a room without permission, failed login.
|
||||
MForbidden = RespError{ErrCode: "M_FORBIDDEN"}
|
||||
// The access token specified was not recognised.
|
||||
MUnknownToken = RespError{ErrCode: "M_UNKNOWN_TOKEN"}
|
||||
// No access token was specified for the request.
|
||||
MMissingToken = RespError{ErrCode: "M_MISSING_TOKEN"}
|
||||
// Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys.
|
||||
MBadJSON = RespError{ErrCode: "M_BAD_JSON"}
|
||||
// Request did not contain valid JSON.
|
||||
MNotJSON = RespError{ErrCode: "M_NOT_JSON"}
|
||||
// No resource was found for this request.
|
||||
MNotFound = RespError{ErrCode: "M_NOT_FOUND"}
|
||||
// Too many requests have been sent in a short period of time. Wait a while then try again.
|
||||
MLimitExceeded = RespError{ErrCode: "M_LIMIT_EXCEEDED"}
|
||||
// The user ID associated with the request has been deactivated.
|
||||
// Typically for endpoints that prove authentication, such as /login.
|
||||
MUserDeactivated = RespError{ErrCode: "M_USER_DEACTIVATED"}
|
||||
// Encountered when trying to register a user ID which has been taken.
|
||||
MUserInUse = RespError{ErrCode: "M_USER_IN_USE"}
|
||||
// Encountered when trying to register a user ID which is not valid.
|
||||
MInvalidUsername = RespError{ErrCode: "M_INVALID_USERNAME"}
|
||||
// Sent when the room alias given to the createRoom API is already in use.
|
||||
MRoomInUse = RespError{ErrCode: "M_ROOM_IN_USE"}
|
||||
// The state change requested cannot be performed, such as attempting to unban a user who is not banned.
|
||||
MBadState = RespError{ErrCode: "M_BAD_STATE"}
|
||||
// The request or entity was too large.
|
||||
MTooLarge = RespError{ErrCode: "M_TOO_LARGE"}
|
||||
// The resource being requested is reserved by an application service, or the application service making the request has not created the resource.
|
||||
MExclusive = RespError{ErrCode: "M_EXCLUSIVE"}
|
||||
// The client's request to create a room used a room version that the server does not support.
|
||||
MUnsupportedRoomVersion = RespError{ErrCode: "M_UNSUPPORTED_ROOM_VERSION"}
|
||||
// The client attempted to join a room that has a version the server does not support.
|
||||
// Inspect the room_version property of the error response for the room's version.
|
||||
MIncompatibleRoomVersion = RespError{ErrCode: "M_INCOMPATIBLE_ROOM_VERSION"}
|
||||
)
|
||||
|
||||
// HTTPError An HTTP Error response, which may wrap an underlying native Go Error.
|
||||
type HTTPError struct {
|
||||
Request *http.Request
|
||||
Response *http.Response
|
||||
ResponseBody string
|
||||
|
||||
WrappedError error
|
||||
RespError *RespError
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e HTTPError) Is(err error) bool {
|
||||
return (e.RespError != nil && errors.Is(e.RespError, err)) || (e.WrappedError != nil && errors.Is(e.WrappedError, err))
|
||||
}
|
||||
|
||||
func (e HTTPError) IsStatus(code int) bool {
|
||||
return e.Response != nil && e.Response.StatusCode == code
|
||||
}
|
||||
|
||||
func (e HTTPError) Error() string {
|
||||
if e.WrappedError != nil {
|
||||
return fmt.Sprintf("%s: %v", e.Message, e.WrappedError)
|
||||
} else if e.RespError != nil {
|
||||
return fmt.Sprintf("failed to %s %s: %s (HTTP %d): %s", e.Request.Method, e.Request.URL.Path,
|
||||
e.RespError.ErrCode, e.Response.StatusCode, e.RespError.Err)
|
||||
} else {
|
||||
msg := fmt.Sprintf("failed to %s %s: %s", e.Request.Method, e.Request.URL.Path, e.Response.Status)
|
||||
if len(e.ResponseBody) > 0 {
|
||||
msg = fmt.Sprintf("%s\n%s", msg, e.ResponseBody)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
}
|
||||
|
||||
func (e HTTPError) Unwrap() error {
|
||||
if e.WrappedError != nil {
|
||||
return e.WrappedError
|
||||
} else if e.RespError != nil {
|
||||
return *e.RespError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RespError is the standard JSON error response from Homeservers. It also implements the Golang "error" interface.
|
||||
// See http://matrix.org/docs/spec/client_server/r0.6.1.html#api-standards
|
||||
type RespError struct {
|
||||
ErrCode string
|
||||
Err string
|
||||
ExtraData map[string]interface{}
|
||||
}
|
||||
|
||||
func (e *RespError) UnmarshalJSON(data []byte) error {
|
||||
err := json.Unmarshal(data, &e.ExtraData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.ErrCode, _ = e.ExtraData["errcode"].(string)
|
||||
e.Err, _ = e.ExtraData["error"].(string)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *RespError) MarshalJSON() ([]byte, error) {
|
||||
if e.ExtraData == nil {
|
||||
e.ExtraData = make(map[string]interface{})
|
||||
}
|
||||
e.ExtraData["errcode"] = e.ErrCode
|
||||
e.ExtraData["error"] = e.Err
|
||||
return json.Marshal(&e.ExtraData)
|
||||
}
|
||||
|
||||
// Error returns the errcode and error message.
|
||||
func (e RespError) Error() string {
|
||||
return e.ErrCode + ": " + e.Err
|
||||
}
|
||||
|
||||
func (e RespError) Is(err error) bool {
|
||||
e2, ok := err.(RespError)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if e.ErrCode == "M_UNKNOWN" && e2.ErrCode == "M_UNKNOWN" {
|
||||
return e.Err == e2.Err
|
||||
}
|
||||
return e2.ErrCode == e.ErrCode
|
||||
}
|
45
vendor/maunium.net/go/mautrix/event/accountdata.go
generated
vendored
Normal file
45
vendor/maunium.net/go/mautrix/event/accountdata.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// TagEventContent represents the content of a m.tag room account data event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-tag
|
||||
type TagEventContent struct {
|
||||
Tags Tags `json:"tags"`
|
||||
}
|
||||
|
||||
type Tags map[string]Tag
|
||||
|
||||
type Tag struct {
|
||||
Order json.Number `json:"order,omitempty"`
|
||||
}
|
||||
|
||||
// DirectChatsEventContent represents the content of a m.direct account data event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-direct
|
||||
type DirectChatsEventContent map[id.UserID][]id.RoomID
|
||||
|
||||
// FullyReadEventContent represents the content of a m.fully_read account data event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-fully-read
|
||||
type FullyReadEventContent struct {
|
||||
EventID id.EventID `json:"event_id"`
|
||||
}
|
||||
|
||||
// IgnoredUserListEventContent represents the content of a m.ignored_user_list account data event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-ignored-user-list
|
||||
type IgnoredUserListEventContent struct {
|
||||
IgnoredUsers map[id.UserID]IgnoredUser `json:"ignored_users"`
|
||||
}
|
||||
|
||||
type IgnoredUser struct {
|
||||
// This is an empty object
|
||||
}
|
486
vendor/maunium.net/go/mautrix/event/content.go
generated
vendored
Normal file
486
vendor/maunium.net/go/mautrix/event/content.go
generated
vendored
Normal file
@ -0,0 +1,486 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// TypeMap is a mapping from event type to the content struct type.
|
||||
// This is used by Content.ParseRaw() for creating the correct type of struct.
|
||||
var TypeMap = map[Type]reflect.Type{
|
||||
StateMember: reflect.TypeOf(MemberEventContent{}),
|
||||
StatePowerLevels: reflect.TypeOf(PowerLevelsEventContent{}),
|
||||
StateCanonicalAlias: reflect.TypeOf(CanonicalAliasEventContent{}),
|
||||
StateRoomName: reflect.TypeOf(RoomNameEventContent{}),
|
||||
StateRoomAvatar: reflect.TypeOf(RoomAvatarEventContent{}),
|
||||
StateTopic: reflect.TypeOf(TopicEventContent{}),
|
||||
StateTombstone: reflect.TypeOf(TombstoneEventContent{}),
|
||||
StateCreate: reflect.TypeOf(CreateEventContent{}),
|
||||
StateJoinRules: reflect.TypeOf(JoinRulesEventContent{}),
|
||||
StateHistoryVisibility: reflect.TypeOf(HistoryVisibilityEventContent{}),
|
||||
StateGuestAccess: reflect.TypeOf(GuestAccessEventContent{}),
|
||||
StatePinnedEvents: reflect.TypeOf(PinnedEventsEventContent{}),
|
||||
StateEncryption: reflect.TypeOf(EncryptionEventContent{}),
|
||||
StateBridge: reflect.TypeOf(BridgeEventContent{}),
|
||||
StateHalfShotBridge: reflect.TypeOf(BridgeEventContent{}),
|
||||
StateSpaceParent: reflect.TypeOf(SpaceParentEventContent{}),
|
||||
StateSpaceChild: reflect.TypeOf(SpaceChildEventContent{}),
|
||||
|
||||
EventMessage: reflect.TypeOf(MessageEventContent{}),
|
||||
EventSticker: reflect.TypeOf(MessageEventContent{}),
|
||||
EventEncrypted: reflect.TypeOf(EncryptedEventContent{}),
|
||||
EventRedaction: reflect.TypeOf(RedactionEventContent{}),
|
||||
EventReaction: reflect.TypeOf(ReactionEventContent{}),
|
||||
|
||||
AccountDataRoomTags: reflect.TypeOf(TagEventContent{}),
|
||||
AccountDataDirectChats: reflect.TypeOf(DirectChatsEventContent{}),
|
||||
AccountDataFullyRead: reflect.TypeOf(FullyReadEventContent{}),
|
||||
AccountDataIgnoredUserList: reflect.TypeOf(IgnoredUserListEventContent{}),
|
||||
|
||||
EphemeralEventTyping: reflect.TypeOf(TypingEventContent{}),
|
||||
EphemeralEventReceipt: reflect.TypeOf(ReceiptEventContent{}),
|
||||
EphemeralEventPresence: reflect.TypeOf(PresenceEventContent{}),
|
||||
|
||||
InRoomVerificationStart: reflect.TypeOf(VerificationStartEventContent{}),
|
||||
InRoomVerificationReady: reflect.TypeOf(VerificationReadyEventContent{}),
|
||||
InRoomVerificationAccept: reflect.TypeOf(VerificationAcceptEventContent{}),
|
||||
InRoomVerificationKey: reflect.TypeOf(VerificationKeyEventContent{}),
|
||||
InRoomVerificationMAC: reflect.TypeOf(VerificationMacEventContent{}),
|
||||
InRoomVerificationCancel: reflect.TypeOf(VerificationCancelEventContent{}),
|
||||
|
||||
ToDeviceRoomKey: reflect.TypeOf(RoomKeyEventContent{}),
|
||||
ToDeviceForwardedRoomKey: reflect.TypeOf(ForwardedRoomKeyEventContent{}),
|
||||
ToDeviceRoomKeyRequest: reflect.TypeOf(RoomKeyRequestEventContent{}),
|
||||
ToDeviceEncrypted: reflect.TypeOf(EncryptedEventContent{}),
|
||||
ToDeviceRoomKeyWithheld: reflect.TypeOf(RoomKeyWithheldEventContent{}),
|
||||
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{}),
|
||||
|
||||
ToDeviceOrgMatrixRoomKeyWithheld: reflect.TypeOf(RoomKeyWithheldEventContent{}),
|
||||
|
||||
CallInvite: reflect.TypeOf(CallInviteEventContent{}),
|
||||
CallCandidates: reflect.TypeOf(CallCandidatesEventContent{}),
|
||||
CallAnswer: reflect.TypeOf(CallAnswerEventContent{}),
|
||||
CallReject: reflect.TypeOf(CallRejectEventContent{}),
|
||||
CallSelectAnswer: reflect.TypeOf(CallSelectAnswerEventContent{}),
|
||||
CallNegotiate: reflect.TypeOf(CallNegotiateEventContent{}),
|
||||
CallHangup: reflect.TypeOf(CallHangupEventContent{}),
|
||||
}
|
||||
|
||||
// Content stores the content of a Matrix event.
|
||||
//
|
||||
// By default, the content is only parsed into a map[string]interface{}. However, you can call ParseRaw with the
|
||||
// correct event type to parse the content into a nicer struct, which you can then access from Parsed or via the
|
||||
// helper functions.
|
||||
type Content struct {
|
||||
VeryRaw json.RawMessage
|
||||
Raw map[string]interface{}
|
||||
Parsed interface{}
|
||||
}
|
||||
|
||||
type Relatable interface {
|
||||
GetRelatesTo() *RelatesTo
|
||||
OptionalGetRelatesTo() *RelatesTo
|
||||
SetRelatesTo(rel *RelatesTo)
|
||||
}
|
||||
|
||||
func (content *Content) UnmarshalJSON(data []byte) error {
|
||||
content.VeryRaw = data
|
||||
err := json.Unmarshal(data, &content.Raw)
|
||||
return err
|
||||
}
|
||||
|
||||
func (content *Content) MarshalJSON() ([]byte, error) {
|
||||
if content.Raw == nil {
|
||||
if content.Parsed == nil {
|
||||
if content.VeryRaw == nil {
|
||||
return []byte("{}"), nil
|
||||
}
|
||||
return content.VeryRaw, nil
|
||||
}
|
||||
return json.Marshal(content.Parsed)
|
||||
} else if content.Parsed != nil {
|
||||
// TODO this whole thing is incredibly hacky
|
||||
// It needs to produce JSON, where:
|
||||
// * content.Parsed is applied after content.Raw
|
||||
// * MarshalJSON() is respected inside content.Parsed
|
||||
// * Custom field inside nested objects of content.Raw are preserved,
|
||||
// even if content.Parsed contains the higher-level objects.
|
||||
// * content.Raw is not modified
|
||||
|
||||
unparsed, err := json.Marshal(content.Parsed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var rawParsed map[string]interface{}
|
||||
err = json.Unmarshal(unparsed, &rawParsed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
output := make(map[string]interface{})
|
||||
for key, value := range content.Raw {
|
||||
output[key] = value
|
||||
}
|
||||
|
||||
mergeMaps(output, rawParsed)
|
||||
return json.Marshal(output)
|
||||
}
|
||||
return json.Marshal(content.Raw)
|
||||
}
|
||||
|
||||
func IsUnsupportedContentType(err error) bool {
|
||||
return errors.Is(err, UnsupportedContentType)
|
||||
}
|
||||
|
||||
var ContentAlreadyParsed = errors.New("content is already parsed")
|
||||
var UnsupportedContentType = errors.New("unsupported event type")
|
||||
|
||||
func (content *Content) ParseRaw(evtType Type) error {
|
||||
if content.Parsed != nil {
|
||||
return ContentAlreadyParsed
|
||||
}
|
||||
structType, ok := TypeMap[evtType]
|
||||
if !ok {
|
||||
return fmt.Errorf("%w %s", UnsupportedContentType, evtType.Repr())
|
||||
}
|
||||
content.Parsed = reflect.New(structType).Interface()
|
||||
return json.Unmarshal(content.VeryRaw, &content.Parsed)
|
||||
}
|
||||
|
||||
func mergeMaps(into, from map[string]interface{}) {
|
||||
for key, newValue := range from {
|
||||
existingValue, ok := into[key]
|
||||
if !ok {
|
||||
into[key] = newValue
|
||||
continue
|
||||
}
|
||||
existingValueMap, okEx := existingValue.(map[string]interface{})
|
||||
newValueMap, okNew := newValue.(map[string]interface{})
|
||||
if okEx && okNew {
|
||||
mergeMaps(existingValueMap, newValueMap)
|
||||
} else {
|
||||
into[key] = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
gob.Register(&MemberEventContent{})
|
||||
gob.Register(&PowerLevelsEventContent{})
|
||||
gob.Register(&CanonicalAliasEventContent{})
|
||||
gob.Register(&EncryptionEventContent{})
|
||||
gob.Register(&BridgeEventContent{})
|
||||
gob.Register(&SpaceChildEventContent{})
|
||||
gob.Register(&SpaceParentEventContent{})
|
||||
gob.Register(&RoomNameEventContent{})
|
||||
gob.Register(&RoomAvatarEventContent{})
|
||||
gob.Register(&TopicEventContent{})
|
||||
gob.Register(&TombstoneEventContent{})
|
||||
gob.Register(&CreateEventContent{})
|
||||
gob.Register(&JoinRulesEventContent{})
|
||||
gob.Register(&HistoryVisibilityEventContent{})
|
||||
gob.Register(&GuestAccessEventContent{})
|
||||
gob.Register(&PinnedEventsEventContent{})
|
||||
gob.Register(&MessageEventContent{})
|
||||
gob.Register(&MessageEventContent{})
|
||||
gob.Register(&EncryptedEventContent{})
|
||||
gob.Register(&RedactionEventContent{})
|
||||
gob.Register(&ReactionEventContent{})
|
||||
gob.Register(&TagEventContent{})
|
||||
gob.Register(&DirectChatsEventContent{})
|
||||
gob.Register(&FullyReadEventContent{})
|
||||
gob.Register(&IgnoredUserListEventContent{})
|
||||
gob.Register(&TypingEventContent{})
|
||||
gob.Register(&ReceiptEventContent{})
|
||||
gob.Register(&PresenceEventContent{})
|
||||
gob.Register(&RoomKeyEventContent{})
|
||||
gob.Register(&ForwardedRoomKeyEventContent{})
|
||||
gob.Register(&RoomKeyRequestEventContent{})
|
||||
gob.Register(&RoomKeyWithheldEventContent{})
|
||||
}
|
||||
|
||||
// Helper cast functions below
|
||||
|
||||
func (content *Content) AsMember() *MemberEventContent {
|
||||
casted, ok := content.Parsed.(*MemberEventContent)
|
||||
if !ok {
|
||||
return &MemberEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsPowerLevels() *PowerLevelsEventContent {
|
||||
casted, ok := content.Parsed.(*PowerLevelsEventContent)
|
||||
if !ok {
|
||||
return &PowerLevelsEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCanonicalAlias() *CanonicalAliasEventContent {
|
||||
casted, ok := content.Parsed.(*CanonicalAliasEventContent)
|
||||
if !ok {
|
||||
return &CanonicalAliasEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRoomName() *RoomNameEventContent {
|
||||
casted, ok := content.Parsed.(*RoomNameEventContent)
|
||||
if !ok {
|
||||
return &RoomNameEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRoomAvatar() *RoomAvatarEventContent {
|
||||
casted, ok := content.Parsed.(*RoomAvatarEventContent)
|
||||
if !ok {
|
||||
return &RoomAvatarEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsTopic() *TopicEventContent {
|
||||
casted, ok := content.Parsed.(*TopicEventContent)
|
||||
if !ok {
|
||||
return &TopicEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsTombstone() *TombstoneEventContent {
|
||||
casted, ok := content.Parsed.(*TombstoneEventContent)
|
||||
if !ok {
|
||||
return &TombstoneEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCreate() *CreateEventContent {
|
||||
casted, ok := content.Parsed.(*CreateEventContent)
|
||||
if !ok {
|
||||
return &CreateEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsJoinRules() *JoinRulesEventContent {
|
||||
casted, ok := content.Parsed.(*JoinRulesEventContent)
|
||||
if !ok {
|
||||
return &JoinRulesEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsHistoryVisibility() *HistoryVisibilityEventContent {
|
||||
casted, ok := content.Parsed.(*HistoryVisibilityEventContent)
|
||||
if !ok {
|
||||
return &HistoryVisibilityEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsGuestAccess() *GuestAccessEventContent {
|
||||
casted, ok := content.Parsed.(*GuestAccessEventContent)
|
||||
if !ok {
|
||||
return &GuestAccessEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsPinnedEvents() *PinnedEventsEventContent {
|
||||
casted, ok := content.Parsed.(*PinnedEventsEventContent)
|
||||
if !ok {
|
||||
return &PinnedEventsEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsEncryption() *EncryptionEventContent {
|
||||
casted, ok := content.Parsed.(*EncryptionEventContent)
|
||||
if !ok {
|
||||
return &EncryptionEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsBridge() *BridgeEventContent {
|
||||
casted, ok := content.Parsed.(*BridgeEventContent)
|
||||
if !ok {
|
||||
return &BridgeEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsSpaceChild() *SpaceChildEventContent {
|
||||
casted, ok := content.Parsed.(*SpaceChildEventContent)
|
||||
if !ok {
|
||||
return &SpaceChildEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsSpaceParent() *SpaceParentEventContent {
|
||||
casted, ok := content.Parsed.(*SpaceParentEventContent)
|
||||
if !ok {
|
||||
return &SpaceParentEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsMessage() *MessageEventContent {
|
||||
casted, ok := content.Parsed.(*MessageEventContent)
|
||||
if !ok {
|
||||
return &MessageEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsEncrypted() *EncryptedEventContent {
|
||||
casted, ok := content.Parsed.(*EncryptedEventContent)
|
||||
if !ok {
|
||||
return &EncryptedEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRedaction() *RedactionEventContent {
|
||||
casted, ok := content.Parsed.(*RedactionEventContent)
|
||||
if !ok {
|
||||
return &RedactionEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsReaction() *ReactionEventContent {
|
||||
casted, ok := content.Parsed.(*ReactionEventContent)
|
||||
if !ok {
|
||||
return &ReactionEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsTag() *TagEventContent {
|
||||
casted, ok := content.Parsed.(*TagEventContent)
|
||||
if !ok {
|
||||
return &TagEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsDirectChats() *DirectChatsEventContent {
|
||||
casted, ok := content.Parsed.(*DirectChatsEventContent)
|
||||
if !ok {
|
||||
return &DirectChatsEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsFullyRead() *FullyReadEventContent {
|
||||
casted, ok := content.Parsed.(*FullyReadEventContent)
|
||||
if !ok {
|
||||
return &FullyReadEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsIgnoredUserList() *IgnoredUserListEventContent {
|
||||
casted, ok := content.Parsed.(*IgnoredUserListEventContent)
|
||||
if !ok {
|
||||
return &IgnoredUserListEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsTyping() *TypingEventContent {
|
||||
casted, ok := content.Parsed.(*TypingEventContent)
|
||||
if !ok {
|
||||
return &TypingEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsReceipt() *ReceiptEventContent {
|
||||
casted, ok := content.Parsed.(*ReceiptEventContent)
|
||||
if !ok {
|
||||
return &ReceiptEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsPresence() *PresenceEventContent {
|
||||
casted, ok := content.Parsed.(*PresenceEventContent)
|
||||
if !ok {
|
||||
return &PresenceEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRoomKey() *RoomKeyEventContent {
|
||||
casted, ok := content.Parsed.(*RoomKeyEventContent)
|
||||
if !ok {
|
||||
return &RoomKeyEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsForwardedRoomKey() *ForwardedRoomKeyEventContent {
|
||||
casted, ok := content.Parsed.(*ForwardedRoomKeyEventContent)
|
||||
if !ok {
|
||||
return &ForwardedRoomKeyEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRoomKeyRequest() *RoomKeyRequestEventContent {
|
||||
casted, ok := content.Parsed.(*RoomKeyRequestEventContent)
|
||||
if !ok {
|
||||
return &RoomKeyRequestEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRoomKeyWithheld() *RoomKeyWithheldEventContent {
|
||||
casted, ok := content.Parsed.(*RoomKeyWithheldEventContent)
|
||||
if !ok {
|
||||
return &RoomKeyWithheldEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallInvite() *CallInviteEventContent {
|
||||
casted, ok := content.Parsed.(*CallInviteEventContent)
|
||||
if !ok {
|
||||
return &CallInviteEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallCandidates() *CallCandidatesEventContent {
|
||||
casted, ok := content.Parsed.(*CallCandidatesEventContent)
|
||||
if !ok {
|
||||
return &CallCandidatesEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallAnswer() *CallAnswerEventContent {
|
||||
casted, ok := content.Parsed.(*CallAnswerEventContent)
|
||||
if !ok {
|
||||
return &CallAnswerEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallReject() *CallRejectEventContent {
|
||||
casted, ok := content.Parsed.(*CallRejectEventContent)
|
||||
if !ok {
|
||||
return &CallRejectEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallSelectAnswer() *CallSelectAnswerEventContent {
|
||||
casted, ok := content.Parsed.(*CallSelectAnswerEventContent)
|
||||
if !ok {
|
||||
return &CallSelectAnswerEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallNegotiate() *CallNegotiateEventContent {
|
||||
casted, ok := content.Parsed.(*CallNegotiateEventContent)
|
||||
if !ok {
|
||||
return &CallNegotiateEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallHangup() *CallHangupEventContent {
|
||||
casted, ok := content.Parsed.(*CallHangupEventContent)
|
||||
if !ok {
|
||||
return &CallHangupEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
143
vendor/maunium.net/go/mautrix/event/encryption.go
generated
vendored
Normal file
143
vendor/maunium.net/go/mautrix/event/encryption.go
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// EncryptionEventContent represents the content of a m.room.encryption state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-encryption
|
||||
type EncryptionEventContent struct {
|
||||
// The encryption algorithm to be used to encrypt messages sent in this room. Must be 'm.megolm.v1.aes-sha2'.
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
// How long the session should be used before changing it. 604800000 (a week) is the recommended default.
|
||||
RotationPeriodMillis int64 `json:"rotation_period_ms,omitempty"`
|
||||
// How many messages should be sent before changing the session. 100 is the recommended default.
|
||||
RotationPeriodMessages int `json:"rotation_period_msgs,omitempty"`
|
||||
}
|
||||
|
||||
// EncryptedEventContent represents the content of a m.room.encrypted message event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-encrypted
|
||||
type EncryptedEventContent struct {
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
SenderKey id.SenderKey `json:"sender_key"`
|
||||
DeviceID id.DeviceID `json:"device_id,omitempty"` // Only present for Megolm events
|
||||
SessionID id.SessionID `json:"session_id,omitempty"` // Only present for Megolm events
|
||||
Ciphertext json.RawMessage `json:"ciphertext"`
|
||||
|
||||
MegolmCiphertext []byte `json:"-"`
|
||||
OlmCiphertext OlmCiphertexts `json:"-"`
|
||||
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
type OlmCiphertexts map[id.Curve25519]struct {
|
||||
Body string `json:"body"`
|
||||
Type id.OlmMsgType `json:"type"`
|
||||
}
|
||||
|
||||
type serializableEncryptedEventContent EncryptedEventContent
|
||||
|
||||
func (content *EncryptedEventContent) UnmarshalJSON(data []byte) error {
|
||||
err := json.Unmarshal(data, (*serializableEncryptedEventContent)(content))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch content.Algorithm {
|
||||
case id.AlgorithmOlmV1:
|
||||
content.OlmCiphertext = make(OlmCiphertexts)
|
||||
return json.Unmarshal(content.Ciphertext, &content.OlmCiphertext)
|
||||
case id.AlgorithmMegolmV1:
|
||||
if len(content.Ciphertext) == 0 || content.Ciphertext[0] != '"' || content.Ciphertext[len(content.Ciphertext)-1] != '"' {
|
||||
return id.InputNotJSONString
|
||||
}
|
||||
content.MegolmCiphertext = content.Ciphertext[1 : len(content.Ciphertext)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (content *EncryptedEventContent) MarshalJSON() ([]byte, error) {
|
||||
var err error
|
||||
switch content.Algorithm {
|
||||
case id.AlgorithmOlmV1:
|
||||
content.Ciphertext, err = json.Marshal(content.OlmCiphertext)
|
||||
case id.AlgorithmMegolmV1:
|
||||
content.Ciphertext = make([]byte, len(content.MegolmCiphertext)+2)
|
||||
content.Ciphertext[0] = '"'
|
||||
content.Ciphertext[len(content.Ciphertext)-1] = '"'
|
||||
copy(content.Ciphertext[1:len(content.Ciphertext)-1], content.MegolmCiphertext)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal((*serializableEncryptedEventContent)(content))
|
||||
}
|
||||
|
||||
// RoomKeyEventContent represents the content of a m.room_key to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-key
|
||||
type RoomKeyEventContent struct {
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
SessionID id.SessionID `json:"session_id"`
|
||||
SessionKey string `json:"session_key"`
|
||||
}
|
||||
|
||||
// ForwardedRoomKeyEventContent represents the content of a m.forwarded_room_key to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-forwarded-room-key
|
||||
type ForwardedRoomKeyEventContent struct {
|
||||
RoomKeyEventContent
|
||||
SenderKey id.SenderKey `json:"sender_key"`
|
||||
SenderClaimedKey id.Ed25519 `json:"sender_claimed_ed25519_key"`
|
||||
ForwardingKeyChain []string `json:"forwarding_curve25519_key_chain"`
|
||||
}
|
||||
|
||||
type KeyRequestAction string
|
||||
|
||||
const (
|
||||
KeyRequestActionRequest = "request"
|
||||
KeyRequestActionCancel = "request_cancellation"
|
||||
)
|
||||
|
||||
// RoomKeyRequestEventContent represents the content of a m.room_key_request to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-key-request
|
||||
type RoomKeyRequestEventContent struct {
|
||||
Body RequestedKeyInfo `json:"body"`
|
||||
Action KeyRequestAction `json:"action"`
|
||||
RequestingDeviceID id.DeviceID `json:"requesting_device_id"`
|
||||
RequestID string `json:"request_id"`
|
||||
}
|
||||
|
||||
type RequestedKeyInfo struct {
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
SenderKey id.SenderKey `json:"sender_key"`
|
||||
SessionID id.SessionID `json:"session_id"`
|
||||
}
|
||||
|
||||
type RoomKeyWithheldCode string
|
||||
|
||||
const (
|
||||
RoomKeyWithheldBlacklisted RoomKeyWithheldCode = "m.blacklisted"
|
||||
RoomKeyWithheldUnverified RoomKeyWithheldCode = "m.unverified"
|
||||
RoomKeyWithheldUnauthorized RoomKeyWithheldCode = "m.unauthorized"
|
||||
RoomKeyWithheldUnavailable RoomKeyWithheldCode = "m.unavailable"
|
||||
RoomKeyWithheldNoOlmSession RoomKeyWithheldCode = "m.no_olm"
|
||||
)
|
||||
|
||||
type RoomKeyWithheldEventContent struct {
|
||||
RoomID id.RoomID `json:"room_id,omitempty"`
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
SessionID id.SessionID `json:"session_id,omitempty"`
|
||||
SenderKey id.SenderKey `json:"sender_key"`
|
||||
Code RoomKeyWithheldCode `json:"code"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
type DummyEventContent struct{}
|
80
vendor/maunium.net/go/mautrix/event/ephemeral.go
generated
vendored
Normal file
80
vendor/maunium.net/go/mautrix/event/ephemeral.go
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// TagEventContent represents the content of a m.typing ephemeral event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-typing
|
||||
type TypingEventContent struct {
|
||||
UserIDs []id.UserID `json:"user_ids"`
|
||||
}
|
||||
|
||||
// ReceiptEventContent represents the content of a m.receipt ephemeral event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-receipt
|
||||
type ReceiptEventContent map[id.EventID]Receipts
|
||||
|
||||
type Receipts struct {
|
||||
Read map[id.UserID]ReadReceipt `json:"m.read"`
|
||||
}
|
||||
|
||||
type ReadReceipt struct {
|
||||
Timestamp int64 `json:"ts"`
|
||||
|
||||
// Extra contains any unknown fields in the read receipt event.
|
||||
// Most servers don't allow clients to set them, so this will be empty in most cases.
|
||||
Extra map[string]interface{} `json:"-"`
|
||||
}
|
||||
|
||||
func (rr *ReadReceipt) UnmarshalJSON(data []byte) error {
|
||||
// Hacky compatibility hack against crappy clients that send double-encoded read receipts.
|
||||
// TODO is this actually needed? clients can't currently set custom content in receipts 🤔
|
||||
if data[0] == '"' && data[len(data)-1] == '"' {
|
||||
var strData string
|
||||
err := json.Unmarshal(data, &strData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data = []byte(strData)
|
||||
}
|
||||
|
||||
var parsed map[string]interface{}
|
||||
err := json.Unmarshal(data, &parsed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ts, _ := parsed["ts"].(float64)
|
||||
delete(parsed, "ts")
|
||||
*rr = ReadReceipt{
|
||||
Timestamp: int64(ts),
|
||||
Extra: parsed,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Presence string
|
||||
|
||||
const (
|
||||
PresenceOnline Presence = "online"
|
||||
PresenceOffline Presence = "offline"
|
||||
PresenceUnavailable Presence = "unavailable"
|
||||
)
|
||||
|
||||
// PresenceEventContent represents the content of a m.presence ephemeral event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-presence
|
||||
type PresenceEventContent struct {
|
||||
Presence Presence `json:"presence"`
|
||||
Displayname string `json:"displayname,omitempty"`
|
||||
AvatarURL id.ContentURIString `json:"avatar_url,omitempty"`
|
||||
LastActiveAgo int64 `json:"last_active_ago,omitempty"`
|
||||
CurrentlyActive bool `json:"currently_active,omitempty"`
|
||||
StatusMessage string `json:"status_msg,omitempty"`
|
||||
}
|
138
vendor/maunium.net/go/mautrix/event/events.go
generated
vendored
Normal file
138
vendor/maunium.net/go/mautrix/event/events.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Event represents a single Matrix event.
|
||||
type Event struct {
|
||||
StateKey *string `json:"state_key,omitempty"` // The state key for the event. Only present on State Events.
|
||||
Sender id.UserID `json:"sender,omitempty"` // The user ID of the sender of the event
|
||||
Type Type `json:"type"` // The event type
|
||||
Timestamp int64 `json:"origin_server_ts,omitempty"` // The unix timestamp when this message was sent by the origin server
|
||||
ID id.EventID `json:"event_id,omitempty"` // The unique ID of this event
|
||||
RoomID id.RoomID `json:"room_id,omitempty"` // The room the event was sent to. May be nil (e.g. for presence)
|
||||
Content Content `json:"content"` // The JSON content of the event.
|
||||
Redacts id.EventID `json:"redacts,omitempty"` // The event ID that was redacted if a m.room.redaction event
|
||||
Unsigned Unsigned `json:"unsigned,omitempty"` // Unsigned content set by own homeserver.
|
||||
|
||||
Mautrix MautrixInfo `json:"-"`
|
||||
|
||||
ToUserID id.UserID `json:"to_user_id,omitempty"` // The user ID that the to-device event was sent to. Only present in MSC2409 appservice transactions.
|
||||
ToDeviceID id.DeviceID `json:"to_device_id,omitempty"` // The device ID that the to-device event was sent to. Only present in MSC2409 appservice transactions.
|
||||
}
|
||||
|
||||
type eventForMarshaling struct {
|
||||
StateKey *string `json:"state_key,omitempty"`
|
||||
Sender id.UserID `json:"sender,omitempty"`
|
||||
Type Type `json:"type"`
|
||||
Timestamp int64 `json:"origin_server_ts,omitempty"`
|
||||
ID id.EventID `json:"event_id,omitempty"`
|
||||
RoomID id.RoomID `json:"room_id,omitempty"`
|
||||
Content Content `json:"content"`
|
||||
Redacts id.EventID `json:"redacts,omitempty"`
|
||||
Unsigned *Unsigned `json:"unsigned,omitempty"`
|
||||
|
||||
PrevContent *Content `json:"prev_content,omitempty"`
|
||||
ReplacesState *id.EventID `json:"replaces_state,omitempty"`
|
||||
|
||||
ToUserID id.UserID `json:"to_user_id,omitempty"`
|
||||
ToDeviceID id.DeviceID `json:"to_device_id,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals the event, including moving prev_content from the top level to inside unsigned.
|
||||
func (evt *Event) UnmarshalJSON(data []byte) error {
|
||||
var efm eventForMarshaling
|
||||
err := json.Unmarshal(data, &efm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
evt.StateKey = efm.StateKey
|
||||
evt.Sender = efm.Sender
|
||||
evt.Type = efm.Type
|
||||
evt.Timestamp = efm.Timestamp
|
||||
evt.ID = efm.ID
|
||||
evt.RoomID = efm.RoomID
|
||||
evt.Content = efm.Content
|
||||
evt.Redacts = efm.Redacts
|
||||
if efm.Unsigned != nil {
|
||||
evt.Unsigned = *efm.Unsigned
|
||||
}
|
||||
if efm.PrevContent != nil && evt.Unsigned.PrevContent == nil {
|
||||
evt.Unsigned.PrevContent = efm.PrevContent
|
||||
}
|
||||
if efm.ReplacesState != nil && *efm.ReplacesState != "" && evt.Unsigned.ReplacesState == "" {
|
||||
evt.Unsigned.ReplacesState = *efm.ReplacesState
|
||||
}
|
||||
evt.ToUserID = efm.ToUserID
|
||||
evt.ToDeviceID = efm.ToDeviceID
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the event, including omitting the unsigned field if it's empty.
|
||||
//
|
||||
// This is necessary because Unsigned is not a pointer (for convenience reasons),
|
||||
// and encoding/json doesn't know how to check if a non-pointer struct is empty.
|
||||
//
|
||||
// TODO(tulir): maybe it makes more sense to make Unsigned a pointer and make an easy and safe way to access it?
|
||||
func (evt *Event) MarshalJSON() ([]byte, error) {
|
||||
unsigned := &evt.Unsigned
|
||||
if unsigned.IsEmpty() {
|
||||
unsigned = nil
|
||||
}
|
||||
return json.Marshal(&eventForMarshaling{
|
||||
StateKey: evt.StateKey,
|
||||
Sender: evt.Sender,
|
||||
Type: evt.Type,
|
||||
Timestamp: evt.Timestamp,
|
||||
ID: evt.ID,
|
||||
RoomID: evt.RoomID,
|
||||
Content: evt.Content,
|
||||
Redacts: evt.Redacts,
|
||||
Unsigned: unsigned,
|
||||
ToUserID: evt.ToUserID,
|
||||
ToDeviceID: evt.ToDeviceID,
|
||||
})
|
||||
}
|
||||
|
||||
type MautrixInfo struct {
|
||||
Verified bool
|
||||
}
|
||||
|
||||
func (evt *Event) GetStateKey() string {
|
||||
if evt.StateKey != nil {
|
||||
return *evt.StateKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type StrippedState struct {
|
||||
Content Content `json:"content"`
|
||||
Type Type `json:"type"`
|
||||
StateKey string `json:"state_key"`
|
||||
}
|
||||
|
||||
type Unsigned struct {
|
||||
PrevContent *Content `json:"prev_content,omitempty"`
|
||||
PrevSender id.UserID `json:"prev_sender,omitempty"`
|
||||
ReplacesState id.EventID `json:"replaces_state,omitempty"`
|
||||
Age int64 `json:"age,omitempty"`
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
Relations Relations `json:"m.relations,omitempty"`
|
||||
RedactedBecause *Event `json:"redacted_because,omitempty"`
|
||||
InviteRoomState []StrippedState `json:"invite_room_state,omitempty"`
|
||||
}
|
||||
|
||||
func (us *Unsigned) IsEmpty() bool {
|
||||
return us.PrevContent == nil && us.PrevSender == "" && us.ReplacesState == "" && us.Age == 0 &&
|
||||
us.TransactionID == "" && us.RedactedBecause == nil && us.InviteRoomState == nil && us.Relations.Raw == nil &&
|
||||
us.Relations.Annotations.Map == nil && us.Relations.References.List == nil && us.Relations.Replaces.List == nil
|
||||
}
|
53
vendor/maunium.net/go/mautrix/event/member.go
generated
vendored
Normal file
53
vendor/maunium.net/go/mautrix/event/member.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Membership is an enum specifying the membership state of a room member.
|
||||
type Membership string
|
||||
|
||||
func (ms Membership) IsInviteOrJoin() bool {
|
||||
return ms == MembershipJoin || ms == MembershipInvite
|
||||
}
|
||||
|
||||
func (ms Membership) IsLeaveOrBan() bool {
|
||||
return ms == MembershipLeave || ms == MembershipBan
|
||||
}
|
||||
|
||||
// The allowed membership states as specified in spec section 10.5.5.
|
||||
const (
|
||||
MembershipJoin Membership = "join"
|
||||
MembershipLeave Membership = "leave"
|
||||
MembershipInvite Membership = "invite"
|
||||
MembershipBan Membership = "ban"
|
||||
MembershipKnock Membership = "knock"
|
||||
)
|
||||
|
||||
// MemberEventContent represents the content of a m.room.member state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-member
|
||||
type MemberEventContent struct {
|
||||
Membership Membership `json:"membership"`
|
||||
AvatarURL id.ContentURIString `json:"avatar_url,omitempty"`
|
||||
Displayname string `json:"displayname,omitempty"`
|
||||
IsDirect bool `json:"is_direct,omitempty"`
|
||||
ThirdPartyInvite *ThirdPartyInvite `json:"third_party_invite,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
type ThirdPartyInvite struct {
|
||||
DisplayName string `json:"display_name"`
|
||||
Signed struct {
|
||||
Token string `json:"token"`
|
||||
Signatures json.RawMessage `json:"signatures"`
|
||||
MXID string `json:"mxid"`
|
||||
}
|
||||
}
|
246
vendor/maunium.net/go/mautrix/event/message.go
generated
vendored
Normal file
246
vendor/maunium.net/go/mautrix/event/message.go
generated
vendored
Normal file
@ -0,0 +1,246 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/attachment"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// MessageType is the sub-type of a m.room.message event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-message-msgtypes
|
||||
type MessageType string
|
||||
|
||||
// Msgtypes
|
||||
const (
|
||||
MsgText MessageType = "m.text"
|
||||
MsgEmote MessageType = "m.emote"
|
||||
MsgNotice MessageType = "m.notice"
|
||||
MsgImage MessageType = "m.image"
|
||||
MsgLocation MessageType = "m.location"
|
||||
MsgVideo MessageType = "m.video"
|
||||
MsgAudio MessageType = "m.audio"
|
||||
MsgFile MessageType = "m.file"
|
||||
|
||||
MsgVerificationRequest MessageType = "m.key.verification.request"
|
||||
)
|
||||
|
||||
// Format specifies the format of the formatted_body in m.room.message events.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-message-msgtypes
|
||||
type Format string
|
||||
|
||||
// Message formats
|
||||
const (
|
||||
FormatHTML Format = "org.matrix.custom.html"
|
||||
)
|
||||
|
||||
// RedactionEventContent represents the content of a m.room.redaction message event.
|
||||
//
|
||||
// The redacted event ID is still at the top level, but will move in a future room version.
|
||||
// See https://github.com/matrix-org/matrix-doc/pull/2244 and https://github.com/matrix-org/matrix-doc/pull/2174
|
||||
//
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-redaction
|
||||
type RedactionEventContent struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
// ReactionEventContent represents the content of a m.reaction message event.
|
||||
// This is not yet in a spec release, see https://github.com/matrix-org/matrix-doc/pull/1849
|
||||
type ReactionEventContent struct {
|
||||
RelatesTo RelatesTo `json:"m.relates_to"`
|
||||
}
|
||||
|
||||
func (content *ReactionEventContent) GetRelatesTo() *RelatesTo {
|
||||
return &content.RelatesTo
|
||||
}
|
||||
|
||||
func (content *ReactionEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return &content.RelatesTo
|
||||
}
|
||||
|
||||
func (content *ReactionEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
content.RelatesTo = *rel
|
||||
}
|
||||
|
||||
// MssageEventContent represents the content of a m.room.message event.
|
||||
//
|
||||
// It is also used to represent m.sticker events, as they are equivalent to m.room.message
|
||||
// with the exception of the msgtype field.
|
||||
//
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-message
|
||||
type MessageEventContent struct {
|
||||
// Base m.room.message fields
|
||||
MsgType MessageType `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
|
||||
// Extra fields for text types
|
||||
Format Format `json:"format,omitempty"`
|
||||
FormattedBody string `json:"formatted_body,omitempty"`
|
||||
|
||||
// Extra field for m.location
|
||||
GeoURI string `json:"geo_uri,omitempty"`
|
||||
|
||||
// Extra fields for media types
|
||||
URL id.ContentURIString `json:"url,omitempty"`
|
||||
Info *FileInfo `json:"info,omitempty"`
|
||||
File *EncryptedFileInfo `json:"file,omitempty"`
|
||||
|
||||
// Edits and relations
|
||||
NewContent *MessageEventContent `json:"m.new_content,omitempty"`
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
|
||||
// In-room verification
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
FromDevice id.DeviceID `json:"from_device,omitempty"`
|
||||
Methods []VerificationMethod `json:"methods,omitempty"`
|
||||
|
||||
replyFallbackRemoved bool
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) GetRelatesTo() *RelatesTo {
|
||||
if content.RelatesTo == nil {
|
||||
content.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return content.RelatesTo
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return content.RelatesTo
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
content.RelatesTo = rel
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) SetEdit(original id.EventID) {
|
||||
newContent := *content
|
||||
content.NewContent = &newContent
|
||||
content.RelatesTo = &RelatesTo{
|
||||
Type: RelReplace,
|
||||
EventID: original,
|
||||
}
|
||||
if content.MsgType == MsgText || content.MsgType == MsgNotice {
|
||||
content.Body = "* " + content.Body
|
||||
if content.Format == FormatHTML && len(content.FormattedBody) > 0 {
|
||||
content.FormattedBody = "* " + content.FormattedBody
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) GetFile() *EncryptedFileInfo {
|
||||
if content.File == nil {
|
||||
content.File = &EncryptedFileInfo{}
|
||||
}
|
||||
return content.File
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) GetInfo() *FileInfo {
|
||||
if content.Info == nil {
|
||||
content.Info = &FileInfo{}
|
||||
}
|
||||
return content.Info
|
||||
}
|
||||
|
||||
type EncryptedFileInfo struct {
|
||||
attachment.EncryptedFile
|
||||
URL id.ContentURIString `json:"url"`
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
MimeType string `json:"mimetype,omitempty"`
|
||||
ThumbnailInfo *FileInfo `json:"thumbnail_info,omitempty"`
|
||||
ThumbnailURL id.ContentURIString `json:"thumbnail_url,omitempty"`
|
||||
ThumbnailFile *EncryptedFileInfo `json:"thumbnail_file,omitempty"`
|
||||
Width int `json:"-"`
|
||||
Height int `json:"-"`
|
||||
Duration int `json:"-"`
|
||||
Size int `json:"-"`
|
||||
}
|
||||
|
||||
type serializableFileInfo struct {
|
||||
MimeType string `json:"mimetype,omitempty"`
|
||||
ThumbnailInfo *serializableFileInfo `json:"thumbnail_info,omitempty"`
|
||||
ThumbnailURL id.ContentURIString `json:"thumbnail_url,omitempty"`
|
||||
ThumbnailFile *EncryptedFileInfo `json:"thumbnail_file,omitempty"`
|
||||
|
||||
Width json.Number `json:"w,omitempty"`
|
||||
Height json.Number `json:"h,omitempty"`
|
||||
Duration json.Number `json:"duration,omitempty"`
|
||||
Size json.Number `json:"size,omitempty"`
|
||||
}
|
||||
|
||||
func (sfi *serializableFileInfo) CopyFrom(fileInfo *FileInfo) *serializableFileInfo {
|
||||
if fileInfo == nil {
|
||||
return nil
|
||||
}
|
||||
*sfi = serializableFileInfo{
|
||||
MimeType: fileInfo.MimeType,
|
||||
ThumbnailURL: fileInfo.ThumbnailURL,
|
||||
ThumbnailInfo: (&serializableFileInfo{}).CopyFrom(fileInfo.ThumbnailInfo),
|
||||
ThumbnailFile: fileInfo.ThumbnailFile,
|
||||
}
|
||||
if fileInfo.Width > 0 {
|
||||
sfi.Width = json.Number(strconv.Itoa(fileInfo.Width))
|
||||
}
|
||||
if fileInfo.Height > 0 {
|
||||
sfi.Height = json.Number(strconv.Itoa(fileInfo.Height))
|
||||
}
|
||||
if fileInfo.Size > 0 {
|
||||
sfi.Size = json.Number(strconv.Itoa(fileInfo.Size))
|
||||
|
||||
}
|
||||
if fileInfo.Duration > 0 {
|
||||
sfi.Duration = json.Number(strconv.Itoa(int(fileInfo.Duration)))
|
||||
}
|
||||
return sfi
|
||||
}
|
||||
|
||||
func (sfi *serializableFileInfo) CopyTo(fileInfo *FileInfo) {
|
||||
*fileInfo = FileInfo{
|
||||
Width: numberToInt(sfi.Width),
|
||||
Height: numberToInt(sfi.Height),
|
||||
Size: numberToInt(sfi.Size),
|
||||
Duration: numberToInt(sfi.Duration),
|
||||
MimeType: sfi.MimeType,
|
||||
ThumbnailURL: sfi.ThumbnailURL,
|
||||
}
|
||||
if sfi.ThumbnailInfo != nil {
|
||||
fileInfo.ThumbnailInfo = &FileInfo{}
|
||||
sfi.ThumbnailInfo.CopyTo(fileInfo.ThumbnailInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func (fileInfo *FileInfo) UnmarshalJSON(data []byte) error {
|
||||
sfi := &serializableFileInfo{}
|
||||
if err := json.Unmarshal(data, sfi); err != nil {
|
||||
return err
|
||||
}
|
||||
sfi.CopyTo(fileInfo)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fileInfo *FileInfo) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal((&serializableFileInfo{}).CopyFrom(fileInfo))
|
||||
}
|
||||
|
||||
func numberToInt(val json.Number) int {
|
||||
f64, _ := val.Float64()
|
||||
if f64 > 0 {
|
||||
return int(f64)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fileInfo *FileInfo) GetThumbnailInfo() *FileInfo {
|
||||
if fileInfo.ThumbnailInfo == nil {
|
||||
fileInfo.ThumbnailInfo = &FileInfo{}
|
||||
}
|
||||
return fileInfo.ThumbnailInfo
|
||||
}
|
136
vendor/maunium.net/go/mautrix/event/powerlevels.go
generated
vendored
Normal file
136
vendor/maunium.net/go/mautrix/event/powerlevels.go
generated
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// PowerLevelsEventContent represents the content of a m.room.power_levels state event content.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-power-levels
|
||||
type PowerLevelsEventContent struct {
|
||||
usersLock sync.RWMutex `json:"-"`
|
||||
Users map[id.UserID]int `json:"users,omitempty"`
|
||||
UsersDefault int `json:"users_default,omitempty"`
|
||||
|
||||
eventsLock sync.RWMutex `json:"-"`
|
||||
Events map[string]int `json:"events,omitempty"`
|
||||
EventsDefault int `json:"events_default,omitempty"`
|
||||
|
||||
StateDefaultPtr *int `json:"state_default,omitempty"`
|
||||
|
||||
InvitePtr *int `json:"invite,omitempty"`
|
||||
KickPtr *int `json:"kick,omitempty"`
|
||||
BanPtr *int `json:"ban,omitempty"`
|
||||
RedactPtr *int `json:"redact,omitempty"`
|
||||
HistoricalPtr *int `json:"historical,omitempty"`
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) Invite() int {
|
||||
if pl.InvitePtr != nil {
|
||||
return *pl.InvitePtr
|
||||
}
|
||||
return 50
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) Kick() int {
|
||||
if pl.KickPtr != nil {
|
||||
return *pl.KickPtr
|
||||
}
|
||||
return 50
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) Ban() int {
|
||||
if pl.BanPtr != nil {
|
||||
return *pl.BanPtr
|
||||
}
|
||||
return 50
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) Redact() int {
|
||||
if pl.RedactPtr != nil {
|
||||
return *pl.RedactPtr
|
||||
}
|
||||
return 50
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) Historical() int {
|
||||
if pl.HistoricalPtr != nil {
|
||||
return *pl.HistoricalPtr
|
||||
}
|
||||
return 100
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) StateDefault() int {
|
||||
if pl.StateDefaultPtr != nil {
|
||||
return *pl.StateDefaultPtr
|
||||
}
|
||||
return 50
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) GetUserLevel(userID id.UserID) int {
|
||||
pl.usersLock.RLock()
|
||||
defer pl.usersLock.RUnlock()
|
||||
level, ok := pl.Users[userID]
|
||||
if !ok {
|
||||
return pl.UsersDefault
|
||||
}
|
||||
return level
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) SetUserLevel(userID id.UserID, level int) {
|
||||
pl.usersLock.Lock()
|
||||
defer pl.usersLock.Unlock()
|
||||
if level == pl.UsersDefault {
|
||||
delete(pl.Users, userID)
|
||||
} else {
|
||||
pl.Users[userID] = level
|
||||
}
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) EnsureUserLevel(userID id.UserID, level int) bool {
|
||||
existingLevel := pl.GetUserLevel(userID)
|
||||
if existingLevel != level {
|
||||
pl.SetUserLevel(userID, level)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) GetEventLevel(eventType Type) int {
|
||||
pl.eventsLock.RLock()
|
||||
defer pl.eventsLock.RUnlock()
|
||||
level, ok := pl.Events[eventType.String()]
|
||||
if !ok {
|
||||
if eventType.IsState() {
|
||||
return pl.StateDefault()
|
||||
}
|
||||
return pl.EventsDefault
|
||||
}
|
||||
return level
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) SetEventLevel(eventType Type, level int) {
|
||||
pl.eventsLock.Lock()
|
||||
defer pl.eventsLock.Unlock()
|
||||
if (eventType.IsState() && level == pl.StateDefault()) || (!eventType.IsState() && level == pl.EventsDefault) {
|
||||
delete(pl.Events, eventType.String())
|
||||
} else {
|
||||
pl.Events[eventType.String()] = level
|
||||
}
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) EnsureEventLevel(eventType Type, level int) bool {
|
||||
existingLevel := pl.GetEventLevel(eventType)
|
||||
if existingLevel != level {
|
||||
pl.SetEventLevel(eventType, level)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
200
vendor/maunium.net/go/mautrix/event/relations.go
generated
vendored
Normal file
200
vendor/maunium.net/go/mautrix/event/relations.go
generated
vendored
Normal file
@ -0,0 +1,200 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type RelationType string
|
||||
|
||||
const (
|
||||
RelReplace RelationType = "m.replace"
|
||||
RelReference RelationType = "m.reference"
|
||||
RelAnnotation RelationType = "m.annotation"
|
||||
RelReply RelationType = "net.maunium.reply"
|
||||
)
|
||||
|
||||
type RelatesTo struct {
|
||||
Type RelationType
|
||||
EventID id.EventID
|
||||
Key string
|
||||
}
|
||||
|
||||
type serializableInReplyTo struct {
|
||||
EventID id.EventID `json:"event_id,omitempty"`
|
||||
}
|
||||
|
||||
type serializableRelatesTo struct {
|
||||
InReplyTo *serializableInReplyTo `json:"m.in_reply_to,omitempty"`
|
||||
|
||||
Type RelationType `json:"rel_type,omitempty"`
|
||||
EventID id.EventID `json:"event_id,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) GetReplaceID() id.EventID {
|
||||
if rel.Type == RelReplace {
|
||||
return rel.EventID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) GetReferenceID() id.EventID {
|
||||
if rel.Type == RelReference {
|
||||
return rel.EventID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) GetReplyID() id.EventID {
|
||||
if rel.Type == RelReply {
|
||||
return rel.EventID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) GetAnnotationID() id.EventID {
|
||||
if rel.Type == RelAnnotation {
|
||||
return rel.EventID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) GetAnnotationKey() string {
|
||||
if rel.Type == RelAnnotation {
|
||||
return rel.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) UnmarshalJSON(data []byte) error {
|
||||
var srel serializableRelatesTo
|
||||
if err := json.Unmarshal(data, &srel); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(srel.Type) > 0 {
|
||||
rel.Type = srel.Type
|
||||
rel.EventID = srel.EventID
|
||||
rel.Key = srel.Key
|
||||
} else if srel.InReplyTo != nil && len(srel.InReplyTo.EventID) > 0 {
|
||||
rel.Type = RelReply
|
||||
rel.EventID = srel.InReplyTo.EventID
|
||||
rel.Key = ""
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) MarshalJSON() ([]byte, error) {
|
||||
srel := serializableRelatesTo{Type: rel.Type, EventID: rel.EventID, Key: rel.Key}
|
||||
if rel.Type == RelReply {
|
||||
srel.InReplyTo = &serializableInReplyTo{rel.EventID}
|
||||
}
|
||||
return json.Marshal(&srel)
|
||||
}
|
||||
|
||||
type RelationChunkItem struct {
|
||||
Type RelationType `json:"type"`
|
||||
EventID string `json:"event_id,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
}
|
||||
|
||||
type RelationChunk struct {
|
||||
Chunk []RelationChunkItem `json:"chunk"`
|
||||
|
||||
Limited bool `json:"limited"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
type AnnotationChunk struct {
|
||||
RelationChunk
|
||||
Map map[string]int `json:"-"`
|
||||
}
|
||||
|
||||
type serializableAnnotationChunk AnnotationChunk
|
||||
|
||||
func (ac *AnnotationChunk) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, (*serializableAnnotationChunk)(ac)); err != nil {
|
||||
return err
|
||||
}
|
||||
ac.Map = make(map[string]int)
|
||||
for _, item := range ac.Chunk {
|
||||
ac.Map[item.Key] += item.Count
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ac *AnnotationChunk) Serialize() RelationChunk {
|
||||
ac.Chunk = make([]RelationChunkItem, len(ac.Map))
|
||||
i := 0
|
||||
for key, count := range ac.Map {
|
||||
ac.Chunk[i] = RelationChunkItem{
|
||||
Type: RelAnnotation,
|
||||
Key: key,
|
||||
Count: count,
|
||||
}
|
||||
}
|
||||
return ac.RelationChunk
|
||||
}
|
||||
|
||||
type EventIDChunk struct {
|
||||
RelationChunk
|
||||
List []string `json:"-"`
|
||||
}
|
||||
|
||||
type serializableEventIDChunk EventIDChunk
|
||||
|
||||
func (ec *EventIDChunk) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, (*serializableEventIDChunk)(ec)); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range ec.Chunk {
|
||||
ec.List = append(ec.List, item.EventID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ec *EventIDChunk) Serialize(typ RelationType) RelationChunk {
|
||||
ec.Chunk = make([]RelationChunkItem, len(ec.List))
|
||||
for i, eventID := range ec.List {
|
||||
ec.Chunk[i] = RelationChunkItem{
|
||||
Type: typ,
|
||||
EventID: eventID,
|
||||
}
|
||||
}
|
||||
return ec.RelationChunk
|
||||
}
|
||||
|
||||
type Relations struct {
|
||||
Raw map[RelationType]RelationChunk `json:"-"`
|
||||
|
||||
Annotations AnnotationChunk `json:"m.annotation,omitempty"`
|
||||
References EventIDChunk `json:"m.reference,omitempty"`
|
||||
Replaces EventIDChunk `json:"m.replace,omitempty"`
|
||||
}
|
||||
|
||||
type serializableRelations Relations
|
||||
|
||||
func (relations *Relations) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &relations.Raw); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, (*serializableRelations)(relations))
|
||||
}
|
||||
|
||||
func (relations *Relations) MarshalJSON() ([]byte, error) {
|
||||
if relations.Raw == nil {
|
||||
relations.Raw = make(map[RelationType]RelationChunk)
|
||||
}
|
||||
relations.Raw[RelAnnotation] = relations.Annotations.Serialize()
|
||||
relations.Raw[RelReference] = relations.References.Serialize(RelReference)
|
||||
relations.Raw[RelReplace] = relations.Replaces.Serialize(RelReplace)
|
||||
return json.Marshal(relations.Raw)
|
||||
}
|
108
vendor/maunium.net/go/mautrix/event/reply.go
generated
vendored
Normal file
108
vendor/maunium.net/go/mautrix/event/reply.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
var HTMLReplyFallbackRegex = regexp.MustCompile(`^<mx-reply>[\s\S]+?</mx-reply>`)
|
||||
|
||||
func TrimReplyFallbackHTML(html string) string {
|
||||
return HTMLReplyFallbackRegex.ReplaceAllString(html, "")
|
||||
}
|
||||
|
||||
func TrimReplyFallbackText(text string) string {
|
||||
if !strings.HasPrefix(text, "> ") || !strings.Contains(text, "\n") {
|
||||
return text
|
||||
}
|
||||
|
||||
lines := strings.Split(text, "\n")
|
||||
for len(lines) > 0 && strings.HasPrefix(lines[0], "> ") {
|
||||
lines = lines[1:]
|
||||
}
|
||||
return strings.TrimSpace(strings.Join(lines, "\n"))
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) RemoveReplyFallback() {
|
||||
if len(content.GetReplyTo()) > 0 && !content.replyFallbackRemoved {
|
||||
if content.Format == FormatHTML {
|
||||
content.FormattedBody = TrimReplyFallbackHTML(content.FormattedBody)
|
||||
}
|
||||
content.Body = TrimReplyFallbackText(content.Body)
|
||||
content.replyFallbackRemoved = true
|
||||
}
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) GetReplyTo() id.EventID {
|
||||
if content.RelatesTo != nil && content.RelatesTo.Type == RelReply {
|
||||
return content.RelatesTo.EventID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
const ReplyFormat = `<mx-reply><blockquote><a href="https://matrix.to/#/%s/%s">In reply to</a> <a href="https://matrix.to/#/%s">%s</a><br>%s</blockquote></mx-reply>`
|
||||
|
||||
func (evt *Event) GenerateReplyFallbackHTML() string {
|
||||
parsedContent, ok := evt.Content.Parsed.(*MessageEventContent)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
parsedContent.RemoveReplyFallback()
|
||||
body := parsedContent.FormattedBody
|
||||
if len(body) == 0 {
|
||||
body = html.EscapeString(parsedContent.Body)
|
||||
}
|
||||
|
||||
senderDisplayName := evt.Sender
|
||||
|
||||
return fmt.Sprintf(ReplyFormat, evt.RoomID, evt.ID, evt.Sender, senderDisplayName, body)
|
||||
}
|
||||
|
||||
func (evt *Event) GenerateReplyFallbackText() string {
|
||||
parsedContent, ok := evt.Content.Parsed.(*MessageEventContent)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
parsedContent.RemoveReplyFallback()
|
||||
body := parsedContent.Body
|
||||
lines := strings.Split(strings.TrimSpace(body), "\n")
|
||||
firstLine, lines := lines[0], lines[1:]
|
||||
|
||||
senderDisplayName := evt.Sender
|
||||
|
||||
var fallbackText strings.Builder
|
||||
_, _ = fmt.Fprintf(&fallbackText, "> <%s> %s", senderDisplayName, firstLine)
|
||||
for _, line := range lines {
|
||||
_, _ = fmt.Fprintf(&fallbackText, "\n> %s", line)
|
||||
}
|
||||
fallbackText.WriteString("\n\n")
|
||||
return fallbackText.String()
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) SetReply(inReplyTo *Event) {
|
||||
content.RelatesTo = &RelatesTo{
|
||||
EventID: inReplyTo.ID,
|
||||
Type: RelReply,
|
||||
}
|
||||
|
||||
if content.MsgType == MsgText || content.MsgType == MsgNotice {
|
||||
if len(content.FormattedBody) == 0 || content.Format != FormatHTML {
|
||||
content.FormattedBody = html.EscapeString(content.Body)
|
||||
content.Format = FormatHTML
|
||||
}
|
||||
content.FormattedBody = inReplyTo.GenerateReplyFallbackHTML() + content.FormattedBody
|
||||
content.Body = inReplyTo.GenerateReplyFallbackText() + content.Body
|
||||
content.replyFallbackRemoved = false
|
||||
}
|
||||
}
|
138
vendor/maunium.net/go/mautrix/event/state.go
generated
vendored
Normal file
138
vendor/maunium.net/go/mautrix/event/state.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// CanonicalAliasEventContent represents the content of a m.room.canonical_alias state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.1#m-room-canonical-alias
|
||||
type CanonicalAliasEventContent struct {
|
||||
Alias id.RoomAlias `json:"alias"`
|
||||
AltAliases []id.RoomAlias `json:"alt_aliases,omitempty"`
|
||||
}
|
||||
|
||||
// RoomNameEventContent represents the content of a m.room.name state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-name
|
||||
type RoomNameEventContent struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// RoomAvatarEventContent represents the content of a m.room.avatar state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-avatar
|
||||
type RoomAvatarEventContent struct {
|
||||
URL id.ContentURI `json:"url"`
|
||||
}
|
||||
|
||||
// TopicEventContent represents the content of a m.room.topic state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-topic
|
||||
type TopicEventContent struct {
|
||||
Topic string `json:"topic"`
|
||||
}
|
||||
|
||||
// TombstoneEventContent represents the content of a m.room.tombstone state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-tombstone
|
||||
type TombstoneEventContent struct {
|
||||
Body string `json:"body"`
|
||||
ReplacementRoom id.RoomID `json:"replacement_room"`
|
||||
}
|
||||
|
||||
// CreateEventContent represents the content of a m.room.create state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-create
|
||||
type CreateEventContent struct {
|
||||
Type RoomType `json:"type,omitempty"`
|
||||
Creator id.UserID `json:"creator,omitempty"`
|
||||
Federate bool `json:"m.federate,omitempty"`
|
||||
RoomVersion string `json:"version,omitempty"`
|
||||
Predecessor struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
EventID id.EventID `json:"event_id"`
|
||||
} `json:"predecessor"`
|
||||
}
|
||||
|
||||
// JoinRule specifies how open a room is to new members.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-join-rules
|
||||
type JoinRule string
|
||||
|
||||
const (
|
||||
JoinRulePublic JoinRule = "public"
|
||||
JoinRuleKnock JoinRule = "knock"
|
||||
JoinRuleInvite JoinRule = "invite"
|
||||
JoinRulePrivate JoinRule = "private"
|
||||
)
|
||||
|
||||
// JoinRulesEventContent represents the content of a m.room.join_rules state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-join-rules
|
||||
type JoinRulesEventContent struct {
|
||||
JoinRule JoinRule `json:"join_rule"`
|
||||
}
|
||||
|
||||
// PinnedEventsEventContent represents the content of a m.room.pinned_events state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-pinned-events
|
||||
type PinnedEventsEventContent struct {
|
||||
Pinned []id.EventID `json:"pinned"`
|
||||
}
|
||||
|
||||
// HistoryVisibility specifies who can see new messages.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-history-visibility
|
||||
type HistoryVisibility string
|
||||
|
||||
const (
|
||||
HistoryVisibilityInvited HistoryVisibility = "invited"
|
||||
HistoryVisibilityJoined HistoryVisibility = "joined"
|
||||
HistoryVisibilityShared HistoryVisibility = "shared"
|
||||
HistoryVisibilityWorldReadable HistoryVisibility = "world_readable"
|
||||
)
|
||||
|
||||
// HistoryVisibilityEventContent represents the content of a m.room.history_visibility state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-history-visibility
|
||||
type HistoryVisibilityEventContent struct {
|
||||
HistoryVisibility HistoryVisibility `json:"history_visibility"`
|
||||
}
|
||||
|
||||
// GuestAccess specifies whether or not guest accounts can join.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-guest-access
|
||||
type GuestAccess string
|
||||
|
||||
const (
|
||||
GuestAccessCanJoin GuestAccess = "can_join"
|
||||
GuestAccessForbidden GuestAccess = "forbidden"
|
||||
)
|
||||
|
||||
// GuestAccessEventContent represents the content of a m.room.guest_access state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-guest-access
|
||||
type GuestAccessEventContent struct {
|
||||
GuestAccess GuestAccess `json:"guest_access"`
|
||||
}
|
||||
|
||||
type BridgeInfoSection struct {
|
||||
ID string `json:"id"`
|
||||
DisplayName string `json:"displayname,omitempty"`
|
||||
AvatarURL id.ContentURIString `json:"avatar_url,omitempty"`
|
||||
ExternalURL string `json:"external_url,omitempty"`
|
||||
}
|
||||
|
||||
// BridgeEventContent represents the content of a m.bridge state event.
|
||||
// https://github.com/matrix-org/matrix-doc/pull/2346
|
||||
type BridgeEventContent struct {
|
||||
BridgeBot id.UserID `json:"bridgebot"`
|
||||
Creator id.UserID `json:"creator,omitempty"`
|
||||
Protocol BridgeInfoSection `json:"protocol"`
|
||||
Network *BridgeInfoSection `json:"network,omitempty"`
|
||||
Channel BridgeInfoSection `json:"channel"`
|
||||
}
|
||||
|
||||
type SpaceChildEventContent struct {
|
||||
Via []string `json:"via,omitempty"`
|
||||
Order string `json:"order,omitempty"`
|
||||
}
|
||||
|
||||
type SpaceParentEventContent struct {
|
||||
Via []string `json:"via,omitempty"`
|
||||
Canonical bool `json:"canonical,omitempty"`
|
||||
}
|
248
vendor/maunium.net/go/mautrix/event/type.go
generated
vendored
Normal file
248
vendor/maunium.net/go/mautrix/event/type.go
generated
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RoomType string
|
||||
|
||||
const (
|
||||
RoomTypeDefault RoomType = ""
|
||||
RoomTypeSpace RoomType = "m.space"
|
||||
)
|
||||
|
||||
type TypeClass int
|
||||
|
||||
func (tc TypeClass) Name() string {
|
||||
switch tc {
|
||||
case MessageEventType:
|
||||
return "message"
|
||||
case StateEventType:
|
||||
return "state"
|
||||
case EphemeralEventType:
|
||||
return "ephemeral"
|
||||
case AccountDataEventType:
|
||||
return "account data"
|
||||
case ToDeviceEventType:
|
||||
return "to-device"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// Unknown events
|
||||
UnknownEventType TypeClass = iota
|
||||
// Normal message events
|
||||
MessageEventType
|
||||
// State events
|
||||
StateEventType
|
||||
// Ephemeral events
|
||||
EphemeralEventType
|
||||
// Account data events
|
||||
AccountDataEventType
|
||||
// Device-to-device events
|
||||
ToDeviceEventType
|
||||
)
|
||||
|
||||
type Type struct {
|
||||
Type string
|
||||
Class TypeClass
|
||||
}
|
||||
|
||||
func NewEventType(name string) Type {
|
||||
evtType := Type{Type: name}
|
||||
evtType.Class = evtType.GuessClass()
|
||||
return evtType
|
||||
}
|
||||
|
||||
func (et *Type) IsState() bool {
|
||||
return et.Class == StateEventType
|
||||
}
|
||||
|
||||
func (et *Type) IsEphemeral() bool {
|
||||
return et.Class == EphemeralEventType
|
||||
}
|
||||
|
||||
func (et *Type) IsAccountData() bool {
|
||||
return et.Class == AccountDataEventType
|
||||
}
|
||||
|
||||
func (et *Type) IsToDevice() bool {
|
||||
return et.Class == ToDeviceEventType
|
||||
}
|
||||
|
||||
func (et *Type) IsInRoomVerification() bool {
|
||||
switch et.Type {
|
||||
case InRoomVerificationStart.Type, InRoomVerificationReady.Type, InRoomVerificationAccept.Type,
|
||||
InRoomVerificationKey.Type, InRoomVerificationMAC.Type, InRoomVerificationCancel.Type:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (et *Type) IsCall() bool {
|
||||
switch et.Type {
|
||||
case CallInvite.Type, CallCandidates.Type, CallAnswer.Type, CallReject.Type, CallSelectAnswer.Type,
|
||||
CallNegotiate.Type, CallHangup.Type:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (et *Type) IsCustom() bool {
|
||||
return !strings.HasPrefix(et.Type, "m.")
|
||||
}
|
||||
|
||||
func (et *Type) GuessClass() TypeClass {
|
||||
switch et.Type {
|
||||
case StateAliases.Type, StateCanonicalAlias.Type, StateCreate.Type, StateJoinRules.Type, StateMember.Type,
|
||||
StatePowerLevels.Type, StateRoomName.Type, StateRoomAvatar.Type, StateTopic.Type, StatePinnedEvents.Type,
|
||||
StateTombstone.Type, StateEncryption.Type, StateBridge.Type, StateHalfShotBridge.Type, StateSpaceParent.Type,
|
||||
StateSpaceChild.Type:
|
||||
return StateEventType
|
||||
case EphemeralEventReceipt.Type, EphemeralEventTyping.Type, EphemeralEventPresence.Type:
|
||||
return EphemeralEventType
|
||||
case AccountDataDirectChats.Type, AccountDataPushRules.Type, AccountDataRoomTags.Type,
|
||||
AccountDataSecretStorageKey.Type, AccountDataSecretStorageDefaultKey.Type,
|
||||
AccountDataCrossSigningMaster.Type, AccountDataCrossSigningSelf.Type, AccountDataCrossSigningUser.Type:
|
||||
return AccountDataEventType
|
||||
case EventRedaction.Type, EventMessage.Type, EventEncrypted.Type, EventReaction.Type, EventSticker.Type,
|
||||
InRoomVerificationStart.Type, InRoomVerificationReady.Type, InRoomVerificationAccept.Type,
|
||||
InRoomVerificationKey.Type, InRoomVerificationMAC.Type, InRoomVerificationCancel.Type,
|
||||
CallInvite.Type, CallCandidates.Type, CallAnswer.Type, CallReject.Type, CallSelectAnswer.Type,
|
||||
CallNegotiate.Type, CallHangup.Type:
|
||||
return MessageEventType
|
||||
case ToDeviceRoomKey.Type, ToDeviceRoomKeyRequest.Type, ToDeviceForwardedRoomKey.Type, ToDeviceRoomKeyWithheld.Type:
|
||||
return ToDeviceEventType
|
||||
default:
|
||||
return UnknownEventType
|
||||
}
|
||||
}
|
||||
|
||||
func (et *Type) UnmarshalJSON(data []byte) error {
|
||||
err := json.Unmarshal(data, &et.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
et.Class = et.GuessClass()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (et *Type) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(&et.Type)
|
||||
}
|
||||
|
||||
func (et Type) UnmarshalText(data []byte) error {
|
||||
et.Type = string(data)
|
||||
et.Class = et.GuessClass()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (et Type) MarshalText() ([]byte, error) {
|
||||
return []byte(et.Type), nil
|
||||
}
|
||||
|
||||
func (et *Type) String() string {
|
||||
return et.Type
|
||||
}
|
||||
|
||||
func (et *Type) Repr() string {
|
||||
return fmt.Sprintf("%s (%s)", et.Type, et.Class.Name())
|
||||
}
|
||||
|
||||
// State events
|
||||
var (
|
||||
StateAliases = Type{"m.room.aliases", StateEventType}
|
||||
StateCanonicalAlias = Type{"m.room.canonical_alias", StateEventType}
|
||||
StateCreate = Type{"m.room.create", StateEventType}
|
||||
StateJoinRules = Type{"m.room.join_rules", StateEventType}
|
||||
StateHistoryVisibility = Type{"m.room.history_visibility", StateEventType}
|
||||
StateGuestAccess = Type{"m.room.guest_access", StateEventType}
|
||||
StateMember = Type{"m.room.member", StateEventType}
|
||||
StatePowerLevels = Type{"m.room.power_levels", StateEventType}
|
||||
StateRoomName = Type{"m.room.name", StateEventType}
|
||||
StateTopic = Type{"m.room.topic", StateEventType}
|
||||
StateRoomAvatar = Type{"m.room.avatar", StateEventType}
|
||||
StatePinnedEvents = Type{"m.room.pinned_events", StateEventType}
|
||||
StateTombstone = Type{"m.room.tombstone", StateEventType}
|
||||
StateEncryption = Type{"m.room.encryption", StateEventType}
|
||||
StateBridge = Type{"m.bridge", StateEventType}
|
||||
StateHalfShotBridge = Type{"uk.half-shot.bridge", StateEventType}
|
||||
StateSpaceChild = Type{"m.space.child", StateEventType}
|
||||
StateSpaceParent = Type{"m.space.parent", StateEventType}
|
||||
)
|
||||
|
||||
// Message events
|
||||
var (
|
||||
EventRedaction = Type{"m.room.redaction", MessageEventType}
|
||||
EventMessage = Type{"m.room.message", MessageEventType}
|
||||
EventEncrypted = Type{"m.room.encrypted", MessageEventType}
|
||||
EventReaction = Type{"m.reaction", MessageEventType}
|
||||
EventSticker = Type{"m.sticker", MessageEventType}
|
||||
|
||||
InRoomVerificationStart = Type{"m.key.verification.start", MessageEventType}
|
||||
InRoomVerificationReady = Type{"m.key.verification.ready", MessageEventType}
|
||||
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}
|
||||
CallAnswer = Type{"m.call.answer", MessageEventType}
|
||||
CallReject = Type{"m.call.reject", MessageEventType}
|
||||
CallSelectAnswer = Type{"m.call.select_answer", MessageEventType}
|
||||
CallNegotiate = Type{"m.call.negotiate", MessageEventType}
|
||||
CallHangup = Type{"m.call.hangup", MessageEventType}
|
||||
)
|
||||
|
||||
// Ephemeral events
|
||||
var (
|
||||
EphemeralEventReceipt = Type{"m.receipt", EphemeralEventType}
|
||||
EphemeralEventTyping = Type{"m.typing", EphemeralEventType}
|
||||
EphemeralEventPresence = Type{"m.presence", EphemeralEventType}
|
||||
)
|
||||
|
||||
// Account data events
|
||||
var (
|
||||
AccountDataDirectChats = Type{"m.direct", AccountDataEventType}
|
||||
AccountDataPushRules = Type{"m.push_rules", AccountDataEventType}
|
||||
AccountDataRoomTags = Type{"m.tag", AccountDataEventType}
|
||||
AccountDataFullyRead = Type{"m.fully_read", AccountDataEventType}
|
||||
AccountDataIgnoredUserList = Type{"m.ignored_user_list", AccountDataEventType}
|
||||
|
||||
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}
|
||||
)
|
||||
|
||||
// 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}
|
||||
ToDeviceVerificationRequest = Type{"m.key.verification.request", 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}
|
||||
ToDeviceVerificationCancel = Type{"m.key.verification.cancel", ToDeviceEventType}
|
||||
|
||||
ToDeviceOrgMatrixRoomKeyWithheld = Type{"org.matrix.room_key.withheld", ToDeviceEventType}
|
||||
)
|
306
vendor/maunium.net/go/mautrix/event/verification.go
generated
vendored
Normal file
306
vendor/maunium.net/go/mautrix/event/verification.go
generated
vendored
Normal file
@ -0,0 +1,306 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type VerificationMethod string
|
||||
|
||||
const VerificationMethodSAS VerificationMethod = "m.sas.v1"
|
||||
|
||||
// VerificationRequestEventContent represents the content of a m.key.verification.request to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-request
|
||||
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.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vrec *VerificationRequestEventContent) SupportsVerificationMethod(meth VerificationMethod) bool {
|
||||
for _, supportedMeth := range vrec.Methods {
|
||||
if supportedMeth == meth {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type KeyAgreementProtocol string
|
||||
|
||||
const (
|
||||
KeyAgreementCurve25519 KeyAgreementProtocol = "curve25519"
|
||||
KeyAgreementCurve25519HKDFSHA256 KeyAgreementProtocol = "curve25519-hkdf-sha256"
|
||||
)
|
||||
|
||||
type VerificationHashMethod string
|
||||
|
||||
const VerificationHashSHA256 VerificationHashMethod = "sha256"
|
||||
|
||||
type MACMethod string
|
||||
|
||||
const HKDFHMACSHA256 MACMethod = "hkdf-hmac-sha256"
|
||||
|
||||
type SASMethod string
|
||||
|
||||
const (
|
||||
SASDecimal SASMethod = "decimal"
|
||||
SASEmoji SASMethod = "emoji"
|
||||
)
|
||||
|
||||
// VerificationStartEventContent represents the content of a m.key.verification.start to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-start
|
||||
type VerificationStartEventContent struct {
|
||||
// The device ID which is initiating the process.
|
||||
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 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.
|
||||
MessageAuthenticationCodes []MACMethod `json:"message_authentication_codes"`
|
||||
// The SAS methods the sending device (and the sending device's user) understands.
|
||||
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"`
|
||||
}
|
||||
|
||||
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.
|
||||
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://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-accept
|
||||
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://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-key
|
||||
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://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-mac
|
||||
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
|
||||
}
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// VerificationCancelEventContent represents the content of a m.key.verification.cancel to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-cancel
|
||||
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.
|
||||
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"`
|
||||
}
|
||||
|
||||
func (vcec *VerificationCancelEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vcec.RelatesTo == nil {
|
||||
vcec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vcec.RelatesTo
|
||||
}
|
||||
|
||||
func (vcec *VerificationCancelEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vcec.RelatesTo
|
||||
}
|
||||
|
||||
func (vcec *VerificationCancelEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vcec.RelatesTo = rel
|
||||
}
|
116
vendor/maunium.net/go/mautrix/event/voip.go
generated
vendored
Normal file
116
vendor/maunium.net/go/mautrix/event/voip.go
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
// 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 event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type CallHangupReason string
|
||||
|
||||
const (
|
||||
CallHangupICEFailed CallHangupReason = "ice_failed"
|
||||
CallHangupInviteTimeout CallHangupReason = "invite_timeout"
|
||||
CallHangupUserHangup CallHangupReason = "user_hangup"
|
||||
CallHangupUserMediaFailed CallHangupReason = "user_media_failed"
|
||||
CallHangupUnknownError CallHangupReason = "unknown_error"
|
||||
)
|
||||
|
||||
type CallDataType string
|
||||
|
||||
const (
|
||||
CallDataTypeOffer CallDataType = "offer"
|
||||
CallDataTypeAnswer CallDataType = "answer"
|
||||
)
|
||||
|
||||
type CallData struct {
|
||||
SDP string `json:"sdp"`
|
||||
Type CallDataType `json:"type"`
|
||||
}
|
||||
|
||||
type CallCandidate struct {
|
||||
Candidate string `json:"candidate"`
|
||||
SDPMLineIndex int `json:"sdpMLineIndex"`
|
||||
SDPMID string `json:"sdpMid"`
|
||||
}
|
||||
|
||||
type CallVersion string
|
||||
|
||||
func (cv *CallVersion) UnmarshalJSON(raw []byte) error {
|
||||
var numberVersion int
|
||||
err := json.Unmarshal(raw, &numberVersion)
|
||||
if err != nil {
|
||||
var stringVersion string
|
||||
err = json.Unmarshal(raw, &stringVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse CallVersion: %w", err)
|
||||
}
|
||||
*cv = CallVersion(stringVersion)
|
||||
} else {
|
||||
*cv = CallVersion(strconv.Itoa(numberVersion))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cv *CallVersion) MarshalJSON() ([]byte, error) {
|
||||
for _, char := range *cv {
|
||||
if char < '0' || char > '9' {
|
||||
// The version contains weird characters, return as string.
|
||||
return json.Marshal(string(*cv))
|
||||
}
|
||||
}
|
||||
// The version consists of only ASCII digits, return as an integer.
|
||||
return []byte(*cv), nil
|
||||
}
|
||||
|
||||
func (cv *CallVersion) Int() (int, error) {
|
||||
return strconv.Atoi(string(*cv))
|
||||
}
|
||||
|
||||
type BaseCallEventContent struct {
|
||||
CallID string `json:"call_id"`
|
||||
PartyID string `json:"party_id"`
|
||||
Version CallVersion `json:"version"`
|
||||
}
|
||||
|
||||
type CallInviteEventContent struct {
|
||||
BaseCallEventContent
|
||||
Lifetime int `json:"lifetime"`
|
||||
Offer CallData `json:"offer"`
|
||||
}
|
||||
|
||||
type CallCandidatesEventContent struct {
|
||||
BaseCallEventContent
|
||||
Candidates []CallCandidate `json:"candidates"`
|
||||
}
|
||||
|
||||
type CallRejectEventContent struct {
|
||||
BaseCallEventContent
|
||||
}
|
||||
|
||||
type CallAnswerEventContent struct {
|
||||
BaseCallEventContent
|
||||
Answer CallData `json:"answer"`
|
||||
}
|
||||
|
||||
type CallSelectAnswerEventContent struct {
|
||||
BaseCallEventContent
|
||||
SelectedPartyID string `json:"selected_party_id"`
|
||||
}
|
||||
|
||||
type CallNegotiateEventContent struct {
|
||||
BaseCallEventContent
|
||||
Lifetime int `json:"lifetime"`
|
||||
Description CallData `json:"description"`
|
||||
}
|
||||
|
||||
type CallHangupEventContent struct {
|
||||
BaseCallEventContent
|
||||
Reason CallHangupReason `json:"reason"`
|
||||
}
|
93
vendor/maunium.net/go/mautrix/filter.go
generated
vendored
Normal file
93
vendor/maunium.net/go/mautrix/filter.go
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2017 Jan Christian Grünhage
|
||||
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type EventFormat string
|
||||
|
||||
const (
|
||||
EventFormatClient EventFormat = "client"
|
||||
EventFormatFederation EventFormat = "federation"
|
||||
)
|
||||
|
||||
//Filter is used by clients to specify how the server should filter responses to e.g. sync requests
|
||||
//Specified by: https://matrix.org/docs/spec/client_server/r0.6.0.html#filtering
|
||||
type Filter struct {
|
||||
AccountData FilterPart `json:"account_data,omitempty"`
|
||||
EventFields []string `json:"event_fields,omitempty"`
|
||||
EventFormat EventFormat `json:"event_format,omitempty"`
|
||||
Presence FilterPart `json:"presence,omitempty"`
|
||||
Room RoomFilter `json:"room,omitempty"`
|
||||
}
|
||||
|
||||
// RoomFilter is used to define filtering rules for room events
|
||||
type RoomFilter struct {
|
||||
AccountData FilterPart `json:"account_data,omitempty"`
|
||||
Ephemeral FilterPart `json:"ephemeral,omitempty"`
|
||||
IncludeLeave bool `json:"include_leave,omitempty"`
|
||||
NotRooms []id.RoomID `json:"not_rooms,omitempty"`
|
||||
Rooms []id.RoomID `json:"rooms,omitempty"`
|
||||
State FilterPart `json:"state,omitempty"`
|
||||
Timeline FilterPart `json:"timeline,omitempty"`
|
||||
}
|
||||
|
||||
// FilterPart is used to define filtering rules for specific categories of events
|
||||
type FilterPart struct {
|
||||
NotRooms []id.RoomID `json:"not_rooms,omitempty"`
|
||||
Rooms []id.RoomID `json:"rooms,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
NotSenders []id.UserID `json:"not_senders,omitempty"`
|
||||
NotTypes []event.Type `json:"not_types,omitempty"`
|
||||
Senders []id.UserID `json:"senders,omitempty"`
|
||||
Types []event.Type `json:"types,omitempty"`
|
||||
ContainsURL *bool `json:"contains_url,omitempty"`
|
||||
|
||||
LazyLoadMembers bool `json:"lazy_load_members,omitempty"`
|
||||
IncludeRedundantMembers bool `json:"include_redundant_members,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks if the filter contains valid property values
|
||||
func (filter *Filter) Validate() error {
|
||||
if filter.EventFormat != EventFormatClient && filter.EventFormat != EventFormatFederation {
|
||||
return errors.New("Bad event_format value. Must be one of [\"client\", \"federation\"]")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultFilter returns the default filter used by the Matrix server if no filter is provided in the request
|
||||
func DefaultFilter() Filter {
|
||||
return Filter{
|
||||
AccountData: DefaultFilterPart(),
|
||||
EventFields: nil,
|
||||
EventFormat: "client",
|
||||
Presence: DefaultFilterPart(),
|
||||
Room: RoomFilter{
|
||||
AccountData: DefaultFilterPart(),
|
||||
Ephemeral: DefaultFilterPart(),
|
||||
IncludeLeave: false,
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
State: DefaultFilterPart(),
|
||||
Timeline: DefaultFilterPart(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultFilterPart returns the default filter part used by the Matrix server if no filter is provided in the request
|
||||
func DefaultFilterPart() FilterPart {
|
||||
return FilterPart{
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
Limit: 20,
|
||||
NotSenders: nil,
|
||||
NotTypes: nil,
|
||||
Senders: nil,
|
||||
Types: nil,
|
||||
}
|
||||
}
|
133
vendor/maunium.net/go/mautrix/id/contenturi.go
generated
vendored
Normal file
133
vendor/maunium.net/go/mautrix/id/contenturi.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
// 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"
|
||||
"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://matrix.org/docs/spec/client_server/r0.6.0#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.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) {
|
||||
if uri.IsEmpty() {
|
||||
return []byte(""), nil
|
||||
}
|
||||
return []byte(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
|
||||
}
|
114
vendor/maunium.net/go/mautrix/id/crypto.go
generated
vendored
Normal file
114
vendor/maunium.net/go/mautrix/id/crypto.go
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
// 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://matrix.org/docs/spec/client_server/r0.6.0#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)
|
||||
}
|
||||
|
||||
// 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:])
|
||||
}
|
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)
|
||||
}
|
211
vendor/maunium.net/go/mautrix/id/userid.go
generated
vendored
Normal file
211
vendor/maunium.net/go/mautrix/id/userid.go
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 http://matrix.org/docs/spec/intro.html#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 http://matrix.org/docs/spec/intro.html#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
|
||||
}
|
124
vendor/maunium.net/go/mautrix/pushrules/action.go
generated
vendored
Normal file
124
vendor/maunium.net/go/mautrix/pushrules/action.go
generated
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
// 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 pushrules
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// PushActionType is the type of a PushAction
|
||||
type PushActionType string
|
||||
|
||||
// The allowed push action types as specified in spec section 11.12.1.4.1.
|
||||
const (
|
||||
ActionNotify PushActionType = "notify"
|
||||
ActionDontNotify PushActionType = "dont_notify"
|
||||
ActionCoalesce PushActionType = "coalesce"
|
||||
ActionSetTweak PushActionType = "set_tweak"
|
||||
)
|
||||
|
||||
// PushActionTweak is the type of the tweak in SetTweak push actions.
|
||||
type PushActionTweak string
|
||||
|
||||
// The allowed tweak types as specified in spec section 11.12.1.4.1.1.
|
||||
const (
|
||||
TweakSound PushActionTweak = "sound"
|
||||
TweakHighlight PushActionTweak = "highlight"
|
||||
)
|
||||
|
||||
// PushActionArray is an array of PushActions.
|
||||
type PushActionArray []*PushAction
|
||||
|
||||
// PushActionArrayShould contains the important information parsed from a PushActionArray.
|
||||
type PushActionArrayShould struct {
|
||||
// Whether or not the array contained a Notify, DontNotify or Coalesce action type.
|
||||
NotifySpecified bool
|
||||
// Whether or not the event in question should trigger a notification.
|
||||
Notify bool
|
||||
// Whether or not the event in question should be highlighted.
|
||||
Highlight bool
|
||||
|
||||
// Whether or not the event in question should trigger a sound alert.
|
||||
PlaySound bool
|
||||
// The name of the sound to play if PlaySound is true.
|
||||
SoundName string
|
||||
}
|
||||
|
||||
// Should parses this push action array and returns the relevant details wrapped in a PushActionArrayShould struct.
|
||||
func (actions PushActionArray) Should() (should PushActionArrayShould) {
|
||||
for _, action := range actions {
|
||||
switch action.Action {
|
||||
case ActionNotify, ActionCoalesce:
|
||||
should.Notify = true
|
||||
should.NotifySpecified = true
|
||||
case ActionDontNotify:
|
||||
should.Notify = false
|
||||
should.NotifySpecified = true
|
||||
case ActionSetTweak:
|
||||
switch action.Tweak {
|
||||
case TweakHighlight:
|
||||
var ok bool
|
||||
should.Highlight, ok = action.Value.(bool)
|
||||
if !ok {
|
||||
// Highlight value not specified, so assume true since the tweak is set.
|
||||
should.Highlight = true
|
||||
}
|
||||
case TweakSound:
|
||||
should.SoundName = action.Value.(string)
|
||||
should.PlaySound = len(should.SoundName) > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PushAction is a single action that should be triggered when receiving a message.
|
||||
type PushAction struct {
|
||||
Action PushActionType
|
||||
Tweak PushActionTweak
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses JSON into this PushAction.
|
||||
//
|
||||
// * If the JSON is a single string, the value is stored in the Action field.
|
||||
// * If the JSON is an object with the set_tweak field, Action will be set to
|
||||
// "set_tweak", Tweak will be set to the value of the set_tweak field and
|
||||
// and Value will be set to the value of the value field.
|
||||
// * In any other case, the function does nothing.
|
||||
func (action *PushAction) UnmarshalJSON(raw []byte) error {
|
||||
var data interface{}
|
||||
|
||||
err := json.Unmarshal(raw, &data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch val := data.(type) {
|
||||
case string:
|
||||
action.Action = PushActionType(val)
|
||||
case map[string]interface{}:
|
||||
tweak, ok := val["set_tweak"].(string)
|
||||
if ok {
|
||||
action.Action = ActionSetTweak
|
||||
action.Tweak = PushActionTweak(tweak)
|
||||
action.Value, _ = val["value"]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON is the reverse of UnmarshalJSON()
|
||||
func (action *PushAction) MarshalJSON() (raw []byte, err error) {
|
||||
if action.Action == ActionSetTweak {
|
||||
data := map[string]interface{}{
|
||||
"set_tweak": action.Tweak,
|
||||
"value": action.Value,
|
||||
}
|
||||
return json.Marshal(&data)
|
||||
}
|
||||
data := string(action.Action)
|
||||
return json.Marshal(&data)
|
||||
}
|
149
vendor/maunium.net/go/mautrix/pushrules/condition.go
generated
vendored
Normal file
149
vendor/maunium.net/go/mautrix/pushrules/condition.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 pushrules
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/pushrules/glob"
|
||||
)
|
||||
|
||||
// Room is an interface with the functions that are needed for processing room-specific push conditions
|
||||
type Room interface {
|
||||
GetOwnDisplayname() string
|
||||
GetMemberCount() int
|
||||
}
|
||||
|
||||
// PushCondKind is the type of a push condition.
|
||||
type PushCondKind string
|
||||
|
||||
// The allowed push condition kinds as specified in section 11.12.1.4.3 of r0.3.0 of the Client-Server API.
|
||||
const (
|
||||
KindEventMatch PushCondKind = "event_match"
|
||||
KindContainsDisplayName PushCondKind = "contains_display_name"
|
||||
KindRoomMemberCount PushCondKind = "room_member_count"
|
||||
)
|
||||
|
||||
// PushCondition wraps a condition that is required for a specific PushRule to be used.
|
||||
type PushCondition struct {
|
||||
// The type of the condition.
|
||||
Kind PushCondKind `json:"kind"`
|
||||
// The dot-separated field of the event to match. Only applicable if kind is EventMatch.
|
||||
Key string `json:"key,omitempty"`
|
||||
// The glob-style pattern to match the field against. Only applicable if kind is EventMatch.
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
// The condition that needs to be fulfilled for RoomMemberCount-type conditions.
|
||||
// A decimal integer optionally prefixed by ==, <, >, >= or <=. Prefix "==" is assumed if no prefix found.
|
||||
MemberCountCondition string `json:"is,omitempty"`
|
||||
}
|
||||
|
||||
// MemberCountFilterRegex is the regular expression to parse the MemberCountCondition of PushConditions.
|
||||
var MemberCountFilterRegex = regexp.MustCompile("^(==|[<>]=?)?([0-9]+)$")
|
||||
|
||||
// Match checks if this condition is fulfilled for the given event in the given room.
|
||||
func (cond *PushCondition) Match(room Room, evt *event.Event) bool {
|
||||
switch cond.Kind {
|
||||
case KindEventMatch:
|
||||
return cond.matchValue(room, evt)
|
||||
case KindContainsDisplayName:
|
||||
return cond.matchDisplayName(room, evt)
|
||||
case KindRoomMemberCount:
|
||||
return cond.matchMemberCount(room)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchValue(room Room, evt *event.Event) bool {
|
||||
index := strings.IndexRune(cond.Key, '.')
|
||||
key := cond.Key
|
||||
subkey := ""
|
||||
if index > 0 {
|
||||
subkey = key[index+1:]
|
||||
key = key[0:index]
|
||||
}
|
||||
|
||||
pattern, err := glob.Compile(cond.Pattern)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch key {
|
||||
case "type":
|
||||
return pattern.MatchString(evt.Type.String())
|
||||
case "sender":
|
||||
return pattern.MatchString(string(evt.Sender))
|
||||
case "room_id":
|
||||
return pattern.MatchString(string(evt.RoomID))
|
||||
case "state_key":
|
||||
if evt.StateKey == nil {
|
||||
return cond.Pattern == ""
|
||||
}
|
||||
return pattern.MatchString(*evt.StateKey)
|
||||
case "content":
|
||||
val, _ := evt.Content.Raw[subkey].(string)
|
||||
return pattern.MatchString(val)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchDisplayName(room Room, evt *event.Event) bool {
|
||||
displayname := room.GetOwnDisplayname()
|
||||
if len(displayname) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
msg, ok := evt.Content.Raw["body"].(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
isAcceptable := func(r uint8) bool {
|
||||
return unicode.IsSpace(rune(r)) || unicode.IsPunct(rune(r))
|
||||
}
|
||||
length := len(displayname)
|
||||
for index := strings.Index(msg, displayname); index != -1; index = strings.Index(msg, displayname) {
|
||||
if (index <= 0 || isAcceptable(msg[index-1])) && (index+length >= len(msg) || isAcceptable(msg[index+length])) {
|
||||
return true
|
||||
}
|
||||
msg = msg[index+len(displayname):]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchMemberCount(room Room) bool {
|
||||
group := MemberCountFilterRegex.FindStringSubmatch(cond.MemberCountCondition)
|
||||
if len(group) != 3 {
|
||||
return false
|
||||
}
|
||||
|
||||
operator := group[1]
|
||||
wantedMemberCount, _ := strconv.Atoi(group[2])
|
||||
|
||||
memberCount := room.GetMemberCount()
|
||||
|
||||
switch operator {
|
||||
case "==", "":
|
||||
return memberCount == wantedMemberCount
|
||||
case ">":
|
||||
return memberCount > wantedMemberCount
|
||||
case ">=":
|
||||
return memberCount >= wantedMemberCount
|
||||
case "<":
|
||||
return memberCount < wantedMemberCount
|
||||
case "<=":
|
||||
return memberCount <= wantedMemberCount
|
||||
default:
|
||||
// Should be impossible due to regex.
|
||||
return false
|
||||
}
|
||||
}
|
2
vendor/maunium.net/go/mautrix/pushrules/doc.go
generated
vendored
Normal file
2
vendor/maunium.net/go/mautrix/pushrules/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package pushrules contains utilities to parse push notification rules.
|
||||
package pushrules
|
22
vendor/maunium.net/go/mautrix/pushrules/glob/LICENSE
generated
vendored
Normal file
22
vendor/maunium.net/go/mautrix/pushrules/glob/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
Glob is licensed under the MIT "Expat" License:
|
||||
|
||||
Copyright (c) 2016: Zachary Yedidia.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
28
vendor/maunium.net/go/mautrix/pushrules/glob/README.md
generated
vendored
Normal file
28
vendor/maunium.net/go/mautrix/pushrules/glob/README.md
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
# String globbing in Go
|
||||
|
||||
[![GoDoc](https://godoc.org/github.com/zyedidia/glob?status.svg)](http://godoc.org/github.com/zyedidia/glob)
|
||||
|
||||
This package adds support for globs in Go.
|
||||
|
||||
It simply converts glob expressions to regexps. I try to follow the standard defined [here](http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13).
|
||||
|
||||
# Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/zyedidia/glob"
|
||||
|
||||
func main() {
|
||||
glob, err := glob.Compile("{*.go,*.c}")
|
||||
if err != nil {
|
||||
// Error
|
||||
}
|
||||
|
||||
glob.Match([]byte("test.c")) // true
|
||||
glob.Match([]byte("hello.go")) // true
|
||||
glob.Match([]byte("test.d")) // false
|
||||
}
|
||||
```
|
||||
|
||||
You can call all the same functions on a glob that you can call on a regexp.
|
108
vendor/maunium.net/go/mautrix/pushrules/glob/glob.go
generated
vendored
Normal file
108
vendor/maunium.net/go/mautrix/pushrules/glob/glob.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
// Package glob provides objects for matching strings with globs
|
||||
package glob
|
||||
|
||||
import "regexp"
|
||||
|
||||
// Glob is a wrapper of *regexp.Regexp.
|
||||
// It should contain a glob expression compiled into a regular expression.
|
||||
type Glob struct {
|
||||
*regexp.Regexp
|
||||
}
|
||||
|
||||
// Compile a takes a glob expression as a string and transforms it
|
||||
// into a *Glob object (which is really just a regular expression)
|
||||
// Compile also returns a possible error.
|
||||
func Compile(pattern string) (*Glob, error) {
|
||||
r, err := globToRegex(pattern)
|
||||
return &Glob{r}, err
|
||||
}
|
||||
|
||||
func globToRegex(glob string) (*regexp.Regexp, error) {
|
||||
regex := ""
|
||||
inGroup := 0
|
||||
inClass := 0
|
||||
firstIndexInClass := -1
|
||||
arr := []byte(glob)
|
||||
|
||||
hasGlobCharacters := false
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
ch := arr[i]
|
||||
|
||||
switch ch {
|
||||
case '\\':
|
||||
i++
|
||||
if i >= len(arr) {
|
||||
regex += "\\"
|
||||
} else {
|
||||
next := arr[i]
|
||||
switch next {
|
||||
case ',':
|
||||
// Nothing
|
||||
case 'Q', 'E':
|
||||
regex += "\\\\"
|
||||
default:
|
||||
regex += "\\"
|
||||
}
|
||||
regex += string(next)
|
||||
}
|
||||
case '*':
|
||||
if inClass == 0 {
|
||||
regex += ".*"
|
||||
} else {
|
||||
regex += "*"
|
||||
}
|
||||
hasGlobCharacters = true
|
||||
case '?':
|
||||
if inClass == 0 {
|
||||
regex += "."
|
||||
} else {
|
||||
regex += "?"
|
||||
}
|
||||
hasGlobCharacters = true
|
||||
case '[':
|
||||
inClass++
|
||||
firstIndexInClass = i + 1
|
||||
regex += "["
|
||||
hasGlobCharacters = true
|
||||
case ']':
|
||||
inClass--
|
||||
regex += "]"
|
||||
case '.', '(', ')', '+', '|', '^', '$', '@', '%':
|
||||
if inClass == 0 || (firstIndexInClass == i && ch == '^') {
|
||||
regex += "\\"
|
||||
}
|
||||
regex += string(ch)
|
||||
hasGlobCharacters = true
|
||||
case '!':
|
||||
if firstIndexInClass == i {
|
||||
regex += "^"
|
||||
} else {
|
||||
regex += "!"
|
||||
}
|
||||
hasGlobCharacters = true
|
||||
case '{':
|
||||
inGroup++
|
||||
regex += "("
|
||||
hasGlobCharacters = true
|
||||
case '}':
|
||||
inGroup--
|
||||
regex += ")"
|
||||
case ',':
|
||||
if inGroup > 0 {
|
||||
regex += "|"
|
||||
hasGlobCharacters = true
|
||||
} else {
|
||||
regex += ","
|
||||
}
|
||||
default:
|
||||
regex += string(ch)
|
||||
}
|
||||
}
|
||||
|
||||
if hasGlobCharacters {
|
||||
return regexp.Compile("^" + regex + "$")
|
||||
} else {
|
||||
return regexp.Compile(regex)
|
||||
}
|
||||
}
|
37
vendor/maunium.net/go/mautrix/pushrules/pushrules.go
generated
vendored
Normal file
37
vendor/maunium.net/go/mautrix/pushrules/pushrules.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// 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 pushrules
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
)
|
||||
|
||||
// EventContent represents the content of a m.push_rules account data event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-push-rules
|
||||
type EventContent struct {
|
||||
Ruleset *PushRuleset `json:"global"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
event.TypeMap[event.AccountDataPushRules] = reflect.TypeOf(EventContent{})
|
||||
gob.Register(&EventContent{})
|
||||
}
|
||||
|
||||
// EventToPushRules converts a m.push_rules event to a PushRuleset by passing the data through JSON.
|
||||
func EventToPushRules(evt *event.Event) (*PushRuleset, error) {
|
||||
content := &EventContent{}
|
||||
err := json.Unmarshal(evt.Content.VeryRaw, content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return content.Ruleset, nil
|
||||
}
|
154
vendor/maunium.net/go/mautrix/pushrules/rule.go
generated
vendored
Normal file
154
vendor/maunium.net/go/mautrix/pushrules/rule.go
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
// 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 pushrules
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
"maunium.net/go/mautrix/pushrules/glob"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(PushRuleArray{})
|
||||
gob.Register(PushRuleMap{})
|
||||
}
|
||||
|
||||
type PushRuleCollection interface {
|
||||
GetActions(room Room, evt *event.Event) PushActionArray
|
||||
}
|
||||
|
||||
type PushRuleArray []*PushRule
|
||||
|
||||
func (rules PushRuleArray) SetType(typ PushRuleType) PushRuleArray {
|
||||
for _, rule := range rules {
|
||||
rule.Type = typ
|
||||
}
|
||||
return rules
|
||||
}
|
||||
|
||||
func (rules PushRuleArray) GetActions(room Room, evt *event.Event) PushActionArray {
|
||||
for _, rule := range rules {
|
||||
if !rule.Match(room, evt) {
|
||||
continue
|
||||
}
|
||||
return rule.Actions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PushRuleMap struct {
|
||||
Map map[string]*PushRule
|
||||
Type PushRuleType
|
||||
}
|
||||
|
||||
func (rules PushRuleArray) SetTypeAndMap(typ PushRuleType) PushRuleMap {
|
||||
data := PushRuleMap{
|
||||
Map: make(map[string]*PushRule),
|
||||
Type: typ,
|
||||
}
|
||||
for _, rule := range rules {
|
||||
rule.Type = typ
|
||||
data.Map[rule.RuleID] = rule
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (ruleMap PushRuleMap) GetActions(room Room, evt *event.Event) PushActionArray {
|
||||
var rule *PushRule
|
||||
var found bool
|
||||
switch ruleMap.Type {
|
||||
case RoomRule:
|
||||
rule, found = ruleMap.Map[string(evt.RoomID)]
|
||||
case SenderRule:
|
||||
rule, found = ruleMap.Map[string(evt.Sender)]
|
||||
}
|
||||
if found && rule.Match(room, evt) {
|
||||
return rule.Actions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ruleMap PushRuleMap) Unmap() PushRuleArray {
|
||||
array := make(PushRuleArray, len(ruleMap.Map))
|
||||
index := 0
|
||||
for _, rule := range ruleMap.Map {
|
||||
array[index] = rule
|
||||
index++
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
type PushRuleType string
|
||||
|
||||
const (
|
||||
OverrideRule PushRuleType = "override"
|
||||
ContentRule PushRuleType = "content"
|
||||
RoomRule PushRuleType = "room"
|
||||
SenderRule PushRuleType = "sender"
|
||||
UnderrideRule PushRuleType = "underride"
|
||||
)
|
||||
|
||||
type PushRule struct {
|
||||
// The type of this rule.
|
||||
Type PushRuleType `json:"-"`
|
||||
// The ID of this rule.
|
||||
// For room-specific rules and user-specific rules, this is the room or user ID (respectively)
|
||||
// For other types of rules, this doesn't affect anything.
|
||||
RuleID string `json:"rule_id"`
|
||||
// The actions this rule should trigger when matched.
|
||||
Actions PushActionArray `json:"actions"`
|
||||
// Whether this is a default rule, or has been set explicitly.
|
||||
Default bool `json:"default"`
|
||||
// Whether or not this push rule is enabled.
|
||||
Enabled bool `json:"enabled"`
|
||||
// The conditions to match in order to trigger this rule.
|
||||
// Only applicable to generic underride/override rules.
|
||||
Conditions []*PushCondition `json:"conditions,omitempty"`
|
||||
// Pattern for content-specific push rules
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
}
|
||||
|
||||
func (rule *PushRule) Match(room Room, evt *event.Event) bool {
|
||||
if !rule.Enabled {
|
||||
return false
|
||||
}
|
||||
switch rule.Type {
|
||||
case OverrideRule, UnderrideRule:
|
||||
return rule.matchConditions(room, evt)
|
||||
case ContentRule:
|
||||
return rule.matchPattern(room, evt)
|
||||
case RoomRule:
|
||||
return id.RoomID(rule.RuleID) == evt.RoomID
|
||||
case SenderRule:
|
||||
return id.UserID(rule.RuleID) == evt.Sender
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (rule *PushRule) matchConditions(room Room, evt *event.Event) bool {
|
||||
for _, cond := range rule.Conditions {
|
||||
if !cond.Match(room, evt) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (rule *PushRule) matchPattern(room Room, evt *event.Event) bool {
|
||||
pattern, err := glob.Compile(rule.Pattern)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
msg, ok := evt.Content.Raw["body"].(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return pattern.MatchString(msg)
|
||||
}
|
88
vendor/maunium.net/go/mautrix/pushrules/ruleset.go
generated
vendored
Normal file
88
vendor/maunium.net/go/mautrix/pushrules/ruleset.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
// 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 pushrules
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
)
|
||||
|
||||
type PushRuleset struct {
|
||||
Override PushRuleArray
|
||||
Content PushRuleArray
|
||||
Room PushRuleMap
|
||||
Sender PushRuleMap
|
||||
Underride PushRuleArray
|
||||
}
|
||||
|
||||
type rawPushRuleset struct {
|
||||
Override PushRuleArray `json:"override"`
|
||||
Content PushRuleArray `json:"content"`
|
||||
Room PushRuleArray `json:"room"`
|
||||
Sender PushRuleArray `json:"sender"`
|
||||
Underride PushRuleArray `json:"underride"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses JSON into this PushRuleset.
|
||||
//
|
||||
// For override, sender and underride push rule arrays, the type is added
|
||||
// to each PushRule and the array is used as-is.
|
||||
//
|
||||
// For room and sender push rule arrays, the type is added to each PushRule
|
||||
// and the array is converted to a map with the rule ID as the key and the
|
||||
// PushRule as the value.
|
||||
func (rs *PushRuleset) UnmarshalJSON(raw []byte) (err error) {
|
||||
data := rawPushRuleset{}
|
||||
err = json.Unmarshal(raw, &data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
rs.Override = data.Override.SetType(OverrideRule)
|
||||
rs.Content = data.Content.SetType(ContentRule)
|
||||
rs.Room = data.Room.SetTypeAndMap(RoomRule)
|
||||
rs.Sender = data.Sender.SetTypeAndMap(SenderRule)
|
||||
rs.Underride = data.Underride.SetType(UnderrideRule)
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalJSON is the reverse of UnmarshalJSON()
|
||||
func (rs *PushRuleset) MarshalJSON() ([]byte, error) {
|
||||
data := rawPushRuleset{
|
||||
Override: rs.Override,
|
||||
Content: rs.Content,
|
||||
Room: rs.Room.Unmap(),
|
||||
Sender: rs.Sender.Unmap(),
|
||||
Underride: rs.Underride,
|
||||
}
|
||||
return json.Marshal(&data)
|
||||
}
|
||||
|
||||
// DefaultPushActions is the value returned if none of the rule
|
||||
// collections in a Ruleset match the event given to GetActions()
|
||||
var DefaultPushActions = PushActionArray{&PushAction{Action: ActionDontNotify}}
|
||||
|
||||
// GetActions matches the given event against all of the push rule
|
||||
// collections in this push ruleset in the order of priority as
|
||||
// specified in spec section 11.12.1.4.
|
||||
func (rs *PushRuleset) GetActions(room Room, evt *event.Event) (match PushActionArray) {
|
||||
// Add push rule collections to array in priority order
|
||||
arrays := []PushRuleCollection{rs.Override, rs.Content, rs.Room, rs.Sender, rs.Underride}
|
||||
// Loop until one of the push rule collections matches the room/event combo.
|
||||
for _, pra := range arrays {
|
||||
if pra == nil {
|
||||
continue
|
||||
}
|
||||
if match = pra.GetActions(room, evt); match != nil {
|
||||
// Match found, return it.
|
||||
return
|
||||
}
|
||||
}
|
||||
// No match found, return default actions.
|
||||
return DefaultPushActions
|
||||
}
|
317
vendor/maunium.net/go/mautrix/requests.go
generated
vendored
Normal file
317
vendor/maunium.net/go/mautrix/requests.go
generated
vendored
Normal file
@ -0,0 +1,317 @@
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
"maunium.net/go/mautrix/pushrules"
|
||||
)
|
||||
|
||||
type AuthType string
|
||||
|
||||
const (
|
||||
AuthTypePassword AuthType = "m.login.password"
|
||||
AuthTypeReCAPTCHA AuthType = "m.login.recaptcha"
|
||||
AuthTypeOAuth2 AuthType = "m.login.oauth2"
|
||||
AuthTypeSSO AuthType = "m.login.sso"
|
||||
AuthTypeEmail AuthType = "m.login.email.identity"
|
||||
AuthTypeMSISDN AuthType = "m.login.msisdn"
|
||||
AuthTypeToken AuthType = "m.login.token"
|
||||
AuthTypeDummy AuthType = "m.login.dummy"
|
||||
|
||||
AuthTypeAppservice AuthType = "m.login.application_service"
|
||||
AuthTypeHalfyAppservice AuthType = "uk.half-shot.msc2778.login.application_service"
|
||||
)
|
||||
|
||||
type IdentifierType string
|
||||
|
||||
const (
|
||||
IdentifierTypeUser = "m.id.user"
|
||||
IdentifierTypeThirdParty = "m.id.thirdparty"
|
||||
IdentifierTypePhone = "m.id.phone"
|
||||
)
|
||||
|
||||
// ReqRegister is the JSON request for https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-register
|
||||
type ReqRegister struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
DeviceID id.DeviceID `json:"device_id,omitempty"`
|
||||
InitialDeviceDisplayName string `json:"initial_device_display_name,omitempty"`
|
||||
InhibitLogin bool `json:"inhibit_login,omitempty"`
|
||||
Auth interface{} `json:"auth,omitempty"`
|
||||
|
||||
// Type for registration, only used for appservice user registrations
|
||||
// https://matrix.org/docs/spec/application_service/r0.1.2#server-admin-style-permissions
|
||||
Type AuthType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type BaseAuthData struct {
|
||||
Type AuthType `json:"type"`
|
||||
Session string `json:"session,omitempty"`
|
||||
}
|
||||
|
||||
type UserIdentifier struct {
|
||||
Type IdentifierType `json:"type"`
|
||||
|
||||
User string `json:"user,omitempty"`
|
||||
|
||||
Medium string `json:"medium,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
|
||||
Country string `json:"country,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
}
|
||||
|
||||
// ReqLogin is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-login
|
||||
type ReqLogin struct {
|
||||
Type AuthType `json:"type"`
|
||||
Identifier UserIdentifier `json:"identifier"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
DeviceID id.DeviceID `json:"device_id,omitempty"`
|
||||
InitialDeviceDisplayName string `json:"initial_device_display_name,omitempty"`
|
||||
|
||||
// Whether or not the returned credentials should be stored in the Client
|
||||
StoreCredentials bool `json:"-"`
|
||||
// Whether or not the returned .well-known data should update the homeserver URL in the Client
|
||||
StoreHomeserverURL bool `json:"-"`
|
||||
}
|
||||
|
||||
type ReqUIAuthFallback struct {
|
||||
Session string `json:"session"`
|
||||
User string `json:"user"`
|
||||
}
|
||||
|
||||
type ReqUIAuthLogin struct {
|
||||
BaseAuthData
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// ReqCreateRoom is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
||||
type ReqCreateRoom struct {
|
||||
Visibility string `json:"visibility,omitempty"`
|
||||
RoomAliasName string `json:"room_alias_name,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Topic string `json:"topic,omitempty"`
|
||||
Invite []id.UserID `json:"invite,omitempty"`
|
||||
Invite3PID []ReqInvite3PID `json:"invite_3pid,omitempty"`
|
||||
CreationContent map[string]interface{} `json:"creation_content,omitempty"`
|
||||
InitialState []*event.Event `json:"initial_state,omitempty"`
|
||||
Preset string `json:"preset,omitempty"`
|
||||
IsDirect bool `json:"is_direct,omitempty"`
|
||||
|
||||
PowerLevelOverride *event.PowerLevelsEventContent `json:"power_level_content_override,omitempty"`
|
||||
}
|
||||
|
||||
// ReqRedact is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
|
||||
type ReqRedact struct {
|
||||
Reason string
|
||||
TxnID string
|
||||
Extra map[string]interface{}
|
||||
}
|
||||
|
||||
type ReqMembers struct {
|
||||
At string `json:"at"`
|
||||
Membership event.Membership `json:"membership,omitempty"`
|
||||
NotMembership event.Membership `json:"not_membership,omitempty"`
|
||||
}
|
||||
|
||||
// ReqInvite3PID is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#id57
|
||||
// It is also a JSON object used in https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
||||
type ReqInvite3PID struct {
|
||||
IDServer string `json:"id_server"`
|
||||
Medium string `json:"medium"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
// ReqInviteUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
|
||||
type ReqInviteUser struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqKickUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
|
||||
type ReqKickUser struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqBanUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
|
||||
type ReqBanUser struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqUnbanUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
|
||||
type ReqUnbanUser struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqTyping is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
|
||||
type ReqTyping struct {
|
||||
Typing bool `json:"typing"`
|
||||
Timeout int64 `json:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
type ReqPresence struct {
|
||||
Presence event.Presence `json:"presence"`
|
||||
}
|
||||
|
||||
type ReqAliasCreate struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
}
|
||||
|
||||
type OneTimeKey struct {
|
||||
Key id.Curve25519 `json:"key"`
|
||||
IsSigned bool `json:"-"`
|
||||
Signatures Signatures `json:"signatures,omitempty"`
|
||||
Unsigned map[string]interface{} `json:"unsigned,omitempty"`
|
||||
}
|
||||
|
||||
type serializableOTK OneTimeKey
|
||||
|
||||
func (otk *OneTimeKey) UnmarshalJSON(data []byte) (err error) {
|
||||
if len(data) > 0 && data[0] == '"' && data[len(data)-1] == '"' {
|
||||
err = json.Unmarshal(data, &otk.Key)
|
||||
otk.Signatures = nil
|
||||
otk.Unsigned = nil
|
||||
otk.IsSigned = false
|
||||
} else {
|
||||
err = json.Unmarshal(data, (*serializableOTK)(otk))
|
||||
otk.IsSigned = true
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (otk *OneTimeKey) MarshalJSON() ([]byte, error) {
|
||||
if !otk.IsSigned {
|
||||
return json.Marshal(otk.Key)
|
||||
} else {
|
||||
return json.Marshal((*serializableOTK)(otk))
|
||||
}
|
||||
}
|
||||
|
||||
type ReqUploadKeys struct {
|
||||
DeviceKeys *DeviceKeys `json:"device_keys,omitempty"`
|
||||
OneTimeKeys map[id.KeyID]OneTimeKey `json:"one_time_keys"`
|
||||
}
|
||||
|
||||
type ReqKeysSignatures struct {
|
||||
UserID id.UserID `json:"user_id"`
|
||||
DeviceID id.DeviceID `json:"device_id,omitempty"`
|
||||
Algorithms []id.Algorithm `json:"algorithms,omitempty"`
|
||||
Usage []id.CrossSigningUsage `json:"usage,omitempty"`
|
||||
Keys map[id.KeyID]string `json:"keys"`
|
||||
Signatures Signatures `json:"signatures"`
|
||||
}
|
||||
|
||||
type ReqUploadSignatures map[id.UserID]map[string]ReqKeysSignatures
|
||||
|
||||
type DeviceKeys struct {
|
||||
UserID id.UserID `json:"user_id"`
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
Algorithms []id.Algorithm `json:"algorithms"`
|
||||
Keys KeyMap `json:"keys"`
|
||||
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"`
|
||||
}
|
||||
|
||||
func (csk *CrossSigningKeys) FirstKey() id.Ed25519 {
|
||||
for _, key := range csk.Keys {
|
||||
return key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type UploadCrossSigningKeysReq struct {
|
||||
Master CrossSigningKeys `json:"master_key"`
|
||||
SelfSigning CrossSigningKeys `json:"self_signing_key"`
|
||||
UserSigning CrossSigningKeys `json:"user_signing_key"`
|
||||
Auth interface{} `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
type KeyMap map[id.DeviceKeyID]string
|
||||
|
||||
func (km KeyMap) GetEd25519(deviceID id.DeviceID) id.Ed25519 {
|
||||
val, ok := km[id.NewDeviceKeyID(id.KeyAlgorithmEd25519, deviceID)]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return id.Ed25519(val)
|
||||
}
|
||||
|
||||
func (km KeyMap) GetCurve25519(deviceID id.DeviceID) id.Curve25519 {
|
||||
val, ok := km[id.NewDeviceKeyID(id.KeyAlgorithmCurve25519, deviceID)]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
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"`
|
||||
Token string `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
type DeviceKeysRequest map[id.UserID]DeviceIDList
|
||||
|
||||
type DeviceIDList []id.DeviceID
|
||||
|
||||
type ReqClaimKeys struct {
|
||||
OneTimeKeys OneTimeKeysRequest `json:"one_time_keys"`
|
||||
|
||||
Timeout int64 `json:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
type OneTimeKeysRequest map[id.UserID]map[id.DeviceID]id.KeyAlgorithm
|
||||
|
||||
type ReqSendToDevice struct {
|
||||
Messages map[id.UserID]map[id.DeviceID]*event.Content `json:"messages"`
|
||||
}
|
||||
|
||||
// ReqDeviceInfo is the JSON request for https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-devices-deviceid
|
||||
type ReqDeviceInfo struct {
|
||||
DisplayName string `json:"display_name,omitempty"`
|
||||
}
|
||||
|
||||
// ReqDeleteDevice is the JSON request for https://matrix.org/docs/spec/client_server/r0.6.1#delete-matrix-client-r0-devices-deviceid
|
||||
type ReqDeleteDevice struct {
|
||||
Auth interface{} `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
// ReqDeleteDevices is the JSON request for https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-delete-devices
|
||||
type ReqDeleteDevices struct {
|
||||
Devices []id.DeviceID `json:"devices"`
|
||||
Auth interface{} `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
type ReqPutPushRule struct {
|
||||
Before string `json:"-"`
|
||||
After string `json:"-"`
|
||||
|
||||
Actions []pushrules.PushActionType `json:"actions"`
|
||||
Conditions []pushrules.PushCondition `json:"conditions"`
|
||||
Pattern string `json:"pattern"`
|
||||
}
|
||||
|
||||
type ReqBatchSend struct {
|
||||
PrevEventID id.EventID `json:"-"`
|
||||
BatchID id.BatchID `json:"-"`
|
||||
|
||||
StateEventsAtStart []*event.Event `json:"state_events_at_start"`
|
||||
Events []*event.Event `json:"events"`
|
||||
}
|
326
vendor/maunium.net/go/mautrix/responses.go
generated
vendored
Normal file
326
vendor/maunium.net/go/mautrix/responses.go
generated
vendored
Normal file
@ -0,0 +1,326 @@
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// RespWhoami is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-account-whoami
|
||||
type RespWhoami struct {
|
||||
UserID id.UserID `json:"user_id"`
|
||||
// N.B. This field is not in the spec yet, it's expected to land in r0.6.2 or r0.7.0
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
}
|
||||
|
||||
// RespCreateFilter is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-user-userid-filter
|
||||
type RespCreateFilter struct {
|
||||
FilterID string `json:"filter_id"`
|
||||
}
|
||||
|
||||
// RespVersions is the JSON response for http://matrix.org/docs/spec/client_server/r0.6.1.html#get-matrix-client-versions
|
||||
type RespVersions struct {
|
||||
Versions []string `json:"versions"`
|
||||
UnstableFeatures map[string]bool `json:"unstable_features"`
|
||||
}
|
||||
|
||||
// RespJoinRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-join
|
||||
type RespJoinRoom struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
}
|
||||
|
||||
// RespLeaveRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-leave
|
||||
type RespLeaveRoom struct{}
|
||||
|
||||
// RespForgetRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-forget
|
||||
type RespForgetRoom struct{}
|
||||
|
||||
// RespInviteUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
|
||||
type RespInviteUser struct{}
|
||||
|
||||
// RespKickUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
|
||||
type RespKickUser struct{}
|
||||
|
||||
// RespBanUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
|
||||
type RespBanUser struct{}
|
||||
|
||||
// RespUnbanUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
|
||||
type RespUnbanUser struct{}
|
||||
|
||||
// RespTyping is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
|
||||
type RespTyping struct{}
|
||||
|
||||
// RespPresence is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-presence-userid-status
|
||||
type RespPresence struct {
|
||||
Presence event.Presence `json:"presence"`
|
||||
LastActiveAgo int `json:"last_active_ago"`
|
||||
StatusMsg string `json:"status_msg"`
|
||||
CurrentlyActive bool `json:"currently_active"`
|
||||
}
|
||||
|
||||
// RespJoinedRooms is the JSON response for https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-joined-rooms
|
||||
type RespJoinedRooms struct {
|
||||
JoinedRooms []id.RoomID `json:"joined_rooms"`
|
||||
}
|
||||
|
||||
// RespJoinedMembers is the JSON response for https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-joined-rooms
|
||||
type RespJoinedMembers struct {
|
||||
Joined map[id.UserID]struct {
|
||||
DisplayName *string `json:"display_name"`
|
||||
AvatarURL *string `json:"avatar_url"`
|
||||
} `json:"joined"`
|
||||
}
|
||||
|
||||
// RespMessages is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-messages
|
||||
type RespMessages struct {
|
||||
Start string `json:"start"`
|
||||
Chunk []*event.Event `json:"chunk"`
|
||||
State []*event.Event `json:"state"`
|
||||
End string `json:"end"`
|
||||
}
|
||||
|
||||
// RespContext is the JSON response for https://spec.matrix.org/v1.1/client-server-api/#get_matrixclientv3roomsroomidcontexteventid
|
||||
type RespContext struct {
|
||||
End string `json:"end"`
|
||||
Event *event.Event `json:"event"`
|
||||
EventsAfter []*event.Event `json:"events_after"`
|
||||
EventsBefore []*event.Event `json:"events_before"`
|
||||
Start string `json:"start"`
|
||||
State []*event.Event `json:"state"`
|
||||
}
|
||||
|
||||
// RespSendEvent is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
|
||||
type RespSendEvent struct {
|
||||
EventID id.EventID `json:"event_id"`
|
||||
}
|
||||
|
||||
// RespMediaUpload is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-media-r0-upload
|
||||
type RespMediaUpload struct {
|
||||
ContentURI id.ContentURI `json:"content_uri"`
|
||||
}
|
||||
|
||||
// RespUserInteractive is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#user-interactive-authentication-api
|
||||
type RespUserInteractive struct {
|
||||
Flows []struct {
|
||||
Stages []AuthType `json:"stages"`
|
||||
} `json:"flows"`
|
||||
Params map[AuthType]interface{} `json:"params"`
|
||||
Session string `json:"session"`
|
||||
Completed []string `json:"completed"`
|
||||
|
||||
ErrCode string `json:"errcode"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
// HasSingleStageFlow returns true if there exists at least 1 Flow with a single stage of stageName.
|
||||
func (r RespUserInteractive) HasSingleStageFlow(stageName AuthType) bool {
|
||||
for _, f := range r.Flows {
|
||||
if len(f.Stages) == 1 && f.Stages[0] == stageName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RespUserDisplayName is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-displayname
|
||||
type RespUserDisplayName struct {
|
||||
DisplayName string `json:"displayname"`
|
||||
}
|
||||
|
||||
// RespRegister is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register
|
||||
type RespRegister struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
HomeServer string `json:"home_server"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
}
|
||||
|
||||
type LoginFlow struct {
|
||||
Type AuthType `json:"type"`
|
||||
}
|
||||
|
||||
type RespLoginFlows struct {
|
||||
Flows []LoginFlow `json:"flows"`
|
||||
}
|
||||
|
||||
func (rlf *RespLoginFlows) FirstFlowOfType(flowTypes ...AuthType) *LoginFlow {
|
||||
for _, flow := range rlf.Flows {
|
||||
for _, flowType := range flowTypes {
|
||||
if flow.Type == flowType {
|
||||
return &flow
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rlf *RespLoginFlows) HasFlow(flowType ...AuthType) bool {
|
||||
return rlf.FirstFlowOfType(flowType...) != nil
|
||||
}
|
||||
|
||||
// RespLogin is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-login
|
||||
type RespLogin struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
WellKnown *ClientWellKnown `json:"well_known"`
|
||||
}
|
||||
|
||||
// RespLogout is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-logout
|
||||
type RespLogout struct{}
|
||||
|
||||
// RespCreateRoom is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.0.html#post-matrix-client-r0-createroom
|
||||
type RespCreateRoom struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
}
|
||||
|
||||
type RespMembers struct {
|
||||
Chunk []*event.Event `json:"chunk"`
|
||||
}
|
||||
|
||||
type LazyLoadSummary struct {
|
||||
Heroes []id.UserID `json:"m.heroes,omitempty"`
|
||||
JoinedMemberCount *int `json:"m.joined_member_count,omitempty"`
|
||||
InvitedMemberCount *int `json:"m.invited_member_count,omitempty"`
|
||||
}
|
||||
|
||||
// RespSync is the JSON response for http://matrix.org/docs/spec/client_server/r0.6.0.html#get-matrix-client-r0-sync
|
||||
type RespSync struct {
|
||||
NextBatch string `json:"next_batch"`
|
||||
|
||||
AccountData struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"account_data"`
|
||||
Presence struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"presence"`
|
||||
ToDevice struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"to_device"`
|
||||
|
||||
DeviceLists DeviceLists `json:"device_lists"`
|
||||
DeviceOTKCount OTKCount `json:"device_one_time_keys_count"`
|
||||
|
||||
Rooms struct {
|
||||
Leave map[id.RoomID]SyncLeftRoom `json:"leave"`
|
||||
Join map[id.RoomID]SyncJoinedRoom `json:"join"`
|
||||
Invite map[id.RoomID]SyncInvitedRoom `json:"invite"`
|
||||
} `json:"rooms"`
|
||||
}
|
||||
|
||||
type DeviceLists struct {
|
||||
Changed []id.UserID `json:"changed"`
|
||||
Left []id.UserID `json:"left"`
|
||||
}
|
||||
|
||||
type OTKCount struct {
|
||||
Curve25519 int `json:"curve25519"`
|
||||
SignedCurve25519 int `json:"signed_curve25519"`
|
||||
|
||||
// For appservice OTK counts only: the user ID in question
|
||||
UserID id.UserID `json:"-"`
|
||||
DeviceID id.DeviceID `json:"-"`
|
||||
}
|
||||
|
||||
type SyncLeftRoom struct {
|
||||
Summary LazyLoadSummary `json:"summary"`
|
||||
State struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"state"`
|
||||
Timeline struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
Limited bool `json:"limited"`
|
||||
PrevBatch string `json:"prev_batch"`
|
||||
} `json:"timeline"`
|
||||
}
|
||||
|
||||
type SyncJoinedRoom struct {
|
||||
Summary LazyLoadSummary `json:"summary"`
|
||||
State struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"state"`
|
||||
Timeline struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
Limited bool `json:"limited"`
|
||||
PrevBatch string `json:"prev_batch"`
|
||||
} `json:"timeline"`
|
||||
Ephemeral struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"ephemeral"`
|
||||
AccountData struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"account_data"`
|
||||
}
|
||||
|
||||
type SyncInvitedRoom struct {
|
||||
Summary LazyLoadSummary `json:"summary"`
|
||||
State struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"invite_state"`
|
||||
}
|
||||
|
||||
type RespTurnServer struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
TTL int `json:"ttl"`
|
||||
URIs []string `json:"uris"`
|
||||
}
|
||||
|
||||
type RespAliasCreate struct{}
|
||||
type RespAliasDelete struct{}
|
||||
type RespAliasResolve struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
Servers []string `json:"servers"`
|
||||
}
|
||||
|
||||
type RespUploadKeys struct {
|
||||
OneTimeKeyCounts OTKCount `json:"one_time_key_counts"`
|
||||
}
|
||||
|
||||
type RespQueryKeys struct {
|
||||
Failures map[string]interface{} `json:"failures"`
|
||||
DeviceKeys map[id.UserID]map[id.DeviceID]DeviceKeys `json:"device_keys"`
|
||||
MasterKeys map[id.UserID]CrossSigningKeys `json:"master_keys"`
|
||||
SelfSigningKeys map[id.UserID]CrossSigningKeys `json:"self_signing_keys"`
|
||||
UserSigningKeys map[id.UserID]CrossSigningKeys `json:"user_signing_keys"`
|
||||
}
|
||||
|
||||
type RespClaimKeys struct {
|
||||
Failures map[string]interface{} `json:"failures"`
|
||||
OneTimeKeys map[id.UserID]map[id.DeviceID]map[id.KeyID]OneTimeKey `json:"one_time_keys"`
|
||||
}
|
||||
|
||||
type RespUploadSignatures struct {
|
||||
Failures map[string]interface{} `json:"failures"`
|
||||
}
|
||||
|
||||
type RespKeyChanges struct {
|
||||
Changed []id.UserID `json:"changed"`
|
||||
Left []id.UserID `json:"left"`
|
||||
}
|
||||
|
||||
type RespSendToDevice struct{}
|
||||
|
||||
// RespDevicesInfo is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-devices
|
||||
type RespDevicesInfo struct {
|
||||
Devices []RespDeviceInfo `json:"devices"`
|
||||
}
|
||||
|
||||
// RespDeviceInfo is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-devices-deviceid
|
||||
type RespDeviceInfo struct {
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
LastSeenIP string `json:"last_seen_ip"`
|
||||
LastSeenTS int64 `json:"last_seen_ts"`
|
||||
}
|
||||
|
||||
type RespBatchSend struct {
|
||||
StateEventIDs []id.EventID `json:"state_event_ids"`
|
||||
EventIDs []id.EventID `json:"event_ids"`
|
||||
|
||||
InsertionEventID id.EventID `json:"insertion_event_id"`
|
||||
BatchEventID id.EventID `json:"batch_event_id"`
|
||||
BaseInsertionEventID id.EventID `json:"base_insertion_event_id"`
|
||||
|
||||
NextBatchID id.BatchID `json:"next_batch_id"`
|
||||
}
|
54
vendor/maunium.net/go/mautrix/room.go
generated
vendored
Normal file
54
vendor/maunium.net/go/mautrix/room.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type RoomStateMap = map[event.Type]map[string]*event.Event
|
||||
|
||||
// Room represents a single Matrix room.
|
||||
type Room struct {
|
||||
ID id.RoomID
|
||||
State RoomStateMap
|
||||
}
|
||||
|
||||
// UpdateState updates the room's current state with the given Event. This will clobber events based
|
||||
// on the type/state_key combination.
|
||||
func (room Room) UpdateState(evt *event.Event) {
|
||||
_, exists := room.State[evt.Type]
|
||||
if !exists {
|
||||
room.State[evt.Type] = make(map[string]*event.Event)
|
||||
}
|
||||
room.State[evt.Type][*evt.StateKey] = evt
|
||||
}
|
||||
|
||||
// GetStateEvent returns the state event for the given type/state_key combo, or nil.
|
||||
func (room Room) GetStateEvent(eventType event.Type, stateKey string) *event.Event {
|
||||
stateEventMap, _ := room.State[eventType]
|
||||
evt, _ := stateEventMap[stateKey]
|
||||
return evt
|
||||
}
|
||||
|
||||
// GetMembershipState returns the membership state of the given user ID in this room. If there is
|
||||
// no entry for this member, 'leave' is returned for consistency with left users.
|
||||
func (room Room) GetMembershipState(userID id.UserID) event.Membership {
|
||||
state := event.MembershipLeave
|
||||
evt := room.GetStateEvent(event.StateMember, string(userID))
|
||||
if evt != nil {
|
||||
membership, ok := evt.Content.Raw["membership"].(string)
|
||||
if ok {
|
||||
state = event.Membership(membership)
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// NewRoom creates a new Room with the given ID
|
||||
func NewRoom(roomID id.RoomID) *Room {
|
||||
// Init the State map and return a pointer to the Room
|
||||
return &Room{
|
||||
ID: roomID,
|
||||
State: make(RoomStateMap),
|
||||
}
|
||||
}
|
162
vendor/maunium.net/go/mautrix/store.go
generated
vendored
Normal file
162
vendor/maunium.net/go/mautrix/store.go
generated
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Storer is an interface which must be satisfied to store client data.
|
||||
//
|
||||
// You can either write a struct which persists this data to disk, or you can use the
|
||||
// provided "InMemoryStore" which just keeps data around in-memory which is lost on
|
||||
// restarts.
|
||||
type Storer interface {
|
||||
SaveFilterID(userID id.UserID, filterID string)
|
||||
LoadFilterID(userID id.UserID) string
|
||||
SaveNextBatch(userID id.UserID, nextBatchToken string)
|
||||
LoadNextBatch(userID id.UserID) string
|
||||
SaveRoom(room *Room)
|
||||
LoadRoom(roomID id.RoomID) *Room
|
||||
}
|
||||
|
||||
// InMemoryStore implements the Storer interface.
|
||||
//
|
||||
// Everything is persisted in-memory as maps. It is not safe to load/save filter IDs
|
||||
// or next batch tokens on any goroutine other than the syncing goroutine: the one
|
||||
// which called Client.Sync().
|
||||
type InMemoryStore struct {
|
||||
Filters map[id.UserID]string
|
||||
NextBatch map[id.UserID]string
|
||||
Rooms map[id.RoomID]*Room
|
||||
}
|
||||
|
||||
// SaveFilterID to memory.
|
||||
func (s *InMemoryStore) SaveFilterID(userID id.UserID, filterID string) {
|
||||
s.Filters[userID] = filterID
|
||||
}
|
||||
|
||||
// LoadFilterID from memory.
|
||||
func (s *InMemoryStore) LoadFilterID(userID id.UserID) string {
|
||||
return s.Filters[userID]
|
||||
}
|
||||
|
||||
// SaveNextBatch to memory.
|
||||
func (s *InMemoryStore) SaveNextBatch(userID id.UserID, nextBatchToken string) {
|
||||
s.NextBatch[userID] = nextBatchToken
|
||||
}
|
||||
|
||||
// LoadNextBatch from memory.
|
||||
func (s *InMemoryStore) LoadNextBatch(userID id.UserID) string {
|
||||
return s.NextBatch[userID]
|
||||
}
|
||||
|
||||
// SaveRoom to memory.
|
||||
func (s *InMemoryStore) SaveRoom(room *Room) {
|
||||
s.Rooms[room.ID] = room
|
||||
}
|
||||
|
||||
// LoadRoom from memory.
|
||||
func (s *InMemoryStore) LoadRoom(roomID id.RoomID) *Room {
|
||||
return s.Rooms[roomID]
|
||||
}
|
||||
|
||||
// UpdateState stores a state event. This can be passed to DefaultSyncer.OnEvent to keep all room state cached.
|
||||
func (s *InMemoryStore) UpdateState(_ EventSource, evt *event.Event) {
|
||||
if !evt.Type.IsState() {
|
||||
return
|
||||
}
|
||||
room := s.LoadRoom(evt.RoomID)
|
||||
if room == nil {
|
||||
room = NewRoom(evt.RoomID)
|
||||
s.SaveRoom(room)
|
||||
}
|
||||
room.UpdateState(evt)
|
||||
}
|
||||
|
||||
// NewInMemoryStore constructs a new InMemoryStore.
|
||||
func NewInMemoryStore() *InMemoryStore {
|
||||
return &InMemoryStore{
|
||||
Filters: make(map[id.UserID]string),
|
||||
NextBatch: make(map[id.UserID]string),
|
||||
Rooms: make(map[id.RoomID]*Room),
|
||||
}
|
||||
}
|
||||
|
||||
// AccountDataStore uses account data to store the next batch token, and
|
||||
// reuses the InMemoryStore for all other operations.
|
||||
type AccountDataStore struct {
|
||||
*InMemoryStore
|
||||
eventType string
|
||||
client *Client
|
||||
}
|
||||
|
||||
type accountData struct {
|
||||
NextBatch string `json:"next_batch"`
|
||||
}
|
||||
|
||||
// SaveNextBatch to account data.
|
||||
func (s *AccountDataStore) SaveNextBatch(userID id.UserID, nextBatchToken string) {
|
||||
if userID.String() != s.client.UserID.String() {
|
||||
panic("AccountDataStore must only be used with bots")
|
||||
}
|
||||
|
||||
data := accountData{
|
||||
NextBatch: nextBatchToken,
|
||||
}
|
||||
|
||||
err := s.client.SetAccountData(s.eventType, data)
|
||||
if err != nil {
|
||||
if s.client.Logger != nil {
|
||||
s.client.Logger.Debugfln("failed to save next batch token to account data: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LoadNextBatch from account data.
|
||||
func (s *AccountDataStore) LoadNextBatch(userID id.UserID) string {
|
||||
if userID.String() != s.client.UserID.String() {
|
||||
panic("AccountDataStore must only be used with bots")
|
||||
}
|
||||
|
||||
data := &accountData{}
|
||||
|
||||
err := s.client.GetAccountData(s.eventType, data)
|
||||
if err != nil {
|
||||
if s.client.Logger != nil {
|
||||
s.client.Logger.Debugfln("failed to load next batch token to account data: %s", err.Error())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
return data.NextBatch
|
||||
}
|
||||
|
||||
// NewAccountDataStore returns a new AccountDataStore, which stores
|
||||
// the next_batch token as a custom event in account data in the
|
||||
// homeserver.
|
||||
//
|
||||
// AccountDataStore is only appropriate for bots, not appservices.
|
||||
//
|
||||
// eventType should be a reversed DNS name like tld.domain.sub.internal and
|
||||
// must be unique for a client. The data stored in it is considered internal
|
||||
// and must not be modified through outside means. You should also add a filter
|
||||
// for account data changes of this event type, to avoid ending up in a sync
|
||||
// loop:
|
||||
//
|
||||
// mautrix.Filter{
|
||||
// AccountData: mautrix.FilterPart{
|
||||
// Limit: 20,
|
||||
// NotTypes: []event.Type{
|
||||
// event.NewEventType(eventType),
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
// mautrix.Client.CreateFilter(...)
|
||||
//
|
||||
func NewAccountDataStore(eventType string, client *Client) *AccountDataStore {
|
||||
return &AccountDataStore{
|
||||
InMemoryStore: NewInMemoryStore(),
|
||||
eventType: eventType,
|
||||
client: client,
|
||||
}
|
||||
}
|
283
vendor/maunium.net/go/mautrix/sync.go
generated
vendored
Normal file
283
vendor/maunium.net/go/mautrix/sync.go
generated
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
// 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 mautrix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// EventSource represents the part of the sync response that an event came from.
|
||||
type EventSource int
|
||||
|
||||
const (
|
||||
EventSourcePresence EventSource = 1 << iota
|
||||
EventSourceJoin
|
||||
EventSourceInvite
|
||||
EventSourceLeave
|
||||
EventSourceAccountData
|
||||
EventSourceTimeline
|
||||
EventSourceState
|
||||
EventSourceEphemeral
|
||||
EventSourceToDevice
|
||||
)
|
||||
|
||||
func (es EventSource) String() string {
|
||||
switch {
|
||||
case es == EventSourcePresence:
|
||||
return "presence"
|
||||
case es == EventSourceAccountData:
|
||||
return "user account data"
|
||||
case es == EventSourceToDevice:
|
||||
return "to-device"
|
||||
case es&EventSourceJoin != 0:
|
||||
es -= EventSourceJoin
|
||||
switch es {
|
||||
case EventSourceState:
|
||||
return "joined state"
|
||||
case EventSourceTimeline:
|
||||
return "joined timeline"
|
||||
case EventSourceEphemeral:
|
||||
return "room ephemeral (joined)"
|
||||
case EventSourceAccountData:
|
||||
return "room account data (joined)"
|
||||
}
|
||||
case es&EventSourceInvite != 0:
|
||||
es -= EventSourceInvite
|
||||
switch es {
|
||||
case EventSourceState:
|
||||
return "invited state"
|
||||
}
|
||||
case es&EventSourceLeave != 0:
|
||||
es -= EventSourceLeave
|
||||
switch es {
|
||||
case EventSourceState:
|
||||
return "left state"
|
||||
case EventSourceTimeline:
|
||||
return "left timeline"
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("unknown (%d)", es)
|
||||
}
|
||||
|
||||
// EventHandler handles a single event from a sync response.
|
||||
type EventHandler func(source EventSource, evt *event.Event)
|
||||
|
||||
// SyncHandler handles a whole sync response. If the return value is false, handling will be stopped completely.
|
||||
type SyncHandler func(resp *RespSync, since string) bool
|
||||
|
||||
// Syncer is an interface that must be satisfied in order to do /sync requests on a client.
|
||||
type Syncer interface {
|
||||
// Process the /sync response. The since parameter is the since= value that was used to produce the response.
|
||||
// This is useful for detecting the very first sync (since=""). If an error is return, Syncing will be stopped
|
||||
// permanently.
|
||||
ProcessResponse(resp *RespSync, since string) error
|
||||
// OnFailedSync returns either the time to wait before retrying or an error to stop syncing permanently.
|
||||
OnFailedSync(res *RespSync, err error) (time.Duration, error)
|
||||
// GetFilterJSON for the given user ID. NOT the filter ID.
|
||||
GetFilterJSON(userID id.UserID) *Filter
|
||||
}
|
||||
|
||||
type ExtensibleSyncer interface {
|
||||
OnSync(callback SyncHandler)
|
||||
OnEvent(callback EventHandler)
|
||||
OnEventType(eventType event.Type, callback EventHandler)
|
||||
}
|
||||
|
||||
// DefaultSyncer is the default syncing implementation. You can either write your own syncer, or selectively
|
||||
// replace parts of this default syncer (e.g. the ProcessResponse method). The default syncer uses the observer
|
||||
// pattern to notify callers about incoming events. See DefaultSyncer.OnEventType for more information.
|
||||
type DefaultSyncer struct {
|
||||
// syncListeners want the whole sync response, e.g. the crypto machine
|
||||
syncListeners []SyncHandler
|
||||
// globalListeners want all events
|
||||
globalListeners []EventHandler
|
||||
// listeners want a specific event type
|
||||
listeners map[event.Type][]EventHandler
|
||||
// ParseEventContent determines whether or not event content should be parsed before passing to handlers.
|
||||
ParseEventContent bool
|
||||
// ParseErrorHandler is called when event.Content.ParseRaw returns an error.
|
||||
// If it returns false, the event will not be forwarded to listeners.
|
||||
ParseErrorHandler func(evt *event.Event, err error) bool
|
||||
}
|
||||
|
||||
var _ Syncer = (*DefaultSyncer)(nil)
|
||||
var _ ExtensibleSyncer = (*DefaultSyncer)(nil)
|
||||
|
||||
// NewDefaultSyncer returns an instantiated DefaultSyncer
|
||||
func NewDefaultSyncer() *DefaultSyncer {
|
||||
return &DefaultSyncer{
|
||||
listeners: make(map[event.Type][]EventHandler),
|
||||
syncListeners: []SyncHandler{},
|
||||
globalListeners: []EventHandler{},
|
||||
ParseEventContent: true,
|
||||
ParseErrorHandler: func(evt *event.Event, err error) bool {
|
||||
return false
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessResponse processes the /sync response in a way suitable for bots. "Suitable for bots" means a stream of
|
||||
// unrepeating events. Returns a fatal error if a listener panics.
|
||||
func (s *DefaultSyncer) ProcessResponse(res *RespSync, since string) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("ProcessResponse panicked! since=%s panic=%s\n%s", since, r, debug.Stack())
|
||||
}
|
||||
}()
|
||||
|
||||
for _, listener := range s.syncListeners {
|
||||
if !listener(res, since) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
s.processSyncEvents("", res.Presence.Events, EventSourcePresence)
|
||||
s.processSyncEvents("", res.AccountData.Events, EventSourceAccountData)
|
||||
|
||||
for roomID, roomData := range res.Rooms.Join {
|
||||
s.processSyncEvents(roomID, roomData.State.Events, EventSourceJoin|EventSourceState)
|
||||
s.processSyncEvents(roomID, roomData.Timeline.Events, EventSourceJoin|EventSourceTimeline)
|
||||
s.processSyncEvents(roomID, roomData.Ephemeral.Events, EventSourceJoin|EventSourceEphemeral)
|
||||
s.processSyncEvents(roomID, roomData.AccountData.Events, EventSourceJoin|EventSourceAccountData)
|
||||
}
|
||||
for roomID, roomData := range res.Rooms.Invite {
|
||||
s.processSyncEvents(roomID, roomData.State.Events, EventSourceInvite|EventSourceState)
|
||||
}
|
||||
for roomID, roomData := range res.Rooms.Leave {
|
||||
s.processSyncEvents(roomID, roomData.State.Events, EventSourceLeave|EventSourceState)
|
||||
s.processSyncEvents(roomID, roomData.Timeline.Events, EventSourceLeave|EventSourceTimeline)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) processSyncEvents(roomID id.RoomID, events []*event.Event, source EventSource) {
|
||||
for _, evt := range events {
|
||||
s.processSyncEvent(roomID, evt, source)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) processSyncEvent(roomID id.RoomID, evt *event.Event, source EventSource) {
|
||||
evt.RoomID = roomID
|
||||
|
||||
// Ensure the type class is correct. It's safe to mutate the class since the event type is not a pointer.
|
||||
// Listeners are keyed by type structs, which means only the correct class will pass.
|
||||
switch {
|
||||
case evt.StateKey != nil:
|
||||
evt.Type.Class = event.StateEventType
|
||||
case source == EventSourcePresence, source&EventSourceEphemeral != 0:
|
||||
evt.Type.Class = event.EphemeralEventType
|
||||
case source&EventSourceAccountData != 0:
|
||||
evt.Type.Class = event.AccountDataEventType
|
||||
case source == EventSourceToDevice:
|
||||
evt.Type.Class = event.ToDeviceEventType
|
||||
default:
|
||||
evt.Type.Class = event.MessageEventType
|
||||
}
|
||||
|
||||
if s.ParseEventContent {
|
||||
err := evt.Content.ParseRaw(evt.Type)
|
||||
if err != nil && !s.ParseErrorHandler(evt, err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
s.notifyListeners(source, evt)
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) notifyListeners(source EventSource, evt *event.Event) {
|
||||
for _, fn := range s.globalListeners {
|
||||
fn(source, evt)
|
||||
}
|
||||
listeners, exists := s.listeners[evt.Type]
|
||||
if exists {
|
||||
for _, fn := range listeners {
|
||||
fn(source, evt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnEventType allows callers to be notified when there are new events for the given event type.
|
||||
// There are no duplicate checks.
|
||||
func (s *DefaultSyncer) OnEventType(eventType event.Type, callback EventHandler) {
|
||||
_, exists := s.listeners[eventType]
|
||||
if !exists {
|
||||
s.listeners[eventType] = []EventHandler{}
|
||||
}
|
||||
s.listeners[eventType] = append(s.listeners[eventType], callback)
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) OnSync(callback SyncHandler) {
|
||||
s.syncListeners = append(s.syncListeners, callback)
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) OnEvent(callback EventHandler) {
|
||||
s.globalListeners = append(s.globalListeners, callback)
|
||||
}
|
||||
|
||||
// OnFailedSync always returns a 10 second wait period between failed /syncs, never a fatal error.
|
||||
func (s *DefaultSyncer) OnFailedSync(res *RespSync, err error) (time.Duration, error) {
|
||||
return 10 * time.Second, nil
|
||||
}
|
||||
|
||||
// GetFilterJSON returns a filter with a timeline limit of 50.
|
||||
func (s *DefaultSyncer) GetFilterJSON(userID id.UserID) *Filter {
|
||||
return &Filter{
|
||||
Room: RoomFilter{
|
||||
Timeline: FilterPart{
|
||||
Limit: 50,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// OldEventIgnorer is an utility struct for bots to ignore events from before the bot joined the room.
|
||||
// Create a struct and call Register with your DefaultSyncer to register the sync handler.
|
||||
type OldEventIgnorer struct {
|
||||
UserID id.UserID
|
||||
}
|
||||
|
||||
func (oei *OldEventIgnorer) Register(syncer ExtensibleSyncer) {
|
||||
syncer.OnSync(oei.DontProcessOldEvents)
|
||||
}
|
||||
|
||||
// DontProcessOldEvents returns true if a sync response should be processed. May modify the response to remove
|
||||
// stuff that shouldn't be processed.
|
||||
func (oei *OldEventIgnorer) DontProcessOldEvents(resp *RespSync, since string) bool {
|
||||
if since == "" {
|
||||
return false
|
||||
}
|
||||
// This is a horrible hack because /sync will return the most recent messages for a room
|
||||
// as soon as you /join it. We do NOT want to process those events in that particular room
|
||||
// because they may have already been processed (if you toggle the bot in/out of the room).
|
||||
//
|
||||
// Work around this by inspecting each room's timeline and seeing if an m.room.member event for us
|
||||
// exists and is "join" and then discard processing that room entirely if so.
|
||||
// TODO: We probably want to process messages from after the last join event in the timeline.
|
||||
for roomID, roomData := range resp.Rooms.Join {
|
||||
for i := len(roomData.Timeline.Events) - 1; i >= 0; i-- {
|
||||
evt := roomData.Timeline.Events[i]
|
||||
if evt.Type == event.StateMember && evt.GetStateKey() == string(oei.UserID) {
|
||||
membership, _ := evt.Content.Raw["membership"].(string)
|
||||
if membership == "join" {
|
||||
_, ok := resp.Rooms.Join[roomID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
delete(resp.Rooms.Join, roomID) // don't re-process messages
|
||||
delete(resp.Rooms.Invite, roomID) // don't re-process invites
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
5
vendor/maunium.net/go/mautrix/version.go
generated
vendored
Normal file
5
vendor/maunium.net/go/mautrix/version.go
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package mautrix
|
||||
|
||||
const Version = "v0.10.9"
|
||||
|
||||
var DefaultUserAgent = "mautrix-go/" + Version
|
20
vendor/modules.txt
vendored
Normal file
20
vendor/modules.txt
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# github.com/btcsuite/btcutil v1.0.2
|
||||
## explicit; go 1.13
|
||||
github.com/btcsuite/btcutil/base58
|
||||
# golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||
## explicit; go 1.17
|
||||
golang.org/x/crypto/hkdf
|
||||
golang.org/x/crypto/pbkdf2
|
||||
# golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
|
||||
## explicit; go 1.17
|
||||
golang.org/x/net/html
|
||||
golang.org/x/net/html/atom
|
||||
# maunium.net/go/mautrix v0.10.9
|
||||
## explicit; go 1.14
|
||||
maunium.net/go/mautrix
|
||||
maunium.net/go/mautrix/crypto/attachment
|
||||
maunium.net/go/mautrix/crypto/utils
|
||||
maunium.net/go/mautrix/event
|
||||
maunium.net/go/mautrix/id
|
||||
maunium.net/go/mautrix/pushrules
|
||||
maunium.net/go/mautrix/pushrules/glob
|
Loading…
Reference in New Issue
Block a user