146 lines
4.6 KiB
Go
146 lines
4.6 KiB
Go
package bilibili
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"everypublish/server/internal/credentials"
|
|
"everypublish/server/internal/platform"
|
|
)
|
|
|
|
func TestQRLoginAndCredentialSave(t *testing.T) {
|
|
var poll int
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if strings.HasSuffix(r.URL.Path, "/generate") {
|
|
_, _ = w.Write([]byte(`{"code":0,"data":{"url":"https://qr.test/x","qrcode_key":"k"}}`))
|
|
return
|
|
}
|
|
poll++
|
|
switch poll {
|
|
case 1:
|
|
_, _ = w.Write([]byte(`{"code":86101}`))
|
|
case 2:
|
|
_, _ = w.Write([]byte(`{"code":86090}`))
|
|
default:
|
|
_, _ = w.Write([]byte(`{"code":0,"data":{"url":"https://passport.test/c?SESSDATA=s%2Bv&bili_jct=j%2Fv&DedeUserID=7"}}`))
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
dir := t.TempDir()
|
|
store, err := credentials.Open(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
a := New(store)
|
|
a.PassportBase = srv.URL
|
|
s, err := a.BeginLogin(context.Background())
|
|
if err != nil || s.Token != "k" {
|
|
t.Fatalf("begin: %#v %v", s, err)
|
|
}
|
|
p, err := a.PollLogin(context.Background(), s.Token)
|
|
if err != nil || p.State != platform.LoginPending {
|
|
t.Fatalf("pending: %#v %v", p, err)
|
|
}
|
|
p, err = a.PollLogin(context.Background(), s.Token)
|
|
if err != nil || p.State != platform.LoginScanned {
|
|
t.Fatalf("scanned: %#v %v", p, err)
|
|
}
|
|
p, err = a.PollLogin(context.Background(), s.Token)
|
|
if err != nil || p.Cookies != "SESSDATA=s+v; bili_jct=j/v; DedeUserID=7" {
|
|
t.Fatalf("confirmed: %#v %v", p, err)
|
|
}
|
|
if err := a.SaveCredentials(1, 2, p.Cookies); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := store.Load(1, 2)
|
|
if err != nil || string(got) != p.Cookies {
|
|
t.Fatalf("stored=%q err=%v", got, err)
|
|
}
|
|
}
|
|
|
|
func TestPublishUPOSUsesETagAndEncodedCSRF(t *testing.T) {
|
|
dir := t.TempDir()
|
|
store, err := credentials.Open(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = store.Save(1, 2, []byte("SESSDATA=s; bili_jct=a&b; DedeUserID=7")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var sawPart, sawMerge, sawSubmit bool
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
switch r.URL.Path {
|
|
case "/material":
|
|
_, _ = w.Write([]byte("video"))
|
|
case "/preupload":
|
|
_, _ = w.Write([]byte(`{"OK":1,"endpoint":"//` + r.Host + `","auth":"auth","biz_id":1,"upos_uri":"upos://folder/v.mp4","chunk_size":2}`))
|
|
case "/folder/v.mp4":
|
|
if r.Method == http.MethodPost && r.URL.Query().Has("uploads") {
|
|
_, _ = w.Write([]byte(`{"upload_id":"u1"}`))
|
|
} else if r.Method == http.MethodPut {
|
|
sawPart = true
|
|
w.Header().Set("ETag", `"real-etag"`)
|
|
w.WriteHeader(http.StatusOK)
|
|
} else if r.Method == http.MethodPost {
|
|
sawMerge = true
|
|
_, _ = w.Write([]byte(`{"OK":1}`))
|
|
}
|
|
case "/x/vu/web/add":
|
|
if r.URL.Query().Get("csrf") != "a&b" {
|
|
t.Errorf("csrf not decoded: %q", r.URL.RawQuery)
|
|
}
|
|
sawSubmit = true
|
|
_, _ = w.Write([]byte(`{"code":0,"data":{"bvid":"BV1"}}`))
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
a := New(store)
|
|
a.MemberBase = srv.URL
|
|
a.UpOSScheme = "http"
|
|
material := srv.URL + "/material"
|
|
result, err := a.Publish(context.Background(), platform.PublishInput{WorkspaceID: 1, AccountID: 2, Title: "title", Content: "body", MaterialURLs: []string{material}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result.URL != "https://www.bilibili.com/video/BV1" || !sawPart || !sawMerge || !sawSubmit {
|
|
t.Fatalf("result=%#v part=%v merge=%v submit=%v", result, sawPart, sawMerge, sawSubmit)
|
|
}
|
|
}
|
|
|
|
func TestSaveCredentialsRejectsIncompleteCookie(t *testing.T) {
|
|
store, err := credentials.Open(t.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := New(store).SaveCredentials(1, 1, "SESSDATA=only"); err == nil || platform.CategoryOf(err) != platform.Validation {
|
|
t.Fatalf("expected validation error for incomplete cookie, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCheckCredentialsUsesEncryptedCookieAndNavEndpoint(t *testing.T) {
|
|
store, err := credentials.Open(t.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = store.Save(1, 2, []byte("SESSDATA=s; bili_jct=j; DedeUserID=7")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/x/web-interface/nav" || r.Header.Get("Cookie") != "SESSDATA=s; bili_jct=j; DedeUserID=7" {
|
|
t.Fatalf("unexpected nav request: %s cookie=%q", r.URL.Path, r.Header.Get("Cookie"))
|
|
}
|
|
_, _ = w.Write([]byte(`{"code":0,"data":{"isLogin":true}}`))
|
|
}))
|
|
defer srv.Close()
|
|
a := New(store)
|
|
a.MemberBase = srv.URL
|
|
if err := a.CheckCredentials(context.Background(), 1, 2); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|