浏览代码

Add initial support for bot accounts. Fixes #12

Tulir Asokan 2 年之前
父节点
当前提交
60c260a471
共有 2 个文件被更改,包括 77 次插入4 次删除
  1. 55 3
      commands.go
  2. 22 1
      user.go

+ 55 - 3
commands.go

@@ -19,6 +19,7 @@ package main
 import (
 	"bytes"
 	"context"
+	"encoding/base64"
 	"errors"
 	"fmt"
 	"html"
@@ -80,12 +81,45 @@ var cmdLoginToken = &commands.FullHandler{
 	Help: commands.HelpMeta{
 		Section:     commands.HelpSectionAuth,
 		Description: "Link the bridge to your Discord account by extracting the access token manually.",
+		Args:        "<user/bot/oauth> <_token_>",
 	},
 }
 
+const discordTokenEpoch = 1293840000
+
+func decodeToken(token string) (userID int64, err error) {
+	parts := strings.Split(token, ".")
+	if len(parts) != 3 {
+		err = fmt.Errorf("invalid number of parts in token")
+		return
+	}
+	var userIDStr []byte
+	userIDStr, err = base64.RawURLEncoding.DecodeString(parts[0])
+	if err != nil {
+		err = fmt.Errorf("invalid base64 in user ID part: %w", err)
+		return
+	}
+	_, err = base64.RawURLEncoding.DecodeString(parts[1])
+	if err != nil {
+		err = fmt.Errorf("invalid base64 in random part: %w", err)
+		return
+	}
+	_, err = base64.RawURLEncoding.DecodeString(parts[2])
+	if err != nil {
+		err = fmt.Errorf("invalid base64 in checksum part: %w", err)
+		return
+	}
+	userID, err = strconv.ParseInt(string(userIDStr), 10, 64)
+	if err != nil {
+		err = fmt.Errorf("invalid number in decoded user ID part: %w", err)
+		return
+	}
+	return
+}
+
 func fnLoginToken(ce *WrappedCommandEvent) {
-	if len(ce.Args) == 0 {
-		ce.Reply("**Usage**: `$cmdprefix login-token <token>`")
+	if len(ce.Args) != 2 {
+		ce.Reply("**Usage**: `$cmdprefix login-token <user/bot/oauth> <token>`")
 		return
 	}
 	ce.MarkRead()
@@ -94,7 +128,25 @@ func fnLoginToken(ce *WrappedCommandEvent) {
 		ce.Reply("You're already logged in")
 		return
 	}
-	if err := ce.User.Login(ce.Args[0]); err != nil {
+	token := ce.Args[1]
+	userID, err := decodeToken(token)
+	if err != nil {
+		ce.Reply("Invalid token")
+		return
+	}
+	switch strings.ToLower(ce.Args[0]) {
+	case "user":
+		// Token is used as-is
+	case "bot":
+		token = "Bot " + token
+	case "oauth":
+		token = "Bearer " + token
+	default:
+		ce.Reply("Token type must be `user`, `bot` or `oauth`")
+		return
+	}
+	ce.Reply("Connecting to Discord as user ID %d", userID)
+	if err = ce.User.Login(token); err != nil {
 		ce.Reply("Error connecting to Discord: %v", err)
 		return
 	}

+ 22 - 1
user.go

@@ -487,6 +487,24 @@ func (user *User) Connected() bool {
 	return user.Session != nil
 }
 
+const BotIntents = discordgo.IntentGuilds |
+	discordgo.IntentGuildMessages |
+	discordgo.IntentGuildMessageReactions |
+	discordgo.IntentGuildMessageTyping |
+	discordgo.IntentGuildBans |
+	discordgo.IntentGuildEmojis |
+	discordgo.IntentGuildIntegrations |
+	discordgo.IntentGuildInvites |
+	//discordgo.IntentGuildVoiceStates |
+	//discordgo.IntentGuildScheduledEvents |
+	discordgo.IntentDirectMessages |
+	discordgo.IntentDirectMessageTyping |
+	discordgo.IntentDirectMessageTyping |
+	// Privileged intents
+	discordgo.IntentMessageContent |
+	//discordgo.IntentGuildPresences |
+	discordgo.IntentGuildMembers
+
 func (user *User) Connect() error {
 	user.Lock()
 	defer user.Unlock()
@@ -505,6 +523,9 @@ func (user *User) Connect() error {
 	if os.Getenv("DISCORD_DEBUG") == "1" {
 		session.LogLevel = discordgo.LogDebug
 	}
+	if !session.IsUser {
+		session.Identify.Intents = BotIntents
+	}
 
 	user.Session = session
 
@@ -593,7 +614,7 @@ func (user *User) readyHandler(_ *discordgo.Session, r *discordgo.Ready) {
 	}
 	user.PrunePortalList(updateTS)
 
-	if r.ReadState.Version > user.ReadStateVersion {
+	if r.ReadState != nil && r.ReadState.Version > user.ReadStateVersion {
 		// TODO can we figure out which read states are actually new?
 		for _, entry := range r.ReadState.Entries {
 			user.messageAckHandler(nil, &discordgo.MessageAck{