4 "github.com/HimbeerserverDE/srp"
5 "github.com/anon55555/mt"
6 "github.com/dragonfireclient/hydra/tolua"
7 "github.com/yuin/gopher-lua"
15 asInit authState = iota
30 srpBytesA, bytesA []byte
31 userdata *lua.LUserData
34 var authFuncs = map[string]lua.LGFunction{
35 "username": l_auth_username,
36 "password": l_auth_password,
37 "language": l_auth_language,
38 "version": l_auth_version,
39 "state": l_auth_state,
42 func getAuth(l *lua.LState) *Auth {
43 return l.CheckUserData(1).Value.(*Auth)
46 func (auth *Auth) create(client *Client, l *lua.LState) {
47 if client.state != csNew {
48 panic("can't add auth component after connect")
52 auth.language = "en_US"
53 auth.version = "hydra-dragonfire"
55 auth.userdata = l.NewUserData()
56 auth.userdata.Value = auth
57 l.SetMetatable(auth.userdata, l.GetTypeMetatable("hydra.auth"))
60 func (auth *Auth) tolua() lua.LValue {
64 func (auth *Auth) connect() {
65 if auth.username == "" {
66 panic("missing username")
70 for auth.client.state == csConnected && auth.state == asInit {
71 auth.client.conn.SendCmd(&mt.ToSrvInit{
75 PlayerName: auth.username,
77 time.Sleep(500 * time.Millisecond)
82 func (auth *Auth) fail(err string) {
85 auth.client.disconnect()
88 func (auth *Auth) checkState(state authState, pkt *mt.Pkt) bool {
89 if auth.state == state {
93 auth.fail("received " + string(tolua.PktType(pkt)) + " in invalid state")
97 func (auth *Auth) process(pkt *mt.Pkt) {
98 if auth.state == asError {
102 switch cmd := pkt.Cmd.(type) {
104 if !auth.checkState(asInit, pkt) {
108 if cmd.SerializeVer != 28 {
109 auth.fail("unsupported serialize version")
113 if cmd.AuthMethods == mt.FirstSRP {
114 salt, verifier, err := srp.NewClient([]byte(strings.ToLower(auth.username)), []byte(auth.password))
116 auth.fail(err.Error())
120 auth.client.conn.SendCmd(&mt.ToSrvFirstSRP{
123 EmptyPasswd: auth.password == "",
125 auth.state = asVerified
126 } else if cmd.AuthMethods == mt.SRP {
128 auth.srpBytesA, auth.bytesA, err = srp.InitiateHandshake()
130 auth.fail(err.Error())
134 auth.client.conn.SendCmd(&mt.ToSrvSRPBytesA{
138 auth.state = asRequested
140 auth.fail("invalid auth methods")
144 case *mt.ToCltSRPBytesSaltB:
145 if !auth.checkState(asRequested, pkt) {
149 srpBytesK, err := srp.CompleteHandshake(auth.srpBytesA, auth.bytesA, []byte(strings.ToLower(auth.username)), []byte(auth.password), cmd.Salt, cmd.B)
151 auth.fail(err.Error())
155 M := srp.ClientProof([]byte(auth.username), cmd.Salt, auth.srpBytesA, cmd.B, srpBytesK)
156 auth.srpBytesA = []byte{}
157 auth.bytesA = []byte{}
160 auth.fail("srp safety check fail")
164 auth.client.conn.SendCmd(&mt.ToSrvSRPBytesM{
167 auth.state = asVerified
169 case *mt.ToCltAcceptAuth:
170 auth.client.conn.SendCmd(&mt.ToSrvInit2{Lang: auth.language})
172 case *mt.ToCltTimeOfDay:
173 if auth.state == asActive {
177 if !auth.checkState(asVerified, pkt) {
181 auth.client.conn.SendCmd(&mt.ToSrvCltReady{
187 Version: auth.version,
189 auth.state = asActive
193 func (auth *Auth) accessProperty(l *lua.LState, key string, ptr *string) int {
194 if str, ok := l.Get(2).(lua.LString); ok {
195 if auth.client.state != csNew {
196 panic("can't change " + key + " after connecting")
201 l.Push(lua.LString(*ptr))
206 func l_auth_username(l *lua.LState) int {
208 return auth.accessProperty(l, "username", &auth.username)
211 func l_auth_password(l *lua.LState) int {
213 return auth.accessProperty(l, "password", &auth.password)
216 func l_auth_language(l *lua.LState) int {
218 return auth.accessProperty(l, "language", &auth.language)
221 func l_auth_version(l *lua.LState) int {
223 return auth.accessProperty(l, "version", &auth.version)
226 func l_auth_state(l *lua.LState) int {
231 l.Push(lua.LString("init"))
233 l.Push(lua.LString("requested"))
235 l.Push(lua.LString("verified"))
237 l.Push(lua.LString("active"))
239 l.Push(lua.LString("error"))
240 l.Push(lua.LString(auth.err))