main.router.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package main
  2. /*
  3. ArOZ Online System Main Request Router
  4. This is used to check authentication before actually serving file to the target client
  5. This function also handle the special page (login.html and user.html) delivery
  6. */
  7. import (
  8. "net/http"
  9. "path/filepath"
  10. "strconv"
  11. "strings"
  12. fs "imuslab.com/arozos/mod/filesystem"
  13. "imuslab.com/arozos/mod/network/gzipmiddleware"
  14. "imuslab.com/arozos/mod/utils"
  15. )
  16. func mrouter(h http.Handler) http.Handler {
  17. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  18. /*
  19. You can also check the path for url using r.URL.Path
  20. */
  21. if r.URL.Path == "/favicon.ico" || r.URL.Path == "/manifest.webmanifest" || r.URL.Path == "/robots.txt" || r.URL.Path == "/humans.txt" {
  22. //Serving web specification files. Allow no auth access.
  23. h.ServeHTTP(w, r)
  24. } else if r.URL.Path == "/login.html" {
  25. //Login page. Require special treatment for template.
  26. //Get the redirection address from the request URL
  27. red, _ := utils.GetPara(r, "redirect")
  28. //Append the redirection addr into the template
  29. imgsrc := filepath.Join(vendorResRoot, "auth_icon.png")
  30. if !fs.FileExists(imgsrc) {
  31. imgsrc = "./web/img/public/auth_icon.png"
  32. }
  33. imageBase64, _ := utils.LoadImageAsBase64(imgsrc)
  34. parsedPage, err := utils.Templateload("web/login.html", map[string]string{
  35. "redirection_addr": red,
  36. "usercount": strconv.Itoa(authAgent.GetUserCounts()),
  37. "service_logo": imageBase64,
  38. "login_addr": "system/auth/login",
  39. })
  40. if err != nil {
  41. panic("Error. Unable to parse login page. Is web directory data exists?")
  42. }
  43. w.Header().Add("Content-Type", "text/html; charset=UTF-8")
  44. w.Write([]byte(parsedPage))
  45. } else if r.URL.Path == "/reset.html" && authAgent.GetUserCounts() > 0 {
  46. //Password restart page. Allow access only when user number > 0
  47. system_resetpw_handlePasswordReset(w, r)
  48. } else if r.URL.Path == "/user.html" && authAgent.GetUserCounts() == 0 {
  49. //Serve user management page. This only allows serving of such page when the total usercount = 0 (aka System Initiation)
  50. h.ServeHTTP(w, r)
  51. } else if (len(r.URL.Path) > 11 && r.URL.Path[:11] == "/img/public") || (len(r.URL.Path) > 7 && r.URL.Path[:7] == "/script") {
  52. //Public image directory. Allow anyone to access resources inside this directory.
  53. if filepath.Ext("web"+fs.DecodeURI(r.RequestURI)) == ".js" {
  54. //Fixed serve js meme type invalid bug on Firefox
  55. w.Header().Add("Content-Type", "application/javascript; charset=UTF-8")
  56. }
  57. h.ServeHTTP(w, r)
  58. } else if len(r.URL.Path) >= len("/caldav") && r.URL.Path[:7] == "/caldav" {
  59. //CalDAV sub-router (bidirectional calendar sync for iOS)
  60. if CalDAVHandler == nil {
  61. errorHandleInternalServerError(w, r)
  62. return
  63. }
  64. CalDAVHandler.ServeHTTP(w, r)
  65. } else if r.URL.Path == "/.well-known/caldav" {
  66. //CalDAV service discovery redirect (RFC 6764)
  67. http.Redirect(w, r, "/caldav/", http.StatusMovedPermanently)
  68. } else if len(r.URL.Path) >= len("/webdav") && r.URL.Path[:7] == "/webdav" {
  69. //WebDAV sub-router
  70. if WebDAVManager == nil {
  71. errorHandleInternalServerError(w, r)
  72. return
  73. }
  74. WebDAVManager.HandleRequest(w, r)
  75. } else if len(r.URL.Path) >= len("/share") && r.URL.Path[:6] == "/share" {
  76. //Share Manager sub-router
  77. if shareManager == nil {
  78. errorHandleInternalServerError(w, r)
  79. return
  80. }
  81. shareManager.HandleShareAccess(w, r)
  82. } else if len(r.URL.Path) >= len("/api/remote") && r.URL.Path[:11] == "/api/remote" {
  83. //Serverless sub-router
  84. if AGIGateway == nil {
  85. errorHandleInternalServerError(w, r)
  86. return
  87. }
  88. AGIGateway.ExtAPIHandler(w, r)
  89. } else if len(r.URL.Path) >= len("/fileview") && r.URL.Path[:9] == "/fileview" {
  90. //File server sub-router
  91. if DirListManager == nil {
  92. errorHandleInternalServerError(w, r)
  93. return
  94. }
  95. DirListManager.ServerWebFileRequest(w, r)
  96. } else if r.URL.Path == "/" && authAgent.CheckAuth(r) {
  97. //Use logged in and request the index. Serve the user's interface module
  98. w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
  99. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  100. if err != nil {
  101. //ERROR!! Server default
  102. h.ServeHTTP(w, r)
  103. } else {
  104. interfaceModule := userinfo.GetInterfaceModules()
  105. if len(interfaceModule) == 1 && interfaceModule[0] == "Desktop" {
  106. http.Redirect(w, r, "./desktop.html", http.StatusTemporaryRedirect)
  107. } else if len(interfaceModule) == 1 {
  108. //User with default interface module not desktop
  109. modileInfo := moduleHandler.GetModuleInfoByID(interfaceModule[0])
  110. if modileInfo == nil {
  111. //The module is not found or not enabled
  112. http.Redirect(w, r, "./SystemAO/boot/interface_disabled.html", http.StatusTemporaryRedirect)
  113. return
  114. }
  115. http.Redirect(w, r, modileInfo.StartDir, http.StatusTemporaryRedirect)
  116. } else if len(interfaceModule) > 1 {
  117. //Redirect to module selector
  118. http.Redirect(w, r, "./SystemAO/boot/interface_selector.html", http.StatusTemporaryRedirect)
  119. } else if len(interfaceModule) == 0 {
  120. //Redirect to error page
  121. http.Redirect(w, r, "./SystemAO/boot/no_interfaceing.html", http.StatusTemporaryRedirect)
  122. } else {
  123. //For unknown operations, send it to desktop
  124. http.Redirect(w, r, "./desktop.html", http.StatusTemporaryRedirect)
  125. }
  126. }
  127. } else if ((len(r.URL.Path) >= 5 && r.URL.Path[:5] == "/www/") || r.URL.Path == "/www") && *allow_homepage {
  128. //Serve the custom homepage of the user defined. Hand over to the www router
  129. userWwwHandler.RouteRequest(w, r)
  130. } else if authAgent.CheckAuth(r) {
  131. //User logged in. Continue to serve the file the client want
  132. authAgent.UpdateSessionExpireTime(w, r)
  133. if build_version == "development" {
  134. //Do something if development build
  135. //w.Header().Add("Cross-Origin-Opener-Policy", "same-origin")
  136. //w.Header().Add("Cross-Origin-Embedder-Policy", "require-corp")
  137. }
  138. if filepath.Ext("web"+fs.DecodeURI(r.RequestURI)) == ".js" {
  139. //Fixed serve js meme type invalid bug on Firefox
  140. w.Header().Add("Content-Type", "application/javascript; charset=UTF-8")
  141. }
  142. if !*disable_subservices {
  143. //Enable subservice access
  144. //Check if this path is reverse proxy path. If yes, serve with proxyserver
  145. isRP, proxy, rewriteURL, subserviceObject := ssRouter.CheckIfReverseProxyPath(r)
  146. if isRP {
  147. //Check user permission on that module
  148. ssRouter.HandleRoutingRequest(w, r, proxy, subserviceObject, rewriteURL)
  149. return
  150. }
  151. }
  152. //Not subservice routine. Handle file server
  153. if !*enable_dir_listing {
  154. if strings.HasSuffix(r.URL.Path, "/") {
  155. //User trying to access a directory. Send NOT FOUND.
  156. if fileExistsInWebOrVendor(r.URL.Path + "index.html") {
  157. //Index exists. Allow passthrough
  158. } else {
  159. errorHandleNotFound(w, r)
  160. return
  161. }
  162. }
  163. }
  164. if !fileExistsInWebOrVendor(r.URL.Path) {
  165. //File not found
  166. errorHandleNotFound(w, r)
  167. return
  168. }
  169. routerStaticContentServer(h, w, r)
  170. } else {
  171. //User not logged in. Check if the path end with public/. If yes, allow public access
  172. if !fileExistsInWebOrVendor(r.URL.Path) {
  173. //Requested file not exists on the server. Return not found
  174. errorHandleNotFound(w, r)
  175. } else if r.URL.Path[len(r.URL.Path)-1:] != "/" && filepath.Base(filepath.Dir(r.URL.Path)) == "public" {
  176. //This file path end with public/. Allow public access
  177. routerStaticContentServer(h, w, r)
  178. } else if *allow_homepage && len(r.URL.Path) >= 5 && r.URL.Path[:5] == "/www/" {
  179. //Handle public home serving if homepage mode is enabled
  180. routerStaticContentServer(h, w, r)
  181. } else {
  182. //Other paths
  183. //Rediect to login page
  184. w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
  185. http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.html")+"?redirect="+r.URL.String(), 307)
  186. }
  187. }
  188. })
  189. }
  190. // fileExistsInWebOrVendor reports whether a URL path resolves to a file in
  191. // either the standard ./web directory or the vendorResRoot/web/ overlay.
  192. func fileExistsInWebOrVendor(urlPath string) bool {
  193. if fs.FileExists("web" + urlPath) {
  194. return true
  195. }
  196. return fs.FileExists(filepath.Join(vendorResRoot, "web", urlPath))
  197. }
  198. func routerStaticContentServer(h http.Handler, w http.ResponseWriter, r *http.Request) {
  199. if *enable_gzip {
  200. gzipmiddleware.Compress(h).ServeHTTP(w, r)
  201. } else {
  202. h.ServeHTTP(w, r)
  203. }
  204. }