agi.appdata.go 3.8 KB

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