externalReqHandler.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package agi
  2. import (
  3. "encoding/json"
  4. "log"
  5. "net/http"
  6. "path/filepath"
  7. "strings"
  8. uuid "github.com/satori/go.uuid"
  9. "imuslab.com/arozos/mod/agi/static"
  10. "imuslab.com/arozos/mod/utils"
  11. )
  12. type endpointFormat struct {
  13. Username string `json:"username"`
  14. Path string `json:"path"`
  15. }
  16. // Handle request from EXTERNAL RESTFUL API
  17. func (g *Gateway) ExtAPIHandler(w http.ResponseWriter, r *http.Request) {
  18. // get db
  19. sysdb := g.Option.UserHandler.GetDatabase()
  20. if !sysdb.TableExists("external_agi") {
  21. http.Error(w, "invalid API request", http.StatusBadRequest)
  22. return
  23. }
  24. // get the request URI from the r.URL
  25. requestURI := filepath.ToSlash(filepath.Clean(r.URL.Path))
  26. subpathElements := strings.Split(requestURI[1:], "/")
  27. // check if it contains only two part, [rexec uuid]
  28. if len(subpathElements) != 3 {
  29. http.Error(w, "invalid API request", http.StatusBadRequest)
  30. return
  31. }
  32. // check if UUID exists in the database
  33. // get the info from the database
  34. data, isExist := g.checkIfExternalEndpointExist(subpathElements[2])
  35. if !isExist {
  36. http.Error(w, "malformed request: invalid UUID given", http.StatusBadRequest)
  37. return
  38. }
  39. usernameFromDb := data.Username
  40. pathFromDb := data.Path
  41. // get the userinfo and the realPath
  42. userInfo, err := g.Option.UserHandler.GetUserInfoFromUsername(usernameFromDb)
  43. if err != nil {
  44. http.Error(w, "invalid request: API author no longer exists", http.StatusBadRequest)
  45. return
  46. }
  47. fsh, realPath, err := static.VirtualPathToRealPath(pathFromDb, userInfo)
  48. if err != nil {
  49. http.Error(w, "invalid request: backend script path cannot be resolved", http.StatusBadRequest)
  50. return
  51. }
  52. //Check if the script file still exists
  53. if !fsh.FileSystemAbstraction.FileExists(realPath) {
  54. //Script no longer exists
  55. log.Println("[Remote AGI] ", pathFromDb, " cannot be found on "+realPath)
  56. http.Error(w, "invalid request: backend script not exists", http.StatusBadRequest)
  57. return
  58. }
  59. // execute!
  60. //start := time.Now()
  61. //g.ExecuteAGIScript(scriptContent, "", "", w, r, userInfo)
  62. result, err := g.ExecuteAGIScriptAsUser(fsh, realPath, userInfo, w, r)
  63. //duration := time.Since(start)
  64. if err != nil {
  65. log.Println("[Remote AGI] ", pathFromDb, " failed to execute", err.Error())
  66. utils.SendErrorResponse(w, err.Error())
  67. return
  68. }
  69. w.Write([]byte(result))
  70. //log.Println("[Remote AGI] IP:", r.RemoteAddr, "executed the script ", pathFromDb, "on behalf of", userInfo.Username, "with total duration:", duration)
  71. }
  72. func (g *Gateway) AddExternalEndPoint(w http.ResponseWriter, r *http.Request) {
  73. userInfo, err := g.Option.UserHandler.GetUserInfoFromRequest(w, r)
  74. if err != nil {
  75. utils.SendErrorResponse(w, "User not logged in")
  76. return
  77. }
  78. // get db
  79. sysdb := g.Option.UserHandler.GetDatabase()
  80. if !sysdb.TableExists("external_agi") {
  81. sysdb.NewTable("external_agi")
  82. }
  83. var dat endpointFormat
  84. // uuid: [path, id]
  85. path, err := utils.GetPara(r, "path")
  86. if err != nil {
  87. utils.SendErrorResponse(w, "Invalid path given")
  88. return
  89. }
  90. // put the data in then marshal
  91. id := uuid.NewV4().String()
  92. dat.Path = path
  93. dat.Username = userInfo.Username
  94. jsonStr, err := json.Marshal(dat)
  95. if err != nil {
  96. utils.SendErrorResponse(w, "Invalid JSON string: "+err.Error())
  97. return
  98. }
  99. sysdb.Write("external_agi", id, string(jsonStr))
  100. // send the uuid to frontend
  101. utils.SendJSONResponse(w, "\""+id+"\"")
  102. }
  103. func (g *Gateway) RemoveExternalEndPoint(w http.ResponseWriter, r *http.Request) {
  104. userInfo, err := g.Option.UserHandler.GetUserInfoFromRequest(w, r)
  105. if err != nil {
  106. utils.SendErrorResponse(w, "User not logged in")
  107. return
  108. }
  109. // get db
  110. sysdb := g.Option.UserHandler.GetDatabase()
  111. if !sysdb.TableExists("external_agi") {
  112. sysdb.NewTable("external_agi")
  113. }
  114. // get path
  115. uuid, err := utils.GetPara(r, "uuid")
  116. if err != nil {
  117. utils.SendErrorResponse(w, "Invalid uuid given")
  118. return
  119. }
  120. // check if endpoint is here
  121. data, isExist := g.checkIfExternalEndpointExist(uuid)
  122. if !isExist {
  123. utils.SendErrorResponse(w, "UUID does not exists in the database!")
  124. return
  125. }
  126. // make sure user cant see other's endpoint
  127. if data.Username != userInfo.Username {
  128. utils.SendErrorResponse(w, "Permission denied")
  129. return
  130. }
  131. // delete record
  132. sysdb.Delete("external_agi", uuid)
  133. utils.SendOK(w)
  134. }
  135. func (g *Gateway) ListExternalEndpoint(w http.ResponseWriter, r *http.Request) {
  136. userInfo, err := g.Option.UserHandler.GetUserInfoFromRequest(w, r)
  137. if err != nil {
  138. utils.SendErrorResponse(w, "User not logged in")
  139. return
  140. }
  141. // get db
  142. sysdb := g.Option.UserHandler.GetDatabase()
  143. if !sysdb.TableExists("external_agi") {
  144. sysdb.NewTable("external_agi")
  145. }
  146. // declare variable for return
  147. dataFromDB := make(map[string]endpointFormat)
  148. // O(n) method to do the lookup
  149. entries, err := sysdb.ListTable("external_agi")
  150. if err != nil {
  151. utils.SendErrorResponse(w, "Invalid table")
  152. return
  153. }
  154. for _, keypairs := range entries {
  155. //Decode the string
  156. var dataFromResult endpointFormat
  157. result := ""
  158. uuid := string(keypairs[0])
  159. json.Unmarshal(keypairs[1], &result)
  160. //fmt.Println(result)
  161. json.Unmarshal([]byte(result), &dataFromResult)
  162. if dataFromResult.Username == userInfo.Username {
  163. dataFromDB[uuid] = dataFromResult
  164. }
  165. }
  166. // marhsal and return
  167. returnJson, err := json.Marshal(dataFromDB)
  168. if err != nil {
  169. utils.SendErrorResponse(w, "Invalid JSON: "+err.Error())
  170. return
  171. }
  172. utils.SendJSONResponse(w, string(returnJson))
  173. }
  174. func (g *Gateway) checkIfExternalEndpointExist(uuid string) (endpointFormat, bool) {
  175. // get db
  176. sysdb := g.Option.UserHandler.GetDatabase()
  177. if !sysdb.TableExists("external_agi") {
  178. sysdb.NewTable("external_agi")
  179. }
  180. var dat endpointFormat
  181. // check if key exist
  182. if !sysdb.KeyExists("external_agi", uuid) {
  183. return dat, false
  184. }
  185. // if yes then return the value
  186. jsonData := ""
  187. sysdb.Read("external_agi", uuid, &jsonData)
  188. json.Unmarshal([]byte(jsonData), &dat)
  189. return dat, true
  190. }