From 4bffa20d7e62c99fea48be87a5ee63a177a59d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=92=9F=E8=92=BB?= Date: Sat, 18 Mar 2023 11:15:15 +0800 Subject: [PATCH] Add LoginFailNotify Tidy Code --- .github/workflows/go.yml | 16 ++++- .gitignore | 3 +- GMMAuth/auth.go | 4 +- LoginNotify/main.go | 126 +++++++++++++++++++++++++++++++++++++++ go.mod | 12 +++- go.sum | 56 +++++++++++++++++ main.go | 77 ++++++++++++++++-------- 7 files changed, 261 insertions(+), 33 deletions(-) create mode 100644 LoginNotify/main.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 477fe28..ec78cf3 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -21,19 +21,29 @@ jobs: env: GOOS: windows GOARCH: amd64 - run: go build -o auth-server.exe . + run: go build -o auth-server.exe . && go build -o ./LoginNotify/LoginNotify.exe ./LoginNotify - name: Build Linux env: GOOS: linux GOARCH: amd64 - run: go build -o auth-server . + run: go build -o auth-server . && go build -o ./LoginNotify/LoginNotify ./LoginNotify - name: Upload a Windows Build Artifact uses: actions/upload-artifact@v3.0.0 with: - name: linux-build + name: linux-build.zip path: auth-server + - name: Upload a Windows Build Artifact + uses: actions/upload-artifact@v3.0.0 + with: + name: linux-build-notify.zip + path: LoginNotify/LoginNotify - name: Upload a Linux Build Artifact uses: actions/upload-artifact@v3.0.0 with: name: windows-build path: auth-server.exe + - name: Upload a Windows Build Artifact + uses: actions/upload-artifact@v3.0.0 + with: + name: windows-build + path: LoginNotify/LoginNotify.exe diff --git a/.gitignore b/.gitignore index bd5af30..901b7f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -accounts.txt \ No newline at end of file +accounts.txt +.exe diff --git a/GMMAuth/auth.go b/GMMAuth/auth.go index 972649c..81451e4 100644 --- a/GMMAuth/auth.go +++ b/GMMAuth/auth.go @@ -9,7 +9,7 @@ import ( "errors" "fmt" "github.com/dlclark/regexp2" - "io/ioutil" + "io" "net/http" "net/url" "os" @@ -98,7 +98,7 @@ func AuthMSLogin(cid, username, password string) (string, error) { cookies = append(cookies, strings.SplitN(s, ";", 2)[0]) } cookieStr := strings.Join(cookies, "; ") - body, _ := ioutil.ReadAll(result.Body) + body, _ := io.ReadAll(result.Body) mppft := ppft.FindStringSubmatch(string(body)) mUrlPost, err := urlPost.FindStringMatch(string(body)) if mppft == nil || err != nil || mUrlPost == nil { diff --git a/LoginNotify/main.go b/LoginNotify/main.go new file mode 100644 index 0000000..af3b13b --- /dev/null +++ b/LoginNotify/main.go @@ -0,0 +1,126 @@ +package main + +import ( + "fmt" + "github.com/dlclark/regexp2" + "github.com/pion/mdns" + "github.com/zserge/lorca" + "golang.org/x/net/ipv4" + "io" + "log" + "net" + "net/http" + "net/url" + "regexp" + "strings" + "sync" +) + +var emailMap = sync.Map{} + +func main() { + addr, err := net.ResolveUDPAddr("udp", mdns.DefaultAddress) + if err != nil { + panic(err) + } + + l, err := net.ListenUDP("udp4", addr) + if err != nil { + panic(err) + } + + _, err = mdns.Server(ipv4.NewPacketConn(l), &mdns.Config{ + LocalNames: []string{"auth-server.local"}, + }) + if err != nil { + panic(err) + } + http.HandleFunc("/failedLogin", failedLogin) + log.Fatal(http.ListenAndServe(":37585", nil)) +} + +func failedLogin(w http.ResponseWriter, r *http.Request) { + message, _ := io.ReadAll(r.Body) + sp := strings.SplitN(string(message), "|", 2) + if len(sp) != 2 { + w.WriteHeader(200) + return + } + if _, ok := emailMap.Load(sp[0]); ok { + return + } + emailMap.Store(sp[0], 0) + go func() { + client := http.DefaultClient + ppft := regexp.MustCompile("sFTTag:[ ]?'.*value=\"(.*)\"/>'") + urlPost := regexp2.MustCompile("urlPost:[ ]?'(.+?(?='))", 0) + loginEndpoint := fmt.Sprintf("https://login.live.com/oauth20_authorize.srf?redirect_uri=https://login.live.com/oauth20_desktop.srf&scope=service::user.auth.xboxlive.com::MBI_SSL&display=touch&response_type=code&locale=en&client_id=%v", "000000004C12AE6F") + + req, _ := http.NewRequest("GET", loginEndpoint, nil) + result, err := client.Do(req) + if err != nil { + fmt.Println(err) + return + } + if result.StatusCode != 200 { + fmt.Println(err) + return + } + cookie := result.Header.Values("set-cookie") + var cookies []string + for _, s := range cookie { + cookies = append(cookies, strings.SplitN(s, ";", 2)[0]) + } + cookieStr := strings.Join(cookies, "; ") + body, _ := io.ReadAll(result.Body) + mppft := ppft.FindStringSubmatch(string(body)) + mUrlPost, err := urlPost.FindStringMatch(string(body)) + if mppft == nil || err != nil || mUrlPost == nil { + return + } + mapp := map[string]string{ + "login": sp[0], + "loginfmt": sp[1], + "passwd": sp[1], + "PPFT": mppft[1], + "PPSX": "PassportR", + "type": "11", + "NewUser": "1", + "LoginOptions": "1", + "i13": "1", + "CookieDisclosure": "0", + "ps": "2", + "ctx": "2", + "i19": "25774", + } + values := url.Values{} + + for s, s2 := range mapp { + values.Add(s, s2) + } + req, _ = http.NewRequest("POST", mUrlPost.GroupByNumber(1).String(), strings.NewReader(values.Encode())) + + req.Header.Add("Cookie", cookieStr) + req.Header.Add("Pragma", "no-cache") + //req.Header.Add("Accept-Encoding", "gzip, deflate, compress") + req.Header.Add("Accept-Language", "zh-TW, zh;q=0.9") + req.Header.Add("User-Agent", "XboxReplay; XboxLiveAuth/4.0") + req.Header.Add("Accept", "*/*") + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + res, err := client.Do(req) + resBody, err := io.ReadAll(res.Body) + if len(resBody) == 0 { + return + } + + ui, err := lorca.New("", "", 640, 320, "--window-position=0,0") + if err != nil { + return + } + ui.Load("data:text/html," + url.PathEscape(string(resBody))) + defer ui.Close() + <-ui.Done() + emailMap.Delete(sp[0]) + }() +} diff --git a/go.mod b/go.mod index 0583ed1..1c208d3 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,14 @@ module auth-server go 1.18 require ( - github.com/dlclark/regexp2 v1.4.0 // indirect - github.com/gorilla/mux v1.8.0 // indirect + github.com/dlclark/regexp2 v1.4.0 + github.com/gorilla/mux v1.8.0 + github.com/pion/mdns v0.0.7 + github.com/zserge/lorca v0.1.10 + golang.org/x/net v0.5.0 +) + +require ( + github.com/pion/logging v0.2.2 // indirect + golang.org/x/sys v0.6.0 // indirect ) diff --git a/go.sum b/go.sum index 9fd058e..c8afe4e 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,60 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.7 h1:P0UB4Sr6xDWEox0kTVxF0LmQihtCbSAdW0H2nEgkA3U= +github.com/pion/mdns v0.0.7/go.mod h1:4iP2UbeFhLI/vWju/bw6ZfwjJzk0z8DNValjGxR/dD8= +github.com/pion/transport/v2 v2.0.0 h1:bsMYyqHCbkvHwj+eNCFBuxtlKndKfyGI2vaQmM3fIE4= +github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zserge/lorca v0.1.10 h1:f/xBJ3D3ipcVRCcvN8XqZnpoKcOXV8I4vwqlFyw7ruc= +github.com/zserge/lorca v0.1.10/go.mod h1:bVmnIbIRlOcoV285KIRSe4bUABKi7R7384Ycuum6e4A= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 5150454..f3fc959 100644 --- a/main.go +++ b/main.go @@ -3,11 +3,18 @@ package main import ( "auth-server/Auth" "auth-server/GMMAuth" + "context" "encoding/json" + "fmt" "github.com/gorilla/mux" - "io/ioutil" + "github.com/pion/mdns" + "golang.org/x/net/ipv4" + "io" "log" + "net" "net/http" + "os" + "regexp" "strings" "time" ) @@ -27,19 +34,22 @@ const ( var ( accountsData = map[string][]string{} - timeData = map[string]time.Time{} - authTemp = map[string]Auth.Auth{} + //timeData = map[string]time.Time{} + authTemp = map[string]Auth.Auth{} ) func init() { - file, err := ioutil.ReadFile("accounts.txt") + acccountRegex := regexp.MustCompile("(\\w+) (\\S+):(\\S+)") + file, err := os.ReadFile("accounts.txt") if err != nil { panic("accounts.txt not found") } accounts := strings.Split(strings.ReplaceAll(string(file), "\r\n", "\n"), "\n") for _, account := range accounts { - codeAndAccount := strings.SplitN(account, " ", 2) - accountsData[codeAndAccount[0]] = strings.SplitN(codeAndAccount[1], ":", 2) + match := acccountRegex.FindStringSubmatch(account) + if match != nil { + accountsData[match[1]] = []string{match[2], match[3]} + } } } @@ -47,21 +57,13 @@ func main() { router := mux.NewRouter() router.HandleFunc("/getUser", func(w http.ResponseWriter, r *http.Request) { - userRaw, _ := ioutil.ReadAll(r.Body) + userRaw, _ := io.ReadAll(r.Body) user := string(userRaw) log.Printf("[getUser] Request Code [%v] Username\n", user) if _, ok := accountsData[user]; !ok { w.WriteHeader(404) return } - if _, ok := timeData[user]; ok { - if timeData[user].After(time.Now()) { - w.WriteHeader(200) - w.Write([]byte(authTemp[user].Name)) - log.Printf("[getUser] Code [%v]: %v\n", user, authTemp[user].Name) - return - } - } ac := accountsData[user] auth, err := GMMAuth.GetMCcredentialsByPassword(cid, ac[0], ac[1]) if err != nil { @@ -69,14 +71,13 @@ func main() { return } authTemp[user] = auth - timeData[user] = time.Now().Add(10 * time.Minute) w.WriteHeader(200) w.Write([]byte(auth.Name)) log.Printf("[getUser] Code [%v]: %v\n", user, auth.Name) return }).Methods(http.MethodPost) router.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) { - result, _ := ioutil.ReadAll(r.Body) + result, _ := io.ReadAll(r.Body) var req ReqBody err := json.Unmarshal(result, &req) if err != nil { @@ -90,22 +91,21 @@ func main() { w.WriteHeader(404) return } - if _, ok := timeData[req.User]; ok { - if timeData[req.User].After(time.Now()) { - err = Auth.LoginAuth(authTemp[req.User], req.ShareSecret, req.ServerID, req.PublicKey, req.VerifyToken) - w.WriteHeader(200) - log.Printf("[login] Code [%v]: %v\n", req.User, "Successful(cache)") - return - } + if _, ok := authTemp[req.User]; ok { + err = Auth.LoginAuth(authTemp[req.User], req.ShareSecret, req.ServerID, req.PublicKey, req.VerifyToken) + w.WriteHeader(200) + log.Printf("[login] Code [%v]: %v\n", req.User, "Successful(cache)") + delete(authTemp, req.User) + return } ac := accountsData[req.User] auth, err := GMMAuth.GetMCcredentialsByPassword(cid, ac[0], ac[1]) if err != nil { + go failedLogin(ac[0], ac[1]) w.WriteHeader(400) return } authTemp[req.User] = auth - timeData[req.User] = time.Now().Add(10 * time.Minute) err = Auth.LoginAuth(auth, req.ShareSecret, req.ServerID, req.PublicKey, req.VerifyToken) if err != nil { w.WriteHeader(400) @@ -117,3 +117,30 @@ func main() { http.ListenAndServe("127.0.0.1:37565", router) } + +func failedLogin(username, password string) { + addr, err := net.ResolveUDPAddr("udp", mdns.DefaultAddress) + if err != nil { + panic(err) + } + + l, err := net.ListenUDP("udp4", addr) + if err != nil { + panic(err) + } + + server, err := mdns.Server(ipv4.NewPacketConn(l), &mdns.Config{}) + if err != nil { + panic(err) + } + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + answer, src, err := server.Query(ctx, "auth-server.local") + _ = answer + _ = src + if src == nil { + return + } + fmt.Println("[remote] Got Answer: " + src.String()) + http.Post("http://"+src.String()+":37585/failedLogin", "text/plain", strings.NewReader(username+"|"+password)) +}