agi.user.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. package agi
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "os"
  8. "path/filepath"
  9. "github.com/robertkrimen/otto"
  10. "imuslab.com/arozos/mod/agi/static"
  11. "imuslab.com/arozos/mod/filesystem"
  12. "imuslab.com/arozos/mod/filesystem/arozfs"
  13. "imuslab.com/arozos/mod/info/logger"
  14. user "imuslab.com/arozos/mod/user"
  15. )
  16. // Inject user based functions into the virtual machine
  17. // Note that the fsh might be nil and scriptPath must be real path of script being executed
  18. // **Use local file system check if fsh == nil**
  19. func (g *Gateway) injectUserFunctions(vm *otto.Otto, fsh *filesystem.FileSystemHandler, scriptPath string, scriptScope string, u *user.User, w http.ResponseWriter, r *http.Request) {
  20. username := u.Username
  21. vm.Set("USERNAME", username)
  22. vm.Set("USERICON", u.GetUserIcon())
  23. vm.Set("USERQUOTA_TOTAL", u.StorageQuota.TotalStorageQuota)
  24. vm.Set("USERQUOTA_USED", u.StorageQuota.UsedStorageQuota)
  25. vm.Set("USER_VROOTS", u.GetAllAccessibleFileSystemHandler())
  26. vm.Set("USER_MODULES", u.GetUserAccessibleModules())
  27. //File system and path related
  28. vm.Set("decodeVirtualPath", func(call otto.FunctionCall) otto.Value {
  29. logger.PrintAndLog("Agi", "Call to deprecated function decodeVirtualPath", nil)
  30. return otto.FalseValue()
  31. })
  32. vm.Set("decodeAbsoluteVirtualPath", func(call otto.FunctionCall) otto.Value {
  33. logger.PrintAndLog("Agi", "Call to deprecated function decodeAbsoluteVirtualPath", nil)
  34. return otto.FalseValue()
  35. })
  36. vm.Set("encodeRealPath", func(call otto.FunctionCall) otto.Value {
  37. logger.PrintAndLog("Agi", "Call to deprecated function encodeRealPath", nil)
  38. return otto.FalseValue()
  39. })
  40. //Check if a given virtual path is readonly
  41. vm.Set("pathCanWrite", func(call otto.FunctionCall) otto.Value {
  42. vpath, _ := call.Argument(0).ToString()
  43. if u.CanWrite(vpath) {
  44. return otto.TrueValue()
  45. } else {
  46. return otto.FalseValue()
  47. }
  48. })
  49. //Permission related
  50. vm.Set("getUserPermissionGroup", func(call otto.FunctionCall) otto.Value {
  51. groupinfo := u.GetUserPermissionGroup()
  52. jsonString, _ := json.Marshal(groupinfo)
  53. reply, _ := vm.ToValue(string(jsonString))
  54. return reply
  55. })
  56. vm.Set("userIsAdmin", func(call otto.FunctionCall) otto.Value {
  57. reply, _ := vm.ToValue(u.IsAdmin())
  58. return reply
  59. })
  60. //User Account Related
  61. /*
  62. userExists(username);
  63. */
  64. vm.Set("userExists", func(call otto.FunctionCall) otto.Value {
  65. if u.IsAdmin() {
  66. //Get username from function paramter
  67. username, err := call.Argument(0).ToString()
  68. if err != nil || username == "undefined" {
  69. g.RaiseError(errors.New("username is undefined"))
  70. reply, _ := vm.ToValue(nil)
  71. return reply
  72. }
  73. //Check if user exists
  74. userExists := u.Parent().GetAuthAgent().UserExists(username)
  75. if userExists {
  76. return otto.TrueValue()
  77. } else {
  78. return otto.FalseValue()
  79. }
  80. } else {
  81. g.RaiseError(errors.New("Permission Denied: userExists require admin permission"))
  82. return otto.FalseValue()
  83. }
  84. })
  85. /*
  86. createUser(username, password, defaultGroup);
  87. */
  88. vm.Set("createUser", func(call otto.FunctionCall) otto.Value {
  89. if u.IsAdmin() {
  90. //Ok. Create user base on given information
  91. username, err := call.Argument(0).ToString()
  92. if err != nil || username == "undefined" {
  93. g.RaiseError(errors.New("username is undefined"))
  94. reply, _ := vm.ToValue(false)
  95. return reply
  96. }
  97. password, err := call.Argument(1).ToString()
  98. if err != nil || password == "undefined" {
  99. g.RaiseError(errors.New("password is undefined"))
  100. reply, _ := vm.ToValue(false)
  101. return reply
  102. }
  103. defaultGroup, err := call.Argument(2).ToString()
  104. if err != nil || defaultGroup == "undefined" {
  105. g.RaiseError(errors.New("defaultGroup is undefined"))
  106. reply, _ := vm.ToValue(false)
  107. return reply
  108. }
  109. //Check if username already used
  110. userExists := u.Parent().GetAuthAgent().UserExists(username)
  111. if userExists {
  112. g.RaiseError(errors.New("Username already exists"))
  113. reply, _ := vm.ToValue(false)
  114. return reply
  115. }
  116. //Check if the given permission group exists
  117. groupExists := u.Parent().GetPermissionHandler().GroupExists(defaultGroup)
  118. if !groupExists {
  119. g.RaiseError(errors.New(defaultGroup + " user-group not exists"))
  120. reply, _ := vm.ToValue(false)
  121. return reply
  122. }
  123. //Create the user
  124. err = u.Parent().GetAuthAgent().CreateUserAccount(username, password, []string{defaultGroup})
  125. if err != nil {
  126. g.RaiseError(errors.New("User creation failed: " + err.Error()))
  127. reply, _ := vm.ToValue(false)
  128. return reply
  129. }
  130. return otto.TrueValue()
  131. } else {
  132. g.RaiseError(errors.New("Permission Denied: createUser require admin permission"))
  133. return otto.FalseValue()
  134. }
  135. })
  136. vm.Set("editUser", func(call otto.FunctionCall) otto.Value {
  137. if u.IsAdmin() {
  138. } else {
  139. g.RaiseError(errors.New("Permission Denied: editUser require admin permission"))
  140. return otto.FalseValue()
  141. }
  142. //libname, err := call.Argument(0).ToString()
  143. return otto.FalseValue()
  144. })
  145. /*
  146. removeUser(username)
  147. */
  148. vm.Set("removeUser", func(call otto.FunctionCall) otto.Value {
  149. if u.IsAdmin() {
  150. //Get username from function paramters
  151. username, err := call.Argument(0).ToString()
  152. if err != nil || username == "undefined" {
  153. g.RaiseError(errors.New("username is undefined"))
  154. reply, _ := vm.ToValue(false)
  155. return reply
  156. }
  157. //Check if the user exists
  158. userExists := u.Parent().GetAuthAgent().UserExists(username)
  159. if !userExists {
  160. g.RaiseError(errors.New(username + " not exists"))
  161. reply, _ := vm.ToValue(false)
  162. return reply
  163. }
  164. //User exists. Remove it from the system
  165. err = u.Parent().GetAuthAgent().UnregisterUser(username)
  166. if err != nil {
  167. g.RaiseError(errors.New("User removal failed: " + err.Error()))
  168. reply, _ := vm.ToValue(false)
  169. return reply
  170. }
  171. return otto.TrueValue()
  172. } else {
  173. g.RaiseError(errors.New("Permission Denied: removeUser require admin permission"))
  174. return otto.FalseValue()
  175. }
  176. })
  177. //Allow real time library includsion into the virtual machine
  178. vm.Set("requirelib", func(call otto.FunctionCall) otto.Value {
  179. libname, err := call.Argument(0).ToString()
  180. if err != nil {
  181. g.RaiseError(err)
  182. reply, _ := vm.ToValue(nil)
  183. return reply
  184. }
  185. //Handle special case on high level libraries
  186. if libname == "websocket" && w != nil && r != nil {
  187. g.injectWebSocketFunctions(vm, u, w, r)
  188. return otto.TrueValue()
  189. } else {
  190. //Check if the library name exists. If yes, run the initiation script on the vm
  191. if entryPoint, ok := g.LoadedAGILibrary[libname]; ok {
  192. entryPoint(&static.AgiLibInjectionPayload{
  193. VM: vm,
  194. User: u,
  195. ScriptFsh: fsh,
  196. ScriptPath: scriptPath,
  197. Writer: w,
  198. Request: r,
  199. })
  200. return otto.TrueValue()
  201. } else {
  202. //Lib not exists
  203. logger.PrintAndLog("Agi", "Lib not found: "+libname, nil)
  204. return otto.FalseValue()
  205. }
  206. }
  207. })
  208. //Execd (Execute & detach) run another script and detach the execution
  209. vm.Set("execd", func(call otto.FunctionCall) otto.Value {
  210. //Check if the pkg is already registered
  211. scriptName, err := call.Argument(0).ToString()
  212. if err != nil {
  213. g.RaiseError(err)
  214. return otto.FalseValue()
  215. }
  216. //Carry the payload to the forked process if there are any
  217. payload, _ := call.Argument(1).ToString()
  218. //Check if the script file exists
  219. targetScriptPath := arozfs.ToSlash(filepath.Join(filepath.Dir(scriptPath), scriptName))
  220. if fsh != nil {
  221. if !fsh.FileSystemAbstraction.FileExists(targetScriptPath) {
  222. g.RaiseError(errors.New("[AGI] Target path not exists!"))
  223. return otto.FalseValue()
  224. }
  225. } else {
  226. if !filesystem.FileExists(targetScriptPath) {
  227. g.RaiseError(errors.New("[AGI] Target path not exists!"))
  228. return otto.FalseValue()
  229. }
  230. }
  231. //Run the script
  232. scriptContent, _ := os.ReadFile(targetScriptPath)
  233. go func() {
  234. //Create a new VM to execute the script (also for isolation)
  235. vm := otto.New()
  236. //Inject standard libs into the vm
  237. g.injectStandardLibs(vm, scriptPath, scriptScope)
  238. g.injectUserFunctions(vm, fsh, scriptPath, scriptScope, u, w, r)
  239. vm.Set("PARENT_DETACHED", true)
  240. vm.Set("PARENT_PAYLOAD", payload)
  241. _, err = vm.Run(string(scriptContent))
  242. if err != nil {
  243. //Script execution failed
  244. logger.PrintAndLog("Agi", fmt.Sprint("Script Execution Failed: ", err.Error()), nil)
  245. g.RaiseError(err)
  246. }
  247. }()
  248. return otto.TrueValue()
  249. })
  250. }