static.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package static
  2. import (
  3. "net/http"
  4. "net/url"
  5. "path/filepath"
  6. "strings"
  7. "github.com/robertkrimen/otto"
  8. "imuslab.com/arozos/mod/filesystem"
  9. "imuslab.com/arozos/mod/filesystem/arozfs"
  10. user "imuslab.com/arozos/mod/user"
  11. "imuslab.com/arozos/mod/utils"
  12. )
  13. // Injection payload, the minimal required information for a function module to execute the
  14. // agi script in virtualized environment
  15. type AgiLibInjectionPayload struct {
  16. VM *otto.Otto
  17. User *user.User
  18. ScriptFsh *filesystem.FileSystemHandler
  19. ScriptPath string
  20. Writer http.ResponseWriter
  21. Request *http.Request
  22. }
  23. // Get the full vpath if the passing value is a relative path
  24. // Return the original vpath if any error occured
  25. func RelativeVpathRewrite(fsh *filesystem.FileSystemHandler, vpath string, vm *otto.Otto, u *user.User) string {
  26. //Check if the vpath contain a UUID
  27. if strings.Contains(vpath, ":/") || (len(vpath) > 0 && vpath[len(vpath)-1:] == ":") {
  28. //This vpath contain root uuid.
  29. return vpath
  30. }
  31. //We have no idea where the script is from. Trust its vpath is always full path
  32. if fsh == nil {
  33. return vpath
  34. }
  35. //Get the script execution root path
  36. rootPath, err := vm.Get("__FILE__")
  37. if err != nil {
  38. return vpath
  39. }
  40. rootPathString, err := rootPath.ToString()
  41. if err != nil {
  42. return vpath
  43. }
  44. //Convert the root path to vpath
  45. rootVpath, err := fsh.FileSystemAbstraction.RealPathToVirtualPath(rootPathString, u.Username)
  46. if err != nil {
  47. return vpath
  48. }
  49. rootScriptDir := filepath.Dir(rootVpath)
  50. return arozfs.ToSlash(filepath.Clean(filepath.Join(rootScriptDir, vpath)))
  51. }
  52. // Define path translation function
  53. func VirtualPathToRealPath(vpath string, u *user.User) (*filesystem.FileSystemHandler, string, error) {
  54. fsh, err := u.GetFileSystemHandlerFromVirtualPath(vpath)
  55. if err != nil {
  56. return nil, "", err
  57. }
  58. rpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(vpath, u.Username)
  59. if err != nil {
  60. return nil, "", err
  61. }
  62. return fsh, rpath, nil
  63. }
  64. func RealpathToVirtualpath(fsh *filesystem.FileSystemHandler, path string, u *user.User) (string, error) {
  65. return fsh.FileSystemAbstraction.RealPathToVirtualPath(path, u.Username)
  66. }
  67. // Check if the user can access this script file
  68. func CheckUserAccessToScript(thisuser *user.User, scriptFile string, scriptScope string) bool {
  69. moduleName := GetScriptRoot(scriptFile, scriptScope)
  70. if !thisuser.GetModuleAccessPermission(moduleName) {
  71. return false
  72. }
  73. return true
  74. }
  75. // validate the given path is a script from webroot
  76. func IsValidAGIScript(scriptPath string) bool {
  77. return utils.FileExists(filepath.Join("./web", scriptPath)) && (filepath.Ext(scriptPath) == ".js" || filepath.Ext(scriptPath) == ".agi")
  78. }
  79. // Return the script root of the current executing script
  80. func GetScriptRoot(scriptFile string, scriptScope string) string {
  81. //Get the script root from the script path
  82. webRootAbs, _ := filepath.Abs(scriptScope)
  83. webRootAbs = filepath.ToSlash(filepath.Clean(webRootAbs) + "/")
  84. scriptFileAbs, _ := filepath.Abs(scriptFile)
  85. scriptFileAbs = filepath.ToSlash(filepath.Clean(scriptFileAbs))
  86. scriptRoot := strings.Replace(scriptFileAbs, webRootAbs, "", 1)
  87. scriptRoot = strings.Split(scriptRoot, "/")[0]
  88. return scriptRoot
  89. }
  90. // For handling special url decode in the request
  91. func SpecialURIDecode(inputPath string) string {
  92. inputPath = strings.ReplaceAll(inputPath, "+", "{{plus_sign}}")
  93. inputPath, _ = url.QueryUnescape(inputPath)
  94. inputPath = strings.ReplaceAll(inputPath, "{{plus_sign}}", "+")
  95. return inputPath
  96. }
  97. // Check if the target path is escaping the rootpath, accept relative and absolute path
  98. func CheckRootEscape(rootPath string, targetPath string) (bool, error) {
  99. rootAbs, err := filepath.Abs(rootPath)
  100. if err != nil {
  101. return true, err
  102. }
  103. targetAbs, err := filepath.Abs(targetPath)
  104. if err != nil {
  105. return true, err
  106. }
  107. if len(targetAbs) < len(rootAbs) || targetAbs[:len(rootAbs)] != rootAbs {
  108. //Potential path escape. Return true
  109. return true, nil
  110. }
  111. return false, nil
  112. }