diff --git a/src/mod/acme/autorenew.go b/src/mod/acme/autorenew.go index 73637cd..02de955 100644 --- a/src/mod/acme/autorenew.go +++ b/src/mod/acme/autorenew.go @@ -248,15 +248,19 @@ func (a *AutoRenewer) HandleAutoRenewEnable(w http.ResponseWriter, r *http.Reque } func (a *AutoRenewer) HandleACMEEmail(w http.ResponseWriter, r *http.Request) { - - email, err := utils.PostPara(r, "set") - if err != nil { + if r.Method == http.MethodGet { //Return the current email to user js, _ := json.Marshal(a.RenewerConfig.Email) utils.SendJSONResponse(w, string(js)) - } else { + } else if r.Method == http.MethodPost { + email, err := utils.PostPara(r, "set") + if err != nil { + utils.SendErrorResponse(w, "invalid or empty email given") + return + } + //Check if the email is valid - _, err := mail.ParseAddress(email) + _, err = mail.ParseAddress(email) if err != nil { utils.SendErrorResponse(w, err.Error()) return @@ -265,8 +269,11 @@ func (a *AutoRenewer) HandleACMEEmail(w http.ResponseWriter, r *http.Request) { //Set the new config a.RenewerConfig.Email = email a.saveRenewConfigToFile() - } + utils.SendOK(w) + } else { + http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed) + } } // Check and renew certificates. This check all the certificates in the diff --git a/src/mod/dynamicproxy/proxyRequestHandler.go b/src/mod/dynamicproxy/proxyRequestHandler.go index 2cba30b..d2e05ea 100644 --- a/src/mod/dynamicproxy/proxyRequestHandler.go +++ b/src/mod/dynamicproxy/proxyRequestHandler.go @@ -123,32 +123,30 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe } /* WebSocket automatic proxy */ - if !target.DisableAutoWebSockeyProxy { - requestURL := r.URL.String() - if r.Header["Upgrade"] != nil && strings.ToLower(r.Header["Upgrade"][0]) == "websocket" { - //Handle WebSocket request. Forward the custom Upgrade header and rewrite origin - r.Header.Set("Zr-Origin-Upgrade", "websocket") - wsRedirectionEndpoint := selectedUpstream.OriginIpOrDomain - if wsRedirectionEndpoint[len(wsRedirectionEndpoint)-1:] != "/" { - //Append / to the end of the redirection endpoint if not exists - wsRedirectionEndpoint = wsRedirectionEndpoint + "/" - } - if len(requestURL) > 0 && requestURL[:1] == "/" { - //Remove starting / from request URL if exists - requestURL = requestURL[1:] - } - u, _ := url.Parse("ws://" + wsRedirectionEndpoint + requestURL) - if selectedUpstream.RequireTLS { - u, _ = url.Parse("wss://" + wsRedirectionEndpoint + requestURL) - } - h.Parent.logRequest(r, true, 101, "host-websocket", selectedUpstream.OriginIpOrDomain) - wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{ - SkipTLSValidation: selectedUpstream.SkipCertValidations, - SkipOriginCheck: selectedUpstream.SkipWebSocketOriginCheck, - }) - wspHandler.ServeHTTP(w, r) - return + requestURL := r.URL.String() + if r.Header["Upgrade"] != nil && strings.ToLower(r.Header["Upgrade"][0]) == "websocket" { + //Handle WebSocket request. Forward the custom Upgrade header and rewrite origin + r.Header.Set("Zr-Origin-Upgrade", "websocket") + wsRedirectionEndpoint := selectedUpstream.OriginIpOrDomain + if wsRedirectionEndpoint[len(wsRedirectionEndpoint)-1:] != "/" { + //Append / to the end of the redirection endpoint if not exists + wsRedirectionEndpoint = wsRedirectionEndpoint + "/" } + if len(requestURL) > 0 && requestURL[:1] == "/" { + //Remove starting / from request URL if exists + requestURL = requestURL[1:] + } + u, _ := url.Parse("ws://" + wsRedirectionEndpoint + requestURL) + if selectedUpstream.RequireTLS { + u, _ = url.Parse("wss://" + wsRedirectionEndpoint + requestURL) + } + h.Parent.logRequest(r, true, 101, "host-websocket", selectedUpstream.OriginIpOrDomain) + wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{ + SkipTLSValidation: selectedUpstream.SkipCertValidations, + SkipOriginCheck: selectedUpstream.SkipWebSocketOriginCheck, + }) + wspHandler.ServeHTTP(w, r) + return } originalHostHeader := r.Host diff --git a/src/mod/dynamicproxy/typedef.go b/src/mod/dynamicproxy/typedef.go index a1ceddb..cd4d6bc 100644 --- a/src/mod/dynamicproxy/typedef.go +++ b/src/mod/dynamicproxy/typedef.go @@ -137,7 +137,6 @@ type ProxyEndpoint struct { EnablePermissionPolicyHeader bool //Enable injection of permission policy header PermissionPolicy *permissionpolicy.PermissionsPolicy //Permission policy header DisableHopByHopHeaderRemoval bool //Do not remove hop-by-hop headers - DisableAutoWebSockeyProxy bool //Disable auto sniffing logic for websocket upgrade //Authentication RequireBasicAuth bool //Set to true to request basic auth before proxy diff --git a/src/mod/tlscert/tlscert.go b/src/mod/tlscert/tlscert.go index fbd0a13..ba6443d 100644 --- a/src/mod/tlscert/tlscert.go +++ b/src/mod/tlscert/tlscert.go @@ -11,6 +11,7 @@ import ( "path/filepath" "strings" + "imuslab.com/zoraxy/mod/info/logger" "imuslab.com/zoraxy/mod/utils" ) @@ -21,15 +22,16 @@ type CertCache struct { } type Manager struct { - CertStore string //Path where all the certs are stored - LoadedCerts []*CertCache //A list of loaded certs + CertStore string //Path where all the certs are stored + LoadedCerts []*CertCache //A list of loaded certs + Logger *logger.Logger //System wide logger for debug mesage verbal bool } //go:embed localhost.pem localhost.key var buildinCertStore embed.FS -func NewManager(certStore string, verbal bool) (*Manager, error) { +func NewManager(certStore string, verbal bool, logger *logger.Logger) (*Manager, error) { if !utils.FileExists(certStore) { os.MkdirAll(certStore, 0775) } @@ -52,6 +54,7 @@ func NewManager(certStore string, verbal bool) (*Manager, error) { CertStore: certStore, LoadedCerts: []*CertCache{}, verbal: verbal, + Logger: logger, } err := thisManager.UpdateLoadedCertList() @@ -78,7 +81,7 @@ func (m *Manager) UpdateLoadedCertList() error { priKey := filepath.Join(m.CertStore, certname+".key") certificate, err := tls.LoadX509KeyPair(pubKey, priKey) if err != nil { - log.Println("Certificate loaded failed: " + certname) + m.Logger.PrintAndLog("tls-router", "Certificate load failed: "+certname, err) continue } @@ -86,6 +89,7 @@ func (m *Manager) UpdateLoadedCertList() error { loadedCert, err := x509.ParseCertificate(thisCert) if err != nil { //Error pasring cert, skip this byte segment + m.Logger.PrintAndLog("tls-router", "Certificate parse failed: "+certname, err) continue } @@ -171,37 +175,10 @@ func (m *Manager) GetCert(helloInfo *tls.ClientHelloInfo) (*tls.Certificate, err pubKey, priKey = m.GetCertByX509CNHostname(helloInfo.ServerName) } else { //Fallback to legacy method of matching certificates - /* - domainCerts, _ := m.ListCertDomains() - cloestDomainCert := matchClosestDomainCertificate(helloInfo.ServerName, domainCerts) - if cloestDomainCert != "" { - //There is a matching parent domain for this subdomain. Use this instead. - pubKey = filepath.Join(m.CertStore, cloestDomainCert+".pem") - priKey = filepath.Join(m.CertStore, cloestDomainCert+".key") - } else if m.DefaultCertExists() { - //Use default.pem and default.key - pubKey = filepath.Join(m.CertStore, "default.pem") - priKey = filepath.Join(m.CertStore, "default.key") - if m.verbal { - log.Println("No matching certificate found. Serving with default") - } - } else { - if m.verbal { - log.Println("Matching certificate not found. Serving with build-in certificate. Requesting server name: ", helloInfo.ServerName) - } - }*/ - if m.DefaultCertExists() { //Use default.pem and default.key pubKey = filepath.Join(m.CertStore, "default.pem") priKey = filepath.Join(m.CertStore, "default.key") - //if m.verbal { - // log.Println("No matching certificate found. Serving with default") - //} - } else { - //if m.verbal { - // log.Println("Matching certificate not found. Serving with build-in certificate. Requesting server name: ", helloInfo.ServerName) - //} } } diff --git a/src/start.go b/src/start.go index cadac93..43a8597 100644 --- a/src/start.go +++ b/src/start.go @@ -84,7 +84,7 @@ func startupSequence() { }) //Create a TLS certificate manager - tlsCertManager, err = tlscert.NewManager("./conf/certs", development) + tlsCertManager, err = tlscert.NewManager("./conf/certs", development, SystemWideLogger) if err != nil { panic(err) } diff --git a/src/web/components/cert.html b/src/web/components/cert.html index 784203f..a897b8a 100644 --- a/src/web/components/cert.html +++ b/src/web/components/cert.html @@ -423,6 +423,8 @@ } if (uploadPendingPublicKey && uploadPendingPrivateKey && typeof uploadPendingPublicKey === 'object' && typeof uploadPendingPrivateKey === 'object') { const publicKeyForm = new FormData(); + const csrfToken = document.querySelector('meta[name="zoraxy.csrf.Token"]').getAttribute("content"); + publicKeyForm.append('file', uploadPendingPublicKey, 'publicKey'); const privateKeyForm = new FormData(); @@ -430,6 +432,7 @@ const publicKeyRequest = new XMLHttpRequest(); publicKeyRequest.open('POST', '/api/cert/upload?ktype=pub&domain=' + domain); + publicKeyRequest.setRequestHeader('X-CSRF-Token', csrfToken); publicKeyRequest.onreadystatechange = function() { if (publicKeyRequest.readyState === XMLHttpRequest.DONE) { if (publicKeyRequest.status !== 200) { @@ -446,6 +449,7 @@ const privateKeyRequest = new XMLHttpRequest(); privateKeyRequest.open('POST', '/api/cert/upload?ktype=pri&domain=' + domain); + privateKeyRequest.setRequestHeader('X-CSRF-Token', csrfToken); privateKeyRequest.onreadystatechange = function() { if (privateKeyRequest.readyState === XMLHttpRequest.DONE) { if (privateKeyRequest.status !== 200) { @@ -466,15 +470,11 @@ //ktype = {"pub" / "pri"} function handleFileSelect(event, ktype="pub") { const file = event.target.files[0]; - //const fileNameInput = document.getElementById('selected-file-name'); if (ktype == "pub"){ uploadPendingPublicKey = file; }else if (ktype == "pri"){ uploadPendingPrivateKey = file; } - - - //fileNameInput.value = file.name; } //Check if the default keypairs exists @@ -497,14 +497,18 @@ input.addEventListener('change', () => { // create form data object const formData = new FormData(); - + const csrfToken = document.querySelector('meta[name="zoraxy.csrf.Token"]').getAttribute("content"); + // add selected file to form data formData.append('file', input.files[0]); // send form data to server fetch('/api/cert/upload?ktype=pri', { method: 'POST', - body: formData + body: formData, + headers: { + 'X-CSRF-Token': csrfToken + } }) .then(response => { initDefaultKeypairCheck(); @@ -531,6 +535,7 @@ function uploadPublicKey() { // create file input element const input = document.createElement('input'); + const csrfToken = document.querySelector('meta[name="zoraxy.csrf.Token"]').getAttribute("content"); input.type = 'file'; // add change listener to file input @@ -544,7 +549,10 @@ // send form data to server fetch('/api/cert/upload?ktype=pub', { method: 'POST', - body: formData + body: formData, + headers: { + 'X-CSRF-Token': csrfToken + } }) .then(response => { if (response.ok) {