Files
EveryPublish/server/internal/platform/bilibili/bilibili_test.go
T

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)
}
}