much more cleanup
Signed-off-by: Sumner Evans <sumner@beeper.com>
This commit is contained in:
parent
e702662919
commit
47656ca0bb
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
.idea
|
.idea
|
||||||
|
logs/*
|
||||||
|
|
||||||
*.session
|
*.session
|
||||||
*.json
|
*.json
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.1.0
|
rev: v4.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
exclude_types: [markdown]
|
exclude_types: [markdown]
|
||||||
@ -9,7 +9,7 @@ repos:
|
|||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
|
|
||||||
- repo: https://github.com/tekwizely/pre-commit-golang
|
- repo: https://github.com/tekwizely/pre-commit-golang
|
||||||
rev: v1.0.0-beta.5
|
rev: v1.0.0-rc.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: go-imports-repo
|
- id: go-imports-repo
|
||||||
args:
|
args:
|
||||||
|
10
ROADMAP.md
10
ROADMAP.md
@ -69,10 +69,10 @@
|
|||||||
* [x] At startup
|
* [x] At startup
|
||||||
* [x] When receiving invite
|
* [x] When receiving invite
|
||||||
* [x] When receiving message
|
* [x] When receiving message
|
||||||
* [ ] Private chat creation by inviting Matrix puppet of WhatsApp user to new room
|
* [ ] Private chat creation by inviting Matrix puppet of GroupMe user to new room
|
||||||
* [ ] Option to use own Matrix account for messages sent from WhatsApp mobile/other web clients
|
* [ ] Option to use own Matrix account for messages sent from GroupMe mobile/other web clients
|
||||||
* [ ] Shared group chat portals
|
* [ ] Shared group chat portals
|
||||||
|
|
||||||
<sup>[1]</sup> Basic feature works. Improvements are TODO.
|
<sup>[1]</sup> Basic feature works. Improvements are TODO.
|
||||||
<sup>[2]</sup> May already work
|
<sup>[2]</sup> May already work
|
||||||
<sup>[3]</sup> May not be possible
|
<sup>[3]</sup> May not be possible
|
||||||
|
@ -24,13 +24,15 @@ import (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
*bridgeconfig.BaseConfig `yaml:",inline"`
|
*bridgeconfig.BaseConfig `yaml:",inline"`
|
||||||
|
|
||||||
SegmentKey string `yaml:"segment_key"`
|
SegmentKey string `yaml:"segment_key"`
|
||||||
|
SegmentUserID string `yaml:"segment_user_id"`
|
||||||
|
|
||||||
Metrics struct {
|
Metrics struct {
|
||||||
Enabled bool `yaml:"enabled"`
|
Enabled bool `yaml:"enabled"`
|
||||||
Listen string `yaml:"listen"`
|
Listen string `yaml:"listen"`
|
||||||
} `yaml:"metrics"`
|
} `yaml:"metrics"`
|
||||||
|
|
||||||
|
// TODO need these?
|
||||||
GroupMe struct {
|
GroupMe struct {
|
||||||
OSName string `yaml:"os_name"`
|
OSName string `yaml:"os_name"`
|
||||||
BrowserName string `yaml:"browser_name"`
|
BrowserName string `yaml:"browser_name"`
|
||||||
|
@ -98,7 +98,7 @@ func (br *GMBridge) newDoublePuppetClient(mxid id.UserID, accessToken string) (*
|
|||||||
homeserverURL, found := br.Config.Bridge.DoublePuppetServerMap[homeserver]
|
homeserverURL, found := br.Config.Bridge.DoublePuppetServerMap[homeserver]
|
||||||
if !found {
|
if !found {
|
||||||
if homeserver == br.AS.HomeserverDomain {
|
if homeserver == br.AS.HomeserverDomain {
|
||||||
homeserverURL = br.AS.HomeserverURL
|
homeserverURL = ""
|
||||||
} else if br.Config.Bridge.DoublePuppetAllowDiscovery {
|
} else if br.Config.Bridge.DoublePuppetAllowDiscovery {
|
||||||
resp, err := mautrix.DiscoverClientAPI(homeserver)
|
resp, err := mautrix.DiscoverClientAPI(homeserver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -110,14 +110,7 @@ func (br *GMBridge) newDoublePuppetClient(mxid id.UserID, accessToken string) (*
|
|||||||
return nil, fmt.Errorf("double puppeting from %s is not allowed", homeserver)
|
return nil, fmt.Errorf("double puppeting from %s is not allowed", homeserver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client, err := mautrix.NewClient(homeserverURL, mxid, accessToken)
|
return br.AS.NewExternalMautrixClient(mxid, accessToken, homeserverURL)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
client.Logger = br.AS.Log.Sub(mxid.String())
|
|
||||||
client.Client = br.AS.HTTPClient
|
|
||||||
client.DefaultHTTPRetries = br.AS.DefaultHTTPRetries
|
|
||||||
return client, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (puppet *Puppet) newCustomIntent() (*appservice.IntentAPI, error) {
|
func (puppet *Puppet) newCustomIntent() (*appservice.IntentAPI, error) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
|
// mautrix-groupme - A Matrix-GroupMe puppeting bridge.
|
||||||
// Copyright (C) 2022 Tulir Asokan
|
// Copyright (C) 2022 Tulir Asokan
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -9,7 +9,7 @@ homeserver:
|
|||||||
# Standard Matrix homeservers like Synapse, Dendrite and Conduit should just use "standard" here.
|
# Standard Matrix homeservers like Synapse, Dendrite and Conduit should just use "standard" here.
|
||||||
software: standard
|
software: standard
|
||||||
# The URL to push real-time bridge status to.
|
# The URL to push real-time bridge status to.
|
||||||
# If set, the bridge will make POST requests to this URL whenever a user's whatsapp connection state changes.
|
# If set, the bridge will make POST requests to this URL whenever a user's GroupMe connection state changes.
|
||||||
# The bridge will use the appservice as_token to authorize requests.
|
# The bridge will use the appservice as_token to authorize requests.
|
||||||
status_endpoint: null
|
status_endpoint: null
|
||||||
# Endpoint for reporting per-message status.
|
# Endpoint for reporting per-message status.
|
||||||
@ -29,10 +29,11 @@ appservice:
|
|||||||
|
|
||||||
# Database config.
|
# Database config.
|
||||||
database:
|
database:
|
||||||
# The database type. "sqlite3" and "postgres" are supported.
|
# The database type. "sqlite3-fk-wal" and "postgres" are supported.
|
||||||
type: postgres
|
type: postgres
|
||||||
# The database URI.
|
# The database URI.
|
||||||
# SQLite: File name is enough. https://github.com/mattn/go-sqlite3#connection-string
|
# SQLite: A raw file path is supported, but `file:<path>?_txlock=immediate` is recommended.
|
||||||
|
# https://github.com/mattn/go-sqlite3#connection-string
|
||||||
# Postgres: Connection string. For example, postgres://user:password@host/database?sslmode=disable
|
# Postgres: Connection string. For example, postgres://user:password@host/database?sslmode=disable
|
||||||
# To connect via Unix socket, use something like postgres:///dbname?host=/var/run/postgresql
|
# To connect via Unix socket, use something like postgres:///dbname?host=/var/run/postgresql
|
||||||
uri: postgres://user:password@host/database?sslmode=disable
|
uri: postgres://user:password@host/database?sslmode=disable
|
||||||
@ -53,7 +54,11 @@ appservice:
|
|||||||
# Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty
|
# Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty
|
||||||
# to leave display name/avatar as-is.
|
# to leave display name/avatar as-is.
|
||||||
displayname: GroupMe bridge bot
|
displayname: GroupMe bridge bot
|
||||||
avatar: mxc://malhotra.cc/YTWNAdhgJhYOPsKIxyfFZsrA
|
avatar: mxc://nevarro.space/eoAJPcSuTEvffoNycrXjvsmj
|
||||||
|
|
||||||
|
# Whether or not to receive ephemeral events via appservice transactions.
|
||||||
|
# Requires MSC2409 support (i.e. Synapse 1.22+).
|
||||||
|
ephemeral_events: true
|
||||||
|
|
||||||
# Authentication tokens for AS <-> HS communication. Autogenerated; do not modify.
|
# Authentication tokens for AS <-> HS communication. Autogenerated; do not modify.
|
||||||
as_token: "This value is generated when generating the registration"
|
as_token: "This value is generated when generating the registration"
|
||||||
@ -80,8 +85,8 @@ groupme:
|
|||||||
|
|
||||||
# Bridge config
|
# Bridge config
|
||||||
bridge:
|
bridge:
|
||||||
# Localpart template of MXIDs for WhatsApp users.
|
# Localpart template of MXIDs for GroupMe users.
|
||||||
# {{.}} is replaced with the phone number of the WhatsApp user.
|
# {{.}} is replaced with the phone number of the GroupMe user.
|
||||||
username_template: groupme_{{.}}
|
username_template: groupme_{{.}}
|
||||||
# Displayname template for GroupMe users.
|
# Displayname template for GroupMe users.
|
||||||
# {{call .UserID.String}} - the number GroupMe assigns to the user
|
# {{call .UserID.String}} - the number GroupMe assigns to the user
|
||||||
@ -91,7 +96,7 @@ bridge:
|
|||||||
# Should the bridge create a space for each logged-in user and add bridged rooms to it?
|
# Should the bridge create a space for each logged-in user and add bridged rooms to it?
|
||||||
# Users who logged in before turning this on should run `!wa sync space` to create and fill the space for the first time.
|
# Users who logged in before turning this on should run `!wa sync space` to create and fill the space for the first time.
|
||||||
personal_filtering_spaces: false
|
personal_filtering_spaces: false
|
||||||
# Should the bridge send a read receipt from the bridge bot when a message has been sent to WhatsApp?
|
# Should the bridge send a read receipt from the bridge bot when a message has been sent to GroupMe?
|
||||||
delivery_receipts: false
|
delivery_receipts: false
|
||||||
# Whether the bridge should send the message status as a custom com.beeper.message_send_status event.
|
# Whether the bridge should send the message status as a custom com.beeper.message_send_status event.
|
||||||
message_status_events: false
|
message_status_events: false
|
||||||
@ -158,7 +163,7 @@ bridge:
|
|||||||
# manually.
|
# manually.
|
||||||
login_shared_secret: null
|
login_shared_secret: null
|
||||||
|
|
||||||
# Whether or not to invite own WhatsApp user's Matrix puppet into private
|
# Whether or not to invite own GroupMe user's Matrix puppet into private
|
||||||
# chat portals when backfilling if needed.
|
# chat portals when backfilling if needed.
|
||||||
# This always uses the default puppet instead of custom puppets due to
|
# This always uses the default puppet instead of custom puppets due to
|
||||||
# rate limits and timestamp massaging.
|
# rate limits and timestamp massaging.
|
||||||
@ -172,11 +177,11 @@ bridge:
|
|||||||
# except if the config file is not writable.
|
# except if the config file is not writable.
|
||||||
resend_bridge_info: false
|
resend_bridge_info: false
|
||||||
|
|
||||||
# Whether or not thumbnails from WhatsApp should be sent.
|
# Whether or not thumbnails from GroupMe should be sent.
|
||||||
# They're disabled by default due to very low resolution.
|
# They're disabled by default due to very low resolution.
|
||||||
whatsapp_thumbnail: false
|
groupme_thumbnail: false
|
||||||
|
|
||||||
# Allow invite permission for user. User can invite any bots to room with whatsapp
|
# Allow invite permission for user. User can invite any bots to room with GroupMe
|
||||||
# users (private chat and groups)
|
# users (private chat and groups)
|
||||||
allow_user_invite: false
|
allow_user_invite: false
|
||||||
|
|
||||||
@ -222,7 +227,7 @@ bridge:
|
|||||||
# verified - Require manual per-device verification
|
# verified - Require manual per-device verification
|
||||||
# (currently only possible by modifying the `trust` column in the `crypto_device` database table).
|
# (currently only possible by modifying the `trust` column in the `crypto_device` database table).
|
||||||
verification_levels:
|
verification_levels:
|
||||||
# Minimum level for which the bridge should send keys to when bridging messages from WhatsApp to Matrix.
|
# Minimum level for which the bridge should send keys to when bridging messages from GroupMe to Matrix.
|
||||||
receive: unverified
|
receive: unverified
|
||||||
# Minimum level that the bridge should accept for incoming Matrix messages.
|
# Minimum level that the bridge should accept for incoming Matrix messages.
|
||||||
send: unverified
|
send: unverified
|
||||||
@ -256,7 +261,7 @@ bridge:
|
|||||||
# Permissions for using the bridge.
|
# Permissions for using the bridge.
|
||||||
# Permitted values:
|
# Permitted values:
|
||||||
# relaybot - Talk through the relaybot (if enabled), no access otherwise
|
# relaybot - Talk through the relaybot (if enabled), no access otherwise
|
||||||
# user - Access to use the bridge to chat with a WhatsApp account.
|
# user - Access to use the bridge to chat with a GroupMe account.
|
||||||
# admin - User level and some additional administration tools
|
# admin - User level and some additional administration tools
|
||||||
# Permitted keys:
|
# Permitted keys:
|
||||||
# * - All Matrix users
|
# * - All Matrix users
|
||||||
@ -267,18 +272,15 @@ bridge:
|
|||||||
"example.com": user
|
"example.com": user
|
||||||
"@admin:example.com": admin
|
"@admin:example.com": admin
|
||||||
|
|
||||||
# Logging config.
|
# Logging config. See https://github.com/tulir/zeroconfig for details.
|
||||||
logging:
|
logging:
|
||||||
# The directory for log files. Will be created if not found.
|
min_level: debug
|
||||||
directory: ./logs
|
writers:
|
||||||
# Available variables: .Date for the file date and .Index for different log files on the same day.
|
- type: stdout
|
||||||
file_name_format: "{{.Date}}-{{.Index}}.log"
|
format: pretty-colored
|
||||||
# Date format for file names in the Go time format: https://golang.org/pkg/time/#pkg-constants
|
- type: file
|
||||||
file_date_format: 2006-01-02
|
format: json
|
||||||
# Log file permissions.
|
filename: ./logs/mautrix-groupme.log
|
||||||
file_mode: 0600
|
max_size: 100
|
||||||
# Timestamp format for log entries in the Go time format.
|
max_backups: 10
|
||||||
timestamp_format: Jan _2, 2006 15:04:05
|
compress: true
|
||||||
# Minimum severity for log messages.
|
|
||||||
# Options: debug, info, warn, error, fatal
|
|
||||||
print_level: debug
|
|
||||||
|
138
formatting.go
138
formatting.go
@ -18,127 +18,33 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"maunium.net/go/mautrix/event"
|
||||||
"maunium.net/go/mautrix/format"
|
"maunium.net/go/mautrix/format"
|
||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/util/variationselector"
|
||||||
|
|
||||||
"github.com/beeper/groupme-lib"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var italicRegex = regexp.MustCompile("([\\s>~*]|^)_(.+?)_([^a-zA-Z\\d]|$)")
|
const formatterContextAllowedMentionsKey = "com.beeper.groupme.allowed_mentions"
|
||||||
var boldRegex = regexp.MustCompile("([\\s>_~]|^)\\*(.+?)\\*([^a-zA-Z\\d]|$)")
|
|
||||||
var strikethroughRegex = regexp.MustCompile("([\\s>_*]|^)~(.+?)~([^a-zA-Z\\d]|$)")
|
|
||||||
var codeBlockRegex = regexp.MustCompile("```(?:.|\n)+?```")
|
|
||||||
|
|
||||||
const mentionedGMIDsContextKey = "net.maunium.groupme.mentioned_gmids"
|
func (br *GMBridge) pillConverter(displayname, mxid, eventID string, ctx format.Context) string {
|
||||||
|
// GroupMe only supports user mentions.
|
||||||
type Formatter struct {
|
if len(mxid) == 0 || mxid[0] != '@' {
|
||||||
bridge *GMBridge
|
return displayname
|
||||||
|
|
||||||
matrixHTMLParser *format.HTMLParser
|
|
||||||
|
|
||||||
waReplString map[*regexp.Regexp]string
|
|
||||||
waReplFunc map[*regexp.Regexp]func(string) string
|
|
||||||
waReplFuncText map[*regexp.Regexp]func(string) string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFormatter(bridge *GMBridge) *Formatter {
|
|
||||||
formatter := &Formatter{
|
|
||||||
bridge: bridge,
|
|
||||||
matrixHTMLParser: &format.HTMLParser{
|
|
||||||
TabsToSpaces: 4,
|
|
||||||
Newline: "\n",
|
|
||||||
|
|
||||||
PillConverter: func(displayname, mxid, eventID string, ctx format.Context) string {
|
|
||||||
if mxid[0] == '@' {
|
|
||||||
puppet := bridge.GetPuppetByMXID(id.UserID(mxid))
|
|
||||||
if puppet != nil {
|
|
||||||
gmids, ok := ctx[mentionedGMIDsContextKey].([]groupme.ID)
|
|
||||||
if !ok {
|
|
||||||
ctx[mentionedGMIDsContextKey] = []groupme.ID{puppet.GMID}
|
|
||||||
} else {
|
|
||||||
ctx[mentionedGMIDsContextKey] = append(gmids, puppet.GMID)
|
|
||||||
}
|
|
||||||
return "@" + puppet.PhoneNumber()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mxid
|
|
||||||
},
|
|
||||||
BoldConverter: func(text string, _ format.Context) string {
|
|
||||||
return fmt.Sprintf("*%s*", text)
|
|
||||||
},
|
|
||||||
ItalicConverter: func(text string, _ format.Context) string {
|
|
||||||
return fmt.Sprintf("_%s_", text)
|
|
||||||
},
|
|
||||||
StrikethroughConverter: func(text string, _ format.Context) string {
|
|
||||||
return fmt.Sprintf("~%s~", text)
|
|
||||||
},
|
|
||||||
MonospaceConverter: func(text string, _ format.Context) string {
|
|
||||||
return fmt.Sprintf("```%s```", text)
|
|
||||||
},
|
|
||||||
MonospaceBlockConverter: func(text, language string, _ format.Context) string {
|
|
||||||
return fmt.Sprintf("```%s```", text)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
waReplString: map[*regexp.Regexp]string{
|
|
||||||
italicRegex: "$1<em>$2</em>$3",
|
|
||||||
boldRegex: "$1<strong>$2</strong>$3",
|
|
||||||
strikethroughRegex: "$1<del>$2</del>$3",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
formatter.waReplFunc = map[*regexp.Regexp]func(string) string{
|
|
||||||
codeBlockRegex: func(str string) string {
|
return fmt.Sprintf("@%s", displayname)
|
||||||
str = str[3 : len(str)-3]
|
}
|
||||||
if strings.ContainsRune(str, '\n') {
|
|
||||||
return fmt.Sprintf("<pre><code>%s</code></pre>", str)
|
var matrixHTMLParser = &format.HTMLParser{
|
||||||
}
|
TabsToSpaces: 4,
|
||||||
return fmt.Sprintf("<code>%s</code>", str)
|
Newline: "\n",
|
||||||
},
|
HorizontalLine: "\n---\n",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (portal *Portal) parseMatrixHTML(content *event.MessageEventContent) string {
|
||||||
|
if content.Format == event.FormatHTML && len(content.FormattedBody) > 0 {
|
||||||
|
return variationselector.FullyQualify(matrixHTMLParser.Parse(content.FormattedBody, format.NewContext()))
|
||||||
|
} else {
|
||||||
|
return variationselector.FullyQualify(content.Body)
|
||||||
}
|
}
|
||||||
formatter.waReplFuncText = map[*regexp.Regexp]func(string) string{}
|
|
||||||
return formatter
|
|
||||||
}
|
|
||||||
|
|
||||||
//func (formatter *Formatter) getMatrixInfoByJID(jid groupme.ID) (mxid id.UserID, displayname string) {
|
|
||||||
// if user := formatter.bridge.GetUserByJID(jid); user != nil {
|
|
||||||
// mxid = user.MXID
|
|
||||||
// displayname = string(user.MXID)
|
|
||||||
// } else if puppet := formatter.bridge.GetPuppetByJID(jid); puppet != nil {
|
|
||||||
// mxid = puppet.MXID
|
|
||||||
// displayname = puppet.Displayname
|
|
||||||
// }
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
|
|
||||||
//func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent, mentionedJIDs []groupme.ID) {
|
|
||||||
// output := html.EscapeString(content.Body)
|
|
||||||
// for regex, replacement := range formatter.waReplString {
|
|
||||||
// output = regex.ReplaceAllString(output, replacement)
|
|
||||||
// }
|
|
||||||
// for regex, replacer := range formatter.waReplFunc {
|
|
||||||
// output = regex.ReplaceAllStringFunc(output, replacer)
|
|
||||||
// }
|
|
||||||
// for _, jid := range mentionedJIDs {
|
|
||||||
// mxid, displayname := formatter.getMatrixInfoByJID(jid)
|
|
||||||
// number := "@" + strings.Replace(jid, whatsappExt.NewUserSuffix, "", 1)
|
|
||||||
// output = strings.Replace(output, number, fmt.Sprintf(`<a href="https://matrix.to/#/%s">%s</a>`, mxid, displayname), -1)
|
|
||||||
// content.Body = strings.Replace(content.Body, number, displayname, -1)
|
|
||||||
// }
|
|
||||||
// if output != content.Body {
|
|
||||||
// output = strings.Replace(output, "\n", "<br/>", -1)
|
|
||||||
// content.FormattedBody = output
|
|
||||||
// content.Format = event.FormatHTML
|
|
||||||
// for regex, replacer := range formatter.waReplFuncText {
|
|
||||||
// content.Body = regex.ReplaceAllStringFunc(content.Body, replacer)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
func (formatter *Formatter) ParseMatrix(html string) (string, []groupme.ID) {
|
|
||||||
ctx := make(format.Context)
|
|
||||||
result := formatter.matrixHTMLParser.Parse(html, ctx)
|
|
||||||
mentionedJIDs, _ := ctx[mentionedGMIDsContextKey].([]groupme.ID)
|
|
||||||
return result, mentionedJIDs
|
|
||||||
}
|
}
|
||||||
|
25
go.mod
25
go.mod
@ -3,42 +3,43 @@ module github.com/beeper/groupme
|
|||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Rhymen/go-whatsapp v0.1.1
|
|
||||||
github.com/beeper/groupme-lib v0.2.1-0.20221021205945-8f23e04eea71
|
github.com/beeper/groupme-lib v0.2.1-0.20221021205945-8f23e04eea71
|
||||||
github.com/gabriel-vasile/mimetype v1.1.2
|
github.com/gabriel-vasile/mimetype v1.1.2
|
||||||
github.com/gorilla/websocket v1.5.0
|
|
||||||
github.com/karmanyaahm/wray v0.0.0-20210303233435-756d58657c14
|
github.com/karmanyaahm/wray v0.0.0-20210303233435-756d58657c14
|
||||||
github.com/lib/pq v1.10.7
|
github.com/lib/pq v1.10.7
|
||||||
github.com/mattn/go-sqlite3 v1.14.15
|
github.com/mattn/go-sqlite3 v1.14.16
|
||||||
github.com/prometheus/client_golang v1.9.0
|
github.com/prometheus/client_golang v1.9.0
|
||||||
maunium.net/go/maulogger/v2 v2.3.2
|
maunium.net/go/maulogger/v2 v2.4.1
|
||||||
maunium.net/go/mautrix v0.12.3-0.20221020190005-d0c13d2f04a1
|
maunium.net/go/mautrix v0.15.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||||
|
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534 // indirect
|
||||||
github.com/golang/protobuf v1.4.3 // indirect
|
github.com/golang/protobuf v1.4.3 // indirect
|
||||||
github.com/google/uuid v1.2.0 // indirect
|
github.com/google/uuid v1.2.0 // indirect
|
||||||
github.com/gorilla/mux v1.8.0 // indirect
|
github.com/gorilla/mux v1.8.0 // indirect
|
||||||
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/prometheus/client_model v0.2.0 // indirect
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
github.com/prometheus/common v0.15.0 // indirect
|
github.com/prometheus/common v0.15.0 // indirect
|
||||||
github.com/prometheus/procfs v0.6.0 // indirect
|
github.com/prometheus/procfs v0.6.0 // indirect
|
||||||
github.com/rs/zerolog v1.28.0 // indirect
|
github.com/rs/zerolog v1.29.0 // indirect
|
||||||
github.com/tidwall/gjson v1.14.3 // indirect
|
github.com/tidwall/gjson v1.14.4 // indirect
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.0 // indirect
|
github.com/tidwall/pretty v1.2.0 // indirect
|
||||||
github.com/tidwall/sjson v1.2.5 // indirect
|
github.com/tidwall/sjson v1.2.5 // indirect
|
||||||
github.com/yuin/goldmark v1.5.2 // indirect
|
github.com/yuin/goldmark v1.5.4 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a // indirect
|
go.mau.fi/zeroconfig v0.1.2 // indirect
|
||||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b // indirect
|
golang.org/x/crypto v0.6.0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
|
golang.org/x/net v0.6.0 // indirect
|
||||||
|
golang.org/x/sys v0.5.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
google.golang.org/protobuf v1.25.0 // indirect
|
google.golang.org/protobuf v1.25.0 // indirect
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
maunium.net/go/mauflag v1.0.0 // indirect
|
maunium.net/go/mauflag v1.0.0 // indirect
|
||||||
)
|
)
|
||||||
|
61
go.sum
61
go.sum
@ -1,16 +1,8 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/go.mod h1:4a58ifQTEe2uwwsaqbh3i2un5/CBPg+At/qHpt18Tmk=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
|
|
||||||
github.com/Rhymen/go-whatsapp v0.1.1 h1:OK+bCugQcr2YjyYKeDzULqCtM50TPUFM6LvQtszKfcw=
|
|
||||||
github.com/Rhymen/go-whatsapp v0.1.1/go.mod h1:o7jjkvKnigfu432dMbQ/w4PH0Yp5u4Y6ysCNjUlcYCk=
|
|
||||||
github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:zgCiQtBtZ4P4gFWvwl9aashsdwOcbb/EHOGRmSzM8ME=
|
|
||||||
github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU=
|
|
||||||
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw=
|
|
||||||
github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM=
|
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||||
@ -48,6 +40,7 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z
|
|||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534 h1:rtAn27wIbmOGUs7RIbVgPEjb31ehTVniDwPGXyMxm5U=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
@ -89,7 +82,6 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er
|
|||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
@ -124,8 +116,6 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
|
|||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
|
||||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
@ -184,17 +174,15 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
|
|||||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
|
||||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
@ -241,7 +229,6 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0
|
|||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@ -279,8 +266,8 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
|
|||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
|
github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
|
||||||
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||||
@ -289,7 +276,6 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
|||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
@ -307,10 +293,10 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
|
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||||
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||||
@ -321,10 +307,12 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1
|
|||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/yuin/goldmark v1.5.2 h1:ALmeCk/px5FSm1MAcFBAsVKZjDuMVj8Tm7FFIlMJnqU=
|
github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU=
|
||||||
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.5.4/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||||
|
go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto=
|
||||||
|
go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70=
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
@ -337,14 +325,13 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|||||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg=
|
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
@ -370,8 +357,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU=
|
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -390,7 +377,6 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -405,8 +391,8 @@ golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@ -434,7 +420,6 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
|||||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||||
@ -469,6 +454,8 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS
|
|||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
@ -487,9 +474,9 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
||||||
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
||||||
maunium.net/go/maulogger/v2 v2.3.2 h1:1XmIYmMd3PoQfp9J+PaHhpt80zpfmMqaShzUTC7FwY0=
|
maunium.net/go/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8=
|
||||||
maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho=
|
||||||
maunium.net/go/mautrix v0.12.3-0.20221020190005-d0c13d2f04a1 h1:daraaP+GcSrFLgVckFpp+ciVrtQeG5s2w3Fi8AInaj8=
|
maunium.net/go/mautrix v0.15.0 h1:gkK9HXc1SSPwY7qOAqchzj2xxYqiOYeee8lr28A2g/o=
|
||||||
maunium.net/go/mautrix v0.12.3-0.20221020190005-d0c13d2f04a1/go.mod h1:bCw45Qx/m9qsz7eazmbe7Rzq5ZbTPzwRE1UgX2S9DXs=
|
maunium.net/go/mautrix v0.15.0/go.mod h1:1v8QVDd7q/eJ+eg4sgeOSEafBAFhkt4ab2i97M3IkNQ=
|
||||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||||
|
67
main.go
67
main.go
@ -20,6 +20,7 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/bridge"
|
"maunium.net/go/mautrix/bridge"
|
||||||
"maunium.net/go/mautrix/bridge/commands"
|
"maunium.net/go/mautrix/bridge/commands"
|
||||||
"maunium.net/go/mautrix/bridge/status"
|
"maunium.net/go/mautrix/bridge/status"
|
||||||
@ -48,7 +49,6 @@ type GMBridge struct {
|
|||||||
Config *config.Config
|
Config *config.Config
|
||||||
DB *database.Database
|
DB *database.Database
|
||||||
Provisioning *ProvisioningAPI
|
Provisioning *ProvisioningAPI
|
||||||
Formatter *Formatter
|
|
||||||
Metrics *MetricsHandler
|
Metrics *MetricsHandler
|
||||||
|
|
||||||
usersByMXID map[id.UserID]*User
|
usersByMXID map[id.UserID]*User
|
||||||
@ -70,10 +70,16 @@ func (br *GMBridge) Init() {
|
|||||||
br.CommandProcessor = commands.NewProcessor(&br.Bridge)
|
br.CommandProcessor = commands.NewProcessor(&br.Bridge)
|
||||||
br.RegisterCommands()
|
br.RegisterCommands()
|
||||||
|
|
||||||
|
matrixHTMLParser.PillConverter = br.pillConverter
|
||||||
|
|
||||||
Segment.log = br.Log.Sub("Segment")
|
Segment.log = br.Log.Sub("Segment")
|
||||||
Segment.key = br.Config.SegmentKey
|
Segment.key = br.Config.SegmentKey
|
||||||
|
Segment.userID = br.Config.SegmentUserID
|
||||||
if Segment.IsEnabled() {
|
if Segment.IsEnabled() {
|
||||||
Segment.log.Infoln("Segment metrics are enabled")
|
Segment.log.Infoln("Segment metrics are enabled")
|
||||||
|
if Segment.userID != "" {
|
||||||
|
Segment.log.Infoln("Overriding Segment user_id with %v", Segment.userID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
br.DB = database.New(br.Bridge.DB, br.Log.Sub("Database"))
|
br.DB = database.New(br.Bridge.DB, br.Log.Sub("Database"))
|
||||||
@ -83,47 +89,18 @@ func (br *GMBridge) Init() {
|
|||||||
br.Provisioning = &ProvisioningAPI{bridge: br}
|
br.Provisioning = &ProvisioningAPI{bridge: br}
|
||||||
}
|
}
|
||||||
|
|
||||||
br.Formatter = NewFormatter(br)
|
|
||||||
br.Metrics = NewMetricsHandler(br.Config.Metrics.Listen, br.Log.Sub("Metrics"), br.DB)
|
br.Metrics = NewMetricsHandler(br.Config.Metrics.Listen, br.Log.Sub("Metrics"), br.DB)
|
||||||
br.MatrixHandler.TrackEventDuration = br.Metrics.TrackMatrixEvent
|
br.MatrixHandler.TrackEventDuration = br.Metrics.TrackMatrixEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *GMBridge) Start() {
|
func (br *GMBridge) Start() {
|
||||||
if bridge.Provisioning != nil {
|
if br.Provisioning != nil {
|
||||||
bridge.Log.Debugln("Initializing provisioning API")
|
br.Log.Debugln("Initializing provisioning API")
|
||||||
bridge.Provisioning.Init()
|
br.Provisioning.Init()
|
||||||
}
|
}
|
||||||
go bridge.StartUsers()
|
go br.StartUsers()
|
||||||
if bridge.Config.Metrics.Enabled {
|
if br.Config.Metrics.Enabled {
|
||||||
go bridge.Metrics.Start()
|
go br.Metrics.Start()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bridge *GMBridge) UpdateBotProfile() {
|
|
||||||
bridge.Log.Debugln("Updating bot profile")
|
|
||||||
botConfig := bridge.Config.AppService.Bot
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var mxc id.ContentURI
|
|
||||||
if botConfig.Avatar == "remove" {
|
|
||||||
err = bridge.Bot.SetAvatarURL(mxc)
|
|
||||||
} else if len(botConfig.Avatar) > 0 {
|
|
||||||
mxc, err = id.ParseContentURI(botConfig.Avatar)
|
|
||||||
if err == nil {
|
|
||||||
err = bridge.Bot.SetAvatarURL(mxc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
bridge.Log.Warnln("Failed to update bot avatar:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if botConfig.Displayname == "remove" {
|
|
||||||
err = bridge.Bot.SetDisplayName("")
|
|
||||||
} else if len(botConfig.Avatar) > 0 {
|
|
||||||
err = bridge.Bot.SetDisplayName(botConfig.Displayname)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
bridge.Log.Warnln("Failed to update bot displayname:", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +108,7 @@ func (br *GMBridge) StartUsers() {
|
|||||||
br.Log.Debugln("Starting users")
|
br.Log.Debugln("Starting users")
|
||||||
foundAnySessions := false
|
foundAnySessions := false
|
||||||
for _, user := range br.GetAllUsers() {
|
for _, user := range br.GetAllUsers() {
|
||||||
if user.GMID.String() != "" {
|
if user.GMID.Valid() {
|
||||||
foundAnySessions = true
|
foundAnySessions = true
|
||||||
}
|
}
|
||||||
go user.Connect()
|
go user.Connect()
|
||||||
@ -174,6 +151,20 @@ func (br *GMBridge) GetConfigPtr() interface{} {
|
|||||||
return br.Config
|
return br.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unstableFeatureBatchSending = "org.matrix.msc2716"
|
||||||
|
|
||||||
|
func (br *GMBridge) CheckFeatures(versions *mautrix.RespVersions) (string, bool) {
|
||||||
|
if br.Config.Bridge.HistorySync.Backfill {
|
||||||
|
supported, known := versions.UnstableFeatures[unstableFeatureBatchSending]
|
||||||
|
if !known {
|
||||||
|
return "Backfilling is enabled in bridge config, but homeserver does not support MSC2716 batch sending", false
|
||||||
|
} else if !supported {
|
||||||
|
return "Backfilling is enabled in bridge config, but MSC2716 batch sending is not enabled on homeserver", false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", true
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
br := &GMBridge{
|
br := &GMBridge{
|
||||||
usersByMXID: make(map[id.UserID]*User),
|
usersByMXID: make(map[id.UserID]*User),
|
||||||
|
@ -97,7 +97,6 @@ func (portal *Portal) sendStatusEvent(evtID, lastRetry id.EventID, err error) {
|
|||||||
content.Reason, content.Status, _, _, content.Message = errorToStatusReason(err)
|
content.Reason, content.Status, _, _, content.Message = errorToStatusReason(err)
|
||||||
content.Error = err.Error()
|
content.Error = err.Error()
|
||||||
}
|
}
|
||||||
content.FillLegacyBooleans()
|
|
||||||
_, err = intent.SendMessageEvent(portal.MXID, event.BeeperMessageStatus, &content)
|
_, err = intent.SendMessageEvent(portal.MXID, event.BeeperMessageStatus, &content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Warnln("Failed to send message status event:", err)
|
portal.log.Warnln("Failed to send message status event:", err)
|
||||||
|
302
portal.go
302
portal.go
@ -37,7 +37,6 @@ import (
|
|||||||
"maunium.net/go/mautrix/bridge/bridgeconfig"
|
"maunium.net/go/mautrix/bridge/bridgeconfig"
|
||||||
"maunium.net/go/mautrix/crypto/attachment"
|
"maunium.net/go/mautrix/crypto/attachment"
|
||||||
|
|
||||||
"github.com/Rhymen/go-whatsapp"
|
|
||||||
"github.com/gabriel-vasile/mimetype"
|
"github.com/gabriel-vasile/mimetype"
|
||||||
|
|
||||||
"github.com/beeper/groupme-lib"
|
"github.com/beeper/groupme-lib"
|
||||||
@ -385,7 +384,7 @@ func (portal *Portal) SyncParticipants(metadata *groupme.Group) {
|
|||||||
if !shouldBePresent {
|
if !shouldBePresent {
|
||||||
_, err := portal.MainIntent().KickUser(portal.MXID, &mautrix.ReqKickUser{
|
_, err := portal.MainIntent().KickUser(portal.MXID, &mautrix.ReqKickUser{
|
||||||
UserID: member,
|
UserID: member,
|
||||||
Reason: "User had left this WhatsApp chat",
|
Reason: "User had left this GroupMe chat",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Warnfln("Failed to kick user %s who had left: %v", member, err)
|
portal.log.Warnfln("Failed to kick user %s who had left: %v", member, err)
|
||||||
@ -1158,7 +1157,6 @@ func (portal *Portal) HandleTextMessage(source *User, message *groupme.Message)
|
|||||||
sendText = sendText && text
|
sendText = sendText && text
|
||||||
}
|
}
|
||||||
|
|
||||||
// portal.bridge.Formatter.ParseWhatsApp(content, message.ContextInfo.MentionedJID)
|
|
||||||
// portal.SetReply(content, message.ContextInfo)
|
// portal.SetReply(content, message.ContextInfo)
|
||||||
//TODO: mentions
|
//TODO: mentions
|
||||||
content := &event.MessageEventContent{
|
content := &event.MessageEventContent{
|
||||||
@ -1262,108 +1260,6 @@ func (portal *Portal) HandleTextMessage(source *User, message *groupme.Message)
|
|||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func (portal *Portal) HandleLocationMessage(source *User, message whatsapp.LocationMessage) {
|
|
||||||
// intent := portal.startHandling(source, message.Info)
|
|
||||||
// if intent == nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// url := message.Url
|
|
||||||
// if len(url) == 0 {
|
|
||||||
// url = fmt.Sprintf("https://maps.google.com/?q=%.5f,%.5f", message.DegreesLatitude, message.DegreesLongitude)
|
|
||||||
// }
|
|
||||||
// name := message.Name
|
|
||||||
// if len(name) == 0 {
|
|
||||||
// latChar := 'N'
|
|
||||||
// if message.DegreesLatitude < 0 {
|
|
||||||
// latChar = 'S'
|
|
||||||
// }
|
|
||||||
// longChar := 'E'
|
|
||||||
// if message.DegreesLongitude < 0 {
|
|
||||||
// longChar = 'W'
|
|
||||||
// }
|
|
||||||
// name = fmt.Sprintf("%.4f° %c %.4f° %c", math.Abs(message.DegreesLatitude), latChar, math.Abs(message.DegreesLongitude), longChar)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// content := &event.MessageEventContent{
|
|
||||||
// MsgType: event.MsgLocation,
|
|
||||||
// Body: fmt.Sprintf("Location: %s\n%s\n%s", name, message.Address, url),
|
|
||||||
// Format: event.FormatHTML,
|
|
||||||
// FormattedBody: fmt.Sprintf("Location: <a href='%s'>%s</a><br>%s", url, name, message.Address),
|
|
||||||
// GeoURI: fmt.Sprintf("geo:%.5f,%.5f", message.DegreesLatitude, message.DegreesLongitude),
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if len(message.JpegThumbnail) > 0 {
|
|
||||||
// thumbnailMime := http.DetectContentType(message.JpegThumbnail)
|
|
||||||
// uploadedThumbnail, _ := intent.UploadBytes(message.JpegThumbnail, thumbnailMime)
|
|
||||||
// if uploadedThumbnail != nil {
|
|
||||||
// cfg, _, _ := image.DecodeConfig(bytes.NewReader(message.JpegThumbnail))
|
|
||||||
// content.Info = &event.FileInfo{
|
|
||||||
// ThumbnailInfo: &event.FileInfo{
|
|
||||||
// Size: len(message.JpegThumbnail),
|
|
||||||
// Width: cfg.Width,
|
|
||||||
// Height: cfg.Height,
|
|
||||||
// MimeType: thumbnailMime,
|
|
||||||
// },
|
|
||||||
// ThumbnailURL: uploadedThumbnail.ContentURI.CUString(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// portal.SetReply(content, message.ContextInfo)
|
|
||||||
//
|
|
||||||
// _, _ = intent.UserTyping(portal.MXID, false, 0)
|
|
||||||
// resp, err := portal.sendMessage(intent, event.EventMessage, content, int64(message.Info.Timestamp*1000))
|
|
||||||
// if err != nil {
|
|
||||||
// portal.log.Errorfln("Failed to handle message %s: %v", message.Info.Id, err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// portal.finishHandling(source, message.Info.Source, resp.EventID)
|
|
||||||
//}
|
|
||||||
|
|
||||||
//func (portal *Portal) HandleContactMessage(source *User, message whatsapp.ContactMessage) {
|
|
||||||
// intent := portal.startHandling(source, message.Info)
|
|
||||||
// if intent == nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fileName := fmt.Sprintf("%s.vcf", message.DisplayName)
|
|
||||||
// data := []byte(message.Vcard)
|
|
||||||
// mimeType := "text/vcard"
|
|
||||||
// data, uploadMimeType, file := portal.encryptFile(data, mimeType)
|
|
||||||
//
|
|
||||||
// uploadResp, err := intent.UploadBytesWithName(data, uploadMimeType, fileName)
|
|
||||||
// if err != nil {
|
|
||||||
// portal.log.Errorfln("Failed to upload vcard of %s: %v", message.DisplayName, err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// content := &event.MessageEventContent{
|
|
||||||
// Body: fileName,
|
|
||||||
// MsgType: event.MsgFile,
|
|
||||||
// File: file,
|
|
||||||
// Info: &event.FileInfo{
|
|
||||||
// MimeType: mimeType,
|
|
||||||
// Size: len(message.Vcard),
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// if content.File != nil {
|
|
||||||
// content.File.URL = uploadResp.ContentURI.CUString()
|
|
||||||
// } else {
|
|
||||||
// content.URL = uploadResp.ContentURI.CUString()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// portal.SetReply(content, message.ContextInfo)
|
|
||||||
//
|
|
||||||
// _, _ = intent.UserTyping(portal.MXID, false, 0)
|
|
||||||
// resp, err := portal.sendMessage(intent, event.EventMessage, content, int64(message.Info.Timestamp*1000))
|
|
||||||
// if err != nil {
|
|
||||||
// portal.log.Errorfln("Failed to handle message %s: %v", message.Info.Id, err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// portal.finishHandling(source, message.Info.Source, resp.EventID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (portal *Portal) sendMediaBridgeFailure(source *User, intent *appservice.IntentAPI, message groupme.Message, bridgeErr error) {
|
func (portal *Portal) sendMediaBridgeFailure(source *User, intent *appservice.IntentAPI, message groupme.Message, bridgeErr error) {
|
||||||
portal.log.Errorfln("Failed to bridge media for %s: %v", message.UserID.String(), bridgeErr)
|
portal.log.Errorfln("Failed to bridge media for %s: %v", message.UserID.String(), bridgeErr)
|
||||||
resp, err := portal.sendMessage(intent, event.EventMessage, &event.MessageEventContent{
|
resp, err := portal.sendMessage(intent, event.EventMessage, &event.MessageEventContent{
|
||||||
@ -1467,93 +1363,13 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) ([]*g
|
|||||||
case event.MsgText, event.MsgEmote, event.MsgNotice:
|
case event.MsgText, event.MsgEmote, event.MsgNotice:
|
||||||
text := content.Body
|
text := content.Body
|
||||||
if content.Format == event.FormatHTML {
|
if content.Format == event.FormatHTML {
|
||||||
text, _ = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
|
text = portal.parseMatrixHTML(content)
|
||||||
//TODO mentions
|
|
||||||
}
|
}
|
||||||
if content.MsgType == event.MsgEmote && !relaybotFormatted {
|
if content.MsgType == event.MsgEmote && !relaybotFormatted {
|
||||||
text = "/me " + text
|
text = "/me " + text
|
||||||
}
|
}
|
||||||
info.Text = text
|
info.Text = text
|
||||||
|
|
||||||
// if ctxInfo.StanzaId != nil || ctxInfo.MentionedJid != nil {
|
|
||||||
// info.Message.ExtendedTextMessage = &waProto.ExtendedTextMessage{
|
|
||||||
// Text: &text,
|
|
||||||
// ContextInfo: ctxInfo,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//else {
|
|
||||||
// info.Message.Conversation = &text
|
|
||||||
// }
|
|
||||||
// case event.MsgImage:
|
|
||||||
// media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaImage)
|
|
||||||
// if media == nil {
|
|
||||||
// return nil, sender
|
|
||||||
// }
|
|
||||||
// ctxInfo.MentionedJid = media.MentionedJIDs
|
|
||||||
// info.Message.ImageMessage = &waProto.ImageMessage{
|
|
||||||
// ContextInfo: ctxInfo,
|
|
||||||
// Caption: &media.Caption,
|
|
||||||
// JpegThumbnail: media.Thumbnail,
|
|
||||||
// Url: &media.URL,
|
|
||||||
// MediaKey: media.MediaKey,
|
|
||||||
// Mimetype: &content.GetInfo().MimeType,
|
|
||||||
// FileEncSha256: media.FileEncSHA256,
|
|
||||||
// FileSha256: media.FileSHA256,
|
|
||||||
// FileLength: &media.FileLength,
|
|
||||||
// }
|
|
||||||
// case event.MsgVideo:
|
|
||||||
// gifPlayback := content.GetInfo().MimeType == "image/gif"
|
|
||||||
// media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaVideo)
|
|
||||||
// if media == nil {
|
|
||||||
// return nil, sender
|
|
||||||
// }
|
|
||||||
// duration := uint32(content.GetInfo().Duration)
|
|
||||||
// ctxInfo.MentionedJid = media.MentionedJIDs
|
|
||||||
// info.Message.VideoMessage = &waProto.VideoMessage{
|
|
||||||
// ContextInfo: ctxInfo,
|
|
||||||
// Caption: &media.Caption,
|
|
||||||
// JpegThumbnail: media.Thumbnail,
|
|
||||||
// Url: &media.URL,
|
|
||||||
// MediaKey: media.MediaKey,
|
|
||||||
// Mimetype: &content.GetInfo().MimeType,
|
|
||||||
// GifPlayback: &gifPlayback,
|
|
||||||
// Seconds: &duration,
|
|
||||||
// FileEncSha256: media.FileEncSHA256,
|
|
||||||
// FileSha256: media.FileSHA256,
|
|
||||||
// FileLength: &media.FileLength,
|
|
||||||
// }
|
|
||||||
// case event.MsgAudio:
|
|
||||||
// media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaAudio)
|
|
||||||
// if media == nil {
|
|
||||||
// return nil, sender
|
|
||||||
// }
|
|
||||||
// duration := uint32(content.GetInfo().Duration)
|
|
||||||
// info.Message.AudioMessage = &waProto.AudioMessage{
|
|
||||||
// ContextInfo: ctxInfo,
|
|
||||||
// Url: &media.URL,
|
|
||||||
// MediaKey: media.MediaKey,
|
|
||||||
// Mimetype: &content.GetInfo().MimeType,
|
|
||||||
// Seconds: &duration,
|
|
||||||
// FileEncSha256: media.FileEncSHA256,
|
|
||||||
// FileSha256: media.FileSHA256,
|
|
||||||
// FileLength: &media.FileLength,
|
|
||||||
// }
|
|
||||||
// case event.MsgFile:
|
|
||||||
// media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaDocument)
|
|
||||||
// if media == nil {
|
|
||||||
// return nil, sender
|
|
||||||
// }
|
|
||||||
// info.Message.DocumentMessage = &waProto.DocumentMessage{
|
|
||||||
// ContextInfo: ctxInfo,
|
|
||||||
// Url: &media.URL,
|
|
||||||
// Title: &content.Body,
|
|
||||||
// FileName: &content.Body,
|
|
||||||
// MediaKey: media.MediaKey,
|
|
||||||
// Mimetype: &content.GetInfo().MimeType,
|
|
||||||
// FileEncSha256: media.FileEncSHA256,
|
|
||||||
// FileSha256: media.FileSHA256,
|
|
||||||
// FileLength: &media.FileLength,
|
|
||||||
// }
|
|
||||||
default:
|
default:
|
||||||
portal.log.Debugln("Unhandled Matrix event %s: unknown msgtype %s", evt.ID, content.MsgType)
|
portal.log.Debugln("Unhandled Matrix event %s: unknown msgtype %s", evt.ID, content.MsgType)
|
||||||
return nil, sender
|
return nil, sender
|
||||||
@ -1562,13 +1378,6 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) ([]*g
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) wasMessageSent(sender *User, id string) bool {
|
func (portal *Portal) wasMessageSent(sender *User, id string) bool {
|
||||||
// _, err := sender.Conn.LoadMessagesAfter(portal.Key.JID, id, true, 0)
|
|
||||||
// if err != nil {
|
|
||||||
// if err != whatsapp.ErrServerRespondedWith404 {
|
|
||||||
// portal.log.Warnfln("Failed to check if message was bridged without response: %v", err)
|
|
||||||
// }
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1620,98 +1429,9 @@ func (portal *Portal) sendRaw(sender *User, evt *event.Event, info *groupme.Mess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
// errChan := make(chan error, 1)
|
|
||||||
// go sender.Conn.SendRaw(info, errChan)
|
|
||||||
|
|
||||||
// var err error
|
|
||||||
// var errorEventID id.EventID
|
|
||||||
// select {
|
|
||||||
// case err = <-errChan:
|
|
||||||
// var statusResp whatsapp.StatusResponse
|
|
||||||
// if !isRetry && errors.As(err, &statusResp) && statusResp.Status == 599 {
|
|
||||||
// portal.log.Debugfln("599 status response sending %s to WhatsApp (%+v), retrying...", evt.ID, statusResp)
|
|
||||||
// errorEventID = portal.sendErrorMessage(fmt.Sprintf("%v. The bridge will retry in 5 seconds.", err))
|
|
||||||
// time.Sleep(5 * time.Second)
|
|
||||||
// portal.sendRaw(sender, evt, info, true)
|
|
||||||
// }
|
|
||||||
// case <-time.After(time.Duration(portal.bridge.Config.Bridge.ConnectionTimeout) * time.Second):
|
|
||||||
// if portal.bridge.Config.Bridge.FetchMessageOnTimeout && portal.wasMessageSent(sender, info.Key.GetId()) {
|
|
||||||
// portal.log.Debugln("Matrix event %s was bridged, but response didn't arrive within timeout")
|
|
||||||
// portal.sendDeliveryReceipt(evt.ID)
|
|
||||||
// } else {
|
|
||||||
// portal.log.Warnfln("Response when bridging Matrix event %s is taking long to arrive", evt.ID)
|
|
||||||
// errorEventID = portal.sendErrorMessage(timeout.Error())
|
|
||||||
// }
|
|
||||||
// err = <-errChan
|
|
||||||
// }
|
|
||||||
// if err != nil {
|
|
||||||
// portal.log.Errorfln("Error handling Matrix event %s: %v", evt.ID, err)
|
|
||||||
// var statusResp whatsapp.StatusResponse
|
|
||||||
// if errors.As(err, &statusResp) && statusResp.Status == 599 {
|
|
||||||
// portal.log.Debugfln("599 status response data: %+v", statusResp)
|
|
||||||
// }
|
|
||||||
// portal.sendErrorMessage(err.Error())
|
|
||||||
// } else {
|
|
||||||
// portal.log.Debugfln("Handled Matrix event %s", evt.ID)
|
|
||||||
// portal.sendDeliveryReceipt(evt.ID)
|
|
||||||
// }
|
|
||||||
// if errorEventID != "" {
|
|
||||||
// _, err = portal.MainIntent().RedactEvent(portal.MXID, errorEventID)
|
|
||||||
// if err != nil {
|
|
||||||
// portal.log.Warnfln("Failed to redact timeout warning message %s: %v", errorEventID, err)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) HandleMatrixRedaction(sender *User, evt *event.Event) {
|
func (portal *Portal) HandleMatrixRedaction(sender *User, evt *event.Event) {
|
||||||
// if portal.IsPrivateChat() && sender.JID != portal.Key.Receiver {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// msg := portal.bridge.DB.Message.GetByMXID(evt.Redacts)
|
|
||||||
// if msg == nil || msg.Sender != sender.JID {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ts := uint64(evt.Timestamp / 1000)
|
|
||||||
// status := waProto.WebMessageInfo_PENDING
|
|
||||||
// protoMsgType := waProto.ProtocolMessage_REVOKE
|
|
||||||
// fromMe := true
|
|
||||||
// info := &waProto.WebMessageInfo{
|
|
||||||
// Key: &waProto.MessageKey{
|
|
||||||
// FromMe: &fromMe,
|
|
||||||
// Id: makeMessageID(),
|
|
||||||
// RemoteJid: &portal.Key.JID,
|
|
||||||
// },
|
|
||||||
// MessageTimestamp: &ts,
|
|
||||||
// Message: &waProto.Message{
|
|
||||||
// ProtocolMessage: &waProto.ProtocolMessage{
|
|
||||||
// Type: &protoMsgType,
|
|
||||||
// Key: &waProto.MessageKey{
|
|
||||||
// FromMe: &fromMe,
|
|
||||||
// Id: &msg.JID,
|
|
||||||
// RemoteJid: &portal.Key.JID,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// Status: &status,
|
|
||||||
// }
|
|
||||||
// errChan := make(chan error, 1)
|
|
||||||
// go sender.Conn.SendRaw(info, errChan)
|
|
||||||
|
|
||||||
// var err error
|
|
||||||
// select {
|
|
||||||
// case err = <-errChan:
|
|
||||||
// case <-time.After(time.Duration(portal.bridge.Config.Bridge.ConnectionTimeout) * time.Second):
|
|
||||||
// portal.log.Warnfln("Response when bridging Matrix redaction %s is taking long to arrive", evt.ID)
|
|
||||||
// err = <-errChan
|
|
||||||
// }
|
|
||||||
// if err != nil {
|
|
||||||
// portal.log.Errorfln("Error handling Matrix redaction %s: %v", evt.ID, err)
|
|
||||||
// } else {
|
|
||||||
// portal.log.Debugln("Handled Matrix redaction %s of %s", evt.ID, evt.Redacts)
|
|
||||||
// portal.sendDeliveryReceipt(evt.ID)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) Delete() {
|
func (portal *Portal) Delete() {
|
||||||
@ -1811,25 +1531,7 @@ func (portal *Portal) HandleMatrixLeave(sender *User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) HandleMatrixKick(sender *User, evt *event.Event) {
|
func (portal *Portal) HandleMatrixKick(sender *User, evt *event.Event) {
|
||||||
// puppet := portal.bridge.GetPuppetByMXID(id.UserID(evt.GetStateKey()))
|
|
||||||
// if puppet != nil {
|
|
||||||
// resp, err := sender.Conn.RemoveMember(portal.Key.JID, []string{puppet.JID})
|
|
||||||
// if err != nil {
|
|
||||||
// portal.log.Errorfln("Failed to kick %s from group as %s: %v", puppet.JID, sender.MXID, err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// portal.log.Infoln("Kick %s response: %s", puppet.JID, <-resp)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) HandleMatrixInvite(sender *User, evt *event.Event) {
|
func (portal *Portal) HandleMatrixInvite(sender *User, evt *event.Event) {
|
||||||
// puppet := portal.bridge.GetPuppetByMXID(id.UserID(evt.GetStateKey()))
|
|
||||||
// if puppet != nil {
|
|
||||||
// resp, err := sender.Conn.AddMember(portal.Key.JID, []string{puppet.JID})
|
|
||||||
// if err != nil {
|
|
||||||
// portal.log.Errorfln("Failed to add %s to group as %s: %v", puppet.JID, sender.MXID, err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// portal.log.Infoln("Add %s response: %s", puppet.JID, <-resp)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
330
provisioning.go
330
provisioning.go
@ -21,7 +21,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
log "maunium.net/go/maulogger/v2"
|
log "maunium.net/go/maulogger/v2"
|
||||||
|
|
||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/id"
|
||||||
@ -37,13 +36,6 @@ func (prov *ProvisioningAPI) Init() {
|
|||||||
prov.log.Debugln("Enabling provisioning API at", prov.bridge.Config.Bridge.Provisioning.Prefix)
|
prov.log.Debugln("Enabling provisioning API at", prov.bridge.Config.Bridge.Provisioning.Prefix)
|
||||||
r := prov.bridge.AS.Router.PathPrefix(prov.bridge.Config.Bridge.Provisioning.Prefix).Subrouter()
|
r := prov.bridge.AS.Router.PathPrefix(prov.bridge.Config.Bridge.Provisioning.Prefix).Subrouter()
|
||||||
r.Use(prov.AuthMiddleware)
|
r.Use(prov.AuthMiddleware)
|
||||||
r.HandleFunc("/ping", prov.Ping).Methods(http.MethodGet)
|
|
||||||
r.HandleFunc("/login", prov.Login)
|
|
||||||
r.HandleFunc("/logout", prov.Logout).Methods(http.MethodPost)
|
|
||||||
r.HandleFunc("/delete_session", prov.DeleteSession).Methods(http.MethodPost)
|
|
||||||
r.HandleFunc("/delete_connection", prov.DeleteConnection).Methods(http.MethodPost)
|
|
||||||
r.HandleFunc("/disconnect", prov.Disconnect).Methods(http.MethodPost)
|
|
||||||
r.HandleFunc("/reconnect", prov.Reconnect).Methods(http.MethodPost)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (prov *ProvisioningAPI) AuthMiddleware(h http.Handler) http.Handler {
|
func (prov *ProvisioningAPI) AuthMiddleware(h http.Handler) http.Handler {
|
||||||
@ -53,8 +45,8 @@ func (prov *ProvisioningAPI) AuthMiddleware(h http.Handler) http.Handler {
|
|||||||
authParts := strings.Split(r.Header.Get("Sec-WebSocket-Protocol"), ",")
|
authParts := strings.Split(r.Header.Get("Sec-WebSocket-Protocol"), ",")
|
||||||
for _, part := range authParts {
|
for _, part := range authParts {
|
||||||
part = strings.TrimSpace(part)
|
part = strings.TrimSpace(part)
|
||||||
if strings.HasPrefix(part, "net.maunium.whatsapp.auth-") {
|
if strings.HasPrefix(part, "com.beeper.groupme.auth-") {
|
||||||
auth = part[len("net.maunium.whatsapp.auth-"):]
|
auth = part[len("com.beeper.groupme.auth-"):]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,326 +77,8 @@ type Response struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (prov *ProvisioningAPI) DeleteSession(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// user := r.Context().Value("user").(*User)
|
|
||||||
// if user.Session == nil && user.Conn == nil {
|
|
||||||
// jsonResponse(w, http.StatusNotFound, Error{
|
|
||||||
// Error: "Nothing to purge: no session information stored and no active connection.",
|
|
||||||
// ErrCode: "no session",
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// user.SetSession(nil)
|
|
||||||
// if user.Conn != nil {
|
|
||||||
// _, _ = user.Conn.Disconnect()
|
|
||||||
// user.Conn.RemoveHandlers()
|
|
||||||
// user.Conn = nil
|
|
||||||
// user.bridge.Metrics.TrackConnectionState(user.JID, false)
|
|
||||||
// }
|
|
||||||
// jsonResponse(w, http.StatusOK, Response{true, "Session information purged"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (prov *ProvisioningAPI) DeleteConnection(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// user := r.Context().Value("user").(*User)
|
|
||||||
// if user.Conn == nil {
|
|
||||||
// jsonResponse(w, http.StatusNotFound, Error{
|
|
||||||
// Error: "You don't have a WhatsApp connection.",
|
|
||||||
// ErrCode: "not connected",
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// sess, err := user.Conn.Disconnect()
|
|
||||||
// if err == nil && len(sess.Wid) > 0 {
|
|
||||||
// user.SetSession(&sess)
|
|
||||||
// }
|
|
||||||
// user.Conn.RemoveHandlers()
|
|
||||||
// user.Conn = nil
|
|
||||||
// user.bridge.Metrics.TrackConnectionState(user.JID, false)
|
|
||||||
// jsonResponse(w, http.StatusOK, Response{true, "Disconnected from WhatsApp and connection deleted"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (prov *ProvisioningAPI) Disconnect(w http.ResponseWriter, r *http.Request) {
|
|
||||||
user := r.Context().Value("user").(*User)
|
|
||||||
if user.Conn == nil {
|
|
||||||
jsonResponse(w, http.StatusNotFound, Error{
|
|
||||||
Error: "You don't have a WhatsApp connection.",
|
|
||||||
ErrCode: "no connection",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//sess, err :=
|
|
||||||
//user.Conn.Stop(context.TODO())
|
|
||||||
// if err == whatsapp.ErrNotConnected {
|
|
||||||
// jsonResponse(w, http.StatusNotFound, Error{
|
|
||||||
// Error: "You were not connected",
|
|
||||||
// ErrCode: "not connected",
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// } else if err != nil {
|
|
||||||
// user.log.Warnln("Error while disconnecting:", err)
|
|
||||||
// jsonResponse(w, http.StatusInternalServerError, Error{
|
|
||||||
// Error: fmt.Sprintf("Unknown error while disconnecting: %v", err),
|
|
||||||
// ErrCode: err.Error(),
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// } else if len(sess.Wid) > 0 {
|
|
||||||
// user.SetSession(&sess)
|
|
||||||
// }
|
|
||||||
user.bridge.Metrics.TrackConnectionState(user.GMID, false)
|
|
||||||
jsonResponse(w, http.StatusOK, Response{true, "Disconnected from WhatsApp"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (prov *ProvisioningAPI) Reconnect(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// user := r.Context().Value("user").(*User)
|
|
||||||
// if user.Conn == nil {
|
|
||||||
// if user.Session == nil {
|
|
||||||
// jsonResponse(w, http.StatusForbidden, Error{
|
|
||||||
// Error: "No existing connection and no session. Please log in first.",
|
|
||||||
// ErrCode: "no session",
|
|
||||||
// })
|
|
||||||
// } else {
|
|
||||||
// user.Connect(false)
|
|
||||||
// jsonResponse(w, http.StatusOK, Response{true, "Created connection to WhatsApp."})
|
|
||||||
// }
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// wasConnected := true
|
|
||||||
// sess, err := user.Conn.Disconnect()
|
|
||||||
// if err == whatsapp.ErrNotConnected {
|
|
||||||
// wasConnected = false
|
|
||||||
// } else if err != nil {
|
|
||||||
// user.log.Warnln("Error while disconnecting:", err)
|
|
||||||
// } else if len(sess.Wid) > 0 {
|
|
||||||
// user.SetSession(&sess)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// err = user.Conn.Restore()
|
|
||||||
// if err == whatsapp.ErrInvalidSession {
|
|
||||||
// if user.Session != nil {
|
|
||||||
// user.log.Debugln("Got invalid session error when reconnecting, but user has session. Retrying using RestoreWithSession()...")
|
|
||||||
// var sess whatsapp.Session
|
|
||||||
// sess, err = user.Conn.RestoreWithSession(*user.Session)
|
|
||||||
// if err == nil {
|
|
||||||
// user.SetSession(&sess)
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// jsonResponse(w, http.StatusForbidden, Error{
|
|
||||||
// Error: "You're not logged in",
|
|
||||||
// ErrCode: "not logged in",
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// } else if err == whatsapp.ErrLoginInProgress {
|
|
||||||
// jsonResponse(w, http.StatusConflict, Error{
|
|
||||||
// Error: "A login or reconnection is already in progress.",
|
|
||||||
// ErrCode: "login in progress",
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// } else if err == whatsapp.ErrAlreadyLoggedIn {
|
|
||||||
// jsonResponse(w, http.StatusConflict, Error{
|
|
||||||
// Error: "You were already connected.",
|
|
||||||
// ErrCode: err.Error(),
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// if err != nil {
|
|
||||||
// user.log.Warnln("Error while reconnecting:", err)
|
|
||||||
// if err.Error() == "restore session connection timed out" {
|
|
||||||
// jsonResponse(w, http.StatusForbidden, Error{
|
|
||||||
// Error: "Reconnection timed out. Is WhatsApp on your phone reachable?",
|
|
||||||
// ErrCode: err.Error(),
|
|
||||||
// })
|
|
||||||
// } else {
|
|
||||||
// jsonResponse(w, http.StatusForbidden, Error{
|
|
||||||
// Error: fmt.Sprintf("Unknown error while reconnecting: %v", err),
|
|
||||||
// ErrCode: err.Error(),
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// user.log.Debugln("Disconnecting due to failed session restore in reconnect command...")
|
|
||||||
// sess, err := user.Conn.Disconnect()
|
|
||||||
// if err != nil {
|
|
||||||
// user.log.Errorln("Failed to disconnect after failed session restore in reconnect command:", err)
|
|
||||||
// } else if len(sess.Wid) > 0 {
|
|
||||||
// user.SetSession(&sess)
|
|
||||||
// }
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// user.ConnectionErrors = 0
|
|
||||||
// user.PostLogin()
|
|
||||||
|
|
||||||
// var msg string
|
|
||||||
// if wasConnected {
|
|
||||||
// msg = "Reconnected successfully."
|
|
||||||
// } else {
|
|
||||||
// msg = "Connected successfully."
|
|
||||||
// }
|
|
||||||
|
|
||||||
// jsonResponse(w, http.StatusOK, Response{true, msg})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (prov *ProvisioningAPI) Ping(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// user := r.Context().Value("user").(*User)
|
|
||||||
// wa := map[string]interface{}{
|
|
||||||
// "has_session": user.Client != nil,
|
|
||||||
// "management_room": user.ManagementRoom,
|
|
||||||
// "jid": user.JID,
|
|
||||||
// "conn": nil,
|
|
||||||
// "ping": nil,
|
|
||||||
// }
|
|
||||||
// if user.Conn != nil {
|
|
||||||
// wa["conn"] = map[string]interface{}{
|
|
||||||
// "is_connected": user.IsConnected(),
|
|
||||||
// "is_logged_in": user.IsLoggedIn(),
|
|
||||||
// "is_login_in_progress": user.IsLoginInProgress(),
|
|
||||||
// }
|
|
||||||
// err := user.Conn.AdminTest()
|
|
||||||
// wa["ping"] = map[string]interface{}{
|
|
||||||
// "ok": err == nil,
|
|
||||||
// "err": err,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// resp := map[string]interface{}{
|
|
||||||
// "mxid": user.MXID,
|
|
||||||
// "admin": user.Admin,
|
|
||||||
// "whitelisted": user.Whitelisted,
|
|
||||||
// "relaybot_whitelisted": user.RelaybotWhitelisted,
|
|
||||||
// "whatsapp": wa,
|
|
||||||
// }
|
|
||||||
// jsonResponse(w, http.StatusOK, resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func jsonResponse(w http.ResponseWriter, status int, response interface{}) {
|
func jsonResponse(w http.ResponseWriter, status int, response interface{}) {
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Add("Content-Type", "application/json")
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
_ = json.NewEncoder(w).Encode(response)
|
_ = json.NewEncoder(w).Encode(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (prov *ProvisioningAPI) Logout(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// user := r.Context().Value("user").(*User)
|
|
||||||
// if user.Session == nil {
|
|
||||||
// jsonResponse(w, http.StatusNotFound, Error{
|
|
||||||
// Error: "You're not logged in",
|
|
||||||
// ErrCode: "not logged in",
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// force := strings.ToLower(r.URL.Query().Get("force")) != "false"
|
|
||||||
|
|
||||||
// if user.Conn == nil {
|
|
||||||
// if !force {
|
|
||||||
// jsonResponse(w, http.StatusNotFound, Error{
|
|
||||||
// Error: "You're not connected",
|
|
||||||
// ErrCode: "not connected",
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// err := user.Conn.Logout()
|
|
||||||
// if err != nil {
|
|
||||||
// user.log.Warnln("Error while logging out:", err)
|
|
||||||
// if !force {
|
|
||||||
// jsonResponse(w, http.StatusInternalServerError, Error{
|
|
||||||
// Error: fmt.Sprintf("Unknown error while logging out: %v", err),
|
|
||||||
// ErrCode: err.Error(),
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// _, err = user.Conn.Disconnect()
|
|
||||||
// if err != nil {
|
|
||||||
// user.log.Warnln("Error while disconnecting after logout:", err)
|
|
||||||
// }
|
|
||||||
// user.Conn.RemoveHandlers()
|
|
||||||
// user.Conn = nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// user.bridge.Metrics.TrackConnectionState(user.JID, false)
|
|
||||||
// user.removeFromJIDMap()
|
|
||||||
|
|
||||||
// // TODO this causes a foreign key violation, which should be fixed
|
|
||||||
// //ce.User.JID = ""
|
|
||||||
// user.SetSession(nil)
|
|
||||||
// jsonResponse(w, http.StatusOK, Response{true, "Logged out successfully."})
|
|
||||||
}
|
|
||||||
|
|
||||||
var upgrader = websocket.Upgrader{
|
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
Subprotocols: []string{"net.maunium.whatsapp.login"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (prov *ProvisioningAPI) Login(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// userID := r.URL.Query().Get("user_id")
|
|
||||||
// user := prov.bridge.GetUserByMXID(id.UserID(userID))
|
|
||||||
|
|
||||||
// if len(ce.Args) < 1 {
|
|
||||||
// // Return error that the token needs to be longer than 0 length
|
|
||||||
// // ce.Reply(`Get your access token from https://dev.groupme.com/ which should be the first argument to login`)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// user.Token = ce.Args[0]
|
|
||||||
|
|
||||||
// user.addToJIDMap()
|
|
||||||
// // ce.Reply("Successfully logged in, synchronizing chats...")
|
|
||||||
// user.PostLogin()
|
|
||||||
// user.Connect()
|
|
||||||
|
|
||||||
// c, err := upgrader.Upgrade(w, r, nil)
|
|
||||||
// if err != nil {
|
|
||||||
// prov.log.Errorfln("Failed to upgrade connection to websocket:", err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// defer c.Close()
|
|
||||||
|
|
||||||
// if !user.Connect(true) {
|
|
||||||
// user.log.Debugln("Connect() returned false, assuming error was logged elsewhere and canceling login.")
|
|
||||||
// _ = c.WriteJSON(Error{
|
|
||||||
// Error: "Failed to connect to WhatsApp",
|
|
||||||
// ErrCode: "connection error",
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// qrChan := make(chan string, 3)
|
|
||||||
// go func() {
|
|
||||||
// for code := range qrChan {
|
|
||||||
// if code == "stop" {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// _ = c.WriteJSON(map[string]interface{}{
|
|
||||||
// "code": code,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }()
|
|
||||||
// session, err := user.Conn.LoginWithRetry(qrChan, user.bridge.Config.Bridge.LoginQRRegenCount)
|
|
||||||
// qrChan <- "stop"
|
|
||||||
// if err != nil {
|
|
||||||
// var msg string
|
|
||||||
// if err == whatsapp.ErrAlreadyLoggedIn {
|
|
||||||
// msg = "You're already logged in"
|
|
||||||
// } else if err == whatsapp.ErrLoginInProgress {
|
|
||||||
// msg = "You have a login in progress already."
|
|
||||||
// } else if err == whatsapp.ErrLoginTimedOut {
|
|
||||||
// msg = "QR code scan timed out. Please try again."
|
|
||||||
// } else {
|
|
||||||
// user.log.Warnln("Failed to log in:", err)
|
|
||||||
// msg = fmt.Sprintf("Unknown error while logging in: %v", err)
|
|
||||||
// }
|
|
||||||
// _ = c.WriteJSON(Error{
|
|
||||||
// Error: msg,
|
|
||||||
// ErrCode: err.Error(),
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// user.ConnectionErrors = 0
|
|
||||||
// user.JID = strings.Replace(user.Conn.Info.Wid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, 1)
|
|
||||||
// user.addToJIDMap()
|
|
||||||
// user.SetSession(&session)
|
|
||||||
// _ = c.WriteJSON(map[string]interface{}{
|
|
||||||
// "success": true,
|
|
||||||
// "jid": user.JID,
|
|
||||||
// })
|
|
||||||
// user.PostLogin()
|
|
||||||
}
|
|
||||||
|
@ -30,6 +30,7 @@ const SegmentURL = "https://api.segment.io/v1/track"
|
|||||||
|
|
||||||
type SegmentClient struct {
|
type SegmentClient struct {
|
||||||
key string
|
key string
|
||||||
|
userID string
|
||||||
log log.Logger
|
log log.Logger
|
||||||
client http.Client
|
client http.Client
|
||||||
}
|
}
|
||||||
@ -38,8 +39,14 @@ var Segment SegmentClient
|
|||||||
|
|
||||||
func (sc *SegmentClient) trackSync(userID id.UserID, event string, properties map[string]interface{}) error {
|
func (sc *SegmentClient) trackSync(userID id.UserID, event string, properties map[string]interface{}) error {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
var segmentUserID string
|
||||||
|
if Segment.userID != "" {
|
||||||
|
segmentUserID = Segment.userID
|
||||||
|
} else {
|
||||||
|
segmentUserID = userID.String()
|
||||||
|
}
|
||||||
err := json.NewEncoder(&buf).Encode(map[string]interface{}{
|
err := json.NewEncoder(&buf).Encode(map[string]interface{}{
|
||||||
"userId": userID,
|
"userId": segmentUserID,
|
||||||
"event": event,
|
"event": event,
|
||||||
"properties": properties,
|
"properties": properties,
|
||||||
})
|
})
|
||||||
|
409
user.go
409
user.go
@ -26,9 +26,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "maunium.net/go/maulogger/v2"
|
log "maunium.net/go/maulogger/v2"
|
||||||
|
|
||||||
"github.com/Rhymen/go-whatsapp"
|
|
||||||
|
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/appservice"
|
"maunium.net/go/mautrix/appservice"
|
||||||
"maunium.net/go/mautrix/bridge"
|
"maunium.net/go/mautrix/bridge"
|
||||||
@ -206,7 +203,7 @@ func (br *GMBridge) NewUser(dbUser *database.User) *User {
|
|||||||
user.PermissionLevel = user.bridge.Config.Bridge.Permissions.Get(user.MXID)
|
user.PermissionLevel = user.bridge.Config.Bridge.Permissions.Get(user.MXID)
|
||||||
user.Whitelisted = user.PermissionLevel >= bridgeconfig.PermissionLevelUser
|
user.Whitelisted = user.PermissionLevel >= bridgeconfig.PermissionLevelUser
|
||||||
user.Admin = user.PermissionLevel >= bridgeconfig.PermissionLevelAdmin
|
user.Admin = user.PermissionLevel >= bridgeconfig.PermissionLevelAdmin
|
||||||
user.BridgeState = br.NewBridgeStateQueue(user, user.log)
|
user.BridgeState = br.NewBridgeStateQueue(user)
|
||||||
go user.handleMessageLoop()
|
go user.handleMessageLoop()
|
||||||
go user.runMessageRingBuffer()
|
go user.runMessageRingBuffer()
|
||||||
return user
|
return user
|
||||||
@ -332,14 +329,6 @@ func (user *User) SetManagementRoom(roomID id.RoomID) {
|
|||||||
user.Update()
|
user.Update()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) SetSession(session *whatsapp.Session) {
|
|
||||||
// user.Session = session
|
|
||||||
// if session == nil {
|
|
||||||
// user.LastConnection = 0
|
|
||||||
// }
|
|
||||||
// user.Update()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user *User) Connect() bool {
|
func (user *User) Connect() bool {
|
||||||
if user.Conn != nil {
|
if user.Conn != nil {
|
||||||
return true
|
return true
|
||||||
@ -347,14 +336,14 @@ func (user *User) Connect() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
user.log.Debugln("Connecting to GroupMe")
|
user.log.Debugfln("Connecting to GroupMe")
|
||||||
timeout := time.Duration(user.bridge.Config.GroupMe.ConnectionTimeout)
|
timeout := time.Duration(user.bridge.Config.GroupMe.ConnectionTimeout)
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
timeout = 20
|
timeout = 20
|
||||||
}
|
}
|
||||||
conn := groupme.NewPushSubscription(context.Background())
|
conn := groupme.NewPushSubscription(context.Background())
|
||||||
user.Conn = &conn
|
user.Conn = &conn
|
||||||
user.Conn.StartListening(context.TODO(), groupmeext.NewFayeClient(user.log))
|
user.Conn.StartListening(context.Background(), groupmeext.NewFayeClient(user.log))
|
||||||
user.Conn.AddFullHandler(user)
|
user.Conn.AddFullHandler(user)
|
||||||
|
|
||||||
//TODO: typing notification?
|
//TODO: typing notification?
|
||||||
@ -737,112 +726,7 @@ func (user *User) UpdateDirectChats(chats map[id.UserID][]id.RoomID) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) HandleContactList(contacts []whatsapp.Contact) {
|
|
||||||
contactMap := make(map[string]whatsapp.Contact)
|
|
||||||
for _, contact := range contacts {
|
|
||||||
contactMap[contact.Jid] = contact
|
|
||||||
}
|
|
||||||
go user.syncPuppets(contactMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user *User) syncPuppets(contacts map[string]whatsapp.Contact) {
|
|
||||||
// if contacts == nil {
|
|
||||||
// contacts = user.Conn.Store.Contacts
|
|
||||||
// }
|
|
||||||
// user.log.Infoln("Syncing puppet info from contacts")
|
|
||||||
// for jid, contact := range contacts {
|
|
||||||
// if strings.HasSuffix(jid, whatsappExt.NewUserSuffix) {
|
|
||||||
// puppet := user.bridge.GetPuppetByJID(contact.Jid)
|
|
||||||
// puppet.Sync(user, contact)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// user.log.Infoln("Finished syncing puppet info from contacts")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user *User) updateLastConnectionIfNecessary() {
|
|
||||||
// if user.LastConnection+60 < uint64(time.Now().Unix()) {
|
|
||||||
// user.UpdateLastConnection()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user *User) HandleError(err error) {
|
func (user *User) HandleError(err error) {
|
||||||
if !errors.Is(err, whatsapp.ErrInvalidWsData) {
|
|
||||||
user.log.Errorfln("WhatsApp error: %v", err)
|
|
||||||
}
|
|
||||||
if closed, ok := err.(*whatsapp.ErrConnectionClosed); ok {
|
|
||||||
user.bridge.Metrics.TrackDisconnection(user.MXID)
|
|
||||||
if closed.Code == 1000 && user.cleanDisconnection {
|
|
||||||
user.bridge.Metrics.TrackConnectionState(user.GMID, false)
|
|
||||||
user.cleanDisconnection = false
|
|
||||||
user.log.Infoln("Clean disconnection by server")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go user.tryReconnect(fmt.Sprintf("Your WhatsApp connection was closed with websocket status code %d", closed.Code))
|
|
||||||
} else if failed, ok := err.(*whatsapp.ErrConnectionFailed); ok {
|
|
||||||
user.bridge.Metrics.TrackDisconnection(user.MXID)
|
|
||||||
user.ConnectionErrors++
|
|
||||||
go user.tryReconnect(fmt.Sprintf("Your WhatsApp connection failed: %v", failed.Err))
|
|
||||||
}
|
|
||||||
// Otherwise unknown error, probably mostly harmless
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user *User) tryReconnect(msg string) {
|
|
||||||
// user.bridge.Metrics.TrackConnectionState(user.JID, false)
|
|
||||||
// if user.ConnectionErrors > user.bridge.Config.Bridge.MaxConnectionAttempts {
|
|
||||||
// user.sendMarkdownBridgeAlert("%s. Use the `reconnect` command to reconnect.", msg)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// if user.bridge.Config.Bridge.ReportConnectionRetry {
|
|
||||||
// user.sendBridgeNotice("%s. Reconnecting...", msg)
|
|
||||||
// // Don't want the same error to be repeated
|
|
||||||
// msg = ""
|
|
||||||
// }
|
|
||||||
// var tries uint
|
|
||||||
// var exponentialBackoff bool
|
|
||||||
// baseDelay := time.Duration(user.bridge.Config.Bridge.ConnectionRetryDelay)
|
|
||||||
// if baseDelay < 0 {
|
|
||||||
// exponentialBackoff = true
|
|
||||||
// baseDelay = -baseDelay + 1
|
|
||||||
// }
|
|
||||||
// delay := baseDelay
|
|
||||||
// for user.ConnectionErrors <= user.bridge.Config.Bridge.MaxConnectionAttempts {
|
|
||||||
// err := user.Conn.Restore()
|
|
||||||
// if err == nil {
|
|
||||||
// user.ConnectionErrors = 0
|
|
||||||
// if user.bridge.Config.Bridge.ReportConnectionRetry {
|
|
||||||
// user.sendBridgeNotice("Reconnected successfully")
|
|
||||||
// }
|
|
||||||
// user.PostLogin()
|
|
||||||
// return
|
|
||||||
// } else if err.Error() == "init responded with 400" {
|
|
||||||
// user.log.Infoln("Got init 400 error when trying to reconnect, resetting connection...")
|
|
||||||
// sess, err := user.Conn.Disconnect()
|
|
||||||
// if err != nil {
|
|
||||||
// user.log.Debugln("Error while disconnecting for connection reset:", err)
|
|
||||||
// }
|
|
||||||
// if len(sess.Wid) > 0 {
|
|
||||||
// user.SetSession(&sess)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// user.log.Errorln("Error while trying to reconnect after disconnection:", err)
|
|
||||||
// tries++
|
|
||||||
// user.ConnectionErrors++
|
|
||||||
// if user.ConnectionErrors <= user.bridge.Config.Bridge.MaxConnectionAttempts {
|
|
||||||
// if exponentialBackoff {
|
|
||||||
// delay = (1 << tries) + baseDelay
|
|
||||||
// }
|
|
||||||
// if user.bridge.Config.Bridge.ReportConnectionRetry {
|
|
||||||
// user.sendBridgeNotice("Reconnection attempt failed: %v. Retrying in %d seconds...", err, delay)
|
|
||||||
// }
|
|
||||||
// time.Sleep(delay * time.Second)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if user.bridge.Config.Bridge.ReportConnectionRetry {
|
|
||||||
// user.sendMarkdownBridgeAlert("%d reconnection attempts failed. Use the `reconnect` command to try to reconnect manually.", tries)
|
|
||||||
// } else {
|
|
||||||
// user.sendMarkdownBridgeAlert("\u26a0 %s. Additionally, %d reconnection attempts failed. Use the `reconnect` command to try to reconnect.", msg, tries)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) ShouldCallSynchronously() bool {
|
func (user *User) ShouldCallSynchronously() bool {
|
||||||
@ -850,7 +734,7 @@ func (user *User) ShouldCallSynchronously() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) HandleJSONParseError(err error) {
|
func (user *User) HandleJSONParseError(err error) {
|
||||||
user.log.Errorln("WhatsApp JSON parse error:", err)
|
user.log.Errorln("GroupMe JSON parse error:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) PortalKey(gmid groupme.ID) database.PortalKey {
|
func (user *User) PortalKey(gmid groupme.ID) database.PortalKey {
|
||||||
@ -893,34 +777,6 @@ func (user *User) handleMessageLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (user *User) HandleNewContact(contact whatsapp.Contact) {
|
|
||||||
// user.log.Debugfln("Contact message: %+v", contact)
|
|
||||||
// go func() {
|
|
||||||
// if strings.HasSuffix(contact.Jid, whatsappExt.OldUserSuffix) {
|
|
||||||
// contact.Jid = strings.Replace(contact.Jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1)
|
|
||||||
// }
|
|
||||||
// puppet := user.bridge.GetPuppetByJID(contact.Jid)
|
|
||||||
// puppet.UpdateName(user, contact)
|
|
||||||
// }()
|
|
||||||
//}
|
|
||||||
|
|
||||||
//func (user *User) HandleBatteryMessage(battery whatsapp.BatteryMessage) {
|
|
||||||
// user.log.Debugfln("Battery message: %+v", battery)
|
|
||||||
// var notice string
|
|
||||||
// if !battery.Plugged && battery.Percentage < 15 && user.batteryWarningsSent < 1 {
|
|
||||||
// notice = fmt.Sprintf("Phone battery low (%d %% remaining)", battery.Percentage)
|
|
||||||
// user.batteryWarningsSent = 1
|
|
||||||
// } else if !battery.Plugged && battery.Percentage < 5 && user.batteryWarningsSent < 2 {
|
|
||||||
// notice = fmt.Sprintf("Phone battery very low (%d %% remaining)", battery.Percentage)
|
|
||||||
// user.batteryWarningsSent = 2
|
|
||||||
// } else if battery.Percentage > 15 || battery.Plugged {
|
|
||||||
// user.batteryWarningsSent = 0
|
|
||||||
// }
|
|
||||||
// if notice != "" {
|
|
||||||
// go user.sendBridgeNotice("%s", notice)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
func (user *User) HandleTextMessage(message groupme.Message) {
|
func (user *User) HandleTextMessage(message groupme.Message) {
|
||||||
id := database.ParsePortalKey(message.GroupID.String())
|
id := database.ParsePortalKey(message.GroupID.String())
|
||||||
|
|
||||||
@ -983,270 +839,15 @@ func (user *User) HandleNewNickname(groupID, userID groupme.ID, name string) {
|
|||||||
|
|
||||||
func (user *User) HandleNewAvatarInGroup(groupID, userID groupme.ID, url string) {
|
func (user *User) HandleNewAvatarInGroup(groupID, userID groupme.ID, url string) {
|
||||||
puppet := user.bridge.GetPuppetByGMID(userID)
|
puppet := user.bridge.GetPuppetByGMID(userID)
|
||||||
if puppet != nil {
|
puppet.UpdateAvatar(user, false)
|
||||||
puppet.UpdateAvatar(user, false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) HandleMembers(_ groupme.ID, _ []groupme.Member, _ bool) {
|
func (user *User) HandleMembers(_ groupme.ID, _ []groupme.Member, _ bool) {
|
||||||
user.HandleChatList()
|
user.HandleChatList()
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (user *User) HandleImageMessage(message whatsapp.ImageMessage) {
|
|
||||||
// user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleStickerMessage(message whatsapp.StickerMessage) {
|
|
||||||
// user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleVideoMessage(message whatsapp.VideoMessage) {
|
|
||||||
// user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleAudioMessage(message whatsapp.AudioMessage) {
|
|
||||||
// user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleDocumentMessage(message whatsapp.DocumentMessage) {
|
|
||||||
// user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleContactMessage(message whatsapp.ContactMessage) {
|
|
||||||
// user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleLocationMessage(message whatsapp.LocationMessage) {
|
|
||||||
// user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleMessageRevoke(message whatsappExt.MessageRevocation) {
|
|
||||||
// user.messageInput <- PortalMessage{message.RemoteJid, user, message, 0}
|
|
||||||
//}
|
|
||||||
|
|
||||||
type FakeMessage struct {
|
type FakeMessage struct {
|
||||||
Text string
|
Text string
|
||||||
ID string
|
ID string
|
||||||
Alert bool
|
Alert bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (user *User) HandleCallInfo(info whatsappExt.CallInfo) {
|
|
||||||
// if info.Data != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// data := FakeMessage{
|
|
||||||
// ID: info.ID,
|
|
||||||
// }
|
|
||||||
// switch info.Type {
|
|
||||||
// case whatsappExt.CallOffer:
|
|
||||||
// if !user.bridge.Config.Bridge.CallNotices.Start {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// data.Text = "Incoming call"
|
|
||||||
// data.Alert = true
|
|
||||||
// case whatsappExt.CallOfferVideo:
|
|
||||||
// if !user.bridge.Config.Bridge.CallNotices.Start {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// data.Text = "Incoming video call"
|
|
||||||
// data.Alert = true
|
|
||||||
// case whatsappExt.CallTerminate:
|
|
||||||
// if !user.bridge.Config.Bridge.CallNotices.End {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// data.Text = "Call ended"
|
|
||||||
// data.ID += "E"
|
|
||||||
// default:
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// portal := user.GetPortalByJID(info.From)
|
|
||||||
// if portal != nil {
|
|
||||||
// portal.messages <- PortalMessage{info.From, user, data, 0}
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//func (user *User) HandlePresence(info whatsappExt.Presence) {
|
|
||||||
// puppet := user.bridge.GetPuppetByJID(info.SenderJID)
|
|
||||||
// switch info.Status {
|
|
||||||
// case whatsapp.PresenceUnavailable:
|
|
||||||
// _ = puppet.DefaultIntent().SetPresence("offline")
|
|
||||||
// case whatsapp.PresenceAvailable:
|
|
||||||
// if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() {
|
|
||||||
// portal := user.bridge.GetPortalByMXID(puppet.typingIn)
|
|
||||||
// _, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0)
|
|
||||||
// puppet.typingIn = ""
|
|
||||||
// puppet.typingAt = 0
|
|
||||||
// } else {
|
|
||||||
// _ = puppet.DefaultIntent().SetPresence("online")
|
|
||||||
// }
|
|
||||||
// case whatsapp.PresenceComposing:
|
|
||||||
// portal := user.GetPortalByJID(info.JID)
|
|
||||||
// if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() {
|
|
||||||
// if puppet.typingIn == portal.MXID {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// _, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0)
|
|
||||||
// }
|
|
||||||
// puppet.typingIn = portal.MXID
|
|
||||||
// puppet.typingAt = time.Now().Unix()
|
|
||||||
// _, _ = puppet.IntentFor(portal).UserTyping(portal.MXID, true, 15*1000)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleMsgInfo(info whatsappExt.MsgInfo) {
|
|
||||||
// if (info.Command == whatsappExt.MsgInfoCommandAck || info.Command == whatsappExt.MsgInfoCommandAcks) && info.Acknowledgement == whatsappExt.AckMessageRead {
|
|
||||||
// portal := user.GetPortalByJID(info.ToJID)
|
|
||||||
// if len(portal.MXID) == 0 {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// go func() {
|
|
||||||
// intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal)
|
|
||||||
// for _, msgID := range info.IDs {
|
|
||||||
// msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID)
|
|
||||||
// if msg == nil {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// err := intent.MarkRead(portal.MXID, msg.MXID)
|
|
||||||
// if err != nil {
|
|
||||||
// user.log.Warnln("Failed to mark message %s as read by %s: %v", msg.MXID, info.SenderJID, err)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }()
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//func (user *User) HandleReceivedMessage(received whatsapp.ReceivedMessage) {
|
|
||||||
// if received.Type == "read" {
|
|
||||||
// user.markSelfRead(received.Jid, received.Index)
|
|
||||||
// } else {
|
|
||||||
// user.log.Debugfln("Unknown received message type: %+v", received)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleReadMessage(read whatsapp.ReadMessage) {
|
|
||||||
// user.log.Debugfln("Received chat read message: %+v", read)
|
|
||||||
// user.markSelfRead(read.Jid, "")
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) markSelfRead(jid, messageID string) {
|
|
||||||
// if strings.HasSuffix(jid, whatsappExt.OldUserSuffix) {
|
|
||||||
// jid = strings.Replace(jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1)
|
|
||||||
// }
|
|
||||||
// puppet := user.bridge.GetPuppetByJID(user.JID)
|
|
||||||
// if puppet == nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// intent := puppet.CustomIntent()
|
|
||||||
// if intent == nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// portal := user.GetPortalByJID(jid)
|
|
||||||
// if portal == nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// var message *database.Message
|
|
||||||
// if messageID == "" {
|
|
||||||
// message = user.bridge.DB.Message.GetLastInChat(portal.Key)
|
|
||||||
// if message == nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// user.log.Debugfln("User read chat %s/%s in WhatsApp mobile (last known event: %s/%s)", portal.Key.JID, portal.MXID, message.JID, message.MXID)
|
|
||||||
// } else {
|
|
||||||
// message = user.bridge.DB.Message.GetByJID(portal.Key, messageID)
|
|
||||||
// if message == nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// user.log.Debugfln("User read message %s/%s in %s/%s in WhatsApp mobile", message.JID, message.MXID, portal.Key.JID, portal.MXID)
|
|
||||||
// }
|
|
||||||
// err := intent.MarkRead(portal.MXID, message.MXID)
|
|
||||||
// if err != nil {
|
|
||||||
// user.log.Warnfln("Failed to bridge own read receipt in %s: %v", jid, err)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleCommand(cmd whatsappExt.Command) {
|
|
||||||
// switch cmd.Type {
|
|
||||||
// case whatsappExt.CommandPicture:
|
|
||||||
// if strings.HasSuffix(cmd.JID, whatsappExt.NewUserSuffix) {
|
|
||||||
// puppet := user.bridge.GetPuppetByJID(cmd.JID)
|
|
||||||
// go puppet.UpdateAvatar(user, cmd.ProfilePicInfo)
|
|
||||||
// } else {
|
|
||||||
// portal := user.GetPortalByJID(cmd.JID)
|
|
||||||
// go portal.UpdateAvatar(user, cmd.ProfilePicInfo, true)
|
|
||||||
// }
|
|
||||||
// case whatsappExt.CommandDisconnect:
|
|
||||||
// user.cleanDisconnection = true
|
|
||||||
// if cmd.Kind == "replaced" {
|
|
||||||
// go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server because you opened another WhatsApp Web client.\n\n" +
|
|
||||||
// "Use the `reconnect` command to disconnect the other client and resume bridging.")
|
|
||||||
// } else {
|
|
||||||
// user.log.Warnln("Unknown kind of disconnect:", string(cmd.Raw))
|
|
||||||
// go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server (reason code: %s).\n\n"+
|
|
||||||
// "Use the `reconnect` command to reconnect.", cmd.Kind)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleChatUpdate(cmd whatsappExt.ChatUpdate) {
|
|
||||||
// if cmd.Command != whatsappExt.ChatUpdateCommandAction {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// portal := user.GetPortalByJID(cmd.JID)
|
|
||||||
// if len(portal.MXID) == 0 {
|
|
||||||
// if cmd.Data.Action == whatsappExt.ChatActionIntroduce || cmd.Data.Action == whatsappExt.ChatActionCreate {
|
|
||||||
// go func() {
|
|
||||||
// err := portal.CreateMatrixRoom(user)
|
|
||||||
// if err != nil {
|
|
||||||
// user.log.Errorln("Failed to create portal room after receiving join event:", err)
|
|
||||||
// }
|
|
||||||
// }()
|
|
||||||
// }
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// switch cmd.Data.Action {
|
|
||||||
// case whatsappExt.ChatActionNameChange:
|
|
||||||
// go portal.UpdateName(cmd.Data.NameChange.Name, cmd.Data.SenderJID, true)
|
|
||||||
// case whatsappExt.ChatActionAddTopic:
|
|
||||||
// go portal.UpdateTopic(cmd.Data.AddTopic.Topic, cmd.Data.SenderJID, true)
|
|
||||||
// case whatsappExt.ChatActionRemoveTopic:
|
|
||||||
// go portal.UpdateTopic("", cmd.Data.SenderJID, true)
|
|
||||||
// case whatsappExt.ChatActionPromote:
|
|
||||||
// go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, true)
|
|
||||||
// case whatsappExt.ChatActionDemote:
|
|
||||||
// go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, false)
|
|
||||||
// case whatsappExt.ChatActionAnnounce:
|
|
||||||
// go portal.RestrictMessageSending(cmd.Data.Announce)
|
|
||||||
// case whatsappExt.ChatActionRestrict:
|
|
||||||
// go portal.RestrictMetadataChanges(cmd.Data.Restrict)
|
|
||||||
// case whatsappExt.ChatActionRemove:
|
|
||||||
// go portal.HandleWhatsAppKick(cmd.Data.SenderJID, cmd.Data.UserChange.JIDs)
|
|
||||||
// case whatsappExt.ChatActionAdd:
|
|
||||||
// go portal.HandleWhatsAppInvite(cmd.Data.SenderJID, cmd.Data.UserChange.JIDs)
|
|
||||||
// //case whatsappExt.ChatActionIntroduce:
|
|
||||||
// // if cmd.Data.SenderJID != "unknown" {
|
|
||||||
// // go portal.Sync(user, whatsapp.Contact{Jid: portal.Key.JID})
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//func (user *User) HandleJsonMessage(message string) {
|
|
||||||
// var msg json.RawMessage
|
|
||||||
// err := json.Unmarshal([]byte(message), &msg)
|
|
||||||
// if err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// user.log.Debugln("JSON message:", message)
|
|
||||||
// user.updateLastConnectionIfNecessary()
|
|
||||||
//}
|
|
||||||
|
|
||||||
//func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) {
|
|
||||||
// user.updateLastConnectionIfNecessary()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (user *User) HandleUnknownBinaryNode(node *waBinary.Node) {
|
|
||||||
// user.log.Debugfln("Unknown binary message: %+v", node)
|
|
||||||
//}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user