userFunc.go 8.6 KB

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