nodejs.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package nodejs
  2. import (
  3. _ "embed"
  4. "encoding/base64"
  5. "fmt"
  6. "os"
  7. "os/exec"
  8. "path"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "github.com/langgenius/dify-sandbox/internal/core/runner"
  13. "github.com/langgenius/dify-sandbox/internal/core/runner/types"
  14. "github.com/langgenius/dify-sandbox/internal/static"
  15. )
  16. type NodeJsRunner struct {
  17. runner.TempDirRunner
  18. }
  19. //go:embed prescript.js
  20. var nodejs_sandbox_fs []byte
  21. var (
  22. REQUIRED_FS = []string{
  23. path.Join(LIB_PATH, PROJECT_NAME, "node_temp"),
  24. path.Join(LIB_PATH, LIB_NAME),
  25. "/etc/ssl/certs/ca-certificates.crt",
  26. "/etc/nsswitch.conf",
  27. "/etc/resolv.conf",
  28. "/run/systemd/resolve/stub-resolv.conf",
  29. "/etc/hosts",
  30. }
  31. )
  32. func (p *NodeJsRunner) Run(
  33. code string,
  34. timeout time.Duration,
  35. stdin []byte,
  36. preload string,
  37. options *types.RunnerOptions,
  38. ) (chan []byte, chan []byte, chan bool, error) {
  39. configuration := static.GetDifySandboxGlobalConfigurations()
  40. // capture the output
  41. output_handler := runner.NewOutputCaptureRunner()
  42. output_handler.SetTimeout(timeout)
  43. err := p.WithTempDir("/", REQUIRED_FS, func(root_path string) error {
  44. output_handler.SetAfterExitHook(func() {
  45. os.RemoveAll(root_path)
  46. os.Remove(root_path)
  47. })
  48. // initialize the environment
  49. script_path, err := p.InitializeEnvironment(code, preload, root_path)
  50. if err != nil {
  51. return err
  52. }
  53. // create a new process
  54. cmd := exec.Command(
  55. static.GetDifySandboxGlobalConfigurations().NodejsPath,
  56. script_path,
  57. strconv.Itoa(static.SANDBOX_USER_UID),
  58. strconv.Itoa(static.SANDBOX_GROUP_ID),
  59. options.Json(),
  60. )
  61. cmd.Env = []string{}
  62. if len(configuration.AllowedSyscalls) > 0 {
  63. cmd.Env = append(
  64. cmd.Env,
  65. fmt.Sprintf("ALLOWED_SYSCALLS=%s", strings.Trim(
  66. strings.Join(strings.Fields(fmt.Sprint(configuration.AllowedSyscalls)), ","), "[]",
  67. )),
  68. )
  69. }
  70. // capture the output
  71. err = output_handler.CaptureOutput(cmd)
  72. if err != nil {
  73. return err
  74. }
  75. return nil
  76. })
  77. if err != nil {
  78. return nil, nil, nil, err
  79. }
  80. return output_handler.GetStdout(), output_handler.GetStderr(), output_handler.GetDone(), nil
  81. }
  82. func (p *NodeJsRunner) InitializeEnvironment(code string, preload string, root_path string) (string, error) {
  83. if !checkLibAvaliable() {
  84. releaseLibBinary()
  85. }
  86. node_sandbox_file := string(nodejs_sandbox_fs)
  87. if preload != "" {
  88. node_sandbox_file = fmt.Sprintf("%s\n%s", preload, node_sandbox_file)
  89. }
  90. // join nodejs_sandbox_fs and code
  91. // encode code with base64
  92. code = base64.StdEncoding.EncodeToString([]byte(code))
  93. // FIXE: redeclared function causes code injection
  94. evalCode := fmt.Sprintf("eval(Buffer.from('%s', 'base64').toString('utf-8'))", code)
  95. code = node_sandbox_file + evalCode
  96. // override root_path/tmp/sandbox-nodejs-project/prescript.js
  97. script_path := path.Join(root_path, LIB_PATH, PROJECT_NAME, "node_temp/node_temp/test.js")
  98. err := os.WriteFile(script_path, []byte(code), 0755)
  99. if err != nil {
  100. return "", err
  101. }
  102. return script_path, nil
  103. }