mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-16 20:57:21 +08:00
This PR migrates the Box web OAuth flow from Python to Go for: - POST /api/v1/connectors/box/oauth/web/start - GET /api/v1/connectors/box/oauth/web/callback - POST /api/v1/connectors/box/oauth/web/result
172 lines
4.7 KiB
Go
172 lines
4.7 KiB
Go
package service
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"ragflow/internal/common"
|
|
redisengine "ragflow/internal/engine/redis"
|
|
)
|
|
|
|
type roundTripFunc func(*http.Request) (*http.Response, error)
|
|
|
|
func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return f(req)
|
|
}
|
|
|
|
func forceNilConnectorRedis(t *testing.T) {
|
|
t.Helper()
|
|
previous := connectorRedisGet
|
|
connectorRedisGet = func() *redisengine.RedisClient { return nil }
|
|
t.Cleanup(func() {
|
|
connectorRedisGet = previous
|
|
})
|
|
}
|
|
|
|
func TestBuildBoxAuthorizationURL(t *testing.T) {
|
|
authURL, err := buildBoxAuthorizationURL("client-1", "http://localhost/callback", "flow-1")
|
|
if err != nil {
|
|
t.Fatalf("buildBoxAuthorizationURL: %v", err)
|
|
}
|
|
|
|
parsed, err := url.Parse(authURL)
|
|
if err != nil {
|
|
t.Fatalf("parse auth url: %v", err)
|
|
}
|
|
if got := parsed.Scheme + "://" + parsed.Host + parsed.Path; got != boxOAuthAuthorizeURL {
|
|
t.Fatalf("base url=%q want=%q", got, boxOAuthAuthorizeURL)
|
|
}
|
|
|
|
query := parsed.Query()
|
|
if query.Get("client_id") != "client-1" {
|
|
t.Fatalf("client_id=%q", query.Get("client_id"))
|
|
}
|
|
if query.Get("redirect_uri") != "http://localhost/callback" {
|
|
t.Fatalf("redirect_uri=%q", query.Get("redirect_uri"))
|
|
}
|
|
if query.Get("response_type") != "code" {
|
|
t.Fatalf("response_type=%q", query.Get("response_type"))
|
|
}
|
|
if query.Get("state") != "flow-1" {
|
|
t.Fatalf("state=%q", query.Get("state"))
|
|
}
|
|
}
|
|
|
|
func TestRenderWebOAuthPopupBoxPayload(t *testing.T) {
|
|
html := renderWebOAuthPopup("flow-1", true, "Authorization completed successfully.", "box")
|
|
|
|
for _, want := range []string{
|
|
"Box Authorization",
|
|
"Authorization complete",
|
|
"ragflow-box-oauth",
|
|
`"status":"success"`,
|
|
`"flowId":"flow-1"`,
|
|
"window.close();",
|
|
} {
|
|
if !strings.Contains(html, want) {
|
|
t.Fatalf("popup html missing %q:\n%s", want, html)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDefaultBoxWebOAuthRedirectURI(t *testing.T) {
|
|
t.Setenv("BOX_WEB_OAUTH_REDIRECT_URI", "http://example.test/box/callback")
|
|
|
|
if got := defaultBoxWebOAuthRedirectURI(); got != "http://example.test/box/callback" {
|
|
t.Fatalf("redirect uri=%q", got)
|
|
}
|
|
}
|
|
|
|
func TestExchangeBoxAuthorizationCodeRequestBody(t *testing.T) {
|
|
oldClient := http.DefaultClient
|
|
t.Cleanup(func() { http.DefaultClient = oldClient })
|
|
|
|
var form url.Values
|
|
http.DefaultClient = &http.Client{
|
|
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
|
|
if req.Method != http.MethodPost {
|
|
t.Fatalf("method=%s", req.Method)
|
|
}
|
|
if req.URL.String() != boxOAuthTokenURL {
|
|
t.Fatalf("url=%s", req.URL.String())
|
|
}
|
|
if got := req.Header.Get("Content-Type"); got != "application/x-www-form-urlencoded" {
|
|
t.Fatalf("content-type=%q", got)
|
|
}
|
|
|
|
body, err := io.ReadAll(req.Body)
|
|
if err != nil {
|
|
t.Fatalf("read body: %v", err)
|
|
}
|
|
form, err = url.ParseQuery(string(body))
|
|
if err != nil {
|
|
t.Fatalf("parse body: %v", err)
|
|
}
|
|
|
|
return &http.Response{
|
|
StatusCode: http.StatusOK,
|
|
Header: make(http.Header),
|
|
Body: io.NopCloser(strings.NewReader(`{"access_token":"access-1","refresh_token":"refresh-1"}`)),
|
|
}, nil
|
|
}),
|
|
}
|
|
|
|
token, err := exchangeBoxAuthorizationCode("client-1", "secret-1", "http://localhost/callback", "code-1")
|
|
if err != nil {
|
|
t.Fatalf("exchangeBoxAuthorizationCode: %v", err)
|
|
}
|
|
if token.AccessToken != "access-1" || token.RefreshToken != "refresh-1" {
|
|
t.Fatalf("token=%#v", token)
|
|
}
|
|
|
|
want := map[string]string{
|
|
"grant_type": "authorization_code",
|
|
"code": "code-1",
|
|
"client_id": "client-1",
|
|
"client_secret": "secret-1",
|
|
}
|
|
for key, value := range want {
|
|
if form.Get(key) != value {
|
|
t.Fatalf("%s=%q want=%q", key, form.Get(key), value)
|
|
}
|
|
}
|
|
if got := form.Get("redirect_uri"); got != "" {
|
|
t.Fatalf("redirect_uri should not be sent to Box token endpoint, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestStartBoxWebOAuthRequiresClientCredentials(t *testing.T) {
|
|
svc := NewConnectorService()
|
|
|
|
_, code, err := svc.StartBoxWebOAuth("user-1", &StartBoxWebOAuthRequest{ClientID: "client-1"})
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
if code != common.CodeArgumentError {
|
|
t.Fatalf("code=%v want=%v", code, common.CodeArgumentError)
|
|
}
|
|
if err.Error() != "Box client_id and client_secret are required." {
|
|
t.Fatalf("error=%q", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestPollBoxWebOAuthResultPendingWithoutRedis(t *testing.T) {
|
|
forceNilConnectorRedis(t)
|
|
|
|
svc := NewConnectorService()
|
|
|
|
_, code, err := svc.PollBoxWebOAuthResult("user-1", &PollBoxWebOAuthResultRequest{FlowID: "flow-1"})
|
|
if err == nil {
|
|
t.Fatal("expected pending error")
|
|
}
|
|
if code != common.CodeRunning {
|
|
t.Fatalf("code=%v want=%v", code, common.CodeRunning)
|
|
}
|
|
if err.Error() != "Authorization is still pending." {
|
|
t.Fatalf("error=%q", err.Error())
|
|
}
|
|
}
|