1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-07 14:50:56 +00:00

Fix - non-logged-in needs a reply if auth needed

Refactor for testing - all janitors have sleep in a different function
from the work, so tests can trigger them
This commit is contained in:
Kane York 2015-12-16 13:59:51 -08:00
parent 4b2449aecf
commit 26747a1104
4 changed files with 104 additions and 79 deletions

View file

@ -23,8 +23,8 @@ type CommandHandler func(*websocket.Conn, *ClientInfo, ClientMessage) (ClientMes
var commandHandlers = map[Command]CommandHandler{ var commandHandlers = map[Command]CommandHandler{
HelloCommand: C2SHello, HelloCommand: C2SHello,
"ping": C2SPing, "ping": C2SPing,
"setuser": C2SSetUser, SetUserCommand: C2SSetUser,
"ready": C2SReady, ReadyCommand: C2SReady,
"sub": C2SSubscribe, "sub": C2SSubscribe,
"unsub": C2SUnsubscribe, "unsub": C2SUnsubscribe,
@ -143,7 +143,6 @@ func C2SSetUser(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rm
go client.StartAuthorization(func(_ *ClientInfo, _ bool) { go client.StartAuthorization(func(_ *ClientInfo, _ bool) {
client.MsgChannelKeepalive.Done() client.MsgChannelKeepalive.Done()
}) })
} }
return ResponseSuccess, nil return ResponseSuccess, nil
@ -316,11 +315,11 @@ func C2SEmoticonUses(conn *websocket.Conn, client *ClientInfo, msg ClientMessage
func aggregateDataSender() { func aggregateDataSender() {
for { for {
time.Sleep(5 * time.Minute) time.Sleep(5 * time.Minute)
doSendAggregateData() aggregateDataSender_do()
} }
} }
func doSendAggregateData() { func aggregateDataSender_do() {
followEventsLock.Lock() followEventsLock.Lock()
follows := followEvents follows := followEvents
followEvents = nil followEvents = nil
@ -538,11 +537,18 @@ func C2SHandleRemoteCommand(conn *websocket.Conn, client *ClientInfo, msg Client
} }
const AuthorizationFailedErrorString = "Failed to verify your Twitch username." const AuthorizationFailedErrorString = "Failed to verify your Twitch username."
const AuthorizationNeededError = "You must be signed in to use that command."
func doRemoteCommand(conn *websocket.Conn, msg ClientMessage, client *ClientInfo) { func doRemoteCommand(conn *websocket.Conn, msg ClientMessage, client *ClientInfo) {
resp, err := SendRemoteCommandCached(string(msg.Command), msg.origArguments, client.AuthInfo) resp, err := SendRemoteCommandCached(string(msg.Command), msg.origArguments, client.AuthInfo)
if err == ErrAuthorizationNeeded { if err == ErrAuthorizationNeeded {
if client.TwitchUsername == "" {
// Not logged in
client.MessageChannel <- ClientMessage{MessageID: msg.MessageID, Command: ErrorCommand, Arguments: AuthorizationNeededError}
client.MsgChannelKeepalive.Done()
return
}
client.StartAuthorization(func(_ *ClientInfo, success bool) { client.StartAuthorization(func(_ *ClientInfo, success bool) {
if success { if success {
doRemoteCommand(conn, msg, client) doRemoteCommand(conn, msg, client)

View file

@ -34,6 +34,12 @@ const ErrorCommand Command = "error"
// Sending any other command will result in a CloseFirstMessageNotHello. // Sending any other command will result in a CloseFirstMessageNotHello.
const HelloCommand Command = "hello" const HelloCommand Command = "hello"
// ReadyCommand is a C2S Command.
// It indicates that the client is finished sending the initial 'sub' commands and the server should send the backlog.
const ReadyCommand Command = "ready"
const SetUserCommand Command = "set_user"
// AuthorizeCommand is a S2C Command sent as part of Twitch username validation. // AuthorizeCommand is a S2C Command sent as part of Twitch username validation.
const AuthorizeCommand Command = "do_authorize" const AuthorizeCommand Command = "do_authorize"

View file

@ -10,6 +10,7 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"errors"
) )
type AuthCallback func(client *ClientInfo, successful bool) type AuthCallback func(client *ClientInfo, successful bool)
@ -39,8 +40,11 @@ func AddPendingAuthorization(client *ClientInfo, challenge string, callback Auth
func authorizationJanitor() { func authorizationJanitor() {
for { for {
time.Sleep(5 * time.Minute) time.Sleep(5 * time.Minute)
authorizationJanitor_do()
}
}
func() { func authorizationJanitor_do() {
cullTime := time.Now().Add(-30 * time.Minute) cullTime := time.Now().Add(-30 * time.Minute)
PendingAuthLock.Lock() PendingAuthLock.Lock()
@ -51,16 +55,16 @@ func authorizationJanitor() {
for _, v := range PendingAuths { for _, v := range PendingAuths {
if !cullTime.After(v.EnteredAt) { if !cullTime.After(v.EnteredAt) {
newPendingAuths = append(newPendingAuths, v) newPendingAuths = append(newPendingAuths, v)
} else {
v.Callback(v.Client, false)
} }
} }
PendingAuths = newPendingAuths PendingAuths = newPendingAuths
}()
}
} }
func (client *ClientInfo) StartAuthorization(callback AuthCallback) { func (client *ClientInfo) StartAuthorization(callback AuthCallback) {
fmt.Println(DEBUG, "startig auth for user", client.TwitchUsername, client.RemoteAddr) fmt.Println(DEBUG, "starting auth for user", client.TwitchUsername, client.RemoteAddr)
var nonce [32]byte var nonce [32]byte
_, err := rand.Read(nonce[:]) _, err := rand.Read(nonce[:])
if err != nil { if err != nil {
@ -88,6 +92,8 @@ const AuthCommand = "AUTH"
const DEBUG = "DEBUG" const DEBUG = "DEBUG"
var errChallengeNotFound = errors.New("did not find a challenge solved by that message")
func ircConnection() { func ircConnection() {
c := irc.SimpleClient("justinfan123") c := irc.SimpleClient("justinfan123")
@ -113,12 +119,23 @@ func ircConnection() {
submittedUser := line.Nick submittedUser := line.Nick
submittedChallenge := msgArray[1] submittedChallenge := msgArray[1]
submitAuth(submittedUser, submittedChallenge)
})
err := c.ConnectTo("irc.twitch.tv")
if err != nil {
log.Fatalln("Cannot connect to IRC:", err)
}
}
func submitAuth(user, challenge string) error {
var auth PendingAuthorization var auth PendingAuthorization
var idx int = -1 var idx int = -1
PendingAuthLock.Lock() PendingAuthLock.Lock()
for i, v := range PendingAuths { for i, v := range PendingAuths {
if v.Client.TwitchUsername == submittedUser && v.Challenge == submittedChallenge { if v.Client.TwitchUsername == user && v.Challenge == challenge {
auth = v auth = v
idx = i idx = i
break break
@ -130,8 +147,7 @@ func ircConnection() {
PendingAuthLock.Unlock() PendingAuthLock.Unlock()
if idx == -1 { if idx == -1 {
fmt.Println(DEBUG, "discarded msg - challenge not found", line.Raw) return errChallengeNotFound // perhaps it was for another socket server
return
} }
// auth is valid, and removed from pending list // auth is valid, and removed from pending list
@ -139,7 +155,7 @@ func ircConnection() {
fmt.Println(DEBUG, "authorization success for user", auth.Client.TwitchUsername) fmt.Println(DEBUG, "authorization success for user", auth.Client.TwitchUsername)
var usernameChanged bool var usernameChanged bool
auth.Client.Mutex.Lock() auth.Client.Mutex.Lock()
if auth.Client.TwitchUsername == submittedUser { // recheck condition if auth.Client.TwitchUsername == user { // recheck condition
auth.Client.UsernameValidated = true auth.Client.UsernameValidated = true
} else { } else {
usernameChanged = true usernameChanged = true
@ -153,11 +169,4 @@ func ircConnection() {
auth.Callback(auth.Client, false) auth.Callback(auth.Client, false)
} }
} }
})
err := c.ConnectTo("irc.twitch.tv")
if err != nil {
log.Fatalln("Cannot connect to IRC:", err)
}
} }

View file

@ -149,6 +149,11 @@ const ReapingDelay = 1 * time.Minute
func pubsubJanitor() { func pubsubJanitor() {
for { for {
time.Sleep(ReapingDelay) time.Sleep(ReapingDelay)
pubsubJanitor_do()
}
}
func pubsubJanitor_do() {
var cleanedUp = make([]string, 0, 6) var cleanedUp = make([]string, 0, 6)
ChatSubscriptionLock.Lock() ChatSubscriptionLock.Lock()
for key, val := range ChatSubscriptionInfo { for key, val := range ChatSubscriptionInfo {
@ -165,7 +170,6 @@ func pubsubJanitor() {
log.Println("error reporting cleaned subs:", err) log.Println("error reporting cleaned subs:", err)
} }
} }
}
} }
// Add a channel to the subscriptions while holding a read-lock to the map. // Add a channel to the subscriptions while holding a read-lock to the map.