From 67387ff3508dbbbf084dcce5dd21bcce6e36ef73 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Mon, 15 Jun 2026 12:20:40 +0700 Subject: [PATCH] fix(gold): parse VNAppMob JWT object wrapper --- internal/modules/gold/vnappmob_client.go | 16 ++++++-- internal/modules/gold/vnappmob_client_test.go | 39 +++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/internal/modules/gold/vnappmob_client.go b/internal/modules/gold/vnappmob_client.go index 7a7c83a..51bb66b 100644 --- a/internal/modules/gold/vnappmob_client.go +++ b/internal/modules/gold/vnappmob_client.go @@ -232,11 +232,19 @@ func (c *VNAppMobClient) refreshKeyLocked(ctx context.Context) error { if err != nil { return fmt.Errorf("vnappmob: refresh read body: %w", err) } - // The endpoint may return either a JSON-quoted string or a raw JWT. + // The live endpoint wraps the JWT in {"results":""}. Keep fallbacks + // for a JSON-quoted string or a raw JWT in case the format changes. token = strings.TrimSpace(string(body)) - var quoted string - if err := json.Unmarshal(body, "ed); err == nil { - token = strings.TrimSpace(quoted) + var wrapped struct { + Results string `json:"results"` + } + if err := json.Unmarshal(body, &wrapped); err == nil { + token = strings.TrimSpace(wrapped.Results) + } else { + var quoted string + if err := json.Unmarshal(body, "ed); err == nil { + token = strings.TrimSpace(quoted) + } } if token == "" { return fmt.Errorf("vnappmob: refresh returned empty token") diff --git a/internal/modules/gold/vnappmob_client_test.go b/internal/modules/gold/vnappmob_client_test.go index ab67871..188cf7d 100644 --- a/internal/modules/gold/vnappmob_client_test.go +++ b/internal/modules/gold/vnappmob_client_test.go @@ -141,6 +141,45 @@ func TestRefreshKey(t *testing.T) { } } +func TestRefreshKey_ObjectWrapper(t *testing.T) { + exp := time.Unix(1000, 0).Add(14 * 24 * time.Hour).Unix() + jwt := makeJWT(exp) + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/api/request_api_key" { + t.Errorf("refresh path: got %s", r.URL.Path) + } + fmt.Fprintf(w, `{"results":%q}`, jwt) + })) + defer srv.Close() + + c := newTestVNAppMobClient(srv, storage.NewMemoryKVStore()) + key, err := c.getKey(context.Background()) + if err != nil { + t.Fatalf("getKey: %v", err) + } + if key != jwt { + t.Fatalf("key mismatch: got %q, want %q", key, jwt) + } +} + +func TestRefreshKey_QuotedString(t *testing.T) { + exp := time.Unix(1000, 0).Add(14 * 24 * time.Hour).Unix() + jwt := makeJWT(exp) + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "%q", jwt) + })) + defer srv.Close() + + c := newTestVNAppMobClient(srv, storage.NewMemoryKVStore()) + key, err := c.getKey(context.Background()) + if err != nil { + t.Fatalf("getKey: %v", err) + } + if key != jwt { + t.Fatalf("key mismatch: got %q, want %q", key, jwt) + } +} + func TestFetchSJCPrice(t *testing.T) { exp := time.Unix(1000, 0).Add(14 * 24 * time.Hour).Unix() srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {