Skip to content

Commit 8c75769

Browse files
UcnacDx2John Doe
authored andcommitted
test(drivers/139): cover live login authorization paths
1 parent 039773f commit 8c75769

2 files changed

Lines changed: 164 additions & 0 deletions

File tree

drivers/139/util.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,21 @@ func (d *Yun139) step2_get_single_token(sid string) (string, error) {
10351035

10361036
dycpwd := jsoniter.Get(res.Body(), "var", "artifact").ToString()
10371037
if dycpwd == "" {
1038+
code := jsoniter.Get(res.Body(), "code").ToString()
1039+
summary := jsoniter.Get(res.Body(), "summary").ToString()
1040+
if code == "" {
1041+
if match := regexp.MustCompile(`['"]code['"]\s*:\s*['"]([^'"]+)['"]`).FindSubmatch(res.Body()); len(match) == 2 {
1042+
code = string(match[1])
1043+
}
1044+
}
1045+
if summary == "" {
1046+
if match := regexp.MustCompile(`['"]summary['"]\s*:\s*['"]([^'"]+)['"]`).FindSubmatch(res.Body()); len(match) == 2 {
1047+
summary = string(match[1])
1048+
}
1049+
}
1050+
if code != "" || summary != "" {
1051+
return "", fmt.Errorf("failed to extract dycpwd from artifact exchange response: code=%s summary=%s", code, summary)
1052+
}
10381053
return "", errors.New("failed to extract dycpwd from artifact exchange response")
10391054
}
10401055
log.Debugf("DEBUG: dycpwd extracted from artifact exchange response.")
@@ -1376,6 +1391,9 @@ func (d *Yun139) credentialState() (credentialState, error) {
13761391
d.MailCookies = strings.TrimSpace(d.MailCookies)
13771392

13781393
if d.Authorization != "" {
1394+
if strings.HasPrefix(strings.ToLower(d.Authorization), "basic ") {
1395+
return 0, fmt.Errorf("authorization should not include Basic prefix")
1396+
}
13791397
return credentialStateAuthorization, nil
13801398
}
13811399

drivers/139/util_test.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ package _139
22

33
import (
44
"net/http"
5+
"os"
6+
"strings"
57
"testing"
8+
"time"
9+
10+
"github.com/OpenListTeam/OpenList/v4/drivers/base"
11+
"github.com/go-resty/resty/v2"
612
)
713

814
func TestSanitizeLoginCookiesReplacesJSessionIDAndOrdersAllowlist(t *testing.T) {
@@ -81,6 +87,11 @@ func TestCredentialState(t *testing.T) {
8187
d: Yun139{Addition: Addition{MailCookies: "invalid-cookie"}},
8288
err: true,
8389
},
90+
{
91+
name: "authorization with basic prefix",
92+
d: Yun139{Addition: Addition{Authorization: "Basic abc"}},
93+
err: true,
94+
},
8495
}
8596

8697
for _, tt := range tests {
@@ -102,6 +113,141 @@ func TestCredentialState(t *testing.T) {
102113
}
103114
}
104115

116+
func TestIntegrationLoginObtainsAuthorization(t *testing.T) {
117+
if os.Getenv("OPENLIST_139_INTEGRATION") != "1" {
118+
t.Skip("set OPENLIST_139_INTEGRATION=1 to run live 139Yun login checks")
119+
}
120+
base.RestyClient = resty.New().
121+
SetHeader("user-agent", base.UserAgent).
122+
SetRetryCount(3).
123+
SetRetryResetReaders(true).
124+
SetTimeout(30 * time.Second)
125+
126+
username := os.Getenv("OPENLIST_139_USERNAME")
127+
password := os.Getenv("OPENLIST_139_PASSWORD")
128+
mailCookies := os.Getenv("OPENLIST_139_MAIL_COOKIES")
129+
authorization := strings.TrimSpace(os.Getenv("OPENLIST_139_AUTHORIZATION"))
130+
131+
if authorization != "" {
132+
t.Run("authorization", func(t *testing.T) {
133+
d := Yun139{Addition: Addition{Authorization: authorization}}
134+
state, err := d.credentialState()
135+
if err != nil {
136+
t.Fatalf("credentialState() unexpected error: %v", err)
137+
}
138+
if state != credentialStateAuthorization {
139+
t.Fatalf("credentialState() = %v, want authorization", state)
140+
}
141+
if d.Authorization == "" || strings.HasPrefix(strings.ToLower(d.Authorization), "basic ") {
142+
t.Fatal("authorization should be present without Basic prefix")
143+
}
144+
})
145+
}
146+
147+
if mailCookies == "" {
148+
t.Fatal("OPENLIST_139_MAIL_COOKIES is required")
149+
}
150+
151+
runFastLogin := func(t *testing.T, mailCookies string) {
152+
t.Helper()
153+
d := Yun139{Addition: Addition{MailCookies: mailCookies}}
154+
state, err := d.credentialState()
155+
if err != nil {
156+
t.Fatalf("credentialState() unexpected error: %v", err)
157+
}
158+
if state != credentialStateCookiesOnly {
159+
t.Fatalf("credentialState() = %v, want cookies only", state)
160+
}
161+
sid, rmkey := extractFastLoginCookies(d.MailCookies)
162+
if sid == "" || rmkey == "" {
163+
t.Fatal("mail cookies are missing Os_SSo_Sid or RMKEY")
164+
}
165+
token, err := d.step2_get_single_token(sid)
166+
if err != nil {
167+
t.Fatalf("step2_get_single_token() error: %v", err)
168+
}
169+
auth, err := d.step3_third_party_login(token)
170+
if err != nil {
171+
t.Fatalf("step3_third_party_login() error: %v", err)
172+
}
173+
d.Authorization = auth
174+
if d.Authorization == "" {
175+
t.Fatal("authorization is empty after fast login")
176+
}
177+
}
178+
179+
if username == "" || password == "" {
180+
t.Fatal("OPENLIST_139_USERNAME and OPENLIST_139_PASSWORD are required for password fallback")
181+
}
182+
183+
var refreshedMailCookies string
184+
var generatedAuthorization string
185+
t.Run("password login fallback", func(t *testing.T) {
186+
d := Yun139{Addition: Addition{
187+
MailCookies: mailCookies,
188+
Username: username,
189+
Password: password,
190+
}}
191+
state, err := d.credentialState()
192+
if err != nil {
193+
t.Fatalf("credentialState() unexpected error: %v", err)
194+
}
195+
if state != credentialStateFullLogin {
196+
t.Fatalf("credentialState() = %v, want full login", state)
197+
}
198+
passId, err := d.step1_password_login()
199+
if err != nil {
200+
t.Fatalf("step1_password_login() error: %v", err)
201+
}
202+
token, err := d.step2_get_single_token(passId)
203+
if err != nil {
204+
t.Fatalf("step2_get_single_token() error: %v", err)
205+
}
206+
auth, err := d.step3_third_party_login(token)
207+
if err != nil {
208+
t.Fatalf("step3_third_party_login() error: %v", err)
209+
}
210+
d.Authorization = auth
211+
if auth == "" || d.Authorization == "" {
212+
t.Fatal("authorization is empty after password login")
213+
}
214+
generatedAuthorization = auth
215+
refreshedMailCookies = d.MailCookies
216+
})
217+
218+
t.Run("authorization generated by password login", func(t *testing.T) {
219+
if generatedAuthorization == "" {
220+
t.Fatal("password login did not generate authorization")
221+
}
222+
d := Yun139{Addition: Addition{Authorization: generatedAuthorization}}
223+
state, err := d.credentialState()
224+
if err != nil {
225+
t.Fatalf("credentialState() unexpected error: %v", err)
226+
}
227+
if state != credentialStateAuthorization {
228+
t.Fatalf("credentialState() = %v, want authorization", state)
229+
}
230+
if strings.HasPrefix(strings.ToLower(d.Authorization), "basic ") {
231+
t.Fatal("authorization should not include Basic prefix")
232+
}
233+
})
234+
235+
t.Run("mail cookies fast login from input", func(t *testing.T) {
236+
sid, rmkey := extractFastLoginCookies(mailCookies)
237+
if sid == "" || rmkey == "" {
238+
t.Skip("input mail cookies are missing Os_SSo_Sid or RMKEY")
239+
}
240+
runFastLogin(t, mailCookies)
241+
})
242+
243+
t.Run("mail cookies fast login after password login", func(t *testing.T) {
244+
if refreshedMailCookies == "" {
245+
t.Fatal("password login did not refresh mail cookies")
246+
}
247+
runFastLogin(t, refreshedMailCookies)
248+
})
249+
}
250+
105251
func TestIsRedirectStatus(t *testing.T) {
106252
for _, status := range []int{300, 301, 302, 307, 399} {
107253
if !isRedirectStatus(status) {

0 commit comments

Comments
 (0)