]> git.lizzy.rs Git - go-anidb.git/blobdiff - auth.go
Modernize
[go-anidb.git] / auth.go
diff --git a/auth.go b/auth.go
index 1b3fe234df882466029b32deeb3388dca42695aa..c0c7efaf050b75043ba88c0d7f089728289e9361 100644 (file)
--- a/auth.go
+++ b/auth.go
@@ -4,7 +4,7 @@ import (
        "crypto/aes"
        "crypto/cipher"
        "crypto/rand"
-       "errors"
+       "github.com/EliasFleckenstein03/go-anidb/udp"
        "io"
        "runtime"
 )
@@ -83,53 +83,110 @@ func newCredentials(username, password, udpKey string) *credentials {
        }
 }
 
-// Re-authenticates the current user. Do not use unless really necessary.
-func (a *AniDB) ReAuth() error {
-       return a.udp.ReAuth()
-}
+func (udp *udpWrap) ReAuth() udpapi.APIReply {
+       if Banned() {
+               return bannedReply
+       }
 
-func (udp *udpWrap) ReAuth() error {
-       if c := udp.credentials; c != nil {
-               defer runtime.GC() // any better way to clean the plaintexts?
+       udp.credLock.Lock()
+       defer udp.credLock.Unlock()
 
-               udp.connected = true
-               return udp.Auth(
+       if c := udp.credentials; c != nil {
+               udp.logRequest(paramSet{cmd: "AUTH", params: paramMap{"user": decrypt(c.username)}})
+               r := udp.AniDBUDP.Auth(
                        decrypt(c.username),
                        decrypt(c.password),
                        decrypt(c.udpKey))
+               udp.logReply(r)
+
+               err := r.Error()
+
+               if err != nil {
+                       switch r.Code() {
+                       // 555 -- banned
+                       // 601 -- server down, treat the same as a ban
+                       case 555, 601:
+                               setBanned()
+                       case 500: // bad credentials
+                               udp.credentials.shred()
+                               udp.credentials = nil
+                       case 503, 504: // client rejected
+                               panic(err)
+                       }
+               }
+               udp.connected = err == nil
+
+               if udp.connected {
+                       if user := UserByName(decrypt(c.username)); user != nil {
+                               udp.user = user
+                       } else {
+                               // We can't use SendRecv here as it would deadlock
+                               ch := make(chan udpapi.APIReply, 1)
+                               udp.sendQueueCh <- paramSet{
+                                       cmd:    "USER",
+                                       params: paramMap{"user": decrypt(c.username)},
+                                       ch:     ch,
+                               }
+                               reply := <-ch
+
+                               if reply != nil {
+                                       uid, _ := parseUserReply(reply)
+                                       udp.user = uid.User()
+                               }
+                       }
+               }
+
+               runtime.GC()
+               return r
        }
-       return errors.New("No credentials stored")
+       return &noauthAPIReply{}
 }
 
 // Saves the used credentials in the AniDB struct, to allow automatic
 // re-authentication when needed; they are (properly) encrypted with a key that's
 // uniquely generated every time the module is initialized.
-func (a *AniDB) SetCredentials(username, password, udpKey string) {
-       a.udp.credentials.shred()
-       a.udp.credentials = newCredentials(username, password, udpKey)
+func (adb *AniDB) SetCredentials(username, password, udpKey string) {
+       adb.udp.credLock.Lock()
+       defer adb.udp.credLock.Unlock()
+
+       adb.udp.credentials.shred()
+       adb.udp.credentials = newCredentials(username, password, udpKey)
 }
 
 // Authenticates to anidb's UDP API and, on success, stores the credentials using
 // SetCredentials. If udpKey is not "", the communication with the server
 // will be encrypted, but in the VERY weak ECB mode.
-func (a *AniDB) Auth(username, password, udpKey string) (err error) {
+func (adb *AniDB) Auth(username, password, udpKey string) (err error) {
        defer runtime.GC() // any better way to clean the plaintexts?
 
-       if err = a.udp.Auth(username, password, udpKey); err == nil {
-               a.udp.connected = true
-               a.SetCredentials(username, password, udpKey)
+       adb.udp.sendLock.Lock()
+       defer adb.udp.sendLock.Unlock()
+
+       if !Banned() {
+               adb.SetCredentials(username, password, udpKey)
        }
-       return
+
+       // ReAuth clears the credentials if they're bad
+       return adb.udp.ReAuth().Error()
 }
 
 // Logs the user out and removes the credentials from the AniDB struct.
-func (a *AniDB) Logout() error {
-       if a.udp.connected {
-               a.udp.credentials.shred()
-               a.udp.credentials = nil
+func (adb *AniDB) Logout() error {
+       adb.udp.credLock.Lock()
+       defer adb.udp.credLock.Unlock()
+
+       adb.udp.credentials.shred()
+       adb.udp.credentials = nil
+
+       adb.udp.sendLock.Lock()
+       defer adb.udp.sendLock.Unlock()
+
+       adb.udp.user = nil
 
-               a.udp.connected = false
-               return a.udp.Logout()
+       if adb.udp.connected {
+               adb.udp.connected = false
+               adb.udp.logRequest(paramSet{cmd: "LOGOUT"})
+               return adb.udp.Logout()
        }
        return nil
 }