This repository has been archived on 2022-01-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
gidbig/webserver.go
T
da 1e50475a46 Worlds biggest commit
forgot to make it a separate goroutine
2017-01-19 23:44:58 +01:00

196 lines
5.3 KiB
Go

package main
import (
"crypto/rand"
"encoding/base64"
"fmt"
"html/template"
"net/http"
"github.com/bwmarrin/discordgo"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
"golang.org/x/oauth2"
)
const (
header = "templates/header.html"
footer = "templates/footer.html"
templateDir = "templates/"
)
var (
discordOauthConfig = &oauth2.Config{
RedirectURL: "",
ClientID: "",
ClientSecret: "",
Scopes: []string{"identify", "guilds"},
Endpoint: *endp,
}
// Some random string, random for each request
oauthStateString string
endp = &oauth2.Endpoint{
AuthURL: "https://discordapp.com/api/oauth2/authorize",
TokenURL: "https://discordapp.com/api/oauth2/token",
}
tmpls = map[string]*template.Template{}
// TODO change secret
store *sessions.CookieStore
)
type SoundItem struct {
Itemcommand string
Itemsoundname string
Itemtext string
}
// startWebServer
func startWebServer(port string, ci string, cs string, redirectURL string) {
tmpls["home.html"] = template.Must(template.ParseFiles(templateDir+"home.html", header, footer))
tmpls["internal.html"] = template.Must(template.ParseFiles(templateDir+"internal.html", header, footer))
tmpls["itemrow.html"] = template.Must(template.ParseFiles(templateDir + "itemrow.html"))
store = sessions.NewCookieStore([]byte(cs))
discordOauthConfig.ClientID = ci
discordOauthConfig.ClientSecret = cs
discordOauthConfig.RedirectURL = redirectURL + "/discordCallback"
r := mux.NewRouter()
r.HandleFunc("/", handleMain)
r.HandleFunc("/logout", handleLogout)
r.HandleFunc("/discordLogin", handlediscordLogin)
r.HandleFunc("/discordCallback", handlediscordCallback)
r.HandleFunc("/playsound", handlePlaySound)
http.Handle("/", r)
http.ListenAndServe(":"+port, nil)
}
func handlePlaySound(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
sound, soundCollection := findSoundAndCollection(r.FormValue("command"), r.FormValue("soundname"))
session, _ := store.Get(r, "session-name")
var guild *discordgo.Guild
user, _ := discord.User(session.Values["discordUserID"].(string))
for _, g := range discord.State.Guilds {
for _, vs := range g.VoiceStates {
if vs.UserID == session.Values["discordUserID"].(string) {
guild = g
}
}
}
if user != nil && guild != nil && sound != nil && soundCollection != nil {
go enqueuePlay(user, guild, soundCollection, sound)
}
}
func handleMain(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session-name")
if session.Values["discordUsername"] != nil {
err := tmpls["internal.html"].ExecuteTemplate(w, "header", map[string]interface{}{})
if err != nil {
fmt.Println(err)
return
}
var si [4]SoundItem
cnt := 0
for _, sc := range COLLECTIONS {
for _, snd := range sc.Sounds {
si[cnt%4].Itemcommand = "!" + sc.Prefix
si[cnt%4].Itemsoundname = snd.Name
si[cnt%4].Itemtext = si[cnt%4].Itemcommand + " " + si[cnt%4].Itemsoundname
if cnt != 0 && cnt%4 == 3 {
err = tmpls["itemrow.html"].Execute(w, si)
if err != nil {
fmt.Println(err)
return
}
}
cnt++
}
}
if cnt%4 != 0 {
err = tmpls["itemrow.html"].Execute(w, si)
if err != nil {
fmt.Println(err)
return
}
}
err = tmpls["internal.html"].ExecuteTemplate(w, "footer", map[string]interface{}{})
if err != nil {
fmt.Println(err)
return
}
return
}
tmpls["home.html"].ExecuteTemplate(w, "header", map[string]interface{}{})
tmpls["home.html"].ExecuteTemplate(w, "footer", map[string]interface{}{})
}
func handleLogout(w http.ResponseWriter, r *http.Request) {
cookie := &http.Cookie{
Name: "session-name",
Value: "",
Path: "/",
MaxAge: -1,
}
http.SetCookie(w, cookie)
http.Redirect(w, r, "/", http.StatusFound)
}
func handlediscordLogin(w http.ResponseWriter, r *http.Request) {
b := make([]byte, 16)
rand.Read(b)
oauthStateString = base64.URLEncoding.EncodeToString(b)
session, _ := store.Get(r, "session-name")
session.Values["state"] = oauthStateString
session.Save(r, w)
url := discordOauthConfig.AuthCodeURL(oauthStateString)
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}
func handlediscordCallback(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "session-name")
if err != nil {
fmt.Fprintln(w, "aborted")
return
}
if r.URL.Query().Get("state") != session.Values["state"] {
fmt.Fprintln(w, "no state match; possible csrf OR cookies not enabled")
return
}
state := r.FormValue("state")
if state != oauthStateString {
fmt.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
token, err := discordOauthConfig.Exchange(oauth2.NoContext, r.FormValue("code"))
if err != nil {
fmt.Fprintln(w, "Code exchange (could not get token) failed with ", err)
return
}
if !token.Valid() {
fmt.Fprintln(w, "retrieved invalid token")
return
}
dg, err := discordgo.New("Bearer " + token.AccessToken)
if err != nil {
fmt.Println("Error while creating discord session: ", err)
return
}
user, _ := dg.User("@me")
session.Values["discordUserID"] = user.ID
session.Values["discordUsername"] = user.Username
session.Values["accessToken"] = token.AccessToken
session.Save(r, w)
dg.Close()
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
}