PIN verification, notifications, multiple notif providers

Discord, Email & Telegram can be enabled, although email is always
enabled right now (will fix). Also apparently markdown hyperlinks don't
work in Discord, eventually will implement something to convert them to
embeds.
This commit is contained in:
Harvey Tindall
2021-05-21 21:35:25 +01:00
parent 524941da0c
commit f8f5f35cc1
16 changed files with 509 additions and 92 deletions
+114 -42
View File
@@ -7,22 +7,17 @@ import (
dg "github.com/bwmarrin/discordgo"
)
type DiscordToken struct {
Token string
ChannelID string
UserID string
Username string
}
type DiscordDaemon struct {
Stopped bool
ShutdownChannel chan string
bot *dg.Session
username string
tokens map[string]DiscordToken // map of user IDs to tokens.
verifiedTokens []DiscordToken
languages map[string]string // Store of languages for user IDs. Added to on first interaction, and loaded from app.storage.discord on start.
app *appContext
Stopped bool
ShutdownChannel chan string
bot *dg.Session
username string
tokens []string
verifiedTokens map[string]DiscordUser // Map of tokens to discord users.
channelID, channelName string
serverChannelName string
users map[string]DiscordUser // Map of user IDs to users. Added to on first interaction, and loaded from app.storage.discord on start.
app *appContext
}
func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) {
@@ -38,28 +33,39 @@ func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) {
Stopped: false,
ShutdownChannel: make(chan string),
bot: bot,
tokens: map[string]DiscordToken{},
verifiedTokens: []DiscordToken{},
languages: map[string]string{},
tokens: []string{},
verifiedTokens: map[string]DiscordUser{},
users: map[string]DiscordUser{},
app: app,
}
for _, user := range app.storage.discord {
if user.Lang != "" {
dd.languages[user.ID] = user.Lang
}
dd.users[user.ID] = user
}
return dd, nil
}
func (d *DiscordDaemon) NewAuthToken(channelID, userID, username string) DiscordToken {
// NewAuthToken generates an 8-character pin in the form "A1-2B-CD".
func (d *DiscordDaemon) NewAuthToken() string {
pin := genAuthToken()
token := DiscordToken{
Token: pin,
ChannelID: channelID,
UserID: userID,
Username: username,
d.tokens = append(d.tokens, pin)
return pin
}
func (d *DiscordDaemon) NewUnknownUser(channelID, userID, discrim, username string) DiscordUser {
user := DiscordUser{
ChannelID: channelID,
ID: userID,
Username: username,
Discriminator: discrim,
}
return token
return user
}
func (d *DiscordDaemon) MustGetUser(channelID, userID, discrim, username string) DiscordUser {
if user, ok := d.users[userID]; ok {
return user
}
return d.NewUnknownUser(channelID, userID, discrim, username)
}
func (d *DiscordDaemon) run() {
@@ -70,6 +76,15 @@ func (d *DiscordDaemon) run() {
return
}
d.username = d.bot.State.User.Username
// Choose the last guild (server), for now we don't really support multiple anyway
guild, err := d.bot.Guild(d.bot.State.Guilds[len(d.bot.State.Guilds)-1].ID)
if err != nil {
d.app.err.Printf("Discord: Failed to get guild: %v", err)
}
d.serverChannelName = guild.Name
if channel := d.app.config.Section("discord").Key("channel").String(); channel != "" {
d.channelName = channel
}
defer d.bot.Close()
<-d.ShutdownChannel
d.ShutdownChannel <- "Down"
@@ -84,6 +99,22 @@ func (d *DiscordDaemon) Shutdown() {
}
func (d *DiscordDaemon) messageHandler(s *dg.Session, m *dg.MessageCreate) {
if m.GuildID != "" && d.channelName != "" {
if d.channelID == "" {
channel, err := s.Channel(m.ChannelID)
if err != nil {
d.app.err.Printf("Discord: Couldn't get channel, will monitor all: %v", err)
d.channelName = ""
}
if channel.Name == d.channelName {
d.channelID = channel.ID
}
}
if d.channelID != m.ChannelID {
d.app.debug.Printf("Discord: Ignoring message as not in specified channel")
return
}
}
if m.Author.ID == s.State.User.ID {
return
}
@@ -92,11 +123,13 @@ func (d *DiscordDaemon) messageHandler(s *dg.Session, m *dg.MessageCreate) {
return
}
lang := d.app.storage.lang.chosenTelegramLang
if storedLang, ok := d.languages[m.Author.ID]; ok {
lang = storedLang
if user, ok := d.users[m.Author.ID]; ok {
if _, ok := d.app.storage.lang.Telegram[user.Lang]; ok {
lang = user.Lang
}
}
switch msg := sects[0]; msg {
case d.app.config.Section("telegram").Key("start_command").MustString("!start"):
case d.app.config.Section("discord").Key("start_command").MustString("!start"):
d.commandStart(s, m, lang)
case "!lang":
d.commandLang(s, m, sects, lang)
@@ -111,8 +144,8 @@ func (d *DiscordDaemon) commandStart(s *dg.Session, m *dg.MessageCreate, lang st
d.app.err.Printf("Discord: Failed to create private channel with \"%s\": %v", m.Author.Username, err)
return
}
token := d.NewAuthToken(channel.ID, m.Author.ID, m.Author.Username)
d.tokens[m.Author.ID] = token
user := d.MustGetUser(channel.ID, m.Author.ID, m.Author.Discriminator, m.Author.Username)
d.users[m.Author.ID] = user
content := d.app.storage.lang.Telegram[lang].Strings.get("startMessage") + "\n"
content += d.app.storage.lang.Telegram[lang].Strings.template("languageMessage", tmpl{"command": "!lang"})
_, err = s.ChannelMessageSend(channel.ID, content)
@@ -139,7 +172,7 @@ func (d *DiscordDaemon) commandLang(s *dg.Session, m *dg.MessageCreate, sects []
return
}
if _, ok := d.app.storage.lang.Telegram[sects[1]]; ok {
d.languages[m.Author.ID] = sects[1]
var user DiscordUser
for jfID, user := range d.app.storage.discord {
if user.ID == m.Author.ID {
user.Lang = sects[1]
@@ -150,30 +183,69 @@ func (d *DiscordDaemon) commandLang(s *dg.Session, m *dg.MessageCreate, sects []
break
}
}
d.users[m.Author.ID] = user
}
}
func (d *DiscordDaemon) commandPIN(s *dg.Session, m *dg.MessageCreate, sects []string, lang string) {
token, ok := d.tokens[m.Author.ID]
if !ok || token.Token != sects[0] {
_, err := s.ChannelMessageSendReply(
if _, ok := d.users[m.Author.ID]; ok {
channel, err := s.Channel(m.ChannelID)
if err != nil {
d.app.err.Printf("Discord: Failed to get channel: %v", err)
return
}
if channel.Type != dg.ChannelTypeDM {
d.app.debug.Println("Discord: Ignoring message as not a DM")
return
}
} else {
d.app.debug.Println("Discord: Ignoring message as user was not found")
return
}
tokenIndex := -1
for i, token := range d.tokens {
if sects[0] == token {
tokenIndex = i
break
}
}
if tokenIndex == -1 {
_, err := s.ChannelMessageSend(
m.ChannelID,
d.app.storage.lang.Telegram[lang].Strings.get("invalidPIN"),
m.Reference(),
)
if err != nil {
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", m.Author.Username, err)
}
return
}
_, err := s.ChannelMessageSendReply(
_, err := s.ChannelMessageSend(
m.ChannelID,
d.app.storage.lang.Telegram[lang].Strings.get("pinSuccess"),
m.Reference(),
)
if err != nil {
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", m.Author.Username, err)
}
d.verifiedTokens = append(d.verifiedTokens, token)
delete(d.tokens, m.Author.ID)
d.verifiedTokens[sects[0]] = d.users[m.Author.ID]
d.tokens[len(d.tokens)-1], d.tokens[tokenIndex] = d.tokens[tokenIndex], d.tokens[len(d.tokens)-1]
d.tokens = d.tokens[:len(d.tokens)-1]
}
func (d *DiscordDaemon) Send(message *Message, channelID ...string) error {
for _, id := range channelID {
msg := ""
if message.Markdown == "" {
msg = message.Text
} else {
msg = message.Markdown
}
_, err := d.bot.ChannelMessageSend(
id,
msg,
)
if err != nil {
return err
}
}
return nil
}