agi.appdata.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package agi
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "log"
  6. "os"
  7. "path/filepath"
  8. "github.com/robertkrimen/otto"
  9. "imuslab.com/arozos/mod/agi/static"
  10. "imuslab.com/arozos/mod/filesystem"
  11. "imuslab.com/arozos/mod/utils"
  12. )
  13. /*
  14. AGI Appdata Access Library
  15. Author: tobychui
  16. This library allow agi script to access files located in the web root
  17. *This library provide READ ONLY function*
  18. You cannot write to web folder due to security reasons. If you need to read write
  19. web root (which is not recommended), ask the user to mount it to web:/ manually
  20. */
  21. var webRoot string = "./web" //The web folder root
  22. func (g *Gateway) AppdataLibRegister() {
  23. err := g.RegisterLib("appdata", g.injectAppdataLibFunctions)
  24. if err != nil {
  25. log.Fatal(err)
  26. }
  27. }
  28. func (g *Gateway) injectAppdataLibFunctions(payload *static.AgiLibInjectionPayload) {
  29. vm := payload.VM
  30. vm.Set("_appdata_readfile", func(call otto.FunctionCall) otto.Value {
  31. relpath, err := call.Argument(0).ToString()
  32. if err != nil {
  33. g.RaiseError(err)
  34. return otto.FalseValue()
  35. }
  36. //Check if this is path escape
  37. escaped, err := static.CheckRootEscape(webRoot, filepath.Join(webRoot, relpath))
  38. if err != nil {
  39. g.RaiseError(err)
  40. return otto.FalseValue()
  41. }
  42. if escaped {
  43. g.RaiseError(errors.New("Path escape detected"))
  44. return otto.FalseValue()
  45. }
  46. //Check if file exists
  47. targetFile := filepath.Join(webRoot, relpath)
  48. if utils.FileExists(targetFile) && !filesystem.IsDir(targetFile) {
  49. content, err := os.ReadFile(targetFile)
  50. if err != nil {
  51. g.RaiseError(err)
  52. return otto.FalseValue()
  53. }
  54. //OK. Return the content of the file
  55. result, _ := vm.ToValue(string(content))
  56. return result
  57. } else if filesystem.IsDir(targetFile) {
  58. g.RaiseError(errors.New("Cannot read from directory"))
  59. return otto.FalseValue()
  60. } else {
  61. g.RaiseError(errors.New("File not exists"))
  62. return otto.FalseValue()
  63. }
  64. })
  65. vm.Set("_appdata_listdir", func(call otto.FunctionCall) otto.Value {
  66. relpath, err := call.Argument(0).ToString()
  67. if err != nil {
  68. g.RaiseError(err)
  69. return otto.FalseValue()
  70. }
  71. //Check if this is path escape
  72. escaped, err := static.CheckRootEscape(webRoot, filepath.Join(webRoot, relpath))
  73. if err != nil {
  74. g.RaiseError(err)
  75. return otto.FalseValue()
  76. }
  77. if escaped {
  78. g.RaiseError(errors.New("Path escape detected"))
  79. return otto.FalseValue()
  80. }
  81. //Check if file exists
  82. targetFolder := filepath.Join(webRoot, relpath)
  83. if utils.FileExists(targetFolder) && filesystem.IsDir(targetFolder) {
  84. //Glob the directory for filelist
  85. files, err := filepath.Glob(filepath.ToSlash(filepath.Clean(targetFolder)) + "/*")
  86. if err != nil {
  87. g.RaiseError(err)
  88. return otto.FalseValue()
  89. }
  90. results := []string{}
  91. for _, file := range files {
  92. rel, _ := filepath.Rel(webRoot, file)
  93. rel = filepath.ToSlash(rel)
  94. results = append(results, rel)
  95. }
  96. js, _ := json.Marshal(results)
  97. //OK. Return the content of the file
  98. result, _ := vm.ToValue(string(js))
  99. return result
  100. } else {
  101. g.RaiseError(errors.New("Directory not exists"))
  102. return otto.FalseValue()
  103. }
  104. })
  105. //Wrap all the native code function into an imagelib class
  106. vm.Run(`
  107. var appdata = {};
  108. appdata.readFile = _appdata_readfile;
  109. appdata.listDir = _appdata_listdir;
  110. `)
  111. }