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:
+57
-42
@@ -23,13 +23,40 @@ import (
|
||||
|
||||
var myAnimeListJwt MyAnimeListJWT
|
||||
|
||||
var myAnimeListRing, _ = keyring.Open(keyring.Config{
|
||||
ServiceName: "AniTrack",
|
||||
KeychainName: "AniTrack",
|
||||
KeychainSynchronizable: false,
|
||||
KeychainTrustApplication: true,
|
||||
KeychainAccessibleWhenUnlocked: true,
|
||||
})
|
||||
var myAnimeListRing keyring.Keyring
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
myAnimeListRing, err = keyring.Open(keyring.Config{
|
||||
ServiceName: "AniTrack",
|
||||
KeychainName: "AniTrack",
|
||||
KeychainSynchronizable: false,
|
||||
KeychainTrustApplication: true,
|
||||
KeychainAccessibleWhenUnlocked: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("mal: secure storage unavailable: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func malRingReady() bool {
|
||||
if myAnimeListRing == nil {
|
||||
log.Println("mal: secure storage unavailable")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func malRingSet(key string, data []byte) error {
|
||||
if !malRingReady() {
|
||||
return errors.New("mal: secure storage unavailable")
|
||||
}
|
||||
if err := myAnimeListRing.Set(keyring.Item{Key: key, Data: data}); err != nil {
|
||||
log.Printf("mal: save %s failed: %s", key, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var myAnimeListCtxShutdown, myAnimeListCancel = context.WithCancel(context.Background())
|
||||
|
||||
@@ -72,6 +99,9 @@ func (v *CodeVerifier) CodeChallengeS256() string {
|
||||
|
||||
func (a *App) CheckIfMyAnimeListLoggedIn() bool {
|
||||
if (MyAnimeListJWT{} == myAnimeListJwt) {
|
||||
if !malRingReady() {
|
||||
return false
|
||||
}
|
||||
tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType")
|
||||
expiresIn, expiresInErr := myAnimeListRing.Get("MyAnimeListExpiresIn")
|
||||
accessToken, accessTokenErr := myAnimeListRing.Get("MyAnimeListAccessToken")
|
||||
@@ -83,7 +113,8 @@ func (a *App) CheckIfMyAnimeListLoggedIn() bool {
|
||||
myAnimeListJwt.TokenType = string(tokenType.Data)
|
||||
myAnimeListJwt.ExpiresIn, expiresInConvertErr = strconv.Atoi(string(expiresIn.Data))
|
||||
if expiresInConvertErr != nil {
|
||||
fmt.Println("unable to convert string to int")
|
||||
log.Printf("mal: invalid expiresIn %q: %s", string(expiresIn.Data), expiresInConvertErr)
|
||||
return false
|
||||
}
|
||||
myAnimeListJwt.AccessToken = string(accessToken.Data)
|
||||
myAnimeListJwt.RefreshToken = string(refreshToken.Data)
|
||||
@@ -97,6 +128,10 @@ func (a *App) CheckIfMyAnimeListLoggedIn() bool {
|
||||
func (a *App) MyAnimeListLogin() {
|
||||
if !a.CheckIfMyAnimeListLoggedIn() {
|
||||
fmt.Println("check logged in function failed")
|
||||
if !malRingReady() {
|
||||
log.Println("mal: cannot check login, secure storage unavailable")
|
||||
return
|
||||
}
|
||||
tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType")
|
||||
expiresIn, expiresInErr := myAnimeListRing.Get("MyAnimeListExpiresIn")
|
||||
accessToken, accessTokenErr := myAnimeListRing.Get("MyAnimeListAccessToken")
|
||||
@@ -114,7 +149,7 @@ func (a *App) MyAnimeListLogin() {
|
||||
myAnimeListJwt.TokenType = string(tokenType.Data)
|
||||
myAnimeListJwt.ExpiresIn, expiresInConvertErr = strconv.Atoi(string(expiresIn.Data))
|
||||
if expiresInConvertErr != nil {
|
||||
fmt.Println("unable to convert string to int in Login function")
|
||||
log.Printf("mal: invalid expiresIn %q: %s", string(expiresIn.Data), expiresInConvertErr)
|
||||
}
|
||||
myAnimeListJwt.AccessToken = string(accessToken.Data)
|
||||
myAnimeListJwt.RefreshToken = string(refreshToken.Data)
|
||||
@@ -136,22 +171,10 @@ func (a *App) handleMyAnimeListCallback(wg *sync.WaitGroup, verifier *CodeVerifi
|
||||
|
||||
if content != "" {
|
||||
myAnimeListJwt = getMyAnimeListAuthorizationToken(content, verifier)
|
||||
_ = myAnimeListRing.Set(keyring.Item{
|
||||
Key: "MyAnimeListTokenType",
|
||||
Data: []byte(myAnimeListJwt.TokenType),
|
||||
})
|
||||
_ = myAnimeListRing.Set(keyring.Item{
|
||||
Key: "MyAnimeListExpiresIn",
|
||||
Data: []byte(strconv.Itoa(myAnimeListJwt.ExpiresIn)),
|
||||
})
|
||||
_ = myAnimeListRing.Set(keyring.Item{
|
||||
Key: "MyAnimeListAccessToken",
|
||||
Data: []byte(myAnimeListJwt.AccessToken),
|
||||
})
|
||||
_ = myAnimeListRing.Set(keyring.Item{
|
||||
Key: "MyAnimeListRefreshToken",
|
||||
Data: []byte(myAnimeListJwt.RefreshToken),
|
||||
})
|
||||
_ = malRingSet("MyAnimeListTokenType", []byte(myAnimeListJwt.TokenType))
|
||||
_ = malRingSet("MyAnimeListExpiresIn", []byte(strconv.Itoa(myAnimeListJwt.ExpiresIn)))
|
||||
_ = malRingSet("MyAnimeListAccessToken", []byte(myAnimeListJwt.AccessToken))
|
||||
_ = malRingSet("MyAnimeListRefreshToken", []byte(myAnimeListJwt.RefreshToken))
|
||||
_, err := runtime.MessageDialog(*wailsContext, runtime.MessageDialogOptions{
|
||||
Title: "MyAnimeList Authorization",
|
||||
Message: "It is now safe to close your browser tab",
|
||||
@@ -292,22 +315,10 @@ func refreshMyAnimeListAuthorizationToken() bool {
|
||||
|
||||
myAnimeListJwt = refreshed
|
||||
|
||||
_ = myAnimeListRing.Set(keyring.Item{
|
||||
Key: "MyAnimeListTokenType",
|
||||
Data: []byte(myAnimeListJwt.TokenType),
|
||||
})
|
||||
_ = myAnimeListRing.Set(keyring.Item{
|
||||
Key: "MyAnimeListExpiresIn",
|
||||
Data: []byte(strconv.Itoa(myAnimeListJwt.ExpiresIn)),
|
||||
})
|
||||
_ = myAnimeListRing.Set(keyring.Item{
|
||||
Key: "MyAnimeListAccessToken",
|
||||
Data: []byte(myAnimeListJwt.AccessToken),
|
||||
})
|
||||
_ = myAnimeListRing.Set(keyring.Item{
|
||||
Key: "MyAnimeListRefreshToken",
|
||||
Data: []byte(myAnimeListJwt.RefreshToken),
|
||||
})
|
||||
_ = malRingSet("MyAnimeListTokenType", []byte(myAnimeListJwt.TokenType))
|
||||
_ = malRingSet("MyAnimeListExpiresIn", []byte(strconv.Itoa(myAnimeListJwt.ExpiresIn)))
|
||||
_ = malRingSet("MyAnimeListAccessToken", []byte(myAnimeListJwt.AccessToken))
|
||||
_ = malRingSet("MyAnimeListRefreshToken", []byte(myAnimeListJwt.RefreshToken))
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -367,12 +378,16 @@ func createUser() MyAnimeListUser {
|
||||
|
||||
func (a *App) LogoutMyAnimeList() string {
|
||||
if (MyAnimeListJWT{} != myAnimeListJwt) {
|
||||
if !malRingReady() {
|
||||
myAnimeListJwt = MyAnimeListJWT{}
|
||||
return "MAL Logged Out Successfully"
|
||||
}
|
||||
typeErr := myAnimeListRing.Remove("MyAnimeListTokenType")
|
||||
expiresInErr := myAnimeListRing.Remove("MyAnimeListExpiresIn")
|
||||
accessTokenErr := myAnimeListRing.Remove("MyAnimeListAccessToken")
|
||||
refreshTokenErr := myAnimeListRing.Remove("MyAnimeListRefreshToken")
|
||||
if typeErr != nil || expiresInErr != nil || accessTokenErr != nil || refreshTokenErr != nil {
|
||||
fmt.Println("MAL Logout Failed")
|
||||
log.Printf("mal: logout cleanup failed (type=%v expires=%v access=%v refresh=%v)", typeErr, expiresInErr, accessTokenErr, refreshTokenErr)
|
||||
}
|
||||
myAnimeListJwt = MyAnimeListJWT{}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user