forked from lug/matterbridge
		
	Compare commits
	
		
			62 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					051e6e76e9 | ||
| 
						 | 
					1e55dd47f2 | ||
| 
						 | 
					700b95546b | ||
| 
						 | 
					2fa96ec0ed | ||
| 
						 | 
					81e6f75aa4 | ||
| 
						 | 
					888c8b9a84 | ||
| 
						 | 
					e775a8a22e | ||
| 
						 | 
					99fbd9cae6 | ||
| 
						 | 
					67adad3e08 | ||
| 
						 | 
					2fca3c7563 | ||
| 
						 | 
					c3573f1a46 | ||
| 
						 | 
					ee932a9f8e | ||
| 
						 | 
					ce18c948e6 | ||
| 
						 | 
					7bc93c5506 | ||
| 
						 | 
					d7cad3b404 | ||
| 
						 | 
					7740a362c9 | ||
| 
						 | 
					281ef53e7d | ||
| 
						 | 
					f044b948e2 | ||
| 
						 | 
					32474a5f4d | ||
| 
						 | 
					26596acf80 | ||
| 
						 | 
					e63870a631 | ||
| 
						 | 
					ce782ff6fb | ||
| 
						 | 
					c6716e030c | ||
| 
						 | 
					4ab72acec6 | ||
| 
						 | 
					30aae8e257 | ||
| 
						 | 
					d7b7ff7bb4 | ||
| 
						 | 
					6fe0cff342 | ||
| 
						 | 
					5f75f9886d | ||
| 
						 | 
					5d9604cd15 | ||
| 
						 | 
					cc36ebf1c9 | ||
| 
						 | 
					e6adecfd81 | ||
| 
						 | 
					5c8f224e3b | ||
| 
						 | 
					952221d3b9 | ||
| 
						 | 
					496d5b4ec7 | ||
| 
						 | 
					2623a412c4 | ||
| 
						 | 
					d64eed49bc | ||
| 
						 | 
					fffa29c2f3 | ||
| 
						 | 
					4da1444ffc | ||
| 
						 | 
					21c4e56d16 | ||
| 
						 | 
					5356b3856a | ||
| 
						 | 
					320c996a21 | ||
| 
						 | 
					69c74be7bb | ||
| 
						 | 
					aefa70891c | ||
| 
						 | 
					1b9877fda4 | ||
| 
						 | 
					0205a67309 | ||
| 
						 | 
					e3cafeaf92 | ||
| 
						 | 
					e7b193788a | ||
| 
						 | 
					17da95b094 | ||
| 
						 | 
					c5e49eec96 | ||
| 
						 | 
					24bc0f127b | ||
| 
						 | 
					f0f801402d | ||
| 
						 | 
					663850a2b8 | ||
| 
						 | 
					c51753cab1 | ||
| 
						 | 
					b3be2e208c | ||
| 
						 | 
					c30e90ff3f | ||
| 
						 | 
					e4c0ca0f48 | ||
| 
						 | 
					9c203327c0 | ||
| 
						 | 
					ccb5b1d075 | ||
| 
						 | 
					0dbbd0414c | ||
| 
						 | 
					e7b3ebf98a | ||
| 
						 | 
					5bc18fb780 | ||
| 
						 | 
					df30366072 | 
							
								
								
									
										22
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,22 +0,0 @@
 | 
			
		||||
# Docs: <https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/customizing-dependency-updates>
 | 
			
		||||
 | 
			
		||||
version: 2
 | 
			
		||||
 | 
			
		||||
updates:
 | 
			
		||||
  - package-ecosystem: gomod
 | 
			
		||||
    directory: /
 | 
			
		||||
    schedule: {interval: weekly}
 | 
			
		||||
    reviewers: [42wim]
 | 
			
		||||
    assignees: [42wim]
 | 
			
		||||
 | 
			
		||||
  - package-ecosystem: github-actions
 | 
			
		||||
    directory: /
 | 
			
		||||
    schedule: {interval: weekly}
 | 
			
		||||
    reviewers: [42wim]
 | 
			
		||||
    assignees: [42wim]
 | 
			
		||||
 | 
			
		||||
  - package-ecosystem: docker
 | 
			
		||||
    directory: /
 | 
			
		||||
    schedule: {interval: weekly}
 | 
			
		||||
    reviewers: [42wim]
 | 
			
		||||
    assignees: [42wim]
 | 
			
		||||
							
								
								
									
										14
									
								
								Dockerfile_whatsappmulti
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Dockerfile_whatsappmulti
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
FROM alpine AS builder
 | 
			
		||||
 | 
			
		||||
COPY . /go/src/matterbridge
 | 
			
		||||
RUN apk --no-cache add go git \
 | 
			
		||||
        && cd /go/src/matterbridge \
 | 
			
		||||
        && CGO_ENABLED=0 go build -tags whatsappmulti -mod vendor -ldflags "-X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
 | 
			
		||||
 | 
			
		||||
FROM alpine
 | 
			
		||||
RUN apk --no-cache add ca-certificates mailcap
 | 
			
		||||
COPY --from=builder /bin/matterbridge /bin/matterbridge
 | 
			
		||||
RUN mkdir /etc/matterbridge \
 | 
			
		||||
  && touch /etc/matterbridge/matterbridge.toml \
 | 
			
		||||
  && ln -sf /matterbridge.toml /etc/matterbridge/matterbridge.toml
 | 
			
		||||
ENTRYPOINT ["/bin/matterbridge", "-conf", "/etc/matterbridge/matterbridge.toml"]
 | 
			
		||||
							
								
								
									
										76
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								README.md
									
									
									
									
									
								
							@@ -58,21 +58,22 @@ And more...
 | 
			
		||||
    - [Binaries](#binaries)
 | 
			
		||||
    - [Packages](#packages)
 | 
			
		||||
  - [Building](#building)
 | 
			
		||||
  - [Building with whatsapp (beta) multidevice support](#building-with-whatsapp-beta-multidevice-support)
 | 
			
		||||
  - [Configuration](#configuration)
 | 
			
		||||
    - [Basic configuration](#basic-configuration)
 | 
			
		||||
    - [Settings](#settings)
 | 
			
		||||
    - [Advanced configuration](#advanced-configuration)
 | 
			
		||||
    - [Examples](#examples)
 | 
			
		||||
      - [Bridge mattermost (off-topic) - irc (#testing)](#bridge-mattermost-off-topic---irc-testing)
 | 
			
		||||
      - [Bridge slack (#general) - discord (general)](#bridge-slack-general---discord-general)
 | 
			
		||||
  - [Running](#running)
 | 
			
		||||
    - [Docker](#docker)
 | 
			
		||||
    - [Systemd](#systemd)
 | 
			
		||||
  - [Changelog](#changelog)
 | 
			
		||||
  - [FAQ](#faq)
 | 
			
		||||
  - [Related projects](#related-projects)
 | 
			
		||||
  - [Articles / Tutorials](#articles--tutorials)
 | 
			
		||||
  - [Thanks](#thanks)
 | 
			
		||||
      - [Examples](#examples)
 | 
			
		||||
        - [Bridge mattermost (off-topic) - irc (#testing)](#bridge-mattermost-off-topic---irc-testing)
 | 
			
		||||
        - [Bridge slack (#general) - discord (general)](#bridge-slack-general---discord-general)
 | 
			
		||||
    - [Running](#running)
 | 
			
		||||
      - [Docker](#docker)
 | 
			
		||||
      - [Systemd](#systemd)
 | 
			
		||||
    - [Changelog](#changelog)
 | 
			
		||||
    - [FAQ](#faq)
 | 
			
		||||
    - [Related projects](#related-projects)
 | 
			
		||||
    - [Articles / Tutorials](#articles--tutorials)
 | 
			
		||||
    - [Thanks](#thanks)
 | 
			
		||||
 | 
			
		||||
## Features
 | 
			
		||||
 | 
			
		||||
@@ -89,6 +90,7 @@ And more...
 | 
			
		||||
 | 
			
		||||
- [Discord](https://discordapp.com)
 | 
			
		||||
- [Gitter](https://gitter.im)
 | 
			
		||||
- [Harmony](https://harmonyapp.io)
 | 
			
		||||
- [IRC](http://www.mirc.com/servers.html)
 | 
			
		||||
- [Keybase](https://keybase.io)
 | 
			
		||||
- [Matrix](https://matrix.org)
 | 
			
		||||
@@ -105,6 +107,8 @@ And more...
 | 
			
		||||
- [Twitch](https://twitch.tv)
 | 
			
		||||
- [VK](https://vk.com/)
 | 
			
		||||
- [WhatsApp](https://www.whatsapp.com/)
 | 
			
		||||
  - Whatsapp legacy is natively supported
 | 
			
		||||
  - Whatsapp multidevice beta is natively supported but you need to build yourself, see [here](#building-with-whatsapp-beta-multidevice-support)
 | 
			
		||||
- [XMPP](https://xmpp.org)
 | 
			
		||||
- [Zulip](https://zulipchat.com)
 | 
			
		||||
 | 
			
		||||
@@ -120,6 +124,8 @@ And more...
 | 
			
		||||
- [Counter-Strike, half-life and more](https://forums.alliedmods.net/showthread.php?t=319430)
 | 
			
		||||
- [MatterAMXX](https://github.com/GabeIggy/MatterAMXX)
 | 
			
		||||
- [Vintage Story](https://github.com/NikkyAI/vs-matterbridge)
 | 
			
		||||
- [Ultima Online Emulator](https://github.com/kuoushi/ServUO-Matterbridge)
 | 
			
		||||
- [Teamspeak](https://github.com/Archeb/ts-matterbridge)
 | 
			
		||||
 | 
			
		||||
### API
 | 
			
		||||
 | 
			
		||||
@@ -138,6 +144,8 @@ Used by the projects below. Feel free to make a PR to add your project to this l
 | 
			
		||||
- [matterbabble](https://github.com/DeclanHoare/matterbabble) (Discourse support)
 | 
			
		||||
- [MatterAMXX](https://forums.alliedmods.net/showthread.php?t=319430) (Counter-Strike, half-life and more via AMXX mod)
 | 
			
		||||
- [Vintage Story](https://github.com/NikkyAI/vs-matterbridge)
 | 
			
		||||
- [ServUO-matterbridge](https://github.com/kuoushi/ServUO-Matterbridge) (A matterbridge connector for ServUO servers)
 | 
			
		||||
- [ts-matterbridge](https://github.com/Archeb/ts-matterbridge) (Integrate teamspeak chat with matterbridge)
 | 
			
		||||
 | 
			
		||||
## Chat with us
 | 
			
		||||
 | 
			
		||||
@@ -164,10 +172,10 @@ See <https://github.com/42wim/matterbridge/wiki>
 | 
			
		||||
 | 
			
		||||
### Binaries
 | 
			
		||||
 | 
			
		||||
- Latest stable release [v1.24.0](https://github.com/42wim/matterbridge/releases/latest)
 | 
			
		||||
- Latest stable release [v1.25.1](https://github.com/42wim/matterbridge/releases/latest)
 | 
			
		||||
- Development releases (follows master) can be downloaded [here](https://github.com/42wim/matterbridge/actions) selecting the latest green build and then artifacts.
 | 
			
		||||
 | 
			
		||||
To install or upgrade just download the latest [binary](https://github.com/42wim/matterbridge/releases/latest). On \*nix platforms you may need to make the binary executable - you can do this by running `chmod a+x` on the binary (example: `chmod a+x matterbridge-1.20.0-linux-64bit`). After downloading (and making the binary executable, if necessary), follow the instructions on the [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration.
 | 
			
		||||
To install or upgrade just download the latest [binary](https://github.com/42wim/matterbridge/releases/latest). On \*nix platforms you may need to make the binary executable - you can do this by running `chmod a+x` on the binary (example: `chmod a+x matterbridge-1.24.1-linux-64bit`). After downloading (and making the binary executable, if necessary), follow the instructions on the [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration.
 | 
			
		||||
 | 
			
		||||
### Packages
 | 
			
		||||
 | 
			
		||||
@@ -182,6 +190,11 @@ Most people just want to use binaries, you can find those [here](https://github.
 | 
			
		||||
If you really want to build from source, follow these instructions:
 | 
			
		||||
Go 1.17+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed.
 | 
			
		||||
 | 
			
		||||
Building the binary with **all** the bridges enabled needs about 3GB RAM to compile.
 | 
			
		||||
You can reduce this memory requirement to 0,5GB RAM by adding the `nomsteams` tag if you don't need/use the Microsoft Teams bridge.
 | 
			
		||||
 | 
			
		||||
Matterbridge can be build without gcc/c-compiler: If you're running on windows first run `set CGO_ENABLED=0` on other platforms you prepend `CGO_ENABLED=0` to the `go build` command. (eg `CGO_ENABLED=0 go install github.com/42wim/matterbridge`)
 | 
			
		||||
 | 
			
		||||
To install the latest stable run:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
@@ -194,6 +207,38 @@ To install the latest dev run:
 | 
			
		||||
go install github.com/42wim/matterbridge@master
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To install the latest stable run without msteams or zulip bridge:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
go install -tags nomsteams,nozulip github.com/42wim/matterbridge
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You should now have matterbridge binary in the ~/go/bin directory:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
$ ls ~/go/bin/
 | 
			
		||||
matterbridge
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Building with whatsapp (beta) multidevice support
 | 
			
		||||
 | 
			
		||||
Because the library we use for Whatsapp multidevice support includes a GPL3 library we can not provide you binaries.
 | 
			
		||||
(as this would require the Matterbridge to change it license to GPL)
 | 
			
		||||
 | 
			
		||||
Matterbridge can be build without gcc/c-compiler: If you're running on windows first run `set CGO_ENABLED=0` on other platforms you prepend `CGO_ENABLED=0` to the `go build` command. (eg `CGO_ENABLED=0 go install github.com/42wim/matterbridge`)
 | 
			
		||||
 | 
			
		||||
So this means you have to build it yourself using the instructions below:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
go install -tags whatsappmulti github.com/42wim/matterbridge@master
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If you're low on memory and don't need msteams:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
go install -tags nomsteams,whatsappmulti github.com/42wim/matterbridge@master
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You should now have matterbridge binary in the ~/go/bin directory:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
@@ -323,6 +368,8 @@ See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ)
 | 
			
		||||
- [nextcloud talk](https://github.com/nextcloud/talk_matterbridge) (Integrates matterbridge in Nextcloud Talk)
 | 
			
		||||
- [mattercraft](https://github.com/raws/mattercraft) (Minecraft bridge)
 | 
			
		||||
- [vs-matterbridge](https://github.com/NikkyAI/vs-matterbridge) (Vintage Story bridge)
 | 
			
		||||
- [ServUO-matterbridge](https://github.com/kuoushi/ServUO-Matterbridge) (A matterbridge connector for ServUO servers)
 | 
			
		||||
- [ts-matterbridge](https://github.com/Archeb/ts-matterbridge) (Integrate teamspeak chat with matterbridge)
 | 
			
		||||
 | 
			
		||||
## Articles / Tutorials
 | 
			
		||||
 | 
			
		||||
@@ -356,6 +403,7 @@ Matterbridge wouldn't exist without these libraries:
 | 
			
		||||
- gops - <https://github.com/google/gops>
 | 
			
		||||
- gozulipbot - <https://github.com/ifo/gozulipbot>
 | 
			
		||||
- gumble - <https://github.com/layeh/gumble>
 | 
			
		||||
- harmony - <https://github.com/harmony-development/shibshib>
 | 
			
		||||
- irc - <https://github.com/lrstanley/girc>
 | 
			
		||||
- keybase - <https://github.com/keybase/go-keybase-chat-bot>
 | 
			
		||||
- matrix - <https://github.com/matrix-org/gomatrix>
 | 
			
		||||
@@ -363,6 +411,7 @@ Matterbridge wouldn't exist without these libraries:
 | 
			
		||||
- msgraph.go - <https://github.com/yaegashi/msgraph.go>
 | 
			
		||||
- mumble - <https://github.com/layeh/gumble>
 | 
			
		||||
- nctalk - <https://github.com/gary-kim/go-nc-talk>
 | 
			
		||||
- rocketchat - <https://github.com/RocketChat/Rocket.Chat.Go.SDK>
 | 
			
		||||
- slack - <https://github.com/nlopes/slack>
 | 
			
		||||
- sshchat - <https://github.com/shazow/ssh-chat>
 | 
			
		||||
- steam - <https://github.com/Philipp15b/go-steam>
 | 
			
		||||
@@ -370,6 +419,7 @@ Matterbridge wouldn't exist without these libraries:
 | 
			
		||||
- tengo - <https://github.com/d5/tengo>
 | 
			
		||||
- vk - <https://github.com/SevereCloud/vksdk>
 | 
			
		||||
- whatsapp - <https://github.com/Rhymen/go-whatsapp>
 | 
			
		||||
- whatsapp - <https://github.com/tulir/whatsmeow>
 | 
			
		||||
- xmpp - <https://github.com/mattn/go-xmpp>
 | 
			
		||||
- zulip - <https://github.com/ifo/gozulipbot>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@ import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/discord/transmitter"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
	lru "github.com/hashicorp/golang-lru"
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -272,7 +272,6 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
 | 
			
		||||
	// Handle prefix hint for unthreaded messages.
 | 
			
		||||
	if msg.ParentNotFound() {
 | 
			
		||||
		msg.ParentID = ""
 | 
			
		||||
		msg.Text = fmt.Sprintf("[thread]: %s", msg.Text)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Use webhook to send the message
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,8 @@ package bdiscord
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
	"github.com/davecgh/go-spew/spew"
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (b *Bdiscord) messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) { //nolint:unparam
 | 
			
		||||
@@ -56,7 +56,7 @@ func (b *Bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdat
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// only when message is actually edited
 | 
			
		||||
	if m.Message.EditedTimestamp != "" {
 | 
			
		||||
	if m.Message.EditedTimestamp != nil {
 | 
			
		||||
		b.Log.Debugf("Sending edit message")
 | 
			
		||||
		m.Content += b.GetString("EditSuffix")
 | 
			
		||||
		msg := &discordgo.MessageCreate{
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ package bdiscord
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode"
 | 
			
		||||
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (b *Bdiscord) getAllowedMentions() *discordgo.MessageAllowedMentions {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ import (
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
	log "github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package transmitter
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// isDiscordPermissionError returns false for nil, and true if a Discord RESTError with code discordgo.ErrorCodeMissionPermissions
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/matterbridge/discordgo"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// shouldMessageUseWebhooks checks if have a channel specific webhook, if we're not using auto webhooks
 | 
			
		||||
@@ -89,7 +89,7 @@ func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordg
 | 
			
		||||
				&discordgo.WebhookParams{
 | 
			
		||||
					Username:        msg.Username,
 | 
			
		||||
					AvatarURL:       msg.Avatar,
 | 
			
		||||
					File:            &file,
 | 
			
		||||
					Files:           []*discordgo.File{&file},
 | 
			
		||||
					Content:         content,
 | 
			
		||||
					AllowedMentions: b.getAllowedMentions(),
 | 
			
		||||
				},
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								bridge/irc/charset.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								bridge/irc/charset.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
package birc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"golang.org/x/text/encoding"
 | 
			
		||||
	"golang.org/x/text/encoding/japanese"
 | 
			
		||||
	"golang.org/x/text/encoding/korean"
 | 
			
		||||
	"golang.org/x/text/encoding/simplifiedchinese"
 | 
			
		||||
	"golang.org/x/text/encoding/traditionalchinese"
 | 
			
		||||
	"golang.org/x/text/encoding/unicode"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var encoders = map[string]encoding.Encoding{
 | 
			
		||||
	"utf-8":       unicode.UTF8,
 | 
			
		||||
	"iso-2022-jp": japanese.ISO2022JP,
 | 
			
		||||
	"big5":        traditionalchinese.Big5,
 | 
			
		||||
	"gbk":         simplifiedchinese.GBK,
 | 
			
		||||
	"euc-kr":      korean.EUCKR,
 | 
			
		||||
	"gb2312":      simplifiedchinese.HZGB2312,
 | 
			
		||||
	"shift-jis":   japanese.ShiftJIS,
 | 
			
		||||
	"euc-jp":      japanese.EUCJP,
 | 
			
		||||
	"gb18030":     simplifiedchinese.GB18030,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toUTF8(from string, input string) string {
 | 
			
		||||
	enc, ok := encoders[from]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return input
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res, _ := enc.NewDecoder().String(input)
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
@@ -11,7 +11,6 @@ import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/lrstanley/girc"
 | 
			
		||||
	"github.com/missdeer/golib/ic"
 | 
			
		||||
	"github.com/paulrosania/go-charset/charset"
 | 
			
		||||
	"github.com/saintfish/chardet"
 | 
			
		||||
 | 
			
		||||
@@ -24,12 +23,12 @@ func (b *Birc) handleCharset(msg *config.Message) error {
 | 
			
		||||
	if b.GetString("Charset") != "" {
 | 
			
		||||
		switch b.GetString("Charset") {
 | 
			
		||||
		case "gbk", "gb18030", "gb2312", "big5", "euc-kr", "euc-jp", "shift-jis", "iso-2022-jp":
 | 
			
		||||
			msg.Text = ic.ConvertString("utf-8", b.GetString("Charset"), msg.Text)
 | 
			
		||||
			msg.Text = toUTF8(b.GetString("Charset"), msg.Text)
 | 
			
		||||
		default:
 | 
			
		||||
			buf := new(bytes.Buffer)
 | 
			
		||||
			w, err := charset.NewWriter(b.GetString("Charset"), buf)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Errorf("charset from utf-8 conversion failed: %s", err)
 | 
			
		||||
				b.Log.Errorf("charset to utf-8 conversion failed: %s", err)
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			fmt.Fprint(w, msg.Text)
 | 
			
		||||
@@ -227,7 +226,7 @@ func (b *Birc) handlePrivMsg(client *girc.Client, event girc.Event) {
 | 
			
		||||
	}
 | 
			
		||||
	switch mycharset {
 | 
			
		||||
	case "gbk", "gb18030", "gb2312", "big5", "euc-kr", "euc-jp", "shift-jis", "iso-2022-jp":
 | 
			
		||||
		rmsg.Text = ic.ConvertString("utf-8", b.GetString("Charset"), rmsg.Text)
 | 
			
		||||
		rmsg.Text = toUTF8(b.GetString("Charset"), rmsg.Text)
 | 
			
		||||
	default:
 | 
			
		||||
		r, err := charset.NewReader(mycharset, strings.NewReader(rmsg.Text))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -362,8 +362,10 @@ func (b *Birc) skipPrivMsg(event girc.Event) bool {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	// don't forward message from ourself
 | 
			
		||||
	if event.Source.Name == b.Nick {
 | 
			
		||||
		return true
 | 
			
		||||
	if event.Source != nil {
 | 
			
		||||
		if event.Source.Name == b.Nick {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// don't forward messages we sent via RELAYMSG
 | 
			
		||||
	if relayedNick, ok := event.Tags.Get("draft/relaymsg"); ok && relayedNick == b.Nick {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	matrix "github.com/matrix-org/gomatrix"
 | 
			
		||||
	matrix "github.com/matterbridge/gomatrix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func newMatrixUsername(username string) *matrixUsername {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	matrix "github.com/matrix-org/gomatrix"
 | 
			
		||||
	matrix "github.com/matterbridge/gomatrix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -428,12 +428,15 @@ func (b *Bmatrix) handleReply(ev *matrix.Event, rmsg config.Message) bool {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	body := rmsg.Text
 | 
			
		||||
	for strings.HasPrefix(body, "> ") {
 | 
			
		||||
		lineIdx := strings.IndexRune(body, '\n')
 | 
			
		||||
		if lineIdx == -1 {
 | 
			
		||||
			body = ""
 | 
			
		||||
		} else {
 | 
			
		||||
			body = body[(lineIdx + 1):]
 | 
			
		||||
 | 
			
		||||
	if !b.GetBool("keepquotedreply") {
 | 
			
		||||
		for strings.HasPrefix(body, "> ") {
 | 
			
		||||
			lineIdx := strings.IndexRune(body, '\n')
 | 
			
		||||
			if lineIdx == -1 {
 | 
			
		||||
				body = ""
 | 
			
		||||
			} else {
 | 
			
		||||
				body = body[(lineIdx + 1):]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -183,6 +183,7 @@ func (b *Bmattermost) sendWebhook(msg config.Message) (string, error) {
 | 
			
		||||
	if b.GetBool("PrefixMessagesWithNick") {
 | 
			
		||||
		msg.Text = msg.Username + msg.Text
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if msg.Extra != nil {
 | 
			
		||||
		// this sends a message only if we received a config.EVENT_FILE_FAILURE_SIZE
 | 
			
		||||
		for _, rmsg := range helper.HandleExtra(&msg, b.General) {
 | 
			
		||||
@@ -206,7 +207,7 @@ func (b *Bmattermost) sendWebhook(msg config.Message) (string, error) {
 | 
			
		||||
			for _, f := range msg.Extra["file"] {
 | 
			
		||||
				fi := f.(config.FileInfo)
 | 
			
		||||
				if fi.URL != "" {
 | 
			
		||||
					msg.Text += fi.URL
 | 
			
		||||
					msg.Text += " " + fi.URL
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										70
									
								
								bridge/mumble/codec.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								bridge/mumble/codec.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
package bmumble
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"layeh.com/gumble/gumble"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This is a dummy implementation of a Gumble audio codec which claims
 | 
			
		||||
// to implement Opus, but does not actually do anything.  This serves
 | 
			
		||||
// as a workaround until https://github.com/layeh/gumble/pull/61 is
 | 
			
		||||
// merged.
 | 
			
		||||
// See https://github.com/42wim/matterbridge/issues/1750 for details.
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	audioCodecIDOpus = 4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func registerNullCodecAsOpus() {
 | 
			
		||||
	codec := &NullCodec{
 | 
			
		||||
		encoder: &NullAudioEncoder{},
 | 
			
		||||
		decoder: &NullAudioDecoder{},
 | 
			
		||||
	}
 | 
			
		||||
	gumble.RegisterAudioCodec(audioCodecIDOpus, codec)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type NullCodec struct {
 | 
			
		||||
	encoder *NullAudioEncoder
 | 
			
		||||
	decoder *NullAudioDecoder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *NullCodec) ID() int {
 | 
			
		||||
	return audioCodecIDOpus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *NullCodec) NewEncoder() gumble.AudioEncoder {
 | 
			
		||||
	e := &NullAudioEncoder{}
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *NullCodec) NewDecoder() gumble.AudioDecoder {
 | 
			
		||||
	d := &NullAudioDecoder{}
 | 
			
		||||
	return d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type NullAudioEncoder struct{}
 | 
			
		||||
 | 
			
		||||
func (e *NullAudioEncoder) ID() int {
 | 
			
		||||
	return audioCodecIDOpus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *NullAudioEncoder) Encode(pcm []int16, mframeSize, maxDataBytes int) ([]byte, error) {
 | 
			
		||||
	return nil, fmt.Errorf("not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *NullAudioEncoder) Reset() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type NullAudioDecoder struct{}
 | 
			
		||||
 | 
			
		||||
func (d *NullAudioDecoder) ID() int {
 | 
			
		||||
	return audioCodecIDOpus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *NullAudioDecoder) Decode(data []byte, frameSize int) ([]int16, error) {
 | 
			
		||||
	return nil, fmt.Errorf("not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *NullAudioDecoder) Reset() {
 | 
			
		||||
}
 | 
			
		||||
@@ -185,6 +185,7 @@ func (b *Bmumble) doConnect() error {
 | 
			
		||||
		gumbleConfig.Password = password
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	registerNullCodecAsOpus()
 | 
			
		||||
	client, err := gumble.DialWithDialer(new(net.Dialer), b.GetString("Server"), gumbleConfig, &b.tlsConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
 
 | 
			
		||||
@@ -282,6 +282,13 @@ func (b *Bslack) handleStatusEvent(ev *slack.MessageEvent, rmsg *config.Message)
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getMessageTitle(attach *slack.Attachment) string {
 | 
			
		||||
	if attach.TitleLink != "" {
 | 
			
		||||
		return fmt.Sprintf("[%s](%s)\n", attach.Title, attach.TitleLink)
 | 
			
		||||
	}
 | 
			
		||||
	return attach.Title
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message) {
 | 
			
		||||
	// File comments are set by the system (because there is no username given).
 | 
			
		||||
	if ev.SubType == sFileComment {
 | 
			
		||||
@@ -290,12 +297,15 @@ func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message)
 | 
			
		||||
 | 
			
		||||
	// See if we have some text in the attachments.
 | 
			
		||||
	if rmsg.Text == "" {
 | 
			
		||||
		for _, attach := range ev.Attachments {
 | 
			
		||||
		for i, attach := range ev.Attachments {
 | 
			
		||||
			if attach.Text != "" {
 | 
			
		||||
				if attach.Title != "" {
 | 
			
		||||
					rmsg.Text = attach.Title + "\n"
 | 
			
		||||
					rmsg.Text = getMessageTitle(&ev.Attachments[i])
 | 
			
		||||
				}
 | 
			
		||||
				rmsg.Text += attach.Text
 | 
			
		||||
				if attach.Footer != "" {
 | 
			
		||||
					rmsg.Text += "\n\n" + attach.Footer
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				rmsg.Text = attach.Fallback
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -87,6 +87,9 @@ func (b *Bslack) populateMessageWithUserInfo(ev *slack.MessageEvent, rmsg *confi
 | 
			
		||||
	if user.Profile.DisplayName != "" {
 | 
			
		||||
		rmsg.Username = user.Profile.DisplayName
 | 
			
		||||
	}
 | 
			
		||||
	if b.GetBool("UseFullName") && user.Profile.RealName != "" {
 | 
			
		||||
		rmsg.Username = user.Profile.RealName
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -124,7 +127,7 @@ var (
 | 
			
		||||
	mentionRE        = regexp.MustCompile(`<@([a-zA-Z0-9]+)>`)
 | 
			
		||||
	channelRE        = regexp.MustCompile(`<#[a-zA-Z0-9]+\|(.+?)>`)
 | 
			
		||||
	variableRE       = regexp.MustCompile(`<!((?:subteam\^)?[a-zA-Z0-9]+)(?:\|@?(.+?))?>`)
 | 
			
		||||
	urlRE            = regexp.MustCompile(`<(.*?)(\|.*?)?>`)
 | 
			
		||||
	urlRE            = regexp.MustCompile(`<([^<\|]+)\|([^>]+)>`)
 | 
			
		||||
	codeFenceRE      = regexp.MustCompile(`(?m)^` + "```" + `\w+$`)
 | 
			
		||||
	topicOrPurposeRE = regexp.MustCompile(`(?s)(@.+) (cleared|set)(?: the)? channel (topic|purpose)(?:: (.*))?`)
 | 
			
		||||
)
 | 
			
		||||
@@ -178,14 +181,7 @@ func (b *Bslack) replaceVariable(text string) string {
 | 
			
		||||
 | 
			
		||||
// @see https://api.slack.com/docs/message-formatting#linking_to_urls
 | 
			
		||||
func (b *Bslack) replaceURL(text string) string {
 | 
			
		||||
	for _, r := range urlRE.FindAllStringSubmatch(text, -1) {
 | 
			
		||||
		if len(strings.TrimSpace(r[2])) == 1 { // A display text separator was found, but the text was blank
 | 
			
		||||
			text = strings.Replace(text, r[0], "", 1)
 | 
			
		||||
		} else {
 | 
			
		||||
			text = strings.Replace(text, r[0], r[1], 1)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return text
 | 
			
		||||
	return urlRE.ReplaceAllString(text, "[${2}](${1})")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) replaceb0rkedMarkDown(text string) string {
 | 
			
		||||
 
 | 
			
		||||
@@ -321,7 +321,7 @@ func (b *Bslack) sendRTM(msg config.Message) (string, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Upload a file if it exists.
 | 
			
		||||
	if msg.Extra != nil {
 | 
			
		||||
	if len(msg.Extra) > 0 {
 | 
			
		||||
		extraMsgs := helper.HandleExtra(&msg, b.General)
 | 
			
		||||
		for i := range extraMsgs {
 | 
			
		||||
			rmsg := &extraMsgs[i]
 | 
			
		||||
@@ -332,7 +332,7 @@ func (b *Bslack) sendRTM(msg config.Message) (string, error) {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// Upload files if necessary (from Slack, Telegram or Mattermost).
 | 
			
		||||
		b.uploadFile(&msg, channelInfo.ID)
 | 
			
		||||
		return b.uploadFile(&msg, channelInfo.ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Post message.
 | 
			
		||||
@@ -443,7 +443,8 @@ func (b *Bslack) postMessage(msg *config.Message, channelInfo *slack.Channel) (s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// uploadFile handles native upload of files
 | 
			
		||||
func (b *Bslack) uploadFile(msg *config.Message, channelID string) {
 | 
			
		||||
func (b *Bslack) uploadFile(msg *config.Message, channelID string) (string, error) {
 | 
			
		||||
	var messageID string
 | 
			
		||||
	for _, f := range msg.Extra["file"] {
 | 
			
		||||
		fi, ok := f.(config.FileInfo)
 | 
			
		||||
		if !ok {
 | 
			
		||||
@@ -471,13 +472,22 @@ func (b *Bslack) uploadFile(msg *config.Message, channelID string) {
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Errorf("uploadfile %#v", err)
 | 
			
		||||
			return
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		if res.ID != "" {
 | 
			
		||||
			b.Log.Debugf("Adding file ID %s to cache with timestamp %s", res.ID, ts.String())
 | 
			
		||||
			b.cache.Add("file"+res.ID, ts)
 | 
			
		||||
 | 
			
		||||
			// search for message id by uploaded file in private/public channels, get thread timestamp from uploaded file
 | 
			
		||||
			if v, ok := res.Shares.Private[channelID]; ok && len(v) > 0 {
 | 
			
		||||
				messageID = v[0].Ts
 | 
			
		||||
			}
 | 
			
		||||
			if v, ok := res.Shares.Public[channelID]; ok && len(v) > 0 {
 | 
			
		||||
				messageID = v[0].Ts
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return messageID, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) prepareMessageOptions(msg *config.Message) []slack.MsgOption {
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,11 @@ func (b *Btelegram) handleForwarded(rmsg *config.Message, message *tgbotapi.Mess
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if message.ForwardFromChat != nil && message.ForwardFrom == nil {
 | 
			
		||||
		rmsg.Text = "Forwarded from " + message.ForwardFromChat.Title + ": " + rmsg.Text
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if message.ForwardFrom == nil {
 | 
			
		||||
		rmsg.Text = "Forwarded from " + unknownUser + ": " + rmsg.Text
 | 
			
		||||
		return
 | 
			
		||||
@@ -66,6 +71,9 @@ func (b *Btelegram) handleForwarded(rmsg *config.Message, message *tgbotapi.Mess
 | 
			
		||||
	if b.GetBool("UseFirstName") {
 | 
			
		||||
		usernameForward = message.ForwardFrom.FirstName
 | 
			
		||||
	}
 | 
			
		||||
	if b.GetBool("UseFullName") {
 | 
			
		||||
		usernameForward = message.ForwardFrom.FirstName + " " + message.ForwardFrom.LastName
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if usernameForward == "" {
 | 
			
		||||
		usernameForward = message.ForwardFrom.UserName
 | 
			
		||||
@@ -89,6 +97,9 @@ func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Messag
 | 
			
		||||
			if b.GetBool("UseFirstName") {
 | 
			
		||||
				usernameReply = message.ReplyToMessage.From.FirstName
 | 
			
		||||
			}
 | 
			
		||||
			if b.GetBool("UseFullName") {
 | 
			
		||||
				usernameReply = message.ReplyToMessage.From.FirstName + " " + message.ReplyToMessage.From.LastName
 | 
			
		||||
			}
 | 
			
		||||
			if usernameReply == "" {
 | 
			
		||||
				usernameReply = message.ReplyToMessage.From.UserName
 | 
			
		||||
				if usernameReply == "" {
 | 
			
		||||
@@ -100,7 +111,11 @@ func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Messag
 | 
			
		||||
			usernameReply = unknownUser
 | 
			
		||||
		}
 | 
			
		||||
		if !b.GetBool("QuoteDisable") {
 | 
			
		||||
			rmsg.Text = b.handleQuote(rmsg.Text, usernameReply, message.ReplyToMessage.Text)
 | 
			
		||||
			quote := message.ReplyToMessage.Text
 | 
			
		||||
			if quote == "" {
 | 
			
		||||
				quote = message.ReplyToMessage.Caption
 | 
			
		||||
			}
 | 
			
		||||
			rmsg.Text = b.handleQuote(rmsg.Text, usernameReply, quote)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -112,6 +127,9 @@ func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Messa
 | 
			
		||||
		if b.GetBool("UseFirstName") {
 | 
			
		||||
			rmsg.Username = message.From.FirstName
 | 
			
		||||
		}
 | 
			
		||||
		if b.GetBool("UseFullName") {
 | 
			
		||||
			rmsg.Username = message.From.FirstName + " " + message.From.LastName
 | 
			
		||||
		}
 | 
			
		||||
		if rmsg.Username == "" {
 | 
			
		||||
			rmsg.Username = message.From.UserName
 | 
			
		||||
			if rmsg.Username == "" {
 | 
			
		||||
@@ -129,6 +147,9 @@ func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Messa
 | 
			
		||||
		if b.GetBool("UseFirstName") {
 | 
			
		||||
			rmsg.Username = message.SenderChat.FirstName
 | 
			
		||||
		}
 | 
			
		||||
		if b.GetBool("UseFullName") {
 | 
			
		||||
			rmsg.Username = message.SenderChat.FirstName + " " + message.SenderChat.LastName
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if rmsg.Username == "" || rmsg.Username == "Channel_Bot" {
 | 
			
		||||
			rmsg.Username = message.SenderChat.UserName
 | 
			
		||||
@@ -182,6 +203,14 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
 | 
			
		||||
		rmsg.ID = strconv.Itoa(message.MessageID)
 | 
			
		||||
		rmsg.Channel = strconv.FormatInt(message.Chat.ID, 10)
 | 
			
		||||
 | 
			
		||||
		// preserve threading from telegram reply
 | 
			
		||||
		if message.ReplyToMessage != nil {
 | 
			
		||||
			rmsg.ParentID = strconv.Itoa(message.ReplyToMessage.MessageID)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// handle entities (adding URLs)
 | 
			
		||||
		b.handleEntities(&rmsg, message)
 | 
			
		||||
 | 
			
		||||
		// handle username
 | 
			
		||||
		b.handleUsername(&rmsg, message)
 | 
			
		||||
 | 
			
		||||
@@ -197,11 +226,9 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
 | 
			
		||||
		// quote the previous message
 | 
			
		||||
		b.handleQuoting(&rmsg, message)
 | 
			
		||||
 | 
			
		||||
		// handle entities (adding URLs)
 | 
			
		||||
		b.handleEntities(&rmsg, message)
 | 
			
		||||
 | 
			
		||||
		if rmsg.Text != "" || len(rmsg.Extra) > 0 {
 | 
			
		||||
			rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text)
 | 
			
		||||
			// Comment the next line out due to avoid removing empty lines in Telegram
 | 
			
		||||
			// rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text)
 | 
			
		||||
			// channels don't have (always?) user information. see #410
 | 
			
		||||
			if message.From != nil {
 | 
			
		||||
				rmsg.Avatar = helper.GetAvatar(b.avatarMap, strconv.FormatInt(message.From.ID, 10), b.General)
 | 
			
		||||
@@ -358,7 +385,7 @@ func (b *Btelegram) getDownloadInfo(id string, suffix string, urlpart bool) (str
 | 
			
		||||
		urlPart := strings.Split(url, "/")
 | 
			
		||||
		name = urlPart[len(urlPart)-1]
 | 
			
		||||
	}
 | 
			
		||||
	if suffix != "" && !strings.HasSuffix(name, suffix) {
 | 
			
		||||
	if suffix != "" && !strings.HasSuffix(name, suffix) && !strings.HasSuffix(name, ".webm") {
 | 
			
		||||
		name += suffix
 | 
			
		||||
	}
 | 
			
		||||
	text := " " + url
 | 
			
		||||
@@ -377,7 +404,7 @@ func (b *Btelegram) handleDelete(msg *config.Message, chatid int64) (string, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cfg := tgbotapi.NewDeleteMessage(chatid, msgid)
 | 
			
		||||
	_, err = b.c.Send(cfg)
 | 
			
		||||
	_, err = b.c.Request(cfg)
 | 
			
		||||
 | 
			
		||||
	return "", err
 | 
			
		||||
}
 | 
			
		||||
@@ -416,8 +443,8 @@ func (b *Btelegram) handleEdit(msg *config.Message, chatid int64) (string, error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// handleUploadFile handles native upload of files
 | 
			
		||||
func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string {
 | 
			
		||||
	var c tgbotapi.Chattable
 | 
			
		||||
func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64, parentID int) (string, error) {
 | 
			
		||||
	var media []interface{}
 | 
			
		||||
	for _, f := range msg.Extra["file"] {
 | 
			
		||||
		fi := f.(config.FileInfo)
 | 
			
		||||
		file := tgbotapi.FileBytes{
 | 
			
		||||
@@ -426,32 +453,42 @@ func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string {
 | 
			
		||||
		}
 | 
			
		||||
		switch filepath.Ext(fi.Name) {
 | 
			
		||||
		case ".jpg", ".jpe", ".png":
 | 
			
		||||
			pc := tgbotapi.NewPhoto(chatid, file)
 | 
			
		||||
			pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			c = pc
 | 
			
		||||
			pc := tgbotapi.NewInputMediaPhoto(file)
 | 
			
		||||
			if fi.Comment != "" {
 | 
			
		||||
				pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			}
 | 
			
		||||
			media = append(media, pc)
 | 
			
		||||
		case ".mp4", ".m4v":
 | 
			
		||||
			vc := tgbotapi.NewVideo(chatid, file)
 | 
			
		||||
			vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			c = vc
 | 
			
		||||
			vc := tgbotapi.NewInputMediaVideo(file)
 | 
			
		||||
			if fi.Comment != "" {
 | 
			
		||||
				vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			}
 | 
			
		||||
			media = append(media, vc)
 | 
			
		||||
		case ".mp3", ".oga":
 | 
			
		||||
			ac := tgbotapi.NewAudio(chatid, file)
 | 
			
		||||
			ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			c = ac
 | 
			
		||||
			ac := tgbotapi.NewInputMediaAudio(file)
 | 
			
		||||
			if fi.Comment != "" {
 | 
			
		||||
				ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			}
 | 
			
		||||
			media = append(media, ac)
 | 
			
		||||
		case ".ogg":
 | 
			
		||||
			voc := tgbotapi.NewVoice(chatid, file)
 | 
			
		||||
			voc.Caption, voc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			c = voc
 | 
			
		||||
			voc.ReplyToMessageID = parentID
 | 
			
		||||
			res, err := b.c.Send(voc)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return "", err
 | 
			
		||||
			}
 | 
			
		||||
			return strconv.Itoa(res.MessageID), nil
 | 
			
		||||
		default:
 | 
			
		||||
			dc := tgbotapi.NewDocument(chatid, file)
 | 
			
		||||
			dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			c = dc
 | 
			
		||||
		}
 | 
			
		||||
		_, err := b.c.Send(c)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Errorf("file upload failed: %#v", err)
 | 
			
		||||
			dc := tgbotapi.NewInputMediaDocument(file)
 | 
			
		||||
			if fi.Comment != "" {
 | 
			
		||||
				dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
 | 
			
		||||
			}
 | 
			
		||||
			media = append(media, dc)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
 | 
			
		||||
	return b.sendMediaFiles(msg, chatid, parentID, media)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Btelegram) handleQuote(message, quoteNick, quoteMessage string) string {
 | 
			
		||||
@@ -480,34 +517,59 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	indexMovedBy := 0
 | 
			
		||||
	prevLinkOffset := -1
 | 
			
		||||
 | 
			
		||||
	// for now only do URL replacements
 | 
			
		||||
	for _, e := range message.Entities {
 | 
			
		||||
 | 
			
		||||
		asRunes := utf16.Encode([]rune(rmsg.Text))
 | 
			
		||||
 | 
			
		||||
		if e.Type == "text_link" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			url, err := e.ParseURL()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				b.Log.Errorf("entity text_link url parse failed: %s", err)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			utfEncodedString := utf16.Encode([]rune(rmsg.Text))
 | 
			
		||||
			if e.Offset+e.Length > len(utfEncodedString) {
 | 
			
		||||
				b.Log.Errorf("entity length is too long %d > %d", e.Offset+e.Length, len(utfEncodedString))
 | 
			
		||||
			if offset+e.Length > len(utfEncodedString) {
 | 
			
		||||
				b.Log.Errorf("entity length is too long %d > %d", offset+e.Length, len(utfEncodedString))
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			link := utf16.Decode(utfEncodedString[e.Offset : e.Offset+e.Length])
 | 
			
		||||
			rmsg.Text = strings.Replace(rmsg.Text, string(link), url.String(), 1)
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset+e.Length])) + " (" + url.String() + ")" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += len(url.String()) + 3
 | 
			
		||||
			prevLinkOffset = e.Offset
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if e.Offset == prevLinkOffset {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if e.Type == "code" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			rmsg.Text = rmsg.Text[:offset] + "`" + rmsg.Text[offset:offset+e.Length] + "`" + rmsg.Text[offset+e.Length:]
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset])) + "`" + string(utf16.Decode(asRunes[offset:offset+e.Length])) + "`" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += 2
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if e.Type == "pre" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			rmsg.Text = rmsg.Text[:offset] + "```\n" + rmsg.Text[offset:offset+e.Length] + "\n```" + rmsg.Text[offset+e.Length:]
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset])) + "```\n" + string(utf16.Decode(asRunes[offset:offset+e.Length])) + "```\n" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += 8
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if e.Type == "bold" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset])) + "*" + string(utf16.Decode(asRunes[offset:offset+e.Length])) + "*" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += 2
 | 
			
		||||
		}
 | 
			
		||||
		if e.Type == "italic" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset])) + "_" + string(utf16.Decode(asRunes[offset:offset+e.Length])) + "_" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += 2
 | 
			
		||||
		}
 | 
			
		||||
		if e.Type == "strike" {
 | 
			
		||||
			offset := e.Offset + indexMovedBy
 | 
			
		||||
			rmsg.Text = string(utf16.Decode(asRunes[:offset])) + "~" + string(utf16.Decode(asRunes[offset:offset+e.Length])) + "~" + string(utf16.Decode(asRunes[offset+e.Length:]))
 | 
			
		||||
			indexMovedBy += 2
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package btelegram
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"html"
 | 
			
		||||
	"log"
 | 
			
		||||
	"strconv"
 | 
			
		||||
@@ -108,16 +109,27 @@ func (b *Btelegram) Send(msg config.Message) (string, error) {
 | 
			
		||||
		return b.handleDelete(&msg, chatid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Handle prefix hint for unthreaded messages.
 | 
			
		||||
	if msg.ParentNotFound() {
 | 
			
		||||
		msg.ParentID = ""
 | 
			
		||||
		msg.Text = fmt.Sprintf("[reply]: %s", msg.Text)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var parentID int
 | 
			
		||||
	if msg.ParentID != "" {
 | 
			
		||||
		parentID, _ = b.intParentID(msg.ParentID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Upload a file if it exists
 | 
			
		||||
	if msg.Extra != nil {
 | 
			
		||||
		for _, rmsg := range helper.HandleExtra(&msg, b.General) {
 | 
			
		||||
			if _, msgErr := b.sendMessage(chatid, rmsg.Username, rmsg.Text); msgErr != nil {
 | 
			
		||||
			if _, msgErr := b.sendMessage(chatid, rmsg.Username, rmsg.Text, parentID); msgErr != nil {
 | 
			
		||||
				b.Log.Errorf("sendMessage failed: %s", msgErr)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// check if we have files to upload (from slack, telegram or mattermost)
 | 
			
		||||
		if len(msg.Extra["file"]) > 0 {
 | 
			
		||||
			b.handleUploadFile(&msg, chatid)
 | 
			
		||||
			return b.handleUploadFile(&msg, chatid, parentID)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -131,7 +143,7 @@ func (b *Btelegram) Send(msg config.Message) (string, error) {
 | 
			
		||||
	// Ignore empty text field needs for prevent double messages from whatsapp to telegram
 | 
			
		||||
	// when sending media with text caption
 | 
			
		||||
	if msg.Text != "" {
 | 
			
		||||
		return b.sendMessage(chatid, msg.Username, msg.Text)
 | 
			
		||||
		return b.sendMessage(chatid, msg.Username, msg.Text, parentID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "", nil
 | 
			
		||||
@@ -145,10 +157,10 @@ func (b *Btelegram) getFileDirectURL(id string) string {
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Btelegram) sendMessage(chatid int64, username, text string) (string, error) {
 | 
			
		||||
func (b *Btelegram) sendMessage(chatid int64, username, text string, parentID int) (string, error) {
 | 
			
		||||
	m := tgbotapi.NewMessage(chatid, "")
 | 
			
		||||
	m.Text, m.ParseMode = TGGetParseMode(b, username, text)
 | 
			
		||||
 | 
			
		||||
	m.ReplyToMessageID = parentID
 | 
			
		||||
	m.DisableWebPagePreview = b.GetBool("DisableWebPagePreview")
 | 
			
		||||
 | 
			
		||||
	res, err := b.c.Send(m)
 | 
			
		||||
@@ -158,6 +170,29 @@ func (b *Btelegram) sendMessage(chatid int64, username, text string) (string, er
 | 
			
		||||
	return strconv.Itoa(res.MessageID), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sendMediaFiles native upload media files via media group
 | 
			
		||||
func (b *Btelegram) sendMediaFiles(msg *config.Message, chatid int64, parentID int, media []interface{}) (string, error) {
 | 
			
		||||
	if len(media) == 0 {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
	mg := tgbotapi.MediaGroupConfig{ChatID: chatid, ChannelUsername: msg.Username, Media: media, ReplyToMessageID: parentID}
 | 
			
		||||
	messages, err := b.c.SendMediaGroup(mg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	// return first message id
 | 
			
		||||
	return strconv.Itoa(messages[0].MessageID), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// intParentID return integer parent id for telegram message
 | 
			
		||||
func (b *Btelegram) intParentID(parentID string) (int, error) {
 | 
			
		||||
	pid, err := strconv.Atoi(parentID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return pid, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Btelegram) cacheAvatar(msg *config.Message) (string, error) {
 | 
			
		||||
	fi := msg.Extra["file"][0].(config.FileInfo)
 | 
			
		||||
	/* if we have a sha we have successfully uploaded the file to the media server,
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ func (b *Bvk) Connect() error {
 | 
			
		||||
	go func() {
 | 
			
		||||
		err := b.lp.Run()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Fatal("Enable longpoll in group management")
 | 
			
		||||
			b.Log.WithError(err).Fatal("Enable longpoll in group management")
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
@@ -223,7 +223,7 @@ func (b *Bvk) uploadFiles(extra map[string][]interface{}, peerID int) (string, s
 | 
			
		||||
		}
 | 
			
		||||
		a, err := b.uploadFile(fi, peerID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Error("File upload error ", fi.Name)
 | 
			
		||||
			b.Log.WithError(err).Error("File upload error ", fi.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		attachments = append(attachments, a)
 | 
			
		||||
@@ -237,7 +237,8 @@ func (b *Bvk) uploadFile(file config.FileInfo, peerID int) (string, error) {
 | 
			
		||||
 | 
			
		||||
	photoRE := regexp.MustCompile(".(jpg|jpe|png)$")
 | 
			
		||||
	if photoRE.MatchString(file.Name) {
 | 
			
		||||
		p, err := b.c.UploadMessagesPhoto(peerID, r)
 | 
			
		||||
		// BUG(VK): for community chat peerID=0
 | 
			
		||||
		p, err := b.c.UploadMessagesPhoto(0, r)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
// nolint:goconst
 | 
			
		||||
package bwhatsapp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
@@ -134,6 +135,7 @@ func (b *Bwhatsapp) HandleTextMessage(message whatsapp.TextMessage) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HandleImageMessage sent from WhatsApp, relay it to the brige
 | 
			
		||||
// nolint:funlen
 | 
			
		||||
func (b *Bwhatsapp) HandleImageMessage(message whatsapp.ImageMessage) {
 | 
			
		||||
	if message.Info.FromMe || message.Info.Timestamp < b.startedAt {
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -111,8 +111,7 @@ func (b *Bwhatsapp) getSenderName(senderJid string) string {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// try to reload this contact
 | 
			
		||||
	_, err := b.conn.Contacts()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if _, err := b.conn.Contacts(); err != nil {
 | 
			
		||||
		b.Log.Errorf("error on update of contacts: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,11 @@ type Bwhatsapp struct {
 | 
			
		||||
func New(cfg *bridge.Config) bridge.Bridger {
 | 
			
		||||
	number := cfg.GetString(cfgNumber)
 | 
			
		||||
 | 
			
		||||
	cfg.Log.Warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
 | 
			
		||||
	cfg.Log.Warn("This bridge is deprecated and not supported anymore. Use the new multidevice whatsapp bridge")
 | 
			
		||||
	cfg.Log.Warn("See https://github.com/42wim/matterbridge#building-with-whatsapp-beta-multidevice-support for more info")
 | 
			
		||||
	cfg.Log.Warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
 | 
			
		||||
 | 
			
		||||
	if number == "" {
 | 
			
		||||
		cfg.Log.Fatalf("Missing configuration for WhatsApp bridge: Number")
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										344
									
								
								bridge/whatsappmulti/handlers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										344
									
								
								bridge/whatsappmulti/handlers.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,344 @@
 | 
			
		||||
// +build whatsappmulti
 | 
			
		||||
 | 
			
		||||
package bwhatsapp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"mime"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
 | 
			
		||||
	"go.mau.fi/whatsmeow/binary/proto"
 | 
			
		||||
	"go.mau.fi/whatsmeow/types"
 | 
			
		||||
	"go.mau.fi/whatsmeow/types/events"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// nolint:gocritic
 | 
			
		||||
func (b *Bwhatsapp) eventHandler(evt interface{}) {
 | 
			
		||||
	switch e := evt.(type) {
 | 
			
		||||
	case *events.Message:
 | 
			
		||||
		b.handleMessage(e)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bwhatsapp) handleMessage(message *events.Message) {
 | 
			
		||||
	msg := message.Message
 | 
			
		||||
	switch {
 | 
			
		||||
	case msg == nil, message.Info.IsFromMe, message.Info.Timestamp.Before(b.startedAt):
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Log.Infof("Receiving message %#v", msg)
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case msg.Conversation != nil || msg.ExtendedTextMessage != nil:
 | 
			
		||||
		b.handleTextMessage(message.Info, msg)
 | 
			
		||||
	case msg.VideoMessage != nil:
 | 
			
		||||
		b.handleVideoMessage(message)
 | 
			
		||||
	case msg.AudioMessage != nil:
 | 
			
		||||
		b.handleAudioMessage(message)
 | 
			
		||||
	case msg.DocumentMessage != nil:
 | 
			
		||||
		b.handleDocumentMessage(message)
 | 
			
		||||
	case msg.ImageMessage != nil:
 | 
			
		||||
		b.handleImageMessage(message)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// nolint:funlen
 | 
			
		||||
func (b *Bwhatsapp) handleTextMessage(messageInfo types.MessageInfo, msg *proto.Message) {
 | 
			
		||||
	senderJID := messageInfo.Sender
 | 
			
		||||
	channel := messageInfo.Chat
 | 
			
		||||
 | 
			
		||||
	senderName := b.getSenderName(messageInfo.Sender)
 | 
			
		||||
	if senderName == "" {
 | 
			
		||||
		senderName = "Someone" // don't expose telephone number
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if msg.GetExtendedTextMessage() == nil && msg.GetConversation() == "" {
 | 
			
		||||
		b.Log.Debugf("message without text content? %#v", msg)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var text string
 | 
			
		||||
 | 
			
		||||
	// nolint:nestif
 | 
			
		||||
	if msg.GetExtendedTextMessage() == nil {
 | 
			
		||||
		text = msg.GetConversation()
 | 
			
		||||
	} else {
 | 
			
		||||
		text = msg.GetExtendedTextMessage().GetText()
 | 
			
		||||
		ci := msg.GetExtendedTextMessage().GetContextInfo()
 | 
			
		||||
 | 
			
		||||
		if senderJID == (types.JID{}) && ci.Participant != nil {
 | 
			
		||||
			senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ci.MentionedJid != nil {
 | 
			
		||||
			// handle user mentions
 | 
			
		||||
			for _, mentionedJID := range ci.MentionedJid {
 | 
			
		||||
				numberAndSuffix := strings.SplitN(mentionedJID, "@", 2)
 | 
			
		||||
 | 
			
		||||
				// mentions comes as telephone numbers and we don't want to expose it to other bridges
 | 
			
		||||
				// replace it with something more meaninful to others
 | 
			
		||||
				mention := b.getSenderNotify(types.NewJID(numberAndSuffix[0], types.DefaultUserServer))
 | 
			
		||||
				if mention == "" {
 | 
			
		||||
					mention = "someone"
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				text = strings.Replace(text, "@"+numberAndSuffix[0], "@"+mention, 1)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rmsg := config.Message{
 | 
			
		||||
		UserID:   senderJID.String(),
 | 
			
		||||
		Username: senderName,
 | 
			
		||||
		Text:     text,
 | 
			
		||||
		Channel:  channel.String(),
 | 
			
		||||
		Account:  b.Account,
 | 
			
		||||
		Protocol: b.Protocol,
 | 
			
		||||
		Extra:    make(map[string][]interface{}),
 | 
			
		||||
		//      ParentID: TODO, // TODO handle thread replies  // map from Info.QuotedMessageID string
 | 
			
		||||
		ID: messageInfo.ID,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
 | 
			
		||||
		rmsg.Avatar = avatarURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
 | 
			
		||||
	b.Log.Debugf("<= Message is %#v", rmsg)
 | 
			
		||||
 | 
			
		||||
	b.Remote <- rmsg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HandleImageMessage sent from WhatsApp, relay it to the brige
 | 
			
		||||
func (b *Bwhatsapp) handleImageMessage(msg *events.Message) {
 | 
			
		||||
	imsg := msg.Message.GetImageMessage()
 | 
			
		||||
 | 
			
		||||
	senderJID := msg.Info.Sender
 | 
			
		||||
	senderName := b.getSenderName(senderJID)
 | 
			
		||||
	ci := imsg.GetContextInfo()
 | 
			
		||||
 | 
			
		||||
	if senderJID == (types.JID{}) && ci.Participant != nil {
 | 
			
		||||
		senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rmsg := config.Message{
 | 
			
		||||
		UserID:   senderJID.String(),
 | 
			
		||||
		Username: senderName,
 | 
			
		||||
		Channel:  msg.Info.Chat.String(),
 | 
			
		||||
		Account:  b.Account,
 | 
			
		||||
		Protocol: b.Protocol,
 | 
			
		||||
		Extra:    make(map[string][]interface{}),
 | 
			
		||||
		ID:       msg.Info.ID,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
 | 
			
		||||
		rmsg.Avatar = avatarURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("Mimetype detection error: %s", err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// rename .jfif to .jpg https://github.com/42wim/matterbridge/issues/1292
 | 
			
		||||
	if fileExt[0] == ".jfif" {
 | 
			
		||||
		fileExt[0] = ".jpg"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// rename .jpe to .jpg https://github.com/42wim/matterbridge/issues/1463
 | 
			
		||||
	if fileExt[0] == ".jpe" {
 | 
			
		||||
		fileExt[0] = ".jpg"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	filename := fmt.Sprintf("%v%v", msg.Info.ID, fileExt[0])
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("Trying to download %s with type %s", filename, imsg.GetMimetype())
 | 
			
		||||
 | 
			
		||||
	data, err := b.wc.Download(imsg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("Download image failed: %s", err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Move file to bridge storage
 | 
			
		||||
	helper.HandleDownloadData(b.Log, &rmsg, filename, imsg.GetCaption(), "", &data, b.General)
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
 | 
			
		||||
	b.Log.Debugf("<= Message is %#v", rmsg)
 | 
			
		||||
 | 
			
		||||
	b.Remote <- rmsg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HandleVideoMessage downloads video messages
 | 
			
		||||
func (b *Bwhatsapp) handleVideoMessage(msg *events.Message) {
 | 
			
		||||
	imsg := msg.Message.GetVideoMessage()
 | 
			
		||||
 | 
			
		||||
	senderJID := msg.Info.Sender
 | 
			
		||||
	senderName := b.getSenderName(senderJID)
 | 
			
		||||
	ci := imsg.GetContextInfo()
 | 
			
		||||
 | 
			
		||||
	if senderJID == (types.JID{}) && ci.Participant != nil {
 | 
			
		||||
		senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rmsg := config.Message{
 | 
			
		||||
		UserID:   senderJID.String(),
 | 
			
		||||
		Username: senderName,
 | 
			
		||||
		Channel:  msg.Info.Chat.String(),
 | 
			
		||||
		Account:  b.Account,
 | 
			
		||||
		Protocol: b.Protocol,
 | 
			
		||||
		Extra:    make(map[string][]interface{}),
 | 
			
		||||
		ID:       msg.Info.ID,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
 | 
			
		||||
		rmsg.Avatar = avatarURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("Mimetype detection error: %s", err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(fileExt) == 0 {
 | 
			
		||||
		fileExt = append(fileExt, ".mp4")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	filename := fmt.Sprintf("%v%v", msg.Info.ID, fileExt[0])
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, imsg.GetFileLength(), imsg.GetMimetype())
 | 
			
		||||
 | 
			
		||||
	data, err := b.wc.Download(imsg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("Download video failed: %s", err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Move file to bridge storage
 | 
			
		||||
	helper.HandleDownloadData(b.Log, &rmsg, filename, imsg.GetCaption(), "", &data, b.General)
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
 | 
			
		||||
	b.Log.Debugf("<= Message is %#v", rmsg)
 | 
			
		||||
 | 
			
		||||
	b.Remote <- rmsg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HandleAudioMessage downloads audio messages
 | 
			
		||||
func (b *Bwhatsapp) handleAudioMessage(msg *events.Message) {
 | 
			
		||||
	imsg := msg.Message.GetAudioMessage()
 | 
			
		||||
 | 
			
		||||
	senderJID := msg.Info.Sender
 | 
			
		||||
	senderName := b.getSenderName(senderJID)
 | 
			
		||||
	ci := imsg.GetContextInfo()
 | 
			
		||||
 | 
			
		||||
	if senderJID == (types.JID{}) && ci.Participant != nil {
 | 
			
		||||
		senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rmsg := config.Message{
 | 
			
		||||
		UserID:   senderJID.String(),
 | 
			
		||||
		Username: senderName,
 | 
			
		||||
		Channel:  msg.Info.Chat.String(),
 | 
			
		||||
		Account:  b.Account,
 | 
			
		||||
		Protocol: b.Protocol,
 | 
			
		||||
		Extra:    make(map[string][]interface{}),
 | 
			
		||||
		ID:       msg.Info.ID,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
 | 
			
		||||
		rmsg.Avatar = avatarURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("Mimetype detection error: %s", err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(fileExt) == 0 {
 | 
			
		||||
		fileExt = append(fileExt, ".ogg")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	filename := fmt.Sprintf("%v%v", msg.Info.ID, fileExt[0])
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, imsg.GetFileLength(), imsg.GetMimetype())
 | 
			
		||||
 | 
			
		||||
	data, err := b.wc.Download(imsg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("Download video failed: %s", err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Move file to bridge storage
 | 
			
		||||
	helper.HandleDownloadData(b.Log, &rmsg, filename, "audio message", "", &data, b.General)
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
 | 
			
		||||
	b.Log.Debugf("<= Message is %#v", rmsg)
 | 
			
		||||
 | 
			
		||||
	b.Remote <- rmsg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HandleDocumentMessage downloads documents
 | 
			
		||||
func (b *Bwhatsapp) handleDocumentMessage(msg *events.Message) {
 | 
			
		||||
	imsg := msg.Message.GetDocumentMessage()
 | 
			
		||||
 | 
			
		||||
	senderJID := msg.Info.Sender
 | 
			
		||||
	senderName := b.getSenderName(senderJID)
 | 
			
		||||
	ci := imsg.GetContextInfo()
 | 
			
		||||
 | 
			
		||||
	if senderJID == (types.JID{}) && ci.Participant != nil {
 | 
			
		||||
		senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rmsg := config.Message{
 | 
			
		||||
		UserID:   senderJID.String(),
 | 
			
		||||
		Username: senderName,
 | 
			
		||||
		Channel:  msg.Info.Chat.String(),
 | 
			
		||||
		Account:  b.Account,
 | 
			
		||||
		Protocol: b.Protocol,
 | 
			
		||||
		Extra:    make(map[string][]interface{}),
 | 
			
		||||
		ID:       msg.Info.ID,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
 | 
			
		||||
		rmsg.Avatar = avatarURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("Mimetype detection error: %s", err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	filename := fmt.Sprintf("%v", imsg.GetFileName())
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("Trying to download %s with extension %s and type %s", filename, fileExt, imsg.GetMimetype())
 | 
			
		||||
 | 
			
		||||
	data, err := b.wc.Download(imsg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("Download document message failed: %s", err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Move file to bridge storage
 | 
			
		||||
	helper.HandleDownloadData(b.Log, &rmsg, filename, "document", "", &data, b.General)
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
 | 
			
		||||
	b.Log.Debugf("<= Message is %#v", rmsg)
 | 
			
		||||
 | 
			
		||||
	b.Remote <- rmsg
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								bridge/whatsappmulti/helpers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								bridge/whatsappmulti/helpers.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
// +build whatsappmulti
 | 
			
		||||
 | 
			
		||||
package bwhatsapp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"go.mau.fi/whatsmeow/store"
 | 
			
		||||
	"go.mau.fi/whatsmeow/store/sqlstore"
 | 
			
		||||
	"go.mau.fi/whatsmeow/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ProfilePicInfo struct {
 | 
			
		||||
	URL    string `json:"eurl"`
 | 
			
		||||
	Tag    string `json:"tag"`
 | 
			
		||||
	Status int16  `json:"status"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bwhatsapp) getSenderName(senderJid types.JID) string {
 | 
			
		||||
	if sender, exists := b.contacts[senderJid]; exists {
 | 
			
		||||
		if sender.FullName != "" {
 | 
			
		||||
			return sender.FullName
 | 
			
		||||
		}
 | 
			
		||||
		// if user is not in phone contacts
 | 
			
		||||
		// it is the most obvious scenario unless you sync your phone contacts with some remote updated source
 | 
			
		||||
		// users can change it in their WhatsApp settings -> profile -> click on Avatar
 | 
			
		||||
		if sender.PushName != "" {
 | 
			
		||||
			return sender.PushName
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if sender.FirstName != "" {
 | 
			
		||||
			return sender.FirstName
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// try to reload this contact
 | 
			
		||||
	if _, err := b.wc.Store.Contacts.GetAllContacts(); err != nil {
 | 
			
		||||
		b.Log.Errorf("error on update of contacts: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	allcontacts, err := b.wc.Store.Contacts.GetAllContacts()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Errorf("error on update of contacts: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(allcontacts) > 0 {
 | 
			
		||||
		b.contacts = allcontacts
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sender, exists := b.contacts[senderJid]; exists {
 | 
			
		||||
		if sender.FullName != "" {
 | 
			
		||||
			return sender.FullName
 | 
			
		||||
		}
 | 
			
		||||
		// if user is not in phone contacts
 | 
			
		||||
		// it is the most obvious scenario unless you sync your phone contacts with some remote updated source
 | 
			
		||||
		// users can change it in their WhatsApp settings -> profile -> click on Avatar
 | 
			
		||||
		if sender.PushName != "" {
 | 
			
		||||
			return sender.PushName
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if sender.FirstName != "" {
 | 
			
		||||
			return sender.FirstName
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "Someone"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bwhatsapp) getSenderNotify(senderJid types.JID) string {
 | 
			
		||||
	if sender, exists := b.contacts[senderJid]; exists {
 | 
			
		||||
		return sender.PushName
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bwhatsapp) GetProfilePicThumb(jid string) (*types.ProfilePictureInfo, error) {
 | 
			
		||||
	pjid, _ := types.ParseJID(jid)
 | 
			
		||||
	info, err := b.wc.GetProfilePictureInfo(pjid, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("failed to get avatar: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return info, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isGroupJid(identifier string) bool {
 | 
			
		||||
	return strings.HasSuffix(identifier, "@g.us") ||
 | 
			
		||||
		strings.HasSuffix(identifier, "@temp") ||
 | 
			
		||||
		strings.HasSuffix(identifier, "@broadcast")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bwhatsapp) getDevice() (*store.Device, error) {
 | 
			
		||||
	device := &store.Device{}
 | 
			
		||||
 | 
			
		||||
	storeContainer, err := sqlstore.New("sqlite", "file:"+b.Config.GetString("sessionfile")+".db?_foreign_keys=on&_pragma=busy_timeout=10000", nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return device, fmt.Errorf("failed to connect to database: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	device, err = storeContainer.GetFirstDevice()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return device, fmt.Errorf("failed to get device: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return device, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										333
									
								
								bridge/whatsappmulti/whatsapp.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										333
									
								
								bridge/whatsappmulti/whatsapp.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,333 @@
 | 
			
		||||
// +build whatsappmulti
 | 
			
		||||
 | 
			
		||||
package bwhatsapp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"mime"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/mdp/qrterminal"
 | 
			
		||||
 | 
			
		||||
	"go.mau.fi/whatsmeow"
 | 
			
		||||
	"go.mau.fi/whatsmeow/binary/proto"
 | 
			
		||||
	"go.mau.fi/whatsmeow/types"
 | 
			
		||||
	waLog "go.mau.fi/whatsmeow/util/log"
 | 
			
		||||
 | 
			
		||||
	goproto "google.golang.org/protobuf/proto"
 | 
			
		||||
 | 
			
		||||
	_ "modernc.org/sqlite" // needed for sqlite
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Account config parameters
 | 
			
		||||
	cfgNumber = "Number"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Bwhatsapp Bridge structure keeping all the information needed for relying
 | 
			
		||||
type Bwhatsapp struct {
 | 
			
		||||
	*bridge.Config
 | 
			
		||||
 | 
			
		||||
	startedAt   time.Time
 | 
			
		||||
	wc          *whatsmeow.Client
 | 
			
		||||
	contacts    map[types.JID]types.ContactInfo
 | 
			
		||||
	users       map[string]types.ContactInfo
 | 
			
		||||
	userAvatars map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New Create a new WhatsApp bridge. This will be called for each [whatsapp.<server>] entry you have in the config file
 | 
			
		||||
func New(cfg *bridge.Config) bridge.Bridger {
 | 
			
		||||
	number := cfg.GetString(cfgNumber)
 | 
			
		||||
 | 
			
		||||
	if number == "" {
 | 
			
		||||
		cfg.Log.Fatalf("Missing configuration for WhatsApp bridge: Number")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b := &Bwhatsapp{
 | 
			
		||||
		Config: cfg,
 | 
			
		||||
 | 
			
		||||
		users:       make(map[string]types.ContactInfo),
 | 
			
		||||
		userAvatars: make(map[string]string),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Connect to WhatsApp. Required implementation of the Bridger interface
 | 
			
		||||
func (b *Bwhatsapp) Connect() error {
 | 
			
		||||
	device, err := b.getDevice()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	number := b.GetString(cfgNumber)
 | 
			
		||||
	if number == "" {
 | 
			
		||||
		return errors.New("whatsapp's telephone number need to be configured")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugln("Connecting to WhatsApp..")
 | 
			
		||||
 | 
			
		||||
	b.wc = whatsmeow.NewClient(device, waLog.Stdout("Client", "INFO", true))
 | 
			
		||||
	b.wc.AddEventHandler(b.eventHandler)
 | 
			
		||||
 | 
			
		||||
	firstlogin := false
 | 
			
		||||
	var qrChan <-chan whatsmeow.QRChannelItem
 | 
			
		||||
	if b.wc.Store.ID == nil {
 | 
			
		||||
		firstlogin = true
 | 
			
		||||
		qrChan, err = b.wc.GetQRChannel(context.Background())
 | 
			
		||||
		if err != nil && !errors.Is(err, whatsmeow.ErrQRStoreContainsID) {
 | 
			
		||||
			return errors.New("failed to to get QR channel:" + err.Error())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = b.wc.Connect()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.New("failed to connect to WhatsApp: " + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if b.wc.Store.ID == nil {
 | 
			
		||||
		for evt := range qrChan {
 | 
			
		||||
			if evt.Event == "code" {
 | 
			
		||||
				qrterminal.GenerateHalfBlock(evt.Code, qrterminal.L, os.Stdout)
 | 
			
		||||
			} else {
 | 
			
		||||
				b.Log.Infof("QR channel result: %s", evt.Event)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// disconnect and reconnect on our first login/pairing
 | 
			
		||||
	// for some reason the GetJoinedGroups in JoinChannel doesn't work on first login
 | 
			
		||||
	if firstlogin {
 | 
			
		||||
		b.wc.Disconnect()
 | 
			
		||||
		time.Sleep(time.Second)
 | 
			
		||||
 | 
			
		||||
		err = b.wc.Connect()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.New("failed to connect to WhatsApp: " + err.Error())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Log.Infoln("WhatsApp connection successful")
 | 
			
		||||
 | 
			
		||||
	b.contacts, err = b.wc.Store.Contacts.GetAllContacts()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.New("failed to get contacts: " + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.startedAt = time.Now()
 | 
			
		||||
 | 
			
		||||
	// map all the users
 | 
			
		||||
	for id, contact := range b.contacts {
 | 
			
		||||
		if !isGroupJid(id.String()) && id.String() != "status@broadcast" {
 | 
			
		||||
			// it is user
 | 
			
		||||
			b.users[id.String()] = contact
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get user avatar asynchronously
 | 
			
		||||
	b.Log.Info("Getting user avatars..")
 | 
			
		||||
 | 
			
		||||
	for jid := range b.users {
 | 
			
		||||
		info, err := b.GetProfilePicThumb(jid)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Warnf("Could not get profile photo of %s: %v", jid, err)
 | 
			
		||||
		} else {
 | 
			
		||||
			b.Lock()
 | 
			
		||||
			if info != nil {
 | 
			
		||||
				b.userAvatars[jid] = info.URL
 | 
			
		||||
			}
 | 
			
		||||
			b.Unlock()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Log.Info("Finished getting avatars..")
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Disconnect is called while reconnecting to the bridge
 | 
			
		||||
// Required implementation of the Bridger interface
 | 
			
		||||
func (b *Bwhatsapp) Disconnect() error {
 | 
			
		||||
	b.wc.Disconnect()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// JoinChannel Join a WhatsApp group specified in gateway config as channel='number-id@g.us' or channel='Channel name'
 | 
			
		||||
// Required implementation of the Bridger interface
 | 
			
		||||
// https://github.com/42wim/matterbridge/blob/2cfd880cdb0df29771bf8f31df8d990ab897889d/bridge/bridge.go#L11-L16
 | 
			
		||||
func (b *Bwhatsapp) JoinChannel(channel config.ChannelInfo) error {
 | 
			
		||||
	byJid := isGroupJid(channel.Name)
 | 
			
		||||
 | 
			
		||||
	groups, err := b.wc.GetJoinedGroups()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// verify if we are member of the given group
 | 
			
		||||
	if byJid {
 | 
			
		||||
		gJID, err := types.ParseJID(channel.Name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, group := range groups {
 | 
			
		||||
			if group.JID == gJID {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	foundGroups := []string{}
 | 
			
		||||
 | 
			
		||||
	for _, group := range groups {
 | 
			
		||||
		if group.Name == channel.Name {
 | 
			
		||||
			foundGroups = append(foundGroups, group.Name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch len(foundGroups) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		// didn't match any group - print out possibilites
 | 
			
		||||
		for _, group := range groups {
 | 
			
		||||
			b.Log.Infof("%s %s", group.JID, group.Name)
 | 
			
		||||
		}
 | 
			
		||||
		return fmt.Errorf("please specify group's JID from the list above instead of the name '%s'", channel.Name)
 | 
			
		||||
	case 1:
 | 
			
		||||
		return fmt.Errorf("group name might change. Please configure gateway with channel=\"%v\" instead of channel=\"%v\"", foundGroups[0], channel.Name)
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("there is more than one group with name '%s'. Please specify one of JIDs as channel name: %v", channel.Name, foundGroups)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Post a document message from the bridge to WhatsApp
 | 
			
		||||
func (b *Bwhatsapp) PostDocumentMessage(msg config.Message, filetype string) (string, error) {
 | 
			
		||||
	groupJID, _ := types.ParseJID(msg.Channel)
 | 
			
		||||
 | 
			
		||||
	fi := msg.Extra["file"][0].(config.FileInfo)
 | 
			
		||||
 | 
			
		||||
	resp, err := b.wc.Upload(context.Background(), *fi.Data, whatsmeow.MediaDocument)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Post document message
 | 
			
		||||
	var message proto.Message
 | 
			
		||||
 | 
			
		||||
	message.DocumentMessage = &proto.DocumentMessage{
 | 
			
		||||
		Title:         &fi.Name,
 | 
			
		||||
		FileName:      &fi.Name,
 | 
			
		||||
		Mimetype:      &filetype,
 | 
			
		||||
		MediaKey:      resp.MediaKey,
 | 
			
		||||
		FileEncSha256: resp.FileEncSHA256,
 | 
			
		||||
		FileSha256:    resp.FileSHA256,
 | 
			
		||||
		FileLength:    goproto.Uint64(resp.FileLength),
 | 
			
		||||
		Url:           &resp.URL,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("=> Sending %#v", msg)
 | 
			
		||||
 | 
			
		||||
	ID := whatsmeow.GenerateMessageID()
 | 
			
		||||
	_, err = b.wc.SendMessage(groupJID, ID, &message)
 | 
			
		||||
 | 
			
		||||
	return ID, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Post an image message from the bridge to WhatsApp
 | 
			
		||||
// Handle, for sure image/jpeg, image/png and image/gif MIME types
 | 
			
		||||
func (b *Bwhatsapp) PostImageMessage(msg config.Message, filetype string) (string, error) {
 | 
			
		||||
	groupJID, _ := types.ParseJID(msg.Channel)
 | 
			
		||||
 | 
			
		||||
	fi := msg.Extra["file"][0].(config.FileInfo)
 | 
			
		||||
 | 
			
		||||
	caption := msg.Username + fi.Comment
 | 
			
		||||
 | 
			
		||||
	resp, err := b.wc.Upload(context.Background(), *fi.Data, whatsmeow.MediaImage)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var message proto.Message
 | 
			
		||||
 | 
			
		||||
	message.ImageMessage = &proto.ImageMessage{
 | 
			
		||||
		Mimetype:      &filetype,
 | 
			
		||||
		Caption:       &caption,
 | 
			
		||||
		MediaKey:      resp.MediaKey,
 | 
			
		||||
		FileEncSha256: resp.FileEncSHA256,
 | 
			
		||||
		FileSha256:    resp.FileSHA256,
 | 
			
		||||
		FileLength:    goproto.Uint64(resp.FileLength),
 | 
			
		||||
		Url:           &resp.URL,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("=> Sending %#v", msg)
 | 
			
		||||
 | 
			
		||||
	ID := whatsmeow.GenerateMessageID()
 | 
			
		||||
	_, err = b.wc.SendMessage(groupJID, ID, &message)
 | 
			
		||||
 | 
			
		||||
	return ID, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send a message from the bridge to WhatsApp
 | 
			
		||||
func (b *Bwhatsapp) Send(msg config.Message) (string, error) {
 | 
			
		||||
	groupJID, _ := types.ParseJID(msg.Channel)
 | 
			
		||||
 | 
			
		||||
	b.Log.Debugf("=> Receiving %#v", msg)
 | 
			
		||||
 | 
			
		||||
	// Delete message
 | 
			
		||||
	if msg.Event == config.EventMsgDelete {
 | 
			
		||||
		if msg.ID == "" {
 | 
			
		||||
			// No message ID in case action is executed on a message sent before the bridge was started
 | 
			
		||||
			// and then the bridge cache doesn't have this message ID mapped
 | 
			
		||||
			return "", nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_, err := b.wc.RevokeMessage(groupJID, msg.ID)
 | 
			
		||||
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Edit message
 | 
			
		||||
	if msg.ID != "" {
 | 
			
		||||
		b.Log.Debugf("updating message with id %s", msg.ID)
 | 
			
		||||
 | 
			
		||||
		if b.GetString("editsuffix") != "" {
 | 
			
		||||
			msg.Text += b.GetString("EditSuffix")
 | 
			
		||||
		} else {
 | 
			
		||||
			msg.Text += " (edited)"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Handle Upload a file
 | 
			
		||||
	if msg.Extra["file"] != nil {
 | 
			
		||||
		fi := msg.Extra["file"][0].(config.FileInfo)
 | 
			
		||||
		filetype := mime.TypeByExtension(filepath.Ext(fi.Name))
 | 
			
		||||
 | 
			
		||||
		b.Log.Debugf("Extra file is %#v", filetype)
 | 
			
		||||
 | 
			
		||||
		// TODO: add different types
 | 
			
		||||
		// TODO: add webp conversion
 | 
			
		||||
		switch filetype {
 | 
			
		||||
		case "image/jpeg", "image/png", "image/gif":
 | 
			
		||||
			return b.PostImageMessage(msg, filetype)
 | 
			
		||||
		default:
 | 
			
		||||
			return b.PostDocumentMessage(msg, filetype)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	text := msg.Username + msg.Text
 | 
			
		||||
 | 
			
		||||
	var message proto.Message
 | 
			
		||||
 | 
			
		||||
	message.Conversation = &text
 | 
			
		||||
 | 
			
		||||
	ID := whatsmeow.GenerateMessageID()
 | 
			
		||||
	_, err := b.wc.SendMessage(groupJID, ID, &message)
 | 
			
		||||
 | 
			
		||||
	return ID, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,3 +1,76 @@
 | 
			
		||||
# v1.25.1
 | 
			
		||||
 | 
			
		||||
## Enhancements
 | 
			
		||||
 | 
			
		||||
- matrix: Add KeepQuotedReply option for matrix to fix regression (#1823)
 | 
			
		||||
- slack: Improve Slack attachments formatting (slack) (#1807)
 | 
			
		||||
 | 
			
		||||
## Bugfix
 | 
			
		||||
 | 
			
		||||
- general: Update dependencies (#1813,#1822,#1833)
 | 
			
		||||
- mattermost: Add space between filename and URL (mattermost). Fixes #1820
 | 
			
		||||
- matrix: Update matterbridge/gomatrix. Fixes #1772 (#1803)
 | 
			
		||||
- telegram: Do not modify .webm files (telegram). Fixes #17**88 (#1802)
 | 
			
		||||
- telegram: Do not apply any markup to URL entities (telegram) (#1808)
 | 
			
		||||
- telegram: Fix telegram message deletion request (#1818)
 | 
			
		||||
- vk: Fix UploadMessagesPhoto for vk community chat (vk) (#1812)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@bd808, @chugunov, @sas1024, @SevereCloud, @ValdikSS
 | 
			
		||||
 | 
			
		||||
# v1.25.0
 | 
			
		||||
 | 
			
		||||
## Breaking changes
 | 
			
		||||
 | 
			
		||||
- whatsapp: deprecated, the library <https://github.com/Rhymen/go-whatsapp> isn't maintained anymore.
 | 
			
		||||
We're switching to <https://github.com/tulir/whatsmeow> but as this uses a GPL3 licensed library we can't provide you with binaries.
 | 
			
		||||
You'll need to build it yourself. More information about this can be found here: <https://github.com/42wim/matterbridge#building-with-whatsapp-beta-multidevice-support>
 | 
			
		||||
 | 
			
		||||
## New features
 | 
			
		||||
 | 
			
		||||
- whatsappmulti: whatsapp multidevice support added - more info <https://github.com/42wim/matterbridge#building-with-whatsapp-beta-multidevice-support>
 | 
			
		||||
- general: Add Dockerfile_whatsappmulti for building with WhatsApp Multi-Device support (Whatsmeow) (#1774)
 | 
			
		||||
- telegram: Add UseFullName option (telegram) (#1777)
 | 
			
		||||
- slack: Use slack real name as user name (slack) (#1775)
 | 
			
		||||
 | 
			
		||||
## Enhancements
 | 
			
		||||
 | 
			
		||||
- general: Ignore sending file with comment, if comment contains IgnoreMessages value (#1783)
 | 
			
		||||
- general: Update dependencies (#1784)
 | 
			
		||||
- irc: Update lrstanley/girc dep (#1773)
 | 
			
		||||
- slack: Preserve threading for messages with files (slack) (#1781)
 | 
			
		||||
- telegram: Preserve threading from telegram replies (telegram) (#1776)
 | 
			
		||||
- telegram: Multiple media in one message (telegram) (#1779)
 | 
			
		||||
- whatsapp: Add whatsapp deprecation warning (#1792)
 | 
			
		||||
 | 
			
		||||
## Bugfix
 | 
			
		||||
 | 
			
		||||
- discord: Change discord non-native threading behaviour (discord) (#1791)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@sas1024, @tpxtron
 | 
			
		||||
 | 
			
		||||
# v1.24.1
 | 
			
		||||
 | 
			
		||||
## Enhancements
 | 
			
		||||
 | 
			
		||||
- discord: Switch to discordgo upstream again (#1759)
 | 
			
		||||
- general: Update dependencies and vendor (#1761)
 | 
			
		||||
- general: Create inmessage-logger.tengo (#1688) (#1747)
 | 
			
		||||
- general: Add OpenRC service file (#1746)
 | 
			
		||||
- irc: Refactor utf-8 conversion (irc) (#1767)
 | 
			
		||||
 | 
			
		||||
## Bugfixes
 | 
			
		||||
 | 
			
		||||
- irc: Fix panic in irc. Closes #1751 (#1760)
 | 
			
		||||
- mumble: Implement a workaround to signal Opus support (mumble) (#1764)
 | 
			
		||||
- telegram: Fix for complex-formatted Telegram text (#1765)
 | 
			
		||||
- telegram: Fix Telegram channel title in forwards (#1753)
 | 
			
		||||
- telegram: Fix Telegram Problem (unforwarded formatting and skipping of linebreaks) (#1749)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@s3lph, @ValdikSS, @reckel-jm, @CyberTailor
 | 
			
		||||
 | 
			
		||||
# v1.24.0
 | 
			
		||||
 | 
			
		||||
## New features
 | 
			
		||||
@@ -30,6 +103,9 @@
 | 
			
		||||
- matrix: Make HTMLDisable work correct (matrix) (#1716)
 | 
			
		||||
- whatsapp: Make EditSuffix option actually work (whatsapp). Fixes #1510 (#1728)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@DavyJohnesev, @GoliathLabs, @pontaoski, @PeGaSuS-Coder, @dependabot[bot], @vpzomtrrfrt, @SevereCloud, @soloam, @YashRE42, @danwalmsley, @SuperSandro2000, @inzanity
 | 
			
		||||
 | 
			
		||||
# v1.23.2
 | 
			
		||||
 | 
			
		||||
If you're running whatsapp you should update.
 | 
			
		||||
@@ -38,6 +114,9 @@ If you're running whatsapp you should update.
 | 
			
		||||
 | 
			
		||||
- whatsapp: Update go-whatsapp version (#1630)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@snikpic
 | 
			
		||||
 | 
			
		||||
# v1.23.1
 | 
			
		||||
 | 
			
		||||
If you're running mattermost 6 you should update.
 | 
			
		||||
@@ -52,6 +131,9 @@ If you're running mattermost 6 you should update.
 | 
			
		||||
- xmpp: Use a new msgID when replacing messages (xmpp). Fixes #1584 (#1623)
 | 
			
		||||
- zulip: Add better error handling on Zulip (#1589)
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@Polynomdivision, @minecraftchest1, @alexmv
 | 
			
		||||
 | 
			
		||||
# v1.23.0
 | 
			
		||||
 | 
			
		||||
## New features
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								contrib/inmessage-logger.tengo
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								contrib/inmessage-logger.tengo
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
fmt := import("fmt")
 | 
			
		||||
os := import("os")
 | 
			
		||||
times := import("times")
 | 
			
		||||
 | 
			
		||||
if msgText != "" && msgUsername != "system" {
 | 
			
		||||
    os.chdir("/var/www/matterbridge")
 | 
			
		||||
    file := os.open_file("inmessage.log", os.o_append|os.o_wronly|os.o_create, 0644)
 | 
			
		||||
    file.write_string(fmt.sprintf(
 | 
			
		||||
        "[%s] <%s> %s\n",
 | 
			
		||||
        times.time_format(times.now(), times.format_rfc1123),
 | 
			
		||||
        msgUsername,
 | 
			
		||||
        msgText
 | 
			
		||||
    ))
 | 
			
		||||
    file.close()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								contrib/matterbridge.openrc
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										19
									
								
								contrib/matterbridge.openrc
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
#!/sbin/openrc-run
 | 
			
		||||
# Copyright 2021-2022 Gentoo Authors
 | 
			
		||||
# Distributed under the terms of the GNU General Public License v2
 | 
			
		||||
 | 
			
		||||
command=/usr/bin/matterbridge
 | 
			
		||||
command_args="-conf ${MATTERBRIDGE_CONF:-/etc/matterbridge/bridge.toml} ${MATTERBRIDGE_ARGS}"
 | 
			
		||||
command_user="matterbridge:matterbridge"
 | 
			
		||||
pidfile="/run/${RC_SVCNAME}.pid"
 | 
			
		||||
command_background=1
 | 
			
		||||
output_log="/var/log/${RC_SVCNAME}.log"
 | 
			
		||||
error_log="${output_log}"
 | 
			
		||||
 | 
			
		||||
depend() {
 | 
			
		||||
	need net
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
start_pre() {
 | 
			
		||||
	checkpath -f "${output_log}" -o "${command_user}" || return 1
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
// +build !nowhatsapp
 | 
			
		||||
// +build !whatsappmulti
 | 
			
		||||
 | 
			
		||||
package bridgemap
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								gateway/bridgemap/bwhatsappmulti.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								gateway/bridgemap/bwhatsappmulti.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
// +build whatsappmulti
 | 
			
		||||
 | 
			
		||||
package bridgemap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	bwhatsapp "github.com/42wim/matterbridge/bridge/whatsappmulti"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	FullMap["whatsapp"] = bwhatsapp.New
 | 
			
		||||
}
 | 
			
		||||
@@ -299,13 +299,30 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
 | 
			
		||||
 | 
			
		||||
	igNicks := strings.Fields(gw.Bridges[msg.Account].GetString("IgnoreNicks"))
 | 
			
		||||
	igMessages := strings.Fields(gw.Bridges[msg.Account].GetString("IgnoreMessages"))
 | 
			
		||||
	if gw.ignoreTextEmpty(msg) || gw.ignoreText(msg.Username, igNicks) || gw.ignoreText(msg.Text, igMessages) {
 | 
			
		||||
	if gw.ignoreTextEmpty(msg) || gw.ignoreText(msg.Username, igNicks) || gw.ignoreText(msg.Text, igMessages) || gw.ignoreFilesComment(msg.Extra, igMessages) {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ignoreFilesComment returns true if we need to ignore a file with matched comment.
 | 
			
		||||
func (gw *Gateway) ignoreFilesComment(extra map[string][]interface{}, igMessages []string) bool {
 | 
			
		||||
	if extra == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for _, f := range extra["file"] {
 | 
			
		||||
		fi, ok := f.(config.FileInfo)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if gw.ignoreText(fi.Comment, igMessages) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) string {
 | 
			
		||||
	if dest.GetBool("StripNick") {
 | 
			
		||||
		re := regexp.MustCompile("[^a-zA-Z0-9]+")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										98
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										98
									
								
								go.mod
									
									
									
									
									
								
							@@ -6,55 +6,60 @@ require (
 | 
			
		||||
	github.com/Benau/tgsconverter v0.0.0-20210809170556-99f4a4f6337f
 | 
			
		||||
	github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560
 | 
			
		||||
	github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c
 | 
			
		||||
	github.com/SevereCloud/vksdk/v2 v2.13.1
 | 
			
		||||
	github.com/d5/tengo/v2 v2.10.0
 | 
			
		||||
	github.com/SevereCloud/vksdk/v2 v2.14.0
 | 
			
		||||
	github.com/bwmarrin/discordgo v0.25.0
 | 
			
		||||
	github.com/d5/tengo/v2 v2.10.1
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.1
 | 
			
		||||
	github.com/fsnotify/fsnotify v1.5.1
 | 
			
		||||
	github.com/fsnotify/fsnotify v1.5.4
 | 
			
		||||
	github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
 | 
			
		||||
	github.com/gomarkdown/markdown v0.0.0-20211207152620-5d6539fd8bfc
 | 
			
		||||
	github.com/google/gops v0.3.22
 | 
			
		||||
	github.com/gomarkdown/markdown v0.0.0-20220509074759-a57bf950ab8c
 | 
			
		||||
	github.com/google/gops v0.3.23
 | 
			
		||||
	github.com/gorilla/schema v1.2.0
 | 
			
		||||
	github.com/gorilla/websocket v1.4.2
 | 
			
		||||
	github.com/harmony-development/shibshib v0.0.0-20211127182844-512296f7c548
 | 
			
		||||
	github.com/gorilla/websocket v1.5.0
 | 
			
		||||
	github.com/harmony-development/shibshib v0.0.0-20220101224523-c98059d09cfa
 | 
			
		||||
	github.com/hashicorp/golang-lru v0.5.4
 | 
			
		||||
	github.com/jpillora/backoff v1.0.0
 | 
			
		||||
	github.com/keybase/go-keybase-chat-bot v0.0.0-20211201215354-ee4b23828b55
 | 
			
		||||
	github.com/kyokomi/emoji/v2 v2.2.8
 | 
			
		||||
	github.com/labstack/echo/v4 v4.6.3
 | 
			
		||||
	github.com/lrstanley/girc v0.0.0-20211023233735-147f0ff77566
 | 
			
		||||
	github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
 | 
			
		||||
	github.com/keybase/go-keybase-chat-bot v0.0.0-20220322223021-75d497527469
 | 
			
		||||
	github.com/kyokomi/emoji/v2 v2.2.9
 | 
			
		||||
	github.com/labstack/echo/v4 v4.7.2
 | 
			
		||||
	github.com/lrstanley/girc v0.0.0-20220507183218-96757fe3d2a2
 | 
			
		||||
	github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696
 | 
			
		||||
	github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7
 | 
			
		||||
	github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be
 | 
			
		||||
	github.com/matterbridge/gomatrix v0.0.0-20220411225302-271e5088ea27
 | 
			
		||||
	github.com/matterbridge/gozulipbot v0.0.0-20211023205727-a19d6c1f3b75
 | 
			
		||||
	github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba
 | 
			
		||||
	github.com/matterbridge/matterclient v0.0.0-20211107234719-faca3cd42315
 | 
			
		||||
	github.com/matterbridge/matterclient v0.0.0-20220430213656-07aca2731bc9
 | 
			
		||||
	github.com/mattermost/mattermost-server/v5 v5.39.3
 | 
			
		||||
	github.com/mattermost/mattermost-server/v6 v6.3.0
 | 
			
		||||
	github.com/mattermost/mattermost-server/v6 v6.6.1
 | 
			
		||||
	github.com/mattn/godown v0.0.1
 | 
			
		||||
	github.com/missdeer/golib v1.0.4
 | 
			
		||||
	github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9
 | 
			
		||||
	github.com/mdp/qrterminal v1.0.1
 | 
			
		||||
	github.com/nelsonken/gomf v0.0.0-20190423072027-c65cc0469e94
 | 
			
		||||
	github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
 | 
			
		||||
	github.com/rs/xid v1.3.0
 | 
			
		||||
	github.com/rs/xid v1.4.0
 | 
			
		||||
	github.com/russross/blackfriday v1.6.0
 | 
			
		||||
	github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
 | 
			
		||||
	github.com/shazow/ssh-chat v1.10.1
 | 
			
		||||
	github.com/sirupsen/logrus v1.8.1
 | 
			
		||||
	github.com/slack-go/slack v0.10.0
 | 
			
		||||
	github.com/spf13/viper v1.10.1
 | 
			
		||||
	github.com/stretchr/testify v1.7.0
 | 
			
		||||
	github.com/slack-go/slack v0.10.3
 | 
			
		||||
	github.com/spf13/viper v1.11.0
 | 
			
		||||
	github.com/stretchr/testify v1.7.1
 | 
			
		||||
	github.com/vincent-petithory/dataurl v1.0.0
 | 
			
		||||
	github.com/writeas/go-strip-markdown v2.0.1+incompatible
 | 
			
		||||
	github.com/yaegashi/msgraph.go v0.1.4
 | 
			
		||||
	github.com/zfjagann/golang-ring v0.0.0-20210116075443-7c86fdb43134
 | 
			
		||||
	golang.org/x/image v0.0.0-20211028202545-6944b10bf410
 | 
			
		||||
	golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
 | 
			
		||||
	github.com/zfjagann/golang-ring v0.0.0-20220330170733-19bcea1b6289
 | 
			
		||||
	go.mau.fi/whatsmeow v0.0.0-20220504135614-f1f2a9d231fb
 | 
			
		||||
	golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9
 | 
			
		||||
	golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
 | 
			
		||||
	golang.org/x/text v0.3.7
 | 
			
		||||
	gomod.garykim.dev/nc-talk v0.3.0
 | 
			
		||||
	google.golang.org/protobuf v1.28.0
 | 
			
		||||
	gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376
 | 
			
		||||
	layeh.com/gumble v0.0.0-20200818122324-146f9205029b
 | 
			
		||||
	modernc.org/sqlite v1.17.2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	filippo.io/edwards25519 v1.0.0-rc.1 // indirect
 | 
			
		||||
	github.com/Benau/go_rlottie v0.0.0-20210807002906-98c1b2421989 // indirect
 | 
			
		||||
	github.com/Jeffail/gabs v1.4.0 // indirect
 | 
			
		||||
	github.com/apex/log v1.9.0 // indirect
 | 
			
		||||
@@ -68,15 +73,17 @@ require (
 | 
			
		||||
	github.com/golang/protobuf v1.5.2 // indirect
 | 
			
		||||
	github.com/google/uuid v1.3.0 // indirect
 | 
			
		||||
	github.com/gopackage/ddp v0.0.3 // indirect
 | 
			
		||||
	github.com/graph-gophers/graphql-go v1.3.0 // indirect
 | 
			
		||||
	github.com/hashicorp/errwrap v1.1.0 // indirect
 | 
			
		||||
	github.com/hashicorp/go-multierror v1.1.1 // indirect
 | 
			
		||||
	github.com/hashicorp/hcl v1.0.0 // indirect
 | 
			
		||||
	github.com/json-iterator/go v1.1.12 // indirect
 | 
			
		||||
	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
 | 
			
		||||
	github.com/kettek/apng v0.0.0-20191108220231-414630eed80f // indirect
 | 
			
		||||
	github.com/klauspost/compress v1.14.2 // indirect
 | 
			
		||||
	github.com/klauspost/cpuid/v2 v2.0.9 // indirect
 | 
			
		||||
	github.com/klauspost/compress v1.15.1 // indirect
 | 
			
		||||
	github.com/klauspost/cpuid/v2 v2.0.11 // indirect
 | 
			
		||||
	github.com/labstack/gommon v0.3.1 // indirect
 | 
			
		||||
	github.com/magiconair/properties v1.8.5 // indirect
 | 
			
		||||
	github.com/magiconair/properties v1.8.6 // indirect
 | 
			
		||||
	github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect
 | 
			
		||||
	github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d // indirect
 | 
			
		||||
	github.com/mattermost/logr v1.0.13 // indirect
 | 
			
		||||
@@ -86,7 +93,7 @@ require (
 | 
			
		||||
	github.com/mattn/go-runewidth v0.0.13 // indirect
 | 
			
		||||
	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
 | 
			
		||||
	github.com/minio/md5-simd v1.1.2 // indirect
 | 
			
		||||
	github.com/minio/minio-go/v7 v7.0.16 // indirect
 | 
			
		||||
	github.com/minio/minio-go/v7 v7.0.23 // indirect
 | 
			
		||||
	github.com/minio/sha256-simd v1.0.0 // indirect
 | 
			
		||||
	github.com/mitchellh/go-homedir v1.1.0 // indirect
 | 
			
		||||
	github.com/mitchellh/mapstructure v1.4.3 // indirect
 | 
			
		||||
@@ -95,18 +102,21 @@ require (
 | 
			
		||||
	github.com/monaco-io/request v1.0.5 // indirect
 | 
			
		||||
	github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d // indirect
 | 
			
		||||
	github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect
 | 
			
		||||
	github.com/opentracing/opentracing-go v1.2.0 // indirect
 | 
			
		||||
	github.com/pborman/uuid v1.2.1 // indirect
 | 
			
		||||
	github.com/pelletier/go-toml v1.9.4 // indirect
 | 
			
		||||
	github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect
 | 
			
		||||
	github.com/philhofer/fwd v1.1.1 // indirect
 | 
			
		||||
	github.com/pkg/errors v0.9.1 // indirect
 | 
			
		||||
	github.com/pmezard/go-difflib v1.0.0 // indirect
 | 
			
		||||
	github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
 | 
			
		||||
	github.com/rickb777/date v1.12.4 // indirect
 | 
			
		||||
	github.com/rickb777/plural v1.2.0 // indirect
 | 
			
		||||
	github.com/rivo/uniseg v0.2.0 // indirect
 | 
			
		||||
	github.com/shazow/rateio v0.0.0-20200113175441-4461efc8bdc4 // indirect
 | 
			
		||||
	github.com/sizeofint/webpanimation v0.0.0-20210809145948-1d2b32119882 // indirect
 | 
			
		||||
	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
 | 
			
		||||
	github.com/spf13/afero v1.6.0 // indirect
 | 
			
		||||
	github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 // indirect
 | 
			
		||||
	github.com/spf13/afero v1.8.2 // indirect
 | 
			
		||||
	github.com/spf13/cast v1.4.1 // indirect
 | 
			
		||||
	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 | 
			
		||||
	github.com/spf13/pflag v1.0.5 // indirect
 | 
			
		||||
@@ -119,23 +129,35 @@ require (
 | 
			
		||||
	github.com/wiggin77/cfg v1.0.2 // indirect
 | 
			
		||||
	github.com/wiggin77/merror v1.0.3 // indirect
 | 
			
		||||
	github.com/wiggin77/srslog v1.0.1 // indirect
 | 
			
		||||
	go.mau.fi/libsignal v0.0.0-20220425070825-c40c839ee6a0 // indirect
 | 
			
		||||
	go.uber.org/atomic v1.9.0 // indirect
 | 
			
		||||
	go.uber.org/multierr v1.7.0 // indirect
 | 
			
		||||
	go.uber.org/zap v1.17.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect
 | 
			
		||||
	golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 // indirect
 | 
			
		||||
	golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
 | 
			
		||||
	golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
 | 
			
		||||
	golang.org/x/text v0.3.7 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
 | 
			
		||||
	golang.org/x/mod v0.5.1 // indirect
 | 
			
		||||
	golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
 | 
			
		||||
	golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
 | 
			
		||||
	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
 | 
			
		||||
	golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
 | 
			
		||||
	golang.org/x/tools v0.1.9 // indirect
 | 
			
		||||
	golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
 | 
			
		||||
	google.golang.org/appengine v1.6.7 // indirect
 | 
			
		||||
	google.golang.org/protobuf v1.27.1 // indirect
 | 
			
		||||
	gopkg.in/ini.v1 v1.66.2 // indirect
 | 
			
		||||
	gopkg.in/ini.v1 v1.66.4 // indirect
 | 
			
		||||
	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
 | 
			
		||||
	gopkg.in/yaml.v2 v2.4.0 // indirect
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
 | 
			
		||||
	lukechampine.com/uint128 v1.1.1 // indirect
 | 
			
		||||
	modernc.org/cc/v3 v3.36.0 // indirect
 | 
			
		||||
	modernc.org/ccgo/v3 v3.16.6 // indirect
 | 
			
		||||
	modernc.org/libc v1.16.7 // indirect
 | 
			
		||||
	modernc.org/mathutil v1.4.1 // indirect
 | 
			
		||||
	modernc.org/memory v1.1.1 // indirect
 | 
			
		||||
	modernc.org/opt v0.1.1 // indirect
 | 
			
		||||
	modernc.org/strutil v1.1.1 // indirect
 | 
			
		||||
	modernc.org/token v1.0.0 // indirect
 | 
			
		||||
	rsc.io/qr v0.2.0 // indirect
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
replace github.com/matrix-org/gomatrix => github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419
 | 
			
		||||
//replace github.com/matrix-org/gomatrix => github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419
 | 
			
		||||
 | 
			
		||||
go 1.17
 | 
			
		||||
 
 | 
			
		||||
@@ -862,6 +862,10 @@ ShowUserTyping=false
 | 
			
		||||
#Default "<clipped message>"
 | 
			
		||||
MessageClipped="<clipped message>"
 | 
			
		||||
 | 
			
		||||
#If enabled use the slack "Real Name" as username.
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
UseFullName=false
 | 
			
		||||
 | 
			
		||||
###################################################################
 | 
			
		||||
#discord section
 | 
			
		||||
###################################################################
 | 
			
		||||
@@ -1036,6 +1040,12 @@ DisableWebPagePreview=false
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
UseFirstName=false
 | 
			
		||||
 | 
			
		||||
#If enabled use the "Full Name" as username. If this is empty use the Username
 | 
			
		||||
#If disabled use the "Username" as username. If this is empty use the First Name and Last Name as Full Name
 | 
			
		||||
#If all names are empty, username will be "unknown"
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
UseFullName=false
 | 
			
		||||
 | 
			
		||||
#WARNING! If enabled this will relay GIF/stickers/documents and other attachments as URLs
 | 
			
		||||
#Those URLs will contain your bot-token. This may not be what you want.
 | 
			
		||||
#For now there is no secure way to relay GIF/stickers/documents without seeing your token.
 | 
			
		||||
@@ -1141,6 +1151,12 @@ StripNick=false
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
ShowTopicChange=false
 | 
			
		||||
 | 
			
		||||
#Opportunistically preserve threaded replies between Telegram groups.
 | 
			
		||||
#This only works if the parent message is still in the cache.
 | 
			
		||||
#Cache is flushed between restarts.
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
PreserveThreading=false
 | 
			
		||||
 | 
			
		||||
###################################################################
 | 
			
		||||
#rocketchat section
 | 
			
		||||
###################################################################
 | 
			
		||||
@@ -1312,6 +1328,15 @@ HTMLDisable=false
 | 
			
		||||
# UseUserName shows the username instead of the server nickname
 | 
			
		||||
UseUserName=false
 | 
			
		||||
 | 
			
		||||
# Matrix quotes replies and as of matterbridge 1.24.0 we strip those as this causes
 | 
			
		||||
# issues with bridges support threading and have PreserveThreading enabled.
 | 
			
		||||
# But if you for example use mattermost or discord with webhooks you'll need to enable 
 | 
			
		||||
# this (and keep PreserveThreading disabled) if you want something that looks like a reply from matrix.
 | 
			
		||||
# See issues: 
 | 
			
		||||
# - https://github.com/42wim/matterbridge/issues/1819
 | 
			
		||||
# - https://github.com/42wim/matterbridge/issues/1780
 | 
			
		||||
KeepQuotedReply=false
 | 
			
		||||
 | 
			
		||||
#Nicks you want to ignore.
 | 
			
		||||
#Regular expressions supported
 | 
			
		||||
#Messages from those users will not be sent to other bridges.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/filippo.io/edwards25519/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/filippo.io/edwards25519/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
Copyright (c) 2009 The Go Authors. All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are
 | 
			
		||||
met:
 | 
			
		||||
 | 
			
		||||
   * Redistributions of source code must retain the above copyright
 | 
			
		||||
notice, this list of conditions and the following disclaimer.
 | 
			
		||||
   * Redistributions in binary form must reproduce the above
 | 
			
		||||
copyright notice, this list of conditions and the following disclaimer
 | 
			
		||||
in the documentation and/or other materials provided with the
 | 
			
		||||
distribution.
 | 
			
		||||
   * Neither the name of Google Inc. nor the names of its
 | 
			
		||||
contributors may be used to endorse or promote products derived from
 | 
			
		||||
this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
			
		||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
			
		||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
			
		||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										14
									
								
								vendor/filippo.io/edwards25519/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vendor/filippo.io/edwards25519/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
# filippo.io/edwards25519
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
import "filippo.io/edwards25519"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This library implements the edwards25519 elliptic curve, exposing the necessary APIs to build a wide array of higher-level primitives.
 | 
			
		||||
Read the docs at [pkg.go.dev/filippo.io/edwards25519](https://pkg.go.dev/filippo.io/edwards25519).
 | 
			
		||||
 | 
			
		||||
The code is originally derived from Adam Langley's internal implementation in the Go standard library, and includes George Tankersley's [performance improvements](https://golang.org/cl/71950). It was then further developed by Henry de Valence for use in ristretto255.
 | 
			
		||||
 | 
			
		||||
Most users don't need this package, and should instead use `crypto/ed25519` for signatures, `golang.org/x/crypto/curve25519` for Diffie-Hellman, or `github.com/gtank/ristretto255` for prime order group logic. However, for anyone currently using a fork of `crypto/ed25519/internal/edwards25519` or `github.com/agl/edwards25519`, this package should be a safer, faster, and more powerful alternative.
 | 
			
		||||
 | 
			
		||||
Since this package is meant to curb proliferation of edwards25519 implementations in the Go ecosystem, it welcomes requests for new APIs or reviewable performance improvements.
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/filippo.io/edwards25519/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/filippo.io/edwards25519/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
// Copyright (c) 2021 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package edwards25519 implements group logic for the twisted Edwards curve
 | 
			
		||||
//
 | 
			
		||||
//     -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2
 | 
			
		||||
//
 | 
			
		||||
// This is better known as the Edwards curve equivalent to Curve25519, and is
 | 
			
		||||
// the curve used by the Ed25519 signature scheme.
 | 
			
		||||
//
 | 
			
		||||
// Most users don't need this package, and should instead use crypto/ed25519 for
 | 
			
		||||
// signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or
 | 
			
		||||
// github.com/gtank/ristretto255 for prime order group logic.
 | 
			
		||||
//
 | 
			
		||||
// However, developers who do need to interact with low-level edwards25519
 | 
			
		||||
// operations can use this package, which is an extended version of
 | 
			
		||||
// crypto/ed25519/internal/edwards25519 from the standard library repackaged as
 | 
			
		||||
// an importable module.
 | 
			
		||||
package edwards25519
 | 
			
		||||
							
								
								
									
										428
									
								
								vendor/filippo.io/edwards25519/edwards25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										428
									
								
								vendor/filippo.io/edwards25519/edwards25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,428 @@
 | 
			
		||||
// Copyright (c) 2017 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package edwards25519
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"filippo.io/edwards25519/field"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Point types.
 | 
			
		||||
 | 
			
		||||
type projP1xP1 struct {
 | 
			
		||||
	X, Y, Z, T field.Element
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type projP2 struct {
 | 
			
		||||
	X, Y, Z field.Element
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Point represents a point on the edwards25519 curve.
 | 
			
		||||
//
 | 
			
		||||
// This type works similarly to math/big.Int, and all arguments and receivers
 | 
			
		||||
// are allowed to alias.
 | 
			
		||||
//
 | 
			
		||||
// The zero value is NOT valid, and it may be used only as a receiver.
 | 
			
		||||
type Point struct {
 | 
			
		||||
	// The point is internally represented in extended coordinates (X, Y, Z, T)
 | 
			
		||||
	// where x = X/Z, y = Y/Z, and xy = T/Z per https://eprint.iacr.org/2008/522.
 | 
			
		||||
	x, y, z, t field.Element
 | 
			
		||||
 | 
			
		||||
	// Make the type not comparable (i.e. used with == or as a map key), as
 | 
			
		||||
	// equivalent points can be represented by different Go values.
 | 
			
		||||
	_ incomparable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type incomparable [0]func()
 | 
			
		||||
 | 
			
		||||
func checkInitialized(points ...*Point) {
 | 
			
		||||
	for _, p := range points {
 | 
			
		||||
		if p.x == (field.Element{}) && p.y == (field.Element{}) {
 | 
			
		||||
			panic("edwards25519: use of uninitialized Point")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type projCached struct {
 | 
			
		||||
	YplusX, YminusX, Z, T2d field.Element
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type affineCached struct {
 | 
			
		||||
	YplusX, YminusX, T2d field.Element
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Constructors.
 | 
			
		||||
 | 
			
		||||
func (v *projP2) Zero() *projP2 {
 | 
			
		||||
	v.X.Zero()
 | 
			
		||||
	v.Y.One()
 | 
			
		||||
	v.Z.One()
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// identity is the point at infinity.
 | 
			
		||||
var identity, _ = new(Point).SetBytes([]byte{
 | 
			
		||||
	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
 | 
			
		||||
 | 
			
		||||
// NewIdentityPoint returns a new Point set to the identity.
 | 
			
		||||
func NewIdentityPoint() *Point {
 | 
			
		||||
	return new(Point).Set(identity)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generator is the canonical curve basepoint. See TestGenerator for the
 | 
			
		||||
// correspondence of this encoding with the values in RFC 8032.
 | 
			
		||||
var generator, _ = new(Point).SetBytes([]byte{
 | 
			
		||||
	0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
 | 
			
		||||
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
 | 
			
		||||
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
 | 
			
		||||
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66})
 | 
			
		||||
 | 
			
		||||
// NewGeneratorPoint returns a new Point set to the canonical generator.
 | 
			
		||||
func NewGeneratorPoint() *Point {
 | 
			
		||||
	return new(Point).Set(generator)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *projCached) Zero() *projCached {
 | 
			
		||||
	v.YplusX.One()
 | 
			
		||||
	v.YminusX.One()
 | 
			
		||||
	v.Z.One()
 | 
			
		||||
	v.T2d.Zero()
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *affineCached) Zero() *affineCached {
 | 
			
		||||
	v.YplusX.One()
 | 
			
		||||
	v.YminusX.One()
 | 
			
		||||
	v.T2d.Zero()
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Assignments.
 | 
			
		||||
 | 
			
		||||
// Set sets v = u, and returns v.
 | 
			
		||||
func (v *Point) Set(u *Point) *Point {
 | 
			
		||||
	*v = *u
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Encoding.
 | 
			
		||||
 | 
			
		||||
// Bytes returns the canonical 32-byte encoding of v, according to RFC 8032,
 | 
			
		||||
// Section 5.1.2.
 | 
			
		||||
func (v *Point) Bytes() []byte {
 | 
			
		||||
	// This function is outlined to make the allocations inline in the caller
 | 
			
		||||
	// rather than happen on the heap.
 | 
			
		||||
	var buf [32]byte
 | 
			
		||||
	return v.bytes(&buf)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Point) bytes(buf *[32]byte) []byte {
 | 
			
		||||
	checkInitialized(v)
 | 
			
		||||
 | 
			
		||||
	var zInv, x, y field.Element
 | 
			
		||||
	zInv.Invert(&v.z)       // zInv = 1 / Z
 | 
			
		||||
	x.Multiply(&v.x, &zInv) // x = X / Z
 | 
			
		||||
	y.Multiply(&v.y, &zInv) // y = Y / Z
 | 
			
		||||
 | 
			
		||||
	out := copyFieldElement(buf, &y)
 | 
			
		||||
	out[31] |= byte(x.IsNegative() << 7)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var feOne = new(field.Element).One()
 | 
			
		||||
 | 
			
		||||
// SetBytes sets v = x, where x is a 32-byte encoding of v. If x does not
 | 
			
		||||
// represent a valid point on the curve, SetBytes returns nil and an error and
 | 
			
		||||
// the receiver is unchanged. Otherwise, SetBytes returns v.
 | 
			
		||||
//
 | 
			
		||||
// Note that SetBytes accepts all non-canonical encodings of valid points.
 | 
			
		||||
// That is, it follows decoding rules that match most implementations in
 | 
			
		||||
// the ecosystem rather than RFC 8032.
 | 
			
		||||
func (v *Point) SetBytes(x []byte) (*Point, error) {
 | 
			
		||||
	// Specifically, the non-canonical encodings that are accepted are
 | 
			
		||||
	//   1) the ones where the field element is not reduced (see the
 | 
			
		||||
	//      (*field.Element).SetBytes docs) and
 | 
			
		||||
	//   2) the ones where the x-coordinate is zero and the sign bit is set.
 | 
			
		||||
	//
 | 
			
		||||
	// This is consistent with crypto/ed25519/internal/edwards25519. Read more
 | 
			
		||||
	// at https://hdevalence.ca/blog/2020-10-04-its-25519am, specifically the
 | 
			
		||||
	// "Canonical A, R" section.
 | 
			
		||||
 | 
			
		||||
	y, err := new(field.Element).SetBytes(x)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("edwards25519: invalid point encoding length")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -x² + y² = 1 + dx²y²
 | 
			
		||||
	// x² + dx²y² = x²(dy² + 1) = y² - 1
 | 
			
		||||
	// x² = (y² - 1) / (dy² + 1)
 | 
			
		||||
 | 
			
		||||
	// u = y² - 1
 | 
			
		||||
	y2 := new(field.Element).Square(y)
 | 
			
		||||
	u := new(field.Element).Subtract(y2, feOne)
 | 
			
		||||
 | 
			
		||||
	// v = dy² + 1
 | 
			
		||||
	vv := new(field.Element).Multiply(y2, d)
 | 
			
		||||
	vv = vv.Add(vv, feOne)
 | 
			
		||||
 | 
			
		||||
	// x = +√(u/v)
 | 
			
		||||
	xx, wasSquare := new(field.Element).SqrtRatio(u, vv)
 | 
			
		||||
	if wasSquare == 0 {
 | 
			
		||||
		return nil, errors.New("edwards25519: invalid point encoding")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Select the negative square root if the sign bit is set.
 | 
			
		||||
	xxNeg := new(field.Element).Negate(xx)
 | 
			
		||||
	xx = xx.Select(xxNeg, xx, int(x[31]>>7))
 | 
			
		||||
 | 
			
		||||
	v.x.Set(xx)
 | 
			
		||||
	v.y.Set(y)
 | 
			
		||||
	v.z.One()
 | 
			
		||||
	v.t.Multiply(xx, y) // xy = T / Z
 | 
			
		||||
 | 
			
		||||
	return v, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyFieldElement(buf *[32]byte, v *field.Element) []byte {
 | 
			
		||||
	copy(buf[:], v.Bytes())
 | 
			
		||||
	return buf[:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Conversions.
 | 
			
		||||
 | 
			
		||||
func (v *projP2) FromP1xP1(p *projP1xP1) *projP2 {
 | 
			
		||||
	v.X.Multiply(&p.X, &p.T)
 | 
			
		||||
	v.Y.Multiply(&p.Y, &p.Z)
 | 
			
		||||
	v.Z.Multiply(&p.Z, &p.T)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *projP2) FromP3(p *Point) *projP2 {
 | 
			
		||||
	v.X.Set(&p.x)
 | 
			
		||||
	v.Y.Set(&p.y)
 | 
			
		||||
	v.Z.Set(&p.z)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Point) fromP1xP1(p *projP1xP1) *Point {
 | 
			
		||||
	v.x.Multiply(&p.X, &p.T)
 | 
			
		||||
	v.y.Multiply(&p.Y, &p.Z)
 | 
			
		||||
	v.z.Multiply(&p.Z, &p.T)
 | 
			
		||||
	v.t.Multiply(&p.X, &p.Y)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Point) fromP2(p *projP2) *Point {
 | 
			
		||||
	v.x.Multiply(&p.X, &p.Z)
 | 
			
		||||
	v.y.Multiply(&p.Y, &p.Z)
 | 
			
		||||
	v.z.Square(&p.Z)
 | 
			
		||||
	v.t.Multiply(&p.X, &p.Y)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// d is a constant in the curve equation.
 | 
			
		||||
var d, _ = new(field.Element).SetBytes([]byte{
 | 
			
		||||
	0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75,
 | 
			
		||||
	0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00,
 | 
			
		||||
	0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c,
 | 
			
		||||
	0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52})
 | 
			
		||||
var d2 = new(field.Element).Add(d, d)
 | 
			
		||||
 | 
			
		||||
func (v *projCached) FromP3(p *Point) *projCached {
 | 
			
		||||
	v.YplusX.Add(&p.y, &p.x)
 | 
			
		||||
	v.YminusX.Subtract(&p.y, &p.x)
 | 
			
		||||
	v.Z.Set(&p.z)
 | 
			
		||||
	v.T2d.Multiply(&p.t, d2)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *affineCached) FromP3(p *Point) *affineCached {
 | 
			
		||||
	v.YplusX.Add(&p.y, &p.x)
 | 
			
		||||
	v.YminusX.Subtract(&p.y, &p.x)
 | 
			
		||||
	v.T2d.Multiply(&p.t, d2)
 | 
			
		||||
 | 
			
		||||
	var invZ field.Element
 | 
			
		||||
	invZ.Invert(&p.z)
 | 
			
		||||
	v.YplusX.Multiply(&v.YplusX, &invZ)
 | 
			
		||||
	v.YminusX.Multiply(&v.YminusX, &invZ)
 | 
			
		||||
	v.T2d.Multiply(&v.T2d, &invZ)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// (Re)addition and subtraction.
 | 
			
		||||
 | 
			
		||||
// Add sets v = p + q, and returns v.
 | 
			
		||||
func (v *Point) Add(p, q *Point) *Point {
 | 
			
		||||
	checkInitialized(p, q)
 | 
			
		||||
	qCached := new(projCached).FromP3(q)
 | 
			
		||||
	result := new(projP1xP1).Add(p, qCached)
 | 
			
		||||
	return v.fromP1xP1(result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Subtract sets v = p - q, and returns v.
 | 
			
		||||
func (v *Point) Subtract(p, q *Point) *Point {
 | 
			
		||||
	checkInitialized(p, q)
 | 
			
		||||
	qCached := new(projCached).FromP3(q)
 | 
			
		||||
	result := new(projP1xP1).Sub(p, qCached)
 | 
			
		||||
	return v.fromP1xP1(result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *projP1xP1) Add(p *Point, q *projCached) *projP1xP1 {
 | 
			
		||||
	var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
 | 
			
		||||
 | 
			
		||||
	YplusX.Add(&p.y, &p.x)
 | 
			
		||||
	YminusX.Subtract(&p.y, &p.x)
 | 
			
		||||
 | 
			
		||||
	PP.Multiply(&YplusX, &q.YplusX)
 | 
			
		||||
	MM.Multiply(&YminusX, &q.YminusX)
 | 
			
		||||
	TT2d.Multiply(&p.t, &q.T2d)
 | 
			
		||||
	ZZ2.Multiply(&p.z, &q.Z)
 | 
			
		||||
 | 
			
		||||
	ZZ2.Add(&ZZ2, &ZZ2)
 | 
			
		||||
 | 
			
		||||
	v.X.Subtract(&PP, &MM)
 | 
			
		||||
	v.Y.Add(&PP, &MM)
 | 
			
		||||
	v.Z.Add(&ZZ2, &TT2d)
 | 
			
		||||
	v.T.Subtract(&ZZ2, &TT2d)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *projP1xP1) Sub(p *Point, q *projCached) *projP1xP1 {
 | 
			
		||||
	var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
 | 
			
		||||
 | 
			
		||||
	YplusX.Add(&p.y, &p.x)
 | 
			
		||||
	YminusX.Subtract(&p.y, &p.x)
 | 
			
		||||
 | 
			
		||||
	PP.Multiply(&YplusX, &q.YminusX) // flipped sign
 | 
			
		||||
	MM.Multiply(&YminusX, &q.YplusX) // flipped sign
 | 
			
		||||
	TT2d.Multiply(&p.t, &q.T2d)
 | 
			
		||||
	ZZ2.Multiply(&p.z, &q.Z)
 | 
			
		||||
 | 
			
		||||
	ZZ2.Add(&ZZ2, &ZZ2)
 | 
			
		||||
 | 
			
		||||
	v.X.Subtract(&PP, &MM)
 | 
			
		||||
	v.Y.Add(&PP, &MM)
 | 
			
		||||
	v.Z.Subtract(&ZZ2, &TT2d) // flipped sign
 | 
			
		||||
	v.T.Add(&ZZ2, &TT2d)      // flipped sign
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *projP1xP1) AddAffine(p *Point, q *affineCached) *projP1xP1 {
 | 
			
		||||
	var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
 | 
			
		||||
 | 
			
		||||
	YplusX.Add(&p.y, &p.x)
 | 
			
		||||
	YminusX.Subtract(&p.y, &p.x)
 | 
			
		||||
 | 
			
		||||
	PP.Multiply(&YplusX, &q.YplusX)
 | 
			
		||||
	MM.Multiply(&YminusX, &q.YminusX)
 | 
			
		||||
	TT2d.Multiply(&p.t, &q.T2d)
 | 
			
		||||
 | 
			
		||||
	Z2.Add(&p.z, &p.z)
 | 
			
		||||
 | 
			
		||||
	v.X.Subtract(&PP, &MM)
 | 
			
		||||
	v.Y.Add(&PP, &MM)
 | 
			
		||||
	v.Z.Add(&Z2, &TT2d)
 | 
			
		||||
	v.T.Subtract(&Z2, &TT2d)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *projP1xP1) SubAffine(p *Point, q *affineCached) *projP1xP1 {
 | 
			
		||||
	var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
 | 
			
		||||
 | 
			
		||||
	YplusX.Add(&p.y, &p.x)
 | 
			
		||||
	YminusX.Subtract(&p.y, &p.x)
 | 
			
		||||
 | 
			
		||||
	PP.Multiply(&YplusX, &q.YminusX) // flipped sign
 | 
			
		||||
	MM.Multiply(&YminusX, &q.YplusX) // flipped sign
 | 
			
		||||
	TT2d.Multiply(&p.t, &q.T2d)
 | 
			
		||||
 | 
			
		||||
	Z2.Add(&p.z, &p.z)
 | 
			
		||||
 | 
			
		||||
	v.X.Subtract(&PP, &MM)
 | 
			
		||||
	v.Y.Add(&PP, &MM)
 | 
			
		||||
	v.Z.Subtract(&Z2, &TT2d) // flipped sign
 | 
			
		||||
	v.T.Add(&Z2, &TT2d)      // flipped sign
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Doubling.
 | 
			
		||||
 | 
			
		||||
func (v *projP1xP1) Double(p *projP2) *projP1xP1 {
 | 
			
		||||
	var XX, YY, ZZ2, XplusYsq field.Element
 | 
			
		||||
 | 
			
		||||
	XX.Square(&p.X)
 | 
			
		||||
	YY.Square(&p.Y)
 | 
			
		||||
	ZZ2.Square(&p.Z)
 | 
			
		||||
	ZZ2.Add(&ZZ2, &ZZ2)
 | 
			
		||||
	XplusYsq.Add(&p.X, &p.Y)
 | 
			
		||||
	XplusYsq.Square(&XplusYsq)
 | 
			
		||||
 | 
			
		||||
	v.Y.Add(&YY, &XX)
 | 
			
		||||
	v.Z.Subtract(&YY, &XX)
 | 
			
		||||
 | 
			
		||||
	v.X.Subtract(&XplusYsq, &v.Y)
 | 
			
		||||
	v.T.Subtract(&ZZ2, &v.Z)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Negation.
 | 
			
		||||
 | 
			
		||||
// Negate sets v = -p, and returns v.
 | 
			
		||||
func (v *Point) Negate(p *Point) *Point {
 | 
			
		||||
	checkInitialized(p)
 | 
			
		||||
	v.x.Negate(&p.x)
 | 
			
		||||
	v.y.Set(&p.y)
 | 
			
		||||
	v.z.Set(&p.z)
 | 
			
		||||
	v.t.Negate(&p.t)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Equal returns 1 if v is equivalent to u, and 0 otherwise.
 | 
			
		||||
func (v *Point) Equal(u *Point) int {
 | 
			
		||||
	checkInitialized(v, u)
 | 
			
		||||
 | 
			
		||||
	var t1, t2, t3, t4 field.Element
 | 
			
		||||
	t1.Multiply(&v.x, &u.z)
 | 
			
		||||
	t2.Multiply(&u.x, &v.z)
 | 
			
		||||
	t3.Multiply(&v.y, &u.z)
 | 
			
		||||
	t4.Multiply(&u.y, &v.z)
 | 
			
		||||
 | 
			
		||||
	return t1.Equal(&t2) & t3.Equal(&t4)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Constant-time operations
 | 
			
		||||
 | 
			
		||||
// Select sets v to a if cond == 1 and to b if cond == 0.
 | 
			
		||||
func (v *projCached) Select(a, b *projCached, cond int) *projCached {
 | 
			
		||||
	v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
 | 
			
		||||
	v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
 | 
			
		||||
	v.Z.Select(&a.Z, &b.Z, cond)
 | 
			
		||||
	v.T2d.Select(&a.T2d, &b.T2d, cond)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Select sets v to a if cond == 1 and to b if cond == 0.
 | 
			
		||||
func (v *affineCached) Select(a, b *affineCached, cond int) *affineCached {
 | 
			
		||||
	v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
 | 
			
		||||
	v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
 | 
			
		||||
	v.T2d.Select(&a.T2d, &b.T2d, cond)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
 | 
			
		||||
func (v *projCached) CondNeg(cond int) *projCached {
 | 
			
		||||
	v.YplusX.Swap(&v.YminusX, cond)
 | 
			
		||||
	v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
 | 
			
		||||
func (v *affineCached) CondNeg(cond int) *affineCached {
 | 
			
		||||
	v.YplusX.Swap(&v.YminusX, cond)
 | 
			
		||||
	v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										343
									
								
								vendor/filippo.io/edwards25519/extra.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								vendor/filippo.io/edwards25519/extra.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,343 @@
 | 
			
		||||
// Copyright (c) 2021 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package edwards25519
 | 
			
		||||
 | 
			
		||||
// This file contains additional functionality that is not included in the
 | 
			
		||||
// upstream crypto/ed25519/internal/edwards25519 package.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"filippo.io/edwards25519/field"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ExtendedCoordinates returns v in extended coordinates (X:Y:Z:T) where
 | 
			
		||||
// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
 | 
			
		||||
func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) {
 | 
			
		||||
	// This function is outlined to make the allocations inline in the caller
 | 
			
		||||
	// rather than happen on the heap. Don't change the style without making
 | 
			
		||||
	// sure it doesn't increase the inliner cost.
 | 
			
		||||
	var e [4]field.Element
 | 
			
		||||
	X, Y, Z, T = v.extendedCoordinates(&e)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Point) extendedCoordinates(e *[4]field.Element) (X, Y, Z, T *field.Element) {
 | 
			
		||||
	checkInitialized(v)
 | 
			
		||||
	X = e[0].Set(&v.x)
 | 
			
		||||
	Y = e[1].Set(&v.y)
 | 
			
		||||
	Z = e[2].Set(&v.z)
 | 
			
		||||
	T = e[3].Set(&v.t)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetExtendedCoordinates sets v = (X:Y:Z:T) in extended coordinates where
 | 
			
		||||
// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
 | 
			
		||||
//
 | 
			
		||||
// If the coordinates are invalid or don't represent a valid point on the curve,
 | 
			
		||||
// SetExtendedCoordinates returns nil and an error and the receiver is
 | 
			
		||||
// unchanged. Otherwise, SetExtendedCoordinates returns v.
 | 
			
		||||
func (v *Point) SetExtendedCoordinates(X, Y, Z, T *field.Element) (*Point, error) {
 | 
			
		||||
	if !isOnCurve(X, Y, Z, T) {
 | 
			
		||||
		return nil, errors.New("edwards25519: invalid point coordinates")
 | 
			
		||||
	}
 | 
			
		||||
	v.x.Set(X)
 | 
			
		||||
	v.y.Set(Y)
 | 
			
		||||
	v.z.Set(Z)
 | 
			
		||||
	v.t.Set(T)
 | 
			
		||||
	return v, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isOnCurve(X, Y, Z, T *field.Element) bool {
 | 
			
		||||
	var lhs, rhs field.Element
 | 
			
		||||
	XX := new(field.Element).Square(X)
 | 
			
		||||
	YY := new(field.Element).Square(Y)
 | 
			
		||||
	ZZ := new(field.Element).Square(Z)
 | 
			
		||||
	TT := new(field.Element).Square(T)
 | 
			
		||||
	// -x² + y² = 1 + dx²y²
 | 
			
		||||
	// -(X/Z)² + (Y/Z)² = 1 + d(T/Z)²
 | 
			
		||||
	// -X² + Y² = Z² + dT²
 | 
			
		||||
	lhs.Subtract(YY, XX)
 | 
			
		||||
	rhs.Multiply(d, TT).Add(&rhs, ZZ)
 | 
			
		||||
	if lhs.Equal(&rhs) != 1 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	// xy = T/Z
 | 
			
		||||
	// XY/Z² = T/Z
 | 
			
		||||
	// XY = TZ
 | 
			
		||||
	lhs.Multiply(X, Y)
 | 
			
		||||
	rhs.Multiply(T, Z)
 | 
			
		||||
	return lhs.Equal(&rhs) == 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BytesMontgomery converts v to a point on the birationally-equivalent
 | 
			
		||||
// Curve25519 Montgomery curve, and returns its canonical 32 bytes encoding
 | 
			
		||||
// according to RFC 7748.
 | 
			
		||||
//
 | 
			
		||||
// Note that BytesMontgomery only encodes the u-coordinate, so v and -v encode
 | 
			
		||||
// to the same value. If v is the identity point, BytesMontgomery returns 32
 | 
			
		||||
// zero bytes, analogously to the X25519 function.
 | 
			
		||||
func (v *Point) BytesMontgomery() []byte {
 | 
			
		||||
	// This function is outlined to make the allocations inline in the caller
 | 
			
		||||
	// rather than happen on the heap.
 | 
			
		||||
	var buf [32]byte
 | 
			
		||||
	return v.bytesMontgomery(&buf)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Point) bytesMontgomery(buf *[32]byte) []byte {
 | 
			
		||||
	checkInitialized(v)
 | 
			
		||||
 | 
			
		||||
	// RFC 7748, Section 4.1 provides the bilinear map to calculate the
 | 
			
		||||
	// Montgomery u-coordinate
 | 
			
		||||
	//
 | 
			
		||||
	//              u = (1 + y) / (1 - y)
 | 
			
		||||
	//
 | 
			
		||||
	// where y = Y / Z.
 | 
			
		||||
 | 
			
		||||
	var y, recip, u field.Element
 | 
			
		||||
 | 
			
		||||
	y.Multiply(&v.y, y.Invert(&v.z))        // y = Y / Z
 | 
			
		||||
	recip.Invert(recip.Subtract(feOne, &y)) // r = 1/(1 - y)
 | 
			
		||||
	u.Multiply(u.Add(feOne, &y), &recip)    // u = (1 + y)*r
 | 
			
		||||
 | 
			
		||||
	return copyFieldElement(buf, &u)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MultByCofactor sets v = 8 * p, and returns v.
 | 
			
		||||
func (v *Point) MultByCofactor(p *Point) *Point {
 | 
			
		||||
	checkInitialized(p)
 | 
			
		||||
	result := projP1xP1{}
 | 
			
		||||
	pp := (&projP2{}).FromP3(p)
 | 
			
		||||
	result.Double(pp)
 | 
			
		||||
	pp.FromP1xP1(&result)
 | 
			
		||||
	result.Double(pp)
 | 
			
		||||
	pp.FromP1xP1(&result)
 | 
			
		||||
	result.Double(pp)
 | 
			
		||||
	return v.fromP1xP1(&result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given k > 0, set s = s**(2*i).
 | 
			
		||||
func (s *Scalar) pow2k(k int) {
 | 
			
		||||
	for i := 0; i < k; i++ {
 | 
			
		||||
		s.Multiply(s, s)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Invert sets s to the inverse of a nonzero scalar v, and returns s.
 | 
			
		||||
//
 | 
			
		||||
// If t is zero, Invert returns zero.
 | 
			
		||||
func (s *Scalar) Invert(t *Scalar) *Scalar {
 | 
			
		||||
	// Uses a hardcoded sliding window of width 4.
 | 
			
		||||
	var table [8]Scalar
 | 
			
		||||
	var tt Scalar
 | 
			
		||||
	tt.Multiply(t, t)
 | 
			
		||||
	table[0] = *t
 | 
			
		||||
	for i := 0; i < 7; i++ {
 | 
			
		||||
		table[i+1].Multiply(&table[i], &tt)
 | 
			
		||||
	}
 | 
			
		||||
	// Now table = [t**1, t**3, t**7, t**11, t**13, t**15]
 | 
			
		||||
	// so t**k = t[k/2] for odd k
 | 
			
		||||
 | 
			
		||||
	// To compute the sliding window digits, use the following Sage script:
 | 
			
		||||
 | 
			
		||||
	// sage: import itertools
 | 
			
		||||
	// sage: def sliding_window(w,k):
 | 
			
		||||
	// ....:     digits = []
 | 
			
		||||
	// ....:     while k > 0:
 | 
			
		||||
	// ....:         if k % 2 == 1:
 | 
			
		||||
	// ....:             kmod = k % (2**w)
 | 
			
		||||
	// ....:             digits.append(kmod)
 | 
			
		||||
	// ....:             k = k - kmod
 | 
			
		||||
	// ....:         else:
 | 
			
		||||
	// ....:             digits.append(0)
 | 
			
		||||
	// ....:         k = k // 2
 | 
			
		||||
	// ....:     return digits
 | 
			
		||||
 | 
			
		||||
	// Now we can compute s roughly as follows:
 | 
			
		||||
 | 
			
		||||
	// sage: s = 1
 | 
			
		||||
	// sage: for coeff in reversed(sliding_window(4,l-2)):
 | 
			
		||||
	// ....:     s = s*s
 | 
			
		||||
	// ....:     if coeff > 0 :
 | 
			
		||||
	// ....:         s = s*t**coeff
 | 
			
		||||
 | 
			
		||||
	// This works on one bit at a time, with many runs of zeros.
 | 
			
		||||
	// The digits can be collapsed into [(count, coeff)] as follows:
 | 
			
		||||
 | 
			
		||||
	// sage: [(len(list(group)),d) for d,group in itertools.groupby(sliding_window(4,l-2))]
 | 
			
		||||
 | 
			
		||||
	// Entries of the form (k, 0) turn into pow2k(k)
 | 
			
		||||
	// Entries of the form (1, coeff) turn into a squaring and then a table lookup.
 | 
			
		||||
	// We can fold the squaring into the previous pow2k(k) as pow2k(k+1).
 | 
			
		||||
 | 
			
		||||
	*s = table[1/2]
 | 
			
		||||
	s.pow2k(127 + 1)
 | 
			
		||||
	s.Multiply(s, &table[1/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[9/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[11/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[13/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[15/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[7/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[15/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[5/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[1/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[15/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[15/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[7/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[3/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[11/2])
 | 
			
		||||
	s.pow2k(5 + 1)
 | 
			
		||||
	s.Multiply(s, &table[11/2])
 | 
			
		||||
	s.pow2k(9 + 1)
 | 
			
		||||
	s.Multiply(s, &table[9/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[3/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[3/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[3/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[9/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[7/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[3/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[13/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[7/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[9/2])
 | 
			
		||||
	s.pow2k(3 + 1)
 | 
			
		||||
	s.Multiply(s, &table[15/2])
 | 
			
		||||
	s.pow2k(4 + 1)
 | 
			
		||||
	s.Multiply(s, &table[11/2])
 | 
			
		||||
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v.
 | 
			
		||||
//
 | 
			
		||||
// Execution time depends only on the lengths of the two slices, which must match.
 | 
			
		||||
func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point {
 | 
			
		||||
	if len(scalars) != len(points) {
 | 
			
		||||
		panic("edwards25519: called MultiScalarMult with different size inputs")
 | 
			
		||||
	}
 | 
			
		||||
	checkInitialized(points...)
 | 
			
		||||
 | 
			
		||||
	// Proceed as in the single-base case, but share doublings
 | 
			
		||||
	// between each point in the multiscalar equation.
 | 
			
		||||
 | 
			
		||||
	// Build lookup tables for each point
 | 
			
		||||
	tables := make([]projLookupTable, len(points))
 | 
			
		||||
	for i := range tables {
 | 
			
		||||
		tables[i].FromP3(points[i])
 | 
			
		||||
	}
 | 
			
		||||
	// Compute signed radix-16 digits for each scalar
 | 
			
		||||
	digits := make([][64]int8, len(scalars))
 | 
			
		||||
	for i := range digits {
 | 
			
		||||
		digits[i] = scalars[i].signedRadix16()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Unwrap first loop iteration to save computing 16*identity
 | 
			
		||||
	multiple := &projCached{}
 | 
			
		||||
	tmp1 := &projP1xP1{}
 | 
			
		||||
	tmp2 := &projP2{}
 | 
			
		||||
	// Lookup-and-add the appropriate multiple of each input point
 | 
			
		||||
	for j := range tables {
 | 
			
		||||
		tables[j].SelectInto(multiple, digits[j][63])
 | 
			
		||||
		tmp1.Add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords
 | 
			
		||||
		v.fromP1xP1(tmp1)     // update v
 | 
			
		||||
	}
 | 
			
		||||
	tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration
 | 
			
		||||
	for i := 62; i >= 0; i-- {
 | 
			
		||||
		tmp1.Double(tmp2)    // tmp1 =  2*(prev) in P1xP1 coords
 | 
			
		||||
		tmp2.FromP1xP1(tmp1) // tmp2 =  2*(prev) in P2 coords
 | 
			
		||||
		tmp1.Double(tmp2)    // tmp1 =  4*(prev) in P1xP1 coords
 | 
			
		||||
		tmp2.FromP1xP1(tmp1) // tmp2 =  4*(prev) in P2 coords
 | 
			
		||||
		tmp1.Double(tmp2)    // tmp1 =  8*(prev) in P1xP1 coords
 | 
			
		||||
		tmp2.FromP1xP1(tmp1) // tmp2 =  8*(prev) in P2 coords
 | 
			
		||||
		tmp1.Double(tmp2)    // tmp1 = 16*(prev) in P1xP1 coords
 | 
			
		||||
		v.fromP1xP1(tmp1)    //    v = 16*(prev) in P3 coords
 | 
			
		||||
		// Lookup-and-add the appropriate multiple of each input point
 | 
			
		||||
		for j := range tables {
 | 
			
		||||
			tables[j].SelectInto(multiple, digits[j][i])
 | 
			
		||||
			tmp1.Add(v, multiple) // tmp1 = v + x_(j,i)*Q in P1xP1 coords
 | 
			
		||||
			v.fromP1xP1(tmp1)     // update v
 | 
			
		||||
		}
 | 
			
		||||
		tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration
 | 
			
		||||
	}
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VarTimeMultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v.
 | 
			
		||||
//
 | 
			
		||||
// Execution time depends on the inputs.
 | 
			
		||||
func (v *Point) VarTimeMultiScalarMult(scalars []*Scalar, points []*Point) *Point {
 | 
			
		||||
	if len(scalars) != len(points) {
 | 
			
		||||
		panic("edwards25519: called VarTimeMultiScalarMult with different size inputs")
 | 
			
		||||
	}
 | 
			
		||||
	checkInitialized(points...)
 | 
			
		||||
 | 
			
		||||
	// Generalize double-base NAF computation to arbitrary sizes.
 | 
			
		||||
	// Here all the points are dynamic, so we only use the smaller
 | 
			
		||||
	// tables.
 | 
			
		||||
 | 
			
		||||
	// Build lookup tables for each point
 | 
			
		||||
	tables := make([]nafLookupTable5, len(points))
 | 
			
		||||
	for i := range tables {
 | 
			
		||||
		tables[i].FromP3(points[i])
 | 
			
		||||
	}
 | 
			
		||||
	// Compute a NAF for each scalar
 | 
			
		||||
	nafs := make([][256]int8, len(scalars))
 | 
			
		||||
	for i := range nafs {
 | 
			
		||||
		nafs[i] = scalars[i].nonAdjacentForm(5)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	multiple := &projCached{}
 | 
			
		||||
	tmp1 := &projP1xP1{}
 | 
			
		||||
	tmp2 := &projP2{}
 | 
			
		||||
	tmp2.Zero()
 | 
			
		||||
 | 
			
		||||
	// Move from high to low bits, doubling the accumulator
 | 
			
		||||
	// at each iteration and checking whether there is a nonzero
 | 
			
		||||
	// coefficient to look up a multiple of.
 | 
			
		||||
	//
 | 
			
		||||
	// Skip trying to find the first nonzero coefficent, because
 | 
			
		||||
	// searching might be more work than a few extra doublings.
 | 
			
		||||
	for i := 255; i >= 0; i-- {
 | 
			
		||||
		tmp1.Double(tmp2)
 | 
			
		||||
 | 
			
		||||
		for j := range nafs {
 | 
			
		||||
			if nafs[j][i] > 0 {
 | 
			
		||||
				v.fromP1xP1(tmp1)
 | 
			
		||||
				tables[j].SelectInto(multiple, nafs[j][i])
 | 
			
		||||
				tmp1.Add(v, multiple)
 | 
			
		||||
			} else if nafs[j][i] < 0 {
 | 
			
		||||
				v.fromP1xP1(tmp1)
 | 
			
		||||
				tables[j].SelectInto(multiple, -nafs[j][i])
 | 
			
		||||
				tmp1.Sub(v, multiple)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		tmp2.FromP1xP1(tmp1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v.fromP2(tmp2)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										419
									
								
								vendor/filippo.io/edwards25519/field/fe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										419
									
								
								vendor/filippo.io/edwards25519/field/fe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,419 @@
 | 
			
		||||
// Copyright (c) 2017 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package field implements fast arithmetic modulo 2^255-19.
 | 
			
		||||
package field
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"math/bits"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Element represents an element of the field GF(2^255-19). Note that this
 | 
			
		||||
// is not a cryptographically secure group, and should only be used to interact
 | 
			
		||||
// with edwards25519.Point coordinates.
 | 
			
		||||
//
 | 
			
		||||
// This type works similarly to math/big.Int, and all arguments and receivers
 | 
			
		||||
// are allowed to alias.
 | 
			
		||||
//
 | 
			
		||||
// The zero value is a valid zero element.
 | 
			
		||||
type Element struct {
 | 
			
		||||
	// An element t represents the integer
 | 
			
		||||
	//     t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
 | 
			
		||||
	//
 | 
			
		||||
	// Between operations, all limbs are expected to be lower than 2^52.
 | 
			
		||||
	l0 uint64
 | 
			
		||||
	l1 uint64
 | 
			
		||||
	l2 uint64
 | 
			
		||||
	l3 uint64
 | 
			
		||||
	l4 uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const maskLow51Bits uint64 = (1 << 51) - 1
 | 
			
		||||
 | 
			
		||||
var feZero = &Element{0, 0, 0, 0, 0}
 | 
			
		||||
 | 
			
		||||
// Zero sets v = 0, and returns v.
 | 
			
		||||
func (v *Element) Zero() *Element {
 | 
			
		||||
	*v = *feZero
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var feOne = &Element{1, 0, 0, 0, 0}
 | 
			
		||||
 | 
			
		||||
// One sets v = 1, and returns v.
 | 
			
		||||
func (v *Element) One() *Element {
 | 
			
		||||
	*v = *feOne
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// reduce reduces v modulo 2^255 - 19 and returns it.
 | 
			
		||||
func (v *Element) reduce() *Element {
 | 
			
		||||
	v.carryPropagate()
 | 
			
		||||
 | 
			
		||||
	// After the light reduction we now have a field element representation
 | 
			
		||||
	// v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
 | 
			
		||||
 | 
			
		||||
	// If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
 | 
			
		||||
	// generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
 | 
			
		||||
	c := (v.l0 + 19) >> 51
 | 
			
		||||
	c = (v.l1 + c) >> 51
 | 
			
		||||
	c = (v.l2 + c) >> 51
 | 
			
		||||
	c = (v.l3 + c) >> 51
 | 
			
		||||
	c = (v.l4 + c) >> 51
 | 
			
		||||
 | 
			
		||||
	// If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
 | 
			
		||||
	// effectively applying the reduction identity to the carry.
 | 
			
		||||
	v.l0 += 19 * c
 | 
			
		||||
 | 
			
		||||
	v.l1 += v.l0 >> 51
 | 
			
		||||
	v.l0 = v.l0 & maskLow51Bits
 | 
			
		||||
	v.l2 += v.l1 >> 51
 | 
			
		||||
	v.l1 = v.l1 & maskLow51Bits
 | 
			
		||||
	v.l3 += v.l2 >> 51
 | 
			
		||||
	v.l2 = v.l2 & maskLow51Bits
 | 
			
		||||
	v.l4 += v.l3 >> 51
 | 
			
		||||
	v.l3 = v.l3 & maskLow51Bits
 | 
			
		||||
	// no additional carry
 | 
			
		||||
	v.l4 = v.l4 & maskLow51Bits
 | 
			
		||||
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add sets v = a + b, and returns v.
 | 
			
		||||
func (v *Element) Add(a, b *Element) *Element {
 | 
			
		||||
	v.l0 = a.l0 + b.l0
 | 
			
		||||
	v.l1 = a.l1 + b.l1
 | 
			
		||||
	v.l2 = a.l2 + b.l2
 | 
			
		||||
	v.l3 = a.l3 + b.l3
 | 
			
		||||
	v.l4 = a.l4 + b.l4
 | 
			
		||||
	// Using the generic implementation here is actually faster than the
 | 
			
		||||
	// assembly. Probably because the body of this function is so simple that
 | 
			
		||||
	// the compiler can figure out better optimizations by inlining the carry
 | 
			
		||||
	// propagation.
 | 
			
		||||
	return v.carryPropagateGeneric()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Subtract sets v = a - b, and returns v.
 | 
			
		||||
func (v *Element) Subtract(a, b *Element) *Element {
 | 
			
		||||
	// We first add 2 * p, to guarantee the subtraction won't underflow, and
 | 
			
		||||
	// then subtract b (which can be up to 2^255 + 2^13 * 19).
 | 
			
		||||
	v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
 | 
			
		||||
	v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
 | 
			
		||||
	v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
 | 
			
		||||
	v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
 | 
			
		||||
	v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
 | 
			
		||||
	return v.carryPropagate()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Negate sets v = -a, and returns v.
 | 
			
		||||
func (v *Element) Negate(a *Element) *Element {
 | 
			
		||||
	return v.Subtract(feZero, a)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Invert sets v = 1/z mod p, and returns v.
 | 
			
		||||
//
 | 
			
		||||
// If z == 0, Invert returns v = 0.
 | 
			
		||||
func (v *Element) Invert(z *Element) *Element {
 | 
			
		||||
	// Inversion is implemented as exponentiation with exponent p − 2. It uses the
 | 
			
		||||
	// same sequence of 255 squarings and 11 multiplications as [Curve25519].
 | 
			
		||||
	var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
 | 
			
		||||
 | 
			
		||||
	z2.Square(z)             // 2
 | 
			
		||||
	t.Square(&z2)            // 4
 | 
			
		||||
	t.Square(&t)             // 8
 | 
			
		||||
	z9.Multiply(&t, z)       // 9
 | 
			
		||||
	z11.Multiply(&z9, &z2)   // 11
 | 
			
		||||
	t.Square(&z11)           // 22
 | 
			
		||||
	z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
 | 
			
		||||
 | 
			
		||||
	t.Square(&z2_5_0) // 2^6 - 2^1
 | 
			
		||||
	for i := 0; i < 4; i++ {
 | 
			
		||||
		t.Square(&t) // 2^10 - 2^5
 | 
			
		||||
	}
 | 
			
		||||
	z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
 | 
			
		||||
 | 
			
		||||
	t.Square(&z2_10_0) // 2^11 - 2^1
 | 
			
		||||
	for i := 0; i < 9; i++ {
 | 
			
		||||
		t.Square(&t) // 2^20 - 2^10
 | 
			
		||||
	}
 | 
			
		||||
	z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
 | 
			
		||||
 | 
			
		||||
	t.Square(&z2_20_0) // 2^21 - 2^1
 | 
			
		||||
	for i := 0; i < 19; i++ {
 | 
			
		||||
		t.Square(&t) // 2^40 - 2^20
 | 
			
		||||
	}
 | 
			
		||||
	t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
 | 
			
		||||
 | 
			
		||||
	t.Square(&t) // 2^41 - 2^1
 | 
			
		||||
	for i := 0; i < 9; i++ {
 | 
			
		||||
		t.Square(&t) // 2^50 - 2^10
 | 
			
		||||
	}
 | 
			
		||||
	z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
 | 
			
		||||
 | 
			
		||||
	t.Square(&z2_50_0) // 2^51 - 2^1
 | 
			
		||||
	for i := 0; i < 49; i++ {
 | 
			
		||||
		t.Square(&t) // 2^100 - 2^50
 | 
			
		||||
	}
 | 
			
		||||
	z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
 | 
			
		||||
 | 
			
		||||
	t.Square(&z2_100_0) // 2^101 - 2^1
 | 
			
		||||
	for i := 0; i < 99; i++ {
 | 
			
		||||
		t.Square(&t) // 2^200 - 2^100
 | 
			
		||||
	}
 | 
			
		||||
	t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
 | 
			
		||||
 | 
			
		||||
	t.Square(&t) // 2^201 - 2^1
 | 
			
		||||
	for i := 0; i < 49; i++ {
 | 
			
		||||
		t.Square(&t) // 2^250 - 2^50
 | 
			
		||||
	}
 | 
			
		||||
	t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
 | 
			
		||||
 | 
			
		||||
	t.Square(&t) // 2^251 - 2^1
 | 
			
		||||
	t.Square(&t) // 2^252 - 2^2
 | 
			
		||||
	t.Square(&t) // 2^253 - 2^3
 | 
			
		||||
	t.Square(&t) // 2^254 - 2^4
 | 
			
		||||
	t.Square(&t) // 2^255 - 2^5
 | 
			
		||||
 | 
			
		||||
	return v.Multiply(&t, &z11) // 2^255 - 21
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set sets v = a, and returns v.
 | 
			
		||||
func (v *Element) Set(a *Element) *Element {
 | 
			
		||||
	*v = *a
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetBytes sets v to x, where x is a 32-byte little-endian encoding. If x is
 | 
			
		||||
// not of the right length, SetUniformBytes returns nil and an error, and the
 | 
			
		||||
// receiver is unchanged.
 | 
			
		||||
//
 | 
			
		||||
// Consistent with RFC 7748, the most significant bit (the high bit of the
 | 
			
		||||
// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
 | 
			
		||||
// are accepted. Note that this is laxer than specified by RFC 8032.
 | 
			
		||||
func (v *Element) SetBytes(x []byte) (*Element, error) {
 | 
			
		||||
	if len(x) != 32 {
 | 
			
		||||
		return nil, errors.New("edwards25519: invalid field element input size")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
 | 
			
		||||
	v.l0 = binary.LittleEndian.Uint64(x[0:8])
 | 
			
		||||
	v.l0 &= maskLow51Bits
 | 
			
		||||
	// Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
 | 
			
		||||
	v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
 | 
			
		||||
	v.l1 &= maskLow51Bits
 | 
			
		||||
	// Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
 | 
			
		||||
	v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
 | 
			
		||||
	v.l2 &= maskLow51Bits
 | 
			
		||||
	// Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
 | 
			
		||||
	v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
 | 
			
		||||
	v.l3 &= maskLow51Bits
 | 
			
		||||
	// Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51).
 | 
			
		||||
	// Note: not bytes 25:33, shift 4, to avoid overread.
 | 
			
		||||
	v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
 | 
			
		||||
	v.l4 &= maskLow51Bits
 | 
			
		||||
 | 
			
		||||
	return v, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Bytes returns the canonical 32-byte little-endian encoding of v.
 | 
			
		||||
func (v *Element) Bytes() []byte {
 | 
			
		||||
	// This function is outlined to make the allocations inline in the caller
 | 
			
		||||
	// rather than happen on the heap.
 | 
			
		||||
	var out [32]byte
 | 
			
		||||
	return v.bytes(&out)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Element) bytes(out *[32]byte) []byte {
 | 
			
		||||
	t := *v
 | 
			
		||||
	t.reduce()
 | 
			
		||||
 | 
			
		||||
	var buf [8]byte
 | 
			
		||||
	for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
 | 
			
		||||
		bitsOffset := i * 51
 | 
			
		||||
		binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8))
 | 
			
		||||
		for i, bb := range buf {
 | 
			
		||||
			off := bitsOffset/8 + i
 | 
			
		||||
			if off >= len(out) {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			out[off] |= bb
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return out[:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Equal returns 1 if v and u are equal, and 0 otherwise.
 | 
			
		||||
func (v *Element) Equal(u *Element) int {
 | 
			
		||||
	sa, sv := u.Bytes(), v.Bytes()
 | 
			
		||||
	return subtle.ConstantTimeCompare(sa, sv)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
 | 
			
		||||
func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
 | 
			
		||||
 | 
			
		||||
// Select sets v to a if cond == 1, and to b if cond == 0.
 | 
			
		||||
func (v *Element) Select(a, b *Element, cond int) *Element {
 | 
			
		||||
	m := mask64Bits(cond)
 | 
			
		||||
	v.l0 = (m & a.l0) | (^m & b.l0)
 | 
			
		||||
	v.l1 = (m & a.l1) | (^m & b.l1)
 | 
			
		||||
	v.l2 = (m & a.l2) | (^m & b.l2)
 | 
			
		||||
	v.l3 = (m & a.l3) | (^m & b.l3)
 | 
			
		||||
	v.l4 = (m & a.l4) | (^m & b.l4)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
 | 
			
		||||
func (v *Element) Swap(u *Element, cond int) {
 | 
			
		||||
	m := mask64Bits(cond)
 | 
			
		||||
	t := m & (v.l0 ^ u.l0)
 | 
			
		||||
	v.l0 ^= t
 | 
			
		||||
	u.l0 ^= t
 | 
			
		||||
	t = m & (v.l1 ^ u.l1)
 | 
			
		||||
	v.l1 ^= t
 | 
			
		||||
	u.l1 ^= t
 | 
			
		||||
	t = m & (v.l2 ^ u.l2)
 | 
			
		||||
	v.l2 ^= t
 | 
			
		||||
	u.l2 ^= t
 | 
			
		||||
	t = m & (v.l3 ^ u.l3)
 | 
			
		||||
	v.l3 ^= t
 | 
			
		||||
	u.l3 ^= t
 | 
			
		||||
	t = m & (v.l4 ^ u.l4)
 | 
			
		||||
	v.l4 ^= t
 | 
			
		||||
	u.l4 ^= t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsNegative returns 1 if v is negative, and 0 otherwise.
 | 
			
		||||
func (v *Element) IsNegative() int {
 | 
			
		||||
	return int(v.Bytes()[0] & 1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Absolute sets v to |u|, and returns v.
 | 
			
		||||
func (v *Element) Absolute(u *Element) *Element {
 | 
			
		||||
	return v.Select(new(Element).Negate(u), u, u.IsNegative())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Multiply sets v = x * y, and returns v.
 | 
			
		||||
func (v *Element) Multiply(x, y *Element) *Element {
 | 
			
		||||
	feMul(v, x, y)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Square sets v = x * x, and returns v.
 | 
			
		||||
func (v *Element) Square(x *Element) *Element {
 | 
			
		||||
	feSquare(v, x)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Mult32 sets v = x * y, and returns v.
 | 
			
		||||
func (v *Element) Mult32(x *Element, y uint32) *Element {
 | 
			
		||||
	x0lo, x0hi := mul51(x.l0, y)
 | 
			
		||||
	x1lo, x1hi := mul51(x.l1, y)
 | 
			
		||||
	x2lo, x2hi := mul51(x.l2, y)
 | 
			
		||||
	x3lo, x3hi := mul51(x.l3, y)
 | 
			
		||||
	x4lo, x4hi := mul51(x.l4, y)
 | 
			
		||||
	v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
 | 
			
		||||
	v.l1 = x1lo + x0hi
 | 
			
		||||
	v.l2 = x2lo + x1hi
 | 
			
		||||
	v.l3 = x3lo + x2hi
 | 
			
		||||
	v.l4 = x4lo + x3hi
 | 
			
		||||
	// The hi portions are going to be only 32 bits, plus any previous excess,
 | 
			
		||||
	// so we can skip the carry propagation.
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// mul51 returns lo + hi * 2⁵¹ = a * b.
 | 
			
		||||
func mul51(a uint64, b uint32) (lo uint64, hi uint64) {
 | 
			
		||||
	mh, ml := bits.Mul64(a, uint64(b))
 | 
			
		||||
	lo = ml & maskLow51Bits
 | 
			
		||||
	hi = (mh << 13) | (ml >> 51)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
 | 
			
		||||
func (v *Element) Pow22523(x *Element) *Element {
 | 
			
		||||
	var t0, t1, t2 Element
 | 
			
		||||
 | 
			
		||||
	t0.Square(x)             // x^2
 | 
			
		||||
	t1.Square(&t0)           // x^4
 | 
			
		||||
	t1.Square(&t1)           // x^8
 | 
			
		||||
	t1.Multiply(x, &t1)      // x^9
 | 
			
		||||
	t0.Multiply(&t0, &t1)    // x^11
 | 
			
		||||
	t0.Square(&t0)           // x^22
 | 
			
		||||
	t0.Multiply(&t1, &t0)    // x^31
 | 
			
		||||
	t1.Square(&t0)           // x^62
 | 
			
		||||
	for i := 1; i < 5; i++ { // x^992
 | 
			
		||||
		t1.Square(&t1)
 | 
			
		||||
	}
 | 
			
		||||
	t0.Multiply(&t1, &t0)     // x^1023 -> 1023 = 2^10 - 1
 | 
			
		||||
	t1.Square(&t0)            // 2^11 - 2
 | 
			
		||||
	for i := 1; i < 10; i++ { // 2^20 - 2^10
 | 
			
		||||
		t1.Square(&t1)
 | 
			
		||||
	}
 | 
			
		||||
	t1.Multiply(&t1, &t0)     // 2^20 - 1
 | 
			
		||||
	t2.Square(&t1)            // 2^21 - 2
 | 
			
		||||
	for i := 1; i < 20; i++ { // 2^40 - 2^20
 | 
			
		||||
		t2.Square(&t2)
 | 
			
		||||
	}
 | 
			
		||||
	t1.Multiply(&t2, &t1)     // 2^40 - 1
 | 
			
		||||
	t1.Square(&t1)            // 2^41 - 2
 | 
			
		||||
	for i := 1; i < 10; i++ { // 2^50 - 2^10
 | 
			
		||||
		t1.Square(&t1)
 | 
			
		||||
	}
 | 
			
		||||
	t0.Multiply(&t1, &t0)     // 2^50 - 1
 | 
			
		||||
	t1.Square(&t0)            // 2^51 - 2
 | 
			
		||||
	for i := 1; i < 50; i++ { // 2^100 - 2^50
 | 
			
		||||
		t1.Square(&t1)
 | 
			
		||||
	}
 | 
			
		||||
	t1.Multiply(&t1, &t0)      // 2^100 - 1
 | 
			
		||||
	t2.Square(&t1)             // 2^101 - 2
 | 
			
		||||
	for i := 1; i < 100; i++ { // 2^200 - 2^100
 | 
			
		||||
		t2.Square(&t2)
 | 
			
		||||
	}
 | 
			
		||||
	t1.Multiply(&t2, &t1)     // 2^200 - 1
 | 
			
		||||
	t1.Square(&t1)            // 2^201 - 2
 | 
			
		||||
	for i := 1; i < 50; i++ { // 2^250 - 2^50
 | 
			
		||||
		t1.Square(&t1)
 | 
			
		||||
	}
 | 
			
		||||
	t0.Multiply(&t1, &t0)     // 2^250 - 1
 | 
			
		||||
	t0.Square(&t0)            // 2^251 - 2
 | 
			
		||||
	t0.Square(&t0)            // 2^252 - 4
 | 
			
		||||
	return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
 | 
			
		||||
var sqrtM1 = &Element{1718705420411056, 234908883556509,
 | 
			
		||||
	2233514472574048, 2117202627021982, 765476049583133}
 | 
			
		||||
 | 
			
		||||
// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
 | 
			
		||||
//
 | 
			
		||||
// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
 | 
			
		||||
// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
 | 
			
		||||
// and returns r and 0.
 | 
			
		||||
func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) {
 | 
			
		||||
	var a, b Element
 | 
			
		||||
 | 
			
		||||
	// r = (u * v3) * (u * v7)^((p-5)/8)
 | 
			
		||||
	v2 := a.Square(v)
 | 
			
		||||
	uv3 := b.Multiply(u, b.Multiply(v2, v))
 | 
			
		||||
	uv7 := a.Multiply(uv3, a.Square(v2))
 | 
			
		||||
	r.Multiply(uv3, r.Pow22523(uv7))
 | 
			
		||||
 | 
			
		||||
	check := a.Multiply(v, a.Square(r)) // check = v * r^2
 | 
			
		||||
 | 
			
		||||
	uNeg := b.Negate(u)
 | 
			
		||||
	correctSignSqrt := check.Equal(u)
 | 
			
		||||
	flippedSignSqrt := check.Equal(uNeg)
 | 
			
		||||
	flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1))
 | 
			
		||||
 | 
			
		||||
	rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r
 | 
			
		||||
	// r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
 | 
			
		||||
	r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI)
 | 
			
		||||
 | 
			
		||||
	r.Absolute(r) // Choose the nonnegative square root.
 | 
			
		||||
	return r, correctSignSqrt | flippedSignSqrt
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/filippo.io/edwards25519/field/fe_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/filippo.io/edwards25519/field/fe_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
// +build amd64,gc,!purego
 | 
			
		||||
 | 
			
		||||
package field
 | 
			
		||||
 | 
			
		||||
// feMul sets out = a * b. It works like feMulGeneric.
 | 
			
		||||
//go:noescape
 | 
			
		||||
func feMul(out *Element, a *Element, b *Element)
 | 
			
		||||
 | 
			
		||||
// feSquare sets out = a * a. It works like feSquareGeneric.
 | 
			
		||||
//go:noescape
 | 
			
		||||
func feSquare(out *Element, a *Element)
 | 
			
		||||
							
								
								
									
										378
									
								
								vendor/filippo.io/edwards25519/field/fe_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										378
									
								
								vendor/filippo.io/edwards25519/field/fe_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,378 @@
 | 
			
		||||
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
// +build amd64,gc,!purego
 | 
			
		||||
 | 
			
		||||
#include "textflag.h"
 | 
			
		||||
 | 
			
		||||
// func feMul(out *Element, a *Element, b *Element)
 | 
			
		||||
TEXT ·feMul(SB), NOSPLIT, $0-24
 | 
			
		||||
	MOVQ a+8(FP), CX
 | 
			
		||||
	MOVQ b+16(FP), BX
 | 
			
		||||
 | 
			
		||||
	// r0 = a0×b0
 | 
			
		||||
	MOVQ (CX), AX
 | 
			
		||||
	MULQ (BX)
 | 
			
		||||
	MOVQ AX, DI
 | 
			
		||||
	MOVQ DX, SI
 | 
			
		||||
 | 
			
		||||
	// r0 += 19×a1×b4
 | 
			
		||||
	MOVQ   8(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   32(BX)
 | 
			
		||||
	ADDQ   AX, DI
 | 
			
		||||
	ADCQ   DX, SI
 | 
			
		||||
 | 
			
		||||
	// r0 += 19×a2×b3
 | 
			
		||||
	MOVQ   16(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   24(BX)
 | 
			
		||||
	ADDQ   AX, DI
 | 
			
		||||
	ADCQ   DX, SI
 | 
			
		||||
 | 
			
		||||
	// r0 += 19×a3×b2
 | 
			
		||||
	MOVQ   24(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   16(BX)
 | 
			
		||||
	ADDQ   AX, DI
 | 
			
		||||
	ADCQ   DX, SI
 | 
			
		||||
 | 
			
		||||
	// r0 += 19×a4×b1
 | 
			
		||||
	MOVQ   32(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   8(BX)
 | 
			
		||||
	ADDQ   AX, DI
 | 
			
		||||
	ADCQ   DX, SI
 | 
			
		||||
 | 
			
		||||
	// r1 = a0×b1
 | 
			
		||||
	MOVQ (CX), AX
 | 
			
		||||
	MULQ 8(BX)
 | 
			
		||||
	MOVQ AX, R9
 | 
			
		||||
	MOVQ DX, R8
 | 
			
		||||
 | 
			
		||||
	// r1 += a1×b0
 | 
			
		||||
	MOVQ 8(CX), AX
 | 
			
		||||
	MULQ (BX)
 | 
			
		||||
	ADDQ AX, R9
 | 
			
		||||
	ADCQ DX, R8
 | 
			
		||||
 | 
			
		||||
	// r1 += 19×a2×b4
 | 
			
		||||
	MOVQ   16(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   32(BX)
 | 
			
		||||
	ADDQ   AX, R9
 | 
			
		||||
	ADCQ   DX, R8
 | 
			
		||||
 | 
			
		||||
	// r1 += 19×a3×b3
 | 
			
		||||
	MOVQ   24(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   24(BX)
 | 
			
		||||
	ADDQ   AX, R9
 | 
			
		||||
	ADCQ   DX, R8
 | 
			
		||||
 | 
			
		||||
	// r1 += 19×a4×b2
 | 
			
		||||
	MOVQ   32(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   16(BX)
 | 
			
		||||
	ADDQ   AX, R9
 | 
			
		||||
	ADCQ   DX, R8
 | 
			
		||||
 | 
			
		||||
	// r2 = a0×b2
 | 
			
		||||
	MOVQ (CX), AX
 | 
			
		||||
	MULQ 16(BX)
 | 
			
		||||
	MOVQ AX, R11
 | 
			
		||||
	MOVQ DX, R10
 | 
			
		||||
 | 
			
		||||
	// r2 += a1×b1
 | 
			
		||||
	MOVQ 8(CX), AX
 | 
			
		||||
	MULQ 8(BX)
 | 
			
		||||
	ADDQ AX, R11
 | 
			
		||||
	ADCQ DX, R10
 | 
			
		||||
 | 
			
		||||
	// r2 += a2×b0
 | 
			
		||||
	MOVQ 16(CX), AX
 | 
			
		||||
	MULQ (BX)
 | 
			
		||||
	ADDQ AX, R11
 | 
			
		||||
	ADCQ DX, R10
 | 
			
		||||
 | 
			
		||||
	// r2 += 19×a3×b4
 | 
			
		||||
	MOVQ   24(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   32(BX)
 | 
			
		||||
	ADDQ   AX, R11
 | 
			
		||||
	ADCQ   DX, R10
 | 
			
		||||
 | 
			
		||||
	// r2 += 19×a4×b3
 | 
			
		||||
	MOVQ   32(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   24(BX)
 | 
			
		||||
	ADDQ   AX, R11
 | 
			
		||||
	ADCQ   DX, R10
 | 
			
		||||
 | 
			
		||||
	// r3 = a0×b3
 | 
			
		||||
	MOVQ (CX), AX
 | 
			
		||||
	MULQ 24(BX)
 | 
			
		||||
	MOVQ AX, R13
 | 
			
		||||
	MOVQ DX, R12
 | 
			
		||||
 | 
			
		||||
	// r3 += a1×b2
 | 
			
		||||
	MOVQ 8(CX), AX
 | 
			
		||||
	MULQ 16(BX)
 | 
			
		||||
	ADDQ AX, R13
 | 
			
		||||
	ADCQ DX, R12
 | 
			
		||||
 | 
			
		||||
	// r3 += a2×b1
 | 
			
		||||
	MOVQ 16(CX), AX
 | 
			
		||||
	MULQ 8(BX)
 | 
			
		||||
	ADDQ AX, R13
 | 
			
		||||
	ADCQ DX, R12
 | 
			
		||||
 | 
			
		||||
	// r3 += a3×b0
 | 
			
		||||
	MOVQ 24(CX), AX
 | 
			
		||||
	MULQ (BX)
 | 
			
		||||
	ADDQ AX, R13
 | 
			
		||||
	ADCQ DX, R12
 | 
			
		||||
 | 
			
		||||
	// r3 += 19×a4×b4
 | 
			
		||||
	MOVQ   32(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   32(BX)
 | 
			
		||||
	ADDQ   AX, R13
 | 
			
		||||
	ADCQ   DX, R12
 | 
			
		||||
 | 
			
		||||
	// r4 = a0×b4
 | 
			
		||||
	MOVQ (CX), AX
 | 
			
		||||
	MULQ 32(BX)
 | 
			
		||||
	MOVQ AX, R15
 | 
			
		||||
	MOVQ DX, R14
 | 
			
		||||
 | 
			
		||||
	// r4 += a1×b3
 | 
			
		||||
	MOVQ 8(CX), AX
 | 
			
		||||
	MULQ 24(BX)
 | 
			
		||||
	ADDQ AX, R15
 | 
			
		||||
	ADCQ DX, R14
 | 
			
		||||
 | 
			
		||||
	// r4 += a2×b2
 | 
			
		||||
	MOVQ 16(CX), AX
 | 
			
		||||
	MULQ 16(BX)
 | 
			
		||||
	ADDQ AX, R15
 | 
			
		||||
	ADCQ DX, R14
 | 
			
		||||
 | 
			
		||||
	// r4 += a3×b1
 | 
			
		||||
	MOVQ 24(CX), AX
 | 
			
		||||
	MULQ 8(BX)
 | 
			
		||||
	ADDQ AX, R15
 | 
			
		||||
	ADCQ DX, R14
 | 
			
		||||
 | 
			
		||||
	// r4 += a4×b0
 | 
			
		||||
	MOVQ 32(CX), AX
 | 
			
		||||
	MULQ (BX)
 | 
			
		||||
	ADDQ AX, R15
 | 
			
		||||
	ADCQ DX, R14
 | 
			
		||||
 | 
			
		||||
	// First reduction chain
 | 
			
		||||
	MOVQ   $0x0007ffffffffffff, AX
 | 
			
		||||
	SHLQ   $0x0d, DI, SI
 | 
			
		||||
	SHLQ   $0x0d, R9, R8
 | 
			
		||||
	SHLQ   $0x0d, R11, R10
 | 
			
		||||
	SHLQ   $0x0d, R13, R12
 | 
			
		||||
	SHLQ   $0x0d, R15, R14
 | 
			
		||||
	ANDQ   AX, DI
 | 
			
		||||
	IMUL3Q $0x13, R14, R14
 | 
			
		||||
	ADDQ   R14, DI
 | 
			
		||||
	ANDQ   AX, R9
 | 
			
		||||
	ADDQ   SI, R9
 | 
			
		||||
	ANDQ   AX, R11
 | 
			
		||||
	ADDQ   R8, R11
 | 
			
		||||
	ANDQ   AX, R13
 | 
			
		||||
	ADDQ   R10, R13
 | 
			
		||||
	ANDQ   AX, R15
 | 
			
		||||
	ADDQ   R12, R15
 | 
			
		||||
 | 
			
		||||
	// Second reduction chain (carryPropagate)
 | 
			
		||||
	MOVQ   DI, SI
 | 
			
		||||
	SHRQ   $0x33, SI
 | 
			
		||||
	MOVQ   R9, R8
 | 
			
		||||
	SHRQ   $0x33, R8
 | 
			
		||||
	MOVQ   R11, R10
 | 
			
		||||
	SHRQ   $0x33, R10
 | 
			
		||||
	MOVQ   R13, R12
 | 
			
		||||
	SHRQ   $0x33, R12
 | 
			
		||||
	MOVQ   R15, R14
 | 
			
		||||
	SHRQ   $0x33, R14
 | 
			
		||||
	ANDQ   AX, DI
 | 
			
		||||
	IMUL3Q $0x13, R14, R14
 | 
			
		||||
	ADDQ   R14, DI
 | 
			
		||||
	ANDQ   AX, R9
 | 
			
		||||
	ADDQ   SI, R9
 | 
			
		||||
	ANDQ   AX, R11
 | 
			
		||||
	ADDQ   R8, R11
 | 
			
		||||
	ANDQ   AX, R13
 | 
			
		||||
	ADDQ   R10, R13
 | 
			
		||||
	ANDQ   AX, R15
 | 
			
		||||
	ADDQ   R12, R15
 | 
			
		||||
 | 
			
		||||
	// Store output
 | 
			
		||||
	MOVQ out+0(FP), AX
 | 
			
		||||
	MOVQ DI, (AX)
 | 
			
		||||
	MOVQ R9, 8(AX)
 | 
			
		||||
	MOVQ R11, 16(AX)
 | 
			
		||||
	MOVQ R13, 24(AX)
 | 
			
		||||
	MOVQ R15, 32(AX)
 | 
			
		||||
	RET
 | 
			
		||||
 | 
			
		||||
// func feSquare(out *Element, a *Element)
 | 
			
		||||
TEXT ·feSquare(SB), NOSPLIT, $0-16
 | 
			
		||||
	MOVQ a+8(FP), CX
 | 
			
		||||
 | 
			
		||||
	// r0 = l0×l0
 | 
			
		||||
	MOVQ (CX), AX
 | 
			
		||||
	MULQ (CX)
 | 
			
		||||
	MOVQ AX, SI
 | 
			
		||||
	MOVQ DX, BX
 | 
			
		||||
 | 
			
		||||
	// r0 += 38×l1×l4
 | 
			
		||||
	MOVQ   8(CX), AX
 | 
			
		||||
	IMUL3Q $0x26, AX, AX
 | 
			
		||||
	MULQ   32(CX)
 | 
			
		||||
	ADDQ   AX, SI
 | 
			
		||||
	ADCQ   DX, BX
 | 
			
		||||
 | 
			
		||||
	// r0 += 38×l2×l3
 | 
			
		||||
	MOVQ   16(CX), AX
 | 
			
		||||
	IMUL3Q $0x26, AX, AX
 | 
			
		||||
	MULQ   24(CX)
 | 
			
		||||
	ADDQ   AX, SI
 | 
			
		||||
	ADCQ   DX, BX
 | 
			
		||||
 | 
			
		||||
	// r1 = 2×l0×l1
 | 
			
		||||
	MOVQ (CX), AX
 | 
			
		||||
	SHLQ $0x01, AX
 | 
			
		||||
	MULQ 8(CX)
 | 
			
		||||
	MOVQ AX, R8
 | 
			
		||||
	MOVQ DX, DI
 | 
			
		||||
 | 
			
		||||
	// r1 += 38×l2×l4
 | 
			
		||||
	MOVQ   16(CX), AX
 | 
			
		||||
	IMUL3Q $0x26, AX, AX
 | 
			
		||||
	MULQ   32(CX)
 | 
			
		||||
	ADDQ   AX, R8
 | 
			
		||||
	ADCQ   DX, DI
 | 
			
		||||
 | 
			
		||||
	// r1 += 19×l3×l3
 | 
			
		||||
	MOVQ   24(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   24(CX)
 | 
			
		||||
	ADDQ   AX, R8
 | 
			
		||||
	ADCQ   DX, DI
 | 
			
		||||
 | 
			
		||||
	// r2 = 2×l0×l2
 | 
			
		||||
	MOVQ (CX), AX
 | 
			
		||||
	SHLQ $0x01, AX
 | 
			
		||||
	MULQ 16(CX)
 | 
			
		||||
	MOVQ AX, R10
 | 
			
		||||
	MOVQ DX, R9
 | 
			
		||||
 | 
			
		||||
	// r2 += l1×l1
 | 
			
		||||
	MOVQ 8(CX), AX
 | 
			
		||||
	MULQ 8(CX)
 | 
			
		||||
	ADDQ AX, R10
 | 
			
		||||
	ADCQ DX, R9
 | 
			
		||||
 | 
			
		||||
	// r2 += 38×l3×l4
 | 
			
		||||
	MOVQ   24(CX), AX
 | 
			
		||||
	IMUL3Q $0x26, AX, AX
 | 
			
		||||
	MULQ   32(CX)
 | 
			
		||||
	ADDQ   AX, R10
 | 
			
		||||
	ADCQ   DX, R9
 | 
			
		||||
 | 
			
		||||
	// r3 = 2×l0×l3
 | 
			
		||||
	MOVQ (CX), AX
 | 
			
		||||
	SHLQ $0x01, AX
 | 
			
		||||
	MULQ 24(CX)
 | 
			
		||||
	MOVQ AX, R12
 | 
			
		||||
	MOVQ DX, R11
 | 
			
		||||
 | 
			
		||||
	// r3 += 2×l1×l2
 | 
			
		||||
	MOVQ   8(CX), AX
 | 
			
		||||
	IMUL3Q $0x02, AX, AX
 | 
			
		||||
	MULQ   16(CX)
 | 
			
		||||
	ADDQ   AX, R12
 | 
			
		||||
	ADCQ   DX, R11
 | 
			
		||||
 | 
			
		||||
	// r3 += 19×l4×l4
 | 
			
		||||
	MOVQ   32(CX), AX
 | 
			
		||||
	IMUL3Q $0x13, AX, AX
 | 
			
		||||
	MULQ   32(CX)
 | 
			
		||||
	ADDQ   AX, R12
 | 
			
		||||
	ADCQ   DX, R11
 | 
			
		||||
 | 
			
		||||
	// r4 = 2×l0×l4
 | 
			
		||||
	MOVQ (CX), AX
 | 
			
		||||
	SHLQ $0x01, AX
 | 
			
		||||
	MULQ 32(CX)
 | 
			
		||||
	MOVQ AX, R14
 | 
			
		||||
	MOVQ DX, R13
 | 
			
		||||
 | 
			
		||||
	// r4 += 2×l1×l3
 | 
			
		||||
	MOVQ   8(CX), AX
 | 
			
		||||
	IMUL3Q $0x02, AX, AX
 | 
			
		||||
	MULQ   24(CX)
 | 
			
		||||
	ADDQ   AX, R14
 | 
			
		||||
	ADCQ   DX, R13
 | 
			
		||||
 | 
			
		||||
	// r4 += l2×l2
 | 
			
		||||
	MOVQ 16(CX), AX
 | 
			
		||||
	MULQ 16(CX)
 | 
			
		||||
	ADDQ AX, R14
 | 
			
		||||
	ADCQ DX, R13
 | 
			
		||||
 | 
			
		||||
	// First reduction chain
 | 
			
		||||
	MOVQ   $0x0007ffffffffffff, AX
 | 
			
		||||
	SHLQ   $0x0d, SI, BX
 | 
			
		||||
	SHLQ   $0x0d, R8, DI
 | 
			
		||||
	SHLQ   $0x0d, R10, R9
 | 
			
		||||
	SHLQ   $0x0d, R12, R11
 | 
			
		||||
	SHLQ   $0x0d, R14, R13
 | 
			
		||||
	ANDQ   AX, SI
 | 
			
		||||
	IMUL3Q $0x13, R13, R13
 | 
			
		||||
	ADDQ   R13, SI
 | 
			
		||||
	ANDQ   AX, R8
 | 
			
		||||
	ADDQ   BX, R8
 | 
			
		||||
	ANDQ   AX, R10
 | 
			
		||||
	ADDQ   DI, R10
 | 
			
		||||
	ANDQ   AX, R12
 | 
			
		||||
	ADDQ   R9, R12
 | 
			
		||||
	ANDQ   AX, R14
 | 
			
		||||
	ADDQ   R11, R14
 | 
			
		||||
 | 
			
		||||
	// Second reduction chain (carryPropagate)
 | 
			
		||||
	MOVQ   SI, BX
 | 
			
		||||
	SHRQ   $0x33, BX
 | 
			
		||||
	MOVQ   R8, DI
 | 
			
		||||
	SHRQ   $0x33, DI
 | 
			
		||||
	MOVQ   R10, R9
 | 
			
		||||
	SHRQ   $0x33, R9
 | 
			
		||||
	MOVQ   R12, R11
 | 
			
		||||
	SHRQ   $0x33, R11
 | 
			
		||||
	MOVQ   R14, R13
 | 
			
		||||
	SHRQ   $0x33, R13
 | 
			
		||||
	ANDQ   AX, SI
 | 
			
		||||
	IMUL3Q $0x13, R13, R13
 | 
			
		||||
	ADDQ   R13, SI
 | 
			
		||||
	ANDQ   AX, R8
 | 
			
		||||
	ADDQ   BX, R8
 | 
			
		||||
	ANDQ   AX, R10
 | 
			
		||||
	ADDQ   DI, R10
 | 
			
		||||
	ANDQ   AX, R12
 | 
			
		||||
	ADDQ   R9, R12
 | 
			
		||||
	ANDQ   AX, R14
 | 
			
		||||
	ADDQ   R11, R14
 | 
			
		||||
 | 
			
		||||
	// Store output
 | 
			
		||||
	MOVQ out+0(FP), AX
 | 
			
		||||
	MOVQ SI, (AX)
 | 
			
		||||
	MOVQ R8, 8(AX)
 | 
			
		||||
	MOVQ R10, 16(AX)
 | 
			
		||||
	MOVQ R12, 24(AX)
 | 
			
		||||
	MOVQ R14, 32(AX)
 | 
			
		||||
	RET
 | 
			
		||||
							
								
								
									
										12
									
								
								vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
// Copyright (c) 2019 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
//go:build !amd64 || !gc || purego
 | 
			
		||||
// +build !amd64 !gc purego
 | 
			
		||||
 | 
			
		||||
package field
 | 
			
		||||
 | 
			
		||||
func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
 | 
			
		||||
 | 
			
		||||
func feSquare(v, x *Element) { feSquareGeneric(v, x) }
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/filippo.io/edwards25519/field/fe_arm64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/filippo.io/edwards25519/field/fe_arm64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
// Copyright (c) 2020 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
//go:build arm64 && gc && !purego
 | 
			
		||||
// +build arm64,gc,!purego
 | 
			
		||||
 | 
			
		||||
package field
 | 
			
		||||
 | 
			
		||||
//go:noescape
 | 
			
		||||
func carryPropagate(v *Element)
 | 
			
		||||
 | 
			
		||||
func (v *Element) carryPropagate() *Element {
 | 
			
		||||
	carryPropagate(v)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								vendor/filippo.io/edwards25519/field/fe_arm64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/filippo.io/edwards25519/field/fe_arm64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
// Copyright (c) 2020 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// +build arm64,gc,!purego
 | 
			
		||||
 | 
			
		||||
#include "textflag.h"
 | 
			
		||||
 | 
			
		||||
// carryPropagate works exactly like carryPropagateGeneric and uses the
 | 
			
		||||
// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but
 | 
			
		||||
// avoids loading R0-R4 twice and uses LDP and STP.
 | 
			
		||||
//
 | 
			
		||||
// See https://golang.org/issues/43145 for the main compiler issue.
 | 
			
		||||
//
 | 
			
		||||
// func carryPropagate(v *Element)
 | 
			
		||||
TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8
 | 
			
		||||
	MOVD v+0(FP), R20
 | 
			
		||||
 | 
			
		||||
	LDP 0(R20), (R0, R1)
 | 
			
		||||
	LDP 16(R20), (R2, R3)
 | 
			
		||||
	MOVD 32(R20), R4
 | 
			
		||||
 | 
			
		||||
	AND $0x7ffffffffffff, R0, R10
 | 
			
		||||
	AND $0x7ffffffffffff, R1, R11
 | 
			
		||||
	AND $0x7ffffffffffff, R2, R12
 | 
			
		||||
	AND $0x7ffffffffffff, R3, R13
 | 
			
		||||
	AND $0x7ffffffffffff, R4, R14
 | 
			
		||||
 | 
			
		||||
	ADD R0>>51, R11, R11
 | 
			
		||||
	ADD R1>>51, R12, R12
 | 
			
		||||
	ADD R2>>51, R13, R13
 | 
			
		||||
	ADD R3>>51, R14, R14
 | 
			
		||||
	// R4>>51 * 19 + R10 -> R10
 | 
			
		||||
	LSR $51, R4, R21
 | 
			
		||||
	MOVD $19, R22
 | 
			
		||||
	MADD R22, R10, R21, R10
 | 
			
		||||
 | 
			
		||||
	STP (R10, R11), 0(R20)
 | 
			
		||||
	STP (R12, R13), 16(R20)
 | 
			
		||||
	MOVD R14, 32(R20)
 | 
			
		||||
 | 
			
		||||
	RET
 | 
			
		||||
							
								
								
									
										12
									
								
								vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
// Copyright (c) 2021 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
//go:build !arm64 || !gc || purego
 | 
			
		||||
// +build !arm64 !gc purego
 | 
			
		||||
 | 
			
		||||
package field
 | 
			
		||||
 | 
			
		||||
func (v *Element) carryPropagate() *Element {
 | 
			
		||||
	return v.carryPropagateGeneric()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										264
									
								
								vendor/filippo.io/edwards25519/field/fe_generic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								vendor/filippo.io/edwards25519/field/fe_generic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,264 @@
 | 
			
		||||
// Copyright (c) 2017 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package field
 | 
			
		||||
 | 
			
		||||
import "math/bits"
 | 
			
		||||
 | 
			
		||||
// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
 | 
			
		||||
// bits.Mul64 and bits.Add64 intrinsics.
 | 
			
		||||
type uint128 struct {
 | 
			
		||||
	lo, hi uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// mul64 returns a * b.
 | 
			
		||||
func mul64(a, b uint64) uint128 {
 | 
			
		||||
	hi, lo := bits.Mul64(a, b)
 | 
			
		||||
	return uint128{lo, hi}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// addMul64 returns v + a * b.
 | 
			
		||||
func addMul64(v uint128, a, b uint64) uint128 {
 | 
			
		||||
	hi, lo := bits.Mul64(a, b)
 | 
			
		||||
	lo, c := bits.Add64(lo, v.lo, 0)
 | 
			
		||||
	hi, _ = bits.Add64(hi, v.hi, c)
 | 
			
		||||
	return uint128{lo, hi}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits.
 | 
			
		||||
func shiftRightBy51(a uint128) uint64 {
 | 
			
		||||
	return (a.hi << (64 - 51)) | (a.lo >> 51)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func feMulGeneric(v, a, b *Element) {
 | 
			
		||||
	a0 := a.l0
 | 
			
		||||
	a1 := a.l1
 | 
			
		||||
	a2 := a.l2
 | 
			
		||||
	a3 := a.l3
 | 
			
		||||
	a4 := a.l4
 | 
			
		||||
 | 
			
		||||
	b0 := b.l0
 | 
			
		||||
	b1 := b.l1
 | 
			
		||||
	b2 := b.l2
 | 
			
		||||
	b3 := b.l3
 | 
			
		||||
	b4 := b.l4
 | 
			
		||||
 | 
			
		||||
	// Limb multiplication works like pen-and-paper columnar multiplication, but
 | 
			
		||||
	// with 51-bit limbs instead of digits.
 | 
			
		||||
	//
 | 
			
		||||
	//                          a4   a3   a2   a1   a0  x
 | 
			
		||||
	//                          b4   b3   b2   b1   b0  =
 | 
			
		||||
	//                         ------------------------
 | 
			
		||||
	//                        a4b0 a3b0 a2b0 a1b0 a0b0  +
 | 
			
		||||
	//                   a4b1 a3b1 a2b1 a1b1 a0b1       +
 | 
			
		||||
	//              a4b2 a3b2 a2b2 a1b2 a0b2            +
 | 
			
		||||
	//         a4b3 a3b3 a2b3 a1b3 a0b3                 +
 | 
			
		||||
	//    a4b4 a3b4 a2b4 a1b4 a0b4                      =
 | 
			
		||||
	//   ----------------------------------------------
 | 
			
		||||
	//      r8   r7   r6   r5   r4   r3   r2   r1   r0
 | 
			
		||||
	//
 | 
			
		||||
	// We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to
 | 
			
		||||
	// reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5,
 | 
			
		||||
	// r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc.
 | 
			
		||||
	//
 | 
			
		||||
	// Reduction can be carried out simultaneously to multiplication. For
 | 
			
		||||
	// example, we do not compute r5: whenever the result of a multiplication
 | 
			
		||||
	// belongs to r5, like a1b4, we multiply it by 19 and add the result to r0.
 | 
			
		||||
	//
 | 
			
		||||
	//            a4b0    a3b0    a2b0    a1b0    a0b0  +
 | 
			
		||||
	//            a3b1    a2b1    a1b1    a0b1 19×a4b1  +
 | 
			
		||||
	//            a2b2    a1b2    a0b2 19×a4b2 19×a3b2  +
 | 
			
		||||
	//            a1b3    a0b3 19×a4b3 19×a3b3 19×a2b3  +
 | 
			
		||||
	//            a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4  =
 | 
			
		||||
	//           --------------------------------------
 | 
			
		||||
	//              r4      r3      r2      r1      r0
 | 
			
		||||
	//
 | 
			
		||||
	// Finally we add up the columns into wide, overlapping limbs.
 | 
			
		||||
 | 
			
		||||
	a1_19 := a1 * 19
 | 
			
		||||
	a2_19 := a2 * 19
 | 
			
		||||
	a3_19 := a3 * 19
 | 
			
		||||
	a4_19 := a4 * 19
 | 
			
		||||
 | 
			
		||||
	// r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
 | 
			
		||||
	r0 := mul64(a0, b0)
 | 
			
		||||
	r0 = addMul64(r0, a1_19, b4)
 | 
			
		||||
	r0 = addMul64(r0, a2_19, b3)
 | 
			
		||||
	r0 = addMul64(r0, a3_19, b2)
 | 
			
		||||
	r0 = addMul64(r0, a4_19, b1)
 | 
			
		||||
 | 
			
		||||
	// r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
 | 
			
		||||
	r1 := mul64(a0, b1)
 | 
			
		||||
	r1 = addMul64(r1, a1, b0)
 | 
			
		||||
	r1 = addMul64(r1, a2_19, b4)
 | 
			
		||||
	r1 = addMul64(r1, a3_19, b3)
 | 
			
		||||
	r1 = addMul64(r1, a4_19, b2)
 | 
			
		||||
 | 
			
		||||
	// r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
 | 
			
		||||
	r2 := mul64(a0, b2)
 | 
			
		||||
	r2 = addMul64(r2, a1, b1)
 | 
			
		||||
	r2 = addMul64(r2, a2, b0)
 | 
			
		||||
	r2 = addMul64(r2, a3_19, b4)
 | 
			
		||||
	r2 = addMul64(r2, a4_19, b3)
 | 
			
		||||
 | 
			
		||||
	// r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
 | 
			
		||||
	r3 := mul64(a0, b3)
 | 
			
		||||
	r3 = addMul64(r3, a1, b2)
 | 
			
		||||
	r3 = addMul64(r3, a2, b1)
 | 
			
		||||
	r3 = addMul64(r3, a3, b0)
 | 
			
		||||
	r3 = addMul64(r3, a4_19, b4)
 | 
			
		||||
 | 
			
		||||
	// r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
 | 
			
		||||
	r4 := mul64(a0, b4)
 | 
			
		||||
	r4 = addMul64(r4, a1, b3)
 | 
			
		||||
	r4 = addMul64(r4, a2, b2)
 | 
			
		||||
	r4 = addMul64(r4, a3, b1)
 | 
			
		||||
	r4 = addMul64(r4, a4, b0)
 | 
			
		||||
 | 
			
		||||
	// After the multiplication, we need to reduce (carry) the five coefficients
 | 
			
		||||
	// to obtain a result with limbs that are at most slightly larger than 2⁵¹,
 | 
			
		||||
	// to respect the Element invariant.
 | 
			
		||||
	//
 | 
			
		||||
	// Overall, the reduction works the same as carryPropagate, except with
 | 
			
		||||
	// wider inputs: we take the carry for each coefficient by shifting it right
 | 
			
		||||
	// by 51, and add it to the limb above it. The top carry is multiplied by 19
 | 
			
		||||
	// according to the reduction identity and added to the lowest limb.
 | 
			
		||||
	//
 | 
			
		||||
	// The largest coefficient (r0) will be at most 111 bits, which guarantees
 | 
			
		||||
	// that all carries are at most 111 - 51 = 60 bits, which fits in a uint64.
 | 
			
		||||
	//
 | 
			
		||||
	//     r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
 | 
			
		||||
	//     r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²)
 | 
			
		||||
	//     r0 < (1 + 19 × 4) × 2⁵² × 2⁵²
 | 
			
		||||
	//     r0 < 2⁷ × 2⁵² × 2⁵²
 | 
			
		||||
	//     r0 < 2¹¹¹
 | 
			
		||||
	//
 | 
			
		||||
	// Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most
 | 
			
		||||
	// 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and
 | 
			
		||||
	// allows us to easily apply the reduction identity.
 | 
			
		||||
	//
 | 
			
		||||
	//     r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
 | 
			
		||||
	//     r4 < 5 × 2⁵² × 2⁵²
 | 
			
		||||
	//     r4 < 2¹⁰⁷
 | 
			
		||||
	//
 | 
			
		||||
 | 
			
		||||
	c0 := shiftRightBy51(r0)
 | 
			
		||||
	c1 := shiftRightBy51(r1)
 | 
			
		||||
	c2 := shiftRightBy51(r2)
 | 
			
		||||
	c3 := shiftRightBy51(r3)
 | 
			
		||||
	c4 := shiftRightBy51(r4)
 | 
			
		||||
 | 
			
		||||
	rr0 := r0.lo&maskLow51Bits + c4*19
 | 
			
		||||
	rr1 := r1.lo&maskLow51Bits + c0
 | 
			
		||||
	rr2 := r2.lo&maskLow51Bits + c1
 | 
			
		||||
	rr3 := r3.lo&maskLow51Bits + c2
 | 
			
		||||
	rr4 := r4.lo&maskLow51Bits + c3
 | 
			
		||||
 | 
			
		||||
	// Now all coefficients fit into 64-bit registers but are still too large to
 | 
			
		||||
	// be passed around as a Element. We therefore do one last carry chain,
 | 
			
		||||
	// where the carries will be small enough to fit in the wiggle room above 2⁵¹.
 | 
			
		||||
	*v = Element{rr0, rr1, rr2, rr3, rr4}
 | 
			
		||||
	v.carryPropagate()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func feSquareGeneric(v, a *Element) {
 | 
			
		||||
	l0 := a.l0
 | 
			
		||||
	l1 := a.l1
 | 
			
		||||
	l2 := a.l2
 | 
			
		||||
	l3 := a.l3
 | 
			
		||||
	l4 := a.l4
 | 
			
		||||
 | 
			
		||||
	// Squaring works precisely like multiplication above, but thanks to its
 | 
			
		||||
	// symmetry we get to group a few terms together.
 | 
			
		||||
	//
 | 
			
		||||
	//                          l4   l3   l2   l1   l0  x
 | 
			
		||||
	//                          l4   l3   l2   l1   l0  =
 | 
			
		||||
	//                         ------------------------
 | 
			
		||||
	//                        l4l0 l3l0 l2l0 l1l0 l0l0  +
 | 
			
		||||
	//                   l4l1 l3l1 l2l1 l1l1 l0l1       +
 | 
			
		||||
	//              l4l2 l3l2 l2l2 l1l2 l0l2            +
 | 
			
		||||
	//         l4l3 l3l3 l2l3 l1l3 l0l3                 +
 | 
			
		||||
	//    l4l4 l3l4 l2l4 l1l4 l0l4                      =
 | 
			
		||||
	//   ----------------------------------------------
 | 
			
		||||
	//      r8   r7   r6   r5   r4   r3   r2   r1   r0
 | 
			
		||||
	//
 | 
			
		||||
	//            l4l0    l3l0    l2l0    l1l0    l0l0  +
 | 
			
		||||
	//            l3l1    l2l1    l1l1    l0l1 19×l4l1  +
 | 
			
		||||
	//            l2l2    l1l2    l0l2 19×l4l2 19×l3l2  +
 | 
			
		||||
	//            l1l3    l0l3 19×l4l3 19×l3l3 19×l2l3  +
 | 
			
		||||
	//            l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4  =
 | 
			
		||||
	//           --------------------------------------
 | 
			
		||||
	//              r4      r3      r2      r1      r0
 | 
			
		||||
	//
 | 
			
		||||
	// With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with
 | 
			
		||||
	// only three Mul64 and four Add64, instead of five and eight.
 | 
			
		||||
 | 
			
		||||
	l0_2 := l0 * 2
 | 
			
		||||
	l1_2 := l1 * 2
 | 
			
		||||
 | 
			
		||||
	l1_38 := l1 * 38
 | 
			
		||||
	l2_38 := l2 * 38
 | 
			
		||||
	l3_38 := l3 * 38
 | 
			
		||||
 | 
			
		||||
	l3_19 := l3 * 19
 | 
			
		||||
	l4_19 := l4 * 19
 | 
			
		||||
 | 
			
		||||
	// r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3)
 | 
			
		||||
	r0 := mul64(l0, l0)
 | 
			
		||||
	r0 = addMul64(r0, l1_38, l4)
 | 
			
		||||
	r0 = addMul64(r0, l2_38, l3)
 | 
			
		||||
 | 
			
		||||
	// r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
 | 
			
		||||
	r1 := mul64(l0_2, l1)
 | 
			
		||||
	r1 = addMul64(r1, l2_38, l4)
 | 
			
		||||
	r1 = addMul64(r1, l3_19, l3)
 | 
			
		||||
 | 
			
		||||
	// r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4
 | 
			
		||||
	r2 := mul64(l0_2, l2)
 | 
			
		||||
	r2 = addMul64(r2, l1, l1)
 | 
			
		||||
	r2 = addMul64(r2, l3_38, l4)
 | 
			
		||||
 | 
			
		||||
	// r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
 | 
			
		||||
	r3 := mul64(l0_2, l3)
 | 
			
		||||
	r3 = addMul64(r3, l1_2, l2)
 | 
			
		||||
	r3 = addMul64(r3, l4_19, l4)
 | 
			
		||||
 | 
			
		||||
	// r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2
 | 
			
		||||
	r4 := mul64(l0_2, l4)
 | 
			
		||||
	r4 = addMul64(r4, l1_2, l3)
 | 
			
		||||
	r4 = addMul64(r4, l2, l2)
 | 
			
		||||
 | 
			
		||||
	c0 := shiftRightBy51(r0)
 | 
			
		||||
	c1 := shiftRightBy51(r1)
 | 
			
		||||
	c2 := shiftRightBy51(r2)
 | 
			
		||||
	c3 := shiftRightBy51(r3)
 | 
			
		||||
	c4 := shiftRightBy51(r4)
 | 
			
		||||
 | 
			
		||||
	rr0 := r0.lo&maskLow51Bits + c4*19
 | 
			
		||||
	rr1 := r1.lo&maskLow51Bits + c0
 | 
			
		||||
	rr2 := r2.lo&maskLow51Bits + c1
 | 
			
		||||
	rr3 := r3.lo&maskLow51Bits + c2
 | 
			
		||||
	rr4 := r4.lo&maskLow51Bits + c3
 | 
			
		||||
 | 
			
		||||
	*v = Element{rr0, rr1, rr2, rr3, rr4}
 | 
			
		||||
	v.carryPropagate()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// carryPropagate brings the limbs below 52 bits by applying the reduction
 | 
			
		||||
// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry.
 | 
			
		||||
func (v *Element) carryPropagateGeneric() *Element {
 | 
			
		||||
	c0 := v.l0 >> 51
 | 
			
		||||
	c1 := v.l1 >> 51
 | 
			
		||||
	c2 := v.l2 >> 51
 | 
			
		||||
	c3 := v.l3 >> 51
 | 
			
		||||
	c4 := v.l4 >> 51
 | 
			
		||||
 | 
			
		||||
	v.l0 = v.l0&maskLow51Bits + c4*19
 | 
			
		||||
	v.l1 = v.l1&maskLow51Bits + c0
 | 
			
		||||
	v.l2 = v.l2&maskLow51Bits + c1
 | 
			
		||||
	v.l3 = v.l3&maskLow51Bits + c2
 | 
			
		||||
	v.l4 = v.l4&maskLow51Bits + c3
 | 
			
		||||
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1027
									
								
								vendor/filippo.io/edwards25519/scalar.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1027
									
								
								vendor/filippo.io/edwards25519/scalar.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										214
									
								
								vendor/filippo.io/edwards25519/scalarmult.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								vendor/filippo.io/edwards25519/scalarmult.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,214 @@
 | 
			
		||||
// Copyright (c) 2019 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package edwards25519
 | 
			
		||||
 | 
			
		||||
import "sync"
 | 
			
		||||
 | 
			
		||||
// basepointTable is a set of 32 affineLookupTables, where table i is generated
 | 
			
		||||
// from 256i * basepoint. It is precomputed the first time it's used.
 | 
			
		||||
func basepointTable() *[32]affineLookupTable {
 | 
			
		||||
	basepointTablePrecomp.initOnce.Do(func() {
 | 
			
		||||
		p := NewGeneratorPoint()
 | 
			
		||||
		for i := 0; i < 32; i++ {
 | 
			
		||||
			basepointTablePrecomp.table[i].FromP3(p)
 | 
			
		||||
			for j := 0; j < 8; j++ {
 | 
			
		||||
				p.Add(p, p)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	return &basepointTablePrecomp.table
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var basepointTablePrecomp struct {
 | 
			
		||||
	table    [32]affineLookupTable
 | 
			
		||||
	initOnce sync.Once
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ScalarBaseMult sets v = x * B, where B is the canonical generator, and
 | 
			
		||||
// returns v.
 | 
			
		||||
//
 | 
			
		||||
// The scalar multiplication is done in constant time.
 | 
			
		||||
func (v *Point) ScalarBaseMult(x *Scalar) *Point {
 | 
			
		||||
	basepointTable := basepointTable()
 | 
			
		||||
 | 
			
		||||
	// Write x = sum(x_i * 16^i) so  x*B = sum( B*x_i*16^i )
 | 
			
		||||
	// as described in the Ed25519 paper
 | 
			
		||||
	//
 | 
			
		||||
	// Group even and odd coefficients
 | 
			
		||||
	// x*B     = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
 | 
			
		||||
	//         + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B
 | 
			
		||||
	// x*B     = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
 | 
			
		||||
	//    + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B)
 | 
			
		||||
	//
 | 
			
		||||
	// We use a lookup table for each i to get x_i*16^(2*i)*B
 | 
			
		||||
	// and do four doublings to multiply by 16.
 | 
			
		||||
	digits := x.signedRadix16()
 | 
			
		||||
 | 
			
		||||
	multiple := &affineCached{}
 | 
			
		||||
	tmp1 := &projP1xP1{}
 | 
			
		||||
	tmp2 := &projP2{}
 | 
			
		||||
 | 
			
		||||
	// Accumulate the odd components first
 | 
			
		||||
	v.Set(NewIdentityPoint())
 | 
			
		||||
	for i := 1; i < 64; i += 2 {
 | 
			
		||||
		basepointTable[i/2].SelectInto(multiple, digits[i])
 | 
			
		||||
		tmp1.AddAffine(v, multiple)
 | 
			
		||||
		v.fromP1xP1(tmp1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Multiply by 16
 | 
			
		||||
	tmp2.FromP3(v)       // tmp2 =    v in P2 coords
 | 
			
		||||
	tmp1.Double(tmp2)    // tmp1 =  2*v in P1xP1 coords
 | 
			
		||||
	tmp2.FromP1xP1(tmp1) // tmp2 =  2*v in P2 coords
 | 
			
		||||
	tmp1.Double(tmp2)    // tmp1 =  4*v in P1xP1 coords
 | 
			
		||||
	tmp2.FromP1xP1(tmp1) // tmp2 =  4*v in P2 coords
 | 
			
		||||
	tmp1.Double(tmp2)    // tmp1 =  8*v in P1xP1 coords
 | 
			
		||||
	tmp2.FromP1xP1(tmp1) // tmp2 =  8*v in P2 coords
 | 
			
		||||
	tmp1.Double(tmp2)    // tmp1 = 16*v in P1xP1 coords
 | 
			
		||||
	v.fromP1xP1(tmp1)    // now v = 16*(odd components)
 | 
			
		||||
 | 
			
		||||
	// Accumulate the even components
 | 
			
		||||
	for i := 0; i < 64; i += 2 {
 | 
			
		||||
		basepointTable[i/2].SelectInto(multiple, digits[i])
 | 
			
		||||
		tmp1.AddAffine(v, multiple)
 | 
			
		||||
		v.fromP1xP1(tmp1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ScalarMult sets v = x * q, and returns v.
 | 
			
		||||
//
 | 
			
		||||
// The scalar multiplication is done in constant time.
 | 
			
		||||
func (v *Point) ScalarMult(x *Scalar, q *Point) *Point {
 | 
			
		||||
	checkInitialized(q)
 | 
			
		||||
 | 
			
		||||
	var table projLookupTable
 | 
			
		||||
	table.FromP3(q)
 | 
			
		||||
 | 
			
		||||
	// Write x = sum(x_i * 16^i)
 | 
			
		||||
	// so  x*Q = sum( Q*x_i*16^i )
 | 
			
		||||
	//         = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... )
 | 
			
		||||
	//           <------compute inside out---------
 | 
			
		||||
	//
 | 
			
		||||
	// We use the lookup table to get the x_i*Q values
 | 
			
		||||
	// and do four doublings to compute 16*Q
 | 
			
		||||
	digits := x.signedRadix16()
 | 
			
		||||
 | 
			
		||||
	// Unwrap first loop iteration to save computing 16*identity
 | 
			
		||||
	multiple := &projCached{}
 | 
			
		||||
	tmp1 := &projP1xP1{}
 | 
			
		||||
	tmp2 := &projP2{}
 | 
			
		||||
	table.SelectInto(multiple, digits[63])
 | 
			
		||||
 | 
			
		||||
	v.Set(NewIdentityPoint())
 | 
			
		||||
	tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords
 | 
			
		||||
	for i := 62; i >= 0; i-- {
 | 
			
		||||
		tmp2.FromP1xP1(tmp1) // tmp2 =    (prev) in P2 coords
 | 
			
		||||
		tmp1.Double(tmp2)    // tmp1 =  2*(prev) in P1xP1 coords
 | 
			
		||||
		tmp2.FromP1xP1(tmp1) // tmp2 =  2*(prev) in P2 coords
 | 
			
		||||
		tmp1.Double(tmp2)    // tmp1 =  4*(prev) in P1xP1 coords
 | 
			
		||||
		tmp2.FromP1xP1(tmp1) // tmp2 =  4*(prev) in P2 coords
 | 
			
		||||
		tmp1.Double(tmp2)    // tmp1 =  8*(prev) in P1xP1 coords
 | 
			
		||||
		tmp2.FromP1xP1(tmp1) // tmp2 =  8*(prev) in P2 coords
 | 
			
		||||
		tmp1.Double(tmp2)    // tmp1 = 16*(prev) in P1xP1 coords
 | 
			
		||||
		v.fromP1xP1(tmp1)    //    v = 16*(prev) in P3 coords
 | 
			
		||||
		table.SelectInto(multiple, digits[i])
 | 
			
		||||
		tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords
 | 
			
		||||
	}
 | 
			
		||||
	v.fromP1xP1(tmp1)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// basepointNafTable is the nafLookupTable8 for the basepoint.
 | 
			
		||||
// It is precomputed the first time it's used.
 | 
			
		||||
func basepointNafTable() *nafLookupTable8 {
 | 
			
		||||
	basepointNafTablePrecomp.initOnce.Do(func() {
 | 
			
		||||
		basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint())
 | 
			
		||||
	})
 | 
			
		||||
	return &basepointNafTablePrecomp.table
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var basepointNafTablePrecomp struct {
 | 
			
		||||
	table    nafLookupTable8
 | 
			
		||||
	initOnce sync.Once
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical
 | 
			
		||||
// generator, and returns v.
 | 
			
		||||
//
 | 
			
		||||
// Execution time depends on the inputs.
 | 
			
		||||
func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point {
 | 
			
		||||
	checkInitialized(A)
 | 
			
		||||
 | 
			
		||||
	// Similarly to the single variable-base approach, we compute
 | 
			
		||||
	// digits and use them with a lookup table.  However, because
 | 
			
		||||
	// we are allowed to do variable-time operations, we don't
 | 
			
		||||
	// need constant-time lookups or constant-time digit
 | 
			
		||||
	// computations.
 | 
			
		||||
	//
 | 
			
		||||
	// So we use a non-adjacent form of some width w instead of
 | 
			
		||||
	// radix 16.  This is like a binary representation (one digit
 | 
			
		||||
	// for each binary place) but we allow the digits to grow in
 | 
			
		||||
	// magnitude up to 2^{w-1} so that the nonzero digits are as
 | 
			
		||||
	// sparse as possible.  Intuitively, this "condenses" the
 | 
			
		||||
	// "mass" of the scalar onto sparse coefficients (meaning
 | 
			
		||||
	// fewer additions).
 | 
			
		||||
 | 
			
		||||
	basepointNafTable := basepointNafTable()
 | 
			
		||||
	var aTable nafLookupTable5
 | 
			
		||||
	aTable.FromP3(A)
 | 
			
		||||
	// Because the basepoint is fixed, we can use a wider NAF
 | 
			
		||||
	// corresponding to a bigger table.
 | 
			
		||||
	aNaf := a.nonAdjacentForm(5)
 | 
			
		||||
	bNaf := b.nonAdjacentForm(8)
 | 
			
		||||
 | 
			
		||||
	// Find the first nonzero coefficient.
 | 
			
		||||
	i := 255
 | 
			
		||||
	for j := i; j >= 0; j-- {
 | 
			
		||||
		if aNaf[j] != 0 || bNaf[j] != 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	multA := &projCached{}
 | 
			
		||||
	multB := &affineCached{}
 | 
			
		||||
	tmp1 := &projP1xP1{}
 | 
			
		||||
	tmp2 := &projP2{}
 | 
			
		||||
	tmp2.Zero()
 | 
			
		||||
 | 
			
		||||
	// Move from high to low bits, doubling the accumulator
 | 
			
		||||
	// at each iteration and checking whether there is a nonzero
 | 
			
		||||
	// coefficient to look up a multiple of.
 | 
			
		||||
	for ; i >= 0; i-- {
 | 
			
		||||
		tmp1.Double(tmp2)
 | 
			
		||||
 | 
			
		||||
		// Only update v if we have a nonzero coeff to add in.
 | 
			
		||||
		if aNaf[i] > 0 {
 | 
			
		||||
			v.fromP1xP1(tmp1)
 | 
			
		||||
			aTable.SelectInto(multA, aNaf[i])
 | 
			
		||||
			tmp1.Add(v, multA)
 | 
			
		||||
		} else if aNaf[i] < 0 {
 | 
			
		||||
			v.fromP1xP1(tmp1)
 | 
			
		||||
			aTable.SelectInto(multA, -aNaf[i])
 | 
			
		||||
			tmp1.Sub(v, multA)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if bNaf[i] > 0 {
 | 
			
		||||
			v.fromP1xP1(tmp1)
 | 
			
		||||
			basepointNafTable.SelectInto(multB, bNaf[i])
 | 
			
		||||
			tmp1.AddAffine(v, multB)
 | 
			
		||||
		} else if bNaf[i] < 0 {
 | 
			
		||||
			v.fromP1xP1(tmp1)
 | 
			
		||||
			basepointNafTable.SelectInto(multB, -bNaf[i])
 | 
			
		||||
			tmp1.SubAffine(v, multB)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		tmp2.FromP1xP1(tmp1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v.fromP2(tmp2)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										129
									
								
								vendor/filippo.io/edwards25519/tables.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								vendor/filippo.io/edwards25519/tables.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
// Copyright (c) 2019 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package edwards25519
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A dynamic lookup table for variable-base, constant-time scalar muls.
 | 
			
		||||
type projLookupTable struct {
 | 
			
		||||
	points [8]projCached
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A precomputed lookup table for fixed-base, constant-time scalar muls.
 | 
			
		||||
type affineLookupTable struct {
 | 
			
		||||
	points [8]affineCached
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A dynamic lookup table for variable-base, variable-time scalar muls.
 | 
			
		||||
type nafLookupTable5 struct {
 | 
			
		||||
	points [8]projCached
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A precomputed lookup table for fixed-base, variable-time scalar muls.
 | 
			
		||||
type nafLookupTable8 struct {
 | 
			
		||||
	points [64]affineCached
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Constructors.
 | 
			
		||||
 | 
			
		||||
// Builds a lookup table at runtime. Fast.
 | 
			
		||||
func (v *projLookupTable) FromP3(q *Point) {
 | 
			
		||||
	// Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
 | 
			
		||||
	// This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
 | 
			
		||||
	v.points[0].FromP3(q)
 | 
			
		||||
	tmpP3 := Point{}
 | 
			
		||||
	tmpP1xP1 := projP1xP1{}
 | 
			
		||||
	for i := 0; i < 7; i++ {
 | 
			
		||||
		// Compute (i+1)*Q as Q + i*Q and convert to a ProjCached
 | 
			
		||||
		// This is needlessly complicated because the API has explicit
 | 
			
		||||
		// recievers instead of creating stack objects and relying on RVO
 | 
			
		||||
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is not optimised for speed; fixed-base tables should be precomputed.
 | 
			
		||||
func (v *affineLookupTable) FromP3(q *Point) {
 | 
			
		||||
	// Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
 | 
			
		||||
	// This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
 | 
			
		||||
	v.points[0].FromP3(q)
 | 
			
		||||
	tmpP3 := Point{}
 | 
			
		||||
	tmpP1xP1 := projP1xP1{}
 | 
			
		||||
	for i := 0; i < 7; i++ {
 | 
			
		||||
		// Compute (i+1)*Q as Q + i*Q and convert to AffineCached
 | 
			
		||||
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i])))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Builds a lookup table at runtime. Fast.
 | 
			
		||||
func (v *nafLookupTable5) FromP3(q *Point) {
 | 
			
		||||
	// Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q
 | 
			
		||||
	// This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q
 | 
			
		||||
	v.points[0].FromP3(q)
 | 
			
		||||
	q2 := Point{}
 | 
			
		||||
	q2.Add(q, q)
 | 
			
		||||
	tmpP3 := Point{}
 | 
			
		||||
	tmpP1xP1 := projP1xP1{}
 | 
			
		||||
	for i := 0; i < 7; i++ {
 | 
			
		||||
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i])))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is not optimised for speed; fixed-base tables should be precomputed.
 | 
			
		||||
func (v *nafLookupTable8) FromP3(q *Point) {
 | 
			
		||||
	v.points[0].FromP3(q)
 | 
			
		||||
	q2 := Point{}
 | 
			
		||||
	q2.Add(q, q)
 | 
			
		||||
	tmpP3 := Point{}
 | 
			
		||||
	tmpP1xP1 := projP1xP1{}
 | 
			
		||||
	for i := 0; i < 63; i++ {
 | 
			
		||||
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i])))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Selectors.
 | 
			
		||||
 | 
			
		||||
// Set dest to x*Q, where -8 <= x <= 8, in constant time.
 | 
			
		||||
func (v *projLookupTable) SelectInto(dest *projCached, x int8) {
 | 
			
		||||
	// Compute xabs = |x|
 | 
			
		||||
	xmask := x >> 7
 | 
			
		||||
	xabs := uint8((x + xmask) ^ xmask)
 | 
			
		||||
 | 
			
		||||
	dest.Zero()
 | 
			
		||||
	for j := 1; j <= 8; j++ {
 | 
			
		||||
		// Set dest = j*Q if |x| = j
 | 
			
		||||
		cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
 | 
			
		||||
		dest.Select(&v.points[j-1], dest, cond)
 | 
			
		||||
	}
 | 
			
		||||
	// Now dest = |x|*Q, conditionally negate to get x*Q
 | 
			
		||||
	dest.CondNeg(int(xmask & 1))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set dest to x*Q, where -8 <= x <= 8, in constant time.
 | 
			
		||||
func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) {
 | 
			
		||||
	// Compute xabs = |x|
 | 
			
		||||
	xmask := x >> 7
 | 
			
		||||
	xabs := uint8((x + xmask) ^ xmask)
 | 
			
		||||
 | 
			
		||||
	dest.Zero()
 | 
			
		||||
	for j := 1; j <= 8; j++ {
 | 
			
		||||
		// Set dest = j*Q if |x| = j
 | 
			
		||||
		cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
 | 
			
		||||
		dest.Select(&v.points[j-1], dest, cond)
 | 
			
		||||
	}
 | 
			
		||||
	// Now dest = |x|*Q, conditionally negate to get x*Q
 | 
			
		||||
	dest.CondNeg(int(xmask & 1))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given odd x with 0 < x < 2^4, return x*Q (in variable time).
 | 
			
		||||
func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) {
 | 
			
		||||
	*dest = v.points[x/2]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given odd x with 0 < x < 2^7, return x*Q (in variable time).
 | 
			
		||||
func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) {
 | 
			
		||||
	*dest = v.points[x/2]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
# VK SDK for Golang
 | 
			
		||||
 | 
			
		||||
[](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2?tab=subdirectories)
 | 
			
		||||
[](https://vk.com/dev/)
 | 
			
		||||
[](https://dev.vk.com/)
 | 
			
		||||
[](https://codecov.io/gh/SevereCloud/vksdk)
 | 
			
		||||
[](https://vk.me/join/AJQ1d6Or8Q00Y_CSOESfbqGt)
 | 
			
		||||
[](https://github.com/SevereCloud/vksdk/releases)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/account.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/account.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -141,6 +141,8 @@ func (vk *VK) AccountSetInfo(params Params) (response int, err error) {
 | 
			
		||||
// AccountSetNameInMenu sets an application screen name
 | 
			
		||||
// (up to 17 characters), that is shown to the user in the left menu.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: This method is deprecated and may be disabled soon, please avoid
 | 
			
		||||
//
 | 
			
		||||
// https://vk.com/dev/account.setNameInMenu
 | 
			
		||||
func (vk *VK) AccountSetNameInMenu(params Params) (response int, err error) {
 | 
			
		||||
	err = vk.RequestUnmarshal("account.setNameInMenu", &response, params)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/store.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/store.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
package api // import "github.com/SevereCloud/vksdk/api"
 | 
			
		||||
package api // import "github.com/SevereCloud/vksdk/v2/api"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/SevereCloud/vksdk/v2/object"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										35
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/video.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/video.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -235,6 +235,17 @@ func (vk *VK) VideoGetCommentsExtended(params Params) (response VideoGetComments
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VideoLiveGetCategoriesResponse struct.
 | 
			
		||||
type VideoLiveGetCategoriesResponse []object.VideoLiveCategory
 | 
			
		||||
 | 
			
		||||
// VideoLiveGetCategories method.
 | 
			
		||||
//
 | 
			
		||||
// https://vk.com/dev/video.liveGetCategories
 | 
			
		||||
func (vk *VK) VideoLiveGetCategories(params Params) (response VideoLiveGetCategoriesResponse, err error) {
 | 
			
		||||
	err = vk.RequestUnmarshal("video.liveGetCategories", &response, params)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VideoRemoveFromAlbum allows you to remove the video from the album.
 | 
			
		||||
//
 | 
			
		||||
// https://vk.com/dev/video.removeFromAlbum
 | 
			
		||||
@@ -336,3 +347,27 @@ func (vk *VK) VideoSearchExtended(params Params) (response VideoSearchExtendedRe
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VideoStartStreamingResponse struct.
 | 
			
		||||
type VideoStartStreamingResponse object.VideoLive
 | 
			
		||||
 | 
			
		||||
// VideoStartStreaming method.
 | 
			
		||||
//
 | 
			
		||||
// https://vk.com/dev/video.startStreaming
 | 
			
		||||
func (vk *VK) VideoStartStreaming(params Params) (response VideoStartStreamingResponse, err error) {
 | 
			
		||||
	err = vk.RequestUnmarshal("video.startStreaming", &response, params)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VideoStopStreamingResponse struct.
 | 
			
		||||
type VideoStopStreamingResponse struct {
 | 
			
		||||
	UniqueViewers int `json:"unique_viewers"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VideoStopStreaming method.
 | 
			
		||||
//
 | 
			
		||||
// https://vk.com/dev/video.stopStreaming
 | 
			
		||||
func (vk *VK) VideoStopStreaming(params Params) (response VideoStopStreamingResponse, err error) {
 | 
			
		||||
	err = vk.RequestUnmarshal("video.stopStreaming", &response, params)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -7,6 +7,6 @@ package vksdk
 | 
			
		||||
 | 
			
		||||
// Module constants.
 | 
			
		||||
const (
 | 
			
		||||
	Version = "2.13.1"
 | 
			
		||||
	Version = "2.14.0"
 | 
			
		||||
	API     = "5.131"
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/SevereCloud/vksdk/v2/events/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/SevereCloud/vksdk/v2/events/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -15,3 +15,8 @@ func GroupIDFromContext(ctx context.Context) int {
 | 
			
		||||
func EventIDFromContext(ctx context.Context) string {
 | 
			
		||||
	return ctx.Value(internal.EventIDKey).(string)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VersionFromContext returns the version from context.
 | 
			
		||||
func VersionFromContext(ctx context.Context) string {
 | 
			
		||||
	return ctx.Value(internal.EventVersionKey).(string)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/events/events.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/events/events.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -81,6 +81,7 @@ type GroupEvent struct {
 | 
			
		||||
	Object  json.RawMessage `json:"object"`
 | 
			
		||||
	GroupID int             `json:"group_id"`
 | 
			
		||||
	EventID string          `json:"event_id"`
 | 
			
		||||
	V       string          `json:"v"`
 | 
			
		||||
	Secret  string          `json:"secret"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -158,6 +159,7 @@ func NewFuncList() *FuncList {
 | 
			
		||||
func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { // nolint:gocyclo
 | 
			
		||||
	ctx = context.WithValue(ctx, internal.GroupIDKey, e.GroupID)
 | 
			
		||||
	ctx = context.WithValue(ctx, internal.EventIDKey, e.EventID)
 | 
			
		||||
	ctx = context.WithValue(ctx, internal.EventVersionKey, e.V)
 | 
			
		||||
 | 
			
		||||
	if sliceFunc, ok := fl.special[e.Type]; ok {
 | 
			
		||||
		for _, f := range sliceFunc {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/SevereCloud/vksdk/v2/internal/transport.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/SevereCloud/vksdk/v2/internal/transport.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -28,6 +28,7 @@ const (
 | 
			
		||||
	CallbackRetryCounterKey
 | 
			
		||||
	CallbackRetryAfterKey
 | 
			
		||||
	CallbackRemove
 | 
			
		||||
	EventVersionKey
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ContextClient return *http.Client.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/account.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/account.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -84,7 +84,6 @@ type AccountAccountCounters struct {
 | 
			
		||||
 | 
			
		||||
// AccountInfo struct.
 | 
			
		||||
type AccountInfo struct {
 | 
			
		||||
 | 
			
		||||
	// Country code.
 | 
			
		||||
	Country string `json:"country"`
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/messages.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/messages.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -409,7 +409,6 @@ type MessageContentSource struct {
 | 
			
		||||
	Type                        string `json:"type"`
 | 
			
		||||
	MessageContentSourceMessage        // type message
 | 
			
		||||
	MessageContentSourceURL            // type url
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewMessageContentSourceMessage ...
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										211
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/users.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										211
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/users.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -24,110 +24,113 @@ const (
 | 
			
		||||
 | 
			
		||||
// UsersUser struct.
 | 
			
		||||
type UsersUser struct {
 | 
			
		||||
	ID                     int                   `json:"id"`
 | 
			
		||||
	FirstName              string                `json:"first_name"`
 | 
			
		||||
	LastName               string                `json:"last_name"`
 | 
			
		||||
	FirstNameNom           string                `json:"first_name_nom"`
 | 
			
		||||
	FirstNameGen           string                `json:"first_name_gen"`
 | 
			
		||||
	FirstNameDat           string                `json:"first_name_dat"`
 | 
			
		||||
	FirstNameAcc           string                `json:"first_name_acc"`
 | 
			
		||||
	FirstNameIns           string                `json:"first_name_ins"`
 | 
			
		||||
	FirstNameAbl           string                `json:"first_name_abl"`
 | 
			
		||||
	LastNameNom            string                `json:"last_name_nom"`
 | 
			
		||||
	LastNameGen            string                `json:"last_name_gen"`
 | 
			
		||||
	LastNameDat            string                `json:"last_name_dat"`
 | 
			
		||||
	LastNameAcc            string                `json:"last_name_acc"`
 | 
			
		||||
	LastNameIns            string                `json:"last_name_ins"`
 | 
			
		||||
	LastNameAbl            string                `json:"last_name_abl"`
 | 
			
		||||
	MaidenName             string                `json:"maiden_name"`
 | 
			
		||||
	Sex                    int                   `json:"sex"`
 | 
			
		||||
	Nickname               string                `json:"nickname"`
 | 
			
		||||
	Domain                 string                `json:"domain"`
 | 
			
		||||
	ScreenName             string                `json:"screen_name"`
 | 
			
		||||
	Bdate                  string                `json:"bdate"`
 | 
			
		||||
	City                   BaseObject            `json:"city"`
 | 
			
		||||
	Country                BaseObject            `json:"country"`
 | 
			
		||||
	Photo50                string                `json:"photo_50"`
 | 
			
		||||
	Photo100               string                `json:"photo_100"`
 | 
			
		||||
	Photo200               string                `json:"photo_200"`
 | 
			
		||||
	PhotoMax               string                `json:"photo_max"`
 | 
			
		||||
	Photo200Orig           string                `json:"photo_200_orig"`
 | 
			
		||||
	Photo400Orig           string                `json:"photo_400_orig"`
 | 
			
		||||
	PhotoMaxOrig           string                `json:"photo_max_orig"`
 | 
			
		||||
	PhotoID                string                `json:"photo_id"`
 | 
			
		||||
	FriendStatus           int                   `json:"friend_status"` // see FriendStatus const
 | 
			
		||||
	OnlineApp              int                   `json:"online_app"`
 | 
			
		||||
	Online                 BaseBoolInt           `json:"online"`
 | 
			
		||||
	OnlineMobile           BaseBoolInt           `json:"online_mobile"`
 | 
			
		||||
	HasPhoto               BaseBoolInt           `json:"has_photo"`
 | 
			
		||||
	HasMobile              BaseBoolInt           `json:"has_mobile"`
 | 
			
		||||
	IsClosed               BaseBoolInt           `json:"is_closed"`
 | 
			
		||||
	IsFriend               BaseBoolInt           `json:"is_friend"`
 | 
			
		||||
	IsFavorite             BaseBoolInt           `json:"is_favorite"`
 | 
			
		||||
	IsHiddenFromFeed       BaseBoolInt           `json:"is_hidden_from_feed"`
 | 
			
		||||
	CanAccessClosed        BaseBoolInt           `json:"can_access_closed"`
 | 
			
		||||
	CanBeInvitedGroup      BaseBoolInt           `json:"can_be_invited_group"`
 | 
			
		||||
	CanPost                BaseBoolInt           `json:"can_post"`
 | 
			
		||||
	CanSeeAllPosts         BaseBoolInt           `json:"can_see_all_posts"`
 | 
			
		||||
	CanSeeAudio            BaseBoolInt           `json:"can_see_audio"`
 | 
			
		||||
	CanWritePrivateMessage BaseBoolInt           `json:"can_write_private_message"`
 | 
			
		||||
	CanSendFriendRequest   BaseBoolInt           `json:"can_send_friend_request"`
 | 
			
		||||
	CanCallFromGroup       BaseBoolInt           `json:"can_call_from_group"`
 | 
			
		||||
	Verified               BaseBoolInt           `json:"verified"`
 | 
			
		||||
	Trending               BaseBoolInt           `json:"trending"`
 | 
			
		||||
	Blacklisted            BaseBoolInt           `json:"blacklisted"`
 | 
			
		||||
	BlacklistedByMe        BaseBoolInt           `json:"blacklisted_by_me"`
 | 
			
		||||
	Facebook               string                `json:"facebook"`
 | 
			
		||||
	FacebookName           string                `json:"facebook_name"`
 | 
			
		||||
	Twitter                string                `json:"twitter"`
 | 
			
		||||
	Instagram              string                `json:"instagram"`
 | 
			
		||||
	Site                   string                `json:"site"`
 | 
			
		||||
	Status                 string                `json:"status"`
 | 
			
		||||
	StatusAudio            AudioAudio            `json:"status_audio"`
 | 
			
		||||
	LastSeen               UsersLastSeen         `json:"last_seen"`
 | 
			
		||||
	CropPhoto              UsersCropPhoto        `json:"crop_photo"`
 | 
			
		||||
	FollowersCount         int                   `json:"followers_count"`
 | 
			
		||||
	CommonCount            int                   `json:"common_count"`
 | 
			
		||||
	Occupation             UsersOccupation       `json:"occupation"`
 | 
			
		||||
	Career                 []UsersCareer         `json:"career"`
 | 
			
		||||
	Military               []UsersMilitary       `json:"military"`
 | 
			
		||||
	University             int                   `json:"university"`
 | 
			
		||||
	UniversityName         string                `json:"university_name"`
 | 
			
		||||
	Faculty                int                   `json:"faculty"`
 | 
			
		||||
	FacultyName            string                `json:"faculty_name"`
 | 
			
		||||
	Graduation             int                   `json:"graduation"`
 | 
			
		||||
	EducationForm          string                `json:"education_form"`
 | 
			
		||||
	EducationStatus        string                `json:"education_status"`
 | 
			
		||||
	HomeTown               string                `json:"home_town"`
 | 
			
		||||
	Relation               int                   `json:"relation"`
 | 
			
		||||
	Personal               UsersPersonal         `json:"personal"`
 | 
			
		||||
	Interests              string                `json:"interests"`
 | 
			
		||||
	Music                  string                `json:"music"`
 | 
			
		||||
	Activities             string                `json:"activities"`
 | 
			
		||||
	Movies                 string                `json:"movies"`
 | 
			
		||||
	Tv                     string                `json:"tv"`
 | 
			
		||||
	Books                  string                `json:"books"`
 | 
			
		||||
	Games                  string                `json:"games"`
 | 
			
		||||
	Universities           []UsersUniversity     `json:"universities"`
 | 
			
		||||
	Schools                []UsersSchool         `json:"schools"`
 | 
			
		||||
	About                  string                `json:"about"`
 | 
			
		||||
	Relatives              []UsersRelative       `json:"relatives"`
 | 
			
		||||
	Quotes                 string                `json:"quotes"`
 | 
			
		||||
	Lists                  []int                 `json:"lists"`
 | 
			
		||||
	Deactivated            string                `json:"deactivated"`
 | 
			
		||||
	WallDefault            string                `json:"wall_default"`
 | 
			
		||||
	Timezone               int                   `json:"timezone"`
 | 
			
		||||
	Exports                UsersExports          `json:"exports"`
 | 
			
		||||
	Counters               UsersUserCounters     `json:"counters"`
 | 
			
		||||
	MobilePhone            string                `json:"mobile_phone"`
 | 
			
		||||
	HomePhone              string                `json:"home_phone"`
 | 
			
		||||
	FoundWith              int                   `json:"found_with"` // TODO: check it
 | 
			
		||||
	OnlineInfo             UsersOnlineInfo       `json:"online_info"`
 | 
			
		||||
	Mutual                 FriendsRequestsMutual `json:"mutual"`
 | 
			
		||||
	TrackCode              string                `json:"track_code"`
 | 
			
		||||
	RelationPartner        UsersUserMin          `json:"relation_partner"`
 | 
			
		||||
	Type                   string                `json:"type"`
 | 
			
		||||
	Skype                  string                `json:"skype"`
 | 
			
		||||
	ID                     int         `json:"id"`
 | 
			
		||||
	FirstName              string      `json:"first_name"`
 | 
			
		||||
	LastName               string      `json:"last_name"`
 | 
			
		||||
	FirstNameNom           string      `json:"first_name_nom"`
 | 
			
		||||
	FirstNameGen           string      `json:"first_name_gen"`
 | 
			
		||||
	FirstNameDat           string      `json:"first_name_dat"`
 | 
			
		||||
	FirstNameAcc           string      `json:"first_name_acc"`
 | 
			
		||||
	FirstNameIns           string      `json:"first_name_ins"`
 | 
			
		||||
	FirstNameAbl           string      `json:"first_name_abl"`
 | 
			
		||||
	LastNameNom            string      `json:"last_name_nom"`
 | 
			
		||||
	LastNameGen            string      `json:"last_name_gen"`
 | 
			
		||||
	LastNameDat            string      `json:"last_name_dat"`
 | 
			
		||||
	LastNameAcc            string      `json:"last_name_acc"`
 | 
			
		||||
	LastNameIns            string      `json:"last_name_ins"`
 | 
			
		||||
	LastNameAbl            string      `json:"last_name_abl"`
 | 
			
		||||
	MaidenName             string      `json:"maiden_name"`
 | 
			
		||||
	Sex                    int         `json:"sex"`
 | 
			
		||||
	Nickname               string      `json:"nickname"`
 | 
			
		||||
	Domain                 string      `json:"domain"`
 | 
			
		||||
	ScreenName             string      `json:"screen_name"`
 | 
			
		||||
	Bdate                  string      `json:"bdate"`
 | 
			
		||||
	City                   BaseObject  `json:"city"`
 | 
			
		||||
	Country                BaseObject  `json:"country"`
 | 
			
		||||
	Photo50                string      `json:"photo_50"`
 | 
			
		||||
	Photo100               string      `json:"photo_100"`
 | 
			
		||||
	Photo200               string      `json:"photo_200"`
 | 
			
		||||
	PhotoMax               string      `json:"photo_max"`
 | 
			
		||||
	Photo200Orig           string      `json:"photo_200_orig"`
 | 
			
		||||
	Photo400Orig           string      `json:"photo_400_orig"`
 | 
			
		||||
	PhotoMaxOrig           string      `json:"photo_max_orig"`
 | 
			
		||||
	PhotoID                string      `json:"photo_id"`
 | 
			
		||||
	FriendStatus           int         `json:"friend_status"` // see FriendStatus const
 | 
			
		||||
	OnlineApp              int         `json:"online_app"`
 | 
			
		||||
	Online                 BaseBoolInt `json:"online"`
 | 
			
		||||
	OnlineMobile           BaseBoolInt `json:"online_mobile"`
 | 
			
		||||
	HasPhoto               BaseBoolInt `json:"has_photo"`
 | 
			
		||||
	HasMobile              BaseBoolInt `json:"has_mobile"`
 | 
			
		||||
	IsClosed               BaseBoolInt `json:"is_closed"`
 | 
			
		||||
	IsFriend               BaseBoolInt `json:"is_friend"`
 | 
			
		||||
	IsFavorite             BaseBoolInt `json:"is_favorite"`
 | 
			
		||||
	IsHiddenFromFeed       BaseBoolInt `json:"is_hidden_from_feed"`
 | 
			
		||||
	CanAccessClosed        BaseBoolInt `json:"can_access_closed"`
 | 
			
		||||
	CanBeInvitedGroup      BaseBoolInt `json:"can_be_invited_group"`
 | 
			
		||||
	CanPost                BaseBoolInt `json:"can_post"`
 | 
			
		||||
	CanSeeAllPosts         BaseBoolInt `json:"can_see_all_posts"`
 | 
			
		||||
	CanSeeAudio            BaseBoolInt `json:"can_see_audio"`
 | 
			
		||||
	CanWritePrivateMessage BaseBoolInt `json:"can_write_private_message"`
 | 
			
		||||
	CanSendFriendRequest   BaseBoolInt `json:"can_send_friend_request"`
 | 
			
		||||
	CanCallFromGroup       BaseBoolInt `json:"can_call_from_group"`
 | 
			
		||||
	Verified               BaseBoolInt `json:"verified"`
 | 
			
		||||
	Trending               BaseBoolInt `json:"trending"`
 | 
			
		||||
	Blacklisted            BaseBoolInt `json:"blacklisted"`
 | 
			
		||||
	BlacklistedByMe        BaseBoolInt `json:"blacklisted_by_me"`
 | 
			
		||||
	// Deprecated: Facebook и Instagram запрещены в России, Meta признана экстремистской организацией...
 | 
			
		||||
	Facebook string `json:"facebook"`
 | 
			
		||||
	// Deprecated: Facebook и Instagram запрещены в России, Meta признана экстремистской организацией...
 | 
			
		||||
	FacebookName string `json:"facebook_name"`
 | 
			
		||||
	// Deprecated: Facebook и Instagram запрещены в России, Meta признана экстремистской организацией...
 | 
			
		||||
	Instagram       string                `json:"instagram"`
 | 
			
		||||
	Twitter         string                `json:"twitter"`
 | 
			
		||||
	Site            string                `json:"site"`
 | 
			
		||||
	Status          string                `json:"status"`
 | 
			
		||||
	StatusAudio     AudioAudio            `json:"status_audio"`
 | 
			
		||||
	LastSeen        UsersLastSeen         `json:"last_seen"`
 | 
			
		||||
	CropPhoto       UsersCropPhoto        `json:"crop_photo"`
 | 
			
		||||
	FollowersCount  int                   `json:"followers_count"`
 | 
			
		||||
	CommonCount     int                   `json:"common_count"`
 | 
			
		||||
	Occupation      UsersOccupation       `json:"occupation"`
 | 
			
		||||
	Career          []UsersCareer         `json:"career"`
 | 
			
		||||
	Military        []UsersMilitary       `json:"military"`
 | 
			
		||||
	University      int                   `json:"university"`
 | 
			
		||||
	UniversityName  string                `json:"university_name"`
 | 
			
		||||
	Faculty         int                   `json:"faculty"`
 | 
			
		||||
	FacultyName     string                `json:"faculty_name"`
 | 
			
		||||
	Graduation      int                   `json:"graduation"`
 | 
			
		||||
	EducationForm   string                `json:"education_form"`
 | 
			
		||||
	EducationStatus string                `json:"education_status"`
 | 
			
		||||
	HomeTown        string                `json:"home_town"`
 | 
			
		||||
	Relation        int                   `json:"relation"`
 | 
			
		||||
	Personal        UsersPersonal         `json:"personal"`
 | 
			
		||||
	Interests       string                `json:"interests"`
 | 
			
		||||
	Music           string                `json:"music"`
 | 
			
		||||
	Activities      string                `json:"activities"`
 | 
			
		||||
	Movies          string                `json:"movies"`
 | 
			
		||||
	Tv              string                `json:"tv"`
 | 
			
		||||
	Books           string                `json:"books"`
 | 
			
		||||
	Games           string                `json:"games"`
 | 
			
		||||
	Universities    []UsersUniversity     `json:"universities"`
 | 
			
		||||
	Schools         []UsersSchool         `json:"schools"`
 | 
			
		||||
	About           string                `json:"about"`
 | 
			
		||||
	Relatives       []UsersRelative       `json:"relatives"`
 | 
			
		||||
	Quotes          string                `json:"quotes"`
 | 
			
		||||
	Lists           []int                 `json:"lists"`
 | 
			
		||||
	Deactivated     string                `json:"deactivated"`
 | 
			
		||||
	WallDefault     string                `json:"wall_default"`
 | 
			
		||||
	Timezone        int                   `json:"timezone"`
 | 
			
		||||
	Exports         UsersExports          `json:"exports"`
 | 
			
		||||
	Counters        UsersUserCounters     `json:"counters"`
 | 
			
		||||
	MobilePhone     string                `json:"mobile_phone"`
 | 
			
		||||
	HomePhone       string                `json:"home_phone"`
 | 
			
		||||
	FoundWith       int                   `json:"found_with"` // TODO: check it
 | 
			
		||||
	OnlineInfo      UsersOnlineInfo       `json:"online_info"`
 | 
			
		||||
	Mutual          FriendsRequestsMutual `json:"mutual"`
 | 
			
		||||
	TrackCode       string                `json:"track_code"`
 | 
			
		||||
	RelationPartner UsersUserMin          `json:"relation_partner"`
 | 
			
		||||
	Type            string                `json:"type"`
 | 
			
		||||
	Skype           string                `json:"skype"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToMention return mention.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/video.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/video.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -297,3 +297,27 @@ type VideoVideoImage struct {
 | 
			
		||||
	BaseImage
 | 
			
		||||
	WithPadding BaseBoolInt `json:"with_padding"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VideoLive struct.
 | 
			
		||||
type VideoLive struct {
 | 
			
		||||
	OwnerID     int             `json:"owner_id"`
 | 
			
		||||
	VideoID     int             `json:"video_id"`
 | 
			
		||||
	Name        string          `json:"name"`
 | 
			
		||||
	Description string          `json:"description"`
 | 
			
		||||
	AccessKey   string          `json:"access_key"`
 | 
			
		||||
	Stream      VideoLiveStream `json:"stream"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VideoLiveStream struct.
 | 
			
		||||
type VideoLiveStream struct {
 | 
			
		||||
	URL     string `json:"url"`
 | 
			
		||||
	Key     string `json:"key"`
 | 
			
		||||
	OKMPURL string `json:"okmp_url"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VideoLiveCategory struct.
 | 
			
		||||
type VideoLiveCategory struct {
 | 
			
		||||
	ID      int                 `json:"id"`
 | 
			
		||||
	Label   string              `json:"label"`
 | 
			
		||||
	Sublist []VideoLiveCategory `json:"sublist,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/bwmarrin/discordgo/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/bwmarrin/discordgo/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
# IDE-specific metadata
 | 
			
		||||
.idea/
 | 
			
		||||
 | 
			
		||||
# Environment variables. Useful for examples.
 | 
			
		||||
.env
 | 
			
		||||
							
								
								
									
										19
									
								
								vendor/github.com/bwmarrin/discordgo/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/bwmarrin/discordgo/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
linters:
 | 
			
		||||
  disable-all: true
 | 
			
		||||
  enable:
 | 
			
		||||
    # - staticcheck
 | 
			
		||||
    # - unused
 | 
			
		||||
    - golint
 | 
			
		||||
 | 
			
		||||
linters-settings:
 | 
			
		||||
  staticcheck:
 | 
			
		||||
    go: "1.13"
 | 
			
		||||
 | 
			
		||||
    checks: ["all"]
 | 
			
		||||
 | 
			
		||||
  unused:
 | 
			
		||||
    go: "1.13"
 | 
			
		||||
 | 
			
		||||
issues:
 | 
			
		||||
  include:
 | 
			
		||||
    - EXC0002
 | 
			
		||||
@@ -3,6 +3,9 @@ go:
 | 
			
		||||
    - 1.13.x
 | 
			
		||||
    - 1.14.x
 | 
			
		||||
    - 1.15.x
 | 
			
		||||
    - 1.16.x
 | 
			
		||||
    - 1.17.x
 | 
			
		||||
    - 1.18.x
 | 
			
		||||
env:
 | 
			
		||||
    - GO111MODULE=on
 | 
			
		||||
install:
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
# DiscordGo
 | 
			
		||||
 | 
			
		||||
[](https://godoc.org/github.com/bwmarrin/discordgo) [](http://goreportcard.com/report/bwmarrin/discordgo) [](https://travis-ci.org/bwmarrin/discordgo) [](https://discord.gg/0f1SbxBZjYoCtNPP) [](https://discord.com/invite/discord-api)
 | 
			
		||||
[](https://pkg.go.dev/github.com/bwmarrin/discordgo) [](https://goreportcard.com/report/github.com/bwmarrin/discordgo) [](https://travis-ci.com/bwmarrin/discordgo) [](https://discord.gg/golang) [](https://discord.com/invite/discord-api)
 | 
			
		||||
 | 
			
		||||
<img align="right" src="http://bwmarrin.github.io/discordgo/img/discordgo.png">
 | 
			
		||||
<img align="right" alt="DiscordGo logo" src="docs/img/discordgo.svg" width="400">
 | 
			
		||||
 | 
			
		||||
DiscordGo is a [Go](https://golang.org/) package that provides low level 
 | 
			
		||||
bindings to the [Discord](https://discord.com/) chat client API. DiscordGo 
 | 
			
		||||
@@ -22,7 +22,7 @@ tool that wraps `ffmpeg` to create opus encoded audio appropriate for use with
 | 
			
		||||
Discord (and DiscordGo).
 | 
			
		||||
 | 
			
		||||
**For help with this package or general Go discussion, please join the [Discord 
 | 
			
		||||
Gophers](https://discord.gg/0f1SbxBZjYq9jLBk) chat server.**
 | 
			
		||||
Gophers](https://discord.gg/golang) chat server.**
 | 
			
		||||
 | 
			
		||||
## Getting Started
 | 
			
		||||
 | 
			
		||||
@@ -64,8 +64,8 @@ The DiscordGo code is fairly well documented at this point and is currently
 | 
			
		||||
the only documentation available.  Both GoDoc and GoWalker (below) present
 | 
			
		||||
that information in a nice format.
 | 
			
		||||
 | 
			
		||||
- [](https://godoc.org/github.com/bwmarrin/discordgo) 
 | 
			
		||||
- [](https://gowalker.org/github.com/bwmarrin/discordgo) 
 | 
			
		||||
- [](https://pkg.go.dev/github.com/bwmarrin/discordgo)
 | 
			
		||||
- [](https://gowalker.org/github.com/bwmarrin/discordgo) 
 | 
			
		||||
- Hand crafted documentation coming eventually.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										241
									
								
								vendor/github.com/bwmarrin/discordgo/components.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								vendor/github.com/bwmarrin/discordgo/components.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,241 @@
 | 
			
		||||
package discordgo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ComponentType is type of component.
 | 
			
		||||
type ComponentType uint
 | 
			
		||||
 | 
			
		||||
// MessageComponent types.
 | 
			
		||||
const (
 | 
			
		||||
	ActionsRowComponent ComponentType = 1
 | 
			
		||||
	ButtonComponent     ComponentType = 2
 | 
			
		||||
	SelectMenuComponent ComponentType = 3
 | 
			
		||||
	TextInputComponent  ComponentType = 4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MessageComponent is a base interface for all message components.
 | 
			
		||||
type MessageComponent interface {
 | 
			
		||||
	json.Marshaler
 | 
			
		||||
	Type() ComponentType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type unmarshalableMessageComponent struct {
 | 
			
		||||
	MessageComponent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON is a helper function to unmarshal MessageComponent object.
 | 
			
		||||
func (umc *unmarshalableMessageComponent) UnmarshalJSON(src []byte) error {
 | 
			
		||||
	var v struct {
 | 
			
		||||
		Type ComponentType `json:"type"`
 | 
			
		||||
	}
 | 
			
		||||
	err := json.Unmarshal(src, &v)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch v.Type {
 | 
			
		||||
	case ActionsRowComponent:
 | 
			
		||||
		umc.MessageComponent = &ActionsRow{}
 | 
			
		||||
	case ButtonComponent:
 | 
			
		||||
		umc.MessageComponent = &Button{}
 | 
			
		||||
	case SelectMenuComponent:
 | 
			
		||||
		umc.MessageComponent = &SelectMenu{}
 | 
			
		||||
	case TextInputComponent:
 | 
			
		||||
		umc.MessageComponent = &TextInput{}
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("unknown component type: %d", v.Type)
 | 
			
		||||
	}
 | 
			
		||||
	return json.Unmarshal(src, umc.MessageComponent)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageComponentFromJSON is a helper function for unmarshaling message components
 | 
			
		||||
func MessageComponentFromJSON(b []byte) (MessageComponent, error) {
 | 
			
		||||
	var u unmarshalableMessageComponent
 | 
			
		||||
	err := u.UnmarshalJSON(b)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("failed to unmarshal into MessageComponent: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return u.MessageComponent, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ActionsRow is a container for components within one row.
 | 
			
		||||
type ActionsRow struct {
 | 
			
		||||
	Components []MessageComponent `json:"components"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalJSON is a method for marshaling ActionsRow to a JSON object.
 | 
			
		||||
func (r ActionsRow) MarshalJSON() ([]byte, error) {
 | 
			
		||||
	type actionsRow ActionsRow
 | 
			
		||||
 | 
			
		||||
	return Marshal(struct {
 | 
			
		||||
		actionsRow
 | 
			
		||||
		Type ComponentType `json:"type"`
 | 
			
		||||
	}{
 | 
			
		||||
		actionsRow: actionsRow(r),
 | 
			
		||||
		Type:       r.Type(),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON is a helper function to unmarshal Actions Row.
 | 
			
		||||
func (r *ActionsRow) UnmarshalJSON(data []byte) error {
 | 
			
		||||
	var v struct {
 | 
			
		||||
		RawComponents []unmarshalableMessageComponent `json:"components"`
 | 
			
		||||
	}
 | 
			
		||||
	err := json.Unmarshal(data, &v)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	r.Components = make([]MessageComponent, len(v.RawComponents))
 | 
			
		||||
	for i, v := range v.RawComponents {
 | 
			
		||||
		r.Components[i] = v.MessageComponent
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type is a method to get the type of a component.
 | 
			
		||||
func (r ActionsRow) Type() ComponentType {
 | 
			
		||||
	return ActionsRowComponent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ButtonStyle is style of button.
 | 
			
		||||
type ButtonStyle uint
 | 
			
		||||
 | 
			
		||||
// Button styles.
 | 
			
		||||
const (
 | 
			
		||||
	// PrimaryButton is a button with blurple color.
 | 
			
		||||
	PrimaryButton ButtonStyle = 1
 | 
			
		||||
	// SecondaryButton is a button with grey color.
 | 
			
		||||
	SecondaryButton ButtonStyle = 2
 | 
			
		||||
	// SuccessButton is a button with green color.
 | 
			
		||||
	SuccessButton ButtonStyle = 3
 | 
			
		||||
	// DangerButton is a button with red color.
 | 
			
		||||
	DangerButton ButtonStyle = 4
 | 
			
		||||
	// LinkButton is a special type of button which navigates to a URL. Has grey color.
 | 
			
		||||
	LinkButton ButtonStyle = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ComponentEmoji represents button emoji, if it does have one.
 | 
			
		||||
type ComponentEmoji struct {
 | 
			
		||||
	Name     string `json:"name,omitempty"`
 | 
			
		||||
	ID       string `json:"id,omitempty"`
 | 
			
		||||
	Animated bool   `json:"animated,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Button represents button component.
 | 
			
		||||
type Button struct {
 | 
			
		||||
	Label    string         `json:"label"`
 | 
			
		||||
	Style    ButtonStyle    `json:"style"`
 | 
			
		||||
	Disabled bool           `json:"disabled"`
 | 
			
		||||
	Emoji    ComponentEmoji `json:"emoji"`
 | 
			
		||||
 | 
			
		||||
	// NOTE: Only button with LinkButton style can have link. Also, URL is mutually exclusive with CustomID.
 | 
			
		||||
	URL      string `json:"url,omitempty"`
 | 
			
		||||
	CustomID string `json:"custom_id,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalJSON is a method for marshaling Button to a JSON object.
 | 
			
		||||
func (b Button) MarshalJSON() ([]byte, error) {
 | 
			
		||||
	type button Button
 | 
			
		||||
 | 
			
		||||
	if b.Style == 0 {
 | 
			
		||||
		b.Style = PrimaryButton
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Marshal(struct {
 | 
			
		||||
		button
 | 
			
		||||
		Type ComponentType `json:"type"`
 | 
			
		||||
	}{
 | 
			
		||||
		button: button(b),
 | 
			
		||||
		Type:   b.Type(),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type is a method to get the type of a component.
 | 
			
		||||
func (Button) Type() ComponentType {
 | 
			
		||||
	return ButtonComponent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SelectMenuOption represents an option for a select menu.
 | 
			
		||||
type SelectMenuOption struct {
 | 
			
		||||
	Label       string         `json:"label,omitempty"`
 | 
			
		||||
	Value       string         `json:"value"`
 | 
			
		||||
	Description string         `json:"description"`
 | 
			
		||||
	Emoji       ComponentEmoji `json:"emoji"`
 | 
			
		||||
	// Determines whenever option is selected by default or not.
 | 
			
		||||
	Default bool `json:"default"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SelectMenu represents select menu component.
 | 
			
		||||
type SelectMenu struct {
 | 
			
		||||
	CustomID string `json:"custom_id,omitempty"`
 | 
			
		||||
	// The text which will be shown in the menu if there's no default options or all options was deselected and component was closed.
 | 
			
		||||
	Placeholder string `json:"placeholder"`
 | 
			
		||||
	// This value determines the minimal amount of selected items in the menu.
 | 
			
		||||
	MinValues *int `json:"min_values,omitempty"`
 | 
			
		||||
	// This value determines the maximal amount of selected items in the menu.
 | 
			
		||||
	// If MaxValues or MinValues are greater than one then the user can select multiple items in the component.
 | 
			
		||||
	MaxValues int                `json:"max_values,omitempty"`
 | 
			
		||||
	Options   []SelectMenuOption `json:"options"`
 | 
			
		||||
	Disabled  bool               `json:"disabled"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type is a method to get the type of a component.
 | 
			
		||||
func (SelectMenu) Type() ComponentType {
 | 
			
		||||
	return SelectMenuComponent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalJSON is a method for marshaling SelectMenu to a JSON object.
 | 
			
		||||
func (m SelectMenu) MarshalJSON() ([]byte, error) {
 | 
			
		||||
	type selectMenu SelectMenu
 | 
			
		||||
 | 
			
		||||
	return Marshal(struct {
 | 
			
		||||
		selectMenu
 | 
			
		||||
		Type ComponentType `json:"type"`
 | 
			
		||||
	}{
 | 
			
		||||
		selectMenu: selectMenu(m),
 | 
			
		||||
		Type:       m.Type(),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TextInput represents text input component.
 | 
			
		||||
type TextInput struct {
 | 
			
		||||
	CustomID    string         `json:"custom_id"`
 | 
			
		||||
	Label       string         `json:"label"`
 | 
			
		||||
	Style       TextInputStyle `json:"style"`
 | 
			
		||||
	Placeholder string         `json:"placeholder,omitempty"`
 | 
			
		||||
	Value       string         `json:"value,omitempty"`
 | 
			
		||||
	Required    bool           `json:"required"`
 | 
			
		||||
	MinLength   int            `json:"min_length,omitempty"`
 | 
			
		||||
	MaxLength   int            `json:"max_length,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type is a method to get the type of a component.
 | 
			
		||||
func (TextInput) Type() ComponentType {
 | 
			
		||||
	return TextInputComponent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalJSON is a method for marshaling TextInput to a JSON object.
 | 
			
		||||
func (m TextInput) MarshalJSON() ([]byte, error) {
 | 
			
		||||
	type inputText TextInput
 | 
			
		||||
 | 
			
		||||
	return Marshal(struct {
 | 
			
		||||
		inputText
 | 
			
		||||
		Type ComponentType `json:"type"`
 | 
			
		||||
	}{
 | 
			
		||||
		inputText: inputText(m),
 | 
			
		||||
		Type:      m.Type(),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TextInputStyle is style of text in TextInput component.
 | 
			
		||||
type TextInputStyle uint
 | 
			
		||||
 | 
			
		||||
// Text styles
 | 
			
		||||
const (
 | 
			
		||||
	TextInputShort     TextInputStyle = 1
 | 
			
		||||
	TextInputParagraph TextInputStyle = 2
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										60
									
								
								vendor/github.com/bwmarrin/discordgo/discord.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/bwmarrin/discordgo/discord.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
// Discordgo - Discord bindings for Go
 | 
			
		||||
// Available at https://github.com/bwmarrin/discordgo
 | 
			
		||||
 | 
			
		||||
// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// This file contains high level helper functions and easy entry points for the
 | 
			
		||||
// entire discordgo package.  These functions are being developed and are very
 | 
			
		||||
// experimental at this point.  They will most likely change so please use the
 | 
			
		||||
// low level functions if that's a problem.
 | 
			
		||||
 | 
			
		||||
// Package discordgo provides Discord binding for Go
 | 
			
		||||
package discordgo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
 | 
			
		||||
const VERSION = "0.25.0"
 | 
			
		||||
 | 
			
		||||
// New creates a new Discord session with provided token.
 | 
			
		||||
// If the token is for a bot, it must be prefixed with "Bot "
 | 
			
		||||
// 		e.g. "Bot ..."
 | 
			
		||||
// Or if it is an OAuth2 token, it must be prefixed with "Bearer "
 | 
			
		||||
//		e.g. "Bearer ..."
 | 
			
		||||
func New(token string) (s *Session, err error) {
 | 
			
		||||
 | 
			
		||||
	// Create an empty Session interface.
 | 
			
		||||
	s = &Session{
 | 
			
		||||
		State:                  NewState(),
 | 
			
		||||
		Ratelimiter:            NewRatelimiter(),
 | 
			
		||||
		StateEnabled:           true,
 | 
			
		||||
		Compress:               true,
 | 
			
		||||
		ShouldReconnectOnError: true,
 | 
			
		||||
		ShouldRetryOnRateLimit: true,
 | 
			
		||||
		ShardID:                0,
 | 
			
		||||
		ShardCount:             1,
 | 
			
		||||
		MaxRestRetries:         3,
 | 
			
		||||
		Client:                 &http.Client{Timeout: (20 * time.Second)},
 | 
			
		||||
		UserAgent:              "DiscordBot (https://github.com/bwmarrin/discordgo, v" + VERSION + ")",
 | 
			
		||||
		sequence:               new(int64),
 | 
			
		||||
		LastHeartbeatAck:       time.Now().UTC(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Initilize the Identify Package with defaults
 | 
			
		||||
	// These can be modified prior to calling Open()
 | 
			
		||||
	s.Identify.Compress = true
 | 
			
		||||
	s.Identify.LargeThreshold = 250
 | 
			
		||||
	s.Identify.Properties.OS = runtime.GOOS
 | 
			
		||||
	s.Identify.Properties.Browser = "DiscordGo v" + VERSION
 | 
			
		||||
	s.Identify.Intents = IntentsAllWithoutPrivileged
 | 
			
		||||
	s.Identify.Token = token
 | 
			
		||||
	s.Token = token
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										213
									
								
								vendor/github.com/bwmarrin/discordgo/endpoints.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								vendor/github.com/bwmarrin/discordgo/endpoints.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,213 @@
 | 
			
		||||
// Discordgo - Discord bindings for Go
 | 
			
		||||
// Available at https://github.com/bwmarrin/discordgo
 | 
			
		||||
 | 
			
		||||
// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// This file contains variables for all known Discord end points.  All functions
 | 
			
		||||
// throughout the Discordgo package use these variables for all connections
 | 
			
		||||
// to Discord.  These are all exported and you may modify them if needed.
 | 
			
		||||
 | 
			
		||||
package discordgo
 | 
			
		||||
 | 
			
		||||
import "strconv"
 | 
			
		||||
 | 
			
		||||
// APIVersion is the Discord API version used for the REST and Websocket API.
 | 
			
		||||
var APIVersion = "9"
 | 
			
		||||
 | 
			
		||||
// Known Discord API Endpoints.
 | 
			
		||||
var (
 | 
			
		||||
	EndpointStatus     = "https://status.discord.com/api/v2/"
 | 
			
		||||
	EndpointSm         = EndpointStatus + "scheduled-maintenances/"
 | 
			
		||||
	EndpointSmActive   = EndpointSm + "active.json"
 | 
			
		||||
	EndpointSmUpcoming = EndpointSm + "upcoming.json"
 | 
			
		||||
 | 
			
		||||
	EndpointDiscord        = "https://discord.com/"
 | 
			
		||||
	EndpointAPI            = EndpointDiscord + "api/v" + APIVersion + "/"
 | 
			
		||||
	EndpointGuilds         = EndpointAPI + "guilds/"
 | 
			
		||||
	EndpointChannels       = EndpointAPI + "channels/"
 | 
			
		||||
	EndpointUsers          = EndpointAPI + "users/"
 | 
			
		||||
	EndpointGateway        = EndpointAPI + "gateway"
 | 
			
		||||
	EndpointGatewayBot     = EndpointGateway + "/bot"
 | 
			
		||||
	EndpointWebhooks       = EndpointAPI + "webhooks/"
 | 
			
		||||
	EndpointStickers       = EndpointAPI + "stickers/"
 | 
			
		||||
	EndpointStageInstances = EndpointAPI + "stage-instances"
 | 
			
		||||
 | 
			
		||||
	EndpointCDN             = "https://cdn.discordapp.com/"
 | 
			
		||||
	EndpointCDNAttachments  = EndpointCDN + "attachments/"
 | 
			
		||||
	EndpointCDNAvatars      = EndpointCDN + "avatars/"
 | 
			
		||||
	EndpointCDNIcons        = EndpointCDN + "icons/"
 | 
			
		||||
	EndpointCDNSplashes     = EndpointCDN + "splashes/"
 | 
			
		||||
	EndpointCDNChannelIcons = EndpointCDN + "channel-icons/"
 | 
			
		||||
	EndpointCDNBanners      = EndpointCDN + "banners/"
 | 
			
		||||
	EndpointCDNGuilds       = EndpointCDN + "guilds/"
 | 
			
		||||
 | 
			
		||||
	EndpointVoice        = EndpointAPI + "/voice/"
 | 
			
		||||
	EndpointVoiceRegions = EndpointVoice + "regions"
 | 
			
		||||
 | 
			
		||||
	// TODO: EndpointUserGuildMember
 | 
			
		||||
 | 
			
		||||
	EndpointUser               = func(uID string) string { return EndpointUsers + uID }
 | 
			
		||||
	EndpointUserAvatar         = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" }
 | 
			
		||||
	EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" }
 | 
			
		||||
	EndpointDefaultUserAvatar  = func(uDiscriminator string) string {
 | 
			
		||||
		uDiscriminatorInt, _ := strconv.Atoi(uDiscriminator)
 | 
			
		||||
		return EndpointCDN + "embed/avatars/" + strconv.Itoa(uDiscriminatorInt%5) + ".png"
 | 
			
		||||
	}
 | 
			
		||||
	EndpointUserBanner = func(uID, cID string) string {
 | 
			
		||||
		return EndpointCDNBanners + uID + "/" + cID + ".png"
 | 
			
		||||
	}
 | 
			
		||||
	EndpointUserBannerAnimated = func(uID, cID string) string {
 | 
			
		||||
		return EndpointCDNBanners + uID + "/" + cID + ".gif"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	EndpointUserGuilds      = func(uID string) string { return EndpointUsers + uID + "/guilds" }
 | 
			
		||||
	EndpointUserGuild       = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
 | 
			
		||||
	EndpointUserChannels    = func(uID string) string { return EndpointUsers + uID + "/channels" }
 | 
			
		||||
	EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
 | 
			
		||||
 | 
			
		||||
	EndpointGuild                    = func(gID string) string { return EndpointGuilds + gID }
 | 
			
		||||
	EndpointGuildThreads             = func(gID string) string { return EndpointGuild(gID) + "/threads" }
 | 
			
		||||
	EndpointGuildActiveThreads       = func(gID string) string { return EndpointGuildThreads(gID) + "/active" }
 | 
			
		||||
	EndpointGuildPreview             = func(gID string) string { return EndpointGuilds + gID + "/preview" }
 | 
			
		||||
	EndpointGuildChannels            = func(gID string) string { return EndpointGuilds + gID + "/channels" }
 | 
			
		||||
	EndpointGuildMembers             = func(gID string) string { return EndpointGuilds + gID + "/members" }
 | 
			
		||||
	EndpointGuildMembersSearch       = func(gID string) string { return EndpointGuildMembers(gID) + "/search" }
 | 
			
		||||
	EndpointGuildMember              = func(gID, uID string) string { return EndpointGuilds + gID + "/members/" + uID }
 | 
			
		||||
	EndpointGuildMemberRole          = func(gID, uID, rID string) string { return EndpointGuilds + gID + "/members/" + uID + "/roles/" + rID }
 | 
			
		||||
	EndpointGuildBans                = func(gID string) string { return EndpointGuilds + gID + "/bans" }
 | 
			
		||||
	EndpointGuildBan                 = func(gID, uID string) string { return EndpointGuilds + gID + "/bans/" + uID }
 | 
			
		||||
	EndpointGuildIntegrations        = func(gID string) string { return EndpointGuilds + gID + "/integrations" }
 | 
			
		||||
	EndpointGuildIntegration         = func(gID, iID string) string { return EndpointGuilds + gID + "/integrations/" + iID }
 | 
			
		||||
	EndpointGuildRoles               = func(gID string) string { return EndpointGuilds + gID + "/roles" }
 | 
			
		||||
	EndpointGuildRole                = func(gID, rID string) string { return EndpointGuilds + gID + "/roles/" + rID }
 | 
			
		||||
	EndpointGuildInvites             = func(gID string) string { return EndpointGuilds + gID + "/invites" }
 | 
			
		||||
	EndpointGuildWidget              = func(gID string) string { return EndpointGuilds + gID + "/widget" }
 | 
			
		||||
	EndpointGuildEmbed               = EndpointGuildWidget
 | 
			
		||||
	EndpointGuildPrune               = func(gID string) string { return EndpointGuilds + gID + "/prune" }
 | 
			
		||||
	EndpointGuildIcon                = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" }
 | 
			
		||||
	EndpointGuildIconAnimated        = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" }
 | 
			
		||||
	EndpointGuildSplash              = func(gID, hash string) string { return EndpointCDNSplashes + gID + "/" + hash + ".png" }
 | 
			
		||||
	EndpointGuildWebhooks            = func(gID string) string { return EndpointGuilds + gID + "/webhooks" }
 | 
			
		||||
	EndpointGuildAuditLogs           = func(gID string) string { return EndpointGuilds + gID + "/audit-logs" }
 | 
			
		||||
	EndpointGuildEmojis              = func(gID string) string { return EndpointGuilds + gID + "/emojis" }
 | 
			
		||||
	EndpointGuildEmoji               = func(gID, eID string) string { return EndpointGuilds + gID + "/emojis/" + eID }
 | 
			
		||||
	EndpointGuildBanner              = func(gID, hash string) string { return EndpointCDNBanners + gID + "/" + hash + ".png" }
 | 
			
		||||
	EndpointGuildStickers            = func(gID string) string { return EndpointGuilds + gID + "/stickers" }
 | 
			
		||||
	EndpointGuildSticker             = func(gID, sID string) string { return EndpointGuilds + gID + "/stickers/" + sID }
 | 
			
		||||
	EndpointStageInstance            = func(cID string) string { return EndpointStageInstances + "/" + cID }
 | 
			
		||||
	EndpointGuildScheduledEvents     = func(gID string) string { return EndpointGuilds + gID + "/scheduled-events" }
 | 
			
		||||
	EndpointGuildScheduledEvent      = func(gID, eID string) string { return EndpointGuilds + gID + "/scheduled-events/" + eID }
 | 
			
		||||
	EndpointGuildScheduledEventUsers = func(gID, eID string) string { return EndpointGuildScheduledEvent(gID, eID) + "/users" }
 | 
			
		||||
	EndpointGuildTemplate            = func(tID string) string { return EndpointGuilds + "/templates/" + tID }
 | 
			
		||||
	EndpointGuildTemplates           = func(gID string) string { return EndpointGuilds + gID + "/templates" }
 | 
			
		||||
	EndpointGuildTemplateSync        = func(gID, tID string) string { return EndpointGuilds + gID + "/templates/" + tID }
 | 
			
		||||
	EndpointGuildMemberAvatar        = func(gId, uID, aID string) string {
 | 
			
		||||
		return EndpointCDNGuilds + gId + "/users/" + uID + "/avatars/" + aID + ".png"
 | 
			
		||||
	}
 | 
			
		||||
	EndpointGuildMemberAvatarAnimated = func(gId, uID, aID string) string {
 | 
			
		||||
		return EndpointCDNGuilds + gId + "/users/" + uID + "/avatars/" + aID + ".gif"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	EndpointChannel                             = func(cID string) string { return EndpointChannels + cID }
 | 
			
		||||
	EndpointChannelThreads                      = func(cID string) string { return EndpointChannel(cID) + "/threads" }
 | 
			
		||||
	EndpointChannelActiveThreads                = func(cID string) string { return EndpointChannelThreads(cID) + "/active" }
 | 
			
		||||
	EndpointChannelPublicArchivedThreads        = func(cID string) string { return EndpointChannelThreads(cID) + "/archived/public" }
 | 
			
		||||
	EndpointChannelPrivateArchivedThreads       = func(cID string) string { return EndpointChannelThreads(cID) + "/archived/private" }
 | 
			
		||||
	EndpointChannelJoinedPrivateArchivedThreads = func(cID string) string { return EndpointChannel(cID) + "/users/@me/threads/archived/private" }
 | 
			
		||||
	EndpointChannelPermissions                  = func(cID string) string { return EndpointChannels + cID + "/permissions" }
 | 
			
		||||
	EndpointChannelPermission                   = func(cID, tID string) string { return EndpointChannels + cID + "/permissions/" + tID }
 | 
			
		||||
	EndpointChannelInvites                      = func(cID string) string { return EndpointChannels + cID + "/invites" }
 | 
			
		||||
	EndpointChannelTyping                       = func(cID string) string { return EndpointChannels + cID + "/typing" }
 | 
			
		||||
	EndpointChannelMessages                     = func(cID string) string { return EndpointChannels + cID + "/messages" }
 | 
			
		||||
	EndpointChannelMessage                      = func(cID, mID string) string { return EndpointChannels + cID + "/messages/" + mID }
 | 
			
		||||
	EndpointChannelMessageThread                = func(cID, mID string) string { return EndpointChannelMessage(cID, mID) + "/threads" }
 | 
			
		||||
	EndpointChannelMessagesBulkDelete           = func(cID string) string { return EndpointChannel(cID) + "/messages/bulk-delete" }
 | 
			
		||||
	EndpointChannelMessagesPins                 = func(cID string) string { return EndpointChannel(cID) + "/pins" }
 | 
			
		||||
	EndpointChannelMessagePin                   = func(cID, mID string) string { return EndpointChannel(cID) + "/pins/" + mID }
 | 
			
		||||
	EndpointChannelMessageCrosspost             = func(cID, mID string) string { return EndpointChannel(cID) + "/messages/" + mID + "/crosspost" }
 | 
			
		||||
	EndpointChannelFollow                       = func(cID string) string { return EndpointChannel(cID) + "/followers" }
 | 
			
		||||
	EndpointThreadMembers                       = func(tID string) string { return EndpointChannel(tID) + "/thread-members" }
 | 
			
		||||
	EndpointThreadMember                        = func(tID, mID string) string { return EndpointThreadMembers(tID) + "/" + mID }
 | 
			
		||||
 | 
			
		||||
	EndpointGroupIcon = func(cID, hash string) string { return EndpointCDNChannelIcons + cID + "/" + hash + ".png" }
 | 
			
		||||
 | 
			
		||||
	EndpointSticker            = func(sID string) string { return EndpointStickers + sID }
 | 
			
		||||
	EndpointNitroStickersPacks = EndpointAPI + "/sticker-packs"
 | 
			
		||||
 | 
			
		||||
	EndpointChannelWebhooks = func(cID string) string { return EndpointChannel(cID) + "/webhooks" }
 | 
			
		||||
	EndpointWebhook         = func(wID string) string { return EndpointWebhooks + wID }
 | 
			
		||||
	EndpointWebhookToken    = func(wID, token string) string { return EndpointWebhooks + wID + "/" + token }
 | 
			
		||||
	EndpointWebhookMessage  = func(wID, token, messageID string) string {
 | 
			
		||||
		return EndpointWebhookToken(wID, token) + "/messages/" + messageID
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	EndpointMessageReactionsAll = func(cID, mID string) string {
 | 
			
		||||
		return EndpointChannelMessage(cID, mID) + "/reactions"
 | 
			
		||||
	}
 | 
			
		||||
	EndpointMessageReactions = func(cID, mID, eID string) string {
 | 
			
		||||
		return EndpointChannelMessage(cID, mID) + "/reactions/" + eID
 | 
			
		||||
	}
 | 
			
		||||
	EndpointMessageReaction = func(cID, mID, eID, uID string) string {
 | 
			
		||||
		return EndpointMessageReactions(cID, mID, eID) + "/" + uID
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	EndpointApplicationGlobalCommands = func(aID string) string {
 | 
			
		||||
		return EndpointApplication(aID) + "/commands"
 | 
			
		||||
	}
 | 
			
		||||
	EndpointApplicationGlobalCommand = func(aID, cID string) string {
 | 
			
		||||
		return EndpointApplicationGlobalCommands(aID) + "/" + cID
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	EndpointApplicationGuildCommands = func(aID, gID string) string {
 | 
			
		||||
		return EndpointApplication(aID) + "/guilds/" + gID + "/commands"
 | 
			
		||||
	}
 | 
			
		||||
	EndpointApplicationGuildCommand = func(aID, gID, cID string) string {
 | 
			
		||||
		return EndpointApplicationGuildCommands(aID, gID) + "/" + cID
 | 
			
		||||
	}
 | 
			
		||||
	EndpointApplicationCommandPermissions = func(aID, gID, cID string) string {
 | 
			
		||||
		return EndpointApplicationGuildCommand(aID, gID, cID) + "/permissions"
 | 
			
		||||
	}
 | 
			
		||||
	EndpointApplicationCommandsGuildPermissions = func(aID, gID string) string {
 | 
			
		||||
		return EndpointApplicationGuildCommands(aID, gID) + "/permissions"
 | 
			
		||||
	}
 | 
			
		||||
	EndpointInteraction = func(aID, iToken string) string {
 | 
			
		||||
		return EndpointAPI + "interactions/" + aID + "/" + iToken
 | 
			
		||||
	}
 | 
			
		||||
	EndpointInteractionResponse = func(iID, iToken string) string {
 | 
			
		||||
		return EndpointInteraction(iID, iToken) + "/callback"
 | 
			
		||||
	}
 | 
			
		||||
	EndpointInteractionResponseActions = func(aID, iToken string) string {
 | 
			
		||||
		return EndpointWebhookMessage(aID, iToken, "@original")
 | 
			
		||||
	}
 | 
			
		||||
	EndpointFollowupMessage = func(aID, iToken string) string {
 | 
			
		||||
		return EndpointWebhookToken(aID, iToken)
 | 
			
		||||
	}
 | 
			
		||||
	EndpointFollowupMessageActions = func(aID, iToken, mID string) string {
 | 
			
		||||
		return EndpointWebhookMessage(aID, iToken, mID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	EndpointGuildCreate = EndpointAPI + "guilds"
 | 
			
		||||
 | 
			
		||||
	EndpointInvite = func(iID string) string { return EndpointAPI + "invites/" + iID }
 | 
			
		||||
 | 
			
		||||
	EndpointEmoji         = func(eID string) string { return EndpointCDN + "emojis/" + eID + ".png" }
 | 
			
		||||
	EndpointEmojiAnimated = func(eID string) string { return EndpointCDN + "emojis/" + eID + ".gif" }
 | 
			
		||||
 | 
			
		||||
	EndpointApplications = EndpointAPI + "applications"
 | 
			
		||||
	EndpointApplication  = func(aID string) string { return EndpointApplications + "/" + aID }
 | 
			
		||||
 | 
			
		||||
	EndpointOAuth2                  = EndpointAPI + "oauth2/"
 | 
			
		||||
	EndpointOAuth2Applications      = EndpointOAuth2 + "applications"
 | 
			
		||||
	EndpointOAuth2Application       = func(aID string) string { return EndpointOAuth2Applications + "/" + aID }
 | 
			
		||||
	EndpointOAuth2ApplicationsBot   = func(aID string) string { return EndpointOAuth2Applications + "/" + aID + "/bot" }
 | 
			
		||||
	EndpointOAuth2ApplicationAssets = func(aID string) string { return EndpointOAuth2Applications + "/" + aID + "/assets" }
 | 
			
		||||
 | 
			
		||||
	// TODO: Deprecated, remove in the next release
 | 
			
		||||
	EndpointOauth2                  = EndpointOAuth2
 | 
			
		||||
	EndpointOauth2Applications      = EndpointOAuth2Applications
 | 
			
		||||
	EndpointOauth2Application       = EndpointOAuth2Application
 | 
			
		||||
	EndpointOauth2ApplicationsBot   = EndpointOAuth2ApplicationsBot
 | 
			
		||||
	EndpointOauth2ApplicationAssets = EndpointOAuth2ApplicationAssets
 | 
			
		||||
)
 | 
			
		||||
@@ -157,7 +157,7 @@ func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance
 | 
			
		||||
	onceHandlers := s.onceHandlers[t]
 | 
			
		||||
	for i := range onceHandlers {
 | 
			
		||||
		if onceHandlers[i] == ehi {
 | 
			
		||||
			s.onceHandlers[t] = append(onceHandlers[:i], handlers[i+1:]...)
 | 
			
		||||
			s.onceHandlers[t] = append(onceHandlers[:i], onceHandlers[i+1:]...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -7,50 +7,67 @@ package discordgo
 | 
			
		||||
// Event type values are used to match the events returned by Discord.
 | 
			
		||||
// EventTypes surrounded by __ are synthetic and are internal to DiscordGo.
 | 
			
		||||
const (
 | 
			
		||||
	channelCreateEventType            = "CHANNEL_CREATE"
 | 
			
		||||
	channelDeleteEventType            = "CHANNEL_DELETE"
 | 
			
		||||
	channelPinsUpdateEventType        = "CHANNEL_PINS_UPDATE"
 | 
			
		||||
	channelUpdateEventType            = "CHANNEL_UPDATE"
 | 
			
		||||
	connectEventType                  = "__CONNECT__"
 | 
			
		||||
	disconnectEventType               = "__DISCONNECT__"
 | 
			
		||||
	eventEventType                    = "__EVENT__"
 | 
			
		||||
	guildBanAddEventType              = "GUILD_BAN_ADD"
 | 
			
		||||
	guildBanRemoveEventType           = "GUILD_BAN_REMOVE"
 | 
			
		||||
	guildCreateEventType              = "GUILD_CREATE"
 | 
			
		||||
	guildDeleteEventType              = "GUILD_DELETE"
 | 
			
		||||
	guildEmojisUpdateEventType        = "GUILD_EMOJIS_UPDATE"
 | 
			
		||||
	guildIntegrationsUpdateEventType  = "GUILD_INTEGRATIONS_UPDATE"
 | 
			
		||||
	guildMemberAddEventType           = "GUILD_MEMBER_ADD"
 | 
			
		||||
	guildMemberRemoveEventType        = "GUILD_MEMBER_REMOVE"
 | 
			
		||||
	guildMemberUpdateEventType        = "GUILD_MEMBER_UPDATE"
 | 
			
		||||
	guildMembersChunkEventType        = "GUILD_MEMBERS_CHUNK"
 | 
			
		||||
	guildRoleCreateEventType          = "GUILD_ROLE_CREATE"
 | 
			
		||||
	guildRoleDeleteEventType          = "GUILD_ROLE_DELETE"
 | 
			
		||||
	guildRoleUpdateEventType          = "GUILD_ROLE_UPDATE"
 | 
			
		||||
	guildUpdateEventType              = "GUILD_UPDATE"
 | 
			
		||||
	messageAckEventType               = "MESSAGE_ACK"
 | 
			
		||||
	messageCreateEventType            = "MESSAGE_CREATE"
 | 
			
		||||
	messageDeleteEventType            = "MESSAGE_DELETE"
 | 
			
		||||
	messageDeleteBulkEventType        = "MESSAGE_DELETE_BULK"
 | 
			
		||||
	messageReactionAddEventType       = "MESSAGE_REACTION_ADD"
 | 
			
		||||
	messageReactionRemoveEventType    = "MESSAGE_REACTION_REMOVE"
 | 
			
		||||
	messageReactionRemoveAllEventType = "MESSAGE_REACTION_REMOVE_ALL"
 | 
			
		||||
	messageUpdateEventType            = "MESSAGE_UPDATE"
 | 
			
		||||
	presenceUpdateEventType           = "PRESENCE_UPDATE"
 | 
			
		||||
	presencesReplaceEventType         = "PRESENCES_REPLACE"
 | 
			
		||||
	rateLimitEventType                = "__RATE_LIMIT__"
 | 
			
		||||
	readyEventType                    = "READY"
 | 
			
		||||
	relationshipAddEventType          = "RELATIONSHIP_ADD"
 | 
			
		||||
	relationshipRemoveEventType       = "RELATIONSHIP_REMOVE"
 | 
			
		||||
	resumedEventType                  = "RESUMED"
 | 
			
		||||
	typingStartEventType              = "TYPING_START"
 | 
			
		||||
	userGuildSettingsUpdateEventType  = "USER_GUILD_SETTINGS_UPDATE"
 | 
			
		||||
	userNoteUpdateEventType           = "USER_NOTE_UPDATE"
 | 
			
		||||
	userSettingsUpdateEventType       = "USER_SETTINGS_UPDATE"
 | 
			
		||||
	userUpdateEventType               = "USER_UPDATE"
 | 
			
		||||
	voiceServerUpdateEventType        = "VOICE_SERVER_UPDATE"
 | 
			
		||||
	voiceStateUpdateEventType         = "VOICE_STATE_UPDATE"
 | 
			
		||||
	webhooksUpdateEventType           = "WEBHOOKS_UPDATE"
 | 
			
		||||
	channelCreateEventType                 = "CHANNEL_CREATE"
 | 
			
		||||
	channelDeleteEventType                 = "CHANNEL_DELETE"
 | 
			
		||||
	channelPinsUpdateEventType             = "CHANNEL_PINS_UPDATE"
 | 
			
		||||
	channelUpdateEventType                 = "CHANNEL_UPDATE"
 | 
			
		||||
	connectEventType                       = "__CONNECT__"
 | 
			
		||||
	disconnectEventType                    = "__DISCONNECT__"
 | 
			
		||||
	eventEventType                         = "__EVENT__"
 | 
			
		||||
	guildBanAddEventType                   = "GUILD_BAN_ADD"
 | 
			
		||||
	guildBanRemoveEventType                = "GUILD_BAN_REMOVE"
 | 
			
		||||
	guildCreateEventType                   = "GUILD_CREATE"
 | 
			
		||||
	guildDeleteEventType                   = "GUILD_DELETE"
 | 
			
		||||
	guildEmojisUpdateEventType             = "GUILD_EMOJIS_UPDATE"
 | 
			
		||||
	guildIntegrationsUpdateEventType       = "GUILD_INTEGRATIONS_UPDATE"
 | 
			
		||||
	guildMemberAddEventType                = "GUILD_MEMBER_ADD"
 | 
			
		||||
	guildMemberRemoveEventType             = "GUILD_MEMBER_REMOVE"
 | 
			
		||||
	guildMemberUpdateEventType             = "GUILD_MEMBER_UPDATE"
 | 
			
		||||
	guildMembersChunkEventType             = "GUILD_MEMBERS_CHUNK"
 | 
			
		||||
	guildRoleCreateEventType               = "GUILD_ROLE_CREATE"
 | 
			
		||||
	guildRoleDeleteEventType               = "GUILD_ROLE_DELETE"
 | 
			
		||||
	guildRoleUpdateEventType               = "GUILD_ROLE_UPDATE"
 | 
			
		||||
	guildStageInstanceCreateEventType      = "STAGE_INSTANCE_CREATE"
 | 
			
		||||
	guildStageInstanceUpdateEventType      = "STAGE_INSTANCE_UPDATE"
 | 
			
		||||
	guildStageInstanceDeleteEventType      = "STAGE_INSTANCE_DELETE"
 | 
			
		||||
	guildScheduledEventCreateEventType     = "GUILD_SCHEDULED_EVENT_CREATE"
 | 
			
		||||
	guildScheduledEventDeleteEventType     = "GUILD_SCHEDULED_EVENT_DELETE"
 | 
			
		||||
	guildScheduledEventUpdateEventType     = "GUILD_SCHEDULED_EVENT_UPDATE"
 | 
			
		||||
	guildScheduledEventUserAddEventType    = "GUILD_SCHEDULED_EVENT_USER_ADD"
 | 
			
		||||
	guildScheduledEventUserRemoveEventType = "GUILD_SCHEDULED_EVENT_USER_REMOVE"
 | 
			
		||||
	guildUpdateEventType                   = "GUILD_UPDATE"
 | 
			
		||||
	interactionCreateEventType             = "INTERACTION_CREATE"
 | 
			
		||||
	inviteCreateEventType                  = "INVITE_CREATE"
 | 
			
		||||
	inviteDeleteEventType                  = "INVITE_DELETE"
 | 
			
		||||
	messageAckEventType                    = "MESSAGE_ACK"
 | 
			
		||||
	messageCreateEventType                 = "MESSAGE_CREATE"
 | 
			
		||||
	messageDeleteEventType                 = "MESSAGE_DELETE"
 | 
			
		||||
	messageDeleteBulkEventType             = "MESSAGE_DELETE_BULK"
 | 
			
		||||
	messageReactionAddEventType            = "MESSAGE_REACTION_ADD"
 | 
			
		||||
	messageReactionRemoveEventType         = "MESSAGE_REACTION_REMOVE"
 | 
			
		||||
	messageReactionRemoveAllEventType      = "MESSAGE_REACTION_REMOVE_ALL"
 | 
			
		||||
	messageUpdateEventType                 = "MESSAGE_UPDATE"
 | 
			
		||||
	presenceUpdateEventType                = "PRESENCE_UPDATE"
 | 
			
		||||
	presencesReplaceEventType              = "PRESENCES_REPLACE"
 | 
			
		||||
	rateLimitEventType                     = "__RATE_LIMIT__"
 | 
			
		||||
	readyEventType                         = "READY"
 | 
			
		||||
	relationshipAddEventType               = "RELATIONSHIP_ADD"
 | 
			
		||||
	relationshipRemoveEventType            = "RELATIONSHIP_REMOVE"
 | 
			
		||||
	resumedEventType                       = "RESUMED"
 | 
			
		||||
	threadCreateEventType                  = "THREAD_CREATE"
 | 
			
		||||
	threadDeleteEventType                  = "THREAD_DELETE"
 | 
			
		||||
	threadListSyncEventType                = "THREAD_LIST_SYNC"
 | 
			
		||||
	threadMemberUpdateEventType            = "THREAD_MEMBER_UPDATE"
 | 
			
		||||
	threadMembersUpdateEventType           = "THREAD_MEMBERS_UPDATE"
 | 
			
		||||
	threadUpdateEventType                  = "THREAD_UPDATE"
 | 
			
		||||
	typingStartEventType                   = "TYPING_START"
 | 
			
		||||
	userGuildSettingsUpdateEventType       = "USER_GUILD_SETTINGS_UPDATE"
 | 
			
		||||
	userNoteUpdateEventType                = "USER_NOTE_UPDATE"
 | 
			
		||||
	userSettingsUpdateEventType            = "USER_SETTINGS_UPDATE"
 | 
			
		||||
	userUpdateEventType                    = "USER_UPDATE"
 | 
			
		||||
	voiceServerUpdateEventType             = "VOICE_SERVER_UPDATE"
 | 
			
		||||
	voiceStateUpdateEventType              = "VOICE_STATE_UPDATE"
 | 
			
		||||
	webhooksUpdateEventType                = "WEBHOOKS_UPDATE"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// channelCreateEventHandler is an event handler for ChannelCreate events.
 | 
			
		||||
@@ -438,6 +455,166 @@ func (eh guildRoleUpdateEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// guildStageInstanceEventCreateHandler is an event handler for StageInstanceEventCreate events.
 | 
			
		||||
type guildStageInstanceEventCreateHandler func(*Session, *StageInstanceEventCreate)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for StageInstanceEventCreate events.
 | 
			
		||||
func (eh guildStageInstanceEventCreateHandler) Type() string {
 | 
			
		||||
	return guildStageInstanceCreateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of StageInstanceEventCreate.
 | 
			
		||||
func (eh guildStageInstanceEventCreateHandler) New() interface{} {
 | 
			
		||||
	return &StageInstanceEventCreate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for StageInstanceEventCreate events.
 | 
			
		||||
func (eh guildStageInstanceEventCreateHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*StageInstanceEventCreate); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// guildStageInstanceEventUpdateHandler is an event handler for StageInstanceEventUpdate events.
 | 
			
		||||
type guildStageInstanceEventUpdateHandler func(*Session, *StageInstanceEventUpdate)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for StageInstanceEventUpdate events.
 | 
			
		||||
func (eh guildStageInstanceEventUpdateHandler) Type() string {
 | 
			
		||||
	return guildStageInstanceCreateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of StageInstanceEventUpdate.
 | 
			
		||||
func (eh guildStageInstanceEventUpdateHandler) New() interface{} {
 | 
			
		||||
	return &StageInstanceEventUpdate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for StageInstanceEventUpdate events.
 | 
			
		||||
func (eh guildStageInstanceEventUpdateHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*StageInstanceEventUpdate); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// guildStageInstanceEventDeleteHandler is an event handler for StageInstanceEventDelete events.
 | 
			
		||||
type guildStageInstanceEventDeleteHandler func(*Session, *StageInstanceEventDelete)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for StageInstanceEventDelete events.
 | 
			
		||||
func (eh guildStageInstanceEventDeleteHandler) Type() string {
 | 
			
		||||
	return guildStageInstanceCreateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of StageInstanceEventDelete.
 | 
			
		||||
func (eh guildStageInstanceEventDeleteHandler) New() interface{} {
 | 
			
		||||
	return &StageInstanceEventDelete{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for StageInstanceEventDelete events.
 | 
			
		||||
func (eh guildStageInstanceEventDeleteHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*StageInstanceEventDelete); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// guildScheduledEventCreateEventHandler is an event handler for GuildScheduledEventCreate events.
 | 
			
		||||
type guildScheduledEventCreateEventHandler func(*Session, *GuildScheduledEventCreate)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for GuildScheduledEventCreate events.
 | 
			
		||||
func (eh guildScheduledEventCreateEventHandler) Type() string {
 | 
			
		||||
	return guildScheduledEventCreateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of GuildScheduledEventCreate.
 | 
			
		||||
func (eh guildScheduledEventCreateEventHandler) New() interface{} {
 | 
			
		||||
	return &GuildScheduledEventCreate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for GuildScheduledEventCreate events.
 | 
			
		||||
func (eh guildScheduledEventCreateEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*GuildScheduledEventCreate); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// guildScheduledEventDeleteEventHandler is an event handler for GuildScheduledEventDelete events.
 | 
			
		||||
type guildScheduledEventDeleteEventHandler func(*Session, *GuildScheduledEventDelete)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for GuildScheduledEventDelete events.
 | 
			
		||||
func (eh guildScheduledEventDeleteEventHandler) Type() string {
 | 
			
		||||
	return guildScheduledEventDeleteEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of GuildScheduledEventDelete.
 | 
			
		||||
func (eh guildScheduledEventDeleteEventHandler) New() interface{} {
 | 
			
		||||
	return &GuildScheduledEventDelete{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for GuildScheduledEventDelete events.
 | 
			
		||||
func (eh guildScheduledEventDeleteEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*GuildScheduledEventDelete); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// guildScheduledEventUpdateEventHandler is an event handler for GuildScheduledEventUpdate events.
 | 
			
		||||
type guildScheduledEventUpdateEventHandler func(*Session, *GuildScheduledEventUpdate)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for GuildScheduledEventUpdate events.
 | 
			
		||||
func (eh guildScheduledEventUpdateEventHandler) Type() string {
 | 
			
		||||
	return guildScheduledEventUpdateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of GuildScheduledEventUpdate.
 | 
			
		||||
func (eh guildScheduledEventUpdateEventHandler) New() interface{} {
 | 
			
		||||
	return &GuildScheduledEventUpdate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for GuildScheduledEventUpdate events.
 | 
			
		||||
func (eh guildScheduledEventUpdateEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*GuildScheduledEventUpdate); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// guildScheduledEventUserAddEventHandler is an event handler for GuildScheduledEventUserAdd events.
 | 
			
		||||
type guildScheduledEventUserAddEventHandler func(*Session, *GuildScheduledEventUserAdd)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for GuildScheduledEventUserAdd events.
 | 
			
		||||
func (eh guildScheduledEventUserAddEventHandler) Type() string {
 | 
			
		||||
	return guildScheduledEventUserAddEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of GuildScheduledEventUserAdd.
 | 
			
		||||
func (eh guildScheduledEventUserAddEventHandler) New() interface{} {
 | 
			
		||||
	return &GuildScheduledEventUserAdd{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for GuildScheduledEventUserAdd events.
 | 
			
		||||
func (eh guildScheduledEventUserAddEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*GuildScheduledEventUserAdd); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// guildScheduledEventUserRemoveEventHandler is an event handler for GuildScheduledEventUserRemove events.
 | 
			
		||||
type guildScheduledEventUserRemoveEventHandler func(*Session, *GuildScheduledEventUserRemove)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for GuildScheduledEventUserRemove events.
 | 
			
		||||
func (eh guildScheduledEventUserRemoveEventHandler) Type() string {
 | 
			
		||||
	return guildScheduledEventUserRemoveEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of GuildScheduledEventUserRemove.
 | 
			
		||||
func (eh guildScheduledEventUserRemoveEventHandler) New() interface{} {
 | 
			
		||||
	return &GuildScheduledEventUserRemove{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for GuildScheduledEventUserRemove events.
 | 
			
		||||
func (eh guildScheduledEventUserRemoveEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*GuildScheduledEventUserRemove); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// guildUpdateEventHandler is an event handler for GuildUpdate events.
 | 
			
		||||
type guildUpdateEventHandler func(*Session, *GuildUpdate)
 | 
			
		||||
 | 
			
		||||
@@ -458,6 +635,66 @@ func (eh guildUpdateEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// interactionCreateEventHandler is an event handler for InteractionCreate events.
 | 
			
		||||
type interactionCreateEventHandler func(*Session, *InteractionCreate)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for InteractionCreate events.
 | 
			
		||||
func (eh interactionCreateEventHandler) Type() string {
 | 
			
		||||
	return interactionCreateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of InteractionCreate.
 | 
			
		||||
func (eh interactionCreateEventHandler) New() interface{} {
 | 
			
		||||
	return &InteractionCreate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for InteractionCreate events.
 | 
			
		||||
func (eh interactionCreateEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*InteractionCreate); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// inviteCreateEventHandler is an event handler for InviteCreate events.
 | 
			
		||||
type inviteCreateEventHandler func(*Session, *InviteCreate)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for InviteCreate events.
 | 
			
		||||
func (eh inviteCreateEventHandler) Type() string {
 | 
			
		||||
	return inviteCreateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of InviteCreate.
 | 
			
		||||
func (eh inviteCreateEventHandler) New() interface{} {
 | 
			
		||||
	return &InviteCreate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for InviteCreate events.
 | 
			
		||||
func (eh inviteCreateEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*InviteCreate); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// inviteDeleteEventHandler is an event handler for InviteDelete events.
 | 
			
		||||
type inviteDeleteEventHandler func(*Session, *InviteDelete)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for InviteDelete events.
 | 
			
		||||
func (eh inviteDeleteEventHandler) Type() string {
 | 
			
		||||
	return inviteDeleteEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of InviteDelete.
 | 
			
		||||
func (eh inviteDeleteEventHandler) New() interface{} {
 | 
			
		||||
	return &InviteDelete{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for InviteDelete events.
 | 
			
		||||
func (eh inviteDeleteEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*InviteDelete); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// messageAckEventHandler is an event handler for MessageAck events.
 | 
			
		||||
type messageAckEventHandler func(*Session, *MessageAck)
 | 
			
		||||
 | 
			
		||||
@@ -753,6 +990,126 @@ func (eh resumedEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// threadCreateEventHandler is an event handler for ThreadCreate events.
 | 
			
		||||
type threadCreateEventHandler func(*Session, *ThreadCreate)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for ThreadCreate events.
 | 
			
		||||
func (eh threadCreateEventHandler) Type() string {
 | 
			
		||||
	return threadCreateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of ThreadCreate.
 | 
			
		||||
func (eh threadCreateEventHandler) New() interface{} {
 | 
			
		||||
	return &ThreadCreate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for ThreadCreate events.
 | 
			
		||||
func (eh threadCreateEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*ThreadCreate); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// threadDeleteEventHandler is an event handler for ThreadDelete events.
 | 
			
		||||
type threadDeleteEventHandler func(*Session, *ThreadDelete)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for ThreadDelete events.
 | 
			
		||||
func (eh threadDeleteEventHandler) Type() string {
 | 
			
		||||
	return threadDeleteEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of ThreadDelete.
 | 
			
		||||
func (eh threadDeleteEventHandler) New() interface{} {
 | 
			
		||||
	return &ThreadDelete{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for ThreadDelete events.
 | 
			
		||||
func (eh threadDeleteEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*ThreadDelete); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// threadListSyncEventHandler is an event handler for ThreadListSync events.
 | 
			
		||||
type threadListSyncEventHandler func(*Session, *ThreadListSync)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for ThreadListSync events.
 | 
			
		||||
func (eh threadListSyncEventHandler) Type() string {
 | 
			
		||||
	return threadListSyncEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of ThreadListSync.
 | 
			
		||||
func (eh threadListSyncEventHandler) New() interface{} {
 | 
			
		||||
	return &ThreadListSync{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for ThreadListSync events.
 | 
			
		||||
func (eh threadListSyncEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*ThreadListSync); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// threadMemberUpdateEventHandler is an event handler for ThreadMemberUpdate events.
 | 
			
		||||
type threadMemberUpdateEventHandler func(*Session, *ThreadMemberUpdate)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for ThreadMemberUpdate events.
 | 
			
		||||
func (eh threadMemberUpdateEventHandler) Type() string {
 | 
			
		||||
	return threadMemberUpdateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of ThreadMemberUpdate.
 | 
			
		||||
func (eh threadMemberUpdateEventHandler) New() interface{} {
 | 
			
		||||
	return &ThreadMemberUpdate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for ThreadMemberUpdate events.
 | 
			
		||||
func (eh threadMemberUpdateEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*ThreadMemberUpdate); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// threadMembersUpdateEventHandler is an event handler for ThreadMembersUpdate events.
 | 
			
		||||
type threadMembersUpdateEventHandler func(*Session, *ThreadMembersUpdate)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for ThreadMembersUpdate events.
 | 
			
		||||
func (eh threadMembersUpdateEventHandler) Type() string {
 | 
			
		||||
	return threadMembersUpdateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of ThreadMembersUpdate.
 | 
			
		||||
func (eh threadMembersUpdateEventHandler) New() interface{} {
 | 
			
		||||
	return &ThreadMembersUpdate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for ThreadMembersUpdate events.
 | 
			
		||||
func (eh threadMembersUpdateEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*ThreadMembersUpdate); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// threadUpdateEventHandler is an event handler for ThreadUpdate events.
 | 
			
		||||
type threadUpdateEventHandler func(*Session, *ThreadUpdate)
 | 
			
		||||
 | 
			
		||||
// Type returns the event type for ThreadUpdate events.
 | 
			
		||||
func (eh threadUpdateEventHandler) Type() string {
 | 
			
		||||
	return threadUpdateEventType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new instance of ThreadUpdate.
 | 
			
		||||
func (eh threadUpdateEventHandler) New() interface{} {
 | 
			
		||||
	return &ThreadUpdate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle is the handler for ThreadUpdate events.
 | 
			
		||||
func (eh threadUpdateEventHandler) Handle(s *Session, i interface{}) {
 | 
			
		||||
	if t, ok := i.(*ThreadUpdate); ok {
 | 
			
		||||
		eh(s, t)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// typingStartEventHandler is an event handler for TypingStart events.
 | 
			
		||||
type typingStartEventHandler func(*Session, *TypingStart)
 | 
			
		||||
 | 
			
		||||
@@ -957,8 +1314,24 @@ func handlerForInterface(handler interface{}) EventHandler {
 | 
			
		||||
		return guildRoleDeleteEventHandler(v)
 | 
			
		||||
	case func(*Session, *GuildRoleUpdate):
 | 
			
		||||
		return guildRoleUpdateEventHandler(v)
 | 
			
		||||
	case func(*Session, *GuildScheduledEventCreate):
 | 
			
		||||
		return guildScheduledEventCreateEventHandler(v)
 | 
			
		||||
	case func(*Session, *GuildScheduledEventDelete):
 | 
			
		||||
		return guildScheduledEventDeleteEventHandler(v)
 | 
			
		||||
	case func(*Session, *GuildScheduledEventUpdate):
 | 
			
		||||
		return guildScheduledEventUpdateEventHandler(v)
 | 
			
		||||
	case func(*Session, *GuildScheduledEventUserAdd):
 | 
			
		||||
		return guildScheduledEventUserAddEventHandler(v)
 | 
			
		||||
	case func(*Session, *GuildScheduledEventUserRemove):
 | 
			
		||||
		return guildScheduledEventUserRemoveEventHandler(v)
 | 
			
		||||
	case func(*Session, *GuildUpdate):
 | 
			
		||||
		return guildUpdateEventHandler(v)
 | 
			
		||||
	case func(*Session, *InteractionCreate):
 | 
			
		||||
		return interactionCreateEventHandler(v)
 | 
			
		||||
	case func(*Session, *InviteCreate):
 | 
			
		||||
		return inviteCreateEventHandler(v)
 | 
			
		||||
	case func(*Session, *InviteDelete):
 | 
			
		||||
		return inviteDeleteEventHandler(v)
 | 
			
		||||
	case func(*Session, *MessageAck):
 | 
			
		||||
		return messageAckEventHandler(v)
 | 
			
		||||
	case func(*Session, *MessageCreate):
 | 
			
		||||
@@ -989,6 +1362,18 @@ func handlerForInterface(handler interface{}) EventHandler {
 | 
			
		||||
		return relationshipRemoveEventHandler(v)
 | 
			
		||||
	case func(*Session, *Resumed):
 | 
			
		||||
		return resumedEventHandler(v)
 | 
			
		||||
	case func(*Session, *ThreadCreate):
 | 
			
		||||
		return threadCreateEventHandler(v)
 | 
			
		||||
	case func(*Session, *ThreadDelete):
 | 
			
		||||
		return threadDeleteEventHandler(v)
 | 
			
		||||
	case func(*Session, *ThreadListSync):
 | 
			
		||||
		return threadListSyncEventHandler(v)
 | 
			
		||||
	case func(*Session, *ThreadMemberUpdate):
 | 
			
		||||
		return threadMemberUpdateEventHandler(v)
 | 
			
		||||
	case func(*Session, *ThreadMembersUpdate):
 | 
			
		||||
		return threadMembersUpdateEventHandler(v)
 | 
			
		||||
	case func(*Session, *ThreadUpdate):
 | 
			
		||||
		return threadUpdateEventHandler(v)
 | 
			
		||||
	case func(*Session, *TypingStart):
 | 
			
		||||
		return typingStartEventHandler(v)
 | 
			
		||||
	case func(*Session, *UserGuildSettingsUpdate):
 | 
			
		||||
@@ -1028,7 +1413,15 @@ func init() {
 | 
			
		||||
	registerInterfaceProvider(guildRoleCreateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(guildRoleDeleteEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(guildRoleUpdateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(guildScheduledEventCreateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(guildScheduledEventDeleteEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(guildScheduledEventUpdateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(guildScheduledEventUserAddEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(guildScheduledEventUserRemoveEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(guildUpdateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(interactionCreateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(inviteCreateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(inviteDeleteEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(messageAckEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(messageCreateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(messageDeleteEventHandler(nil))
 | 
			
		||||
@@ -1043,6 +1436,12 @@ func init() {
 | 
			
		||||
	registerInterfaceProvider(relationshipAddEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(relationshipRemoveEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(resumedEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(threadCreateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(threadDeleteEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(threadListSyncEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(threadMemberUpdateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(threadMembersUpdateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(threadUpdateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(typingStartEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(userGuildSettingsUpdateEventHandler(nil))
 | 
			
		||||
	registerInterfaceProvider(userNoteUpdateEventHandler(nil))
 | 
			
		||||
@@ -73,6 +73,53 @@ type ChannelPinsUpdate struct {
 | 
			
		||||
	GuildID          string `json:"guild_id,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ThreadCreate is the data for a ThreadCreate event.
 | 
			
		||||
type ThreadCreate struct {
 | 
			
		||||
	*Channel
 | 
			
		||||
	NewlyCreated bool `json:"newly_created"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ThreadUpdate is the data for a ThreadUpdate event.
 | 
			
		||||
type ThreadUpdate struct {
 | 
			
		||||
	*Channel
 | 
			
		||||
	BeforeUpdate *Channel `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ThreadDelete is the data for a ThreadDelete event.
 | 
			
		||||
type ThreadDelete struct {
 | 
			
		||||
	*Channel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ThreadListSync is the data for a ThreadListSync event.
 | 
			
		||||
type ThreadListSync struct {
 | 
			
		||||
	// The id of the guild
 | 
			
		||||
	GuildID string `json:"guild_id"`
 | 
			
		||||
	// The parent channel ids whose threads are being synced.
 | 
			
		||||
	// If omitted, then threads were synced for the entire guild.
 | 
			
		||||
	// This array may contain channel_ids that have no active threads as well, so you know to clear that data.
 | 
			
		||||
	ChannelIDs []string `json:"channel_ids"`
 | 
			
		||||
	// All active threads in the given channels that the current user can access
 | 
			
		||||
	Threads []*Channel `json:"threads"`
 | 
			
		||||
	// All thread member objects from the synced threads for the current user,
 | 
			
		||||
	// indicating which threads the current user has been added to
 | 
			
		||||
	Members []*ThreadMember `json:"members"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ThreadMemberUpdate is the data for a ThreadMemberUpdate event.
 | 
			
		||||
type ThreadMemberUpdate struct {
 | 
			
		||||
	*ThreadMember
 | 
			
		||||
	GuildID string `json:"guild_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ThreadMembersUpdate is the data for a ThreadMembersUpdate event.
 | 
			
		||||
type ThreadMembersUpdate struct {
 | 
			
		||||
	ID             string              `json:"id"`
 | 
			
		||||
	GuildID        string              `json:"guild_id"`
 | 
			
		||||
	MemberCount    int                 `json:"member_count"`
 | 
			
		||||
	AddedMembers   []AddedThreadMember `json:"added_members"`
 | 
			
		||||
	RemovedMembers []string            `json:"removed_member_ids"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GuildCreate is the data for a GuildCreate event.
 | 
			
		||||
type GuildCreate struct {
 | 
			
		||||
	*Guild
 | 
			
		||||
@@ -86,6 +133,7 @@ type GuildUpdate struct {
 | 
			
		||||
// GuildDelete is the data for a GuildDelete event.
 | 
			
		||||
type GuildDelete struct {
 | 
			
		||||
	*Guild
 | 
			
		||||
	BeforeDelete *Guild `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GuildBanAdd is the data for a GuildBanAdd event.
 | 
			
		||||
@@ -143,7 +191,9 @@ type GuildMembersChunk struct {
 | 
			
		||||
	Members    []*Member   `json:"members"`
 | 
			
		||||
	ChunkIndex int         `json:"chunk_index"`
 | 
			
		||||
	ChunkCount int         `json:"chunk_count"`
 | 
			
		||||
	NotFound   []string    `json:"not_found,omitempty"`
 | 
			
		||||
	Presences  []*Presence `json:"presences,omitempty"`
 | 
			
		||||
	Nonce      string      `json:"nonce,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GuildIntegrationsUpdate is the data for a GuildIntegrationsUpdate event.
 | 
			
		||||
@@ -151,6 +201,50 @@ type GuildIntegrationsUpdate struct {
 | 
			
		||||
	GuildID string `json:"guild_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StageInstanceEventCreate is the data for a StageInstanceEventCreate event.
 | 
			
		||||
type StageInstanceEventCreate struct {
 | 
			
		||||
	*StageInstance
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StageInstanceEventUpdate is the data for a StageInstanceEventUpdate event.
 | 
			
		||||
type StageInstanceEventUpdate struct {
 | 
			
		||||
	*StageInstance
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StageInstanceEventDelete is the data for a StageInstanceEventDelete event.
 | 
			
		||||
type StageInstanceEventDelete struct {
 | 
			
		||||
	*StageInstance
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GuildScheduledEventCreate is the data for a GuildScheduledEventCreate event.
 | 
			
		||||
type GuildScheduledEventCreate struct {
 | 
			
		||||
	*GuildScheduledEvent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GuildScheduledEventUpdate is the data for a GuildScheduledEventUpdate event.
 | 
			
		||||
type GuildScheduledEventUpdate struct {
 | 
			
		||||
	*GuildScheduledEvent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GuildScheduledEventDelete is the data for a GuildScheduledEventDelete event.
 | 
			
		||||
type GuildScheduledEventDelete struct {
 | 
			
		||||
	*GuildScheduledEvent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GuildScheduledEventUserAdd is the data for a GuildScheduledEventUserAdd event.
 | 
			
		||||
type GuildScheduledEventUserAdd struct {
 | 
			
		||||
	GuildScheduledEventID string `json:"guild_scheduled_event_id"`
 | 
			
		||||
	UserID                string `json:"user_id"`
 | 
			
		||||
	GuildID               string `json:"guild_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GuildScheduledEventUserRemove is the data for a GuildScheduledEventUserRemove event.
 | 
			
		||||
type GuildScheduledEventUserRemove struct {
 | 
			
		||||
	GuildScheduledEventID string `json:"guild_scheduled_event_id"`
 | 
			
		||||
	UserID                string `json:"user_id"`
 | 
			
		||||
	GuildID               string `json:"guild_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageAck is the data for a MessageAck event.
 | 
			
		||||
type MessageAck struct {
 | 
			
		||||
	MessageID string `json:"message_id"`
 | 
			
		||||
@@ -162,6 +256,11 @@ type MessageCreate struct {
 | 
			
		||||
	*Message
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON is a helper function to unmarshal MessageCreate object.
 | 
			
		||||
func (m *MessageCreate) UnmarshalJSON(b []byte) error {
 | 
			
		||||
	return json.Unmarshal(b, &m.Message)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageUpdate is the data for a MessageUpdate event.
 | 
			
		||||
type MessageUpdate struct {
 | 
			
		||||
	*Message
 | 
			
		||||
@@ -169,15 +268,26 @@ type MessageUpdate struct {
 | 
			
		||||
	BeforeUpdate *Message `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON is a helper function to unmarshal MessageUpdate object.
 | 
			
		||||
func (m *MessageUpdate) UnmarshalJSON(b []byte) error {
 | 
			
		||||
	return json.Unmarshal(b, &m.Message)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageDelete is the data for a MessageDelete event.
 | 
			
		||||
type MessageDelete struct {
 | 
			
		||||
	*Message
 | 
			
		||||
	BeforeDelete *Message `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON is a helper function to unmarshal MessageDelete object.
 | 
			
		||||
func (m *MessageDelete) UnmarshalJSON(b []byte) error {
 | 
			
		||||
	return json.Unmarshal(b, &m.Message)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageReactionAdd is the data for a MessageReactionAdd event.
 | 
			
		||||
type MessageReactionAdd struct {
 | 
			
		||||
	*MessageReaction
 | 
			
		||||
	Member *Member `json:"member,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageReactionRemove is the data for a MessageReactionRemove event.
 | 
			
		||||
@@ -267,3 +377,27 @@ type WebhooksUpdate struct {
 | 
			
		||||
	GuildID   string `json:"guild_id"`
 | 
			
		||||
	ChannelID string `json:"channel_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InteractionCreate is the data for a InteractionCreate event
 | 
			
		||||
type InteractionCreate struct {
 | 
			
		||||
	*Interaction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON is a helper function to unmarshal Interaction object.
 | 
			
		||||
func (i *InteractionCreate) UnmarshalJSON(b []byte) error {
 | 
			
		||||
	return json.Unmarshal(b, &i.Interaction)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InviteCreate is the data for a InviteCreate event
 | 
			
		||||
type InviteCreate struct {
 | 
			
		||||
	*Invite
 | 
			
		||||
	ChannelID string `json:"channel_id"`
 | 
			
		||||
	GuildID   string `json:"guild_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InviteDelete is the data for a InviteDelete event
 | 
			
		||||
type InviteDelete struct {
 | 
			
		||||
	ChannelID string `json:"channel_id"`
 | 
			
		||||
	GuildID   string `json:"guild_id"`
 | 
			
		||||
	Code      string `json:"code"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										574
									
								
								vendor/github.com/bwmarrin/discordgo/interactions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										574
									
								
								vendor/github.com/bwmarrin/discordgo/interactions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,574 @@
 | 
			
		||||
package discordgo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/ed25519"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// InteractionDeadline is the time allowed to respond to an interaction.
 | 
			
		||||
const InteractionDeadline = time.Second * 3
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandType represents the type of application command.
 | 
			
		||||
type ApplicationCommandType uint8
 | 
			
		||||
 | 
			
		||||
// Application command types
 | 
			
		||||
const (
 | 
			
		||||
	// ChatApplicationCommand is default command type. They are slash commands (i.e. called directly from the chat).
 | 
			
		||||
	ChatApplicationCommand ApplicationCommandType = 1
 | 
			
		||||
	// UserApplicationCommand adds command to user context menu.
 | 
			
		||||
	UserApplicationCommand ApplicationCommandType = 2
 | 
			
		||||
	// MessageApplicationCommand adds command to message context menu.
 | 
			
		||||
	MessageApplicationCommand ApplicationCommandType = 3
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ApplicationCommand represents an application's slash command.
 | 
			
		||||
type ApplicationCommand struct {
 | 
			
		||||
	ID                string                 `json:"id,omitempty"`
 | 
			
		||||
	ApplicationID     string                 `json:"application_id,omitempty"`
 | 
			
		||||
	Version           string                 `json:"version,omitempty"`
 | 
			
		||||
	Type              ApplicationCommandType `json:"type,omitempty"`
 | 
			
		||||
	Name              string                 `json:"name"`
 | 
			
		||||
	NameLocalizations *map[Locale]string     `json:"name_localizations,omitempty"`
 | 
			
		||||
	DefaultPermission *bool                  `json:"default_permission,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// NOTE: Chat commands only. Otherwise it mustn't be set.
 | 
			
		||||
 | 
			
		||||
	Description              string                      `json:"description,omitempty"`
 | 
			
		||||
	DescriptionLocalizations *map[Locale]string          `json:"description_localizations,omitempty"`
 | 
			
		||||
	Options                  []*ApplicationCommandOption `json:"options"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandOptionType indicates the type of a slash command's option.
 | 
			
		||||
type ApplicationCommandOptionType uint8
 | 
			
		||||
 | 
			
		||||
// Application command option types.
 | 
			
		||||
const (
 | 
			
		||||
	ApplicationCommandOptionSubCommand      ApplicationCommandOptionType = 1
 | 
			
		||||
	ApplicationCommandOptionSubCommandGroup ApplicationCommandOptionType = 2
 | 
			
		||||
	ApplicationCommandOptionString          ApplicationCommandOptionType = 3
 | 
			
		||||
	ApplicationCommandOptionInteger         ApplicationCommandOptionType = 4
 | 
			
		||||
	ApplicationCommandOptionBoolean         ApplicationCommandOptionType = 5
 | 
			
		||||
	ApplicationCommandOptionUser            ApplicationCommandOptionType = 6
 | 
			
		||||
	ApplicationCommandOptionChannel         ApplicationCommandOptionType = 7
 | 
			
		||||
	ApplicationCommandOptionRole            ApplicationCommandOptionType = 8
 | 
			
		||||
	ApplicationCommandOptionMentionable     ApplicationCommandOptionType = 9
 | 
			
		||||
	ApplicationCommandOptionNumber          ApplicationCommandOptionType = 10
 | 
			
		||||
	ApplicationCommandOptionAttachment      ApplicationCommandOptionType = 11
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (t ApplicationCommandOptionType) String() string {
 | 
			
		||||
	switch t {
 | 
			
		||||
	case ApplicationCommandOptionSubCommand:
 | 
			
		||||
		return "SubCommand"
 | 
			
		||||
	case ApplicationCommandOptionSubCommandGroup:
 | 
			
		||||
		return "SubCommandGroup"
 | 
			
		||||
	case ApplicationCommandOptionString:
 | 
			
		||||
		return "String"
 | 
			
		||||
	case ApplicationCommandOptionInteger:
 | 
			
		||||
		return "Integer"
 | 
			
		||||
	case ApplicationCommandOptionBoolean:
 | 
			
		||||
		return "Boolean"
 | 
			
		||||
	case ApplicationCommandOptionUser:
 | 
			
		||||
		return "User"
 | 
			
		||||
	case ApplicationCommandOptionChannel:
 | 
			
		||||
		return "Channel"
 | 
			
		||||
	case ApplicationCommandOptionRole:
 | 
			
		||||
		return "Role"
 | 
			
		||||
	case ApplicationCommandOptionMentionable:
 | 
			
		||||
		return "Mentionable"
 | 
			
		||||
	case ApplicationCommandOptionNumber:
 | 
			
		||||
		return "Number"
 | 
			
		||||
	case ApplicationCommandOptionAttachment:
 | 
			
		||||
		return "Attachment"
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("ApplicationCommandOptionType(%d)", t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandOption represents an option/subcommand/subcommands group.
 | 
			
		||||
type ApplicationCommandOption struct {
 | 
			
		||||
	Type                     ApplicationCommandOptionType `json:"type"`
 | 
			
		||||
	Name                     string                       `json:"name"`
 | 
			
		||||
	NameLocalizations        map[Locale]string            `json:"name_localizations,omitempty"`
 | 
			
		||||
	Description              string                       `json:"description,omitempty"`
 | 
			
		||||
	DescriptionLocalizations map[Locale]string            `json:"description_localizations,omitempty"`
 | 
			
		||||
	// NOTE: This feature was on the API, but at some point developers decided to remove it.
 | 
			
		||||
	// So I commented it, until it will be officially on the docs.
 | 
			
		||||
	// Default     bool                              `json:"default"`
 | 
			
		||||
 | 
			
		||||
	ChannelTypes []ChannelType               `json:"channel_types"`
 | 
			
		||||
	Required     bool                        `json:"required"`
 | 
			
		||||
	Options      []*ApplicationCommandOption `json:"options"`
 | 
			
		||||
 | 
			
		||||
	// NOTE: mutually exclusive with Choices.
 | 
			
		||||
	Autocomplete bool                              `json:"autocomplete"`
 | 
			
		||||
	Choices      []*ApplicationCommandOptionChoice `json:"choices"`
 | 
			
		||||
	// Minimal value of number/integer option.
 | 
			
		||||
	MinValue *float64 `json:"min_value,omitempty"`
 | 
			
		||||
	// Maximum value of number/integer option.
 | 
			
		||||
	MaxValue float64 `json:"max_value,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandOptionChoice represents a slash command option choice.
 | 
			
		||||
type ApplicationCommandOptionChoice struct {
 | 
			
		||||
	Name              string            `json:"name"`
 | 
			
		||||
	NameLocalizations map[Locale]string `json:"name_localizations,omitempty"`
 | 
			
		||||
	Value             interface{}       `json:"value"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandPermissions represents a single user or role permission for a command.
 | 
			
		||||
type ApplicationCommandPermissions struct {
 | 
			
		||||
	ID         string                           `json:"id"`
 | 
			
		||||
	Type       ApplicationCommandPermissionType `json:"type"`
 | 
			
		||||
	Permission bool                             `json:"permission"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandPermissionsList represents a list of ApplicationCommandPermissions, needed for serializing to JSON.
 | 
			
		||||
type ApplicationCommandPermissionsList struct {
 | 
			
		||||
	Permissions []*ApplicationCommandPermissions `json:"permissions"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GuildApplicationCommandPermissions represents all permissions for a single guild command.
 | 
			
		||||
type GuildApplicationCommandPermissions struct {
 | 
			
		||||
	ID            string                           `json:"id"`
 | 
			
		||||
	ApplicationID string                           `json:"application_id"`
 | 
			
		||||
	GuildID       string                           `json:"guild_id"`
 | 
			
		||||
	Permissions   []*ApplicationCommandPermissions `json:"permissions"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandPermissionType indicates whether a permission is user or role based.
 | 
			
		||||
type ApplicationCommandPermissionType uint8
 | 
			
		||||
 | 
			
		||||
// Application command permission types.
 | 
			
		||||
const (
 | 
			
		||||
	ApplicationCommandPermissionTypeRole ApplicationCommandPermissionType = 1
 | 
			
		||||
	ApplicationCommandPermissionTypeUser ApplicationCommandPermissionType = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// InteractionType indicates the type of an interaction event.
 | 
			
		||||
type InteractionType uint8
 | 
			
		||||
 | 
			
		||||
// Interaction types
 | 
			
		||||
const (
 | 
			
		||||
	InteractionPing                           InteractionType = 1
 | 
			
		||||
	InteractionApplicationCommand             InteractionType = 2
 | 
			
		||||
	InteractionMessageComponent               InteractionType = 3
 | 
			
		||||
	InteractionApplicationCommandAutocomplete InteractionType = 4
 | 
			
		||||
	InteractionModalSubmit                    InteractionType = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (t InteractionType) String() string {
 | 
			
		||||
	switch t {
 | 
			
		||||
	case InteractionPing:
 | 
			
		||||
		return "Ping"
 | 
			
		||||
	case InteractionApplicationCommand:
 | 
			
		||||
		return "ApplicationCommand"
 | 
			
		||||
	case InteractionMessageComponent:
 | 
			
		||||
		return "MessageComponent"
 | 
			
		||||
	case InteractionModalSubmit:
 | 
			
		||||
		return "ModalSubmit"
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("InteractionType(%d)", t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Interaction represents data of an interaction.
 | 
			
		||||
type Interaction struct {
 | 
			
		||||
	ID        string          `json:"id"`
 | 
			
		||||
	AppID     string          `json:"application_id"`
 | 
			
		||||
	Type      InteractionType `json:"type"`
 | 
			
		||||
	Data      InteractionData `json:"data"`
 | 
			
		||||
	GuildID   string          `json:"guild_id"`
 | 
			
		||||
	ChannelID string          `json:"channel_id"`
 | 
			
		||||
 | 
			
		||||
	// The message on which interaction was used.
 | 
			
		||||
	// NOTE: this field is only filled when a button click triggered the interaction. Otherwise it will be nil.
 | 
			
		||||
	Message *Message `json:"message"`
 | 
			
		||||
 | 
			
		||||
	// The member who invoked this interaction.
 | 
			
		||||
	// NOTE: this field is only filled when the slash command was invoked in a guild;
 | 
			
		||||
	// if it was invoked in a DM, the `User` field will be filled instead.
 | 
			
		||||
	// Make sure to check for `nil` before using this field.
 | 
			
		||||
	Member *Member `json:"member"`
 | 
			
		||||
	// The user who invoked this interaction.
 | 
			
		||||
	// NOTE: this field is only filled when the slash command was invoked in a DM;
 | 
			
		||||
	// if it was invoked in a guild, the `Member` field will be filled instead.
 | 
			
		||||
	// Make sure to check for `nil` before using this field.
 | 
			
		||||
	User *User `json:"user"`
 | 
			
		||||
 | 
			
		||||
	// The user's discord client locale.
 | 
			
		||||
	Locale Locale `json:"locale"`
 | 
			
		||||
	// The guild's locale. This defaults to EnglishUS
 | 
			
		||||
	// NOTE: this field is only filled when the interaction was invoked in a guild.
 | 
			
		||||
	GuildLocale *Locale `json:"guild_locale"`
 | 
			
		||||
 | 
			
		||||
	Token   string `json:"token"`
 | 
			
		||||
	Version int    `json:"version"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type interaction Interaction
 | 
			
		||||
 | 
			
		||||
type rawInteraction struct {
 | 
			
		||||
	interaction
 | 
			
		||||
	Data json.RawMessage `json:"data"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON is a method for unmarshalling JSON object to Interaction.
 | 
			
		||||
func (i *Interaction) UnmarshalJSON(raw []byte) error {
 | 
			
		||||
	var tmp rawInteraction
 | 
			
		||||
	err := json.Unmarshal(raw, &tmp)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*i = Interaction(tmp.interaction)
 | 
			
		||||
 | 
			
		||||
	switch tmp.Type {
 | 
			
		||||
	case InteractionApplicationCommand, InteractionApplicationCommandAutocomplete:
 | 
			
		||||
		v := ApplicationCommandInteractionData{}
 | 
			
		||||
		err = json.Unmarshal(tmp.Data, &v)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		i.Data = v
 | 
			
		||||
	case InteractionMessageComponent:
 | 
			
		||||
		v := MessageComponentInteractionData{}
 | 
			
		||||
		err = json.Unmarshal(tmp.Data, &v)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		i.Data = v
 | 
			
		||||
	case InteractionModalSubmit:
 | 
			
		||||
		v := ModalSubmitInteractionData{}
 | 
			
		||||
		err = json.Unmarshal(tmp.Data, &v)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		i.Data = v
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageComponentData is helper function to assert the inner InteractionData to MessageComponentInteractionData.
 | 
			
		||||
// Make sure to check that the Type of the interaction is InteractionMessageComponent before calling.
 | 
			
		||||
func (i Interaction) MessageComponentData() (data MessageComponentInteractionData) {
 | 
			
		||||
	if i.Type != InteractionMessageComponent {
 | 
			
		||||
		panic("MessageComponentData called on interaction of type " + i.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	return i.Data.(MessageComponentInteractionData)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandData is helper function to assert the inner InteractionData to ApplicationCommandInteractionData.
 | 
			
		||||
// Make sure to check that the Type of the interaction is InteractionApplicationCommand before calling.
 | 
			
		||||
func (i Interaction) ApplicationCommandData() (data ApplicationCommandInteractionData) {
 | 
			
		||||
	if i.Type != InteractionApplicationCommand && i.Type != InteractionApplicationCommandAutocomplete {
 | 
			
		||||
		panic("ApplicationCommandData called on interaction of type " + i.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	return i.Data.(ApplicationCommandInteractionData)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ModalSubmitData is helper function to assert the inner InteractionData to ModalSubmitInteractionData.
 | 
			
		||||
// Make sure to check that the Type of the interaction is InteractionModalSubmit before calling.
 | 
			
		||||
func (i Interaction) ModalSubmitData() (data ModalSubmitInteractionData) {
 | 
			
		||||
	if i.Type != InteractionModalSubmit {
 | 
			
		||||
		panic("ModalSubmitData called on interaction of type " + i.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	return i.Data.(ModalSubmitInteractionData)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InteractionData is a common interface for all types of interaction data.
 | 
			
		||||
type InteractionData interface {
 | 
			
		||||
	Type() InteractionType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandInteractionData contains the data of application command interaction.
 | 
			
		||||
type ApplicationCommandInteractionData struct {
 | 
			
		||||
	ID       string                                     `json:"id"`
 | 
			
		||||
	Name     string                                     `json:"name"`
 | 
			
		||||
	Resolved *ApplicationCommandInteractionDataResolved `json:"resolved"`
 | 
			
		||||
 | 
			
		||||
	// Slash command options
 | 
			
		||||
	Options []*ApplicationCommandInteractionDataOption `json:"options"`
 | 
			
		||||
	// Target (user/message) id on which context menu command was called.
 | 
			
		||||
	// The details are stored in Resolved according to command type.
 | 
			
		||||
	TargetID string `json:"target_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandInteractionDataResolved contains resolved data of command execution.
 | 
			
		||||
// Partial Member objects are missing user, deaf and mute fields.
 | 
			
		||||
// Partial Channel objects only have id, name, type and permissions fields.
 | 
			
		||||
type ApplicationCommandInteractionDataResolved struct {
 | 
			
		||||
	Users       map[string]*User              `json:"users"`
 | 
			
		||||
	Members     map[string]*Member            `json:"members"`
 | 
			
		||||
	Roles       map[string]*Role              `json:"roles"`
 | 
			
		||||
	Channels    map[string]*Channel           `json:"channels"`
 | 
			
		||||
	Messages    map[string]*Message           `json:"messages"`
 | 
			
		||||
	Attachments map[string]*MessageAttachment `json:"attachments"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type returns the type of interaction data.
 | 
			
		||||
func (ApplicationCommandInteractionData) Type() InteractionType {
 | 
			
		||||
	return InteractionApplicationCommand
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageComponentInteractionData contains the data of message component interaction.
 | 
			
		||||
type MessageComponentInteractionData struct {
 | 
			
		||||
	CustomID      string        `json:"custom_id"`
 | 
			
		||||
	ComponentType ComponentType `json:"component_type"`
 | 
			
		||||
 | 
			
		||||
	// NOTE: Only filled when ComponentType is SelectMenuComponent (3). Otherwise is nil.
 | 
			
		||||
	Values []string `json:"values"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type returns the type of interaction data.
 | 
			
		||||
func (MessageComponentInteractionData) Type() InteractionType {
 | 
			
		||||
	return InteractionMessageComponent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ModalSubmitInteractionData contains the data of modal submit interaction.
 | 
			
		||||
type ModalSubmitInteractionData struct {
 | 
			
		||||
	CustomID   string             `json:"custom_id"`
 | 
			
		||||
	Components []MessageComponent `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type returns the type of interaction data.
 | 
			
		||||
func (ModalSubmitInteractionData) Type() InteractionType {
 | 
			
		||||
	return InteractionModalSubmit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON is a helper function to correctly unmarshal Components.
 | 
			
		||||
func (d *ModalSubmitInteractionData) UnmarshalJSON(data []byte) error {
 | 
			
		||||
	type modalSubmitInteractionData ModalSubmitInteractionData
 | 
			
		||||
	var v struct {
 | 
			
		||||
		modalSubmitInteractionData
 | 
			
		||||
		RawComponents []unmarshalableMessageComponent `json:"components"`
 | 
			
		||||
	}
 | 
			
		||||
	err := json.Unmarshal(data, &v)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	*d = ModalSubmitInteractionData(v.modalSubmitInteractionData)
 | 
			
		||||
	d.Components = make([]MessageComponent, len(v.RawComponents))
 | 
			
		||||
	for i, v := range v.RawComponents {
 | 
			
		||||
		d.Components[i] = v.MessageComponent
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationCommandInteractionDataOption represents an option of a slash command.
 | 
			
		||||
type ApplicationCommandInteractionDataOption struct {
 | 
			
		||||
	Name string                       `json:"name"`
 | 
			
		||||
	Type ApplicationCommandOptionType `json:"type"`
 | 
			
		||||
	// NOTE: Contains the value specified by Type.
 | 
			
		||||
	Value   interface{}                                `json:"value,omitempty"`
 | 
			
		||||
	Options []*ApplicationCommandInteractionDataOption `json:"options,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// NOTE: autocomplete interaction only.
 | 
			
		||||
	Focused bool `json:"focused,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IntValue is a utility function for casting option value to integer
 | 
			
		||||
func (o ApplicationCommandInteractionDataOption) IntValue() int64 {
 | 
			
		||||
	if o.Type != ApplicationCommandOptionInteger {
 | 
			
		||||
		panic("IntValue called on data option of type " + o.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	return int64(o.Value.(float64))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UintValue is a utility function for casting option value to unsigned integer
 | 
			
		||||
func (o ApplicationCommandInteractionDataOption) UintValue() uint64 {
 | 
			
		||||
	if o.Type != ApplicationCommandOptionInteger {
 | 
			
		||||
		panic("UintValue called on data option of type " + o.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	return uint64(o.Value.(float64))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FloatValue is a utility function for casting option value to float
 | 
			
		||||
func (o ApplicationCommandInteractionDataOption) FloatValue() float64 {
 | 
			
		||||
	if o.Type != ApplicationCommandOptionNumber {
 | 
			
		||||
		panic("FloatValue called on data option of type " + o.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	return o.Value.(float64)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StringValue is a utility function for casting option value to string
 | 
			
		||||
func (o ApplicationCommandInteractionDataOption) StringValue() string {
 | 
			
		||||
	if o.Type != ApplicationCommandOptionString {
 | 
			
		||||
		panic("StringValue called on data option of type " + o.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	return o.Value.(string)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BoolValue is a utility function for casting option value to bool
 | 
			
		||||
func (o ApplicationCommandInteractionDataOption) BoolValue() bool {
 | 
			
		||||
	if o.Type != ApplicationCommandOptionBoolean {
 | 
			
		||||
		panic("BoolValue called on data option of type " + o.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	return o.Value.(bool)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChannelValue is a utility function for casting option value to channel object.
 | 
			
		||||
// s : Session object, if not nil, function additionally fetches all channel's data
 | 
			
		||||
func (o ApplicationCommandInteractionDataOption) ChannelValue(s *Session) *Channel {
 | 
			
		||||
	if o.Type != ApplicationCommandOptionChannel {
 | 
			
		||||
		panic("ChannelValue called on data option of type " + o.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	chanID := o.Value.(string)
 | 
			
		||||
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return &Channel{ID: chanID}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ch, err := s.State.Channel(chanID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ch, err = s.Channel(chanID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return &Channel{ID: chanID}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ch
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RoleValue is a utility function for casting option value to role object.
 | 
			
		||||
// s : Session object, if not nil, function additionally fetches all role's data
 | 
			
		||||
func (o ApplicationCommandInteractionDataOption) RoleValue(s *Session, gID string) *Role {
 | 
			
		||||
	if o.Type != ApplicationCommandOptionRole && o.Type != ApplicationCommandOptionMentionable {
 | 
			
		||||
		panic("RoleValue called on data option of type " + o.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	roleID := o.Value.(string)
 | 
			
		||||
 | 
			
		||||
	if s == nil || gID == "" {
 | 
			
		||||
		return &Role{ID: roleID}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r, err := s.State.Role(roleID, gID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		roles, err := s.GuildRoles(gID)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			for _, r = range roles {
 | 
			
		||||
				if r.ID == roleID {
 | 
			
		||||
					return r
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return &Role{ID: roleID}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UserValue is a utility function for casting option value to user object.
 | 
			
		||||
// s : Session object, if not nil, function additionally fetches all user's data
 | 
			
		||||
func (o ApplicationCommandInteractionDataOption) UserValue(s *Session) *User {
 | 
			
		||||
	if o.Type != ApplicationCommandOptionUser && o.Type != ApplicationCommandOptionMentionable {
 | 
			
		||||
		panic("UserValue called on data option of type " + o.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	userID := o.Value.(string)
 | 
			
		||||
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return &User{ID: userID}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	u, err := s.User(userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return &User{ID: userID}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return u
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InteractionResponseType is type of interaction response.
 | 
			
		||||
type InteractionResponseType uint8
 | 
			
		||||
 | 
			
		||||
// Interaction response types.
 | 
			
		||||
const (
 | 
			
		||||
	// InteractionResponsePong is for ACK ping event.
 | 
			
		||||
	InteractionResponsePong InteractionResponseType = 1
 | 
			
		||||
	// InteractionResponseChannelMessageWithSource is for responding with a message, showing the user's input.
 | 
			
		||||
	InteractionResponseChannelMessageWithSource InteractionResponseType = 4
 | 
			
		||||
	// InteractionResponseDeferredChannelMessageWithSource acknowledges that the event was received, and that a follow-up will come later.
 | 
			
		||||
	InteractionResponseDeferredChannelMessageWithSource InteractionResponseType = 5
 | 
			
		||||
	// InteractionResponseDeferredMessageUpdate acknowledges that the message component interaction event was received, and message will be updated later.
 | 
			
		||||
	InteractionResponseDeferredMessageUpdate InteractionResponseType = 6
 | 
			
		||||
	// InteractionResponseUpdateMessage is for updating the message to which message component was attached.
 | 
			
		||||
	InteractionResponseUpdateMessage InteractionResponseType = 7
 | 
			
		||||
	// InteractionApplicationCommandAutocompleteResult shows autocompletion results. Autocomplete interaction only.
 | 
			
		||||
	InteractionApplicationCommandAutocompleteResult InteractionResponseType = 8
 | 
			
		||||
	// InteractionResponseModal is for responding to an interaction with a modal window.
 | 
			
		||||
	InteractionResponseModal InteractionResponseType = 9
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// InteractionResponse represents a response for an interaction event.
 | 
			
		||||
type InteractionResponse struct {
 | 
			
		||||
	Type InteractionResponseType  `json:"type,omitempty"`
 | 
			
		||||
	Data *InteractionResponseData `json:"data,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InteractionResponseData is response data for an interaction.
 | 
			
		||||
type InteractionResponseData struct {
 | 
			
		||||
	TTS             bool                    `json:"tts"`
 | 
			
		||||
	Content         string                  `json:"content"`
 | 
			
		||||
	Components      []MessageComponent      `json:"components"`
 | 
			
		||||
	Embeds          []*MessageEmbed         `json:"embeds"`
 | 
			
		||||
	AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
 | 
			
		||||
	Flags           uint64                  `json:"flags,omitempty"`
 | 
			
		||||
	Files           []*File                 `json:"-"`
 | 
			
		||||
 | 
			
		||||
	// NOTE: autocomplete interaction only.
 | 
			
		||||
	Choices []*ApplicationCommandOptionChoice `json:"choices,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// NOTE: modal interaction only.
 | 
			
		||||
 | 
			
		||||
	CustomID string `json:"custom_id,omitempty"`
 | 
			
		||||
	Title    string `json:"title,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VerifyInteraction implements message verification of the discord interactions api
 | 
			
		||||
// signing algorithm, as documented here:
 | 
			
		||||
// https://discord.com/developers/docs/interactions/receiving-and-responding#security-and-authorization
 | 
			
		||||
func VerifyInteraction(r *http.Request, key ed25519.PublicKey) bool {
 | 
			
		||||
	var msg bytes.Buffer
 | 
			
		||||
 | 
			
		||||
	signature := r.Header.Get("X-Signature-Ed25519")
 | 
			
		||||
	if signature == "" {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sig, err := hex.DecodeString(signature)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(sig) != ed25519.SignatureSize {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timestamp := r.Header.Get("X-Signature-Timestamp")
 | 
			
		||||
	if timestamp == "" {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msg.WriteString(timestamp)
 | 
			
		||||
 | 
			
		||||
	defer r.Body.Close()
 | 
			
		||||
	var body bytes.Buffer
 | 
			
		||||
 | 
			
		||||
	// at the end of the function, copy the original body back into the request
 | 
			
		||||
	defer func() {
 | 
			
		||||
		r.Body = ioutil.NopCloser(&body)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	// copy body into buffers
 | 
			
		||||
	_, err = io.Copy(&msg, io.TeeReader(r.Body, &body))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ed25519.Verify(key, msg.Bytes(), sig)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								vendor/github.com/bwmarrin/discordgo/locales.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								vendor/github.com/bwmarrin/discordgo/locales.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
package discordgo
 | 
			
		||||
 | 
			
		||||
// Locale represents the accepted languages for Discord.
 | 
			
		||||
// https://discord.com/developers/docs/reference#locales
 | 
			
		||||
type Locale string
 | 
			
		||||
 | 
			
		||||
// String returns the human-readable string of the locale
 | 
			
		||||
func (l Locale) String() string {
 | 
			
		||||
	if name, ok := Locales[l]; ok {
 | 
			
		||||
		return name
 | 
			
		||||
	}
 | 
			
		||||
	return Unknown.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// All defined locales in Discord
 | 
			
		||||
const (
 | 
			
		||||
	EnglishUS    Locale = "en-US"
 | 
			
		||||
	EnglishGB    Locale = "en-GB"
 | 
			
		||||
	Bulgarian    Locale = "bg"
 | 
			
		||||
	ChineseCN    Locale = "zh-CN"
 | 
			
		||||
	ChineseTW    Locale = "zh-TW"
 | 
			
		||||
	Croatian     Locale = "hr"
 | 
			
		||||
	Czech        Locale = "cs"
 | 
			
		||||
	Danish       Locale = "da"
 | 
			
		||||
	Dutch        Locale = "nl"
 | 
			
		||||
	Finnish      Locale = "fi"
 | 
			
		||||
	French       Locale = "fr"
 | 
			
		||||
	German       Locale = "de"
 | 
			
		||||
	Greek        Locale = "el"
 | 
			
		||||
	Hindi        Locale = "hi"
 | 
			
		||||
	Hungarian    Locale = "hu"
 | 
			
		||||
	Italian      Locale = "it"
 | 
			
		||||
	Japanese     Locale = "ja"
 | 
			
		||||
	Korean       Locale = "ko"
 | 
			
		||||
	Lithuanian   Locale = "lt"
 | 
			
		||||
	Norwegian    Locale = "no"
 | 
			
		||||
	Polish       Locale = "pl"
 | 
			
		||||
	PortugueseBR Locale = "pt-BR"
 | 
			
		||||
	Romanian     Locale = "ro"
 | 
			
		||||
	Russian      Locale = "ru"
 | 
			
		||||
	SpanishES    Locale = "es-ES"
 | 
			
		||||
	Swedish      Locale = "sv-SE"
 | 
			
		||||
	Thai         Locale = "th"
 | 
			
		||||
	Turkish      Locale = "tr"
 | 
			
		||||
	Ukrainian    Locale = "uk"
 | 
			
		||||
	Vietnamese   Locale = "vi"
 | 
			
		||||
	Unknown      Locale = ""
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Locales is a map of all the languages codes to their names.
 | 
			
		||||
var Locales = map[Locale]string{
 | 
			
		||||
	EnglishUS:    "English (United States)",
 | 
			
		||||
	EnglishGB:    "English (Great Britain)",
 | 
			
		||||
	Bulgarian:    "Bulgarian",
 | 
			
		||||
	ChineseCN:    "Chinese (China)",
 | 
			
		||||
	ChineseTW:    "Chinese (Taiwan)",
 | 
			
		||||
	Croatian:     "Croatian",
 | 
			
		||||
	Czech:        "Czech",
 | 
			
		||||
	Danish:       "Danish",
 | 
			
		||||
	Dutch:        "Dutch",
 | 
			
		||||
	Finnish:      "Finnish",
 | 
			
		||||
	French:       "French",
 | 
			
		||||
	German:       "German",
 | 
			
		||||
	Greek:        "Greek",
 | 
			
		||||
	Hindi:        "Hindi",
 | 
			
		||||
	Hungarian:    "Hungarian",
 | 
			
		||||
	Italian:      "Italian",
 | 
			
		||||
	Japanese:     "Japanese",
 | 
			
		||||
	Korean:       "Korean",
 | 
			
		||||
	Lithuanian:   "Lithuanian",
 | 
			
		||||
	Norwegian:    "Norwegian",
 | 
			
		||||
	Polish:       "Polish",
 | 
			
		||||
	PortugueseBR: "Portuguese (Brazil)",
 | 
			
		||||
	Romanian:     "Romanian",
 | 
			
		||||
	Russian:      "Russian",
 | 
			
		||||
	SpanishES:    "Spanish (Spain)",
 | 
			
		||||
	Swedish:      "Swedish",
 | 
			
		||||
	Thai:         "Thai",
 | 
			
		||||
	Turkish:      "Turkish",
 | 
			
		||||
	Ukrainian:    "Ukrainian",
 | 
			
		||||
	Vietnamese:   "Vietnamese",
 | 
			
		||||
	Unknown:      "unknown",
 | 
			
		||||
}
 | 
			
		||||
@@ -10,9 +10,11 @@
 | 
			
		||||
package discordgo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MessageType is the type of Message
 | 
			
		||||
@@ -21,23 +23,26 @@ type MessageType int
 | 
			
		||||
 | 
			
		||||
// Block contains the valid known MessageType values
 | 
			
		||||
const (
 | 
			
		||||
	MessageTypeDefault MessageType = iota
 | 
			
		||||
	MessageTypeRecipientAdd
 | 
			
		||||
	MessageTypeRecipientRemove
 | 
			
		||||
	MessageTypeCall
 | 
			
		||||
	MessageTypeChannelNameChange
 | 
			
		||||
	MessageTypeChannelIconChange
 | 
			
		||||
	MessageTypeChannelPinnedMessage
 | 
			
		||||
	MessageTypeGuildMemberJoin
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscription
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscriptionTierOne
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscriptionTierTwo
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscriptionTierThree
 | 
			
		||||
	MessageTypeChannelFollowAdd
 | 
			
		||||
	MessageTypeGuildDiscoveryDisqualified = iota + 1
 | 
			
		||||
	MessageTypeGuildDiscoveryRequalified
 | 
			
		||||
	MessageTypeReply = iota + 4
 | 
			
		||||
	MessageTypeApplicationCommand
 | 
			
		||||
	MessageTypeDefault                               MessageType = 0
 | 
			
		||||
	MessageTypeRecipientAdd                          MessageType = 1
 | 
			
		||||
	MessageTypeRecipientRemove                       MessageType = 2
 | 
			
		||||
	MessageTypeCall                                  MessageType = 3
 | 
			
		||||
	MessageTypeChannelNameChange                     MessageType = 4
 | 
			
		||||
	MessageTypeChannelIconChange                     MessageType = 5
 | 
			
		||||
	MessageTypeChannelPinnedMessage                  MessageType = 6
 | 
			
		||||
	MessageTypeGuildMemberJoin                       MessageType = 7
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscription          MessageType = 8
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscriptionTierOne   MessageType = 9
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscriptionTierTwo   MessageType = 10
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscriptionTierThree MessageType = 11
 | 
			
		||||
	MessageTypeChannelFollowAdd                      MessageType = 12
 | 
			
		||||
	MessageTypeGuildDiscoveryDisqualified            MessageType = 14
 | 
			
		||||
	MessageTypeGuildDiscoveryRequalified             MessageType = 15
 | 
			
		||||
	MessageTypeThreadCreated                         MessageType = 18
 | 
			
		||||
	MessageTypeReply                                 MessageType = 19
 | 
			
		||||
	MessageTypeChatInputCommand                      MessageType = 20
 | 
			
		||||
	MessageTypeThreadStarterMessage                  MessageType = 21
 | 
			
		||||
	MessageTypeContextMenuCommand                    MessageType = 23
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Message stores all data related to a specific Discord message.
 | 
			
		||||
@@ -58,11 +63,11 @@ type Message struct {
 | 
			
		||||
	// CAUTION: this field may be removed in a
 | 
			
		||||
	// future API version; it is safer to calculate
 | 
			
		||||
	// the creation time via the ID.
 | 
			
		||||
	Timestamp Timestamp `json:"timestamp"`
 | 
			
		||||
	Timestamp time.Time `json:"timestamp"`
 | 
			
		||||
 | 
			
		||||
	// The time at which the last edit of the message
 | 
			
		||||
	// occurred, if it has been edited.
 | 
			
		||||
	EditedTimestamp Timestamp `json:"edited_timestamp"`
 | 
			
		||||
	EditedTimestamp *time.Time `json:"edited_timestamp"`
 | 
			
		||||
 | 
			
		||||
	// The roles mentioned in the message.
 | 
			
		||||
	MentionRoles []string `json:"mention_roles"`
 | 
			
		||||
@@ -80,8 +85,10 @@ type Message struct {
 | 
			
		||||
	// A list of attachments present in the message.
 | 
			
		||||
	Attachments []*MessageAttachment `json:"attachments"`
 | 
			
		||||
 | 
			
		||||
	// A list of embeds present in the message. Multiple
 | 
			
		||||
	// embeds can currently only be sent by webhooks.
 | 
			
		||||
	// A list of components attached to the message.
 | 
			
		||||
	Components []MessageComponent `json:"-"`
 | 
			
		||||
 | 
			
		||||
	// A list of embeds present in the message.
 | 
			
		||||
	Embeds []*MessageEmbed `json:"embeds"`
 | 
			
		||||
 | 
			
		||||
	// A list of users mentioned in the message.
 | 
			
		||||
@@ -116,13 +123,70 @@ type Message struct {
 | 
			
		||||
	// Is sent with Rich Presence-related chat embeds
 | 
			
		||||
	Application *MessageApplication `json:"application"`
 | 
			
		||||
 | 
			
		||||
	// MessageReference contains reference data sent with crossposted messages
 | 
			
		||||
	// MessageReference contains reference data sent with crossposted or reply messages.
 | 
			
		||||
	// This does not contain the reference *to* this message; this is for when *this* message references another.
 | 
			
		||||
	// To generate a reference to this message, use (*Message).Reference().
 | 
			
		||||
	MessageReference *MessageReference `json:"message_reference"`
 | 
			
		||||
 | 
			
		||||
	// The message associated with the message_reference
 | 
			
		||||
	// NOTE: This field is only returned for messages with a type of 19 (REPLY) or 21 (THREAD_STARTER_MESSAGE).
 | 
			
		||||
	// If the message is a reply but the referenced_message field is not present,
 | 
			
		||||
	// the backend did not attempt to fetch the message that was being replied to, so its state is unknown.
 | 
			
		||||
	// If the field exists but is null, the referenced message was deleted.
 | 
			
		||||
	ReferencedMessage *Message `json:"referenced_message"`
 | 
			
		||||
 | 
			
		||||
	// Is sent when the message is a response to an Interaction, without an existing message.
 | 
			
		||||
	// This means responses to message component interactions do not include this property,
 | 
			
		||||
	// instead including a MessageReference, as components exist on preexisting messages.
 | 
			
		||||
	Interaction *MessageInteraction `json:"interaction"`
 | 
			
		||||
 | 
			
		||||
	// The flags of the message, which describe extra features of a message.
 | 
			
		||||
	// This is a combination of bit masks; the presence of a certain permission can
 | 
			
		||||
	// be checked by performing a bitwise AND between this int and the flag.
 | 
			
		||||
	Flags MessageFlags `json:"flags"`
 | 
			
		||||
 | 
			
		||||
	// The thread that was started from this message, includes thread member object
 | 
			
		||||
	Thread *Channel `json:"thread,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// An array of Sticker objects, if any were sent.
 | 
			
		||||
	StickerItems []*Sticker `json:"sticker_items"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON is a helper function to unmarshal the Message.
 | 
			
		||||
func (m *Message) UnmarshalJSON(data []byte) error {
 | 
			
		||||
	type message Message
 | 
			
		||||
	var v struct {
 | 
			
		||||
		message
 | 
			
		||||
		RawComponents []unmarshalableMessageComponent `json:"components"`
 | 
			
		||||
	}
 | 
			
		||||
	err := json.Unmarshal(data, &v)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	*m = Message(v.message)
 | 
			
		||||
	m.Components = make([]MessageComponent, len(v.RawComponents))
 | 
			
		||||
	for i, v := range v.RawComponents {
 | 
			
		||||
		m.Components[i] = v.MessageComponent
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetCustomEmojis pulls out all the custom (Non-unicode) emojis from a message and returns a Slice of the Emoji struct.
 | 
			
		||||
func (m *Message) GetCustomEmojis() []*Emoji {
 | 
			
		||||
	var toReturn []*Emoji
 | 
			
		||||
	emojis := EmojiRegex.FindAllString(m.Content, -1)
 | 
			
		||||
	if len(emojis) < 1 {
 | 
			
		||||
		return toReturn
 | 
			
		||||
	}
 | 
			
		||||
	for _, em := range emojis {
 | 
			
		||||
		parts := strings.Split(em, ":")
 | 
			
		||||
		toReturn = append(toReturn, &Emoji{
 | 
			
		||||
			ID:       parts[2][:len(parts[2])-1],
 | 
			
		||||
			Name:     parts[1],
 | 
			
		||||
			Animated: strings.HasPrefix(em, "<a:"),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return toReturn
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageFlags is the flags of "message" (see MessageFlags* consts)
 | 
			
		||||
@@ -131,11 +195,26 @@ type MessageFlags int
 | 
			
		||||
 | 
			
		||||
// Valid MessageFlags values
 | 
			
		||||
const (
 | 
			
		||||
	MessageFlagsCrossPosted MessageFlags = 1 << iota
 | 
			
		||||
	MessageFlagsIsCrossPosted
 | 
			
		||||
	MessageFlagsSupressEmbeds
 | 
			
		||||
	MessageFlagsSourceMessageDeleted
 | 
			
		||||
	MessageFlagsUrgent
 | 
			
		||||
	// MessageFlagsCrossPosted This message has been published to subscribed channels (via Channel Following).
 | 
			
		||||
	MessageFlagsCrossPosted MessageFlags = 1 << 0
 | 
			
		||||
	// MessageFlagsIsCrossPosted this message originated from a message in another channel (via Channel Following).
 | 
			
		||||
	MessageFlagsIsCrossPosted MessageFlags = 1 << 1
 | 
			
		||||
	// MessageFlagsSuppressEmbeds do not include any embeds when serializing this message.
 | 
			
		||||
	MessageFlagsSuppressEmbeds MessageFlags = 1 << 2
 | 
			
		||||
	// TODO: deprecated, remove when compatibility is not needed
 | 
			
		||||
	MessageFlagsSupressEmbeds MessageFlags = 1 << 2
 | 
			
		||||
	// MessageFlagsSourceMessageDeleted the source message for this crosspost has been deleted (via Channel Following).
 | 
			
		||||
	MessageFlagsSourceMessageDeleted MessageFlags = 1 << 3
 | 
			
		||||
	// MessageFlagsUrgent this message came from the urgent message system.
 | 
			
		||||
	MessageFlagsUrgent MessageFlags = 1 << 4
 | 
			
		||||
	// MessageFlagsHasThread this message has an associated thread, with the same id as the message.
 | 
			
		||||
	MessageFlagsHasThread MessageFlags = 1 << 5
 | 
			
		||||
	// MessageFlagsEphemeral this message is only visible to the user who invoked the Interaction.
 | 
			
		||||
	MessageFlagsEphemeral MessageFlags = 1 << 6
 | 
			
		||||
	// MessageFlagsLoading this message is an Interaction Response and the bot is "thinking".
 | 
			
		||||
	MessageFlagsLoading MessageFlags = 1 << 7
 | 
			
		||||
	// MessageFlagsFailedToMentionSomeRolesInThread this message failed to mention some roles and add their members to the thread.
 | 
			
		||||
	MessageFlagsFailedToMentionSomeRolesInThread MessageFlags = 1 << 8
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// File stores info about files you e.g. send in messages.
 | 
			
		||||
@@ -148,25 +227,34 @@ type File struct {
 | 
			
		||||
// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
 | 
			
		||||
type MessageSend struct {
 | 
			
		||||
	Content         string                  `json:"content,omitempty"`
 | 
			
		||||
	Embed           *MessageEmbed           `json:"embed,omitempty"`
 | 
			
		||||
	Embeds          []*MessageEmbed         `json:"embeds"`
 | 
			
		||||
	TTS             bool                    `json:"tts"`
 | 
			
		||||
	Components      []MessageComponent      `json:"components"`
 | 
			
		||||
	Files           []*File                 `json:"-"`
 | 
			
		||||
	AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
 | 
			
		||||
	Reference       *MessageReference       `json:"message_reference,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// TODO: Remove this when compatibility is not required.
 | 
			
		||||
	File *File `json:"-"`
 | 
			
		||||
 | 
			
		||||
	// TODO: Remove this when compatibility is not required.
 | 
			
		||||
	Embed *MessageEmbed `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
 | 
			
		||||
// is also where you should get the instance from.
 | 
			
		||||
type MessageEdit struct {
 | 
			
		||||
	Content         *string                 `json:"content,omitempty"`
 | 
			
		||||
	Embed           *MessageEmbed           `json:"embed,omitempty"`
 | 
			
		||||
	Components      []MessageComponent      `json:"components"`
 | 
			
		||||
	Embeds          []*MessageEmbed         `json:"embeds"`
 | 
			
		||||
	AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
 | 
			
		||||
	Flags           MessageFlags            `json:"flags,omitempty"`
 | 
			
		||||
 | 
			
		||||
	ID      string
 | 
			
		||||
	Channel string
 | 
			
		||||
 | 
			
		||||
	// TODO: Remove this when compatibility is not required.
 | 
			
		||||
	Embed *MessageEmbed `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewMessageEdit returns a MessageEdit struct, initialized
 | 
			
		||||
@@ -188,7 +276,14 @@ func (m *MessageEdit) SetContent(str string) *MessageEdit {
 | 
			
		||||
// SetEmbed is a convenience function for setting the embed,
 | 
			
		||||
// so you can chain commands.
 | 
			
		||||
func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit {
 | 
			
		||||
	m.Embed = embed
 | 
			
		||||
	m.Embeds = []*MessageEmbed{embed}
 | 
			
		||||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetEmbeds is a convenience function for setting the embeds,
 | 
			
		||||
// so you can chain commands.
 | 
			
		||||
func (m *MessageEdit) SetEmbeds(embeds []*MessageEmbed) *MessageEdit {
 | 
			
		||||
	m.Embeds = embeds
 | 
			
		||||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -230,13 +325,15 @@ type MessageAllowedMentions struct {
 | 
			
		||||
 | 
			
		||||
// A MessageAttachment stores data for message attachments.
 | 
			
		||||
type MessageAttachment struct {
 | 
			
		||||
	ID       string `json:"id"`
 | 
			
		||||
	URL      string `json:"url"`
 | 
			
		||||
	ProxyURL string `json:"proxy_url"`
 | 
			
		||||
	Filename string `json:"filename"`
 | 
			
		||||
	Width    int    `json:"width"`
 | 
			
		||||
	Height   int    `json:"height"`
 | 
			
		||||
	Size     int    `json:"size"`
 | 
			
		||||
	ID          string `json:"id"`
 | 
			
		||||
	URL         string `json:"url"`
 | 
			
		||||
	ProxyURL    string `json:"proxy_url"`
 | 
			
		||||
	Filename    string `json:"filename"`
 | 
			
		||||
	ContentType string `json:"content_type"`
 | 
			
		||||
	Width       int    `json:"width"`
 | 
			
		||||
	Height      int    `json:"height"`
 | 
			
		||||
	Size        int    `json:"size"`
 | 
			
		||||
	Ephemeral   bool   `json:"ephemeral"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageEmbedFooter is a part of a MessageEmbed struct.
 | 
			
		||||
@@ -248,7 +345,7 @@ type MessageEmbedFooter struct {
 | 
			
		||||
 | 
			
		||||
// MessageEmbedImage is a part of a MessageEmbed struct.
 | 
			
		||||
type MessageEmbedImage struct {
 | 
			
		||||
	URL      string `json:"url,omitempty"`
 | 
			
		||||
	URL      string `json:"url"`
 | 
			
		||||
	ProxyURL string `json:"proxy_url,omitempty"`
 | 
			
		||||
	Width    int    `json:"width,omitempty"`
 | 
			
		||||
	Height   int    `json:"height,omitempty"`
 | 
			
		||||
@@ -256,7 +353,7 @@ type MessageEmbedImage struct {
 | 
			
		||||
 | 
			
		||||
// MessageEmbedThumbnail is a part of a MessageEmbed struct.
 | 
			
		||||
type MessageEmbedThumbnail struct {
 | 
			
		||||
	URL      string `json:"url,omitempty"`
 | 
			
		||||
	URL      string `json:"url"`
 | 
			
		||||
	ProxyURL string `json:"proxy_url,omitempty"`
 | 
			
		||||
	Width    int    `json:"width,omitempty"`
 | 
			
		||||
	Height   int    `json:"height,omitempty"`
 | 
			
		||||
@@ -278,7 +375,7 @@ type MessageEmbedProvider struct {
 | 
			
		||||
// MessageEmbedAuthor is a part of a MessageEmbed struct.
 | 
			
		||||
type MessageEmbedAuthor struct {
 | 
			
		||||
	URL          string `json:"url,omitempty"`
 | 
			
		||||
	Name         string `json:"name,omitempty"`
 | 
			
		||||
	Name         string `json:"name"`
 | 
			
		||||
	IconURL      string `json:"icon_url,omitempty"`
 | 
			
		||||
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
@@ -339,23 +436,10 @@ type MessageActivityType int
 | 
			
		||||
 | 
			
		||||
// Constants for the different types of Message Activity
 | 
			
		||||
const (
 | 
			
		||||
	MessageActivityTypeJoin MessageActivityType = iota + 1
 | 
			
		||||
	MessageActivityTypeSpectate
 | 
			
		||||
	MessageActivityTypeListen
 | 
			
		||||
	MessageActivityTypeJoinRequest
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MessageFlag describes an extra feature of the message
 | 
			
		||||
type MessageFlag int
 | 
			
		||||
 | 
			
		||||
// Constants for the different bit offsets of Message Flags
 | 
			
		||||
const (
 | 
			
		||||
	// This message has been published to subscribed channels (via Channel Following)
 | 
			
		||||
	MessageFlagCrossposted MessageFlag = 1 << iota
 | 
			
		||||
	// This message originated from a message in another channel (via Channel Following)
 | 
			
		||||
	MessageFlagIsCrosspost
 | 
			
		||||
	// Do not include any embeds when serializing this message
 | 
			
		||||
	MessageFlagSuppressEmbeds
 | 
			
		||||
	MessageActivityTypeJoin        MessageActivityType = 1
 | 
			
		||||
	MessageActivityTypeSpectate    MessageActivityType = 2
 | 
			
		||||
	MessageActivityTypeListen      MessageActivityType = 3
 | 
			
		||||
	MessageActivityTypeJoinRequest MessageActivityType = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MessageApplication is sent with Rich Presence-related chat embeds
 | 
			
		||||
@@ -447,3 +531,14 @@ func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, e
 | 
			
		||||
	})
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageInteraction contains information about the application command interaction which generated the message.
 | 
			
		||||
type MessageInteraction struct {
 | 
			
		||||
	ID   string          `json:"id"`
 | 
			
		||||
	Type InteractionType `json:"type"`
 | 
			
		||||
	Name string          `json:"name"`
 | 
			
		||||
	User *User           `json:"user"`
 | 
			
		||||
 | 
			
		||||
	// Member is only present when the interaction is from a guild.
 | 
			
		||||
	Member *Member `json:"member"`
 | 
			
		||||
}
 | 
			
		||||
@@ -18,8 +18,8 @@ type MembershipState int
 | 
			
		||||
 | 
			
		||||
// Constants for the different stages of the MembershipState
 | 
			
		||||
const (
 | 
			
		||||
	MembershipStateInvited MembershipState = iota + 1
 | 
			
		||||
	MembershipStateAccepted
 | 
			
		||||
	MembershipStateInvited  MembershipState = 1
 | 
			
		||||
	MembershipStateAccepted MembershipState = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A TeamMember struct stores values for a single Team Member, extending the normal User data - note that the user field is partial
 | 
			
		||||
@@ -40,28 +40,11 @@ type Team struct {
 | 
			
		||||
	Members     []*TeamMember `json:"members"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An Application struct stores values for a Discord OAuth2 Application
 | 
			
		||||
type Application struct {
 | 
			
		||||
	ID                  string    `json:"id,omitempty"`
 | 
			
		||||
	Name                string    `json:"name"`
 | 
			
		||||
	Description         string    `json:"description,omitempty"`
 | 
			
		||||
	Icon                string    `json:"icon,omitempty"`
 | 
			
		||||
	Secret              string    `json:"secret,omitempty"`
 | 
			
		||||
	RedirectURIs        *[]string `json:"redirect_uris,omitempty"`
 | 
			
		||||
	BotRequireCodeGrant bool      `json:"bot_require_code_grant,omitempty"`
 | 
			
		||||
	BotPublic           bool      `json:"bot_public,omitempty"`
 | 
			
		||||
	RPCApplicationState int       `json:"rpc_application_state,omitempty"`
 | 
			
		||||
	Flags               int       `json:"flags,omitempty"`
 | 
			
		||||
	Owner               *User     `json:"owner"`
 | 
			
		||||
	Bot                 *User     `json:"bot"`
 | 
			
		||||
	Team                *Team     `json:"team"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Application returns an Application structure of a specific Application
 | 
			
		||||
//   appID : The ID of an Application
 | 
			
		||||
func (s *Session) Application(appID string) (st *Application, err error) {
 | 
			
		||||
 | 
			
		||||
	body, err := s.RequestWithBucketID("GET", EndpointApplication(appID), nil, EndpointApplication(""))
 | 
			
		||||
	body, err := s.RequestWithBucketID("GET", EndpointOAuth2Application(appID), nil, EndpointOAuth2Application(""))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -73,7 +56,7 @@ func (s *Session) Application(appID string) (st *Application, err error) {
 | 
			
		||||
// Applications returns all applications for the authenticated user
 | 
			
		||||
func (s *Session) Applications() (st []*Application, err error) {
 | 
			
		||||
 | 
			
		||||
	body, err := s.RequestWithBucketID("GET", EndpointApplications, nil, EndpointApplications)
 | 
			
		||||
	body, err := s.RequestWithBucketID("GET", EndpointOAuth2Applications, nil, EndpointOAuth2Applications)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -88,12 +71,11 @@ func (s *Session) Applications() (st []*Application, err error) {
 | 
			
		||||
func (s *Session) ApplicationCreate(ap *Application) (st *Application, err error) {
 | 
			
		||||
 | 
			
		||||
	data := struct {
 | 
			
		||||
		Name         string    `json:"name"`
 | 
			
		||||
		Description  string    `json:"description"`
 | 
			
		||||
		RedirectURIs *[]string `json:"redirect_uris,omitempty"`
 | 
			
		||||
	}{ap.Name, ap.Description, ap.RedirectURIs}
 | 
			
		||||
		Name        string `json:"name"`
 | 
			
		||||
		Description string `json:"description"`
 | 
			
		||||
	}{ap.Name, ap.Description}
 | 
			
		||||
 | 
			
		||||
	body, err := s.RequestWithBucketID("POST", EndpointApplications, data, EndpointApplications)
 | 
			
		||||
	body, err := s.RequestWithBucketID("POST", EndpointOAuth2Applications, data, EndpointOAuth2Applications)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -107,12 +89,11 @@ func (s *Session) ApplicationCreate(ap *Application) (st *Application, err error
 | 
			
		||||
func (s *Session) ApplicationUpdate(appID string, ap *Application) (st *Application, err error) {
 | 
			
		||||
 | 
			
		||||
	data := struct {
 | 
			
		||||
		Name         string    `json:"name"`
 | 
			
		||||
		Description  string    `json:"description"`
 | 
			
		||||
		RedirectURIs *[]string `json:"redirect_uris,omitempty"`
 | 
			
		||||
	}{ap.Name, ap.Description, ap.RedirectURIs}
 | 
			
		||||
		Name        string `json:"name"`
 | 
			
		||||
		Description string `json:"description"`
 | 
			
		||||
	}{ap.Name, ap.Description}
 | 
			
		||||
 | 
			
		||||
	body, err := s.RequestWithBucketID("PUT", EndpointApplication(appID), data, EndpointApplication(""))
 | 
			
		||||
	body, err := s.RequestWithBucketID("PUT", EndpointOAuth2Application(appID), data, EndpointOAuth2Application(""))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -125,7 +106,7 @@ func (s *Session) ApplicationUpdate(appID string, ap *Application) (st *Applicat
 | 
			
		||||
//   appID : The ID of an Application
 | 
			
		||||
func (s *Session) ApplicationDelete(appID string) (err error) {
 | 
			
		||||
 | 
			
		||||
	_, err = s.RequestWithBucketID("DELETE", EndpointApplication(appID), nil, EndpointApplication(""))
 | 
			
		||||
	_, err = s.RequestWithBucketID("DELETE", EndpointOAuth2Application(appID), nil, EndpointOAuth2Application(""))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -143,7 +124,7 @@ type Asset struct {
 | 
			
		||||
// ApplicationAssets returns an application's assets
 | 
			
		||||
func (s *Session) ApplicationAssets(appID string) (ass []*Asset, err error) {
 | 
			
		||||
 | 
			
		||||
	body, err := s.RequestWithBucketID("GET", EndpointApplicationAssets(appID), nil, EndpointApplicationAssets(""))
 | 
			
		||||
	body, err := s.RequestWithBucketID("GET", EndpointOAuth2ApplicationAssets(appID), nil, EndpointOAuth2ApplicationAssets(""))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -163,7 +144,7 @@ func (s *Session) ApplicationAssets(appID string) (ass []*Asset, err error) {
 | 
			
		||||
// NOTE: func name may change, if I can think up something better.
 | 
			
		||||
func (s *Session) ApplicationBotCreate(appID string) (st *User, err error) {
 | 
			
		||||
 | 
			
		||||
	body, err := s.RequestWithBucketID("POST", EndpointApplicationsBot(appID), nil, EndpointApplicationsBot(""))
 | 
			
		||||
	body, err := s.RequestWithBucketID("POST", EndpointOAuth2ApplicationsBot(appID), nil, EndpointOAuth2ApplicationsBot(""))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -33,7 +33,7 @@ func NewRatelimiter() *RateLimiter {
 | 
			
		||||
		buckets: make(map[string]*Bucket),
 | 
			
		||||
		global:  new(int64),
 | 
			
		||||
		customRateLimits: []*customRateLimit{
 | 
			
		||||
			&customRateLimit{
 | 
			
		||||
			{
 | 
			
		||||
				suffix:   "//reactions//",
 | 
			
		||||
				requests: 1,
 | 
			
		||||
				reset:    200 * time.Millisecond,
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -38,13 +38,15 @@ type State struct {
 | 
			
		||||
	Ready
 | 
			
		||||
 | 
			
		||||
	// MaxMessageCount represents how many messages per channel the state will store.
 | 
			
		||||
	MaxMessageCount int
 | 
			
		||||
	TrackChannels   bool
 | 
			
		||||
	TrackEmojis     bool
 | 
			
		||||
	TrackMembers    bool
 | 
			
		||||
	TrackRoles      bool
 | 
			
		||||
	TrackVoice      bool
 | 
			
		||||
	TrackPresences  bool
 | 
			
		||||
	MaxMessageCount    int
 | 
			
		||||
	TrackChannels      bool
 | 
			
		||||
	TrackThreads       bool
 | 
			
		||||
	TrackEmojis        bool
 | 
			
		||||
	TrackMembers       bool
 | 
			
		||||
	TrackThreadMembers bool
 | 
			
		||||
	TrackRoles         bool
 | 
			
		||||
	TrackVoice         bool
 | 
			
		||||
	TrackPresences     bool
 | 
			
		||||
 | 
			
		||||
	guildMap   map[string]*Guild
 | 
			
		||||
	channelMap map[string]*Channel
 | 
			
		||||
@@ -58,15 +60,17 @@ func NewState() *State {
 | 
			
		||||
			PrivateChannels: []*Channel{},
 | 
			
		||||
			Guilds:          []*Guild{},
 | 
			
		||||
		},
 | 
			
		||||
		TrackChannels:  true,
 | 
			
		||||
		TrackEmojis:    true,
 | 
			
		||||
		TrackMembers:   true,
 | 
			
		||||
		TrackRoles:     true,
 | 
			
		||||
		TrackVoice:     true,
 | 
			
		||||
		TrackPresences: true,
 | 
			
		||||
		guildMap:       make(map[string]*Guild),
 | 
			
		||||
		channelMap:     make(map[string]*Channel),
 | 
			
		||||
		memberMap:      make(map[string]map[string]*Member),
 | 
			
		||||
		TrackChannels:      true,
 | 
			
		||||
		TrackThreads:       true,
 | 
			
		||||
		TrackEmojis:        true,
 | 
			
		||||
		TrackMembers:       true,
 | 
			
		||||
		TrackThreadMembers: true,
 | 
			
		||||
		TrackRoles:         true,
 | 
			
		||||
		TrackVoice:         true,
 | 
			
		||||
		TrackPresences:     true,
 | 
			
		||||
		guildMap:           make(map[string]*Guild),
 | 
			
		||||
		channelMap:         make(map[string]*Channel),
 | 
			
		||||
		memberMap:          make(map[string]map[string]*Member),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -93,6 +97,11 @@ func (s *State) GuildAdd(guild *Guild) error {
 | 
			
		||||
		s.channelMap[c.ID] = c
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add all the threads to the state in case of thread sync list.
 | 
			
		||||
	for _, t := range guild.Threads {
 | 
			
		||||
		s.channelMap[t.ID] = t
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If this guild contains a new member slice, we must regenerate the member map so the pointers stay valid
 | 
			
		||||
	if guild.Members != nil {
 | 
			
		||||
		s.createMemberMap(guild)
 | 
			
		||||
@@ -122,6 +131,9 @@ func (s *State) GuildAdd(guild *Guild) error {
 | 
			
		||||
		if guild.Channels == nil {
 | 
			
		||||
			guild.Channels = g.Channels
 | 
			
		||||
		}
 | 
			
		||||
		if guild.Threads == nil {
 | 
			
		||||
			guild.Threads = g.Threads
 | 
			
		||||
		}
 | 
			
		||||
		if guild.VoiceStates == nil {
 | 
			
		||||
			guild.VoiceStates = g.VoiceStates
 | 
			
		||||
		}
 | 
			
		||||
@@ -180,21 +192,12 @@ func (s *State) Guild(guildID string) (*Guild, error) {
 | 
			
		||||
	return nil, ErrStateNotFound
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PresenceAdd adds a presence to the current world state, or
 | 
			
		||||
// updates it if it already exists.
 | 
			
		||||
func (s *State) PresenceAdd(guildID string, presence *Presence) error {
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return ErrNilState
 | 
			
		||||
func (s *State) presenceAdd(guildID string, presence *Presence) error {
 | 
			
		||||
	guild, ok := s.guildMap[guildID]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return ErrStateNotFound
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	guild, err := s.Guild(guildID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.Lock()
 | 
			
		||||
	defer s.Unlock()
 | 
			
		||||
 | 
			
		||||
	for i, p := range guild.Presences {
 | 
			
		||||
		if p.User.ID == presence.User.ID {
 | 
			
		||||
			//guild.Presences[i] = presence
 | 
			
		||||
@@ -233,6 +236,19 @@ func (s *State) PresenceAdd(guildID string, presence *Presence) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PresenceAdd adds a presence to the current world state, or
 | 
			
		||||
// updates it if it already exists.
 | 
			
		||||
func (s *State) PresenceAdd(guildID string, presence *Presence) error {
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return ErrNilState
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.Lock()
 | 
			
		||||
	defer s.Unlock()
 | 
			
		||||
 | 
			
		||||
	return s.presenceAdd(guildID, presence)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PresenceRemove removes a presence from the current world state.
 | 
			
		||||
func (s *State) PresenceRemove(guildID string, presence *Presence) error {
 | 
			
		||||
	if s == nil {
 | 
			
		||||
@@ -279,21 +295,12 @@ func (s *State) Presence(guildID, userID string) (*Presence, error) {
 | 
			
		||||
 | 
			
		||||
// TODO: Consider moving Guild state update methods onto *Guild.
 | 
			
		||||
 | 
			
		||||
// MemberAdd adds a member to the current world state, or
 | 
			
		||||
// updates it if it already exists.
 | 
			
		||||
func (s *State) MemberAdd(member *Member) error {
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return ErrNilState
 | 
			
		||||
func (s *State) memberAdd(member *Member) error {
 | 
			
		||||
	guild, ok := s.guildMap[member.GuildID]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return ErrStateNotFound
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	guild, err := s.Guild(member.GuildID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.Lock()
 | 
			
		||||
	defer s.Unlock()
 | 
			
		||||
 | 
			
		||||
	members, ok := s.memberMap[member.GuildID]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return ErrStateNotFound
 | 
			
		||||
@@ -306,15 +313,27 @@ func (s *State) MemberAdd(member *Member) error {
 | 
			
		||||
	} else {
 | 
			
		||||
		// We are about to replace `m` in the state with `member`, but first we need to
 | 
			
		||||
		// make sure we preserve any fields that the `member` doesn't contain from `m`.
 | 
			
		||||
		if member.JoinedAt == "" {
 | 
			
		||||
		if member.JoinedAt.IsZero() {
 | 
			
		||||
			member.JoinedAt = m.JoinedAt
 | 
			
		||||
		}
 | 
			
		||||
		*m = *member
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MemberAdd adds a member to the current world state, or
 | 
			
		||||
// updates it if it already exists.
 | 
			
		||||
func (s *State) MemberAdd(member *Member) error {
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return ErrNilState
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.Lock()
 | 
			
		||||
	defer s.Unlock()
 | 
			
		||||
 | 
			
		||||
	return s.memberAdd(member)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MemberRemove removes a member from current world state.
 | 
			
		||||
func (s *State) MemberRemove(member *Member) error {
 | 
			
		||||
	if s == nil {
 | 
			
		||||
@@ -465,6 +484,9 @@ func (s *State) ChannelAdd(channel *Channel) error {
 | 
			
		||||
		if channel.PermissionOverwrites == nil {
 | 
			
		||||
			channel.PermissionOverwrites = c.PermissionOverwrites
 | 
			
		||||
		}
 | 
			
		||||
		if channel.ThreadMetadata == nil {
 | 
			
		||||
			channel.ThreadMetadata = c.ThreadMetadata
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		*c = *channel
 | 
			
		||||
		return nil
 | 
			
		||||
@@ -472,12 +494,18 @@ func (s *State) ChannelAdd(channel *Channel) error {
 | 
			
		||||
 | 
			
		||||
	if channel.Type == ChannelTypeDM || channel.Type == ChannelTypeGroupDM {
 | 
			
		||||
		s.PrivateChannels = append(s.PrivateChannels, channel)
 | 
			
		||||
	} else {
 | 
			
		||||
		guild, ok := s.guildMap[channel.GuildID]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return ErrStateNotFound
 | 
			
		||||
		}
 | 
			
		||||
		s.channelMap[channel.ID] = channel
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	guild, ok := s.guildMap[channel.GuildID]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return ErrStateNotFound
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if channel.IsThread() {
 | 
			
		||||
		guild.Threads = append(guild.Threads, channel)
 | 
			
		||||
	} else {
 | 
			
		||||
		guild.Channels = append(guild.Channels, channel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -507,15 +535,26 @@ func (s *State) ChannelRemove(channel *Channel) error {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		guild, err := s.Guild(channel.GuildID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		delete(s.channelMap, channel.ID)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	guild, err := s.Guild(channel.GuildID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.Lock()
 | 
			
		||||
	defer s.Unlock()
 | 
			
		||||
 | 
			
		||||
	if channel.IsThread() {
 | 
			
		||||
		for i, t := range guild.Threads {
 | 
			
		||||
			if t.ID == channel.ID {
 | 
			
		||||
				guild.Threads = append(guild.Threads[:i], guild.Threads[i+1:]...)
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		s.Lock()
 | 
			
		||||
		defer s.Unlock()
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		for i, c := range guild.Channels {
 | 
			
		||||
			if c.ID == channel.ID {
 | 
			
		||||
				guild.Channels = append(guild.Channels[:i], guild.Channels[i+1:]...)
 | 
			
		||||
@@ -529,6 +568,99 @@ func (s *State) ChannelRemove(channel *Channel) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ThreadListSync syncs guild threads with provided ones.
 | 
			
		||||
func (s *State) ThreadListSync(tls *ThreadListSync) error {
 | 
			
		||||
	guild, err := s.Guild(tls.GuildID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.Lock()
 | 
			
		||||
	defer s.Unlock()
 | 
			
		||||
 | 
			
		||||
	// This algorithm filters out archived or
 | 
			
		||||
	// threads which are children of channels in channelIDs
 | 
			
		||||
	// and then it adds all synced threads to guild threads and cache
 | 
			
		||||
	index := 0
 | 
			
		||||
outer:
 | 
			
		||||
	for _, t := range guild.Threads {
 | 
			
		||||
		if !t.ThreadMetadata.Archived && tls.ChannelIDs != nil {
 | 
			
		||||
			for _, v := range tls.ChannelIDs {
 | 
			
		||||
				if t.ParentID == v {
 | 
			
		||||
					delete(s.channelMap, t.ID)
 | 
			
		||||
					continue outer
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			guild.Threads[index] = t
 | 
			
		||||
			index++
 | 
			
		||||
		} else {
 | 
			
		||||
			delete(s.channelMap, t.ID)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	guild.Threads = guild.Threads[:index]
 | 
			
		||||
	for _, t := range tls.Threads {
 | 
			
		||||
		s.channelMap[t.ID] = t
 | 
			
		||||
		guild.Threads = append(guild.Threads, t)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, m := range tls.Members {
 | 
			
		||||
		if c, ok := s.channelMap[m.ID]; ok {
 | 
			
		||||
			c.Member = m
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ThreadMembersUpdate updates thread members list
 | 
			
		||||
func (s *State) ThreadMembersUpdate(tmu *ThreadMembersUpdate) error {
 | 
			
		||||
	thread, err := s.Channel(tmu.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	s.Lock()
 | 
			
		||||
	defer s.Unlock()
 | 
			
		||||
 | 
			
		||||
	for idx, member := range thread.Members {
 | 
			
		||||
		for _, removedMember := range tmu.RemovedMembers {
 | 
			
		||||
			if member.ID == removedMember {
 | 
			
		||||
				thread.Members = append(thread.Members[:idx], thread.Members[idx+1:]...)
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, addedMember := range tmu.AddedMembers {
 | 
			
		||||
		thread.Members = append(thread.Members, addedMember.ThreadMember)
 | 
			
		||||
		if addedMember.Member != nil {
 | 
			
		||||
			err = s.memberAdd(addedMember.Member)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if addedMember.Presence != nil {
 | 
			
		||||
			err = s.presenceAdd(tmu.GuildID, addedMember.Presence)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	thread.MemberCount = tmu.MemberCount
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ThreadMemberUpdate sets or updates member data for the current user.
 | 
			
		||||
func (s *State) ThreadMemberUpdate(mu *ThreadMemberUpdate) error {
 | 
			
		||||
	thread, err := s.Channel(mu.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	thread.Member = mu.ThreadMember
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GuildChannel gets a channel by ID from a guild.
 | 
			
		||||
// This method is Deprecated, use Channel(channelID)
 | 
			
		||||
func (s *State) GuildChannel(guildID, channelID string) (*Channel, error) {
 | 
			
		||||
@@ -637,7 +769,7 @@ func (s *State) MessageAdd(message *Message) error {
 | 
			
		||||
			if message.Content != "" {
 | 
			
		||||
				m.Content = message.Content
 | 
			
		||||
			}
 | 
			
		||||
			if message.EditedTimestamp != "" {
 | 
			
		||||
			if message.EditedTimestamp != nil {
 | 
			
		||||
				m.EditedTimestamp = message.EditedTimestamp
 | 
			
		||||
			}
 | 
			
		||||
			if message.Mentions != nil {
 | 
			
		||||
@@ -649,12 +781,15 @@ func (s *State) MessageAdd(message *Message) error {
 | 
			
		||||
			if message.Attachments != nil {
 | 
			
		||||
				m.Attachments = message.Attachments
 | 
			
		||||
			}
 | 
			
		||||
			if message.Timestamp != "" {
 | 
			
		||||
			if !message.Timestamp.IsZero() {
 | 
			
		||||
				m.Timestamp = message.Timestamp
 | 
			
		||||
			}
 | 
			
		||||
			if message.Author != nil {
 | 
			
		||||
				m.Author = message.Author
 | 
			
		||||
			}
 | 
			
		||||
			if message.Components != nil {
 | 
			
		||||
				m.Components = message.Components
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
@@ -665,6 +800,7 @@ func (s *State) MessageAdd(message *Message) error {
 | 
			
		||||
	if len(c.Messages) > s.MaxMessageCount {
 | 
			
		||||
		c.Messages = c.Messages[len(c.Messages)-s.MaxMessageCount:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -690,6 +826,7 @@ func (s *State) messageRemoveByID(channelID, messageID string) error {
 | 
			
		||||
	for i, m := range c.Messages {
 | 
			
		||||
		if m.ID == messageID {
 | 
			
		||||
			c.Messages = append(c.Messages[:i], c.Messages[i+1:]...)
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -833,10 +970,18 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
 | 
			
		||||
	case *GuildUpdate:
 | 
			
		||||
		err = s.GuildAdd(t.Guild)
 | 
			
		||||
	case *GuildDelete:
 | 
			
		||||
		var old *Guild
 | 
			
		||||
		old, err = s.Guild(t.ID)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			oldCopy := *old
 | 
			
		||||
			t.BeforeDelete = &oldCopy
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = s.GuildRemove(t.Guild)
 | 
			
		||||
	case *GuildMemberAdd:
 | 
			
		||||
		var guild *Guild
 | 
			
		||||
		// Updates the MemberCount of the guild.
 | 
			
		||||
		guild, err := s.Guild(t.Member.GuildID)
 | 
			
		||||
		guild, err = s.Guild(t.Member.GuildID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
@@ -851,8 +996,9 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
 | 
			
		||||
			err = s.MemberAdd(t.Member)
 | 
			
		||||
		}
 | 
			
		||||
	case *GuildMemberRemove:
 | 
			
		||||
		var guild *Guild
 | 
			
		||||
		// Updates the MemberCount of the guild.
 | 
			
		||||
		guild, err := s.Guild(t.Member.GuildID)
 | 
			
		||||
		guild, err = s.Guild(t.Member.GuildID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
@@ -903,6 +1049,35 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
 | 
			
		||||
		if s.TrackChannels {
 | 
			
		||||
			err = s.ChannelRemove(t.Channel)
 | 
			
		||||
		}
 | 
			
		||||
	case *ThreadCreate:
 | 
			
		||||
		if s.TrackThreads {
 | 
			
		||||
			err = s.ChannelAdd(t.Channel)
 | 
			
		||||
		}
 | 
			
		||||
	case *ThreadUpdate:
 | 
			
		||||
		if s.TrackThreads {
 | 
			
		||||
			old, err := s.Channel(t.ID)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				oldCopy := *old
 | 
			
		||||
				t.BeforeUpdate = &oldCopy
 | 
			
		||||
			}
 | 
			
		||||
			err = s.ChannelAdd(t.Channel)
 | 
			
		||||
		}
 | 
			
		||||
	case *ThreadDelete:
 | 
			
		||||
		if s.TrackThreads {
 | 
			
		||||
			err = s.ChannelRemove(t.Channel)
 | 
			
		||||
		}
 | 
			
		||||
	case *ThreadMemberUpdate:
 | 
			
		||||
		if s.TrackThreads {
 | 
			
		||||
			err = s.ThreadMemberUpdate(t)
 | 
			
		||||
		}
 | 
			
		||||
	case *ThreadMembersUpdate:
 | 
			
		||||
		if s.TrackThreadMembers {
 | 
			
		||||
			err = s.ThreadMembersUpdate(t)
 | 
			
		||||
		}
 | 
			
		||||
	case *ThreadListSync:
 | 
			
		||||
		if s.TrackThreads {
 | 
			
		||||
			err = s.ThreadListSync(t)
 | 
			
		||||
		}
 | 
			
		||||
	case *MessageCreate:
 | 
			
		||||
		if s.MaxMessageCount != 0 {
 | 
			
		||||
			err = s.MessageAdd(t.Message)
 | 
			
		||||
							
								
								
									
										2128
									
								
								vendor/github.com/bwmarrin/discordgo/structs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2128
									
								
								vendor/github.com/bwmarrin/discordgo/structs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,26 +1,25 @@
 | 
			
		||||
package discordgo
 | 
			
		||||
 | 
			
		||||
import "strings"
 | 
			
		||||
 | 
			
		||||
// UserFlags is the flags of "user" (see UserFlags* consts)
 | 
			
		||||
// https://discord.com/developers/docs/resources/user#user-object-user-flags
 | 
			
		||||
type UserFlags int
 | 
			
		||||
 | 
			
		||||
// Valid UserFlags values
 | 
			
		||||
const (
 | 
			
		||||
	UserFlagDiscordEmployee      UserFlags = 1 << 0
 | 
			
		||||
	UserFlagDiscordPartner                 = 1 << 1
 | 
			
		||||
	UserFlagHypeSquadEvents                = 1 << 2
 | 
			
		||||
	UserFlagBugHunterLevel1                = 1 << 3
 | 
			
		||||
	UserFlagHouseBravery                   = 1 << 6
 | 
			
		||||
	UserFlagHouseBrilliance                = 1 << 7
 | 
			
		||||
	UserFlagHouseBalance                   = 1 << 8
 | 
			
		||||
	UserFlagEarlySupporter                 = 1 << 9
 | 
			
		||||
	UserFlagTeamUser                       = 1 << 10
 | 
			
		||||
	UserFlagSystem                         = 1 << 12
 | 
			
		||||
	UserFlagBugHunterLevel2                = 1 << 14
 | 
			
		||||
	UserFlagVerifiedBot                    = 1 << 16
 | 
			
		||||
	UserFlagVerifiedBotDeveloper           = 1 << 17
 | 
			
		||||
	UserFlagDiscordEmployee           UserFlags = 1 << 0
 | 
			
		||||
	UserFlagDiscordPartner            UserFlags = 1 << 1
 | 
			
		||||
	UserFlagHypeSquadEvents           UserFlags = 1 << 2
 | 
			
		||||
	UserFlagBugHunterLevel1           UserFlags = 1 << 3
 | 
			
		||||
	UserFlagHouseBravery              UserFlags = 1 << 6
 | 
			
		||||
	UserFlagHouseBrilliance           UserFlags = 1 << 7
 | 
			
		||||
	UserFlagHouseBalance              UserFlags = 1 << 8
 | 
			
		||||
	UserFlagEarlySupporter            UserFlags = 1 << 9
 | 
			
		||||
	UserFlagTeamUser                  UserFlags = 1 << 10
 | 
			
		||||
	UserFlagSystem                    UserFlags = 1 << 12
 | 
			
		||||
	UserFlagBugHunterLevel2           UserFlags = 1 << 14
 | 
			
		||||
	UserFlagVerifiedBot               UserFlags = 1 << 16
 | 
			
		||||
	UserFlagVerifiedBotDeveloper      UserFlags = 1 << 17
 | 
			
		||||
	UserFlagDiscordCertifiedModerator UserFlags = 1 << 18
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A User stores all data for an individual Discord user.
 | 
			
		||||
@@ -55,6 +54,12 @@ type User struct {
 | 
			
		||||
	// Whether the user has multi-factor authentication enabled.
 | 
			
		||||
	MFAEnabled bool `json:"mfa_enabled"`
 | 
			
		||||
 | 
			
		||||
	// The hash of the user's banner image.
 | 
			
		||||
	Banner string `json:"banner"`
 | 
			
		||||
 | 
			
		||||
	// User's banner color, encoded as an integer representation of hexadecimal color code
 | 
			
		||||
	AccentColor int `json:"accent_color"`
 | 
			
		||||
 | 
			
		||||
	// Whether the user is a bot.
 | 
			
		||||
	Bot bool `json:"bot"`
 | 
			
		||||
 | 
			
		||||
@@ -90,17 +95,13 @@ func (u *User) Mention() string {
 | 
			
		||||
//             if size is an empty string, no size parameter will
 | 
			
		||||
//             be added to the URL.
 | 
			
		||||
func (u *User) AvatarURL(size string) string {
 | 
			
		||||
	var URL string
 | 
			
		||||
	if u.Avatar == "" {
 | 
			
		||||
		URL = EndpointDefaultUserAvatar(u.Discriminator)
 | 
			
		||||
	} else if strings.HasPrefix(u.Avatar, "a_") {
 | 
			
		||||
		URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
 | 
			
		||||
	} else {
 | 
			
		||||
		URL = EndpointUserAvatar(u.ID, u.Avatar)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if size != "" {
 | 
			
		||||
		return URL + "?size=" + size
 | 
			
		||||
	}
 | 
			
		||||
	return URL
 | 
			
		||||
	return avatarURL(u.Avatar, EndpointDefaultUserAvatar(u.Discriminator),
 | 
			
		||||
		EndpointUserAvatar(u.ID, u.Avatar), EndpointUserAvatarAnimated(u.ID, u.Avatar), size)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BannerURL returns the URL of the users's banner image.
 | 
			
		||||
//    size:    The size of the desired banner image as a power of two
 | 
			
		||||
//             Image size can be any power of two between 16 and 4096.
 | 
			
		||||
func (u *User) BannerURL(size string) string {
 | 
			
		||||
	return bannerURL(u.Banner, EndpointUserBanner(u.ID, u.Banner), EndpointUserBannerAnimated(u.ID, u.Banner), size)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								vendor/github.com/bwmarrin/discordgo/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								vendor/github.com/bwmarrin/discordgo/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
package discordgo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"mime/multipart"
 | 
			
		||||
	"net/textproto"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SnowflakeTimestamp returns the creation time of a Snowflake ID relative to the creation of Discord.
 | 
			
		||||
func SnowflakeTimestamp(ID string) (t time.Time, err error) {
 | 
			
		||||
	i, err := strconv.ParseInt(ID, 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	timestamp := (i >> 22) + 1420070400000
 | 
			
		||||
	t = time.Unix(0, timestamp*1000000)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MultipartBodyWithJSON returns the contentType and body for a discord request
 | 
			
		||||
// data  : The object to encode for payload_json in the multipart request
 | 
			
		||||
// files : Files to include in the request
 | 
			
		||||
func MultipartBodyWithJSON(data interface{}, files []*File) (requestContentType string, requestBody []byte, err error) {
 | 
			
		||||
	body := &bytes.Buffer{}
 | 
			
		||||
	bodywriter := multipart.NewWriter(body)
 | 
			
		||||
 | 
			
		||||
	payload, err := Marshal(data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var p io.Writer
 | 
			
		||||
 | 
			
		||||
	h := make(textproto.MIMEHeader)
 | 
			
		||||
	h.Set("Content-Disposition", `form-data; name="payload_json"`)
 | 
			
		||||
	h.Set("Content-Type", "application/json")
 | 
			
		||||
 | 
			
		||||
	p, err = bodywriter.CreatePart(h)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = p.Write(payload); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, file := range files {
 | 
			
		||||
		h := make(textproto.MIMEHeader)
 | 
			
		||||
		h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file%d"; filename="%s"`, i, quoteEscaper.Replace(file.Name)))
 | 
			
		||||
		contentType := file.ContentType
 | 
			
		||||
		if contentType == "" {
 | 
			
		||||
			contentType = "application/octet-stream"
 | 
			
		||||
		}
 | 
			
		||||
		h.Set("Content-Type", contentType)
 | 
			
		||||
 | 
			
		||||
		p, err = bodywriter.CreatePart(h)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if _, err = io.Copy(p, file.Reader); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = bodywriter.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return bodywriter.FormDataContentType(), body.Bytes(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func avatarURL(avatarHash, defaultAvatarURL, staticAvatarURL, animatedAvatarURL, size string) string {
 | 
			
		||||
	var URL string
 | 
			
		||||
	if avatarHash == "" {
 | 
			
		||||
		URL = defaultAvatarURL
 | 
			
		||||
	} else if strings.HasPrefix(avatarHash, "a_") {
 | 
			
		||||
		URL = animatedAvatarURL
 | 
			
		||||
	} else {
 | 
			
		||||
		URL = staticAvatarURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if size != "" {
 | 
			
		||||
		return URL + "?size=" + size
 | 
			
		||||
	}
 | 
			
		||||
	return URL
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bannerURL(bannerHash, staticBannerURL, animatedBannerURL, size string) string {
 | 
			
		||||
	var URL string
 | 
			
		||||
	if bannerHash == "" {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else if strings.HasPrefix(bannerHash, "a_") {
 | 
			
		||||
		URL = animatedBannerURL
 | 
			
		||||
	} else {
 | 
			
		||||
		URL = staticBannerURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if size != "" {
 | 
			
		||||
		return URL + "?size=" + size
 | 
			
		||||
	}
 | 
			
		||||
	return URL
 | 
			
		||||
}
 | 
			
		||||
@@ -831,9 +831,15 @@ func (v *VoiceConnection) opusReceiver(udpConn *net.UDPConn, close <-chan struct
 | 
			
		||||
		copy(nonce[:], recvbuf[0:12])
 | 
			
		||||
		p.Opus, _ = secretbox.Open(nil, recvbuf[12:rlen], &nonce, &v.op4.SecretKey)
 | 
			
		||||
 | 
			
		||||
		if len(p.Opus) > 8 && recvbuf[0] == 0x90 {
 | 
			
		||||
			// Extension bit is set, first 8 bytes is the extended header
 | 
			
		||||
			p.Opus = p.Opus[8:]
 | 
			
		||||
		// extension bit set, and not a RTCP packet
 | 
			
		||||
		if ((recvbuf[0] & 0x10) == 0x10) && ((recvbuf[1] & 0x80) == 0) {
 | 
			
		||||
			// get extended header length
 | 
			
		||||
			extlen := binary.BigEndian.Uint16(p.Opus[2:4])
 | 
			
		||||
			// 4 bytes (ext header header) + 4*extlen (ext header data)
 | 
			
		||||
			shift := int(4 + 4*extlen)
 | 
			
		||||
			if len(p.Opus) > shift {
 | 
			
		||||
				p.Opus = p.Opus[shift:]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if c != nil {
 | 
			
		||||
							
								
								
									
										49
									
								
								vendor/github.com/bwmarrin/discordgo/webhook.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								vendor/github.com/bwmarrin/discordgo/webhook.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
package discordgo
 | 
			
		||||
 | 
			
		||||
// Webhook stores the data for a webhook.
 | 
			
		||||
type Webhook struct {
 | 
			
		||||
	ID        string      `json:"id"`
 | 
			
		||||
	Type      WebhookType `json:"type"`
 | 
			
		||||
	GuildID   string      `json:"guild_id"`
 | 
			
		||||
	ChannelID string      `json:"channel_id"`
 | 
			
		||||
	User      *User       `json:"user"`
 | 
			
		||||
	Name      string      `json:"name"`
 | 
			
		||||
	Avatar    string      `json:"avatar"`
 | 
			
		||||
	Token     string      `json:"token"`
 | 
			
		||||
 | 
			
		||||
	// ApplicationID is the bot/OAuth2 application that created this webhook
 | 
			
		||||
	ApplicationID string `json:"application_id,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WebhookType is the type of Webhook (see WebhookType* consts) in the Webhook struct
 | 
			
		||||
// https://discord.com/developers/docs/resources/webhook#webhook-object-webhook-types
 | 
			
		||||
type WebhookType int
 | 
			
		||||
 | 
			
		||||
// Valid WebhookType values
 | 
			
		||||
const (
 | 
			
		||||
	WebhookTypeIncoming        WebhookType = 1
 | 
			
		||||
	WebhookTypeChannelFollower WebhookType = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// WebhookParams is a struct for webhook params, used in the WebhookExecute command.
 | 
			
		||||
type WebhookParams struct {
 | 
			
		||||
	Content         string                  `json:"content,omitempty"`
 | 
			
		||||
	Username        string                  `json:"username,omitempty"`
 | 
			
		||||
	AvatarURL       string                  `json:"avatar_url,omitempty"`
 | 
			
		||||
	TTS             bool                    `json:"tts,omitempty"`
 | 
			
		||||
	Files           []*File                 `json:"-"`
 | 
			
		||||
	Components      []MessageComponent      `json:"components"`
 | 
			
		||||
	Embeds          []*MessageEmbed         `json:"embeds,omitempty"`
 | 
			
		||||
	AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
 | 
			
		||||
	// NOTE: Works only for followup messages.
 | 
			
		||||
	Flags uint64 `json:"flags,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WebhookEdit stores data for editing of a webhook message.
 | 
			
		||||
type WebhookEdit struct {
 | 
			
		||||
	Content         string                  `json:"content,omitempty"`
 | 
			
		||||
	Components      []MessageComponent      `json:"components"`
 | 
			
		||||
	Embeds          []*MessageEmbed         `json:"embeds,omitempty"`
 | 
			
		||||
	Files           []*File                 `json:"-"`
 | 
			
		||||
	AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
@@ -33,7 +33,7 @@ var ErrWSAlreadyOpen = errors.New("web socket already opened")
 | 
			
		||||
var ErrWSNotFound = errors.New("no websocket connection exists")
 | 
			
		||||
 | 
			
		||||
// ErrWSShardBounds is thrown when you try to use a shard ID that is
 | 
			
		||||
// less than the total shard count
 | 
			
		||||
// more than the total shard count
 | 
			
		||||
var ErrWSShardBounds = errors.New("ShardID must be less than ShardCount")
 | 
			
		||||
 | 
			
		||||
type resumePacket struct {
 | 
			
		||||
@@ -383,6 +383,17 @@ func (s *Session) UpdateListeningStatus(name string) (err error) {
 | 
			
		||||
 | 
			
		||||
// UpdateStatusComplex allows for sending the raw status update data untouched by discordgo.
 | 
			
		||||
func (s *Session) UpdateStatusComplex(usd UpdateStatusData) (err error) {
 | 
			
		||||
	// The comment does say "untouched by discordgo", but we might need to lie a bit here.
 | 
			
		||||
	// The Discord documentation lists `activities` as being nullable, but in practice this
 | 
			
		||||
	// doesn't seem to be the case. I had filed an issue about this at
 | 
			
		||||
	// https://github.com/discord/discord-api-docs/issues/2559, but as of writing this
 | 
			
		||||
	// haven't had any movement on it, so at this point I'm assuming this is an error,
 | 
			
		||||
	// and am fixing this bug accordingly. Because sending `null` for `activities` instantly
 | 
			
		||||
	// disconnects us, I think that disallowing it from being sent in `UpdateStatusComplex`
 | 
			
		||||
	// isn't that big of an issue.
 | 
			
		||||
	if usd.Activities == nil {
 | 
			
		||||
		usd.Activities = make([]*Activity, 0)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.RLock()
 | 
			
		||||
	defer s.RUnlock()
 | 
			
		||||
@@ -398,10 +409,13 @@ func (s *Session) UpdateStatusComplex(usd UpdateStatusData) (err error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type requestGuildMembersData struct {
 | 
			
		||||
	GuildIDs  []string `json:"guild_id"`
 | 
			
		||||
	Query     string   `json:"query"`
 | 
			
		||||
	Limit     int      `json:"limit"`
 | 
			
		||||
	Presences bool     `json:"presences"`
 | 
			
		||||
	// TODO: Deprecated. Use string instead of []string
 | 
			
		||||
	GuildIDs  []string  `json:"guild_id"`
 | 
			
		||||
	Query     *string   `json:"query,omitempty"`
 | 
			
		||||
	UserIDs   *[]string `json:"user_ids,omitempty"`
 | 
			
		||||
	Limit     int       `json:"limit"`
 | 
			
		||||
	Nonce     string    `json:"nonce,omitempty"`
 | 
			
		||||
	Presences bool      `json:"presences"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type requestGuildMembersOp struct {
 | 
			
		||||
@@ -414,16 +428,21 @@ type requestGuildMembersOp struct {
 | 
			
		||||
// guildID   : Single Guild ID to request members of
 | 
			
		||||
// query     : String that username starts with, leave empty to return all members
 | 
			
		||||
// limit     : Max number of items to return, or 0 to request all members matched
 | 
			
		||||
// nonce     : Nonce to identify the Guild Members Chunk response
 | 
			
		||||
// presences : Whether to request presences of guild members
 | 
			
		||||
func (s *Session) RequestGuildMembers(guildID string, query string, limit int, presences bool) (err error) {
 | 
			
		||||
	data := requestGuildMembersData{
 | 
			
		||||
		GuildIDs:  []string{guildID},
 | 
			
		||||
		Query:     query,
 | 
			
		||||
		Limit:     limit,
 | 
			
		||||
		Presences: presences,
 | 
			
		||||
	}
 | 
			
		||||
	err = s.requestGuildMembers(data)
 | 
			
		||||
	return
 | 
			
		||||
func (s *Session) RequestGuildMembers(guildID, query string, limit int, nonce string, presences bool) error {
 | 
			
		||||
	return s.RequestGuildMembersBatch([]string{guildID}, query, limit, nonce, presences)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RequestGuildMembersList requests guild members from the gateway
 | 
			
		||||
// The gateway responds with GuildMembersChunk events
 | 
			
		||||
// guildID   : Single Guild ID to request members of
 | 
			
		||||
// userIDs   : IDs of users to fetch
 | 
			
		||||
// limit     : Max number of items to return, or 0 to request all members matched
 | 
			
		||||
// nonce     : Nonce to identify the Guild Members Chunk response
 | 
			
		||||
// presences : Whether to request presences of guild members
 | 
			
		||||
func (s *Session) RequestGuildMembersList(guildID string, userIDs []string, limit int, nonce string, presences bool) error {
 | 
			
		||||
	return s.RequestGuildMembersBatchList([]string{guildID}, userIDs, limit, nonce, presences)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RequestGuildMembersBatch requests guild members from the gateway
 | 
			
		||||
@@ -431,12 +450,37 @@ func (s *Session) RequestGuildMembers(guildID string, query string, limit int, p
 | 
			
		||||
// guildID   : Slice of guild IDs to request members of
 | 
			
		||||
// query     : String that username starts with, leave empty to return all members
 | 
			
		||||
// limit     : Max number of items to return, or 0 to request all members matched
 | 
			
		||||
// nonce     : Nonce to identify the Guild Members Chunk response
 | 
			
		||||
// presences : Whether to request presences of guild members
 | 
			
		||||
func (s *Session) RequestGuildMembersBatch(guildIDs []string, query string, limit int, presences bool) (err error) {
 | 
			
		||||
//
 | 
			
		||||
// NOTE: this function is deprecated, please use RequestGuildMembers instead
 | 
			
		||||
func (s *Session) RequestGuildMembersBatch(guildIDs []string, query string, limit int, nonce string, presences bool) (err error) {
 | 
			
		||||
	data := requestGuildMembersData{
 | 
			
		||||
		GuildIDs:  guildIDs,
 | 
			
		||||
		Query:     query,
 | 
			
		||||
		Query:     &query,
 | 
			
		||||
		Limit:     limit,
 | 
			
		||||
		Nonce:     nonce,
 | 
			
		||||
		Presences: presences,
 | 
			
		||||
	}
 | 
			
		||||
	err = s.requestGuildMembers(data)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RequestGuildMembersBatchList requests guild members from the gateway
 | 
			
		||||
// The gateway responds with GuildMembersChunk events
 | 
			
		||||
// guildID   : Slice of guild IDs to request members of
 | 
			
		||||
// userIDs   : IDs of users to fetch
 | 
			
		||||
// limit     : Max number of items to return, or 0 to request all members matched
 | 
			
		||||
// nonce     : Nonce to identify the Guild Members Chunk response
 | 
			
		||||
// presences : Whether to request presences of guild members
 | 
			
		||||
//
 | 
			
		||||
// NOTE: this function is deprecated, please use RequestGuildMembersList instead
 | 
			
		||||
func (s *Session) RequestGuildMembersBatchList(guildIDs []string, userIDs []string, limit int, nonce string, presences bool) (err error) {
 | 
			
		||||
	data := requestGuildMembersData{
 | 
			
		||||
		GuildIDs:  guildIDs,
 | 
			
		||||
		UserIDs:   &userIDs,
 | 
			
		||||
		Limit:     limit,
 | 
			
		||||
		Nonce:     nonce,
 | 
			
		||||
		Presences: presences,
 | 
			
		||||
	}
 | 
			
		||||
	err = s.requestGuildMembers(data)
 | 
			
		||||
@@ -755,13 +799,13 @@ func (s *Session) identify() error {
 | 
			
		||||
	s.log(LogDebug, "called")
 | 
			
		||||
 | 
			
		||||
	// TODO: This is a temporary block of code to help
 | 
			
		||||
	// maintain backwards compatability
 | 
			
		||||
	// maintain backwards compatibility
 | 
			
		||||
	if s.Compress == false {
 | 
			
		||||
		s.Identify.Compress = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: This is a temporary block of code to help
 | 
			
		||||
	// maintain backwards compatability
 | 
			
		||||
	// maintain backwards compatibility
 | 
			
		||||
	if s.Token != "" && s.Identify.Token == "" {
 | 
			
		||||
		s.Identify.Token = s.Token
 | 
			
		||||
	}
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/d5/tengo/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/d5/tengo/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -147,7 +147,4 @@ fmt.Println(res) // "success"
 | 
			
		||||
- Syntax Highlighters: [VSCode](https://github.com/lissein/vscode-tengo), [Atom](https://github.com/d5/tengo-atom)
 | 
			
		||||
- **Why the name Tengo?** It's from [1Q84](https://en.wikipedia.org/wiki/1Q84).
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
 | 
			
		||||
:hearts: Like writing Go code? Come work at Skool. [We're hiring!](https://jobs.lever.co/skool)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/d5/tengo/v2/objects.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/d5/tengo/v2/objects.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1577,9 +1577,8 @@ func (o *Undefined) Value() Object {
 | 
			
		||||
// UserFunction represents a user function.
 | 
			
		||||
type UserFunction struct {
 | 
			
		||||
	ObjectImpl
 | 
			
		||||
	Name       string
 | 
			
		||||
	Value      CallableFunc
 | 
			
		||||
	EncodingID string
 | 
			
		||||
	Name  string
 | 
			
		||||
	Value CallableFunc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TypeName returns the name of the type.
 | 
			
		||||
@@ -1593,7 +1592,7 @@ func (o *UserFunction) String() string {
 | 
			
		||||
 | 
			
		||||
// Copy returns a copy of the type.
 | 
			
		||||
func (o *UserFunction) Copy() Object {
 | 
			
		||||
	return &UserFunction{Value: o.Value}
 | 
			
		||||
	return &UserFunction{Value: o.Value, Name: o.Name}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Equals returns true if the value of the type is equal to the value of
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/d5/tengo/v2/stdlib/source_modules.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/d5/tengo/v2/stdlib/source_modules.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,5 +4,5 @@ package stdlib
 | 
			
		||||
 | 
			
		||||
// SourceModules are source type standard library modules.
 | 
			
		||||
var SourceModules = map[string]string{
 | 
			
		||||
	"enum": "is_enumerable := func(x) {\n  return is_array(x) || is_map(x) || is_immutable_array(x) || is_immutable_map(x)\n}\n\nis_array_like := func(x) {\n  return is_array(x) || is_immutable_array(x)\n}\n\nexport {\n  // all returns true if the given function `fn` evaluates to a truthy value on\n  // all of the items in `x`. It returns undefined if `x` is not enumerable.\n  all: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    for k, v in x {\n      if !fn(k, v) { return false }\n    }\n\n    return true\n  },\n  // any returns true if the given function `fn` evaluates to a truthy value on\n  // any of the items in `x`. It returns undefined if `x` is not enumerable.\n  any: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    for k, v in x {\n      if fn(k, v) { return true }\n    }\n\n    return false\n  },\n  // chunk returns an array of elements split into groups the length of size.\n  // If `x` can't be split evenly, the final chunk will be the remaining elements.\n  // It returns undefined if `x` is not array.\n  chunk: func(x, size) {\n    if !is_array_like(x) || !size { return undefined }\n\n    numElements := len(x)\n    if !numElements { return [] }\n\n    res := []\n    idx := 0\n    for idx < numElements {\n      res = append(res, x[idx:idx+size])\n      idx += size\n    }\n\n    return res\n  },\n  // at returns an element at the given index (if `x` is array) or\n  // key (if `x` is map). It returns undefined if `x` is not enumerable.\n  at: func(x, key) {\n    if !is_enumerable(x) { return undefined }\n\n    if is_array_like(x) {\n        if !is_int(key) { return undefined }\n    } else {\n        if !is_string(key) { return undefined }\n    }\n\n    return x[key]\n  },\n  // each iterates over elements of `x` and invokes `fn` for each element. `fn` is\n  // invoked with two arguments: `key` and `value`. `key` is an int index\n  // if `x` is array. `key` is a string key if `x` is map. It does not iterate\n  // and returns undefined if `x` is not enumerable.\n  each: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    for k, v in x {\n      fn(k, v)\n    }\n  },\n  // filter iterates over elements of `x`, returning an array of all elements `fn`\n  // returns truthy for. `fn` is invoked with two arguments: `key` and `value`.\n  // `key` is an int index if `x` is array. `key` is a string key if `x` is map.\n  // It returns undefined if `x` is not enumerable.\n  filter: func(x, fn) {\n    if !is_array_like(x) { return undefined }\n\n    dst := []\n    for k, v in x {\n      if fn(k, v) { dst = append(dst, v) }\n    }\n\n    return dst\n  },\n  // find iterates over elements of `x`, returning value of the first element `fn`\n  // returns truthy for. `fn` is invoked with two arguments: `key` and `value`.\n  // `key` is an int index if `x` is array. `key` is a string key if `x` is map.\n  // It returns undefined if `x` is not enumerable.\n  find: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    for k, v in x {\n      if fn(k, v) { return v }\n    }\n  },\n  // find_key iterates over elements of `x`, returning key or index of the first\n  // element `fn` returns truthy for. `fn` is invoked with two arguments: `key`\n  // and `value`. `key` is an int index if `x` is array. `key` is a string key if\n  // `x` is map. It returns undefined if `x` is not enumerable.\n  find_key: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    for k, v in x {\n      if fn(k, v) { return k }\n    }\n  },\n  // map creates an array of values by running each element in `x` through `fn`.\n  // `fn` is invoked with two arguments: `key` and `value`. `key` is an int index\n  // if `x` is array. `key` is a string key if `x` is map. It returns undefined\n  // if `x` is not enumerable.\n  map: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    dst := []\n    for k, v in x {\n      dst = append(dst, fn(k, v))\n    }\n\n    return dst\n  },\n  // key returns the first argument.\n  key: func(k, _) { return k },\n  // value returns the second argument.\n  value: func(_, v) { return v }\n}\n",
 | 
			
		||||
	"enum": "is_enumerable := func(x) {\n  return is_array(x) || is_map(x) || is_immutable_array(x) || is_immutable_map(x)\n}\n\nis_array_like := func(x) {\n  return is_array(x) || is_immutable_array(x)\n}\n\nexport {\n  // all returns true if the given function `fn` evaluates to a truthy value on\n  // all of the items in `x`. It returns undefined if `x` is not enumerable.\n  all: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    for k, v in x {\n      if !fn(k, v) { return false }\n    }\n\n    return true\n  },\n  // any returns true if the given function `fn` evaluates to a truthy value on\n  // any of the items in `x`. It returns undefined if `x` is not enumerable.\n  any: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    for k, v in x {\n      if fn(k, v) { return true }\n    }\n\n    return false\n  },\n  // chunk returns an array of elements split into groups the length of size.\n  // If `x` can't be split evenly, the final chunk will be the remaining elements.\n  // It returns undefined if `x` is not array.\n  chunk: func(x, size) {\n    if !is_array_like(x) || !size { return undefined }\n\n    numElements := len(x)\n    if !numElements { return [] }\n\n    res := []\n    idx := 0\n    for idx < numElements {\n      res = append(res, x[idx:idx+size])\n      idx += size\n    }\n\n    return res\n  },\n  // at returns an element at the given index (if `x` is array) or\n  // key (if `x` is map). It returns undefined if `x` is not enumerable.\n  at: func(x, key) {\n    if !is_enumerable(x) { return undefined }\n\n    if is_array_like(x) {\n        if !is_int(key) { return undefined }\n    } else {\n        if !is_string(key) { return undefined }\n    }\n\n    return x[key]\n  },\n  // each iterates over elements of `x` and invokes `fn` for each element. `fn` is\n  // invoked with two arguments: `key` and `value`. `key` is an int index\n  // if `x` is array. `key` is a string key if `x` is map. It does not iterate\n  // and returns undefined if `x` is not enumerable.\n  each: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    for k, v in x {\n      fn(k, v)\n    }\n  },\n  // filter iterates over elements of `x`, returning an array of all elements `fn`\n  // returns truthy for. `fn` is invoked with two arguments: `key` and `value`.\n  // `key` is an int index if `x` is array. It returns undefined if `x` is not array.\n  filter: func(x, fn) {\n    if !is_array_like(x) { return undefined }\n\n    dst := []\n    for k, v in x {\n      if fn(k, v) { dst = append(dst, v) }\n    }\n\n    return dst\n  },\n  // find iterates over elements of `x`, returning value of the first element `fn`\n  // returns truthy for. `fn` is invoked with two arguments: `key` and `value`.\n  // `key` is an int index if `x` is array. `key` is a string key if `x` is map.\n  // It returns undefined if `x` is not enumerable.\n  find: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    for k, v in x {\n      if fn(k, v) { return v }\n    }\n  },\n  // find_key iterates over elements of `x`, returning key or index of the first\n  // element `fn` returns truthy for. `fn` is invoked with two arguments: `key`\n  // and `value`. `key` is an int index if `x` is array. `key` is a string key if\n  // `x` is map. It returns undefined if `x` is not enumerable.\n  find_key: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    for k, v in x {\n      if fn(k, v) { return k }\n    }\n  },\n  // map creates an array of values by running each element in `x` through `fn`.\n  // `fn` is invoked with two arguments: `key` and `value`. `key` is an int index\n  // if `x` is array. `key` is a string key if `x` is map. It returns undefined\n  // if `x` is not enumerable.\n  map: func(x, fn) {\n    if !is_enumerable(x) { return undefined }\n\n    dst := []\n    for k, v in x {\n      dst = append(dst, fn(k, v))\n    }\n\n    return dst\n  },\n  // key returns the first argument.\n  key: func(k, _) { return k },\n  // value returns the second argument.\n  value: func(_, v) { return v }\n}\n",
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/d5/tengo/v2/stdlib/srcmod_enum.tengo
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/d5/tengo/v2/stdlib/srcmod_enum.tengo
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -73,8 +73,7 @@ export {
 | 
			
		||||
  },
 | 
			
		||||
  // filter iterates over elements of `x`, returning an array of all elements `fn`
 | 
			
		||||
  // returns truthy for. `fn` is invoked with two arguments: `key` and `value`.
 | 
			
		||||
  // `key` is an int index if `x` is array. `key` is a string key if `x` is map.
 | 
			
		||||
  // It returns undefined if `x` is not enumerable.
 | 
			
		||||
  // `key` is an int index if `x` is array. It returns undefined if `x` is not array.
 | 
			
		||||
  filter: func(x, fn) {
 | 
			
		||||
    if !is_array_like(x) { return undefined }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -7,9 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 | 
			
		||||
 | 
			
		||||
## [Unreleased]
 | 
			
		||||
 | 
			
		||||
## [1.5.4] - 2022-04-25
 | 
			
		||||
 | 
			
		||||
* Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447)
 | 
			
		||||
* go.mod: use latest x/sys [#444](https://github.com/fsnotify/fsnotify/pull/444)
 | 
			
		||||
* Fix compilation for OpenBSD [#443](https://github.com/fsnotify/fsnotify/pull/443)
 | 
			
		||||
 | 
			
		||||
## [1.5.3] - 2022-04-22
 | 
			
		||||
 | 
			
		||||
* This version is retracted. An incorrect branch is published accidentally [#445](https://github.com/fsnotify/fsnotify/issues/445)
 | 
			
		||||
 | 
			
		||||
## [1.5.2] - 2022-04-21
 | 
			
		||||
 | 
			
		||||
* Add a feature to return the directories and files that are being monitored [#374](https://github.com/fsnotify/fsnotify/pull/374)
 | 
			
		||||
* Fix potential crash on windows if `raw.FileNameLength` exceeds `syscall.MAX_PATH` [#361](https://github.com/fsnotify/fsnotify/pull/361)
 | 
			
		||||
* Allow build on unsupported GOOS [#424](https://github.com/fsnotify/fsnotify/pull/424)
 | 
			
		||||
* Don't set `poller.fd` twice in `newFdPoller` [#406](https://github.com/fsnotify/fsnotify/pull/406)
 | 
			
		||||
* fix go vet warnings: call to `(*T).Fatalf` from a non-test goroutine [#416](https://github.com/fsnotify/fsnotify/pull/416)
 | 
			
		||||
 | 
			
		||||
## [1.5.1] - 2021-08-24
 | 
			
		||||
 | 
			
		||||
* Revert Add AddRaw to not follow symlinks
 | 
			
		||||
* Revert Add AddRaw to not follow symlinks [#394](https://github.com/fsnotify/fsnotify/pull/394)
 | 
			
		||||
 | 
			
		||||
## [1.5.0] - 2021-08-20
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -48,18 +48,6 @@ fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Win
 | 
			
		||||
 | 
			
		||||
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
 | 
			
		||||
 | 
			
		||||
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
 | 
			
		||||
 | 
			
		||||
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
 | 
			
		||||
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
 | 
			
		||||
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
 | 
			
		||||
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
 | 
			
		||||
* When you're done, you will want to halt or destroy the Vagrant boxes.
 | 
			
		||||
 | 
			
		||||
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
 | 
			
		||||
 | 
			
		||||
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
 | 
			
		||||
 | 
			
		||||
### Maintainers
 | 
			
		||||
 | 
			
		||||
Help maintaining fsnotify is welcome. To be a maintainer:
 | 
			
		||||
@@ -67,11 +55,6 @@ Help maintaining fsnotify is welcome. To be a maintainer:
 | 
			
		||||
* Submit a pull request and sign the CLA as above.
 | 
			
		||||
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
 | 
			
		||||
 | 
			
		||||
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
 | 
			
		||||
 | 
			
		||||
All code changes should be internal pull requests.
 | 
			
		||||
 | 
			
		||||
Releases are tagged using [Semantic Versioning](http://semver.org/).
 | 
			
		||||
 | 
			
		||||
[hub]: https://github.com/github/hub
 | 
			
		||||
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/github.com/fsnotify/fsnotify/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/fsnotify/fsnotify/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,12 +1,8 @@
 | 
			
		||||
# File system notifications for Go
 | 
			
		||||
 | 
			
		||||
[](https://godoc.org/github.com/fsnotify/fsnotify) [](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
 | 
			
		||||
[](https://pkg.go.dev/github.com/fsnotify/fsnotify) [](https://goreportcard.com/report/github.com/fsnotify/fsnotify) [](https://github.com/fsnotify/fsnotify/issues/413)
 | 
			
		||||
 | 
			
		||||
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
go get -u golang.org/x/sys/...
 | 
			
		||||
```
 | 
			
		||||
fsnotify utilizes [`golang.org/x/sys`](https://pkg.go.dev/golang.org/x/sys) rather than [`syscall`](https://pkg.go.dev/syscall) from the standard library.
 | 
			
		||||
 | 
			
		||||
Cross platform: Windows, Linux, BSD and macOS.
 | 
			
		||||
 | 
			
		||||
@@ -16,22 +12,20 @@ Cross platform: Windows, Linux, BSD and macOS.
 | 
			
		||||
| kqueue                | BSD, macOS, iOS\*                | Supported |
 | 
			
		||||
| ReadDirectoryChangesW | Windows                          | Supported |
 | 
			
		||||
| FSEvents              | macOS                            | [Planned](https://github.com/fsnotify/fsnotify/issues/11)                                                                       |
 | 
			
		||||
| FEN                   | Solaris 11                       | [In Progress](https://github.com/fsnotify/fsnotify/issues/12)                                                                   |
 | 
			
		||||
| fanotify              | Linux 2.6.37+                    | [Planned](https://github.com/fsnotify/fsnotify/issues/114)                                                                      |
 | 
			
		||||
| FEN                   | Solaris 11                       | [In Progress](https://github.com/fsnotify/fsnotify/pull/371)                                                                   |
 | 
			
		||||
| fanotify              | Linux 2.6.37+                    | [Maybe](https://github.com/fsnotify/fsnotify/issues/114)                                                                      |
 | 
			
		||||
| USN Journals          | Windows                          | [Maybe](https://github.com/fsnotify/fsnotify/issues/53)                                                                         |
 | 
			
		||||
| Polling               | *All*                            | [Maybe](https://github.com/fsnotify/fsnotify/issues/9)                                                                          |
 | 
			
		||||
 | 
			
		||||
\* Android and iOS are untested.
 | 
			
		||||
 | 
			
		||||
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
 | 
			
		||||
Please see [the documentation](https://pkg.go.dev/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
 | 
			
		||||
 | 
			
		||||
## API stability
 | 
			
		||||
 | 
			
		||||
fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA). 
 | 
			
		||||
fsnotify is a fork of [howeyc/fsnotify](https://github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
 | 
			
		||||
 | 
			
		||||
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
 | 
			
		||||
 | 
			
		||||
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
 | 
			
		||||
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/).
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
@@ -84,10 +78,6 @@ func main() {
 | 
			
		||||
 | 
			
		||||
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
 | 
			
		||||
 | 
			
		||||
## Example
 | 
			
		||||
 | 
			
		||||
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
 | 
			
		||||
 | 
			
		||||
## FAQ
 | 
			
		||||
 | 
			
		||||
**When a file is moved to another directory is it still being watched?**
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user