11package _123_open
22
33import (
4- "encoding/json"
54 "errors"
65 "fmt"
76 "net/http"
@@ -13,10 +12,16 @@ import (
1312)
1413
1514var (
16- AccessToken = "https://open-api.123pan.com/api/v1/access_token"
17- RefreshToken = "https://open-api.123pan.com/api/v1/oauth2/access_token"
15+ AccessToken = "https://open-api.123pan.com/api/v1/access_token"
1816)
1917
18+ func expiresInToExpiredAt (expiresIn int64 ) (time.Time , error ) {
19+ if expiresIn <= 0 {
20+ return time.Time {}, errors .New ("invalid expires_in from official API" )
21+ }
22+ return time .Now ().UTC ().Add (time .Duration (expiresIn ) * time .Second ), nil
23+ }
24+
2025type tokenManager struct {
2126 // accessToken string
2227 expiredAt time.Time
@@ -43,73 +48,82 @@ func (d *Open123) getAccessToken(forceRefresh bool) (string, error) {
4348}
4449
4550func (d * Open123 ) flushAccessToken () error {
46- // directly send request to avoid deadlock
47- req := base .RestyClient .R ()
48- req .SetHeaders (map [string ]string {
49- "authorization" : "Bearer " + d .AccessToken ,
50- "platform" : "open_platform" ,
51- "Content-Type" : "application/json" ,
52- })
51+ // Official app renewapi response contains access_token, refresh_token and expires_in.
52+ if d .UseOnlineAPI && d .RefreshToken != "" && len (d .APIAddress ) > 0 {
53+ var resp RefreshTokenResp
54+ _ , err := base .RestyClient .R ().
55+ SetResult (& resp ).
56+ SetQueryParams (map [string ]string {
57+ "refresh_ui" : d .RefreshToken ,
58+ "server_use" : "true" ,
59+ "driver_txt" : "123cloud_oa" ,
60+ }).
61+ Get (d .APIAddress )
62+ if err != nil {
63+ return err
64+ }
5365
54- if d .ClientID != "" {
55- if d .RefreshToken != "" {
56- var resp RefreshTokenResp
57- req .SetQueryParam ("client_id" , d .ClientID )
58- if d .ClientSecret != "" {
59- req .SetQueryParam ("client_secret" , d .ClientSecret )
66+ if resp .AccessToken == "" || resp .RefreshToken == "" {
67+ errMessage := resp .ErrorDescription
68+ if errMessage == "" {
69+ errMessage = resp .Text
6070 }
61- req .SetQueryParam ("grant_type" , "refresh_token" )
62- req .SetQueryParam ("refresh_token" , d .RefreshToken )
63- req .SetResult (& resp )
64- res , err := req .Execute (http .MethodPost , RefreshToken )
65- if err != nil {
66- return err
71+ if errMessage == "" {
72+ errMessage = resp .Message
6773 }
68- body := res .Body ()
69- var baseResp BaseResp
70- if err = json .Unmarshal (body , & baseResp ); err != nil {
71- return err
74+ if errMessage == "" {
75+ errMessage = resp .Error
7276 }
73- if baseResp . Code != 0 {
74- return fmt .Errorf ("get access token failed : %s" , baseResp . Message )
77+ if errMessage != "" {
78+ return fmt .Errorf ("failed to refresh token : %s" , errMessage )
7579 }
80+ return fmt .Errorf ("empty access_token or refresh_token returned from official API" )
81+ }
82+ expiredAt , err := expiresInToExpiredAt (resp .ExpiresIn )
83+ if err != nil {
84+ return err
85+ }
7686
77- d .AccessToken = resp .AccessToken
78- // add token expire time
79- d .tm .expiredAt = time .Now ().Add (time .Duration (resp .ExpiresIn ) * time .Second )
80- d .RefreshToken = resp .RefreshToken
81- op .MustSaveDriverStorage (d )
82- d .tm .blockRefresh = false
83- return nil
84- } else if d .ClientSecret != "" {
85- var resp AccessTokenResp
86- req .SetBody (base.Json {
87- "clientID" : d .ClientID ,
88- "clientSecret" : d .ClientSecret ,
89- })
90- req .SetResult (& resp )
91- res , err := req .Execute (http .MethodPost , AccessToken )
92- if err != nil {
93- return err
94- }
95- body := res .Body ()
96- var baseResp BaseResp
97- if err = json .Unmarshal (body , & baseResp ); err != nil {
98- return err
99- }
100- if baseResp .Code != 0 {
101- return fmt .Errorf ("get access token failed: %s" , baseResp .Message )
102- }
103- d .AccessToken = resp .Data .AccessToken
104- // parse token expire time
105- d .tm .expiredAt , err = time .Parse (time .RFC3339 , resp .Data .ExpiredAt )
106- if err != nil {
107- return fmt .Errorf ("parse expire time failed: %w" , err )
108- }
109- op .MustSaveDriverStorage (d )
110- d .tm .blockRefresh = false
111- return nil
87+ d .AccessToken = resp .AccessToken
88+ d .RefreshToken = resp .RefreshToken
89+ d .tm .expiredAt = expiredAt
90+ op .MustSaveDriverStorage (d )
91+ d .tm .blockRefresh = false
92+ return nil
93+ }
94+
95+ // Developer API response contains code/message/data(accessToken, expiredAt).
96+ if d .ClientID != "" && d .ClientSecret != "" {
97+ req := base .RestyClient .R ()
98+ req .SetHeaders (map [string ]string {
99+ "platform" : "open_platform" ,
100+ "Content-Type" : "application/json" ,
101+ })
102+ var resp AccessTokenResp
103+ req .SetBody (base.Json {
104+ "clientID" : d .ClientID ,
105+ "clientSecret" : d .ClientSecret ,
106+ })
107+ req .SetResult (& resp )
108+ _ , err := req .Execute (http .MethodPost , AccessToken )
109+ if err != nil {
110+ return err
111+ }
112+ if resp .Code != 0 {
113+ return fmt .Errorf ("get access token failed: %s" , resp .Message )
114+ }
115+ if resp .Data .AccessToken == "" || resp .Data .ExpiredAt == "" {
116+ return errors .New ("invalid token payload from developer API" )
117+ }
118+ expiredAt , err := time .Parse (time .RFC3339 , resp .Data .ExpiredAt )
119+ if err != nil {
120+ return fmt .Errorf ("parse expire time failed: %w" , err )
112121 }
122+ d .AccessToken = resp .Data .AccessToken
123+ d .tm .expiredAt = expiredAt .UTC ()
124+ op .MustSaveDriverStorage (d )
125+ d .tm .blockRefresh = false
126+ return nil
113127 }
114128 return errors .New ("no valid authentication method available" )
115129}
0 commit comments