aboutsummaryrefslogtreecommitdiff
path: root/comp_auth.go
diff options
context:
space:
mode:
authorElias Fleckenstein <eliasfleckenstein@web.de>2022-06-01 18:09:48 +0200
committerElias Fleckenstein <eliasfleckenstein@web.de>2022-06-01 18:09:48 +0200
commit9018d87c86806b2c6d7cabd964479031d2a1e7b1 (patch)
treeabf57b2eb29a44cb0d7aa93c18bad68625c94da6 /comp_auth.go
parentea4263290b2e7d82b29cc9809d98bf33528b1c61 (diff)
downloadhydra-dragonfire-9018d87c86806b2c6d7cabd964479031d2a1e7b1.tar.xz
Allow multiple clients to share a map
Diffstat (limited to 'comp_auth.go')
-rw-r--r--comp_auth.go245
1 files changed, 245 insertions, 0 deletions
diff --git a/comp_auth.go b/comp_auth.go
new file mode 100644
index 0000000..5d3f838
--- /dev/null
+++ b/comp_auth.go
@@ -0,0 +1,245 @@
+package main
+
+import (
+ "github.com/HimbeerserverDE/srp"
+ "github.com/anon55555/mt"
+ "github.com/dragonfireclient/hydra-dragonfire/convert"
+ "github.com/yuin/gopher-lua"
+ "strings"
+ "time"
+)
+
+type authState uint8
+
+const (
+ asInit authState = iota
+ asRequested
+ asVerified
+ asActive
+ asError
+)
+
+type CompAuth struct {
+ client *Client
+ username string
+ password string
+ language string
+ version string
+ state authState
+ err string
+ srpBytesA, bytesA []byte
+ userdata *lua.LUserData
+}
+
+var compAuthFuncs = map[string]lua.LGFunction{
+ "username": l_comp_auth_username,
+ "password": l_comp_auth_password,
+ "language": l_comp_auth_language,
+ "version": l_comp_auth_version,
+ "state": l_comp_auth_state,
+}
+
+func getCompAuth(l *lua.LState) *CompAuth {
+ return l.CheckUserData(1).Value.(*CompAuth)
+}
+
+func (comp *CompAuth) create(client *Client, l *lua.LState) {
+ if client.state != csNew {
+ panic("can't add auth component after connect")
+ }
+
+ comp.client = client
+ comp.language = "en_US"
+ comp.version = "hydra-dragonfire"
+ comp.state = asInit
+ comp.userdata = l.NewUserData()
+ comp.userdata.Value = comp
+ l.SetMetatable(comp.userdata, l.GetTypeMetatable("hydra.comp.auth"))
+}
+
+func (comp *CompAuth) push() lua.LValue {
+ return comp.userdata
+}
+
+func (comp *CompAuth) connect() {
+ if comp.username == "" {
+ panic("missing username")
+ }
+
+ go func() {
+ for comp.client.state == csConnected && comp.state == asInit {
+ comp.client.conn.SendCmd(&mt.ToSrvInit{
+ SerializeVer: serializeVer,
+ MinProtoVer: protoVer,
+ MaxProtoVer: protoVer,
+ PlayerName: comp.username,
+ })
+ time.Sleep(500 * time.Millisecond)
+ }
+ }()
+}
+
+func (comp *CompAuth) fail(err string) {
+ comp.err = err
+ comp.state = asError
+ comp.client.closeConn()
+}
+
+func (comp *CompAuth) checkState(state authState, pkt *mt.Pkt) bool {
+ if comp.state == state {
+ return true
+ }
+
+ comp.fail("received " + string(convert.PushPktType(pkt)) + " in invalid state")
+ return false
+}
+
+func (comp *CompAuth) process(pkt *mt.Pkt) {
+ if comp.state == asError {
+ return
+ }
+
+ switch cmd := pkt.Cmd.(type) {
+ case *mt.ToCltHello:
+ if !comp.checkState(asInit, pkt) {
+ return
+ }
+
+ if cmd.SerializeVer != 28 {
+ comp.fail("unsupported serialize version")
+ return
+ }
+
+ if cmd.AuthMethods == mt.FirstSRP {
+ salt, verifier, err := srp.NewClient([]byte(strings.ToLower(comp.username)), []byte(comp.password))
+ if err != nil {
+ comp.fail(err.Error())
+ return
+ }
+
+ comp.client.conn.SendCmd(&mt.ToSrvFirstSRP{
+ Salt: salt,
+ Verifier: verifier,
+ EmptyPasswd: comp.password == "",
+ })
+ comp.state = asVerified
+ } else if cmd.AuthMethods == mt.SRP {
+ var err error
+ comp.srpBytesA, comp.bytesA, err = srp.InitiateHandshake()
+ if err != nil {
+ comp.fail(err.Error())
+ return
+ }
+
+ comp.client.conn.SendCmd(&mt.ToSrvSRPBytesA{
+ A: comp.srpBytesA,
+ NoSHA1: true,
+ })
+ comp.state = asRequested
+ } else {
+ comp.fail("invalid auth methods")
+ return
+ }
+
+ case *mt.ToCltSRPBytesSaltB:
+ if !comp.checkState(asRequested, pkt) {
+ return
+ }
+
+ srpBytesK, err := srp.CompleteHandshake(comp.srpBytesA, comp.bytesA, []byte(strings.ToLower(comp.username)), []byte(comp.password), cmd.Salt, cmd.B)
+ if err != nil {
+ comp.fail(err.Error())
+ return
+ }
+
+ M := srp.ClientProof([]byte(comp.username), cmd.Salt, comp.srpBytesA, cmd.B, srpBytesK)
+ comp.srpBytesA = []byte{}
+ comp.bytesA = []byte{}
+
+ if M == nil {
+ comp.fail("srp safety check fail")
+ return
+ }
+
+ comp.client.conn.SendCmd(&mt.ToSrvSRPBytesM{
+ M: M,
+ })
+ comp.state = asVerified
+
+ case *mt.ToCltAcceptAuth:
+ comp.client.conn.SendCmd(&mt.ToSrvInit2{Lang: comp.language})
+
+ case *mt.ToCltTimeOfDay:
+ if comp.state == asActive {
+ return
+ }
+
+ if !comp.checkState(asVerified, pkt) {
+ return
+ }
+
+ comp.client.conn.SendCmd(&mt.ToSrvCltReady{
+ Major: 5,
+ Minor: 6,
+ Patch: 0,
+ Reserved: 0,
+ Formspec: 4,
+ Version: comp.version,
+ })
+ comp.state = asActive
+ }
+}
+
+func (comp *CompAuth) accessProperty(l *lua.LState, key string, ptr *string) int {
+ if str, ok := l.Get(2).(lua.LString); ok {
+ if comp.client.state != csNew {
+ panic("can't change " + key + " after connecting")
+ }
+ *ptr = string(str)
+ return 0
+ } else {
+ l.Push(lua.LString(*ptr))
+ return 1
+ }
+}
+
+func l_comp_auth_username(l *lua.LState) int {
+ comp := getCompAuth(l)
+ return comp.accessProperty(l, "username", &comp.username)
+}
+
+func l_comp_auth_password(l *lua.LState) int {
+ comp := getCompAuth(l)
+ return comp.accessProperty(l, "password", &comp.password)
+}
+
+func l_comp_auth_language(l *lua.LState) int {
+ comp := getCompAuth(l)
+ return comp.accessProperty(l, "language", &comp.language)
+}
+
+func l_comp_auth_version(l *lua.LState) int {
+ comp := getCompAuth(l)
+ return comp.accessProperty(l, "version", &comp.version)
+}
+
+func l_comp_auth_state(l *lua.LState) int {
+ comp := getCompAuth(l)
+
+ switch comp.state {
+ case asInit:
+ l.Push(lua.LString("init"))
+ case asRequested:
+ l.Push(lua.LString("requested"))
+ case asVerified:
+ l.Push(lua.LString("verified"))
+ case asActive:
+ l.Push(lua.LString("active"))
+ case asError:
+ l.Push(lua.LString("error"))
+ l.Push(lua.LString(comp.err))
+ return 2
+ }
+
+ return 1
+}