1package httpd 2 3import ( 4 "context" 5 "crypto/tls" 6 "crypto/x509" 7 "errors" 8 "fmt" 9 "log" 10 "net" 11 "net/http" 12 "strings" 13 "time" 14 15 "github.com/go-chi/chi/v5" 16 "github.com/go-chi/chi/v5/middleware" 17 "github.com/go-chi/jwtauth/v5" 18 "github.com/go-chi/render" 19 "github.com/lestrrat-go/jwx/jwa" 20 "github.com/rs/cors" 21 "github.com/rs/xid" 22 23 "github.com/drakkan/sftpgo/v2/common" 24 "github.com/drakkan/sftpgo/v2/dataprovider" 25 "github.com/drakkan/sftpgo/v2/logger" 26 "github.com/drakkan/sftpgo/v2/mfa" 27 "github.com/drakkan/sftpgo/v2/sdk" 28 "github.com/drakkan/sftpgo/v2/smtp" 29 "github.com/drakkan/sftpgo/v2/util" 30 "github.com/drakkan/sftpgo/v2/version" 31) 32 33var ( 34 compressor = middleware.NewCompressor(5) 35 xForwardedProto = http.CanonicalHeaderKey("X-Forwarded-Proto") 36) 37 38type httpdServer struct { 39 binding Binding 40 staticFilesPath string 41 openAPIPath string 42 enableWebAdmin bool 43 enableWebClient bool 44 renderOpenAPI bool 45 router *chi.Mux 46 tokenAuth *jwtauth.JWTAuth 47 signingPassphrase string 48 cors CorsConfig 49} 50 51func newHttpdServer(b Binding, staticFilesPath, signingPassphrase string, cors CorsConfig, 52 openAPIPath string, 53) *httpdServer { 54 if openAPIPath == "" { 55 b.RenderOpenAPI = false 56 } 57 return &httpdServer{ 58 binding: b, 59 staticFilesPath: staticFilesPath, 60 openAPIPath: openAPIPath, 61 enableWebAdmin: b.EnableWebAdmin, 62 enableWebClient: b.EnableWebClient, 63 renderOpenAPI: b.RenderOpenAPI, 64 signingPassphrase: signingPassphrase, 65 cors: cors, 66 } 67} 68 69func (s *httpdServer) listenAndServe() error { 70 s.initializeRouter() 71 httpServer := &http.Server{ 72 Handler: s.router, 73 ReadHeaderTimeout: 30 * time.Second, 74 ReadTimeout: 60 * time.Second, 75 WriteTimeout: 60 * time.Second, 76 IdleTimeout: 60 * time.Second, 77 MaxHeaderBytes: 1 << 16, // 64KB 78 ErrorLog: log.New(&logger.StdLoggerWrapper{Sender: logSender}, "", 0), 79 } 80 if certMgr != nil && s.binding.EnableHTTPS { 81 config := &tls.Config{ 82 GetCertificate: certMgr.GetCertificateFunc(), 83 MinVersion: tls.VersionTLS12, 84 CipherSuites: util.GetTLSCiphersFromNames(s.binding.TLSCipherSuites), 85 PreferServerCipherSuites: true, 86 } 87 logger.Debug(logSender, "", "configured TLS cipher suites for binding %#v: %v", s.binding.GetAddress(), 88 config.CipherSuites) 89 httpServer.TLSConfig = config 90 if s.binding.ClientAuthType == 1 { 91 httpServer.TLSConfig.ClientCAs = certMgr.GetRootCAs() 92 httpServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert 93 httpServer.TLSConfig.VerifyConnection = s.verifyTLSConnection 94 } 95 return util.HTTPListenAndServe(httpServer, s.binding.Address, s.binding.Port, true, logSender) 96 } 97 return util.HTTPListenAndServe(httpServer, s.binding.Address, s.binding.Port, false, logSender) 98} 99 100func (s *httpdServer) verifyTLSConnection(state tls.ConnectionState) error { 101 if certMgr != nil { 102 var clientCrt *x509.Certificate 103 var clientCrtName string 104 if len(state.PeerCertificates) > 0 { 105 clientCrt = state.PeerCertificates[0] 106 clientCrtName = clientCrt.Subject.String() 107 } 108 if len(state.VerifiedChains) == 0 { 109 logger.Warn(logSender, "", "TLS connection cannot be verified: unable to get verification chain") 110 return errors.New("TLS connection cannot be verified: unable to get verification chain") 111 } 112 for _, verifiedChain := range state.VerifiedChains { 113 var caCrt *x509.Certificate 114 if len(verifiedChain) > 0 { 115 caCrt = verifiedChain[len(verifiedChain)-1] 116 } 117 if certMgr.IsRevoked(clientCrt, caCrt) { 118 logger.Debug(logSender, "", "tls handshake error, client certificate %#v has been revoked", clientCrtName) 119 return common.ErrCrtRevoked 120 } 121 } 122 } 123 124 return nil 125} 126 127func (s *httpdServer) refreshCookie(next http.Handler) http.Handler { 128 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 129 s.checkCookieExpiration(w, r) 130 next.ServeHTTP(w, r) 131 }) 132} 133 134func (s *httpdServer) renderClientLoginPage(w http.ResponseWriter, error string) { 135 data := loginPage{ 136 CurrentURL: webClientLoginPath, 137 Version: version.Get().Version, 138 Error: error, 139 CSRFToken: createCSRFToken(), 140 StaticURL: webStaticFilesPath, 141 } 142 if s.binding.showAdminLoginURL() { 143 data.AltLoginURL = webLoginPath 144 } 145 if smtp.IsEnabled() { 146 data.ForgotPwdURL = webClientForgotPwdPath 147 } 148 renderClientTemplate(w, templateClientLogin, data) 149} 150 151func (s *httpdServer) handleClientWebLogin(w http.ResponseWriter, r *http.Request) { 152 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 153 if !dataprovider.HasAdmin() { 154 http.Redirect(w, r, webAdminSetupPath, http.StatusFound) 155 return 156 } 157 s.renderClientLoginPage(w, "") 158} 159 160func (s *httpdServer) handleWebClientLoginPost(w http.ResponseWriter, r *http.Request) { 161 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 162 163 if err := r.ParseForm(); err != nil { 164 s.renderClientLoginPage(w, err.Error()) 165 return 166 } 167 ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) 168 username := r.Form.Get("username") 169 password := r.Form.Get("password") 170 if username == "" || password == "" { 171 updateLoginMetrics(&dataprovider.User{BaseUser: sdk.BaseUser{Username: username}}, ipAddr, common.ErrNoCredentials) 172 s.renderClientLoginPage(w, "Invalid credentials") 173 return 174 } 175 if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil { 176 updateLoginMetrics(&dataprovider.User{BaseUser: sdk.BaseUser{Username: username}}, ipAddr, err) 177 s.renderClientLoginPage(w, err.Error()) 178 return 179 } 180 181 if err := common.Config.ExecutePostConnectHook(ipAddr, common.ProtocolHTTP); err != nil { 182 s.renderClientLoginPage(w, fmt.Sprintf("access denied by post connect hook: %v", err)) 183 return 184 } 185 186 user, err := dataprovider.CheckUserAndPass(username, password, ipAddr, common.ProtocolHTTP) 187 if err != nil { 188 updateLoginMetrics(&user, ipAddr, err) 189 s.renderClientLoginPage(w, dataprovider.ErrInvalidCredentials.Error()) 190 return 191 } 192 connectionID := fmt.Sprintf("%v_%v", common.ProtocolHTTP, xid.New().String()) 193 if err := checkHTTPClientUser(&user, r, connectionID); err != nil { 194 updateLoginMetrics(&user, ipAddr, err) 195 s.renderClientLoginPage(w, err.Error()) 196 return 197 } 198 199 defer user.CloseFs() //nolint:errcheck 200 err = user.CheckFsRoot(connectionID) 201 if err != nil { 202 logger.Warn(logSender, connectionID, "unable to check fs root: %v", err) 203 updateLoginMetrics(&user, ipAddr, common.ErrInternalFailure) 204 s.renderClientLoginPage(w, err.Error()) 205 return 206 } 207 s.loginUser(w, r, &user, connectionID, ipAddr, false, s.renderClientLoginPage) 208} 209 210func (s *httpdServer) handleWebClientPasswordResetPost(w http.ResponseWriter, r *http.Request) { 211 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 212 err := r.ParseForm() 213 if err != nil { 214 renderClientResetPwdPage(w, err.Error()) 215 return 216 } 217 if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil { 218 renderClientForbiddenPage(w, r, err.Error()) 219 return 220 } 221 _, user, err := handleResetPassword(r, r.Form.Get("code"), r.Form.Get("password"), false) 222 if err != nil { 223 if e, ok := err.(*util.ValidationError); ok { 224 renderClientResetPwdPage(w, e.GetErrorString()) 225 return 226 } 227 renderClientResetPwdPage(w, err.Error()) 228 return 229 } 230 connectionID := fmt.Sprintf("%v_%v", common.ProtocolHTTP, xid.New().String()) 231 if err := checkHTTPClientUser(user, r, connectionID); err != nil { 232 renderClientResetPwdPage(w, fmt.Sprintf("Password reset successfully but unable to login: %v", err.Error())) 233 return 234 } 235 236 defer user.CloseFs() //nolint:errcheck 237 err = user.CheckFsRoot(connectionID) 238 if err != nil { 239 logger.Warn(logSender, connectionID, "unable to check fs root: %v", err) 240 renderClientResetPwdPage(w, fmt.Sprintf("Password reset successfully but unable to login: %v", err.Error())) 241 return 242 } 243 ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) 244 s.loginUser(w, r, user, connectionID, ipAddr, false, renderClientResetPwdPage) 245} 246 247func (s *httpdServer) handleWebClientTwoFactorRecoveryPost(w http.ResponseWriter, r *http.Request) { 248 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 249 claims, err := getTokenClaims(r) 250 if err != nil { 251 renderNotFoundPage(w, r, nil) 252 return 253 } 254 if err := r.ParseForm(); err != nil { 255 renderClientTwoFactorRecoveryPage(w, err.Error()) 256 return 257 } 258 username := claims.Username 259 recoveryCode := r.Form.Get("recovery_code") 260 if username == "" || recoveryCode == "" { 261 renderClientTwoFactorRecoveryPage(w, "Invalid credentials") 262 return 263 } 264 if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil { 265 renderClientTwoFactorRecoveryPage(w, err.Error()) 266 return 267 } 268 user, err := dataprovider.UserExists(username) 269 if err != nil { 270 renderClientTwoFactorRecoveryPage(w, "Invalid credentials") 271 return 272 } 273 if !user.Filters.TOTPConfig.Enabled || !util.IsStringInSlice(common.ProtocolHTTP, user.Filters.TOTPConfig.Protocols) { 274 renderClientTwoFactorPage(w, "Two factory authentication is not enabled") 275 return 276 } 277 for idx, code := range user.Filters.RecoveryCodes { 278 if err := code.Secret.Decrypt(); err != nil { 279 renderClientInternalServerErrorPage(w, r, fmt.Errorf("unable to decrypt recovery code: %w", err)) 280 return 281 } 282 if code.Secret.GetPayload() == recoveryCode { 283 if code.Used { 284 renderClientTwoFactorRecoveryPage(w, "This recovery code was already used") 285 return 286 } 287 user.Filters.RecoveryCodes[idx].Used = true 288 err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)) 289 if err != nil { 290 logger.Warn(logSender, "", "unable to set the recovery code %#v as used: %v", recoveryCode, err) 291 renderClientInternalServerErrorPage(w, r, errors.New("unable to set the recovery code as used")) 292 return 293 } 294 connectionID := fmt.Sprintf("%v_%v", common.ProtocolHTTP, xid.New().String()) 295 s.loginUser(w, r, &user, connectionID, util.GetIPFromRemoteAddress(r.RemoteAddr), true, 296 renderClientTwoFactorRecoveryPage) 297 return 298 } 299 } 300 renderClientTwoFactorRecoveryPage(w, "Invalid recovery code") 301} 302 303func (s *httpdServer) handleWebClientTwoFactorPost(w http.ResponseWriter, r *http.Request) { 304 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 305 claims, err := getTokenClaims(r) 306 if err != nil { 307 renderNotFoundPage(w, r, nil) 308 return 309 } 310 if err := r.ParseForm(); err != nil { 311 renderClientTwoFactorPage(w, err.Error()) 312 return 313 } 314 username := claims.Username 315 passcode := r.Form.Get("passcode") 316 if username == "" || passcode == "" { 317 renderClientTwoFactorPage(w, "Invalid credentials") 318 return 319 } 320 if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil { 321 renderClientTwoFactorPage(w, err.Error()) 322 return 323 } 324 user, err := dataprovider.UserExists(username) 325 if err != nil { 326 renderClientTwoFactorPage(w, "Invalid credentials") 327 return 328 } 329 if !user.Filters.TOTPConfig.Enabled || !util.IsStringInSlice(common.ProtocolHTTP, user.Filters.TOTPConfig.Protocols) { 330 renderClientTwoFactorPage(w, "Two factory authentication is not enabled") 331 return 332 } 333 err = user.Filters.TOTPConfig.Secret.Decrypt() 334 if err != nil { 335 renderClientInternalServerErrorPage(w, r, err) 336 return 337 } 338 match, err := mfa.ValidateTOTPPasscode(user.Filters.TOTPConfig.ConfigName, passcode, 339 user.Filters.TOTPConfig.Secret.GetPayload()) 340 if !match || err != nil { 341 renderClientTwoFactorPage(w, "Invalid authentication code") 342 return 343 } 344 connectionID := fmt.Sprintf("%v_%v", common.ProtocolHTTP, xid.New().String()) 345 s.loginUser(w, r, &user, connectionID, util.GetIPFromRemoteAddress(r.RemoteAddr), true, renderClientTwoFactorPage) 346} 347 348func (s *httpdServer) handleWebAdminTwoFactorRecoveryPost(w http.ResponseWriter, r *http.Request) { 349 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 350 claims, err := getTokenClaims(r) 351 if err != nil { 352 renderNotFoundPage(w, r, nil) 353 return 354 } 355 if err := r.ParseForm(); err != nil { 356 renderTwoFactorRecoveryPage(w, err.Error()) 357 return 358 } 359 username := claims.Username 360 recoveryCode := r.Form.Get("recovery_code") 361 if username == "" || recoveryCode == "" { 362 renderTwoFactorRecoveryPage(w, "Invalid credentials") 363 return 364 } 365 if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil { 366 renderTwoFactorRecoveryPage(w, err.Error()) 367 return 368 } 369 admin, err := dataprovider.AdminExists(username) 370 if err != nil { 371 renderTwoFactorRecoveryPage(w, "Invalid credentials") 372 return 373 } 374 if !admin.Filters.TOTPConfig.Enabled { 375 renderTwoFactorRecoveryPage(w, "Two factory authentication is not enabled") 376 return 377 } 378 for idx, code := range admin.Filters.RecoveryCodes { 379 if err := code.Secret.Decrypt(); err != nil { 380 renderInternalServerErrorPage(w, r, fmt.Errorf("unable to decrypt recovery code: %w", err)) 381 return 382 } 383 if code.Secret.GetPayload() == recoveryCode { 384 if code.Used { 385 renderTwoFactorRecoveryPage(w, "This recovery code was already used") 386 return 387 } 388 admin.Filters.RecoveryCodes[idx].Used = true 389 err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)) 390 if err != nil { 391 logger.Warn(logSender, "", "unable to set the recovery code %#v as used: %v", recoveryCode, err) 392 renderInternalServerErrorPage(w, r, errors.New("unable to set the recovery code as used")) 393 return 394 } 395 s.loginAdmin(w, r, &admin, true, renderTwoFactorRecoveryPage) 396 return 397 } 398 } 399 renderTwoFactorRecoveryPage(w, "Invalid recovery code") 400} 401 402func (s *httpdServer) handleWebAdminTwoFactorPost(w http.ResponseWriter, r *http.Request) { 403 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 404 claims, err := getTokenClaims(r) 405 if err != nil { 406 renderNotFoundPage(w, r, nil) 407 return 408 } 409 if err := r.ParseForm(); err != nil { 410 renderTwoFactorPage(w, err.Error()) 411 return 412 } 413 username := claims.Username 414 passcode := r.Form.Get("passcode") 415 if username == "" || passcode == "" { 416 renderTwoFactorPage(w, "Invalid credentials") 417 return 418 } 419 if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil { 420 renderTwoFactorPage(w, err.Error()) 421 return 422 } 423 admin, err := dataprovider.AdminExists(username) 424 if err != nil { 425 renderTwoFactorPage(w, "Invalid credentials") 426 return 427 } 428 if !admin.Filters.TOTPConfig.Enabled { 429 renderTwoFactorPage(w, "Two factory authentication is not enabled") 430 return 431 } 432 err = admin.Filters.TOTPConfig.Secret.Decrypt() 433 if err != nil { 434 renderInternalServerErrorPage(w, r, err) 435 return 436 } 437 match, err := mfa.ValidateTOTPPasscode(admin.Filters.TOTPConfig.ConfigName, passcode, 438 admin.Filters.TOTPConfig.Secret.GetPayload()) 439 if !match || err != nil { 440 renderTwoFactorPage(w, "Invalid authentication code") 441 return 442 } 443 s.loginAdmin(w, r, &admin, true, renderTwoFactorPage) 444} 445 446func (s *httpdServer) handleWebAdminLoginPost(w http.ResponseWriter, r *http.Request) { 447 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 448 if err := r.ParseForm(); err != nil { 449 s.renderAdminLoginPage(w, err.Error()) 450 return 451 } 452 username := r.Form.Get("username") 453 password := r.Form.Get("password") 454 if username == "" || password == "" { 455 s.renderAdminLoginPage(w, "Invalid credentials") 456 return 457 } 458 if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil { 459 s.renderAdminLoginPage(w, err.Error()) 460 return 461 } 462 admin, err := dataprovider.CheckAdminAndPass(username, password, util.GetIPFromRemoteAddress(r.RemoteAddr)) 463 if err != nil { 464 s.renderAdminLoginPage(w, err.Error()) 465 return 466 } 467 s.loginAdmin(w, r, &admin, false, s.renderAdminLoginPage) 468} 469 470func (s *httpdServer) renderAdminLoginPage(w http.ResponseWriter, error string) { 471 data := loginPage{ 472 CurrentURL: webLoginPath, 473 Version: version.Get().Version, 474 Error: error, 475 CSRFToken: createCSRFToken(), 476 StaticURL: webStaticFilesPath, 477 } 478 if s.binding.showClientLoginURL() { 479 data.AltLoginURL = webClientLoginPath 480 } 481 if smtp.IsEnabled() { 482 data.ForgotPwdURL = webAdminForgotPwdPath 483 } 484 renderAdminTemplate(w, templateLogin, data) 485} 486 487func (s *httpdServer) handleWebAdminLogin(w http.ResponseWriter, r *http.Request) { 488 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 489 if !dataprovider.HasAdmin() { 490 http.Redirect(w, r, webAdminSetupPath, http.StatusFound) 491 return 492 } 493 s.renderAdminLoginPage(w, "") 494} 495 496func (s *httpdServer) handleWebAdminPasswordResetPost(w http.ResponseWriter, r *http.Request) { 497 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 498 err := r.ParseForm() 499 if err != nil { 500 renderResetPwdPage(w, err.Error()) 501 return 502 } 503 if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil { 504 renderForbiddenPage(w, r, err.Error()) 505 return 506 } 507 admin, _, err := handleResetPassword(r, r.Form.Get("code"), r.Form.Get("password"), true) 508 if err != nil { 509 if e, ok := err.(*util.ValidationError); ok { 510 renderResetPwdPage(w, e.GetErrorString()) 511 return 512 } 513 renderResetPwdPage(w, err.Error()) 514 return 515 } 516 517 s.loginAdmin(w, r, admin, false, renderResetPwdPage) 518} 519 520func (s *httpdServer) handleWebAdminSetupPost(w http.ResponseWriter, r *http.Request) { 521 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 522 if dataprovider.HasAdmin() { 523 renderBadRequestPage(w, r, errors.New("an admin user already exists")) 524 return 525 } 526 err := r.ParseForm() 527 if err != nil { 528 renderAdminSetupPage(w, r, "", err.Error()) 529 return 530 } 531 if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil { 532 renderForbiddenPage(w, r, err.Error()) 533 return 534 } 535 username := r.Form.Get("username") 536 password := r.Form.Get("password") 537 confirmPassword := r.Form.Get("confirm_password") 538 if username == "" { 539 renderAdminSetupPage(w, r, username, "Please set a username") 540 return 541 } 542 if password == "" { 543 renderAdminSetupPage(w, r, username, "Please set a password") 544 return 545 } 546 if password != confirmPassword { 547 renderAdminSetupPage(w, r, username, "Passwords mismatch") 548 return 549 } 550 admin := dataprovider.Admin{ 551 Username: username, 552 Password: password, 553 Status: 1, 554 Permissions: []string{dataprovider.PermAdminAny}, 555 } 556 err = dataprovider.AddAdmin(&admin, username, util.GetIPFromRemoteAddress(r.RemoteAddr)) 557 if err != nil { 558 renderAdminSetupPage(w, r, username, err.Error()) 559 return 560 } 561 s.loginAdmin(w, r, &admin, false, nil) 562} 563 564func (s *httpdServer) loginUser( 565 w http.ResponseWriter, r *http.Request, user *dataprovider.User, connectionID, ipAddr string, 566 isSecondFactorAuth bool, errorFunc func(w http.ResponseWriter, error string), 567) { 568 c := jwtTokenClaims{ 569 Username: user.Username, 570 Permissions: user.Filters.WebClient, 571 Signature: user.GetSignature(), 572 } 573 574 audience := tokenAudienceWebClient 575 if user.Filters.TOTPConfig.Enabled && util.IsStringInSlice(common.ProtocolHTTP, user.Filters.TOTPConfig.Protocols) && 576 user.CanManageMFA() && !isSecondFactorAuth { 577 audience = tokenAudienceWebClientPartial 578 } 579 580 err := c.createAndSetCookie(w, r, s.tokenAuth, audience) 581 if err != nil { 582 logger.Warn(logSender, connectionID, "unable to set user login cookie %v", err) 583 updateLoginMetrics(user, ipAddr, common.ErrInternalFailure) 584 errorFunc(w, err.Error()) 585 return 586 } 587 if isSecondFactorAuth { 588 invalidateToken(r) 589 } 590 if audience == tokenAudienceWebClientPartial { 591 http.Redirect(w, r, webClientTwoFactorPath, http.StatusFound) 592 return 593 } 594 updateLoginMetrics(user, ipAddr, err) 595 dataprovider.UpdateLastLogin(user) 596 http.Redirect(w, r, webClientFilesPath, http.StatusFound) 597} 598 599func (s *httpdServer) loginAdmin( 600 w http.ResponseWriter, r *http.Request, admin *dataprovider.Admin, 601 isSecondFactorAuth bool, errorFunc func(w http.ResponseWriter, error string), 602) { 603 c := jwtTokenClaims{ 604 Username: admin.Username, 605 Permissions: admin.Permissions, 606 Signature: admin.GetSignature(), 607 } 608 609 audience := tokenAudienceWebAdmin 610 if admin.Filters.TOTPConfig.Enabled && admin.CanManageMFA() && !isSecondFactorAuth { 611 audience = tokenAudienceWebAdminPartial 612 } 613 614 err := c.createAndSetCookie(w, r, s.tokenAuth, audience) 615 if err != nil { 616 logger.Warn(logSender, "", "unable to set admin login cookie %v", err) 617 if errorFunc == nil { 618 renderAdminSetupPage(w, r, admin.Username, err.Error()) 619 return 620 } 621 errorFunc(w, err.Error()) 622 return 623 } 624 if isSecondFactorAuth { 625 invalidateToken(r) 626 } 627 if audience == tokenAudienceWebAdminPartial { 628 http.Redirect(w, r, webAdminTwoFactorPath, http.StatusFound) 629 return 630 } 631 dataprovider.UpdateAdminLastLogin(admin) 632 http.Redirect(w, r, webUsersPath, http.StatusFound) 633} 634 635func (s *httpdServer) logout(w http.ResponseWriter, r *http.Request) { 636 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 637 invalidateToken(r) 638 sendAPIResponse(w, r, nil, "Your token has been invalidated", http.StatusOK) 639} 640 641func (s *httpdServer) getUserToken(w http.ResponseWriter, r *http.Request) { 642 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 643 ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) 644 username, password, ok := r.BasicAuth() 645 if !ok { 646 updateLoginMetrics(&dataprovider.User{BaseUser: sdk.BaseUser{Username: username}}, ipAddr, common.ErrNoCredentials) 647 w.Header().Set(common.HTTPAuthenticationHeader, basicRealm) 648 sendAPIResponse(w, r, nil, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) 649 return 650 } 651 if username == "" || password == "" { 652 updateLoginMetrics(&dataprovider.User{BaseUser: sdk.BaseUser{Username: username}}, ipAddr, common.ErrNoCredentials) 653 w.Header().Set(common.HTTPAuthenticationHeader, basicRealm) 654 sendAPIResponse(w, r, nil, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) 655 return 656 } 657 if err := common.Config.ExecutePostConnectHook(ipAddr, common.ProtocolHTTP); err != nil { 658 sendAPIResponse(w, r, err, http.StatusText(http.StatusForbidden), http.StatusForbidden) 659 return 660 } 661 user, err := dataprovider.CheckUserAndPass(username, password, ipAddr, common.ProtocolHTTP) 662 if err != nil { 663 w.Header().Set(common.HTTPAuthenticationHeader, basicRealm) 664 updateLoginMetrics(&user, ipAddr, err) 665 sendAPIResponse(w, r, dataprovider.ErrInvalidCredentials, http.StatusText(http.StatusUnauthorized), 666 http.StatusUnauthorized) 667 return 668 } 669 connectionID := fmt.Sprintf("%v_%v", common.ProtocolHTTP, xid.New().String()) 670 if err := checkHTTPClientUser(&user, r, connectionID); err != nil { 671 updateLoginMetrics(&user, ipAddr, err) 672 sendAPIResponse(w, r, err, http.StatusText(http.StatusForbidden), http.StatusForbidden) 673 return 674 } 675 676 if user.Filters.TOTPConfig.Enabled && util.IsStringInSlice(common.ProtocolHTTP, user.Filters.TOTPConfig.Protocols) { 677 passcode := r.Header.Get(otpHeaderCode) 678 if passcode == "" { 679 logger.Debug(logSender, "", "TOTP enabled for user %#v and not passcode provided, authentication refused", user.Username) 680 w.Header().Set(common.HTTPAuthenticationHeader, basicRealm) 681 updateLoginMetrics(&user, ipAddr, dataprovider.ErrInvalidCredentials) 682 sendAPIResponse(w, r, dataprovider.ErrInvalidCredentials, http.StatusText(http.StatusUnauthorized), 683 http.StatusUnauthorized) 684 return 685 } 686 err = user.Filters.TOTPConfig.Secret.Decrypt() 687 if err != nil { 688 updateLoginMetrics(&user, ipAddr, common.ErrInternalFailure) 689 sendAPIResponse(w, r, fmt.Errorf("unable to decrypt TOTP secret: %w", err), http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 690 return 691 } 692 match, err := mfa.ValidateTOTPPasscode(user.Filters.TOTPConfig.ConfigName, passcode, 693 user.Filters.TOTPConfig.Secret.GetPayload()) 694 if !match || err != nil { 695 logger.Debug(logSender, "invalid passcode for user %#v, match? %v, err: %v", user.Username, match, err) 696 w.Header().Set(common.HTTPAuthenticationHeader, basicRealm) 697 updateLoginMetrics(&user, ipAddr, dataprovider.ErrInvalidCredentials) 698 sendAPIResponse(w, r, dataprovider.ErrInvalidCredentials, http.StatusText(http.StatusUnauthorized), 699 http.StatusUnauthorized) 700 return 701 } 702 } 703 704 defer user.CloseFs() //nolint:errcheck 705 err = user.CheckFsRoot(connectionID) 706 if err != nil { 707 logger.Warn(logSender, connectionID, "unable to check fs root: %v", err) 708 updateLoginMetrics(&user, ipAddr, common.ErrInternalFailure) 709 sendAPIResponse(w, r, err, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 710 return 711 } 712 713 s.generateAndSendUserToken(w, r, ipAddr, user) 714} 715 716func (s *httpdServer) generateAndSendUserToken(w http.ResponseWriter, r *http.Request, ipAddr string, user dataprovider.User) { 717 c := jwtTokenClaims{ 718 Username: user.Username, 719 Permissions: user.Filters.WebClient, 720 Signature: user.GetSignature(), 721 } 722 723 resp, err := c.createTokenResponse(s.tokenAuth, tokenAudienceAPIUser) 724 725 if err != nil { 726 updateLoginMetrics(&user, ipAddr, common.ErrInternalFailure) 727 sendAPIResponse(w, r, err, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 728 return 729 } 730 updateLoginMetrics(&user, ipAddr, err) 731 dataprovider.UpdateLastLogin(&user) 732 733 render.JSON(w, r, resp) 734} 735 736func (s *httpdServer) getToken(w http.ResponseWriter, r *http.Request) { 737 username, password, ok := r.BasicAuth() 738 if !ok { 739 w.Header().Set(common.HTTPAuthenticationHeader, basicRealm) 740 sendAPIResponse(w, r, nil, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) 741 return 742 } 743 admin, err := dataprovider.CheckAdminAndPass(username, password, util.GetIPFromRemoteAddress(r.RemoteAddr)) 744 if err != nil { 745 w.Header().Set(common.HTTPAuthenticationHeader, basicRealm) 746 sendAPIResponse(w, r, err, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) 747 return 748 } 749 if admin.Filters.TOTPConfig.Enabled { 750 passcode := r.Header.Get(otpHeaderCode) 751 if passcode == "" { 752 logger.Debug(logSender, "", "TOTP enabled for admin %#v and not passcode provided, authentication refused", admin.Username) 753 w.Header().Set(common.HTTPAuthenticationHeader, basicRealm) 754 sendAPIResponse(w, r, dataprovider.ErrInvalidCredentials, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) 755 return 756 } 757 err = admin.Filters.TOTPConfig.Secret.Decrypt() 758 if err != nil { 759 sendAPIResponse(w, r, fmt.Errorf("unable to decrypt TOTP secret: %w", err), 760 http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 761 return 762 } 763 match, err := mfa.ValidateTOTPPasscode(admin.Filters.TOTPConfig.ConfigName, passcode, 764 admin.Filters.TOTPConfig.Secret.GetPayload()) 765 if !match || err != nil { 766 logger.Debug(logSender, "invalid passcode for admin %#v, match? %v, err: %v", admin.Username, match, err) 767 w.Header().Set(common.HTTPAuthenticationHeader, basicRealm) 768 sendAPIResponse(w, r, dataprovider.ErrInvalidCredentials, http.StatusText(http.StatusUnauthorized), 769 http.StatusUnauthorized) 770 return 771 } 772 } 773 774 s.generateAndSendToken(w, r, admin) 775} 776 777func (s *httpdServer) generateAndSendToken(w http.ResponseWriter, r *http.Request, admin dataprovider.Admin) { 778 c := jwtTokenClaims{ 779 Username: admin.Username, 780 Permissions: admin.Permissions, 781 Signature: admin.GetSignature(), 782 } 783 784 resp, err := c.createTokenResponse(s.tokenAuth, tokenAudienceAPI) 785 786 if err != nil { 787 sendAPIResponse(w, r, err, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 788 return 789 } 790 791 dataprovider.UpdateAdminLastLogin(&admin) 792 render.JSON(w, r, resp) 793} 794 795func (s *httpdServer) checkCookieExpiration(w http.ResponseWriter, r *http.Request) { 796 token, claims, err := jwtauth.FromContext(r.Context()) 797 if err != nil { 798 return 799 } 800 tokenClaims := jwtTokenClaims{} 801 tokenClaims.Decode(claims) 802 if tokenClaims.Username == "" || tokenClaims.Signature == "" { 803 return 804 } 805 if time.Until(token.Expiration()) > tokenRefreshThreshold { 806 return 807 } 808 if util.IsStringInSlice(tokenAudienceWebClient, token.Audience()) { 809 s.refreshClientToken(w, r, tokenClaims) 810 } else { 811 s.refreshAdminToken(w, r, tokenClaims) 812 } 813} 814 815func (s *httpdServer) refreshClientToken(w http.ResponseWriter, r *http.Request, tokenClaims jwtTokenClaims) { 816 user, err := dataprovider.UserExists(tokenClaims.Username) 817 if err != nil { 818 return 819 } 820 if user.GetSignature() != tokenClaims.Signature { 821 logger.Debug(logSender, "", "signature mismatch for user %#v, unable to refresh cookie", user.Username) 822 return 823 } 824 if err := checkHTTPClientUser(&user, r, xid.New().String()); err != nil { 825 logger.Debug(logSender, "", "unable to refresh cookie for user %#v: %v", user.Username, err) 826 return 827 } 828 829 tokenClaims.Permissions = user.Filters.WebClient 830 logger.Debug(logSender, "", "cookie refreshed for user %#v", user.Username) 831 tokenClaims.createAndSetCookie(w, r, s.tokenAuth, tokenAudienceWebClient) //nolint:errcheck 832} 833 834func (s *httpdServer) refreshAdminToken(w http.ResponseWriter, r *http.Request, tokenClaims jwtTokenClaims) { 835 admin, err := dataprovider.AdminExists(tokenClaims.Username) 836 if err != nil { 837 return 838 } 839 if admin.Status != 1 { 840 logger.Debug(logSender, "", "admin %#v is disabled, unable to refresh cookie", admin.Username) 841 return 842 } 843 if admin.GetSignature() != tokenClaims.Signature { 844 logger.Debug(logSender, "", "signature mismatch for admin %#v, unable to refresh cookie", admin.Username) 845 return 846 } 847 if !admin.CanLoginFromIP(util.GetIPFromRemoteAddress(r.RemoteAddr)) { 848 logger.Debug(logSender, "", "admin %#v cannot login from %v, unable to refresh cookie", admin.Username, r.RemoteAddr) 849 return 850 } 851 tokenClaims.Permissions = admin.Permissions 852 logger.Debug(logSender, "", "cookie refreshed for admin %#v", admin.Username) 853 tokenClaims.createAndSetCookie(w, r, s.tokenAuth, tokenAudienceWebAdmin) //nolint:errcheck 854} 855 856func (s *httpdServer) updateContextFromCookie(r *http.Request) *http.Request { 857 token, _, err := jwtauth.FromContext(r.Context()) 858 if token == nil || err != nil { 859 _, err = r.Cookie("jwt") 860 if err != nil { 861 return r 862 } 863 token, err = jwtauth.VerifyRequest(s.tokenAuth, r, jwtauth.TokenFromCookie) 864 ctx := jwtauth.NewContext(r.Context(), token, err) 865 return r.WithContext(ctx) 866 } 867 return r 868} 869 870func (s *httpdServer) checkConnection(next http.Handler) http.Handler { 871 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 872 ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) 873 ip := net.ParseIP(ipAddr) 874 if ip != nil { 875 for _, allow := range s.binding.allowHeadersFrom { 876 if allow(ip) { 877 parsedIP := util.GetRealIP(r) 878 if parsedIP != "" { 879 ipAddr = parsedIP 880 r.RemoteAddr = ipAddr 881 } 882 if forwardedProto := r.Header.Get(xForwardedProto); forwardedProto != "" { 883 ctx := context.WithValue(r.Context(), forwardedProtoKey, forwardedProto) 884 r = r.WithContext(ctx) 885 } 886 break 887 } 888 } 889 } 890 891 common.Connections.AddClientConnection(ipAddr) 892 defer common.Connections.RemoveClientConnection(ipAddr) 893 894 if !common.Connections.IsNewConnectionAllowed(ipAddr) { 895 logger.Log(logger.LevelDebug, common.ProtocolHTTP, "", "connection refused, configured limit reached") 896 s.sendForbiddenResponse(w, r, "configured connections limit reached") 897 return 898 } 899 if common.IsBanned(ipAddr) { 900 s.sendForbiddenResponse(w, r, "your IP address is banned") 901 return 902 } 903 if delay, err := common.LimitRate(common.ProtocolHTTP, ipAddr); err != nil { 904 delay += 499999999 * time.Nanosecond 905 w.Header().Set("Retry-After", fmt.Sprintf("%.0f", delay.Seconds())) 906 w.Header().Set("X-Retry-In", delay.String()) 907 s.sendTooManyRequestResponse(w, r, err) 908 return 909 } 910 911 next.ServeHTTP(w, r) 912 }) 913} 914 915func (s *httpdServer) sendTooManyRequestResponse(w http.ResponseWriter, r *http.Request, err error) { 916 if (s.enableWebAdmin || s.enableWebClient) && isWebRequest(r) { 917 r = s.updateContextFromCookie(r) 918 if s.enableWebClient && (isWebClientRequest(r) || !s.enableWebAdmin) { 919 renderClientMessagePage(w, r, http.StatusText(http.StatusTooManyRequests), "Rate limit exceeded", 920 http.StatusTooManyRequests, err, "") 921 return 922 } 923 renderMessagePage(w, r, http.StatusText(http.StatusTooManyRequests), "Rate limit exceeded", http.StatusTooManyRequests, 924 err, "") 925 return 926 } 927 sendAPIResponse(w, r, err, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) 928} 929 930func (s *httpdServer) sendForbiddenResponse(w http.ResponseWriter, r *http.Request, message string) { 931 if (s.enableWebAdmin || s.enableWebClient) && isWebRequest(r) { 932 r = s.updateContextFromCookie(r) 933 if s.enableWebClient && (isWebClientRequest(r) || !s.enableWebAdmin) { 934 renderClientForbiddenPage(w, r, message) 935 return 936 } 937 renderForbiddenPage(w, r, message) 938 return 939 } 940 sendAPIResponse(w, r, errors.New(message), message, http.StatusForbidden) 941} 942 943func (s *httpdServer) redirectToWebPath(w http.ResponseWriter, r *http.Request, webPath string) { 944 if dataprovider.HasAdmin() { 945 http.Redirect(w, r, webPath, http.StatusMovedPermanently) 946 return 947 } 948 if s.enableWebAdmin { 949 http.Redirect(w, r, webAdminSetupPath, http.StatusFound) 950 } 951} 952 953func (s *httpdServer) isStaticFileURL(r *http.Request) bool { 954 var urlPath string 955 rctx := chi.RouteContext(r.Context()) 956 if rctx != nil && rctx.RoutePath != "" { 957 urlPath = rctx.RoutePath 958 } else { 959 urlPath = r.URL.Path 960 } 961 return !strings.HasPrefix(urlPath, webOpenAPIPath) && !strings.HasPrefix(urlPath, webStaticFilesPath) 962} 963 964func (s *httpdServer) initializeRouter() { 965 s.tokenAuth = jwtauth.New(jwa.HS256.String(), getSigningKey(s.signingPassphrase), nil) 966 s.router = chi.NewRouter() 967 968 s.router.Use(middleware.RequestID) 969 s.router.Use(s.checkConnection) 970 s.router.Use(logger.NewStructuredLogger(logger.GetLogger())) 971 s.router.Use(recoverer) 972 if s.cors.Enabled { 973 c := cors.New(cors.Options{ 974 AllowedOrigins: s.cors.AllowedOrigins, 975 AllowedMethods: s.cors.AllowedMethods, 976 AllowedHeaders: s.cors.AllowedHeaders, 977 ExposedHeaders: s.cors.ExposedHeaders, 978 MaxAge: s.cors.MaxAge, 979 AllowCredentials: s.cors.AllowCredentials, 980 }) 981 s.router.Use(c.Handler) 982 } 983 s.router.Use(middleware.GetHead) 984 // StripSlashes causes infinite redirects at the root path if used with http.FileServer 985 s.router.Use(middleware.Maybe(middleware.StripSlashes, s.isStaticFileURL)) 986 987 s.router.NotFound(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 988 r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) 989 if (s.enableWebAdmin || s.enableWebClient) && isWebRequest(r) { 990 r = s.updateContextFromCookie(r) 991 if s.enableWebClient && (isWebClientRequest(r) || !s.enableWebAdmin) { 992 renderClientNotFoundPage(w, r, nil) 993 return 994 } 995 renderNotFoundPage(w, r, nil) 996 return 997 } 998 sendAPIResponse(w, r, nil, http.StatusText(http.StatusNotFound), http.StatusNotFound) 999 })) 1000 1001 s.router.Get(healthzPath, func(w http.ResponseWriter, r *http.Request) { 1002 render.PlainText(w, r, "ok") 1003 }) 1004 1005 // share API exposed to external users 1006 s.router.Get(sharesPath+"/{id}", downloadFromShare) 1007 s.router.Post(sharesPath+"/{id}", uploadToShare) 1008 1009 s.router.Get(tokenPath, s.getToken) 1010 s.router.Post(adminPath+"/{username}/forgot-password", forgotAdminPassword) 1011 s.router.Post(adminPath+"/{username}/reset-password", resetAdminPassword) 1012 s.router.Post(userPath+"/{username}/forgot-password", forgotUserPassword) 1013 s.router.Post(userPath+"/{username}/reset-password", resetUserPassword) 1014 1015 s.router.Group(func(router chi.Router) { 1016 router.Use(checkAPIKeyAuth(s.tokenAuth, dataprovider.APIKeyScopeAdmin)) 1017 router.Use(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromHeader)) 1018 router.Use(jwtAuthenticatorAPI) 1019 1020 router.Get(versionPath, func(w http.ResponseWriter, r *http.Request) { 1021 r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) 1022 render.JSON(w, r, version.Get()) 1023 }) 1024 1025 router.With(forbidAPIKeyAuthentication).Get(logoutPath, s.logout) 1026 router.With(forbidAPIKeyAuthentication).Get(adminProfilePath, getAdminProfile) 1027 router.With(forbidAPIKeyAuthentication).Put(adminProfilePath, updateAdminProfile) 1028 router.With(forbidAPIKeyAuthentication).Put(adminPwdPath, changeAdminPassword) 1029 // compatibility layer to remove in v2.2 1030 router.With(forbidAPIKeyAuthentication).Put(adminPwdCompatPath, changeAdminPassword) 1031 // admin TOTP APIs 1032 router.With(forbidAPIKeyAuthentication).Get(adminTOTPConfigsPath, getTOTPConfigs) 1033 router.With(forbidAPIKeyAuthentication).Post(adminTOTPGeneratePath, generateTOTPSecret) 1034 router.With(forbidAPIKeyAuthentication).Post(adminTOTPValidatePath, validateTOTPPasscode) 1035 router.With(forbidAPIKeyAuthentication).Post(adminTOTPSavePath, saveTOTPConfig) 1036 router.With(forbidAPIKeyAuthentication).Get(admin2FARecoveryCodesPath, getRecoveryCodes) 1037 router.With(forbidAPIKeyAuthentication).Post(admin2FARecoveryCodesPath, generateRecoveryCodes) 1038 1039 router.With(checkPerm(dataprovider.PermAdminViewServerStatus)). 1040 Get(serverStatusPath, func(w http.ResponseWriter, r *http.Request) { 1041 r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) 1042 render.JSON(w, r, getServicesStatus()) 1043 }) 1044 1045 router.With(checkPerm(dataprovider.PermAdminViewConnections)). 1046 Get(activeConnectionsPath, func(w http.ResponseWriter, r *http.Request) { 1047 r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) 1048 render.JSON(w, r, common.Connections.GetStats()) 1049 }) 1050 1051 router.With(checkPerm(dataprovider.PermAdminCloseConnections)). 1052 Delete(activeConnectionsPath+"/{connectionID}", handleCloseConnection) 1053 router.With(checkPerm(dataprovider.PermAdminQuotaScans)).Get(quotaScanPath, getUsersQuotaScans) 1054 router.With(checkPerm(dataprovider.PermAdminQuotaScans)).Get(quotasBasePath+"/users/scans", getUsersQuotaScans) 1055 router.With(checkPerm(dataprovider.PermAdminQuotaScans)).Post(quotaScanPath, startUserQuotaScanCompat) 1056 router.With(checkPerm(dataprovider.PermAdminQuotaScans)).Post(quotasBasePath+"/users/{username}/scan", startUserQuotaScan) 1057 router.With(checkPerm(dataprovider.PermAdminQuotaScans)).Get(quotaScanVFolderPath, getFoldersQuotaScans) 1058 router.With(checkPerm(dataprovider.PermAdminQuotaScans)).Get(quotasBasePath+"/folders/scans", getFoldersQuotaScans) 1059 router.With(checkPerm(dataprovider.PermAdminQuotaScans)).Post(quotaScanVFolderPath, startFolderQuotaScanCompat) 1060 router.With(checkPerm(dataprovider.PermAdminQuotaScans)).Post(quotasBasePath+"/folders/{name}/scan", startFolderQuotaScan) 1061 router.With(checkPerm(dataprovider.PermAdminViewUsers)).Get(userPath, getUsers) 1062 router.With(checkPerm(dataprovider.PermAdminAddUsers)).Post(userPath, addUser) 1063 router.With(checkPerm(dataprovider.PermAdminViewUsers)).Get(userPath+"/{username}", getUserByUsername) 1064 router.With(checkPerm(dataprovider.PermAdminChangeUsers)).Put(userPath+"/{username}", updateUser) 1065 router.With(checkPerm(dataprovider.PermAdminDeleteUsers)).Delete(userPath+"/{username}", deleteUser) 1066 router.With(checkPerm(dataprovider.PermAdminChangeUsers)).Put(userPath+"/{username}/2fa/disable", disableUser2FA) 1067 router.With(checkPerm(dataprovider.PermAdminViewUsers)).Get(folderPath, getFolders) 1068 router.With(checkPerm(dataprovider.PermAdminViewUsers)).Get(folderPath+"/{name}", getFolderByName) 1069 router.With(checkPerm(dataprovider.PermAdminAddUsers)).Post(folderPath, addFolder) 1070 router.With(checkPerm(dataprovider.PermAdminChangeUsers)).Put(folderPath+"/{name}", updateFolder) 1071 router.With(checkPerm(dataprovider.PermAdminDeleteUsers)).Delete(folderPath+"/{name}", deleteFolder) 1072 router.With(checkPerm(dataprovider.PermAdminManageSystem)).Get(dumpDataPath, dumpData) 1073 router.With(checkPerm(dataprovider.PermAdminManageSystem)).Get(loadDataPath, loadData) 1074 router.With(checkPerm(dataprovider.PermAdminManageSystem)).Post(loadDataPath, loadDataFromRequest) 1075 router.With(checkPerm(dataprovider.PermAdminChangeUsers)).Put(updateUsedQuotaPath, updateUserQuotaUsageCompat) 1076 router.With(checkPerm(dataprovider.PermAdminChangeUsers)).Put(quotasBasePath+"/users/{username}/usage", updateUserQuotaUsage) 1077 router.With(checkPerm(dataprovider.PermAdminChangeUsers)).Put(updateFolderUsedQuotaPath, updateFolderQuotaUsageCompat) 1078 router.With(checkPerm(dataprovider.PermAdminChangeUsers)).Put(quotasBasePath+"/folders/{name}/usage", updateFolderQuotaUsage) 1079 router.With(checkPerm(dataprovider.PermAdminViewDefender)).Get(defenderHosts, getDefenderHosts) 1080 router.With(checkPerm(dataprovider.PermAdminViewDefender)).Get(defenderHosts+"/{id}", getDefenderHostByID) 1081 router.With(checkPerm(dataprovider.PermAdminManageDefender)).Delete(defenderHosts+"/{id}", deleteDefenderHostByID) 1082 router.With(checkPerm(dataprovider.PermAdminViewDefender)).Get(defenderBanTime, getBanTime) 1083 router.With(checkPerm(dataprovider.PermAdminViewDefender)).Get(defenderScore, getScore) 1084 router.With(checkPerm(dataprovider.PermAdminManageDefender)).Post(defenderUnban, unban) 1085 router.With(checkPerm(dataprovider.PermAdminManageAdmins)).Get(adminPath, getAdmins) 1086 router.With(checkPerm(dataprovider.PermAdminManageAdmins)).Post(adminPath, addAdmin) 1087 router.With(checkPerm(dataprovider.PermAdminManageAdmins)).Get(adminPath+"/{username}", getAdminByUsername) 1088 router.With(checkPerm(dataprovider.PermAdminManageAdmins)).Put(adminPath+"/{username}", updateAdmin) 1089 router.With(checkPerm(dataprovider.PermAdminManageAdmins)).Delete(adminPath+"/{username}", deleteAdmin) 1090 router.With(checkPerm(dataprovider.PermAdminManageAdmins)).Put(adminPath+"/{username}/2fa/disable", disableAdmin2FA) 1091 router.With(checkPerm(dataprovider.PermAdminRetentionChecks)).Get(retentionChecksPath, getRetentionChecks) 1092 router.With(checkPerm(dataprovider.PermAdminRetentionChecks)).Post(retentionBasePath+"/{username}/check", 1093 startRetentionCheck) 1094 router.With(checkPerm(dataprovider.PermAdminViewEvents), compressor.Handler). 1095 Get(fsEventsPath, searchFsEvents) 1096 router.With(checkPerm(dataprovider.PermAdminViewEvents), compressor.Handler). 1097 Get(providerEventsPath, searchProviderEvents) 1098 router.With(forbidAPIKeyAuthentication, checkPerm(dataprovider.PermAdminManageAPIKeys)). 1099 Get(apiKeysPath, getAPIKeys) 1100 router.With(forbidAPIKeyAuthentication, checkPerm(dataprovider.PermAdminManageAPIKeys)). 1101 Post(apiKeysPath, addAPIKey) 1102 router.With(forbidAPIKeyAuthentication, checkPerm(dataprovider.PermAdminManageAPIKeys)). 1103 Get(apiKeysPath+"/{id}", getAPIKeyByID) 1104 router.With(forbidAPIKeyAuthentication, checkPerm(dataprovider.PermAdminManageAPIKeys)). 1105 Put(apiKeysPath+"/{id}", updateAPIKey) 1106 router.With(forbidAPIKeyAuthentication, checkPerm(dataprovider.PermAdminManageAPIKeys)). 1107 Delete(apiKeysPath+"/{id}", deleteAPIKey) 1108 }) 1109 1110 s.router.Get(userTokenPath, s.getUserToken) 1111 1112 s.router.Group(func(router chi.Router) { 1113 router.Use(checkAPIKeyAuth(s.tokenAuth, dataprovider.APIKeyScopeUser)) 1114 router.Use(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromHeader)) 1115 router.Use(jwtAuthenticatorAPIUser) 1116 1117 router.With(forbidAPIKeyAuthentication).Get(userLogoutPath, s.logout) 1118 router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientPasswordChangeDisabled)). 1119 Put(userPwdPath, changeUserPassword) 1120 router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)). 1121 Get(userPublicKeysPath, getUserPublicKeys) 1122 router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)). 1123 Put(userPublicKeysPath, setUserPublicKeys) 1124 router.With(forbidAPIKeyAuthentication).Get(userProfilePath, getUserProfile) 1125 router.With(forbidAPIKeyAuthentication).Put(userProfilePath, updateUserProfile) 1126 // user TOTP APIs 1127 router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientMFADisabled)). 1128 Get(userTOTPConfigsPath, getTOTPConfigs) 1129 router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientMFADisabled)). 1130 Post(userTOTPGeneratePath, generateTOTPSecret) 1131 router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientMFADisabled)). 1132 Post(userTOTPValidatePath, validateTOTPPasscode) 1133 router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientMFADisabled)). 1134 Post(userTOTPSavePath, saveTOTPConfig) 1135 router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientMFADisabled)). 1136 Get(user2FARecoveryCodesPath, getRecoveryCodes) 1137 router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientMFADisabled)). 1138 Post(user2FARecoveryCodesPath, generateRecoveryCodes) 1139 1140 // compatibility layer to remove in v2.3 1141 router.With(compressor.Handler).Get(userFolderPath, readUserFolder) 1142 router.Get(userFilePath, getUserFile) 1143 1144 router.With(compressor.Handler).Get(userDirsPath, readUserFolder) 1145 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Post(userDirsPath, createUserDir) 1146 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Patch(userDirsPath, renameUserDir) 1147 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Delete(userDirsPath, deleteUserDir) 1148 router.Get(userFilesPath, getUserFile) 1149 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Post(userFilesPath, uploadUserFiles) 1150 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Patch(userFilesPath, renameUserFile) 1151 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Delete(userFilesPath, deleteUserFile) 1152 router.Post(userStreamZipPath, getUserFilesAsZipStream) 1153 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled)).Get(userSharesPath, getShares) 1154 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled)).Post(userSharesPath, addShare) 1155 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled)).Get(userSharesPath+"/{id}", getShareByID) 1156 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled)).Put(userSharesPath+"/{id}", updateShare) 1157 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled)).Delete(userSharesPath+"/{id}", deleteShare) 1158 }) 1159 1160 if s.renderOpenAPI { 1161 s.router.Group(func(router chi.Router) { 1162 router.Use(compressor.Handler) 1163 fileServer(router, webOpenAPIPath, http.Dir(s.openAPIPath)) 1164 }) 1165 } 1166 1167 if s.enableWebAdmin || s.enableWebClient { 1168 s.router.Group(func(router chi.Router) { 1169 router.Use(compressor.Handler) 1170 fileServer(router, webStaticFilesPath, http.Dir(s.staticFilesPath)) 1171 }) 1172 if s.enableWebClient { 1173 s.router.Get(webRootPath, func(w http.ResponseWriter, r *http.Request) { 1174 r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) 1175 s.redirectToWebPath(w, r, webClientLoginPath) 1176 }) 1177 s.router.Get(webBasePath, func(w http.ResponseWriter, r *http.Request) { 1178 r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) 1179 s.redirectToWebPath(w, r, webClientLoginPath) 1180 }) 1181 } else { 1182 s.router.Get(webRootPath, func(w http.ResponseWriter, r *http.Request) { 1183 r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) 1184 s.redirectToWebPath(w, r, webLoginPath) 1185 }) 1186 s.router.Get(webBasePath, func(w http.ResponseWriter, r *http.Request) { 1187 r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) 1188 s.redirectToWebPath(w, r, webLoginPath) 1189 }) 1190 } 1191 } 1192 1193 if s.enableWebClient { 1194 s.router.Get(webBaseClientPath, func(w http.ResponseWriter, r *http.Request) { 1195 r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) 1196 http.Redirect(w, r, webClientLoginPath, http.StatusMovedPermanently) 1197 }) 1198 s.router.Get(webClientLoginPath, s.handleClientWebLogin) 1199 s.router.Post(webClientLoginPath, s.handleWebClientLoginPost) 1200 s.router.Get(webClientForgotPwdPath, handleWebClientForgotPwd) 1201 s.router.Post(webClientForgotPwdPath, handleWebClientForgotPwdPost) 1202 s.router.Get(webClientResetPwdPath, handleWebClientPasswordReset) 1203 s.router.Post(webClientResetPwdPath, s.handleWebClientPasswordResetPost) 1204 s.router.With(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromCookie), 1205 jwtAuthenticatorPartial(tokenAudienceWebClientPartial)). 1206 Get(webClientTwoFactorPath, handleWebClientTwoFactor) 1207 s.router.With(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromCookie), 1208 jwtAuthenticatorPartial(tokenAudienceWebClientPartial)). 1209 Post(webClientTwoFactorPath, s.handleWebClientTwoFactorPost) 1210 s.router.With(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromCookie), 1211 jwtAuthenticatorPartial(tokenAudienceWebClientPartial)). 1212 Get(webClientTwoFactorRecoveryPath, handleWebClientTwoFactorRecovery) 1213 s.router.With(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromCookie), 1214 jwtAuthenticatorPartial(tokenAudienceWebClientPartial)). 1215 Post(webClientTwoFactorRecoveryPath, s.handleWebClientTwoFactorRecoveryPost) 1216 // share API exposed to external users 1217 s.router.Get(webClientPubSharesPath+"/{id}", downloadFromShare) 1218 s.router.Post(webClientPubSharesPath+"/{id}", uploadToShare) 1219 1220 s.router.Group(func(router chi.Router) { 1221 router.Use(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromCookie)) 1222 router.Use(jwtAuthenticatorWebClient) 1223 1224 router.Get(webClientLogoutPath, handleWebClientLogout) 1225 router.With(s.refreshCookie).Get(webClientFilesPath, handleClientGetFiles) 1226 router.With(s.refreshCookie).Get(webClientViewPDFPath, handleClientViewPDF) 1227 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader). 1228 Post(webClientFilesPath, uploadUserFiles) 1229 router.With(s.refreshCookie).Get(webClientEditFilePath, handleClientEditFile) 1230 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader). 1231 Patch(webClientFilesPath, renameUserFile) 1232 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader). 1233 Delete(webClientFilesPath, deleteUserFile) 1234 router.With(compressor.Handler, s.refreshCookie).Get(webClientDirsPath, handleClientGetDirContents) 1235 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader). 1236 Post(webClientDirsPath, createUserDir) 1237 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader). 1238 Patch(webClientDirsPath, renameUserDir) 1239 router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader). 1240 Delete(webClientDirsPath, deleteUserDir) 1241 router.With(s.refreshCookie).Get(webClientDownloadZipPath, handleWebClientDownloadZip) 1242 router.With(s.refreshCookie).Get(webClientProfilePath, handleClientGetProfile) 1243 router.Post(webClientProfilePath, handleWebClientProfilePost) 1244 router.With(checkHTTPUserPerm(sdk.WebClientPasswordChangeDisabled)). 1245 Get(webChangeClientPwdPath, handleWebClientChangePwd) 1246 router.With(checkHTTPUserPerm(sdk.WebClientPasswordChangeDisabled)). 1247 Post(webChangeClientPwdPath, handleWebClientChangePwdPost) 1248 router.With(checkHTTPUserPerm(sdk.WebClientMFADisabled), s.refreshCookie). 1249 Get(webClientMFAPath, handleWebClientMFA) 1250 router.With(checkHTTPUserPerm(sdk.WebClientMFADisabled), verifyCSRFHeader). 1251 Post(webClientTOTPGeneratePath, generateTOTPSecret) 1252 router.With(checkHTTPUserPerm(sdk.WebClientMFADisabled), verifyCSRFHeader). 1253 Post(webClientTOTPValidatePath, validateTOTPPasscode) 1254 router.With(checkHTTPUserPerm(sdk.WebClientMFADisabled), verifyCSRFHeader). 1255 Post(webClientTOTPSavePath, saveTOTPConfig) 1256 router.With(checkHTTPUserPerm(sdk.WebClientMFADisabled), verifyCSRFHeader, s.refreshCookie). 1257 Get(webClientRecoveryCodesPath, getRecoveryCodes) 1258 router.With(checkHTTPUserPerm(sdk.WebClientMFADisabled), verifyCSRFHeader). 1259 Post(webClientRecoveryCodesPath, generateRecoveryCodes) 1260 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled), s.refreshCookie). 1261 Get(webClientSharesPath, handleClientGetShares) 1262 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled), s.refreshCookie). 1263 Get(webClientSharePath, handleClientAddShareGet) 1264 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled)).Post(webClientSharePath, 1265 handleClientAddSharePost) 1266 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled), s.refreshCookie). 1267 Get(webClientSharePath+"/{id}", handleClientUpdateShareGet) 1268 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled)). 1269 Post(webClientSharePath+"/{id}", handleClientUpdateSharePost) 1270 router.With(checkHTTPUserPerm(sdk.WebClientSharesDisabled), verifyCSRFHeader). 1271 Delete(webClientSharePath+"/{id}", deleteShare) 1272 }) 1273 } 1274 1275 if s.enableWebAdmin { 1276 s.router.Get(webBaseAdminPath, func(w http.ResponseWriter, r *http.Request) { 1277 r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize) 1278 s.redirectToWebPath(w, r, webLoginPath) 1279 }) 1280 s.router.Get(webLoginPath, s.handleWebAdminLogin) 1281 s.router.Post(webLoginPath, s.handleWebAdminLoginPost) 1282 s.router.Get(webAdminSetupPath, handleWebAdminSetupGet) 1283 s.router.Post(webAdminSetupPath, s.handleWebAdminSetupPost) 1284 s.router.Get(webAdminForgotPwdPath, handleWebAdminForgotPwd) 1285 s.router.Post(webAdminForgotPwdPath, handleWebAdminForgotPwdPost) 1286 s.router.Get(webAdminResetPwdPath, handleWebAdminPasswordReset) 1287 s.router.Post(webAdminResetPwdPath, s.handleWebAdminPasswordResetPost) 1288 s.router.With(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromCookie), 1289 jwtAuthenticatorPartial(tokenAudienceWebAdminPartial)). 1290 Get(webAdminTwoFactorPath, handleWebAdminTwoFactor) 1291 s.router.With(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromCookie), 1292 jwtAuthenticatorPartial(tokenAudienceWebAdminPartial)). 1293 Post(webAdminTwoFactorPath, s.handleWebAdminTwoFactorPost) 1294 s.router.With(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromCookie), 1295 jwtAuthenticatorPartial(tokenAudienceWebAdminPartial)). 1296 Get(webAdminTwoFactorRecoveryPath, handleWebAdminTwoFactorRecovery) 1297 s.router.With(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromCookie), 1298 jwtAuthenticatorPartial(tokenAudienceWebAdminPartial)). 1299 Post(webAdminTwoFactorRecoveryPath, s.handleWebAdminTwoFactorRecoveryPost) 1300 1301 s.router.Group(func(router chi.Router) { 1302 router.Use(jwtauth.Verify(s.tokenAuth, jwtauth.TokenFromCookie)) 1303 router.Use(jwtAuthenticatorWebAdmin) 1304 1305 router.Get(webLogoutPath, handleWebLogout) 1306 router.With(s.refreshCookie).Get(webAdminProfilePath, handleWebAdminProfile) 1307 router.Post(webAdminProfilePath, handleWebAdminProfilePost) 1308 router.With(s.refreshCookie).Get(webChangeAdminPwdPath, handleWebAdminChangePwd) 1309 router.Post(webChangeAdminPwdPath, handleWebAdminChangePwdPost) 1310 1311 router.With(s.refreshCookie).Get(webAdminMFAPath, handleWebAdminMFA) 1312 router.With(verifyCSRFHeader).Post(webAdminTOTPGeneratePath, generateTOTPSecret) 1313 router.With(verifyCSRFHeader).Post(webAdminTOTPValidatePath, validateTOTPPasscode) 1314 router.With(verifyCSRFHeader).Post(webAdminTOTPSavePath, saveTOTPConfig) 1315 router.With(verifyCSRFHeader, s.refreshCookie).Get(webAdminRecoveryCodesPath, getRecoveryCodes) 1316 router.With(verifyCSRFHeader).Post(webAdminRecoveryCodesPath, generateRecoveryCodes) 1317 1318 router.With(checkPerm(dataprovider.PermAdminViewUsers), s.refreshCookie). 1319 Get(webUsersPath, handleGetWebUsers) 1320 router.With(checkPerm(dataprovider.PermAdminAddUsers), s.refreshCookie). 1321 Get(webUserPath, handleWebAddUserGet) 1322 router.With(checkPerm(dataprovider.PermAdminChangeUsers), s.refreshCookie). 1323 Get(webUserPath+"/{username}", handleWebUpdateUserGet) 1324 router.With(checkPerm(dataprovider.PermAdminAddUsers)).Post(webUserPath, handleWebAddUserPost) 1325 router.With(checkPerm(dataprovider.PermAdminChangeUsers)).Post(webUserPath+"/{username}", handleWebUpdateUserPost) 1326 router.With(checkPerm(dataprovider.PermAdminViewConnections), s.refreshCookie). 1327 Get(webConnectionsPath, handleWebGetConnections) 1328 router.With(checkPerm(dataprovider.PermAdminViewUsers), s.refreshCookie). 1329 Get(webFoldersPath, handleWebGetFolders) 1330 router.With(checkPerm(dataprovider.PermAdminAddUsers), s.refreshCookie). 1331 Get(webFolderPath, handleWebAddFolderGet) 1332 router.With(checkPerm(dataprovider.PermAdminAddUsers)).Post(webFolderPath, handleWebAddFolderPost) 1333 router.With(checkPerm(dataprovider.PermAdminViewServerStatus), s.refreshCookie). 1334 Get(webStatusPath, handleWebGetStatus) 1335 router.With(checkPerm(dataprovider.PermAdminManageAdmins), s.refreshCookie). 1336 Get(webAdminsPath, handleGetWebAdmins) 1337 router.With(checkPerm(dataprovider.PermAdminManageAdmins), s.refreshCookie). 1338 Get(webAdminPath, handleWebAddAdminGet) 1339 router.With(checkPerm(dataprovider.PermAdminManageAdmins), s.refreshCookie). 1340 Get(webAdminPath+"/{username}", handleWebUpdateAdminGet) 1341 router.With(checkPerm(dataprovider.PermAdminManageAdmins)).Post(webAdminPath, handleWebAddAdminPost) 1342 router.With(checkPerm(dataprovider.PermAdminManageAdmins)).Post(webAdminPath+"/{username}", 1343 handleWebUpdateAdminPost) 1344 router.With(checkPerm(dataprovider.PermAdminManageAdmins), verifyCSRFHeader). 1345 Delete(webAdminPath+"/{username}", deleteAdmin) 1346 router.With(checkPerm(dataprovider.PermAdminCloseConnections), verifyCSRFHeader). 1347 Delete(webConnectionsPath+"/{connectionID}", handleCloseConnection) 1348 router.With(checkPerm(dataprovider.PermAdminChangeUsers), s.refreshCookie). 1349 Get(webFolderPath+"/{name}", handleWebUpdateFolderGet) 1350 router.With(checkPerm(dataprovider.PermAdminChangeUsers)).Post(webFolderPath+"/{name}", 1351 handleWebUpdateFolderPost) 1352 router.With(checkPerm(dataprovider.PermAdminDeleteUsers), verifyCSRFHeader). 1353 Delete(webFolderPath+"/{name}", deleteFolder) 1354 router.With(checkPerm(dataprovider.PermAdminQuotaScans), verifyCSRFHeader). 1355 Post(webScanVFolderPath+"/{name}", startFolderQuotaScan) 1356 router.With(checkPerm(dataprovider.PermAdminDeleteUsers), verifyCSRFHeader). 1357 Delete(webUserPath+"/{username}", deleteUser) 1358 router.With(checkPerm(dataprovider.PermAdminQuotaScans), verifyCSRFHeader). 1359 Post(webQuotaScanPath+"/{username}", startUserQuotaScan) 1360 router.With(checkPerm(dataprovider.PermAdminManageSystem)).Get(webMaintenancePath, handleWebMaintenance) 1361 router.With(checkPerm(dataprovider.PermAdminManageSystem)).Get(webBackupPath, dumpData) 1362 router.With(checkPerm(dataprovider.PermAdminManageSystem)).Post(webRestorePath, handleWebRestore) 1363 router.With(checkPerm(dataprovider.PermAdminManageSystem), s.refreshCookie). 1364 Get(webTemplateUser, handleWebTemplateUserGet) 1365 router.With(checkPerm(dataprovider.PermAdminManageSystem)).Post(webTemplateUser, handleWebTemplateUserPost) 1366 router.With(checkPerm(dataprovider.PermAdminManageSystem), s.refreshCookie). 1367 Get(webTemplateFolder, handleWebTemplateFolderGet) 1368 router.With(checkPerm(dataprovider.PermAdminManageSystem)).Post(webTemplateFolder, handleWebTemplateFolderPost) 1369 router.With(checkPerm(dataprovider.PermAdminViewDefender)).Get(webDefenderPath, handleWebDefenderPage) 1370 router.With(checkPerm(dataprovider.PermAdminViewDefender)).Get(webDefenderHostsPath, getDefenderHosts) 1371 router.With(checkPerm(dataprovider.PermAdminManageDefender)).Delete(webDefenderHostsPath+"/{id}", 1372 deleteDefenderHostByID) 1373 }) 1374 } 1375} 1376