userFunc.go 8.7 KB

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