fix(auth): handle keyring open/set errors per service
Stop ignoring keyring.Open failures in all three login files. A failed Open previously left a nil ring behind the blank identifier, so the next Get/Set panicked with no message. Each service now opens its ring in init, logs a service-prefixed warning when storage is unavailable, and guards every use with a Ready check that fails safe to logged-out. - AniListUserFunctions.go: add aniRingReady/aniRingSet helpers, log Open and per-key Set failures, reject invalid ExpiresIn instead of silently storing 0, clear in-memory JWT on logout even when storage is missing - MALUserFunctions.go: add malRingReady/malRingSet helpers covering login, OAuth callback, and token-refresh saves; same Open/Set/ ExpiresIn/logout treatment - SimklUserFunctions.go: add simklRingReady/simklRingSet helpers; same Open/Set/logout treatment No wallet, key names, or login flow changed. Same ServiceName AniTrack, same keys, same OAuth callback behavior.
This commit is contained in:
+61
-26
@@ -19,18 +19,48 @@ import (
|
||||
|
||||
var aniListJwt AniListJWT
|
||||
|
||||
var aniRing, _ = keyring.Open(keyring.Config{
|
||||
ServiceName: "AniTrack",
|
||||
KeychainName: "AniTrack",
|
||||
KeychainSynchronizable: false,
|
||||
KeychainTrustApplication: true,
|
||||
KeychainAccessibleWhenUnlocked: true,
|
||||
})
|
||||
var aniRing keyring.Keyring
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
aniRing, err = keyring.Open(keyring.Config{
|
||||
ServiceName: "AniTrack",
|
||||
KeychainName: "AniTrack",
|
||||
KeychainSynchronizable: false,
|
||||
KeychainTrustApplication: true,
|
||||
KeychainAccessibleWhenUnlocked: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("anilist: secure storage unavailable: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func aniRingReady() bool {
|
||||
if aniRing == nil {
|
||||
log.Println("anilist: secure storage unavailable")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func aniRingSet(key string, data []byte) error {
|
||||
if !aniRingReady() {
|
||||
return errors.New("anilist: secure storage unavailable")
|
||||
}
|
||||
if err := aniRing.Set(keyring.Item{Key: key, Data: data}); err != nil {
|
||||
log.Printf("anilist: save %s failed: %s", key, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var aniCtxShutdown, aniCancel = context.WithCancel(context.Background())
|
||||
|
||||
func (a *App) CheckIfAniListLoggedIn() bool {
|
||||
if (AniListJWT{} == aniListJwt) {
|
||||
if !aniRingReady() {
|
||||
return false
|
||||
}
|
||||
tokenType, tokenErr := aniRing.Get("anilistTokenType")
|
||||
expiresIn, expiresInErr := aniRing.Get("anilistTokenExpiresIn")
|
||||
refreshToken, refreshTokenErr := aniRing.Get("anilistRefreshToken")
|
||||
@@ -38,10 +68,15 @@ func (a *App) CheckIfAniListLoggedIn() bool {
|
||||
if (tokenErr != nil || expiresInErr != nil || refreshTokenErr != nil || accessTokenErr != nil) || len(accessToken.Data) == 0 {
|
||||
return false
|
||||
} else {
|
||||
var expiresInConvertErr error
|
||||
aniListJwt.TokenType = string(tokenType.Data)
|
||||
aniListJwt.AccessToken = string(accessToken.Data)
|
||||
aniListJwt.RefreshToken = string(refreshToken.Data)
|
||||
aniListJwt.ExpiresIn, _ = strconv.Atoi(string(expiresIn.Data))
|
||||
aniListJwt.ExpiresIn, expiresInConvertErr = strconv.Atoi(string(expiresIn.Data))
|
||||
if expiresInConvertErr != nil {
|
||||
log.Printf("anilist: invalid expiresIn %q: %s", string(expiresIn.Data), expiresInConvertErr)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
@@ -51,6 +86,10 @@ func (a *App) CheckIfAniListLoggedIn() bool {
|
||||
|
||||
func (a *App) AniListLogin() {
|
||||
if (AniListJWT{} == aniListJwt) {
|
||||
if !aniRingReady() {
|
||||
log.Println("anilist: cannot check login, secure storage unavailable")
|
||||
return
|
||||
}
|
||||
tokenType, tokenErr := aniRing.Get("anilistTokenType")
|
||||
expiresIn, expiresInErr := aniRing.Get("anilistTokenExpiresIn")
|
||||
refreshToken, refreshTokenErr := aniRing.Get("anilistRefreshToken")
|
||||
@@ -64,10 +103,14 @@ func (a *App) AniListLogin() {
|
||||
a.handleAniListCallback(serverDone)
|
||||
serverDone.Wait()
|
||||
} else {
|
||||
var expiresInConvertErr error
|
||||
aniListJwt.TokenType = string(tokenType.Data)
|
||||
aniListJwt.AccessToken = string(accessToken.Data)
|
||||
aniListJwt.RefreshToken = string(refreshToken.Data)
|
||||
aniListJwt.ExpiresIn, _ = strconv.Atoi(string(expiresIn.Data))
|
||||
aniListJwt.ExpiresIn, expiresInConvertErr = strconv.Atoi(string(expiresIn.Data))
|
||||
if expiresInConvertErr != nil {
|
||||
log.Printf("anilist: invalid expiresIn %q: %s", string(expiresIn.Data), expiresInConvertErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,22 +128,10 @@ func (a *App) handleAniListCallback(wg *sync.WaitGroup) {
|
||||
content := r.FormValue("code")
|
||||
if content != "" {
|
||||
aniListJwt = getAniListAuthorizationToken(content)
|
||||
_ = aniRing.Set(keyring.Item{
|
||||
Key: "anilistTokenType",
|
||||
Data: []byte(aniListJwt.TokenType),
|
||||
})
|
||||
_ = aniRing.Set(keyring.Item{
|
||||
Key: "anilistTokenExpiresIn",
|
||||
Data: []byte(strconv.Itoa(aniListJwt.ExpiresIn)),
|
||||
})
|
||||
_ = aniRing.Set(keyring.Item{
|
||||
Key: "anilistAccessToken",
|
||||
Data: []byte(aniListJwt.AccessToken),
|
||||
})
|
||||
_ = aniRing.Set(keyring.Item{
|
||||
Key: "anilistRefreshToken",
|
||||
Data: []byte(aniListJwt.RefreshToken),
|
||||
})
|
||||
_ = aniRingSet("anilistTokenType", []byte(aniListJwt.TokenType))
|
||||
_ = aniRingSet("anilistTokenExpiresIn", []byte(strconv.Itoa(aniListJwt.ExpiresIn)))
|
||||
_ = aniRingSet("anilistAccessToken", []byte(aniListJwt.AccessToken))
|
||||
_ = aniRingSet("anilistRefreshToken", []byte(aniListJwt.RefreshToken))
|
||||
_, err := runtime.MessageDialog(*wailsContext, runtime.MessageDialogOptions{
|
||||
Title: "AniList Authorization",
|
||||
Message: "It is now safe to close your browser tab",
|
||||
@@ -208,12 +239,16 @@ func (a *App) GetAniListLoggedInUser() AniListUser {
|
||||
|
||||
func (a *App) LogoutAniList() string {
|
||||
if (AniListJWT{} != aniListJwt) {
|
||||
if !aniRingReady() {
|
||||
aniListJwt = AniListJWT{}
|
||||
return "AniList Logged Out Successfully"
|
||||
}
|
||||
typeErr := aniRing.Remove("anilistTokenType")
|
||||
expiresInErr := aniRing.Remove("anilistTokenExpiresIn")
|
||||
accessTokenErr := aniRing.Remove("anilistAccessToken")
|
||||
refreshTokenErr := aniRing.Remove("anilistRefreshToken")
|
||||
if typeErr != nil || expiresInErr != nil || accessTokenErr != nil || refreshTokenErr != nil {
|
||||
fmt.Println("AniList Logout Failed")
|
||||
log.Printf("anilist: logout cleanup failed (type=%v expires=%v access=%v refresh=%v)", typeErr, expiresInErr, accessTokenErr, refreshTokenErr)
|
||||
}
|
||||
aniListJwt = AniListJWT{}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user