You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

132 rivejä
5.0 KiB

  1. package service
  2. import (
  3. "context"
  4. "io"
  5. "net/http"
  6. "net/http/httptest"
  7. "strings"
  8. "testing"
  9. "github.com/QuantumNous/new-api/common"
  10. "github.com/QuantumNous/new-api/model"
  11. "github.com/QuantumNous/new-api/setting/system_setting"
  12. "github.com/stretchr/testify/require"
  13. )
  14. func TestTianyiYunAssetAdapterCreateAssetMapsActionRequest(t *testing.T) {
  15. disableSSRFProtectionForTianyiYunAssetTest(t)
  16. server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  17. require.Equal(t, http.MethodPost, r.Method)
  18. require.Equal(t, "/v1/api/assets/upload", r.URL.Path)
  19. require.Equal(t, "Bearer key", r.Header.Get("Authorization"))
  20. body, err := io.ReadAll(r.Body)
  21. require.NoError(t, err)
  22. require.JSONEq(t, `{"url":"https://example.test/a.png","asset_type":"Image","name":"cover"}`, string(body))
  23. _, _ = w.Write([]byte(`{"code":0,"data":{"Id":"asset-1"}}`))
  24. }))
  25. defer server.Close()
  26. adapter := NewTianyiYunAssetAdapter()
  27. channel := &model.Channel{BaseURL: common.GetPointer(server.URL + "/v1"), Key: "key"}
  28. response, assetErr := adapter.DoAssetRequest(context.Background(), channel, AssetRequest{
  29. Action: AssetActionSpec{Action: "CreateAsset", Operation: AssetOperationAssetCreate},
  30. Body: map[string]any{"URL": "https://example.test/a.png", "AssetType": "Image", "Name": "cover"},
  31. })
  32. require.Nil(t, assetErr)
  33. require.Equal(t, http.StatusOK, response.StatusCode)
  34. require.JSONEq(t, `{"code":0,"data":{"Id":"asset-1"}}`, string(response.Body))
  35. }
  36. func TestTianyiYunAssetAdapterGetAssetMapsActionRequest(t *testing.T) {
  37. disableSSRFProtectionForTianyiYunAssetTest(t)
  38. server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  39. require.Equal(t, http.MethodGet, r.Method)
  40. require.Equal(t, "/v1/api/assets/asset-1%2Fpart", r.URL.EscapedPath())
  41. require.Equal(t, "Bearer key", r.Header.Get("Authorization"))
  42. body, err := io.ReadAll(r.Body)
  43. require.NoError(t, err)
  44. require.Empty(t, body)
  45. _, _ = w.Write([]byte(`{"code":0,"data":{"Id":"asset-1"}}`))
  46. }))
  47. defer server.Close()
  48. adapter := NewTianyiYunAssetAdapter()
  49. channel := &model.Channel{BaseURL: common.GetPointer(server.URL), Key: "key"}
  50. response, assetErr := adapter.DoAssetRequest(context.Background(), channel, AssetRequest{
  51. Action: AssetActionSpec{Action: "GetAsset", Operation: AssetOperationAssetGet},
  52. Body: map[string]any{"Id": "asset-1/part"},
  53. })
  54. require.Nil(t, assetErr)
  55. require.Equal(t, http.StatusOK, response.StatusCode)
  56. }
  57. func TestTianyiYunAssetAdapterRejectsInvalidCreateRequest(t *testing.T) {
  58. cases := []map[string]any{
  59. {"AssetType": "Image"},
  60. {"URL": "data:image/png;base64,AAAA", "AssetType": "Image"},
  61. {"URL": "aGVsbG8=", "AssetType": "Image"},
  62. {"URL": "ftp://example.test/a.png", "AssetType": "Image"},
  63. {"URL": "https://example.test/a.png", "AssetType": "Document"},
  64. }
  65. for _, body := range cases {
  66. t.Run("invalid", func(t *testing.T) {
  67. adapter := NewTianyiYunAssetAdapter()
  68. response, assetErr := adapter.DoAssetRequest(context.Background(), &model.Channel{Key: "key"}, AssetRequest{
  69. Action: AssetActionSpec{Action: "CreateAsset", Operation: AssetOperationAssetCreate}, Body: body,
  70. })
  71. require.Nil(t, response)
  72. require.NotNil(t, assetErr)
  73. require.Equal(t, http.StatusBadRequest, assetErr.HTTPStatus)
  74. })
  75. }
  76. }
  77. func disableSSRFProtectionForTianyiYunAssetTest(t *testing.T) {
  78. t.Helper()
  79. setting := system_setting.GetFetchSetting()
  80. old := *setting
  81. setting.EnableSSRFProtection = false
  82. t.Cleanup(func() { *setting = old })
  83. }
  84. func TestTianyiYunAssetAdapterRejectsPrivateSourceURL(t *testing.T) {
  85. setting := system_setting.GetFetchSetting()
  86. old := *setting
  87. setting.EnableSSRFProtection = true
  88. setting.AllowPrivateIp = false
  89. setting.DomainFilterMode = false
  90. setting.IpFilterMode = false
  91. setting.DomainList = nil
  92. setting.IpList = nil
  93. setting.AllowedPorts = []string{"80", "443", "8080", "8443"}
  94. t.Cleanup(func() { *setting = old })
  95. for _, sourceURL := range []string{"https://127.0.0.1/a.png", "http://10.0.0.1/a.png"} {
  96. t.Run(sourceURL, func(t *testing.T) {
  97. response, assetErr := NewTianyiYunAssetAdapter().DoAssetRequest(context.Background(), &model.Channel{Key: "key"}, AssetRequest{
  98. Action: AssetActionSpec{Action: "CreateAsset", Operation: AssetOperationAssetCreate},
  99. Body: map[string]any{"URL": sourceURL, "AssetType": "Image"},
  100. })
  101. require.Nil(t, response)
  102. require.NotNil(t, assetErr)
  103. require.Equal(t, http.StatusBadRequest, assetErr.HTTPStatus)
  104. })
  105. }
  106. }
  107. func TestTianyiYunAssetAdapterSupportsOnlyCreateAndGet(t *testing.T) {
  108. adapter := NewTianyiYunAssetAdapter()
  109. require.True(t, adapter.Supports(AssetOperationAssetCreate))
  110. require.True(t, adapter.Supports(AssetOperationAssetGet))
  111. require.False(t, adapter.Supports(AssetOperationAssetList))
  112. _, assetErr := adapter.DoAssetRequest(context.Background(), &model.Channel{Key: "key"}, AssetRequest{
  113. Action: AssetActionSpec{Operation: AssetOperationAssetList},
  114. })
  115. require.NotNil(t, assetErr)
  116. require.Equal(t, AssetErrorOperationNotSupported, assetErr.Type)
  117. require.True(t, strings.Contains(assetErr.Message, "not supported"))
  118. }