Add dep
This commit is contained in:
1
vendor/maunium.net/go/mautrix-appservice/.gitignore
generated
vendored
Normal file
1
vendor/maunium.net/go/mautrix-appservice/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
.idea/
|
21
vendor/maunium.net/go/mautrix-appservice/LICENSE
generated
vendored
Normal file
21
vendor/maunium.net/go/mautrix-appservice/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Tulir Asokan
|
||||
|
||||
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.
|
9
vendor/maunium.net/go/mautrix-appservice/README.md
generated
vendored
Normal file
9
vendor/maunium.net/go/mautrix-appservice/README.md
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
# matrix-appservice-go
|
||||
A [Matrix](https://matrix.org) [Application Service](https://matrix.org/docs/guides/application_services.html) framework written in Go.
|
||||
|
||||
This is highly work in progress, but the base appservice framework should be somewhat usable.
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
go get -u maunium.net/go/mautrix-appservice-go
|
||||
```
|
286
vendor/maunium.net/go/mautrix-appservice/appservice.go
generated
vendored
Normal file
286
vendor/maunium.net/go/mautrix-appservice/appservice.go
generated
vendored
Normal file
@ -0,0 +1,286 @@
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"maunium.net/go/maulogger"
|
||||
"strings"
|
||||
"net/http"
|
||||
"errors"
|
||||
"maunium.net/go/gomatrix"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// EventChannelSize is the size for the Events channel in Appservice instances.
|
||||
var EventChannelSize = 64
|
||||
|
||||
// Create a blank appservice instance.
|
||||
func Create() *AppService {
|
||||
return &AppService{
|
||||
LogConfig: CreateLogConfig(),
|
||||
clients: make(map[string]*gomatrix.Client),
|
||||
intents: make(map[string]*IntentAPI),
|
||||
StateStore: &BasicStateStore{},
|
||||
}
|
||||
}
|
||||
|
||||
// Load an appservice config from a file.
|
||||
func Load(path string) (*AppService, error) {
|
||||
data, readErr := ioutil.ReadFile(path)
|
||||
if readErr != nil {
|
||||
return nil, readErr
|
||||
}
|
||||
|
||||
var config = &AppService{}
|
||||
yaml.Unmarshal(data, config)
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// QueryHandler handles room alias and user ID queries from the homeserver.
|
||||
type QueryHandler interface {
|
||||
QueryAlias(alias string) bool
|
||||
QueryUser(userID string) bool
|
||||
}
|
||||
|
||||
type QueryHandlerStub struct{}
|
||||
|
||||
func (qh *QueryHandlerStub) QueryAlias(alias string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (qh *QueryHandlerStub) QueryUser(userID string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// AppService is the main config for all appservices.
|
||||
// It also serves as the appservice instance struct.
|
||||
type AppService struct {
|
||||
HomeserverDomain string `yaml:"homeserver_domain"`
|
||||
HomeserverURL string `yaml:"homeserver_url"`
|
||||
RegistrationPath string `yaml:"registration"`
|
||||
Host HostConfig `yaml:"host"`
|
||||
LogConfig LogConfig `yaml:"logging"`
|
||||
|
||||
Registration *Registration `yaml:"-"`
|
||||
Log maulogger.Logger `yaml:"-"`
|
||||
|
||||
lastProcessedTransaction string
|
||||
Events chan *gomatrix.Event `yaml:"-"`
|
||||
QueryHandler QueryHandler `yaml:"-"`
|
||||
StateStore StateStore `yaml:"-"`
|
||||
|
||||
server *http.Server
|
||||
botClient *gomatrix.Client
|
||||
botIntent *IntentAPI
|
||||
clients map[string]*gomatrix.Client
|
||||
intents map[string]*IntentAPI
|
||||
}
|
||||
|
||||
// HostConfig contains info about how to host the appservice.
|
||||
type HostConfig struct {
|
||||
Hostname string `yaml:"hostname"`
|
||||
Port uint16 `yaml:"port"`
|
||||
TLSKey string `yaml:"tls_key,omitempty"`
|
||||
TLSCert string `yaml:"tls_cert,omitempty"`
|
||||
}
|
||||
|
||||
// Address gets the whole address of the Appservice.
|
||||
func (hc *HostConfig) Address() string {
|
||||
return fmt.Sprintf("%s:%d", hc.Hostname, hc.Port)
|
||||
}
|
||||
|
||||
// Save saves this config into a file at the given path.
|
||||
func (as *AppService) Save(path string) error {
|
||||
data, err := yaml.Marshal(as)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(path, data, 0644)
|
||||
}
|
||||
|
||||
// YAML returns the config in YAML format.
|
||||
func (as *AppService) YAML() (string, error) {
|
||||
data, err := yaml.Marshal(as)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func (as *AppService) BotMXID() string {
|
||||
return fmt.Sprintf("@%s:%s", as.Registration.SenderLocalpart, as.HomeserverDomain)
|
||||
}
|
||||
|
||||
var MatrixUserIDRegex = regexp.MustCompile("^@([^:]+):(.+)$")
|
||||
|
||||
func ParseUserID(mxid string) (string, string) {
|
||||
match := MatrixUserIDRegex.FindStringSubmatch(mxid)
|
||||
if match != nil && len(match) == 3 {
|
||||
return match[1], match[2]
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func (as *AppService) Intent(userID string) *IntentAPI {
|
||||
intent, ok := as.intents[userID]
|
||||
if !ok {
|
||||
localpart, homeserver := ParseUserID(userID)
|
||||
if len(localpart) == 0 || homeserver != as.HomeserverDomain {
|
||||
return nil
|
||||
}
|
||||
intent = as.NewIntentAPI(localpart)
|
||||
as.intents[userID] = intent
|
||||
}
|
||||
return intent
|
||||
}
|
||||
|
||||
func (as *AppService) BotIntent() *IntentAPI {
|
||||
if as.botIntent == nil {
|
||||
as.botIntent = as.NewIntentAPI(as.Registration.SenderLocalpart)
|
||||
}
|
||||
return as.botIntent
|
||||
}
|
||||
|
||||
func (as *AppService) Client(userID string) *gomatrix.Client {
|
||||
client, ok := as.clients[userID]
|
||||
if !ok {
|
||||
var err error
|
||||
client, err = gomatrix.NewClient(as.HomeserverURL, userID, as.Registration.AppToken)
|
||||
if err != nil {
|
||||
as.Log.Fatalln("Failed to create gomatrix instance:", err)
|
||||
return nil
|
||||
}
|
||||
client.Syncer = nil
|
||||
client.Store = nil
|
||||
client.AppServiceUserID = userID
|
||||
client.Logger = as.Log.Sub(userID)
|
||||
as.clients[userID] = client
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func (as *AppService) BotClient() *gomatrix.Client {
|
||||
if as.botClient == nil {
|
||||
var err error
|
||||
as.botClient, err = gomatrix.NewClient(as.HomeserverURL, as.BotMXID(), as.Registration.AppToken)
|
||||
if err != nil {
|
||||
as.Log.Fatalln("Failed to create gomatrix instance:", err)
|
||||
return nil
|
||||
}
|
||||
as.botClient.Syncer = nil
|
||||
as.botClient.Store = nil
|
||||
as.botClient.Logger = as.Log.Sub("Bot")
|
||||
}
|
||||
return as.botClient
|
||||
}
|
||||
|
||||
// Init initializes the logger and loads the registration of this appservice.
|
||||
func (as *AppService) Init() (bool, error) {
|
||||
as.Events = make(chan *gomatrix.Event, EventChannelSize)
|
||||
as.QueryHandler = &QueryHandlerStub{}
|
||||
|
||||
as.Log = maulogger.Create()
|
||||
as.LogConfig.Configure(as.Log)
|
||||
as.Log.Debugln("Logger initialized successfully.")
|
||||
|
||||
if len(as.RegistrationPath) > 0 {
|
||||
var err error
|
||||
as.Registration, err = LoadRegistration(as.RegistrationPath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
as.Log.Debugln("Appservice initialized successfully.")
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// LogConfig contains configs for the logger.
|
||||
type LogConfig struct {
|
||||
Directory string `yaml:"directory"`
|
||||
FileNameFormat string `yaml:"file_name_format"`
|
||||
FileDateFormat string `yaml:"file_date_format"`
|
||||
FileMode uint32 `yaml:"file_mode"`
|
||||
TimestampFormat string `yaml:"timestamp_format"`
|
||||
RawPrintLevel string `yaml:"print_level"`
|
||||
PrintLevel int `yaml:"-"`
|
||||
}
|
||||
|
||||
type umLogConfig LogConfig
|
||||
|
||||
func (lc *LogConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
err := unmarshal((*umLogConfig)(lc))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch strings.ToUpper(lc.RawPrintLevel) {
|
||||
case "DEBUG":
|
||||
lc.PrintLevel = maulogger.LevelDebug.Severity
|
||||
case "INFO":
|
||||
lc.PrintLevel = maulogger.LevelInfo.Severity
|
||||
case "WARN", "WARNING":
|
||||
lc.PrintLevel = maulogger.LevelWarn.Severity
|
||||
case "ERR", "ERROR":
|
||||
lc.PrintLevel = maulogger.LevelError.Severity
|
||||
case "FATAL":
|
||||
lc.PrintLevel = maulogger.LevelFatal.Severity
|
||||
default:
|
||||
return errors.New("invalid print level " + lc.RawPrintLevel)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (lc *LogConfig) MarshalYAML() (interface{}, error) {
|
||||
switch {
|
||||
case lc.PrintLevel >= maulogger.LevelFatal.Severity:
|
||||
lc.RawPrintLevel = maulogger.LevelFatal.Name
|
||||
case lc.PrintLevel >= maulogger.LevelError.Severity:
|
||||
lc.RawPrintLevel = maulogger.LevelError.Name
|
||||
case lc.PrintLevel >= maulogger.LevelWarn.Severity:
|
||||
lc.RawPrintLevel = maulogger.LevelWarn.Name
|
||||
case lc.PrintLevel >= maulogger.LevelInfo.Severity:
|
||||
lc.RawPrintLevel = maulogger.LevelInfo.Name
|
||||
default:
|
||||
lc.RawPrintLevel = maulogger.LevelDebug.Name
|
||||
}
|
||||
return lc, nil
|
||||
}
|
||||
|
||||
// CreateLogConfig creates a basic LogConfig.
|
||||
func CreateLogConfig() LogConfig {
|
||||
return LogConfig{
|
||||
Directory: "./logs",
|
||||
FileNameFormat: "%[1]s-%02[2]d.log",
|
||||
TimestampFormat: "Jan _2, 2006 15:04:05",
|
||||
FileMode: 0600,
|
||||
FileDateFormat: "2006-01-02",
|
||||
PrintLevel: 10,
|
||||
}
|
||||
}
|
||||
|
||||
// GetFileFormat returns a mauLogger-compatible logger file format based on the data in the struct.
|
||||
func (lc LogConfig) GetFileFormat() maulogger.LoggerFileFormat {
|
||||
path := lc.FileNameFormat
|
||||
if len(lc.Directory) > 0 {
|
||||
path = lc.Directory + "/" + path
|
||||
}
|
||||
|
||||
return func(now string, i int) string {
|
||||
return fmt.Sprintf(path, now, i)
|
||||
}
|
||||
}
|
||||
|
||||
// Configure configures a mauLogger instance with the data in this struct.
|
||||
func (lc LogConfig) Configure(log maulogger.Logger) {
|
||||
basicLogger := log.(*maulogger.BasicLogger)
|
||||
basicLogger.FileFormat = lc.GetFileFormat()
|
||||
basicLogger.FileMode = os.FileMode(lc.FileMode)
|
||||
basicLogger.FileTimeFormat = lc.FileDateFormat
|
||||
basicLogger.TimeFormat = lc.TimestampFormat
|
||||
basicLogger.PrintLevel = lc.PrintLevel
|
||||
}
|
77
vendor/maunium.net/go/mautrix-appservice/eventprocessor.go
generated
vendored
Normal file
77
vendor/maunium.net/go/mautrix-appservice/eventprocessor.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"maunium.net/go/gomatrix"
|
||||
log "maunium.net/go/maulogger"
|
||||
)
|
||||
|
||||
type ExecMode uint8
|
||||
|
||||
const (
|
||||
AsyncHandlers ExecMode = iota
|
||||
AsyncLoop
|
||||
Sync
|
||||
)
|
||||
|
||||
type EventProcessor struct {
|
||||
ExecMode ExecMode
|
||||
|
||||
as *AppService
|
||||
log log.Logger
|
||||
stop chan struct{}
|
||||
handlers map[gomatrix.EventType][]gomatrix.OnEventListener
|
||||
}
|
||||
|
||||
func NewEventProcessor(as *AppService) *EventProcessor {
|
||||
return &EventProcessor{
|
||||
ExecMode: AsyncHandlers,
|
||||
as: as,
|
||||
log: as.Log.Sub("Events"),
|
||||
stop: make(chan struct{}, 1),
|
||||
handlers: make(map[gomatrix.EventType][]gomatrix.OnEventListener),
|
||||
}
|
||||
}
|
||||
|
||||
func (ep *EventProcessor) On(evtType gomatrix.EventType, handler gomatrix.OnEventListener) {
|
||||
handlers, ok := ep.handlers[evtType]
|
||||
if !ok {
|
||||
handlers = []gomatrix.OnEventListener{handler}
|
||||
} else {
|
||||
handlers = append(handlers, handler)
|
||||
}
|
||||
ep.handlers[evtType] = handlers
|
||||
}
|
||||
|
||||
func (ep *EventProcessor) Start() {
|
||||
for {
|
||||
select {
|
||||
case evt := <-ep.as.Events:
|
||||
handlers, ok := ep.handlers[evt.Type]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch ep.ExecMode {
|
||||
case AsyncHandlers:
|
||||
for _, handler := range handlers {
|
||||
go handler(evt)
|
||||
}
|
||||
case AsyncLoop:
|
||||
go func() {
|
||||
for _, handler := range handlers {
|
||||
handler(evt)
|
||||
}
|
||||
}()
|
||||
case Sync:
|
||||
for _, handler := range handlers {
|
||||
handler(evt)
|
||||
}
|
||||
}
|
||||
case <-ep.stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ep *EventProcessor) Stop() {
|
||||
ep.stop <- struct{}{}
|
||||
}
|
208
vendor/maunium.net/go/mautrix-appservice/generator.go
generated
vendored
Normal file
208
vendor/maunium.net/go/mautrix-appservice/generator.go
generated
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
func readString(reader *bufio.Reader, message, defaultValue string) (string, error) {
|
||||
color.Green(message)
|
||||
if len(defaultValue) > 0 {
|
||||
fmt.Printf("[%s]", defaultValue)
|
||||
}
|
||||
fmt.Print("> ")
|
||||
val, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
val = strings.TrimSuffix(val, "\n")
|
||||
if len(val) == 0 {
|
||||
return defaultValue, nil
|
||||
}
|
||||
val = strings.TrimSuffix(val, "\r")
|
||||
if len(val) == 0 {
|
||||
return defaultValue, nil
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
const (
|
||||
yes = "yes"
|
||||
yesShort = "y"
|
||||
)
|
||||
|
||||
// GenerateRegistration asks the user questions and generates a config and registration based on the answers.
|
||||
func GenerateRegistration(asName, botName string, reserveRooms, reserveUsers bool) {
|
||||
var boldCyan = color.New(color.FgCyan).Add(color.Bold)
|
||||
var boldGreen = color.New(color.FgGreen).Add(color.Bold)
|
||||
boldCyan.Println("Generating appservice config and registration.")
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
name, err := readString(reader, "Enter name for appservice", asName)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
registration := CreateRegistration(name)
|
||||
config := Create()
|
||||
registration.RateLimited = false
|
||||
|
||||
registration.SenderLocalpart, err = readString(reader, "Enter bot username", botName)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
|
||||
asProtocol, err := readString(reader, "Enter appservice host protocol", "http")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
if asProtocol == "https" {
|
||||
sslInput, err := readString(reader, "Do you want the appservice to handle SSL [yes/no]?", "yes")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
wantSSL := strings.ToLower(sslInput)
|
||||
if wantSSL == yes {
|
||||
config.Host.TLSCert, err = readString(reader, "Enter path to SSL certificate", "appservice.crt")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
config.Host.TLSKey, err = readString(reader, "Enter path to SSL key", "appservice.key")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
asHostname, err := readString(reader, "Enter appservice hostname", "localhost")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
asInput, err := readString(reader, "Enter appservice host port", "29313")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
asPort, convErr := strconv.Atoi(asInput)
|
||||
if convErr != nil {
|
||||
fmt.Println("Failed to parse port:", convErr)
|
||||
return
|
||||
}
|
||||
registration.URL = fmt.Sprintf("%s://%s:%d", asProtocol, asHostname, asPort)
|
||||
config.Host.Hostname = asHostname
|
||||
config.Host.Port = uint16(asPort)
|
||||
|
||||
config.HomeserverURL, err = readString(reader, "Enter homeserver address", "http://localhost:8008")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
config.HomeserverDomain, err = readString(reader, "Enter homeserver domain", "example.com")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
config.LogConfig.Directory, err = readString(reader, "Enter directory for logs", "./logs")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
os.MkdirAll(config.LogConfig.Directory, 0755)
|
||||
|
||||
if reserveRooms || reserveUsers {
|
||||
for {
|
||||
namespace, err := readString(reader, "Enter namespace prefix", fmt.Sprintf("_%s_", name))
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
roomNamespaceRegex, err := regexp.Compile(fmt.Sprintf("#%s.+:%s", namespace, config.HomeserverDomain))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
userNamespaceRegex, regexpErr := regexp.Compile(fmt.Sprintf("@%s.+:%s", namespace, config.HomeserverDomain))
|
||||
if regexpErr != nil {
|
||||
fmt.Println("Failed to generate regexp for the userNamespace:", err)
|
||||
return
|
||||
}
|
||||
if reserveRooms {
|
||||
registration.Namespaces.RegisterRoomAliases(roomNamespaceRegex, true)
|
||||
}
|
||||
if reserveUsers {
|
||||
registration.Namespaces.RegisterUserIDs(userNamespaceRegex, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
boldCyan.Println("\n==== Registration generated ====")
|
||||
yamlString, yamlErr := registration.YAML()
|
||||
if err != nil {
|
||||
fmt.Println("Failed to return the registration Config:", yamlErr)
|
||||
return
|
||||
}
|
||||
color.Yellow(yamlString)
|
||||
|
||||
okInput, readErr := readString(reader, "Does the registration look OK [yes/no]?", "yes")
|
||||
if readErr != nil {
|
||||
fmt.Println("Failed to read user Input:", readErr)
|
||||
return
|
||||
}
|
||||
ok := strings.ToLower(okInput)
|
||||
if ok != yesShort && ok != yes {
|
||||
fmt.Println("Cancelling generation.")
|
||||
return
|
||||
}
|
||||
|
||||
path, err := readString(reader, "Where should the registration be saved?", "registration.yaml")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
err = registration.Save(path)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to save registration:", err)
|
||||
return
|
||||
}
|
||||
boldGreen.Println("Registration saved.")
|
||||
|
||||
config.RegistrationPath = path
|
||||
|
||||
boldCyan.Println("\n======= Config generated =======")
|
||||
color.Yellow(config.YAML())
|
||||
|
||||
okString, err := readString(reader, "Does the config look OK [yes/no]?", "yes")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
ok = strings.ToLower(okString)
|
||||
if ok != yesShort && ok != yes {
|
||||
fmt.Println("Cancelling generation.")
|
||||
return
|
||||
}
|
||||
|
||||
path, err = readString(reader, "Where should the config be saved?", "config.yaml")
|
||||
if err != nil {
|
||||
fmt.Println("Failed to read user Input:", err)
|
||||
return
|
||||
}
|
||||
err = config.Save(path)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to save config:", err)
|
||||
return
|
||||
}
|
||||
boldGreen.Println("Config saved.")
|
||||
}
|
153
vendor/maunium.net/go/mautrix-appservice/http.go
generated
vendored
Normal file
153
vendor/maunium.net/go/mautrix-appservice/http.go
generated
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"github.com/gorilla/mux"
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Listen starts the HTTP server that listens for calls from the Matrix homeserver.
|
||||
func (as *AppService) Start() {
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/transactions/{txnID}", as.PutTransaction).Methods(http.MethodPut)
|
||||
r.HandleFunc("/rooms/{roomAlias}", as.GetRoom).Methods(http.MethodGet)
|
||||
r.HandleFunc("/users/{userID}", as.GetUser).Methods(http.MethodGet)
|
||||
|
||||
var err error
|
||||
as.server = &http.Server{
|
||||
Addr: as.Host.Address(),
|
||||
Handler: r,
|
||||
}
|
||||
as.Log.Infoln("Listening on", as.Host.Address())
|
||||
if len(as.Host.TLSCert) == 0 || len(as.Host.TLSKey) == 0 {
|
||||
err = as.server.ListenAndServe()
|
||||
} else {
|
||||
err = as.server.ListenAndServeTLS(as.Host.TLSCert, as.Host.TLSKey)
|
||||
}
|
||||
if err != nil && err.Error() != "http: Server closed" {
|
||||
as.Log.Fatalln("Error while listening:", err)
|
||||
} else {
|
||||
as.Log.Debugln("Listener stopped.")
|
||||
}
|
||||
}
|
||||
|
||||
func (as *AppService) Stop() {
|
||||
if as.server == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
as.server.Shutdown(ctx)
|
||||
as.server = nil
|
||||
}
|
||||
|
||||
// CheckServerToken checks if the given request originated from the Matrix homeserver.
|
||||
func (as *AppService) CheckServerToken(w http.ResponseWriter, r *http.Request) bool {
|
||||
query := r.URL.Query()
|
||||
val, ok := query["access_token"]
|
||||
if !ok {
|
||||
Error{
|
||||
ErrorCode: ErrForbidden,
|
||||
HTTPStatus: http.StatusForbidden,
|
||||
Message: "Bad token supplied.",
|
||||
}.Write(w)
|
||||
return false
|
||||
}
|
||||
for _, str := range val {
|
||||
return str == as.Registration.ServerToken
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// PutTransaction handles a /transactions PUT call from the homeserver.
|
||||
func (as *AppService) PutTransaction(w http.ResponseWriter, r *http.Request) {
|
||||
if !as.CheckServerToken(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
txnID := vars["txnID"]
|
||||
if len(txnID) == 0 {
|
||||
Error{
|
||||
ErrorCode: ErrNoTransactionID,
|
||||
HTTPStatus: http.StatusBadRequest,
|
||||
Message: "Missing transaction ID.",
|
||||
}.Write(w)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil || len(body) == 0 {
|
||||
Error{
|
||||
ErrorCode: ErrNoBody,
|
||||
HTTPStatus: http.StatusBadRequest,
|
||||
Message: "Missing request body.",
|
||||
}.Write(w)
|
||||
return
|
||||
}
|
||||
if as.lastProcessedTransaction == txnID {
|
||||
// Duplicate transaction ID: no-op
|
||||
WriteBlankOK(w)
|
||||
return
|
||||
}
|
||||
|
||||
eventList := EventList{}
|
||||
err = json.Unmarshal(body, &eventList)
|
||||
if err != nil {
|
||||
Error{
|
||||
ErrorCode: ErrInvalidJSON,
|
||||
HTTPStatus: http.StatusBadRequest,
|
||||
Message: "Failed to parse body JSON.",
|
||||
}.Write(w)
|
||||
return
|
||||
}
|
||||
|
||||
for _, event := range eventList.Events {
|
||||
as.Log.Debugln("Received event", event.ID)
|
||||
as.UpdateState(event)
|
||||
as.Events <- event
|
||||
}
|
||||
as.lastProcessedTransaction = txnID
|
||||
WriteBlankOK(w)
|
||||
}
|
||||
|
||||
// GetRoom handles a /rooms GET call from the homeserver.
|
||||
func (as *AppService) GetRoom(w http.ResponseWriter, r *http.Request) {
|
||||
if !as.CheckServerToken(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
roomAlias := vars["roomAlias"]
|
||||
ok := as.QueryHandler.QueryAlias(roomAlias)
|
||||
if ok {
|
||||
WriteBlankOK(w)
|
||||
} else {
|
||||
Error{
|
||||
ErrorCode: ErrUnknown,
|
||||
HTTPStatus: http.StatusNotFound,
|
||||
}.Write(w)
|
||||
}
|
||||
}
|
||||
|
||||
// GetUser handles a /users GET call from the homeserver.
|
||||
func (as *AppService) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
if !as.CheckServerToken(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
userID := vars["userID"]
|
||||
ok := as.QueryHandler.QueryUser(userID)
|
||||
if ok {
|
||||
WriteBlankOK(w)
|
||||
} else {
|
||||
Error{
|
||||
ErrorCode: ErrUnknown,
|
||||
HTTPStatus: http.StatusNotFound,
|
||||
}.Write(w)
|
||||
}
|
||||
}
|
218
vendor/maunium.net/go/mautrix-appservice/intent.go
generated
vendored
Normal file
218
vendor/maunium.net/go/mautrix-appservice/intent.go
generated
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maunium.net/go/gomatrix"
|
||||
)
|
||||
|
||||
type IntentAPI struct {
|
||||
*gomatrix.Client
|
||||
bot *gomatrix.Client
|
||||
as *AppService
|
||||
Localpart string
|
||||
UserID string
|
||||
}
|
||||
|
||||
func (as *AppService) NewIntentAPI(localpart string) *IntentAPI {
|
||||
userID := fmt.Sprintf("@%s:%s", localpart, as.HomeserverDomain)
|
||||
bot := as.BotClient()
|
||||
if userID == bot.UserID {
|
||||
bot = nil
|
||||
}
|
||||
return &IntentAPI{
|
||||
Client: as.Client(userID),
|
||||
bot: bot,
|
||||
as: as,
|
||||
Localpart: localpart,
|
||||
UserID: userID,
|
||||
}
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) Register() error {
|
||||
_, _, err := intent.Client.Register(&gomatrix.ReqRegister{
|
||||
Username: intent.Localpart,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) EnsureRegistered() error {
|
||||
if intent.as.StateStore.IsRegistered(intent.UserID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := intent.Register()
|
||||
httpErr, ok := err.(gomatrix.HTTPError)
|
||||
if !ok || httpErr.RespError.ErrCode != "M_USER_IN_USE" {
|
||||
return err
|
||||
}
|
||||
intent.as.StateStore.MarkRegistered(intent.UserID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) EnsureJoined(roomID string) error {
|
||||
if intent.as.StateStore.IsInRoom(roomID, intent.UserID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := intent.EnsureRegistered(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := intent.JoinRoom(roomID, "", nil)
|
||||
if err != nil {
|
||||
httpErr, ok := err.(gomatrix.HTTPError)
|
||||
if !ok || httpErr.RespError.ErrCode != "M_FORBIDDEN" || intent.bot == nil {
|
||||
return httpErr
|
||||
}
|
||||
_, inviteErr := intent.bot.InviteUser(roomID, &gomatrix.ReqInviteUser{
|
||||
UserID: intent.UserID,
|
||||
})
|
||||
if inviteErr != nil {
|
||||
return err
|
||||
}
|
||||
resp, err = intent.JoinRoom(roomID, "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
intent.as.StateStore.SetMembership(resp.RoomID, intent.UserID, "join")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SendMessageEvent(roomID string, eventType gomatrix.EventType, contentJSON interface{}) (*gomatrix.RespSendEvent, error) {
|
||||
if err := intent.EnsureJoined(roomID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return intent.Client.SendMessageEvent(roomID, eventType, contentJSON)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SendMassagedMessageEvent(roomID string, eventType gomatrix.EventType, contentJSON interface{}, ts int64) (*gomatrix.RespSendEvent, error) {
|
||||
if err := intent.EnsureJoined(roomID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return intent.Client.SendMassagedMessageEvent(roomID, eventType, contentJSON, ts)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SendStateEvent(roomID string, eventType gomatrix.EventType, stateKey string, contentJSON interface{}) (*gomatrix.RespSendEvent, error) {
|
||||
if err := intent.EnsureJoined(roomID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return intent.Client.SendStateEvent(roomID, eventType, stateKey, contentJSON)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SendMassagedStateEvent(roomID string, eventType gomatrix.EventType, stateKey string, contentJSON interface{}, ts int64) (*gomatrix.RespSendEvent, error) {
|
||||
if err := intent.EnsureJoined(roomID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return intent.Client.SendMassagedStateEvent(roomID, eventType, stateKey, contentJSON, ts)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) StateEvent(roomID string, eventType gomatrix.EventType, stateKey string, outContent interface{}) (err error) {
|
||||
if err := intent.EnsureJoined(roomID); err != nil {
|
||||
return err
|
||||
}
|
||||
return intent.Client.StateEvent(roomID, eventType, stateKey, outContent)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) PowerLevels(roomID string) (pl *gomatrix.PowerLevels, err error) {
|
||||
pl = intent.as.StateStore.GetPowerLevels(roomID)
|
||||
if pl == nil {
|
||||
pl = &gomatrix.PowerLevels{}
|
||||
err = intent.StateEvent(roomID, gomatrix.StatePowerLevels, "", pl)
|
||||
if err == nil {
|
||||
intent.as.StateStore.SetPowerLevels(roomID, pl)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SetPowerLevels(roomID string, levels *gomatrix.PowerLevels) (resp *gomatrix.RespSendEvent, err error) {
|
||||
resp, err = intent.SendStateEvent(roomID, gomatrix.StatePowerLevels, "", &levels)
|
||||
if err == nil {
|
||||
intent.as.StateStore.SetPowerLevels(roomID, levels)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SetPowerLevel(roomID, userID string, level int) (*gomatrix.RespSendEvent, error) {
|
||||
pl, err := intent.PowerLevels(roomID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pl.GetUserLevel(userID) != level {
|
||||
pl.SetUserLevel(userID, level)
|
||||
return intent.SendStateEvent(roomID, gomatrix.StatePowerLevels, "", &pl)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SendText(roomID, text string) (*gomatrix.RespSendEvent, error) {
|
||||
if err := intent.EnsureJoined(roomID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return intent.Client.SendText(roomID, text)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SendImage(roomID, body, url string) (*gomatrix.RespSendEvent, error) {
|
||||
if err := intent.EnsureJoined(roomID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return intent.Client.SendImage(roomID, body, url)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SendVideo(roomID, body, url string) (*gomatrix.RespSendEvent, error) {
|
||||
if err := intent.EnsureJoined(roomID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return intent.Client.SendVideo(roomID, body, url)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SendNotice(roomID, text string) (*gomatrix.RespSendEvent, error) {
|
||||
if err := intent.EnsureJoined(roomID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return intent.Client.SendNotice(roomID, text)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) RedactEvent(roomID, eventID string, req *gomatrix.ReqRedact) (*gomatrix.RespSendEvent, error) {
|
||||
if err := intent.EnsureJoined(roomID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return intent.Client.RedactEvent(roomID, eventID, req)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SetRoomName(roomID, roomName string) (*gomatrix.RespSendEvent, error) {
|
||||
return intent.SendStateEvent(roomID, "m.room.name", "", map[string]interface{}{
|
||||
"name": roomName,
|
||||
})
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SetRoomAvatar(roomID, avatarURL string) (*gomatrix.RespSendEvent, error) {
|
||||
return intent.SendStateEvent(roomID, "m.room.avatar", "", map[string]interface{}{
|
||||
"url": avatarURL,
|
||||
})
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SetRoomTopic(roomID, topic string) (*gomatrix.RespSendEvent, error) {
|
||||
return intent.SendStateEvent(roomID, "m.room.topic", "", map[string]interface{}{
|
||||
"topic": topic,
|
||||
})
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SetDisplayName(displayName string) error {
|
||||
if err := intent.EnsureRegistered(); err != nil {
|
||||
return err
|
||||
}
|
||||
return intent.Client.SetDisplayName(displayName)
|
||||
}
|
||||
|
||||
func (intent *IntentAPI) SetAvatarURL(avatarURL string) error {
|
||||
if err := intent.EnsureRegistered(); err != nil {
|
||||
return err
|
||||
}
|
||||
return intent.Client.SetAvatarURL(avatarURL)
|
||||
}
|
59
vendor/maunium.net/go/mautrix-appservice/protocol.go
generated
vendored
Normal file
59
vendor/maunium.net/go/mautrix-appservice/protocol.go
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"maunium.net/go/gomatrix"
|
||||
)
|
||||
|
||||
// EventList contains a list of events.
|
||||
type EventList struct {
|
||||
Events []*gomatrix.Event `json:"events"`
|
||||
}
|
||||
|
||||
// EventListener is a function that receives events.
|
||||
type EventListener func(event *gomatrix.Event)
|
||||
|
||||
// WriteBlankOK writes a blank OK message as a reply to a HTTP request.
|
||||
func WriteBlankOK(w http.ResponseWriter) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("{}"))
|
||||
}
|
||||
|
||||
// Respond responds to a HTTP request with a JSON object.
|
||||
func Respond(w http.ResponseWriter, data interface{}) error {
|
||||
dataStr, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write([]byte(dataStr))
|
||||
return err
|
||||
}
|
||||
|
||||
// Error represents a Matrix protocol error.
|
||||
type Error struct {
|
||||
HTTPStatus int `json:"-"`
|
||||
ErrorCode ErrorCode `json:"errcode"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (err Error) Write(w http.ResponseWriter) {
|
||||
w.WriteHeader(err.HTTPStatus)
|
||||
Respond(w, &err)
|
||||
}
|
||||
|
||||
// ErrorCode is the machine-readable code in an Error.
|
||||
type ErrorCode string
|
||||
|
||||
// Native ErrorCodes
|
||||
const (
|
||||
ErrForbidden ErrorCode = "M_FORBIDDEN"
|
||||
ErrUnknown ErrorCode = "M_UNKNOWN"
|
||||
)
|
||||
|
||||
// Custom ErrorCodes
|
||||
const (
|
||||
ErrNoTransactionID ErrorCode = "NET.MAUNIUM.NO_TRANSACTION_ID"
|
||||
ErrNoBody ErrorCode = "NET.MAUNIUM.NO_REQUEST_BODY"
|
||||
ErrInvalidJSON ErrorCode = "NET.MAUNIUM.INVALID_JSON"
|
||||
)
|
34
vendor/maunium.net/go/mautrix-appservice/random.go
generated
vendored
Normal file
34
vendor/maunium.net/go/mautrix-appservice/random.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
const (
|
||||
letterIdxBits = 6
|
||||
letterIdxMask = 1<<letterIdxBits - 1
|
||||
letterIdxMax = 63 / letterIdxBits
|
||||
)
|
||||
|
||||
var src = rand.NewSource(time.Now().UnixNano())
|
||||
|
||||
// RandomString generates a random string of the given length.
|
||||
func RandomString(n int) string {
|
||||
b := make([]byte, n)
|
||||
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
|
||||
if remain == 0 {
|
||||
cache, remain = src.Int63(), letterIdxMax
|
||||
}
|
||||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||
b[i] = letterBytes[idx]
|
||||
i--
|
||||
}
|
||||
cache >>= letterIdxBits
|
||||
remain--
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
99
vendor/maunium.net/go/mautrix-appservice/registration.go
generated
vendored
Normal file
99
vendor/maunium.net/go/mautrix-appservice/registration.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"regexp"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Registration contains the data in a Matrix appservice registration.
|
||||
// See https://matrix.org/docs/spec/application_service/unstable.html#registration
|
||||
type Registration struct {
|
||||
ID string `yaml:"id"`
|
||||
URL string `yaml:"url"`
|
||||
AppToken string `yaml:"as_token"`
|
||||
ServerToken string `yaml:"hs_token"`
|
||||
SenderLocalpart string `yaml:"sender_localpart"`
|
||||
RateLimited bool `yaml:"rate_limited"`
|
||||
Namespaces Namespaces `yaml:"namespaces"`
|
||||
}
|
||||
|
||||
// CreateRegistration creates a Registration with random appservice and homeserver tokens.
|
||||
func CreateRegistration(name string) *Registration {
|
||||
return &Registration{
|
||||
AppToken: RandomString(64),
|
||||
ServerToken: RandomString(64),
|
||||
}
|
||||
}
|
||||
|
||||
// LoadRegistration loads a YAML file and turns it into a Registration.
|
||||
func LoadRegistration(path string) (*Registration, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reg := &Registration{}
|
||||
err = yaml.Unmarshal(data, reg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reg, nil
|
||||
}
|
||||
|
||||
// Save saves this Registration into a file at the given path.
|
||||
func (reg *Registration) Save(path string) error {
|
||||
data, err := yaml.Marshal(reg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(path, data, 0600)
|
||||
}
|
||||
|
||||
// YAML returns the registration in YAML format.
|
||||
func (reg *Registration) YAML() (string, error) {
|
||||
data, err := yaml.Marshal(reg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
// Namespaces contains the three areas that appservices can reserve parts of.
|
||||
type Namespaces struct {
|
||||
UserIDs []Namespace `yaml:"users,omitempty"`
|
||||
RoomAliases []Namespace `yaml:"aliases,omitempty"`
|
||||
RoomIDs []Namespace `yaml:"rooms,omitempty"`
|
||||
}
|
||||
|
||||
// Namespace is a reserved namespace in any area.
|
||||
type Namespace struct {
|
||||
Regex string `yaml:"regex"`
|
||||
Exclusive bool `yaml:"exclusive"`
|
||||
}
|
||||
|
||||
// RegisterUserIDs creates an user ID namespace registration.
|
||||
func (nslist *Namespaces) RegisterUserIDs(regex *regexp.Regexp, exclusive bool) {
|
||||
nslist.UserIDs = append(nslist.UserIDs, Namespace{
|
||||
Regex: regex.String(),
|
||||
Exclusive: exclusive,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterRoomAliases creates an room alias namespace registration.
|
||||
func (nslist *Namespaces) RegisterRoomAliases(regex *regexp.Regexp, exclusive bool) {
|
||||
nslist.RoomAliases = append(nslist.RoomAliases, Namespace{
|
||||
Regex: regex.String(),
|
||||
Exclusive: exclusive,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterRoomIDs creates an room ID namespace registration.
|
||||
func (nslist *Namespaces) RegisterRoomIDs(regex *regexp.Regexp, exclusive bool) {
|
||||
nslist.RoomIDs = append(nslist.RoomIDs, Namespace{
|
||||
Regex: regex.String(),
|
||||
Exclusive: exclusive,
|
||||
})
|
||||
}
|
132
vendor/maunium.net/go/mautrix-appservice/statestore.go
generated
vendored
Normal file
132
vendor/maunium.net/go/mautrix-appservice/statestore.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
package appservice
|
||||
|
||||
import (
|
||||
"maunium.net/go/gomatrix"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type StateStore interface {
|
||||
IsRegistered(userID string) bool
|
||||
MarkRegistered(userID string)
|
||||
|
||||
IsInRoom(roomID, userID string) bool
|
||||
SetMembership(roomID, userID, membership string)
|
||||
|
||||
SetPowerLevels(roomID string, levels *gomatrix.PowerLevels)
|
||||
GetPowerLevels(roomID string) *gomatrix.PowerLevels
|
||||
GetPowerLevel(roomID, userID string) int
|
||||
GetPowerLevelRequirement(roomID string, eventType gomatrix.EventType, isState bool) int
|
||||
HasPowerLevel(roomID, userID string, eventType gomatrix.EventType, isState bool) bool
|
||||
}
|
||||
|
||||
func (as *AppService) UpdateState(evt *gomatrix.Event) {
|
||||
switch evt.Type {
|
||||
case gomatrix.StateMember:
|
||||
as.StateStore.SetMembership(evt.RoomID, evt.GetStateKey(), evt.Content.Membership)
|
||||
}
|
||||
}
|
||||
|
||||
type BasicStateStore struct {
|
||||
registrationsLock sync.RWMutex `json:"-"`
|
||||
Registrations map[string]bool `json:"registrations"`
|
||||
membershipsLock sync.RWMutex `json:"-"`
|
||||
Memberships map[string]map[string]string `json:"memberships"`
|
||||
powerLevelsLock sync.RWMutex `json:"-"`
|
||||
PowerLevels map[string]*gomatrix.PowerLevels `json:"power_levels"`
|
||||
}
|
||||
|
||||
func NewBasicStateStore() *BasicStateStore {
|
||||
return &BasicStateStore{
|
||||
Registrations: make(map[string]bool),
|
||||
Memberships: make(map[string]map[string]string),
|
||||
PowerLevels: make(map[string]*gomatrix.PowerLevels),
|
||||
}
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) IsRegistered(userID string) bool {
|
||||
store.registrationsLock.RLock()
|
||||
registered, ok := store.Registrations[userID]
|
||||
store.registrationsLock.RUnlock()
|
||||
return ok && registered
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) MarkRegistered(userID string) {
|
||||
store.registrationsLock.Lock()
|
||||
store.Registrations[userID] = true
|
||||
store.registrationsLock.Unlock()
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) GetRoomMemberships(roomID string) map[string]string {
|
||||
store.membershipsLock.RLock()
|
||||
memberships, ok := store.Memberships[roomID]
|
||||
store.membershipsLock.RUnlock()
|
||||
if !ok {
|
||||
memberships = make(map[string]string)
|
||||
store.membershipsLock.Lock()
|
||||
store.Memberships[roomID] = memberships
|
||||
store.membershipsLock.Unlock()
|
||||
}
|
||||
return memberships
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) GetMembership(roomID, userID string) string {
|
||||
store.membershipsLock.RLock()
|
||||
membership, ok := store.GetRoomMemberships(roomID)[userID]
|
||||
store.membershipsLock.RUnlock()
|
||||
if !ok {
|
||||
return "leave"
|
||||
}
|
||||
return membership
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) IsInRoom(roomID, userID string) bool {
|
||||
return store.GetMembership(roomID, userID) == "join"
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) SetMembership(roomID, userID, membership string) {
|
||||
store.membershipsLock.Lock()
|
||||
memberships, ok := store.Memberships[roomID]
|
||||
if !ok {
|
||||
store.Memberships[roomID] = map[string]string{
|
||||
userID: strings.ToLower(membership),
|
||||
}
|
||||
} else {
|
||||
memberships[userID] = strings.ToLower(membership)
|
||||
}
|
||||
store.membershipsLock.Unlock()
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) SetPowerLevels(roomID string, levels *gomatrix.PowerLevels) {
|
||||
store.powerLevelsLock.Lock()
|
||||
store.PowerLevels[roomID] = levels
|
||||
store.powerLevelsLock.Unlock()
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) GetPowerLevels(roomID string) (levels *gomatrix.PowerLevels) {
|
||||
store.powerLevelsLock.RLock()
|
||||
levels, _ = store.PowerLevels[roomID]
|
||||
store.powerLevelsLock.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) GetPowerLevel(roomID, userID string) int {
|
||||
return store.GetPowerLevels(roomID).GetUserLevel(userID)
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) GetPowerLevelRequirement(roomID string, eventType gomatrix.EventType, isState bool) int {
|
||||
levels := store.GetPowerLevels(roomID)
|
||||
switch eventType {
|
||||
case "kick":
|
||||
return levels.Kick()
|
||||
case "invite":
|
||||
return levels.Invite()
|
||||
case "redact":
|
||||
return levels.Redact()
|
||||
}
|
||||
return levels.GetEventLevel(eventType, isState)
|
||||
}
|
||||
|
||||
func (store *BasicStateStore) HasPowerLevel(roomID, userID string, eventType gomatrix.EventType, isState bool) bool {
|
||||
return store.GetPowerLevel(roomID, userID) >= store.GetPowerLevelRequirement(roomID, eventType, isState)
|
||||
}
|
Reference in New Issue
Block a user