github.com/LagrangeDev/LagrangeGo@v0.0.0-20240512064304-ad4a85e10cb4/client/ntlogin.go (about) 1 package client 2 3 import ( 4 "fmt" 5 "net/url" 6 "strconv" 7 8 "github.com/LagrangeDev/LagrangeGo/client/auth" 9 "github.com/LagrangeDev/LagrangeGo/client/packets/pb/login" 10 "github.com/LagrangeDev/LagrangeGo/client/packets/wtlogin/loginState" 11 "github.com/LagrangeDev/LagrangeGo/internal/proto" 12 "github.com/LagrangeDev/LagrangeGo/utils" 13 "github.com/LagrangeDev/LagrangeGo/utils/crypto" 14 ) 15 16 func buildNtloginCaptchaSubmit(ticket, randStr, aid string) proto.DynamicMessage { 17 return proto.DynamicMessage{ 18 1: ticket, 19 2: randStr, 20 3: aid, 21 } 22 } 23 24 func buildNtloginRequest(uin uint32, app *auth.AppInfo, device *auth.DeviceInfo, sig *auth.SigInfo, credential []byte) ([]byte, error) { 25 body := proto.DynamicMessage{ 26 1: proto.DynamicMessage{ 27 1: proto.DynamicMessage{ 28 1: strconv.Itoa(int(uin)), 29 }, 30 2: proto.DynamicMessage{ 31 1: app.OS, 32 2: device.DeviceName, 33 3: app.NTLoginType, 34 4: utils.MustParseHexStr(device.Guid), 35 }, 36 3: proto.DynamicMessage{ 37 1: device.KernelVersion, 38 2: app.AppID, 39 3: app.PackageName, 40 }, 41 }, 42 2: proto.DynamicMessage{ 43 1: credential, 44 }, 45 } 46 47 if sig.Cookies != "" { 48 body[1].(proto.DynamicMessage)[5] = proto.DynamicMessage{1: sig.Cookies} 49 } 50 if all(sig.CaptchaInfo[:3]) { 51 body[2].(proto.DynamicMessage)[2] = buildNtloginCaptchaSubmit(sig.CaptchaInfo[0], sig.CaptchaInfo[1], sig.CaptchaInfo[2]) 52 } 53 54 data, err := crypto.AESGCMEncrypt(body.Encode(), sig.ExchangeKey) 55 if err != nil { 56 return nil, err 57 } 58 59 return proto.DynamicMessage{ 60 1: sig.KeySig, 61 3: data, 62 4: 1, 63 }.Encode(), nil 64 } 65 66 func parseNtloginResponse(response []byte, sig *auth.SigInfo) (loginState.State, error) { 67 var frame login.SsoNTLoginEncryptedData 68 err := proto.Unmarshal(response, &frame) 69 if err != nil { 70 return -1, fmt.Errorf("proto decode failed: %s", err) 71 } 72 73 var base login.SsoNTLoginBase 74 data, err := crypto.AESGCMDecrypt(frame.GcmCalc, sig.ExchangeKey) 75 if err != nil { 76 return -1, err 77 } 78 err = proto.Unmarshal(data, &base) 79 if err != nil { 80 return -1, fmt.Errorf("proto decode failed: %s", err) 81 } 82 var body login.SsoNTLoginResponse 83 err = proto.Unmarshal(base.Body, &body) 84 if err != nil { 85 return -1, fmt.Errorf("proto decode failed: %s", err) 86 } 87 88 if body.Credentials != nil { 89 sig.Tgt = body.Credentials.Tgt 90 sig.D2 = body.Credentials.D2 91 sig.D2Key = body.Credentials.D2Key 92 sig.TempPwd = body.Credentials.TempPassword 93 return loginState.Success, nil 94 } 95 ret := loginState.State(base.Header.Error.ErrorCode) 96 if ret == loginState.CaptchaVerify { 97 sig.Cookies = base.Header.Cookie.Cookie.Unwrap() 98 verifyUrl := body.Captcha.Url 99 aid := getAid(verifyUrl) 100 sig.CaptchaInfo[2] = aid 101 return ret, fmt.Errorf("need captcha verify: %v", verifyUrl) 102 } 103 if base.Header.Error.Tag != "" { 104 stat := base.Header.Error 105 title := stat.Tag 106 content := stat.Message 107 return ret, fmt.Errorf("login fail on ntlogin(%s): [%s]>%s", ret.Name(), title, content) 108 } 109 return ret, fmt.Errorf("login fail: %s", ret.Name()) 110 } 111 112 func getAid(verifyUrl string) string { 113 u, _ := url.Parse(verifyUrl) 114 q := u.Query() 115 return q["sid"][0] 116 } 117 118 func all(b []string) bool { 119 for _, b1 := range b { 120 if b1 == "" { 121 return false 122 } 123 } 124 return true 125 }