101 lines
2.1 KiB
Go
101 lines
2.1 KiB
Go
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
|
|
}
|