webdavWindowHandler.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package webdav
  2. /*
  3. WebDAV Handler for Windows
  4. Yes, because Windows sucks and require a special handler
  5. to handle Windows request over WebDAV protocol
  6. */
  7. import (
  8. "fmt"
  9. "log"
  10. "net"
  11. "net/http"
  12. "path/filepath"
  13. "strings"
  14. "time"
  15. uuid "github.com/satori/go.uuid"
  16. )
  17. //Handle request from Windows File Explorer
  18. func (s *Server) HandleWindowClientAccess(w http.ResponseWriter, r *http.Request, vroot string) {
  19. coookieName := "arozosWebdavToken"
  20. cookie, err := r.Cookie(coookieName)
  21. if err != nil {
  22. //New Client! Record its uuid and IP address
  23. //Generate a new UUID for this client
  24. thisWebDAVClientID := uuid.NewV4().String()
  25. //Generate a new HTTP Cookie
  26. http.SetCookie(w, &http.Cookie{
  27. Name: coookieName,
  28. Value: thisWebDAVClientID,
  29. MaxAge: 3600,
  30. })
  31. ip, err := getIP(r)
  32. if err != nil {
  33. ip = "Unknown"
  34. }
  35. if ip == "::1" || ip == "127.0.0.1" {
  36. ip = "localhost"
  37. }
  38. log.Println("New Window WebDAV Client Connected! Assinging UUID:", thisWebDAVClientID)
  39. //Store this UUID with the connection
  40. s.windowsClientNotLoggedIn.Store(thisWebDAVClientID, &WindowClientInfo{
  41. Agent: r.Header["User-Agent"][0],
  42. LastConnectionTimestamp: time.Now().Unix(),
  43. UUID: thisWebDAVClientID,
  44. ClientIP: ip,
  45. })
  46. //OK. Serve the READONLY FS for Winwdows to remember this login
  47. s.serveReadOnlyWebDav(w, r)
  48. return
  49. } else {
  50. //This client already have a token. Extract it
  51. clientUUID := cookie.Value
  52. //Check if the client has been logged in
  53. value, ok := s.windowsClientLoggedIn.Load(clientUUID)
  54. if !ok {
  55. //Not logged in. Check if this is first connection
  56. cinfo, ok := s.windowsClientNotLoggedIn.Load(clientUUID)
  57. if !ok {
  58. //This is where the arozos data is loss about this client. Rebuild its cookie
  59. //Generate a new UUID for this client
  60. thisWebDAVClientID := uuid.NewV4().String()
  61. //Generate a new HTTP Cookie
  62. http.SetCookie(w, &http.Cookie{
  63. Name: coookieName,
  64. Value: thisWebDAVClientID,
  65. MaxAge: 3600,
  66. })
  67. ip, err := getIP(r)
  68. if err != nil {
  69. ip = "Unknown"
  70. }
  71. if ip == "::1" || ip == "127.0.0.1" {
  72. ip = "localhost"
  73. }
  74. //Store this UUID with the connection
  75. s.windowsClientNotLoggedIn.Store(thisWebDAVClientID, &WindowClientInfo{
  76. Agent: r.Header["User-Agent"][0],
  77. LastConnectionTimestamp: time.Now().Unix(),
  78. UUID: thisWebDAVClientID,
  79. ClientIP: ip,
  80. })
  81. //OK. Serve the READONLY FS for Winwdows to remember this login
  82. s.serveReadOnlyWebDav(w, r)
  83. } else {
  84. //This client is not logged in but connected before
  85. //log.Println("Windows client with assigned UUID: " + clientUUID + " try to access becore login validation")
  86. ///Rewrite the r.URL
  87. //Update last connection timestamp
  88. cinfo.(*WindowClientInfo).LastConnectionTimestamp = time.Now().Unix()
  89. //OK. Serve the READONLY FS for Winwdows to remember this login
  90. s.serveReadOnlyWebDav(w, r)
  91. }
  92. return
  93. } else {
  94. //OK. Serve this user
  95. clientInfo := value.(*WindowClientInfo)
  96. userinfo, err := s.userHandler.GetUserInfoFromUsername(clientInfo.Username)
  97. if err != nil {
  98. //User not exists?
  99. w.WriteHeader(http.StatusInternalServerError)
  100. w.Write([]byte("500 - User not exists"))
  101. return
  102. }
  103. fsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(vroot + ":/")
  104. if err != nil {
  105. log.Println("[WebDAV] Failed to load File System Handler from request root: ", err.Error())
  106. http.Error(w, "Invalid ", http.StatusUnauthorized)
  107. return
  108. }
  109. //Get and serve the file content
  110. fs := s.getFsFromRealRoot(fsh, userinfo.Username, filepath.ToSlash(filepath.Join(s.prefix, vroot)))
  111. fs.ServeHTTP(w, r)
  112. }
  113. }
  114. }
  115. func getIP(r *http.Request) (string, error) {
  116. //Get IP from the X-REAL-IP header
  117. ip := r.Header.Get("X-REAL-IP")
  118. netIP := net.ParseIP(ip)
  119. if netIP != nil {
  120. return ip, nil
  121. }
  122. //Get IP from X-FORWARDED-FOR header
  123. ips := r.Header.Get("X-FORWARDED-FOR")
  124. splitIps := strings.Split(ips, ",")
  125. for _, ip := range splitIps {
  126. netIP := net.ParseIP(ip)
  127. if netIP != nil {
  128. return ip, nil
  129. }
  130. }
  131. //Get IP from RemoteAddr
  132. ip, _, err := net.SplitHostPort(r.RemoteAddr)
  133. if err != nil {
  134. return "", err
  135. }
  136. netIP = net.ParseIP(ip)
  137. if netIP != nil {
  138. return ip, nil
  139. }
  140. return "", fmt.Errorf("No valid ip found")
  141. }