Files
ragflow/internal/parser/parser/pptx_tcadp.go
Jin Hai b058229ab3 Go: fix SSRF (#17641)
### Summary

Check the URL to prevent SSRF attack.

---------

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-07-31 19:15:38 +08:00

96 lines
3.2 KiB
Go

package parser
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
models "ragflow/internal/entity/models"
)
// parsePresentationWithTCADP sends binary presentation (PPTX/PPT) data
// to the TCADP cloud reconstruction service and returns the structured
// parse result. Mirrors the spreadsheet-family parseSpreadsheetWithTCADP
// in xls_tcadp.go
func parsePresentationWithTCADP(ctx context.Context, filename string, data []byte, fileType string,
tcadpAPIServer, tcadpAPIKey, tableResultType, markdownImageResponseType string,
outputFormat string,
) ParseResult {
if len(data) == 0 {
return emptyPDFResult(filename)
}
baseURL := strings.TrimSpace(tcadpAPIServer)
if baseURL == "" {
baseURL = strings.TrimSpace(os.Getenv("TCADP_APISERVER"))
}
if baseURL == "" {
return ParseResult{Err: fmt.Errorf("parser: TCADP requires tcadp_apiserver or TCADP_APISERVER")}
}
apiKey := strings.TrimSpace(tcadpAPIKey)
if apiKey == "" {
apiKey = strings.TrimSpace(os.Getenv("TCADP_API_KEY"))
}
requestBody := map[string]any{
"file_type": fileType,
"file_base64": base64.StdEncoding.EncodeToString(data),
"file_start_page_number": 1,
"file_end_page_number": 1000,
"config": map[string]any{
"TableResultType": tableResultType,
"MarkdownImageResponseType": markdownImageResponseType,
},
}
resp, err := models.PostJSONRequest(ctx, models.NewDriverHTTPClient(false),
strings.TrimRight(baseURL, "/")+"/reconstruct_document", bearer(apiKey), requestBody)
if err != nil {
return ParseResult{Err: fmt.Errorf("parser: TCADP submit: %w", err)}
}
defer resp.Body.Close()
raw, err := io.ReadAll(resp.Body)
if err != nil {
return ParseResult{Err: fmt.Errorf("parser: TCADP read submit: %w", err)}
}
if resp.StatusCode >= 300 {
return ParseResult{Err: fmt.Errorf("parser: TCADP HTTP %d: %s", resp.StatusCode, string(raw))}
}
var payload struct {
DocumentRecognizeResultURL string `json:"DocumentRecognizeResultUrl"`
}
if err := json.Unmarshal(raw, &payload); err != nil {
return ParseResult{Err: fmt.Errorf("parser: TCADP decode submit: %w", err)}
}
if payload.DocumentRecognizeResultURL == "" {
return ParseResult{Err: fmt.Errorf("parser: TCADP returned no DocumentRecognizeResultUrl")}
}
downloadReq, err := http.NewRequestWithContext(ctx, http.MethodGet,
payload.DocumentRecognizeResultURL, nil)
if err != nil {
return ParseResult{Err: fmt.Errorf("parser: TCADP download request: %w", err)}
}
if auth := bearer(apiKey); auth != "" {
downloadReq.Header.Set("Authorization", auth)
}
downloadResp, err := models.NewDriverHTTPClient(false).Do(downloadReq)
if err != nil {
return ParseResult{Err: fmt.Errorf("parser: TCADP download: %w", err)}
}
defer downloadResp.Body.Close()
zipBytes, err := io.ReadAll(downloadResp.Body)
if err != nil {
return ParseResult{Err: fmt.Errorf("parser: TCADP read zip: %w", err)}
}
if downloadResp.StatusCode >= 300 {
return ParseResult{Err: fmt.Errorf("parser: TCADP download HTTP %d: %s", downloadResp.StatusCode, string(zipBytes))}
}
items, pageCount, err := tcadpItemsFromZip(zipBytes)
if err != nil {
return ParseResult{Err: err}
}
return pdfItemsToResult(filename, items, outputFormat, pageCount)
}