package captiveportal import ( "net/http" "strings" "github.com/pkg/errors" ) type OS int const ( OSUnknown OS = iota OSAndroid OSApple OSWindows OSLinux ) type Matcher interface { Match(r *http.Request) (bool, OS, error) } type MatchFunc func(r *http.Request) (bool, OS, error) func (f MatchFunc) Match(r *http.Request) (bool, OS, error) { return f(r) } func MatchAndroid(r *http.Request) (bool, error) { // Samples // // https://www.google.com/generate_204 // http://connectivitycheck.gstatic.com/generate_204 // http://www.google.com/gen_204 // http://play.googleapis.com/generate_204 // http://connectivitycheck.gstatic.com/generate_204 // http://clients3.google.com/generate_204 // http://g.cn matches := strings.Contains(r.URL.Path, "generate_204") || strings.Contains(r.URL.Path, "gen_204") || strings.Contains(r.Host, "g.cn") return matches, nil } func MatchApple(r *http.Request) (bool, error) { // Samples // // http://www.apple.com/library/test/success.html // http://captive.apple.com/hotspot-detect.html matches := strings.Contains(r.Host, "www.apple.com") || strings.Contains(r.Host, "captive.apple.com") return matches, nil } func MatchLinux(r *http.Request) (bool, error) { // Samples // // http://start.ubuntu.com/connectivity-check.html // http://nmcheck.gnome.org/check_network_status.txt matches := strings.Contains(r.Host, "start.ubuntu.com") || strings.Contains(r.Host, "nmcheck.gnome.org") return matches, nil } func MatchWindows(r *http.Request) (bool, error) { // Samples // // http://www.msftncsi.com // http://www.msftncsi.com/ncsi.txt matches := strings.Contains(r.Host, "www.msftncsi.com") return matches, nil } // nolint: gochecknoglobals var defaultMatchers = map[OS]func(r *http.Request) (bool, error){ OSAndroid: MatchAndroid, OSApple: MatchApple, OSWindows: MatchWindows, OSLinux: MatchLinux, } func DefaultMatch(r *http.Request) (bool, OS, error) { for os, match := range defaultMatchers { matches, err := match(r) if err != nil { return false, OSUnknown, errors.WithStack(err) } if matches { return matches, os, nil } } return false, OSUnknown, nil }