userFunc.go 9.2 KB

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