"crypto/aes"
"crypto/cipher"
"crypto/rand"
- "errors"
+ "github.com/EliasFleckenstein03/go-anidb/udp"
"io"
"runtime"
)
}
}
-// 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
}