Compare commits
7
Commits
1.6.7
...
v2-final-1.6.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8df8dcce7 | ||
|
|
2bf8d3887e | ||
|
|
efe45f39e7 | ||
|
|
336a1f353f | ||
|
|
a19080ef39 | ||
|
|
2bddc6a224 | ||
|
|
3bf5d8290e |
@@ -80,10 +80,27 @@ jobs:
|
|||||||
go-version: '1.25'
|
go-version: '1.25'
|
||||||
cache-dependency-path: go.sum
|
cache-dependency-path: go.sum
|
||||||
|
|
||||||
|
- name: Cache Go build cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
# setup-go only caches modules (GOMODCACHE). This caches compiled
|
||||||
|
# packages (GOCACHE) so the cgo/WebKit compile goes incremental.
|
||||||
|
# restore-keys gives a close cache instead of a cold one when
|
||||||
|
# go.sum changes. First run after adding this still compiles cold
|
||||||
|
# (it saves); the payoff shows from the second run on.
|
||||||
|
path: ~/.cache/go-build
|
||||||
|
key: go-build-1.25-${{ runner.os }}-${{ hashFiles('go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
go-build-1.25-${{ runner.os }}-
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: '20'
|
||||||
|
# Caches npm's download cache keyed on the frontend lockfile, so
|
||||||
|
# the `npm install` inside `wails build` stops fetching cold.
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: frontend/package-lock.json
|
||||||
|
|
||||||
- name: Install Wails Linux build dependencies
|
- name: Install Wails Linux build dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -94,11 +111,23 @@ jobs:
|
|||||||
libgtk-3-dev libwebkit2gtk-4.1-dev \
|
libgtk-3-dev libwebkit2gtk-4.1-dev \
|
||||||
jq
|
jq
|
||||||
|
|
||||||
|
- name: Cache Wails CLI
|
||||||
|
uses: actions/cache@v4
|
||||||
|
id: wails-cli
|
||||||
|
with:
|
||||||
|
# The compiled CLI binary. Bump the key whenever the @version pin
|
||||||
|
# below changes, or the old CLI will be silently reused.
|
||||||
|
path: ~/go/bin/wails
|
||||||
|
key: wails-v2.15.0-${{ runner.os }}
|
||||||
|
|
||||||
- name: Install Wails CLI
|
- name: Install Wails CLI
|
||||||
|
if: steps.wails-cli.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
go install github.com/wailsapp/wails/v2/cmd/wails@v2.15.0
|
go install github.com/wailsapp/wails/v2/cmd/wails@v2.15.0
|
||||||
echo "${HOME}/go/bin" >> "${GITHUB_PATH}"
|
|
||||||
|
- name: Add Go bin to PATH
|
||||||
|
run: echo "${HOME}/go/bin" >> "${GITHUB_PATH}"
|
||||||
|
|
||||||
- name: Write environment.go from secrets
|
- name: Write environment.go from secrets
|
||||||
env:
|
env:
|
||||||
|
|||||||
+4
-1
@@ -23,10 +23,13 @@ go.work
|
|||||||
|
|
||||||
# ---> Wails
|
# ---> Wails
|
||||||
build/bin
|
build/bin
|
||||||
|
.task/
|
||||||
node_modules
|
node_modules
|
||||||
frontend/dist
|
frontend/dist
|
||||||
package.json.md5
|
package.json.md5
|
||||||
package-lock.json
|
# Root-level lockfile only: the frontend lockfile IS tracked so CI installs
|
||||||
|
# are reproducible and setup-node's npm cache has something to hash.
|
||||||
|
/package-lock.json
|
||||||
.idea
|
.idea
|
||||||
.env
|
.env
|
||||||
environment.go
|
environment.go
|
||||||
|
|||||||
+61
-26
@@ -19,18 +19,48 @@ import (
|
|||||||
|
|
||||||
var aniListJwt AniListJWT
|
var aniListJwt AniListJWT
|
||||||
|
|
||||||
var aniRing, _ = keyring.Open(keyring.Config{
|
var aniRing keyring.Keyring
|
||||||
ServiceName: "AniTrack",
|
|
||||||
KeychainName: "AniTrack",
|
func init() {
|
||||||
KeychainSynchronizable: false,
|
var err error
|
||||||
KeychainTrustApplication: true,
|
aniRing, err = keyring.Open(keyring.Config{
|
||||||
KeychainAccessibleWhenUnlocked: true,
|
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())
|
var aniCtxShutdown, aniCancel = context.WithCancel(context.Background())
|
||||||
|
|
||||||
func (a *App) CheckIfAniListLoggedIn() bool {
|
func (a *App) CheckIfAniListLoggedIn() bool {
|
||||||
if (AniListJWT{} == aniListJwt) {
|
if (AniListJWT{} == aniListJwt) {
|
||||||
|
if !aniRingReady() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
tokenType, tokenErr := aniRing.Get("anilistTokenType")
|
tokenType, tokenErr := aniRing.Get("anilistTokenType")
|
||||||
expiresIn, expiresInErr := aniRing.Get("anilistTokenExpiresIn")
|
expiresIn, expiresInErr := aniRing.Get("anilistTokenExpiresIn")
|
||||||
refreshToken, refreshTokenErr := aniRing.Get("anilistRefreshToken")
|
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 {
|
if (tokenErr != nil || expiresInErr != nil || refreshTokenErr != nil || accessTokenErr != nil) || len(accessToken.Data) == 0 {
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
|
var expiresInConvertErr error
|
||||||
aniListJwt.TokenType = string(tokenType.Data)
|
aniListJwt.TokenType = string(tokenType.Data)
|
||||||
aniListJwt.AccessToken = string(accessToken.Data)
|
aniListJwt.AccessToken = string(accessToken.Data)
|
||||||
aniListJwt.RefreshToken = string(refreshToken.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
|
return true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -51,6 +86,10 @@ func (a *App) CheckIfAniListLoggedIn() bool {
|
|||||||
|
|
||||||
func (a *App) AniListLogin() {
|
func (a *App) AniListLogin() {
|
||||||
if (AniListJWT{} == aniListJwt) {
|
if (AniListJWT{} == aniListJwt) {
|
||||||
|
if !aniRingReady() {
|
||||||
|
log.Println("anilist: cannot check login, secure storage unavailable")
|
||||||
|
return
|
||||||
|
}
|
||||||
tokenType, tokenErr := aniRing.Get("anilistTokenType")
|
tokenType, tokenErr := aniRing.Get("anilistTokenType")
|
||||||
expiresIn, expiresInErr := aniRing.Get("anilistTokenExpiresIn")
|
expiresIn, expiresInErr := aniRing.Get("anilistTokenExpiresIn")
|
||||||
refreshToken, refreshTokenErr := aniRing.Get("anilistRefreshToken")
|
refreshToken, refreshTokenErr := aniRing.Get("anilistRefreshToken")
|
||||||
@@ -64,10 +103,14 @@ func (a *App) AniListLogin() {
|
|||||||
a.handleAniListCallback(serverDone)
|
a.handleAniListCallback(serverDone)
|
||||||
serverDone.Wait()
|
serverDone.Wait()
|
||||||
} else {
|
} else {
|
||||||
|
var expiresInConvertErr error
|
||||||
aniListJwt.TokenType = string(tokenType.Data)
|
aniListJwt.TokenType = string(tokenType.Data)
|
||||||
aniListJwt.AccessToken = string(accessToken.Data)
|
aniListJwt.AccessToken = string(accessToken.Data)
|
||||||
aniListJwt.RefreshToken = string(refreshToken.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")
|
content := r.FormValue("code")
|
||||||
if content != "" {
|
if content != "" {
|
||||||
aniListJwt = getAniListAuthorizationToken(content)
|
aniListJwt = getAniListAuthorizationToken(content)
|
||||||
_ = aniRing.Set(keyring.Item{
|
_ = aniRingSet("anilistTokenType", []byte(aniListJwt.TokenType))
|
||||||
Key: "anilistTokenType",
|
_ = aniRingSet("anilistTokenExpiresIn", []byte(strconv.Itoa(aniListJwt.ExpiresIn)))
|
||||||
Data: []byte(aniListJwt.TokenType),
|
_ = aniRingSet("anilistAccessToken", []byte(aniListJwt.AccessToken))
|
||||||
})
|
_ = aniRingSet("anilistRefreshToken", []byte(aniListJwt.RefreshToken))
|
||||||
_ = 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),
|
|
||||||
})
|
|
||||||
_, err := runtime.MessageDialog(*wailsContext, runtime.MessageDialogOptions{
|
_, err := runtime.MessageDialog(*wailsContext, runtime.MessageDialogOptions{
|
||||||
Title: "AniList Authorization",
|
Title: "AniList Authorization",
|
||||||
Message: "It is now safe to close your browser tab",
|
Message: "It is now safe to close your browser tab",
|
||||||
@@ -208,12 +239,16 @@ func (a *App) GetAniListLoggedInUser() AniListUser {
|
|||||||
|
|
||||||
func (a *App) LogoutAniList() string {
|
func (a *App) LogoutAniList() string {
|
||||||
if (AniListJWT{} != aniListJwt) {
|
if (AniListJWT{} != aniListJwt) {
|
||||||
|
if !aniRingReady() {
|
||||||
|
aniListJwt = AniListJWT{}
|
||||||
|
return "AniList Logged Out Successfully"
|
||||||
|
}
|
||||||
typeErr := aniRing.Remove("anilistTokenType")
|
typeErr := aniRing.Remove("anilistTokenType")
|
||||||
expiresInErr := aniRing.Remove("anilistTokenExpiresIn")
|
expiresInErr := aniRing.Remove("anilistTokenExpiresIn")
|
||||||
accessTokenErr := aniRing.Remove("anilistAccessToken")
|
accessTokenErr := aniRing.Remove("anilistAccessToken")
|
||||||
refreshTokenErr := aniRing.Remove("anilistRefreshToken")
|
refreshTokenErr := aniRing.Remove("anilistRefreshToken")
|
||||||
if typeErr != nil || expiresInErr != nil || accessTokenErr != nil || refreshTokenErr != nil {
|
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{}
|
aniListJwt = AniListJWT{}
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-42
@@ -23,13 +23,40 @@ import (
|
|||||||
|
|
||||||
var myAnimeListJwt MyAnimeListJWT
|
var myAnimeListJwt MyAnimeListJWT
|
||||||
|
|
||||||
var myAnimeListRing, _ = keyring.Open(keyring.Config{
|
var myAnimeListRing keyring.Keyring
|
||||||
ServiceName: "AniTrack",
|
|
||||||
KeychainName: "AniTrack",
|
func init() {
|
||||||
KeychainSynchronizable: false,
|
var err error
|
||||||
KeychainTrustApplication: true,
|
myAnimeListRing, err = keyring.Open(keyring.Config{
|
||||||
KeychainAccessibleWhenUnlocked: true,
|
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())
|
var myAnimeListCtxShutdown, myAnimeListCancel = context.WithCancel(context.Background())
|
||||||
|
|
||||||
@@ -72,6 +99,9 @@ func (v *CodeVerifier) CodeChallengeS256() string {
|
|||||||
|
|
||||||
func (a *App) CheckIfMyAnimeListLoggedIn() bool {
|
func (a *App) CheckIfMyAnimeListLoggedIn() bool {
|
||||||
if (MyAnimeListJWT{} == myAnimeListJwt) {
|
if (MyAnimeListJWT{} == myAnimeListJwt) {
|
||||||
|
if !malRingReady() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType")
|
tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType")
|
||||||
expiresIn, expiresInErr := myAnimeListRing.Get("MyAnimeListExpiresIn")
|
expiresIn, expiresInErr := myAnimeListRing.Get("MyAnimeListExpiresIn")
|
||||||
accessToken, accessTokenErr := myAnimeListRing.Get("MyAnimeListAccessToken")
|
accessToken, accessTokenErr := myAnimeListRing.Get("MyAnimeListAccessToken")
|
||||||
@@ -83,7 +113,8 @@ func (a *App) CheckIfMyAnimeListLoggedIn() bool {
|
|||||||
myAnimeListJwt.TokenType = string(tokenType.Data)
|
myAnimeListJwt.TokenType = string(tokenType.Data)
|
||||||
myAnimeListJwt.ExpiresIn, expiresInConvertErr = strconv.Atoi(string(expiresIn.Data))
|
myAnimeListJwt.ExpiresIn, expiresInConvertErr = strconv.Atoi(string(expiresIn.Data))
|
||||||
if expiresInConvertErr != nil {
|
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.AccessToken = string(accessToken.Data)
|
||||||
myAnimeListJwt.RefreshToken = string(refreshToken.Data)
|
myAnimeListJwt.RefreshToken = string(refreshToken.Data)
|
||||||
@@ -97,6 +128,10 @@ func (a *App) CheckIfMyAnimeListLoggedIn() bool {
|
|||||||
func (a *App) MyAnimeListLogin() {
|
func (a *App) MyAnimeListLogin() {
|
||||||
if !a.CheckIfMyAnimeListLoggedIn() {
|
if !a.CheckIfMyAnimeListLoggedIn() {
|
||||||
fmt.Println("check logged in function failed")
|
fmt.Println("check logged in function failed")
|
||||||
|
if !malRingReady() {
|
||||||
|
log.Println("mal: cannot check login, secure storage unavailable")
|
||||||
|
return
|
||||||
|
}
|
||||||
tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType")
|
tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType")
|
||||||
expiresIn, expiresInErr := myAnimeListRing.Get("MyAnimeListExpiresIn")
|
expiresIn, expiresInErr := myAnimeListRing.Get("MyAnimeListExpiresIn")
|
||||||
accessToken, accessTokenErr := myAnimeListRing.Get("MyAnimeListAccessToken")
|
accessToken, accessTokenErr := myAnimeListRing.Get("MyAnimeListAccessToken")
|
||||||
@@ -114,7 +149,7 @@ func (a *App) MyAnimeListLogin() {
|
|||||||
myAnimeListJwt.TokenType = string(tokenType.Data)
|
myAnimeListJwt.TokenType = string(tokenType.Data)
|
||||||
myAnimeListJwt.ExpiresIn, expiresInConvertErr = strconv.Atoi(string(expiresIn.Data))
|
myAnimeListJwt.ExpiresIn, expiresInConvertErr = strconv.Atoi(string(expiresIn.Data))
|
||||||
if expiresInConvertErr != nil {
|
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.AccessToken = string(accessToken.Data)
|
||||||
myAnimeListJwt.RefreshToken = string(refreshToken.Data)
|
myAnimeListJwt.RefreshToken = string(refreshToken.Data)
|
||||||
@@ -136,22 +171,10 @@ func (a *App) handleMyAnimeListCallback(wg *sync.WaitGroup, verifier *CodeVerifi
|
|||||||
|
|
||||||
if content != "" {
|
if content != "" {
|
||||||
myAnimeListJwt = getMyAnimeListAuthorizationToken(content, verifier)
|
myAnimeListJwt = getMyAnimeListAuthorizationToken(content, verifier)
|
||||||
_ = myAnimeListRing.Set(keyring.Item{
|
_ = malRingSet("MyAnimeListTokenType", []byte(myAnimeListJwt.TokenType))
|
||||||
Key: "MyAnimeListTokenType",
|
_ = malRingSet("MyAnimeListExpiresIn", []byte(strconv.Itoa(myAnimeListJwt.ExpiresIn)))
|
||||||
Data: []byte(myAnimeListJwt.TokenType),
|
_ = malRingSet("MyAnimeListAccessToken", []byte(myAnimeListJwt.AccessToken))
|
||||||
})
|
_ = malRingSet("MyAnimeListRefreshToken", []byte(myAnimeListJwt.RefreshToken))
|
||||||
_ = 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),
|
|
||||||
})
|
|
||||||
_, err := runtime.MessageDialog(*wailsContext, runtime.MessageDialogOptions{
|
_, err := runtime.MessageDialog(*wailsContext, runtime.MessageDialogOptions{
|
||||||
Title: "MyAnimeList Authorization",
|
Title: "MyAnimeList Authorization",
|
||||||
Message: "It is now safe to close your browser tab",
|
Message: "It is now safe to close your browser tab",
|
||||||
@@ -292,22 +315,10 @@ func refreshMyAnimeListAuthorizationToken() bool {
|
|||||||
|
|
||||||
myAnimeListJwt = refreshed
|
myAnimeListJwt = refreshed
|
||||||
|
|
||||||
_ = myAnimeListRing.Set(keyring.Item{
|
_ = malRingSet("MyAnimeListTokenType", []byte(myAnimeListJwt.TokenType))
|
||||||
Key: "MyAnimeListTokenType",
|
_ = malRingSet("MyAnimeListExpiresIn", []byte(strconv.Itoa(myAnimeListJwt.ExpiresIn)))
|
||||||
Data: []byte(myAnimeListJwt.TokenType),
|
_ = malRingSet("MyAnimeListAccessToken", []byte(myAnimeListJwt.AccessToken))
|
||||||
})
|
_ = malRingSet("MyAnimeListRefreshToken", []byte(myAnimeListJwt.RefreshToken))
|
||||||
_ = 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),
|
|
||||||
})
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,12 +378,16 @@ func createUser() MyAnimeListUser {
|
|||||||
|
|
||||||
func (a *App) LogoutMyAnimeList() string {
|
func (a *App) LogoutMyAnimeList() string {
|
||||||
if (MyAnimeListJWT{} != myAnimeListJwt) {
|
if (MyAnimeListJWT{} != myAnimeListJwt) {
|
||||||
|
if !malRingReady() {
|
||||||
|
myAnimeListJwt = MyAnimeListJWT{}
|
||||||
|
return "MAL Logged Out Successfully"
|
||||||
|
}
|
||||||
typeErr := myAnimeListRing.Remove("MyAnimeListTokenType")
|
typeErr := myAnimeListRing.Remove("MyAnimeListTokenType")
|
||||||
expiresInErr := myAnimeListRing.Remove("MyAnimeListExpiresIn")
|
expiresInErr := myAnimeListRing.Remove("MyAnimeListExpiresIn")
|
||||||
accessTokenErr := myAnimeListRing.Remove("MyAnimeListAccessToken")
|
accessTokenErr := myAnimeListRing.Remove("MyAnimeListAccessToken")
|
||||||
refreshTokenErr := myAnimeListRing.Remove("MyAnimeListRefreshToken")
|
refreshTokenErr := myAnimeListRing.Remove("MyAnimeListRefreshToken")
|
||||||
if typeErr != nil || expiresInErr != nil || accessTokenErr != nil || refreshTokenErr != nil {
|
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{}
|
myAnimeListJwt = MyAnimeListJWT{}
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-20
@@ -17,18 +17,48 @@ import (
|
|||||||
|
|
||||||
var simklJwt SimklJWT
|
var simklJwt SimklJWT
|
||||||
|
|
||||||
var simklRing, _ = keyring.Open(keyring.Config{
|
var simklRing keyring.Keyring
|
||||||
ServiceName: "AniTrack",
|
|
||||||
KeychainName: "AniTrack",
|
func init() {
|
||||||
KeychainSynchronizable: false,
|
var err error
|
||||||
KeychainTrustApplication: true,
|
simklRing, err = keyring.Open(keyring.Config{
|
||||||
KeychainAccessibleWhenUnlocked: true,
|
ServiceName: "AniTrack",
|
||||||
})
|
KeychainName: "AniTrack",
|
||||||
|
KeychainSynchronizable: false,
|
||||||
|
KeychainTrustApplication: true,
|
||||||
|
KeychainAccessibleWhenUnlocked: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("simkl: secure storage unavailable: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func simklRingReady() bool {
|
||||||
|
if simklRing == nil {
|
||||||
|
log.Println("simkl: secure storage unavailable")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func simklRingSet(key string, data []byte) error {
|
||||||
|
if !simklRingReady() {
|
||||||
|
return errors.New("simkl: secure storage unavailable")
|
||||||
|
}
|
||||||
|
if err := simklRing.Set(keyring.Item{Key: key, Data: data}); err != nil {
|
||||||
|
log.Printf("simkl: save %s failed: %s", key, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var simklCtxShutdown, simklCancel = context.WithCancel(context.Background())
|
var simklCtxShutdown, simklCancel = context.WithCancel(context.Background())
|
||||||
|
|
||||||
func (a *App) CheckIfSimklLoggedIn() bool {
|
func (a *App) CheckIfSimklLoggedIn() bool {
|
||||||
if (SimklJWT{} == simklJwt) {
|
if (SimklJWT{} == simklJwt) {
|
||||||
|
if !simklRingReady() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
tokenType, tokenTypeErr := simklRing.Get("SimklTokenType")
|
tokenType, tokenTypeErr := simklRing.Get("SimklTokenType")
|
||||||
accessToken, accessTokenErr := simklRing.Get("SimklAccessToken")
|
accessToken, accessTokenErr := simklRing.Get("SimklAccessToken")
|
||||||
scope, scopeErr := simklRing.Get("SimklScope")
|
scope, scopeErr := simklRing.Get("SimklScope")
|
||||||
@@ -47,6 +77,10 @@ func (a *App) CheckIfSimklLoggedIn() bool {
|
|||||||
|
|
||||||
func (a *App) SimklLogin() {
|
func (a *App) SimklLogin() {
|
||||||
if !a.CheckIfSimklLoggedIn() {
|
if !a.CheckIfSimklLoggedIn() {
|
||||||
|
if !simklRingReady() {
|
||||||
|
log.Println("simkl: cannot check login, secure storage unavailable")
|
||||||
|
return
|
||||||
|
}
|
||||||
tokenType, tokenTypeErr := simklRing.Get("SimklTokenType")
|
tokenType, tokenTypeErr := simklRing.Get("SimklTokenType")
|
||||||
accessToken, accessTokenErr := simklRing.Get("SimklAccessToken")
|
accessToken, accessTokenErr := simklRing.Get("SimklAccessToken")
|
||||||
scope, scopeErr := simklRing.Get("SimklScope")
|
scope, scopeErr := simklRing.Get("SimklScope")
|
||||||
@@ -80,18 +114,9 @@ func (a *App) handleSimklCallback(wg *sync.WaitGroup) {
|
|||||||
|
|
||||||
if content != "" {
|
if content != "" {
|
||||||
simklJwt = getSimklAuthorizationToken(content)
|
simklJwt = getSimklAuthorizationToken(content)
|
||||||
_ = simklRing.Set(keyring.Item{
|
_ = simklRingSet("SimklTokenType", []byte(simklJwt.TokenType))
|
||||||
Key: "SimklTokenType",
|
_ = simklRingSet("SimklAccessToken", []byte(simklJwt.AccessToken))
|
||||||
Data: []byte(simklJwt.TokenType),
|
_ = simklRingSet("SimklScope", []byte(simklJwt.Scope))
|
||||||
})
|
|
||||||
_ = simklRing.Set(keyring.Item{
|
|
||||||
Key: "SimklAccessToken",
|
|
||||||
Data: []byte(simklJwt.AccessToken),
|
|
||||||
})
|
|
||||||
_ = simklRing.Set(keyring.Item{
|
|
||||||
Key: "SimklScope",
|
|
||||||
Data: []byte(simklJwt.Scope),
|
|
||||||
})
|
|
||||||
_, err := runtime.MessageDialog(*wailsContext, runtime.MessageDialogOptions{
|
_, err := runtime.MessageDialog(*wailsContext, runtime.MessageDialogOptions{
|
||||||
Title: "Simkl Authorization",
|
Title: "Simkl Authorization",
|
||||||
Message: "It is now safe to close your browser tab",
|
Message: "It is now safe to close your browser tab",
|
||||||
@@ -218,12 +243,16 @@ func (a *App) GetSimklLoggedInUser() SimklUser {
|
|||||||
|
|
||||||
func (a *App) LogoutSimkl() string {
|
func (a *App) LogoutSimkl() string {
|
||||||
if (SimklJWT{} != simklJwt) {
|
if (SimklJWT{} != simklJwt) {
|
||||||
|
if !simklRingReady() {
|
||||||
|
simklJwt = SimklJWT{}
|
||||||
|
return "Simkl Logged Out Successfully"
|
||||||
|
}
|
||||||
tokenTypeErr := simklRing.Remove("SimklTokenType")
|
tokenTypeErr := simklRing.Remove("SimklTokenType")
|
||||||
accessTokenErr := simklRing.Remove("SimklAccessToken")
|
accessTokenErr := simklRing.Remove("SimklAccessToken")
|
||||||
scopeErr := simklRing.Remove("SimklScope")
|
scopeErr := simklRing.Remove("SimklScope")
|
||||||
|
|
||||||
if tokenTypeErr != nil || accessTokenErr != nil || scopeErr != nil {
|
if tokenTypeErr != nil || accessTokenErr != nil || scopeErr != nil {
|
||||||
fmt.Println("Simkl Logout Failed")
|
log.Printf("simkl: logout cleanup failed (type=%v access=%v scope=%v)", tokenTypeErr, accessTokenErr, scopeErr)
|
||||||
}
|
}
|
||||||
simklJwt = SimklJWT{}
|
simklJwt = SimklJWT{}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+2717
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -12,6 +12,6 @@
|
|||||||
},
|
},
|
||||||
"info": {
|
"info": {
|
||||||
"productName": "AniTrack",
|
"productName": "AniTrack",
|
||||||
"productVersion": "1.6.7"
|
"productVersion": "1.6.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user