Compare commits
2 Commits
6e1c27ca27
...
hkremer/re
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b8b01e31a | |||
| 03bcca77f4 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,4 @@
|
|||||||
build/
|
build/
|
||||||
.DS_Store
|
|
||||||
public/
|
public/
|
||||||
disgord-thanos
|
disgord-thanos
|
||||||
disgord-Thanos
|
disgord-Thanos
|
||||||
|
|||||||
49
auth.go
49
auth.go
@ -7,7 +7,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,14 +16,14 @@ func reqPass(w http.ResponseWriter, r *http.Request) {
|
|||||||
username := r.URL.Query()["UserName"][0]
|
username := r.URL.Query()["UserName"][0]
|
||||||
log.LogInfo("reqPass username is %+v.", username)
|
log.LogInfo("reqPass username is %+v.", username)
|
||||||
var userID string
|
var userID string
|
||||||
if dg == nil {
|
if &dg == nil {
|
||||||
log.LogError("Discord session was nill.")
|
log.LogError("Discord session was nill.")
|
||||||
}
|
}
|
||||||
g, err := dg.GuildMembers(config.GuildID, "", 1000)
|
g, err := dg.GuildMembers(config.GuildID, "", 1000)
|
||||||
log.LogInfo("reqPass guild is %+v.", config.GuildID)
|
log.LogInfo("reqPass guild is %+v.", config.GuildID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, m := range g {
|
for _, m := range g {
|
||||||
if strings.EqualFold(m.Nick, username) {
|
if strings.ToUpper(m.Nick) == strings.ToUpper(username) {
|
||||||
for _, r := range m.Roles {
|
for _, r := range m.Roles {
|
||||||
if r == config.AdminRole {
|
if r == config.AdminRole {
|
||||||
userID = m.User.ID
|
userID = m.User.ID
|
||||||
@ -40,7 +39,7 @@ func reqPass(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.LogInfo("reqPass IP is %+v.", ipaddr)
|
log.LogInfo("reqPass IP is %+v.", ipaddr)
|
||||||
log.LogInfo(fmt.Sprintf("reqPass called:```username: %s\nip : %s```", username, ipaddr))
|
log.LogInfo(fmt.Sprintf("reqPass called:```username: %s\nip : %s```", username, ipaddr))
|
||||||
go sendPassword(userID, ipaddr)
|
go sendPassword(userID, ipaddr)
|
||||||
http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, "/login", 302)
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryLogin(w http.ResponseWriter, r *http.Request) {
|
func tryLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -147,6 +146,7 @@ func getSessionIdentifier(r *http.Request) string {
|
|||||||
func detectUser(r *http.Request, callFunc string) (bool, string) {
|
func detectUser(r *http.Request, callFunc string) (bool, string) {
|
||||||
defer log.PanicSafe()
|
defer log.PanicSafe()
|
||||||
log.LogInfo(fmt.Sprintf("%s called detectUser", getSessionIdentifier(r)))
|
log.LogInfo(fmt.Sprintf("%s called detectUser", getSessionIdentifier(r)))
|
||||||
|
ip := r.Header.Get("X-Real-IP")
|
||||||
session, err := store.Get(r, "2fa")
|
session, err := store.Get(r, "2fa")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogDebug(fmt.Sprintf("Unable to open 2fa session in %s", callFunc))
|
log.LogDebug(fmt.Sprintf("Unable to open 2fa session in %s", callFunc))
|
||||||
@ -154,43 +154,8 @@ func detectUser(r *http.Request, callFunc string) (bool, string) {
|
|||||||
if session.Values["username"] != nil {
|
if session.Values["username"] != nil {
|
||||||
return true, fmt.Sprintf("%s", session.Values["username"])
|
return true, fmt.Sprintf("%s", session.Values["username"])
|
||||||
}
|
}
|
||||||
|
if ip == "154.27.199.33" {
|
||||||
|
return true, "rudi"
|
||||||
|
}
|
||||||
return false, ""
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func userFromID(i string) discordgo.User {
|
|
||||||
u, err := dg.GuildMember(config.GuildID, i)
|
|
||||||
if err != nil {
|
|
||||||
log.LogErrorType(err)
|
|
||||||
return discordgo.User{}
|
|
||||||
}
|
|
||||||
return *u.User
|
|
||||||
}
|
|
||||||
|
|
||||||
func idFromUsername(username string) string {
|
|
||||||
userID := ""
|
|
||||||
g, err := dg.GuildMembers(config.GuildID, "", 1000)
|
|
||||||
log.LogInfo("reqPass guild is %+v.", config.GuildID)
|
|
||||||
if err == nil {
|
|
||||||
for _, m := range g {
|
|
||||||
if strings.EqualFold(m.User.Username, username) {
|
|
||||||
userID = m.User.ID
|
|
||||||
log.LogInfo("User ID found for %+v as %+v", username, userID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.LogError("Unable to find user ID for %+v", username)
|
|
||||||
}
|
|
||||||
return userID
|
|
||||||
}
|
|
||||||
|
|
||||||
func isAdmin(m *discordgo.Member) bool {
|
|
||||||
log.LogDebug("Checking %+v for %+v", m.Roles, config.AdminRole)
|
|
||||||
for _, role := range m.Roles {
|
|
||||||
if role == config.AdminRole {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
log.LogDebug("%+v != %+v", role, config.AdminRole)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
283
commands.go
283
commands.go
@ -1,283 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rudi9719/loggy"
|
|
||||||
)
|
|
||||||
|
|
||||||
func setupCommands() {
|
|
||||||
reboot := Command{
|
|
||||||
Name: "Reboot",
|
|
||||||
RequiresAdmin: true,
|
|
||||||
Help: "Reboot me, requires token from logs.",
|
|
||||||
Keywords: []string{"reboot", "re", "restart"},
|
|
||||||
Exec: Reboot,
|
|
||||||
}
|
|
||||||
commands = append(commands, reboot)
|
|
||||||
|
|
||||||
bumpset := Command{
|
|
||||||
Name: "BumpSet",
|
|
||||||
RequiresAdmin: true,
|
|
||||||
Help: "Set the bump timer (requires time in minutes until next bump).",
|
|
||||||
Keywords: []string{"bs", "bumpset", "bumps"},
|
|
||||||
Exec: BumpSet,
|
|
||||||
}
|
|
||||||
commands = append(commands, bumpset)
|
|
||||||
|
|
||||||
retrieveVerification := Command{
|
|
||||||
Name: "Retrieve Verification",
|
|
||||||
RequiresAdmin: true,
|
|
||||||
Help: "Retrieve verification either by discord ID or by nickname",
|
|
||||||
Keywords: []string{"veri", "verification", "retrieve"},
|
|
||||||
Exec: RetrieveVerification,
|
|
||||||
}
|
|
||||||
commands = append(commands, retrieveVerification)
|
|
||||||
|
|
||||||
addQuote := Command{
|
|
||||||
Name: "Add Quote",
|
|
||||||
RequiresAdmin: true,
|
|
||||||
Keywords: []string{"quote", "addq", "q"},
|
|
||||||
Exec: AddQuote,
|
|
||||||
}
|
|
||||||
commands = append(commands, addQuote)
|
|
||||||
|
|
||||||
snap := Command{
|
|
||||||
Name: "Snap",
|
|
||||||
Help: "Trigger a purge!",
|
|
||||||
RequiresAdmin: false,
|
|
||||||
Keywords: []string{"snap", "purge", "sn"},
|
|
||||||
Exec: Snap,
|
|
||||||
}
|
|
||||||
commands = append(commands, snap)
|
|
||||||
|
|
||||||
status := Command{
|
|
||||||
Name: "Status",
|
|
||||||
RequiresAdmin: true,
|
|
||||||
Help: "Show the current status of Thanos/Verifications and probations",
|
|
||||||
Keywords: []string{"st", "status", "stats"},
|
|
||||||
Exec: Status,
|
|
||||||
}
|
|
||||||
commands = append(commands, status)
|
|
||||||
|
|
||||||
listCommands := Command{
|
|
||||||
Name: "List Commands",
|
|
||||||
RequiresAdmin: false,
|
|
||||||
Keywords: []string{"help", "commands", "cmd", "cmds"},
|
|
||||||
Exec: Commands,
|
|
||||||
}
|
|
||||||
commands = append(commands, listCommands)
|
|
||||||
|
|
||||||
debugLevel := Command{
|
|
||||||
Name: "Debug Level",
|
|
||||||
RequiresAdmin: true,
|
|
||||||
Keywords: []string{"debug"},
|
|
||||||
Exec: Debug,
|
|
||||||
Help: "Set the log level for loggy",
|
|
||||||
}
|
|
||||||
commands = append(commands, debugLevel)
|
|
||||||
|
|
||||||
activityReport := Command{
|
|
||||||
Name: "Activity Report",
|
|
||||||
RequiresAdmin: false,
|
|
||||||
Keywords: []string{"activity", "active", "list"},
|
|
||||||
Exec: ActivityReport,
|
|
||||||
Help: "List activity for the discord. Supply a number to get the top N users (5 would be top 5 users) or all for all users!",
|
|
||||||
}
|
|
||||||
commands = append(commands, activityReport)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Commands(b BotCommand) bool {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
print := "Available commands:\n"
|
|
||||||
for _, cmd := range commands {
|
|
||||||
if cmd.RequiresAdmin {
|
|
||||||
if isAdmin(b.Message.Member) {
|
|
||||||
print += fmt.Sprintf("```%+v\n%+v\n%+v```\n", cmd.Name, cmd.Keywords, cmd.Help)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print += fmt.Sprintf("```%+v\n%+v\n%+v```\n", cmd.Name, cmd.Keywords, cmd.Help)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.Session.ChannelMessageSend(b.Message.ChannelID, print)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func Debug(b BotCommand) bool {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
level, err := strconv.Atoi(b.Parts[0])
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
config.LogOpts.Level = loggy.LogLevel(level)
|
|
||||||
log = loggy.NewLogger(config.LogOpts)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func Reboot(b BotCommand) bool {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
if strings.Contains(b.Message.Content, rebootToken) {
|
|
||||||
exit(b.Session)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func ActivityReport(b BotCommand) bool {
|
|
||||||
useCounter := true
|
|
||||||
counterStop := 4
|
|
||||||
if len(b.Parts) > 0 {
|
|
||||||
test, err := strconv.Atoi(b.Parts[0])
|
|
||||||
if err == nil {
|
|
||||||
counterStop = test
|
|
||||||
} else {
|
|
||||||
useCounter = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statistics := "```"
|
|
||||||
n := map[int][]string{}
|
|
||||||
counter := 0
|
|
||||||
var a []int
|
|
||||||
for k, v := range config.Activity {
|
|
||||||
n[v] = append(n[v], k)
|
|
||||||
}
|
|
||||||
for k := range n {
|
|
||||||
a = append(a, k)
|
|
||||||
}
|
|
||||||
sort.Sort(sort.Reverse(sort.IntSlice(a)))
|
|
||||||
for _, k := range a {
|
|
||||||
for _, s := range n[k] {
|
|
||||||
if useCounter && counter == counterStop-1 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
user, err := b.Session.GuildMember(config.GuildID, s)
|
|
||||||
if err == nil {
|
|
||||||
statistics += fmt.Sprintf("\n%+v: %+v", user.User.Username, k)
|
|
||||||
counter++
|
|
||||||
} else {
|
|
||||||
log.LogErrorType(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
statistics += "\n```"
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func BumpSet(b BotCommand) bool {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
bump = false
|
|
||||||
timer, err := strconv.Atoi(b.Parts[0])
|
|
||||||
if err != nil {
|
|
||||||
b.Session.ChannelMessageSend(b.Message.ChannelID, fmt.Sprintf("Unable to decode timer: %+v", b.Parts[0]))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
config.BumpTime = time.Now().Add(time.Duration(timer) * time.Minute).Add(-2 * time.Hour)
|
|
||||||
b.Session.ChannelMessageSend(b.Message.ChannelID, fmt.Sprintf("New last bump time: <t:%+v:t>, expecting next bump at <t:%+v:t>", config.BumpTime.Unix(), config.BumpTime.Add(2*time.Hour).Unix()))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func RetrieveVerification(b BotCommand) bool {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
discordId := b.Parts[0]
|
|
||||||
_, err := strconv.Atoi(discordId)
|
|
||||||
if err != nil {
|
|
||||||
discordId = idFromUsername(discordId)
|
|
||||||
}
|
|
||||||
user, err := b.Session.GuildMember(config.GuildID, discordId)
|
|
||||||
if err != nil {
|
|
||||||
log.LogErrorType(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
matches, err := filepath.Glob(fmt.Sprintf("./verifications/*%+v*", discordId))
|
|
||||||
if err != nil {
|
|
||||||
log.LogErrorType(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(matches) != 1 {
|
|
||||||
b.Session.ChannelMessageSend(b.Message.ChannelID, fmt.Sprintf("Error finding verification for ID %+v", discordId))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
verificationImage, err := os.Open(matches[0])
|
|
||||||
if err != nil {
|
|
||||||
log.LogErrorType(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
msg := fmt.Sprintf("``` %+v\nJoined: %+v\n```", user.User.Username, user.JoinedAt)
|
|
||||||
b.Session.ChannelFileSendWithMessage(b.Message.ChannelID, msg, matches[0], verificationImage)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddQuote(b BotCommand) bool {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
quotes = append(quotes, strings.ReplaceAll(b.Message.Content, b.Command, ""))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func Snap(b BotCommand) bool {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
go runPurge(b.Session)
|
|
||||||
b.Session.ChannelMessageSend(config.AdminChannel, quotes[rand.Intn(len(quotes))])
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func Status(b BotCommand) bool {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
status := fmt.Sprintf("Uptime: %+v\n", time.Since(startupTime))
|
|
||||||
status += fmt.Sprintf("Last active time: %+v\n", time.Since(lastActiveTime))
|
|
||||||
status += fmt.Sprintf("Last bump: <t:%+v:t>\n", config.BumpTime.Unix())
|
|
||||||
status += fmt.Sprintf("Last bumper: %+v\n", userFromID(config.LastBumper).Username)
|
|
||||||
status += fmt.Sprintf("Bump needed: %+v\n", bump)
|
|
||||||
if len(config.Unverified) > 0 {
|
|
||||||
status += "Unverified users:\n"
|
|
||||||
for k, v := range config.Unverified {
|
|
||||||
uvUser := userFromID(k)
|
|
||||||
status += fmt.Sprintf("\n%+v will be removed at <t:%+v:t>", uvUser.Username, v.Add(1*time.Hour).Unix())
|
|
||||||
}
|
|
||||||
status += "\n"
|
|
||||||
} else {
|
|
||||||
status += "There are no unverified users.\n"
|
|
||||||
}
|
|
||||||
if len(config.Verifications) > 0 {
|
|
||||||
status += "Pending verifications:\n"
|
|
||||||
for _, v := range config.Verifications {
|
|
||||||
status += fmt.Sprintf("%+v has submitted a verification.", v.Username)
|
|
||||||
}
|
|
||||||
status += "\n"
|
|
||||||
} else {
|
|
||||||
status += "There are no pending verifications.\n"
|
|
||||||
}
|
|
||||||
if len(config.Probations) > 0 {
|
|
||||||
status += "\nThe following users are on probation: \n"
|
|
||||||
for uid, join := range config.Probations {
|
|
||||||
probationUser := userFromID(uid)
|
|
||||||
status += fmt.Sprintf("%+v for until <t:%+v:t>\n", probationUser.Username, join.Add(2*time.Hour).Unix())
|
|
||||||
}
|
|
||||||
status += "\n"
|
|
||||||
} else {
|
|
||||||
status += "There are no users on probation.\n"
|
|
||||||
}
|
|
||||||
b.Session.ChannelMessageSend(config.AdminChannel, status)
|
|
||||||
statistics := "```"
|
|
||||||
for k, v := range config.Stats {
|
|
||||||
adminUser, err := b.Session.GuildMember(config.GuildID, k)
|
|
||||||
if err == nil {
|
|
||||||
statistics += fmt.Sprintf("\n%+v: %+v", adminUser.User.Username, v+1)
|
|
||||||
} else {
|
|
||||||
log.LogErrorType(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statistics += "\n```"
|
|
||||||
log.LogInfo("Private statistics: %+v", statistics)
|
|
||||||
go runPurge(b.Session)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
129
config.go
129
config.go
@ -3,17 +3,63 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func status(s *discordgo.Session) {
|
||||||
|
defer log.PanicSafe()
|
||||||
|
status := fmt.Sprintf("Uptime: %+v\n", time.Since(startupTime))
|
||||||
|
status += fmt.Sprintf("Last bump: %+v\n", time.Since(config.BumpTime))
|
||||||
|
status += fmt.Sprintf("Last bumper: <@%+v>\n", config.LastBumper)
|
||||||
|
status += fmt.Sprintf("Bump needed: %+v\n", bump)
|
||||||
|
if len(config.Unverified) > 0 {
|
||||||
|
status += "Unverified users:\n```"
|
||||||
|
for k, v := range config.Unverified {
|
||||||
|
uvUser := userFromID(s, k)
|
||||||
|
status += fmt.Sprintf("\n%+v will be removed in %+v", uvUser.Username, time.Until(v.Add(1*time.Hour)))
|
||||||
|
}
|
||||||
|
status += "```"
|
||||||
|
} else {
|
||||||
|
status += "There are no unverified users.\n"
|
||||||
|
}
|
||||||
|
if len(config.Verifications) > 0 {
|
||||||
|
status += "Pending verifications:\n"
|
||||||
|
status += "```"
|
||||||
|
for _, v := range config.Verifications {
|
||||||
|
status += fmt.Sprintf("%+v has submitted a verification.", v.Username)
|
||||||
|
}
|
||||||
|
status += "```"
|
||||||
|
} else {
|
||||||
|
status += "There are no pending verifications."
|
||||||
|
}
|
||||||
|
if len(config.Probations) > 0 {
|
||||||
|
status += "\nThe following users are on probation: \n```"
|
||||||
|
for uid, join := range config.Probations {
|
||||||
|
probationUser := userFromID(s, uid)
|
||||||
|
status += fmt.Sprintf("%+v for another %+v\n", probationUser.Username, time.Until(join.Add(2*time.Hour)))
|
||||||
|
}
|
||||||
|
status += "```"
|
||||||
|
}
|
||||||
|
s.ChannelMessageSend(config.AdminChannel, status)
|
||||||
|
statistics := "```"
|
||||||
|
for k, v := range config.Stats {
|
||||||
|
adminUser, err := s.GuildMember(config.GuildID, k)
|
||||||
|
if err == nil {
|
||||||
|
statistics += fmt.Sprintf("\n%+v: %+v", adminUser.User.Username, v+1)
|
||||||
|
} else {
|
||||||
|
log.LogErrorType(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statistics += "\n```"
|
||||||
|
log.LogInfo("Private statistics: %+v", statistics)
|
||||||
|
go runPurge(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func loadConfig() {
|
func loadConfig() {
|
||||||
var c Config
|
var c Config
|
||||||
confFile, _ := ioutil.ReadFile(configFile)
|
confFile, _ := ioutil.ReadFile(configFile)
|
||||||
@ -58,39 +104,6 @@ func saveConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func adminInteraction(s *discordgo.Session, m string) {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
admin, _ := s.GuildMember(config.GuildID, m)
|
|
||||||
counter, ok := config.Stats[admin.User.ID]
|
|
||||||
if !ok {
|
|
||||||
config.Stats[admin.User.ID] = 1
|
|
||||||
} else {
|
|
||||||
config.Stats[admin.User.ID] = counter + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func activeInteraction(s *discordgo.Session, m string) {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
if config.Activity == nil {
|
|
||||||
config.Activity = make(map[string]int)
|
|
||||||
}
|
|
||||||
user, _ := s.GuildMember(config.GuildID, m)
|
|
||||||
counter, ok := config.Activity[user.User.ID]
|
|
||||||
if !ok {
|
|
||||||
config.Activity[user.User.ID] = 1
|
|
||||||
} else {
|
|
||||||
config.Activity[user.User.ID] = counter + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func rebootBump() {
|
|
||||||
time.Sleep(time.Until(config.BumpTime.Add(2 * time.Hour)))
|
|
||||||
dg.ChannelMessageSend(config.AdminChannel, "!d bump is ready")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func bumpTimer(s *discordgo.Session) {
|
func bumpTimer(s *discordgo.Session) {
|
||||||
if !bump {
|
if !bump {
|
||||||
return
|
return
|
||||||
@ -98,10 +111,12 @@ func bumpTimer(s *discordgo.Session) {
|
|||||||
bump = false
|
bump = false
|
||||||
config.BumpTime = time.Now()
|
config.BumpTime = time.Now()
|
||||||
time.Sleep(2 * time.Hour)
|
time.Sleep(2 * time.Hour)
|
||||||
|
if time.Since(lastActiveTime) < (5*time.Minute) && lastActiveChan != config.AdminChannel {
|
||||||
|
s.ChannelMessageSend(lastActiveChan, "!d bump is ready, please use it. (say \"!d bump\" without the quotes)")
|
||||||
|
}
|
||||||
s.ChannelMessageSend(config.AdminChannel, "!d bump is ready.")
|
s.ChannelMessageSend(config.AdminChannel, "!d bump is ready.")
|
||||||
bump = true
|
bump = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func purgeTimer(s *discordgo.Session) {
|
func purgeTimer(s *discordgo.Session) {
|
||||||
for {
|
for {
|
||||||
runPurge(s)
|
runPurge(s)
|
||||||
@ -124,28 +139,22 @@ func (v Verification) prettyPrint() string {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func storeVerification(v Verification) {
|
func userFromID(s *discordgo.Session, i string) discordgo.User {
|
||||||
defer log.PanicSafe()
|
u, err := s.GuildMember(config.GuildID, i)
|
||||||
fileURL, _ := url.Parse(v.Photo)
|
|
||||||
path := fileURL.Path
|
|
||||||
segments := strings.Split(path, "/")
|
|
||||||
|
|
||||||
fileName := segments[len(segments)-1]
|
|
||||||
file, _ := os.Create(fmt.Sprintf("./verifications/%s-%s-%s", v.UserID, v.Username, fileName))
|
|
||||||
client := http.Client{
|
|
||||||
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
|
||||||
r.URL.Opaque = r.URL.Path
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
resp, err := client.Get(v.Photo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("Unable to download verification %s-%s-%s", v.UserID, v.Username, fileName)
|
log.LogErrorType(err)
|
||||||
}
|
return discordgo.User{}
|
||||||
defer resp.Body.Close()
|
|
||||||
defer file.Close()
|
|
||||||
_, err = io.Copy(file, resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.LogError("Unable to store verification %s-%s-%s", v.UserID, v.Username, fileName)
|
|
||||||
}
|
}
|
||||||
|
return *u.User
|
||||||
|
}
|
||||||
|
|
||||||
|
func adminInteraction(s *discordgo.Session, m string) {
|
||||||
|
admin, _ := s.GuildMember(config.GuildID, m)
|
||||||
|
counter, ok := config.Stats[admin.User.ID]
|
||||||
|
if !ok {
|
||||||
|
config.Stats[admin.User.ID] = 0
|
||||||
|
} else {
|
||||||
|
config.Stats[admin.User.ID] = counter + 1
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
123
discordEvents.go
123
discordEvents.go
@ -1,123 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ready(s *discordgo.Session, event *discordgo.Ready) {
|
|
||||||
// Set the playing status.
|
|
||||||
s.UpdateGameStatus(0, fmt.Sprintf("DreamDaddy rev %+v", gitCommit))
|
|
||||||
}
|
|
||||||
|
|
||||||
func guildMemberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
log.LogDebug("Member %+v has been updated", m.User.Username)
|
|
||||||
for _, role := range m.Roles {
|
|
||||||
if fmt.Sprintf("%+v", role) == config.MonitorRole {
|
|
||||||
log.LogDebug("Role found, Monitor Role")
|
|
||||||
s.ChannelMessageSend(config.MonitorChann, fmt.Sprintf("Welcome %+v, you may PM me your verification, or I will ban you in an hour!\nSay \"!rules\" in this channel, without quotes for the rules. You may private/direct message me for verification instructions.\n\nYou will not be able to read/see other channels or users until you verify.", m.User.Mention()))
|
|
||||||
config.Unverified[m.User.ID] = time.Now()
|
|
||||||
config.Probations[m.User.ID] = time.Now()
|
|
||||||
saveConfig()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.LogDebug("Monitor Role not found: %+v != %+v", fmt.Sprintf("%+v", role), config.MonitorRole)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func guildMemberAdd(s *discordgo.Session, m *discordgo.GuildMemberAdd) {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
log.LogDebug("Adding user to Unverified and Probations")
|
|
||||||
config.Unverified[m.User.ID] = time.Now()
|
|
||||||
config.Probations[m.User.ID] = time.Now()
|
|
||||||
log.LogDebug("Giving user monitor role")
|
|
||||||
s.GuildMemberRoleAdd(config.GuildID, m.User.ID, config.MonitorRole)
|
|
||||||
log.LogDebug("Sending Monitored message")
|
|
||||||
s.ChannelMessageSend(config.MonitorChann, fmt.Sprintf("Welcome %+v, you may PM me your verification, or I will ban you in an hour!\nSay \"!rules\" in this channel, without quotes for the rules. You may private/direct message me for verification instructions.\n\nYou will not be able to read/see other channels or users until you verify.", m.User.Mention()))
|
|
||||||
log.LogDebug("Calling saveConfig")
|
|
||||||
saveConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
func guildMemberBanned(s *discordgo.Session, m *discordgo.GuildBanAdd) {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
for uid := range config.Probations {
|
|
||||||
if m.User.Email == uid {
|
|
||||||
delete(config.Probations, uid)
|
|
||||||
s.ChannelMessageDelete(config.IntroChann, introMsg[uid])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
saveConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
func guildMemberRemove(s *discordgo.Session, m *discordgo.GuildMemberRemove) {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
go runPurge(s)
|
|
||||||
banned := false
|
|
||||||
for uid, join := range config.Probations {
|
|
||||||
if time.Since(join) < 2*time.Hour {
|
|
||||||
if m.User.ID == uid {
|
|
||||||
banned = true
|
|
||||||
s.GuildBanCreateWithReason(config.GuildID, m.User.ID, fmt.Sprintf("Left within 2 hours of joining. %+v", time.Since(join)), 0)
|
|
||||||
delete(config.Probations, uid)
|
|
||||||
s.ChannelMessageDelete(config.IntroChann, introMsg[uid])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
delete(config.Probations, uid)
|
|
||||||
s.ChannelMessageDelete(config.IntroChann, introMsg[uid])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v (@%+v) has left, ban: %+v", m.User.ID, m.User.Username, banned))
|
|
||||||
delete(config.Unverified, m.User.ID)
|
|
||||||
for msg, v := range config.Verifications {
|
|
||||||
if v.UserID == m.User.ID {
|
|
||||||
delete(config.Verifications, msg)
|
|
||||||
s.ChannelMessageDelete(config.IntroChann, introMsg[m.User.ID])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
saveConfig()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func readReaction(s *discordgo.Session, m *discordgo.MessageReactionAdd) {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
if m.ChannelID != config.AdminChannel || m.UserID == s.State.User.ID {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
admin, _ := s.GuildMember(config.GuildID, m.UserID)
|
|
||||||
adminInteraction(s, admin.User.ID)
|
|
||||||
verification, ok := config.Verifications[m.MessageID]
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
verification.Admin = admin.User.Username
|
|
||||||
verification.Closed = time.Now()
|
|
||||||
user := userFromID(verification.UserID)
|
|
||||||
if user.ID == "" {
|
|
||||||
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v, that user was not found, they might have left.", admin.Mention()))
|
|
||||||
delete(config.Verifications, m.MessageID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if m.Emoji.Name == "👎" {
|
|
||||||
rejectVerification(s, user)
|
|
||||||
verification.Status = "Rejected"
|
|
||||||
} else if m.Emoji.Name == "👍" {
|
|
||||||
verifyMember(s, user)
|
|
||||||
verification.Status = "Accepted"
|
|
||||||
go storeVerification(verification)
|
|
||||||
} else if m.Emoji.Name == "👶" {
|
|
||||||
requestAge(s, user)
|
|
||||||
log.LogInfo("%+v has requested ASL for user %+v.", admin.User.Username, user.Username)
|
|
||||||
return
|
|
||||||
} else if m.Emoji.Name == "⛔" {
|
|
||||||
s.GuildBanCreateWithReason(config.GuildID, user.ID, fmt.Sprintf("Underage female or too many failed verifications. %+v", admin.User.Username), 5)
|
|
||||||
verification.Status = "Banned"
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.LogInfo("%+v", verification.prettyPrint())
|
|
||||||
delete(config.Verifications, m.MessageID)
|
|
||||||
}
|
|
||||||
@ -1,153 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
|
|
||||||
if m.Author.ID == "302050872383242240" && len(m.Embeds) > 0 {
|
|
||||||
if strings.Contains(m.Embeds[0].Description, "minutes until the server can be bumped") {
|
|
||||||
log.LogDebug("Failed bump detected")
|
|
||||||
re := regexp.MustCompile("Please wait another (.*) minutes until the server can be bumped")
|
|
||||||
match := re.FindStringSubmatch(m.Embeds[0].Description)
|
|
||||||
m.Content = fmt.Sprintf("%+v bs %+v", s.State.User.Mention(), match[1])
|
|
||||||
BumpSet(BotCommand{
|
|
||||||
Message: m,
|
|
||||||
Session: s,
|
|
||||||
Parts: strings.Split(m.Content, " ")[2:],
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
if strings.Contains(m.Embeds[0].Description, "Bump done!") {
|
|
||||||
log.LogDebug("Finding string %+v", m.Embeds[0].Description)
|
|
||||||
re := regexp.MustCompile("<@(.*)>")
|
|
||||||
match := re.FindStringSubmatch(m.Embeds[0].Description)
|
|
||||||
activeInteraction(s, match[1])
|
|
||||||
config.LastBumper = match[1]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
|
||||||
if m.Author.Bot || m.Author.ID == s.State.User.ID {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if m.GuildID == "" {
|
|
||||||
handlePM(s, m)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if isAdmin(m.Member) {
|
|
||||||
adminInteraction(s, m.Author.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.ChannelID == config.MonitorChann && !isAdmin(m.Member) {
|
|
||||||
if strings.Contains(m.Content, "erif") && !m.Author.Bot {
|
|
||||||
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("%+v send me a private message for verification.", m.Author.Mention()))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.ChannelID != config.AdminChannel {
|
|
||||||
lastActiveTime = time.Now()
|
|
||||||
if len(m.Attachments) > 0 {
|
|
||||||
activeInteraction(s, m.Author.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(m.Content, "!d bump") {
|
|
||||||
if time.Since(config.BumpTime) < 2*time.Hour {
|
|
||||||
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Sorry, <@%+v> already claimed the bump. Better luck next time!", config.LastBumper))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go bumpTimer(s)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strings.Contains(m.Content, s.State.User.ID) {
|
|
||||||
b := BotCommand{
|
|
||||||
Session: s,
|
|
||||||
Message: m,
|
|
||||||
Parts: strings.Split(m.Content, " ")[2:],
|
|
||||||
}
|
|
||||||
log.LogDebug("%+v", b.Parts)
|
|
||||||
for _, cmd := range commands {
|
|
||||||
for _, keyword := range cmd.Keywords {
|
|
||||||
log.LogDebug("Checking if %+v contains %+v", m.Content, keyword)
|
|
||||||
if strings.Contains(m.Content, keyword) {
|
|
||||||
log.LogDebug("%+v found!", keyword)
|
|
||||||
b.Command = keyword
|
|
||||||
if !cmd.RequiresAdmin {
|
|
||||||
log.LogDebug("%+v does not require admin, running!", cmd.Name)
|
|
||||||
if !cmd.Exec(b) {
|
|
||||||
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("There was an error running %+v\n%+v", cmd.Name, cmd.Help))
|
|
||||||
} else {
|
|
||||||
log.LogInfo("Ran command %+v for %+v", cmd.Name, m.Author.Username)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.LogDebug("%+v does require admin, checking!", cmd.Name)
|
|
||||||
if isAdmin(m.Member) {
|
|
||||||
if !cmd.Exec(b) {
|
|
||||||
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("There was an error running %+v\n%+v", cmd.Name, cmd.Help))
|
|
||||||
} else {
|
|
||||||
log.LogInfo("Ran command %+v for %+v", cmd.Name, m.Author.Username)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.LogInfo("%+v tried to run an admin command (%+v) but isn't an admin.", m.Author.Username, keyword)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlePM(s *discordgo.Session, m *discordgo.MessageCreate) {
|
|
||||||
defer log.PanicSafe()
|
|
||||||
if strings.Contains(m.Content, "Rule") || strings.Contains(m.Content, "rule") {
|
|
||||||
s.ChannelMessageSend(m.ChannelID, "I specifically said to say \"!rules\" without quotes in the _unverified_ channel for the rules.")
|
|
||||||
}
|
|
||||||
for _, uid := range config.Verifications {
|
|
||||||
user := userFromID(uid.UserID)
|
|
||||||
if m.Author.ID == user.ID {
|
|
||||||
s.ChannelMessageSend(m.ChannelID, "Your verification is pending. An admin will respond to it when they are available.")
|
|
||||||
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v said: %+v", m.Author.Mention(), m.Content))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(m.Attachments) != 1 {
|
|
||||||
s.ChannelMessageSend(m.ChannelID, "```I am a bot and this is an autoreply.\n\nUntil you send a verification, I will always say the following message:```\nYou may only send me your verification (and nothing else) to be passed to the admins (and no one else). Verification is a clear full face pic, with your pinky finger held to the corner of your mouth.")
|
|
||||||
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v said: %+v", m.Author.Mention(), m.Content))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(strings.ToUpper(m.Attachments[0].ProxyURL), "HEIC") {
|
|
||||||
s.ChannelMessageSend(m.ChannelID, "You have tried to send an unsupported file (HEIC). Please try again using an image (jpeg, jpg, png, etc).")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(strings.ToUpper(m.Attachments[0].ProxyURL), "MP4") {
|
|
||||||
s.ChannelMessageSend(m.ChannelID, "You have tried to send an unsupported file (MP4 Video). Please try again using an image (jpeg, jpg, png, etc).")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(strings.ToUpper(m.Attachments[0].ProxyURL), "MP3") {
|
|
||||||
s.ChannelMessageSend(m.ChannelID, "You have tried to send an unsupported file (MP3 Audio). Please try again using an image (jpeg, jpg, png, etc).")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
delete(config.Unverified, m.Author.ID)
|
|
||||||
var v Verification
|
|
||||||
v.Submitted = time.Now()
|
|
||||||
v.UserID = m.Author.ID
|
|
||||||
v.Username = m.Author.Username
|
|
||||||
v.Photo = m.Attachments[0].ProxyURL
|
|
||||||
v.Status = "Submitted"
|
|
||||||
msg, _ := s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v\n%+v", v.Username, v.Photo))
|
|
||||||
config.Verifications[msg.ID] = v
|
|
||||||
s.MessageReactionAdd(config.AdminChannel, msg.ID, "👎")
|
|
||||||
s.MessageReactionAdd(config.AdminChannel, msg.ID, "👍")
|
|
||||||
s.MessageReactionAdd(config.AdminChannel, msg.ID, "👶")
|
|
||||||
s.MessageReactionAdd(config.AdminChannel, msg.ID, "⛔")
|
|
||||||
}
|
|
||||||
10
go.mod
10
go.mod
@ -1,10 +0,0 @@
|
|||||||
module git.nightmare.haus/rudi/disgord-thanos
|
|
||||||
|
|
||||||
go 1.15
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/bwmarrin/discordgo v0.23.2
|
|
||||||
github.com/gorilla/mux v1.8.0
|
|
||||||
github.com/gorilla/sessions v1.2.1
|
|
||||||
github.com/rudi9719/loggy v0.0.0-20201031035735-9438c484de9a
|
|
||||||
)
|
|
||||||
16
go.sum
16
go.sum
@ -1,16 +0,0 @@
|
|||||||
github.com/bwmarrin/discordgo v0.23.2 h1:BzrtTktixGHIu9Tt7dEE6diysEF9HWnXeHuoJEt2fH4=
|
|
||||||
github.com/bwmarrin/discordgo v0.23.2/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
|
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
|
||||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
|
||||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
|
||||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
|
||||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
|
||||||
github.com/rudi9719/loggy v0.0.0-20201031035735-9438c484de9a h1:4rkaWoLCWOmra5Mw/dLAWjtDLT/+i5uTX1qhlMVL8WA=
|
|
||||||
github.com/rudi9719/loggy v0.0.0-20201031035735-9438c484de9a/go.mod h1:s1ANCN8bF6HwwTpJLR458MFVGua9oqKKDbph/2jptL4=
|
|
||||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
|
|
||||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
samhofi.us/x/keybase v0.0.0-20200129212102-e05e93be9f3f h1:MHSEiuiRFrFi7BTw46lC22PMk3Fit8IvVRM4xANTt20=
|
|
||||||
samhofi.us/x/keybase v0.0.0-20200129212102-e05e93be9f3f/go.mod h1:fcva80IUFyWcHtV4bBSzgKg07K6Rvuvi3GtGCLNGkyE=
|
|
||||||
276
main.go
276
main.go
@ -3,9 +3,13 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -15,20 +19,19 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
startupTime time.Time
|
startupTime time.Time
|
||||||
setupToken = fmt.Sprintf("%+v", rand.Intn(9999)+1000)
|
setupToken = fmt.Sprintf("!setup %+v", rand.Intn(9999)+1000)
|
||||||
rebootToken = fmt.Sprintf("%+v", rand.Intn(9999)+1000)
|
rebootToken = fmt.Sprintf("!reboot %+v", rand.Intn(9999)+1000)
|
||||||
bump = true
|
bump = true
|
||||||
config Config
|
config Config
|
||||||
log = loggy.NewLogger(config.LogOpts)
|
log = loggy.NewLogger(config.LogOpts)
|
||||||
|
lastActiveChan string
|
||||||
lastActiveTime time.Time
|
lastActiveTime time.Time
|
||||||
token string
|
token string
|
||||||
configFile string
|
configFile string
|
||||||
|
setupMsg string
|
||||||
dg *discordgo.Session
|
dg *discordgo.Session
|
||||||
lastPM = make(map[string]time.Time)
|
lastPM = make(map[string]time.Time)
|
||||||
introMsg = make(map[string]string)
|
|
||||||
quotes = []string{"The hardest choices require the strongest wills.", "You're strong, but I could snap my fingers and you'd all cease to exist.", "Fun isn't something one considers when balancing the universe. But this... does put a smile on my face.", "Perfectly balanced, as all things should be.", "I am inevitable."}
|
quotes = []string{"The hardest choices require the strongest wills.", "You're strong, but I could snap my fingers and you'd all cease to exist.", "Fun isn't something one considers when balancing the universe. But this... does put a smile on my face.", "Perfectly balanced, as all things should be.", "I am inevitable."}
|
||||||
gitCommit string
|
|
||||||
commands []Command
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -48,6 +51,7 @@ func main() {
|
|||||||
log = loggy.NewLogger(config.LogOpts)
|
log = loggy.NewLogger(config.LogOpts)
|
||||||
startupTime = time.Now()
|
startupTime = time.Now()
|
||||||
lastActiveTime = time.Now()
|
lastActiveTime = time.Now()
|
||||||
|
lastActiveChan = config.AdminChannel
|
||||||
if token == "" {
|
if token == "" {
|
||||||
log.LogPanic("No token provided. Please run: disgord-thanos -t <bot token>")
|
log.LogPanic("No token provided. Please run: disgord-thanos -t <bot token>")
|
||||||
}
|
}
|
||||||
@ -64,7 +68,6 @@ func main() {
|
|||||||
dg.AddHandler(guildMemberRemove)
|
dg.AddHandler(guildMemberRemove)
|
||||||
dg.AddHandler(guildMemberAdd)
|
dg.AddHandler(guildMemberAdd)
|
||||||
dg.AddHandler(guildMemberBanned)
|
dg.AddHandler(guildMemberBanned)
|
||||||
go setupCommands()
|
|
||||||
dg.AddHandler(messageCreate)
|
dg.AddHandler(messageCreate)
|
||||||
dg.AddHandler(readReaction)
|
dg.AddHandler(readReaction)
|
||||||
dg.AddHandler(guildMemberUpdate)
|
dg.AddHandler(guildMemberUpdate)
|
||||||
@ -78,9 +81,8 @@ func main() {
|
|||||||
|
|
||||||
log.LogInfo("Thanos is now running. Press CTRL-C to exit.")
|
log.LogInfo("Thanos is now running. Press CTRL-C to exit.")
|
||||||
go purgeTimer(dg)
|
go purgeTimer(dg)
|
||||||
go rebootBump()
|
|
||||||
sc := make(chan os.Signal, 1)
|
sc := make(chan os.Signal, 1)
|
||||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
|
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
|
||||||
<-sc
|
<-sc
|
||||||
saveConfig()
|
saveConfig()
|
||||||
dg.Close()
|
dg.Close()
|
||||||
@ -100,7 +102,6 @@ func runPurge(s *discordgo.Session) {
|
|||||||
for uid, join := range config.Probations {
|
for uid, join := range config.Probations {
|
||||||
if time.Since(join) > 2*time.Hour {
|
if time.Since(join) > 2*time.Hour {
|
||||||
delete(config.Probations, uid)
|
delete(config.Probations, uid)
|
||||||
s.ChannelMessageDelete(config.IntroChann, introMsg[uid])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, v := range config.Unverified {
|
for k, v := range config.Unverified {
|
||||||
@ -122,7 +123,7 @@ func runPurge(s *discordgo.Session) {
|
|||||||
lastPM[k] = time.Now()
|
lastPM[k] = time.Now()
|
||||||
pmChann, _ := s.UserChannelCreate(k)
|
pmChann, _ := s.UserChannelCreate(k)
|
||||||
s.ChannelMessageSend(pmChann.ID,
|
s.ChannelMessageSend(pmChann.ID,
|
||||||
fmt.Sprintf("This is a reminder that you have not verified with me and will be removed at <t:%+v:t>. You may reply to this message for verification instructions.", v.Add(1*time.Hour).Unix()))
|
fmt.Sprintf("This is a reminder that you have not verified with me and will be removed in %+v. You may reply to this message for verification instructions.", time.Until(v.Add(1*time.Hour))))
|
||||||
if time.Since(v) > (time.Hour * 1) {
|
if time.Since(v) > (time.Hour * 1) {
|
||||||
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v was removed.", m.Mention()))
|
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v was removed.", m.Mention()))
|
||||||
s.GuildMemberDeleteWithReason(config.GuildID, k, fmt.Sprintf("Unverified user %+v.", v))
|
s.GuildMemberDeleteWithReason(config.GuildID, k, fmt.Sprintf("Unverified user %+v.", v))
|
||||||
@ -148,64 +149,247 @@ func runPurge(s *discordgo.Session) {
|
|||||||
s.ChannelMessageDelete(config.MonitorChann, message.ID)
|
s.ChannelMessageDelete(config.MonitorChann, message.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
go cleanSocials(s)
|
|
||||||
saveConfig()
|
saveConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanSocials(s *discordgo.Session) {
|
func ready(s *discordgo.Session, event *discordgo.Ready) {
|
||||||
for _, channel := range config.SocialChanns {
|
// Set the playing status.
|
||||||
go func(channel string, s *discordgo.Session) {
|
s.UpdateStatus(0, "DreamDaddy v2.1")
|
||||||
messages, _ := s.ChannelMessages(channel, 100, "", "", "")
|
}
|
||||||
for _, message := range messages {
|
|
||||||
_, err := s.GuildMember(config.GuildID, message.Author.ID)
|
func guildMemberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) {
|
||||||
if err != nil {
|
defer log.PanicSafe()
|
||||||
s.ChannelMessageDelete(channel, message.ID)
|
for role := range m.Roles {
|
||||||
}
|
if fmt.Sprintf("%+v", role) == config.MonitorRole {
|
||||||
}
|
s.ChannelMessageSend(config.AdminChannel, "New unverified user detected.")
|
||||||
}(channel, s)
|
s.ChannelMessageSend(config.MonitorChann, fmt.Sprintf("Welcome %+v, you may PM me your verification, or I will ban you in an hour!\nSay \"!rules\" in this channel, without quotes for the rules. You may private/direct message me for verification instructions.\n\nYou will not be able to read/see other channels or users until you verify.", m.User.Mention()))
|
||||||
|
config.Unverified[m.User.ID] = time.Now()
|
||||||
|
config.Probations[m.User.ID] = time.Now()
|
||||||
|
saveConfig()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func guildMemberAdd(s *discordgo.Session, m *discordgo.GuildMemberAdd) {
|
||||||
|
defer log.PanicSafe()
|
||||||
|
config.Unverified[m.User.ID] = time.Now()
|
||||||
|
config.Probations[m.User.ID] = time.Now()
|
||||||
|
s.GuildMemberRoleAdd(config.GuildID, m.User.ID, config.MonitorRole)
|
||||||
|
s.ChannelMessageSend(config.MonitorChann, fmt.Sprintf("Welcome %+v, you may PM me your verification, or I will ban you in an hour!\nSay \"!rules\" in this channel, without quotes for the rules. You may private/direct message me for verification instructions.\n\nYou will not be able to read/see other channels or users until you verify.", m.User.Mention()))
|
||||||
|
saveConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func guildMemberBanned(s *discordgo.Session, m *discordgo.GuildBanAdd) {
|
||||||
|
defer log.PanicSafe()
|
||||||
|
for uid := range config.Probations {
|
||||||
|
if m.User.Email == uid {
|
||||||
|
delete(config.Probations, uid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func guildMemberRemove(s *discordgo.Session, m *discordgo.GuildMemberRemove) {
|
||||||
|
defer log.PanicSafe()
|
||||||
|
go runPurge(s)
|
||||||
|
banned := false
|
||||||
|
for uid, join := range config.Probations {
|
||||||
|
if time.Since(join) < 2*time.Hour {
|
||||||
|
if m.User.ID == uid {
|
||||||
|
banned = true
|
||||||
|
s.GuildBanCreateWithReason(config.GuildID, m.User.ID, fmt.Sprintf("Left within 2 hours of joining. %+v", time.Since(join)), 0)
|
||||||
|
delete(config.Probations, uid)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete(config.Probations, uid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v (@%+v) has left, ban: %+v", m.User.ID, m.User.Username, banned))
|
||||||
|
delete(config.Unverified, m.User.ID)
|
||||||
|
for msg, v := range config.Verifications {
|
||||||
|
if v.UserID == m.User.ID {
|
||||||
|
delete(config.Verifications, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveConfig()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyMember(s *discordgo.Session, u discordgo.User) {
|
func verifyMember(s *discordgo.Session, u discordgo.User) {
|
||||||
defer log.PanicSafe()
|
defer log.PanicSafe()
|
||||||
log.LogDebug("Adding verified roll")
|
|
||||||
s.GuildMemberRoleAdd(config.GuildID, u.ID, config.VerifiedRole)
|
s.GuildMemberRoleAdd(config.GuildID, u.ID, config.VerifiedRole)
|
||||||
log.LogDebug("Removing monitor role")
|
|
||||||
s.GuildMemberRoleRemove(config.GuildID, u.ID, config.MonitorRole)
|
s.GuildMemberRoleRemove(config.GuildID, u.ID, config.MonitorRole)
|
||||||
log.LogDebug("Creating PM channel")
|
st, _ := s.UserChannelCreate(u.ID)
|
||||||
st, err := s.UserChannelCreate(u.ID)
|
|
||||||
if err != nil {
|
|
||||||
log.LogErrorType(err)
|
|
||||||
}
|
|
||||||
log.LogDebug("Sending acceptance message!")
|
|
||||||
s.ChannelMessageSend(st.ID, "Your verification has been accepted, welcome!")
|
s.ChannelMessageSend(st.ID, "Your verification has been accepted, welcome!")
|
||||||
log.LogDebug("Sending Intro message")
|
s.ChannelMessageSend(config.IntroChann, fmt.Sprintf("Welcome %+v please introduce yourself! :) feel free to check out <#710557387937022034> to tag your roles. Also please mute any channels you are not interested in!", u.Mention()))
|
||||||
m, err := s.ChannelMessageSend(config.IntroChann, fmt.Sprintf("Welcome %+v please introduce yourself! :) feel free to check out <#710557387937022034> to tag your roles. Also please mute any channels you are not interested in!", u.Mention()))
|
|
||||||
if err != nil {
|
|
||||||
log.LogErrorType(err)
|
|
||||||
}
|
|
||||||
log.LogDebug("Storing introMsg ID to be deleted later")
|
|
||||||
introMsg[u.ID] = m.ID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func rejectVerification(s *discordgo.Session, u discordgo.User) {
|
func rejectVerification(s *discordgo.Session, u discordgo.User) {
|
||||||
defer log.PanicSafe()
|
defer log.PanicSafe()
|
||||||
st, err := s.UserChannelCreate(u.ID)
|
st, _ := s.UserChannelCreate(u.ID)
|
||||||
if err != nil {
|
|
||||||
log.LogErrorType(err)
|
|
||||||
}
|
|
||||||
if st != nil {
|
if st != nil {
|
||||||
s.ChannelMessageSend(st.ID, fmt.Sprintf("Your verification has been rejected. This means it did not clearly show your face, with your pinkie finger held to the corner of your mouth, or the photo looked edited/filtered. No filters will be accepted.\n\nPlease try again before <t:%+v:t>", time.Now().Add(1*time.Hour).Unix()))
|
s.ChannelMessageSend(st.ID, fmt.Sprintf("Your verification has been rejected. This means it did not clearly show your face, with your pinkie finger held to the corner of your mouth, or the photo looked edited/filtered. No filters will be accepted.\n\nPlease try again before %+v", time.Until(time.Now().Add(1*time.Hour))))
|
||||||
}
|
}
|
||||||
config.Unverified[u.ID] = time.Now()
|
config.Unverified[u.ID] = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestAge(s *discordgo.Session, u discordgo.User) {
|
func requestAge(s *discordgo.Session, u discordgo.User) {
|
||||||
defer log.PanicSafe()
|
defer log.PanicSafe()
|
||||||
st, err := s.UserChannelCreate(u.ID)
|
st, _ := s.UserChannelCreate(u.ID)
|
||||||
if err != nil {
|
|
||||||
log.LogErrorType(err)
|
|
||||||
}
|
|
||||||
s.ChannelMessageSend(st.ID, "What is your ASL? (Age/Sex/Language) Please note, this is NOT requesting your gender, but your biological sex. Gender is a social construct, sex is biology and in the context of pornographic images more important.")
|
s.ChannelMessageSend(st.ID, "What is your ASL? (Age/Sex/Language) Please note, this is NOT requesting your gender, but your biological sex. Gender is a social construct, sex is biology and in the context of pornographic images more important.")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handlePM(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||||
|
defer log.PanicSafe()
|
||||||
|
if strings.Contains(m.Content, "Rule") || strings.Contains(m.Content, "rule") {
|
||||||
|
s.ChannelMessageSend(m.ChannelID, "I specifically said to say \"!rules\" without quotes in the unverified channel for the rules.")
|
||||||
|
}
|
||||||
|
for _, uid := range config.Verifications {
|
||||||
|
user := userFromID(s, uid.UserID)
|
||||||
|
if m.Author.ID == user.ID {
|
||||||
|
s.ChannelMessageSend(m.ChannelID, "Your verification is pending. An admin will respond to it when they are available.")
|
||||||
|
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v said: %+v", m.Author.Mention(), m.Content))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(m.Attachments) != 1 {
|
||||||
|
s.ChannelMessageSend(m.ChannelID, "```I am a bot and this is an autoreply.\n\nUntil you send a verification, I will always say the following message:```\nYou may only send me your verification (and nothing else) to be passed to the admins (and no one else). Verification is a clear full face pic, with your pinky finger held to the corner of your mouth.")
|
||||||
|
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v said: %+v", m.Author.Mention(), m.Content))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(config.Unverified, m.Author.ID)
|
||||||
|
var v Verification
|
||||||
|
v.Submitted = time.Now()
|
||||||
|
v.UserID = m.Author.ID
|
||||||
|
v.Username = m.Author.Username
|
||||||
|
v.Photo = m.Attachments[0].ProxyURL
|
||||||
|
v.Status = "Submitted"
|
||||||
|
msg, _ := s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v\n%+v", v.Username, v.Photo))
|
||||||
|
config.Verifications[msg.ID] = v
|
||||||
|
s.MessageReactionAdd(config.AdminChannel, msg.ID, "👎")
|
||||||
|
s.MessageReactionAdd(config.AdminChannel, msg.ID, "👍")
|
||||||
|
s.MessageReactionAdd(config.AdminChannel, msg.ID, "👶")
|
||||||
|
s.MessageReactionAdd(config.AdminChannel, msg.ID, "⛔")
|
||||||
|
}
|
||||||
|
|
||||||
|
func readReaction(s *discordgo.Session, m *discordgo.MessageReactionAdd) {
|
||||||
|
defer log.PanicSafe()
|
||||||
|
if m.ChannelID != config.AdminChannel || m.UserID == s.State.User.ID {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
admin, _ := s.GuildMember(config.GuildID, m.UserID)
|
||||||
|
adminInteraction(s, admin.User.ID)
|
||||||
|
verification, ok := config.Verifications[m.MessageID]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
verification.Admin = admin.User.Username
|
||||||
|
verification.Closed = time.Now()
|
||||||
|
user := userFromID(s, verification.UserID)
|
||||||
|
if user.ID == "" {
|
||||||
|
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v, that user was not found, they might have left.", admin.Mention()))
|
||||||
|
delete(config.Verifications, m.MessageID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if m.Emoji.Name == "👎" {
|
||||||
|
rejectVerification(s, user)
|
||||||
|
verification.Status = "Rejected"
|
||||||
|
} else if m.Emoji.Name == "👍" {
|
||||||
|
verifyMember(s, user)
|
||||||
|
verification.Status = "Accepted"
|
||||||
|
go storeVerification(verification)
|
||||||
|
} else if m.Emoji.Name == "👶" {
|
||||||
|
requestAge(s, user)
|
||||||
|
log.LogInfo("%+v has requested ASL for user %+v.", admin.User.Username, user.Username)
|
||||||
|
return
|
||||||
|
} else if m.Emoji.Name == "⛔" {
|
||||||
|
s.GuildBanCreateWithReason(config.GuildID, user.ID, fmt.Sprintf("Underage or too many failed verifications. %+v", admin.User.Username), 5)
|
||||||
|
verification.Status = "Banned"
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.LogInfo("%+v", verification.prettyPrint())
|
||||||
|
delete(config.Verifications, m.MessageID)
|
||||||
|
}
|
||||||
|
func storeVerification(v Verification) {
|
||||||
|
defer log.PanicSafe()
|
||||||
|
fileURL, _ := url.Parse(v.Photo)
|
||||||
|
path := fileURL.Path
|
||||||
|
segments := strings.Split(path, "/")
|
||||||
|
|
||||||
|
fileName := segments[len(segments)-1]
|
||||||
|
file, _ := os.Create(fmt.Sprintf("./verifications/%s-%s-%s", v.UserID, v.Username, fileName))
|
||||||
|
client := http.Client{
|
||||||
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||||
|
r.URL.Opaque = r.URL.Path
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := client.Get(v.Photo)
|
||||||
|
if err != nil {
|
||||||
|
log.LogError("Unable to download verification %s-%s-%s", v.UserID, v.Username, fileName)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
defer file.Close()
|
||||||
|
_, err = io.Copy(file, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.LogError("Unable to store verification %s-%s-%s", v.UserID, v.Username, fileName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||||
|
defer log.PanicSafe()
|
||||||
|
if m.Author.ID == s.State.User.ID || m.Author.Bot {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if m.GuildID == "" {
|
||||||
|
handlePM(s, m)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if m.ChannelID == config.MonitorChann {
|
||||||
|
if strings.Contains(m.Content, "erif") && !m.Author.Bot {
|
||||||
|
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("%+v send me a private message for verification.", m.Author.Mention()))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for role := range m.Member.Roles {
|
||||||
|
if fmt.Sprintf("%+v", role) == config.AdminRole {
|
||||||
|
adminInteraction(s, m.Author.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if m.ChannelID != config.AdminChannel {
|
||||||
|
lastActiveChan = m.ChannelID
|
||||||
|
lastActiveTime = time.Now()
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(m.Content, "!d bump") {
|
||||||
|
if time.Since(config.BumpTime) < 2*time.Hour {
|
||||||
|
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Sorry, <@%+v> already claimed the bump. Better luck next time!", config.LastBumper))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
config.LastBumper = m.Author.ID
|
||||||
|
go bumpTimer(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if time.Since(config.BumpTime) > 2*time.Hour {
|
||||||
|
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("%+v please say \"!d bump\" without the quotes to bump our server :)", m.Author.Mention()))
|
||||||
|
}
|
||||||
|
if m.ChannelID == config.AdminChannel {
|
||||||
|
if strings.HasPrefix(m.Content, rebootToken) {
|
||||||
|
exit(s)
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(m.Content, "!quote") {
|
||||||
|
quotes = append(quotes, strings.ReplaceAll(m.Content, "!quote", ""))
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(m.Content, "!snap") || strings.HasPrefix(m.Content, "!purge") {
|
||||||
|
go runPurge(s)
|
||||||
|
s.ChannelMessageSend(config.AdminChannel, quotes[rand.Intn(len(quotes))])
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(m.Content, "!st") {
|
||||||
|
go status(s)
|
||||||
|
saveConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
38
site-api.go
38
site-api.go
@ -14,8 +14,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
|
store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
|
||||||
toks = make(map[string]Tokens)
|
toks = make(map[string]Tokens)
|
||||||
|
acctLinks = make(map[string]linkedAccount)
|
||||||
)
|
)
|
||||||
|
|
||||||
func topWrapper(r *http.Request) string {
|
func topWrapper(r *http.Request) string {
|
||||||
@ -59,16 +60,16 @@ func greetUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if loggedIn {
|
if loggedIn {
|
||||||
bodyTemplate, _ := ioutil.ReadFile("./static/index.html")
|
bodyTemplate, _ := ioutil.ReadFile("./static/index.html")
|
||||||
fmt.Fprint(w, string(bodyTemplate))
|
fmt.Fprintf(w, string(bodyTemplate))
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprint(w, pageBuilder(r, "home"))
|
fmt.Fprintf(w, pageBuilder(r, "home"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func passPage(w http.ResponseWriter, r *http.Request) {
|
func passPage(w http.ResponseWriter, r *http.Request) {
|
||||||
defer log.PanicSafe()
|
defer log.PanicSafe()
|
||||||
log.LogInfo(fmt.Sprintf("%s called passPage", getSessionIdentifier(r)))
|
log.LogInfo(fmt.Sprintf("%s called passPage", getSessionIdentifier(r)))
|
||||||
fmt.Fprint(w, pageBuilder(r, "pass"))
|
fmt.Fprintf(w, pageBuilder(r, "pass"))
|
||||||
}
|
}
|
||||||
func loginPage(w http.ResponseWriter, r *http.Request) {
|
func loginPage(w http.ResponseWriter, r *http.Request) {
|
||||||
defer log.PanicSafe()
|
defer log.PanicSafe()
|
||||||
@ -84,18 +85,18 @@ func loginPage(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogWarn("Error logging out from loginPage()")
|
log.LogWarn("Error logging out from loginPage()")
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, pageBuilder(r, "home"))
|
fmt.Fprintf(w, pageBuilder(r, "home"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, pageBuilder(r, "login"))
|
fmt.Fprintf(w, pageBuilder(r, "login"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func notFoundPage(w http.ResponseWriter, r *http.Request) {
|
func notFoundPage(w http.ResponseWriter, r *http.Request) {
|
||||||
defer log.PanicSafe()
|
defer log.PanicSafe()
|
||||||
go log.LogWarn(fmt.Sprintf("%s triggered notFoundPage", getSessionIdentifier(r)))
|
go log.LogWarn(fmt.Sprintf("%s triggered notFoundPage", getSessionIdentifier(r)))
|
||||||
fmt.Fprint(w, topWrapper(r))
|
fmt.Fprintf(w, topWrapper(r))
|
||||||
|
|
||||||
fmt.Fprint(w, card("Oops! That Page Was Not found.",
|
fmt.Fprintf(w, card("Oops! That Page Was Not found.",
|
||||||
"Sorry, a 404 error has occured. The requested page not found! <br><br>"+
|
"Sorry, a 404 error has occured. The requested page not found! <br><br>"+
|
||||||
"<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/t3otBjVZzT0\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>",
|
"<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/t3otBjVZzT0\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>",
|
||||||
"<div class=\"error-actions\"><a href=\"/\" class=\"btn btn-primary btn-lg\"><span class=\"glyphicon glyphicon-home\"></span>Take Me Home </a> <a href=\"mailto://rudi@nmare.net\" class=\"btn btn-default btn-lg\"><span class=\"glyphicon glyphicon-envelope\"></span> Contact Support </a></div>"))
|
"<div class=\"error-actions\"><a href=\"/\" class=\"btn btn-primary btn-lg\"><span class=\"glyphicon glyphicon-home\"></span>Take Me Home </a> <a href=\"mailto://rudi@nmare.net\" class=\"btn btn-default btn-lg\"><span class=\"glyphicon glyphicon-envelope\"></span> Contact Support </a></div>"))
|
||||||
@ -125,7 +126,7 @@ func getPending(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.LogErrorType(err)
|
log.LogErrorType(err)
|
||||||
notFoundPage(w, r)
|
notFoundPage(w, r)
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, string(pending))
|
fmt.Fprintf(w, string(pending))
|
||||||
} else {
|
} else {
|
||||||
notFoundPage(w, r)
|
notFoundPage(w, r)
|
||||||
}
|
}
|
||||||
@ -139,7 +140,7 @@ func getConfig(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.LogErrorType(err)
|
log.LogErrorType(err)
|
||||||
notFoundPage(w, r)
|
notFoundPage(w, r)
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, string(pending))
|
fmt.Fprintf(w, string(pending))
|
||||||
} else {
|
} else {
|
||||||
notFoundPage(w, r)
|
notFoundPage(w, r)
|
||||||
}
|
}
|
||||||
@ -153,7 +154,7 @@ func getProbations(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.LogErrorType(err)
|
log.LogErrorType(err)
|
||||||
notFoundPage(w, r)
|
notFoundPage(w, r)
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, string(pending))
|
fmt.Fprintf(w, string(pending))
|
||||||
} else {
|
} else {
|
||||||
notFoundPage(w, r)
|
notFoundPage(w, r)
|
||||||
}
|
}
|
||||||
@ -192,7 +193,7 @@ func getVerifications(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogErrorType(err)
|
log.LogErrorType(err)
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, string(verifications))
|
fmt.Fprintf(w, string(verifications))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUser(w http.ResponseWriter, r *http.Request) {
|
func getUser(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -214,7 +215,16 @@ func getUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogErrorType(err)
|
log.LogErrorType(err)
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, string(ret))
|
fmt.Fprintf(w, string(ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVerification(w http.ResponseWriter, r *http.Request) {
|
||||||
|
loggedIn, _ := detectUser(r, "getVerification")
|
||||||
|
if !loggedIn {
|
||||||
|
notFoundPage(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.ServeFile(w, r, r.URL.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWeb() {
|
func runWeb() {
|
||||||
|
|||||||
220
static/app.js
220
static/app.js
@ -1,4 +1,4 @@
|
|||||||
|
//Hopper says hi
|
||||||
// Get the modal
|
// Get the modal
|
||||||
const modal = document.getElementById("myModal");
|
const modal = document.getElementById("myModal");
|
||||||
|
|
||||||
@ -9,141 +9,145 @@ const btn = document.getElementById("myBtn");
|
|||||||
const span = document.getElementsByClassName("close")[0];
|
const span = document.getElementsByClassName("close")[0];
|
||||||
var mode = new URLSearchParams(window.location.search).get("mode");
|
var mode = new URLSearchParams(window.location.search).get("mode");
|
||||||
|
|
||||||
const archiveLink = document.querySelector("#archive-link")
|
const archiveLink = document.querySelector("#archive-link");
|
||||||
const pendingLink = document.querySelector("#pending-link")
|
const pendingLink = document.querySelector("#pending-link");
|
||||||
const statusLink = document.querySelector("#status-link")
|
const statusLink = document.querySelector("#status-link");
|
||||||
function handleForm(event) { event.preventDefault(); }
|
function handleForm(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
archiveLink.classList.remove("active");
|
archiveLink.classList.remove("active");
|
||||||
pendingLink.classList.remove("active");
|
pendingLink.classList.remove("active");
|
||||||
statusLink.classList.remove("active");
|
statusLink.classList.remove("active");
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case "status":
|
case "status":
|
||||||
statusLink.classList.add("active");
|
statusLink.classList.add("active");
|
||||||
return statusPage();
|
return statusPage();
|
||||||
case "pending":
|
case "pending":
|
||||||
pendingLink.classList.add("active");
|
pendingLink.classList.add("active");
|
||||||
break;
|
break;
|
||||||
case "verifications":
|
case "verifications":
|
||||||
archiveLink.classList.add("active");
|
archiveLink.classList.add("active");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log("No mode");
|
console.log("No mode");
|
||||||
mode = "verifications"
|
mode = "verifications";
|
||||||
archiveLink.classList.add("active");
|
archiveLink.classList.add("active");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
document.getElementById("main-app").innerHTML = '';
|
document.getElementById("main-app").innerHTML = "";
|
||||||
fetch(`https://thanos.nightmare.haus/api/${mode}`)
|
fetch(`https://thanos.nightmare.haus/api/${mode}`)
|
||||||
.then(response => response.json())
|
.then((response) => response.json())
|
||||||
.then(data => processData(data));
|
.then((data) => processData(data));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function statusPage() {
|
function statusPage() {
|
||||||
document.getElementById("main-app").innerHTML = '';
|
document.getElementById("main-app").innerHTML = "";
|
||||||
fetch(`https://thanos.nightmare.haus/api/config`)
|
fetch(`https://thanos.nightmare.haus/api/config`)
|
||||||
.then(response => response.json())
|
.then((response) => response.json())
|
||||||
.then(data => {
|
.then((data) => {
|
||||||
var node = document.createElement("config-status");
|
var node = document.createElement("config-status");
|
||||||
|
|
||||||
var upTime = document.createElement("div");
|
var upTime = document.createElement("div");
|
||||||
upTime.setAttribute("slot", "uptime");
|
upTime.setAttribute("slot", "uptime");
|
||||||
upTime.innerText = data.Uptime;
|
upTime.innerText = data.Uptime;
|
||||||
node.appendChild(upTime);
|
node.appendChild(upTime);
|
||||||
|
|
||||||
var bumpTime = document.createElement("div");
|
var bumpTime = document.createElement("div");
|
||||||
bumpTime.setAttribute("slot", "lastbump")
|
bumpTime.setAttribute("slot", "lastbump");
|
||||||
bumpTime.innerText = new Date(data.BumpTime).toLocaleString();
|
bumpTime.innerText = new Date(data.BumpTime).toLocaleString();
|
||||||
node.appendChild(bumpTime);
|
node.appendChild(bumpTime);
|
||||||
|
|
||||||
node.setData(data);
|
node.setData(data);
|
||||||
|
|
||||||
document.getElementById("main-app").appendChild(node);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
document.getElementById("main-app").appendChild(node);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchPage() {
|
function searchPage() {
|
||||||
var search = document.getElementById("search-bar");
|
var search = document.getElementById("search-bar");
|
||||||
fetch('https://thanos.nightmare.haus/api/verifications')
|
fetch("https://thanos.nightmare.haus/api/verifications")
|
||||||
.then(response => response.json())
|
.then((response) => response.json())
|
||||||
.then(data => {
|
.then((data) => {
|
||||||
var searchData = [];
|
var searchData = [];
|
||||||
for (user of data) {
|
for (user of data) {
|
||||||
var match = false;
|
var match = false;
|
||||||
|
|
||||||
if (user.Username.toLowerCase().includes(search.value.toLowerCase())) {
|
if (user.Username.toLowerCase().includes(search.value.toLowerCase())) {
|
||||||
match = true;
|
match = true;
|
||||||
}
|
}
|
||||||
if (new Date(user.Closed).toLocaleString().includes(search.value)) {
|
if (new Date(user.Closed).toLocaleString().includes(search.value)) {
|
||||||
match = true;
|
match = true;
|
||||||
}
|
}
|
||||||
if (user.UserID.includes(search.value)) {
|
if (user.UserID.includes(search.value)) {
|
||||||
match = true;
|
match = true;
|
||||||
}
|
}
|
||||||
if (match) {
|
if (match) {
|
||||||
searchData.push(user);
|
searchData.push(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
processData(searchData);
|
processData(searchData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function processData(data) {
|
function processData(data) {
|
||||||
document.getElementById("main-app").innerHTML = '';
|
document.getElementById("main-app").innerHTML = "";
|
||||||
if (data.length == 0) {
|
if (data.length == 0) {
|
||||||
alert("No data.");
|
alert("No data.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data = Object.values(data);
|
data = Object.values(data);
|
||||||
for (user of data) {
|
for (user of data) {
|
||||||
var node = document.createElement("user-card");
|
var node = document.createElement("user-card");
|
||||||
var nameSlot = document.createElement("div");
|
var nameSlot = document.createElement("div");
|
||||||
nameSlot.setAttribute("slot", "username");
|
nameSlot.setAttribute("slot", "username");
|
||||||
nameSlot.innerText = user.Username;
|
nameSlot.innerText = user.Username;
|
||||||
node.appendChild(nameSlot);
|
node.appendChild(nameSlot);
|
||||||
|
|
||||||
var joinDate = document.createElement("div");
|
var joinDate = document.createElement("div");
|
||||||
joinDate.setAttribute("slot", "join-date");
|
joinDate.setAttribute("slot", "join-date");
|
||||||
joinDate.innerText = mode == "pending" ? new Date(user.Submitted).toLocaleString() : new Date(user.Closed).toLocaleString();
|
joinDate.innerText =
|
||||||
node.appendChild(joinDate);
|
mode == "pending"
|
||||||
|
? new Date(user.Submitted).toLocaleString()
|
||||||
|
: new Date(user.Closed).toLocaleString();
|
||||||
|
node.appendChild(joinDate);
|
||||||
|
|
||||||
var discordSlot = document.createElement("div");
|
var discordSlot = document.createElement("div");
|
||||||
discordSlot.setAttribute("slot", "discord-id");
|
discordSlot.setAttribute("slot", "discord-id");
|
||||||
discordSlot.innerText = user.UserID;
|
discordSlot.innerText = user.UserID;
|
||||||
node.appendChild(discordSlot);
|
node.appendChild(discordSlot);
|
||||||
|
|
||||||
var picSlot = document.createElement("div");
|
var picSlot = document.createElement("div");
|
||||||
picSlot.setAttribute("slot", "pic-link");
|
picSlot.setAttribute("slot", "pic-link");
|
||||||
var aNode = document.createElement("a");
|
var aNode = document.createElement("a");
|
||||||
|
|
||||||
aNode.setAttribute("href", mode == "pending" ? user.Photo : `https://thanos.nightmare.haus/${user.Photo}`);
|
aNode.setAttribute(
|
||||||
aNode.innerText = "Verification Photo";
|
"href",
|
||||||
|
mode == "pending"
|
||||||
|
? user.Photo
|
||||||
|
: `https://thanos.nightmare.haus/${user.Photo}`
|
||||||
|
);
|
||||||
|
aNode.innerText = "Verification Photo";
|
||||||
|
|
||||||
picSlot.appendChild(aNode);
|
picSlot.appendChild(aNode);
|
||||||
node.appendChild(picSlot);
|
node.appendChild(picSlot);
|
||||||
document.getElementById("main-app").appendChild(node);
|
document.getElementById("main-app").appendChild(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the user clicks on <span> (x), close the modal
|
// When the user clicks on <span> (x), close the modal
|
||||||
span.onclick = function () {
|
span.onclick = function () {
|
||||||
modal.style.display = "none";
|
modal.style.display = "none";
|
||||||
}
|
};
|
||||||
|
|
||||||
// When the user clicks anywhere outside of the modal, close it
|
// When the user clicks anywhere outside of the modal, close it
|
||||||
window.onclick = function (event) {
|
window.onclick = function (event) {
|
||||||
if (event.target == modal) {
|
if (event.target == modal) {
|
||||||
modal.style.display = "none";
|
modal.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
var form = document.getElementById("search-form");
|
var form = document.getElementById("search-form");
|
||||||
form.addEventListener('submit', handleForm);
|
form.addEventListener("submit", handleForm);
|
||||||
|
|
||||||
main();
|
main();
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
//Hopper says hi again
|
||||||
const basicCard = document.createElement('basic-card');
|
const basicCard = document.createElement('basic-card');
|
||||||
const configStatus = document.createElement('status');
|
const configStatus = document.createElement('status');
|
||||||
const style = `
|
const style = `
|
||||||
|
|||||||
@ -9,13 +9,14 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
token string
|
token string
|
||||||
|
configFile string
|
||||||
dg *discordgo.Session
|
dg *discordgo.Session
|
||||||
guild string
|
guild = "451553644161138712"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&token, "t", "", "Bot Token")
|
flag.StringVar(&token, "t", "", "Bot Token")
|
||||||
flag.StringVar(&guild, "g", "", "Guild ID")
|
flag.StringVar(&configFile, "c", "", "Config file")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,11 +26,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
dg, _ = discordgo.New("Bot " + token)
|
dg, _ = discordgo.New("Bot " + token)
|
||||||
_ = dg.Open()
|
_ = dg.Open()
|
||||||
runFunction()
|
unbanAll()
|
||||||
dg.Close()
|
dg.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFunction() {
|
func unbanAll() {
|
||||||
bans, _ := dg.GuildBans(guild)
|
bans, _ := dg.GuildBans(guild)
|
||||||
for _, v := range bans {
|
for _, v := range bans {
|
||||||
dg.GuildBanDelete(guild, v.User.ID)
|
dg.GuildBanDelete(guild, v.User.ID)
|
||||||
26
types.go
26
types.go
@ -3,27 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
"github.com/rudi9719/loggy"
|
"github.com/rudi9719/loggy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BotCommand struct used for modular commands
|
|
||||||
type BotCommand struct {
|
|
||||||
Message *discordgo.MessageCreate
|
|
||||||
Session *discordgo.Session
|
|
||||||
Parts []string
|
|
||||||
Command string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command is the type to store commands
|
|
||||||
type Command struct {
|
|
||||||
Name string
|
|
||||||
RequiresAdmin bool
|
|
||||||
Help string
|
|
||||||
Keywords []string
|
|
||||||
Exec func(BotCommand) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config struct used for bot
|
// Config struct used for bot
|
||||||
type Config struct {
|
type Config struct {
|
||||||
GuildID string
|
GuildID string
|
||||||
@ -32,12 +14,10 @@ type Config struct {
|
|||||||
MonitorRole string
|
MonitorRole string
|
||||||
IntroChann string
|
IntroChann string
|
||||||
MonitorChann string
|
MonitorChann string
|
||||||
SocialChanns []string
|
|
||||||
VerifiedRole string
|
VerifiedRole string
|
||||||
BumpTime time.Time
|
BumpTime time.Time
|
||||||
LastBumper string
|
LastBumper string
|
||||||
Stats map[string]int
|
Stats map[string]int
|
||||||
Activity map[string]int
|
|
||||||
Unverified map[string]time.Time
|
Unverified map[string]time.Time
|
||||||
Verifications map[string]Verification
|
Verifications map[string]Verification
|
||||||
Probations map[string]time.Time
|
Probations map[string]time.Time
|
||||||
@ -55,6 +35,12 @@ type Verification struct {
|
|||||||
Closed time.Time
|
Closed time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type linkedAccount struct {
|
||||||
|
domainUser string
|
||||||
|
discordUser string
|
||||||
|
sigHash string
|
||||||
|
}
|
||||||
|
|
||||||
// Tokens are the Login Token struct
|
// Tokens are the Login Token struct
|
||||||
type Tokens struct {
|
type Tokens struct {
|
||||||
Username string
|
Username string
|
||||||
|
|||||||
Reference in New Issue
Block a user