Files
wehub-resource-sync bf9395e022
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:22:54 +08:00

80 lines
2.2 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package auth
import (
"encoding/json"
"fmt"
"time"
"github.com/larksuite/cli/internal/keychain"
)
// StoredUAToken represents a stored user access token.
type StoredUAToken struct {
UserOpenId string `json:"userOpenId"`
AppId string `json:"appId"`
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
ExpiresAt int64 `json:"expiresAt"` // Unix ms
RefreshExpiresAt int64 `json:"refreshExpiresAt"` // Unix ms
Scope string `json:"scope"`
GrantedAt int64 `json:"grantedAt"` // Unix ms
}
const refreshAheadMs = 5 * 60 * 1000 // 5 minutes
// accountKey generates a unique key for an account based on its AppID and UserOpenID.
func accountKey(appId, userOpenId string) string {
return fmt.Sprintf("%s:%s", appId, userOpenId)
}
// MaskToken masks a token for safe logging.
func MaskToken(token string) string {
if len(token) <= 8 {
return "****"
}
return "****" + token[len(token)-4:]
}
// GetStoredToken reads the stored UAT for a given (appId, userOpenId) pair.
func GetStoredToken(appId, userOpenId string) *StoredUAToken {
jsonStr, err := keychain.Get(keychain.LarkCliService, accountKey(appId, userOpenId))
if err != nil || jsonStr == "" {
return nil
}
var token StoredUAToken
if err := json.Unmarshal([]byte(jsonStr), &token); err != nil {
return nil
}
return &token
}
// SetStoredToken persists a UAT.
func SetStoredToken(token *StoredUAToken) error {
key := accountKey(token.AppId, token.UserOpenId)
data, err := json.Marshal(token)
if err != nil {
return err
}
return keychain.Set(keychain.LarkCliService, key, string(data))
}
// RemoveStoredToken removes a stored UAT.
func RemoveStoredToken(appId, userOpenId string) error {
return keychain.Remove(keychain.LarkCliService, accountKey(appId, userOpenId))
}
// TokenStatus determines the freshness of a stored token.
func TokenStatus(token *StoredUAToken) string {
now := time.Now().UnixMilli()
if now < token.ExpiresAt-refreshAheadMs {
return "valid"
}
if now < token.RefreshExpiresAt {
return "needs_refresh"
}
return "expired"
}