123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- package python
- import (
- "crypto/rand"
- _ "embed"
- "encoding/base64"
- "fmt"
- "os"
- "os/exec"
- "path"
- "strconv"
- "strings"
- "time"
- "github.com/google/uuid"
- "github.com/langgenius/dify-sandbox/internal/core/runner"
- "github.com/langgenius/dify-sandbox/internal/core/runner/types"
- "github.com/langgenius/dify-sandbox/internal/static"
- )
- type PythonRunner struct {
- runner.TempDirRunner
- }
- //go:embed prescript.py
- var sandbox_fs []byte
- var (
- REQUIRED_FS = []string{
- path.Join(LIB_PATH, LIB_NAME),
- }
- )
- func (p *PythonRunner) Run(
- code string,
- timeout time.Duration,
- stdin []byte,
- preload string,
- options *types.RunnerOptions,
- ) (chan []byte, chan []byte, chan bool, error) {
- configuration := static.GetDifySandboxGlobalConfigurations()
- // initialize the environment
- untrusted_code_path, key, err := p.InitializeEnvironment(code, preload, options)
- if err != nil {
- return nil, nil, nil, err
- }
- // capture the output
- output_handler := runner.NewOutputCaptureRunner()
- output_handler.SetTimeout(timeout)
- err = p.WithTempDir(LIB_PATH, REQUIRED_FS, func(root_path string) error {
- // cleanup
- output_handler.SetAfterExitHook(func() {
- os.RemoveAll(root_path)
- os.Remove(root_path)
- })
- // create a new process
- cmd := exec.Command(
- configuration.PythonPath,
- untrusted_code_path,
- LIB_PATH,
- key,
- )
- cmd.Env = []string{}
- if configuration.Proxy.Socks5 != "" {
- cmd.Env = append(cmd.Env, fmt.Sprintf("HTTPS_PROXY=%s", configuration.Proxy.Socks5))
- cmd.Env = append(cmd.Env, fmt.Sprintf("HTTP_PROXY=%s", configuration.Proxy.Socks5))
- } else if configuration.Proxy.Https != "" || configuration.Proxy.Http != "" {
- if configuration.Proxy.Https != "" {
- cmd.Env = append(cmd.Env, fmt.Sprintf("HTTPS_PROXY=%s", configuration.Proxy.Https))
- }
- if configuration.Proxy.Http != "" {
- cmd.Env = append(cmd.Env, fmt.Sprintf("HTTP_PROXY=%s", configuration.Proxy.Http))
- }
- }
- err = output_handler.CaptureOutput(cmd)
- if err != nil {
- return err
- }
- return nil
- })
- if err != nil {
- return nil, nil, nil, err
- }
- return output_handler.GetStdout(), output_handler.GetStderr(), output_handler.GetDone(), nil
- }
- func (p *PythonRunner) InitializeEnvironment(code string, preload string, options *types.RunnerOptions) (string, string, error) {
- if !checkLibAvaliable() {
- // ensure environment is reversed
- releaseLibBinary()
- }
- // create a tmp dir and copy the python script
- temp_code_name := strings.ReplaceAll(uuid.New().String(), "-", "_")
- temp_code_name = strings.ReplaceAll(temp_code_name, "/", ".")
- script := strings.Replace(
- string(sandbox_fs),
- "{{uid}}", strconv.Itoa(static.SANDBOX_USER_UID), 1,
- )
- script = strings.Replace(
- script,
- "{{gid}}", strconv.Itoa(static.SANDBOX_GROUP_ID), 1,
- )
- if options.EnableNetwork {
- script = strings.Replace(
- script,
- "{{enable_network}}", "1", 1,
- )
- } else {
- script = strings.Replace(
- script,
- "{{enable_network}}", "0", 1,
- )
- }
- script = strings.Replace(
- script,
- "{{preload}}",
- fmt.Sprintf("%s\n", preload),
- 1,
- )
- // generate a random 512 bit key
- key_len := 64
- key := make([]byte, key_len)
- _, err := rand.Read(key)
- if err != nil {
- return "", "", err
- }
- // encrypt the code
- encrypted_code := make([]byte, len(code))
- for i := 0; i < len(code); i++ {
- encrypted_code[i] = code[i] ^ key[i%key_len]
- }
- // encode code using base64
- code = base64.StdEncoding.EncodeToString(encrypted_code)
- // encode key using base64
- encoded_key := base64.StdEncoding.EncodeToString(key)
- code = strings.Replace(
- script,
- "{{code}}",
- code,
- 1,
- )
- untrusted_code_path := fmt.Sprintf("%s/tmp/%s.py", LIB_PATH, temp_code_name)
- err = os.MkdirAll(path.Dir(untrusted_code_path), 0755)
- if err != nil {
- return "", "", err
- }
- err = os.WriteFile(untrusted_code_path, []byte(code), 0755)
- if err != nil {
- return "", "", err
- }
- return untrusted_code_path, encoded_key, nil
- }
|