mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
181 lines
3.8 KiB
Go
181 lines
3.8 KiB
Go
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"log"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
irc "github.com/fluffle/goirc/client"
|
|
)
|
|
|
|
type AuthCallback func(client *ClientInfo, successful bool)
|
|
|
|
type PendingAuthorization struct {
|
|
Client *ClientInfo
|
|
Challenge string
|
|
Callback AuthCallback
|
|
EnteredAt time.Time
|
|
}
|
|
|
|
var PendingAuths []PendingAuthorization
|
|
var PendingAuthLock sync.Mutex
|
|
|
|
func AddPendingAuthorization(client *ClientInfo, challenge string, callback AuthCallback) {
|
|
PendingAuthLock.Lock()
|
|
defer PendingAuthLock.Unlock()
|
|
|
|
PendingAuths = append(PendingAuths, PendingAuthorization{
|
|
Client: client,
|
|
Challenge: challenge,
|
|
Callback: callback,
|
|
EnteredAt: time.Now(),
|
|
})
|
|
}
|
|
|
|
// is_init_func
|
|
func authorizationJanitor() {
|
|
for {
|
|
time.Sleep(5 * time.Minute)
|
|
authorizationJanitor_do()
|
|
}
|
|
}
|
|
|
|
func authorizationJanitor_do() {
|
|
cullTime := time.Now().Add(-30 * time.Minute)
|
|
|
|
PendingAuthLock.Lock()
|
|
defer PendingAuthLock.Unlock()
|
|
|
|
newPendingAuths := make([]PendingAuthorization, 0, len(PendingAuths))
|
|
|
|
for _, v := range PendingAuths {
|
|
if !cullTime.After(v.EnteredAt) {
|
|
newPendingAuths = append(newPendingAuths, v)
|
|
} else {
|
|
go v.Callback(v.Client, false)
|
|
}
|
|
}
|
|
|
|
PendingAuths = newPendingAuths
|
|
}
|
|
|
|
func (client *ClientInfo) StartAuthorization(callback AuthCallback) {
|
|
if callback == nil {
|
|
return // callback must not be nil
|
|
}
|
|
var nonce [32]byte
|
|
_, err := rand.Read(nonce[:])
|
|
if err != nil {
|
|
go callback(client, false)
|
|
return
|
|
}
|
|
buf := bytes.NewBuffer(nil)
|
|
enc := base64.NewEncoder(base64.RawURLEncoding, buf)
|
|
enc.Write(nonce[:])
|
|
enc.Close()
|
|
challenge := buf.String()
|
|
|
|
AddPendingAuthorization(client, challenge, callback)
|
|
|
|
client.Send(ClientMessage{MessageID: -1, Command: AuthorizeCommand, Arguments: challenge})
|
|
}
|
|
|
|
const AuthChannelName = "frankerfacezauthorizer"
|
|
const AuthChannel = "#" + AuthChannelName
|
|
const AuthCommand = "AUTH"
|
|
|
|
var authIrcConnection *irc.Conn
|
|
|
|
// is_init_func
|
|
func ircConnection() {
|
|
c := irc.SimpleClient("justinfan123")
|
|
c.Config().Server = "irc.chat.twitch.tv"
|
|
authIrcConnection = c
|
|
|
|
var reconnect func(conn *irc.Conn)
|
|
connect := func(conn *irc.Conn) {
|
|
err := c.Connect()
|
|
if err != nil {
|
|
log.Println("irc: failed to connect to IRC:", err)
|
|
go reconnect(conn)
|
|
}
|
|
}
|
|
|
|
reconnect = func(conn *irc.Conn) {
|
|
time.Sleep(5 * time.Second)
|
|
log.Println("irc: Reconnecting…")
|
|
connect(conn)
|
|
}
|
|
|
|
c.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) {
|
|
conn.Join(AuthChannel)
|
|
})
|
|
|
|
c.HandleFunc(irc.DISCONNECTED, func(conn *irc.Conn, line *irc.Line) {
|
|
log.Println("irc: Disconnected. Reconnecting in 5 seconds.")
|
|
go reconnect(conn)
|
|
})
|
|
|
|
c.HandleFunc(irc.PRIVMSG, func(conn *irc.Conn, line *irc.Line) {
|
|
channel := line.Args[0]
|
|
msg := line.Args[1]
|
|
if channel != AuthChannel || !strings.HasPrefix(msg, AuthCommand) || !line.Public() {
|
|
return
|
|
}
|
|
|
|
msgArray := strings.Split(msg, " ")
|
|
if len(msgArray) != 2 {
|
|
return
|
|
}
|
|
|
|
submittedUser := line.Nick
|
|
submittedChallenge := msgArray[1]
|
|
|
|
submitAuth(submittedUser, submittedChallenge)
|
|
})
|
|
|
|
connect(c)
|
|
}
|
|
|
|
func submitAuth(user, challenge string) {
|
|
var auth PendingAuthorization
|
|
var idx int = -1
|
|
|
|
PendingAuthLock.Lock()
|
|
for i, v := range PendingAuths {
|
|
if v.Client.TwitchUsername == user && v.Challenge == challenge {
|
|
auth = v
|
|
idx = i
|
|
break
|
|
}
|
|
}
|
|
if idx != -1 {
|
|
PendingAuths = append(PendingAuths[:idx], PendingAuths[idx+1:]...)
|
|
}
|
|
PendingAuthLock.Unlock()
|
|
|
|
if idx == -1 {
|
|
return // perhaps it was for another socket server
|
|
}
|
|
|
|
// auth is valid, and removed from pending list
|
|
|
|
var usernameChanged bool
|
|
auth.Client.Mutex.Lock()
|
|
if auth.Client.TwitchUsername == user { // recheck condition
|
|
auth.Client.UsernameValidated = true
|
|
} else {
|
|
usernameChanged = true
|
|
}
|
|
auth.Client.Mutex.Unlock()
|
|
|
|
if !usernameChanged {
|
|
auth.Callback(auth.Client, true)
|
|
} else {
|
|
auth.Callback(auth.Client, false)
|
|
}
|
|
}
|