Pull request: home: don't allow all origins
Merge in DNS/adguard-home from 2484-access-control to master Updates #2484. Squashed commit of the following: commit 4f0c6ddae35b55a9251f4d5e14c4d92fd2107443 Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Fri Feb 5 12:42:22 2021 +0300 home: don't allow all origins
This commit is contained in:
parent
c9d2436d77
commit
bc01f4f8bc
|
@ -43,6 +43,8 @@ and this project adheres to
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- `Access-Control-Allow-Origin` is now only set to the same origin as the
|
||||||
|
domain, but with an HTTP scheme as opposed to `*` ([#2484]).
|
||||||
- `workDir` now supports symlinks.
|
- `workDir` now supports symlinks.
|
||||||
- Stopped mounting together the directories `/opt/adguardhome/conf` and
|
- Stopped mounting together the directories `/opt/adguardhome/conf` and
|
||||||
`/opt/adguardhome/work` in our Docker images ([#2589]).
|
`/opt/adguardhome/work` in our Docker images ([#2589]).
|
||||||
|
@ -67,6 +69,7 @@ and this project adheres to
|
||||||
[#2358]: https://github.com/AdguardTeam/AdGuardHome/issues/2358
|
[#2358]: https://github.com/AdguardTeam/AdGuardHome/issues/2358
|
||||||
[#2391]: https://github.com/AdguardTeam/AdGuardHome/issues/2391
|
[#2391]: https://github.com/AdguardTeam/AdGuardHome/issues/2391
|
||||||
[#2394]: https://github.com/AdguardTeam/AdGuardHome/issues/2394
|
[#2394]: https://github.com/AdguardTeam/AdGuardHome/issues/2394
|
||||||
|
[#2484]: https://github.com/AdguardTeam/AdGuardHome/issues/2484
|
||||||
[#2509]: https://github.com/AdguardTeam/AdGuardHome/issues/2509
|
[#2509]: https://github.com/AdguardTeam/AdGuardHome/issues/2509
|
||||||
[#2552]: https://github.com/AdguardTeam/AdGuardHome/issues/2552
|
[#2552]: https://github.com/AdguardTeam/AdGuardHome/issues/2552
|
||||||
[#2589]: https://github.com/AdguardTeam/AdGuardHome/issues/2589
|
[#2589]: https://github.com/AdguardTeam/AdGuardHome/issues/2589
|
||||||
|
|
|
@ -2,6 +2,7 @@ package home
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -202,37 +203,81 @@ func preInstallHandler(handler http.Handler) http.Handler {
|
||||||
return &preInstallHandlerStruct{handler}
|
return &preInstallHandlerStruct{handler}
|
||||||
}
|
}
|
||||||
|
|
||||||
// postInstall lets the handler run only if firstRun is false, and redirects to /install.html otherwise
|
const defaultHTTPSPort = 443
|
||||||
// it also enforces HTTPS if it is enabled and configured
|
|
||||||
|
// handleHTTPSRedirect redirects the request to HTTPS, if needed. If ok is
|
||||||
|
// true, the middleware must continue handling the request.
|
||||||
|
func handleHTTPSRedirect(w http.ResponseWriter, r *http.Request) (ok bool) {
|
||||||
|
web := Context.web
|
||||||
|
if web.httpsServer.server == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
host, _, err := net.SplitHostPort(r.Host)
|
||||||
|
if err != nil {
|
||||||
|
// Check for the missing port error. If it is that error, just
|
||||||
|
// use the host as is.
|
||||||
|
//
|
||||||
|
// See the source code for net.SplitHostPort.
|
||||||
|
const missingPort = "missing port in address"
|
||||||
|
|
||||||
|
addrErr := &net.AddrError{}
|
||||||
|
if !errors.As(err, &addrErr) || addrErr.Err != missingPort {
|
||||||
|
httpError(w, http.StatusBadRequest, "bad host: %s", err)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
host = r.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.TLS == nil && web.forceHTTPS {
|
||||||
|
hostPort := host
|
||||||
|
if port := web.conf.PortHTTPS; port != defaultHTTPSPort {
|
||||||
|
portStr := strconv.Itoa(port)
|
||||||
|
hostPort = net.JoinHostPort(host, portStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
httpsURL := &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: hostPort,
|
||||||
|
Path: r.URL.Path,
|
||||||
|
RawQuery: r.URL.RawQuery,
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, httpsURL.String(), http.StatusTemporaryRedirect)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the frontend from the HTTP origin to send requests to the HTTPS
|
||||||
|
// server. This can happen when the user has just set up HTTPS with
|
||||||
|
// redirects.
|
||||||
|
originURL := &url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: r.Host,
|
||||||
|
}
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", originURL.String())
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// postInstall lets the handler to run only if firstRun is false. Otherwise, it
|
||||||
|
// redirects to /install.html. It also enforces HTTPS if it is enabled and
|
||||||
|
// configured and sets appropriate access control headers.
|
||||||
func postInstall(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
|
func postInstall(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
if Context.firstRun &&
|
path := r.URL.Path
|
||||||
!strings.HasPrefix(r.URL.Path, "/install.") &&
|
if Context.firstRun && !strings.HasPrefix(path, "/install.") &&
|
||||||
!strings.HasPrefix(r.URL.Path, "/assets/") {
|
!strings.HasPrefix(path, "/assets/") {
|
||||||
http.Redirect(w, r, "/install.html", http.StatusFound)
|
http.Redirect(w, r, "/install.html", http.StatusFound)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// enforce https?
|
if !handleHTTPSRedirect(w, r) {
|
||||||
if r.TLS == nil && Context.web.forceHTTPS && Context.web.httpsServer.server != nil {
|
|
||||||
// yes, and we want host from host:port
|
|
||||||
host, _, err := net.SplitHostPort(r.Host)
|
|
||||||
if err != nil {
|
|
||||||
// no port in host
|
|
||||||
host = r.Host
|
|
||||||
}
|
|
||||||
// construct new URL to redirect to
|
|
||||||
newURL := url.URL{
|
|
||||||
Scheme: "https",
|
|
||||||
Host: net.JoinHostPort(host, strconv.Itoa(Context.web.conf.PortHTTPS)),
|
|
||||||
Path: r.URL.Path,
|
|
||||||
RawQuery: r.URL.RawQuery,
|
|
||||||
}
|
|
||||||
http.Redirect(w, r, newURL.String(), http.StatusTemporaryRedirect)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
||||||
handler(w, r)
|
handler(w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ func TestHome(t *testing.T) {
|
||||||
h := http.Client{}
|
h := http.Client{}
|
||||||
for i := 0; i != 50; i++ {
|
for i := 0; i != 50; i++ {
|
||||||
resp, err = h.Get("http://127.0.0.1:3000/")
|
resp, err = h.Get("http://127.0.0.1:3000/")
|
||||||
if err == nil && resp.StatusCode != 404 {
|
if err == nil && resp.StatusCode != http.StatusNotFound {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
Loading…
Reference in New Issue