aboutsummaryrefslogtreecommitdiff
path: root/server_conn.go
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2021-08-27 18:59:27 +0200
committerHimbeerserverDE <himbeerserverde@gmail.com>2021-08-27 18:59:27 +0200
commitb21345fba99d38c5e5ade695e32fc9e23ea48e98 (patch)
tree3d90d8abd9d356109d8690c5babd481abb363b55 /server_conn.go
parentca7c62308867f27a607fd17d72f926fcda05bb32 (diff)
Basic authentication server and content multiplexer
Diffstat (limited to 'server_conn.go')
-rw-r--r--server_conn.go142
1 files changed, 142 insertions, 0 deletions
diff --git a/server_conn.go b/server_conn.go
new file mode 100644
index 0000000..d2d39b1
--- /dev/null
+++ b/server_conn.go
@@ -0,0 +1,142 @@
+package main
+
+import (
+ "errors"
+ "fmt"
+ "log"
+ "net"
+ "time"
+
+ "github.com/HimbeerserverDE/srp"
+ "github.com/anon55555/mt"
+)
+
+type serverConn struct {
+ mt.Peer
+ clt *clientConn
+
+ state clientState
+ name string
+ initCh chan struct{}
+
+ auth struct {
+ method mt.AuthMethods
+ salt, srpA, a, srpK []byte
+ }
+}
+
+func (sc *serverConn) client() *clientConn { return sc.clt }
+
+func (sc *serverConn) init() <-chan struct{} { return sc.initCh }
+
+func (sc *serverConn) log(dir, msg string) {
+ log.Printf("{←|⇶} %s {%s} %s", dir, sc.name, msg)
+}
+
+func handleSrv(sc *serverConn) {
+ if sc.client() == nil {
+ sc.log("-->", "no associated client")
+ }
+
+ go func() {
+ for sc.state == csCreated {
+ sc.SendCmd(&mt.ToSrvInit{
+ SerializeVer: latestSerializeVer,
+ MinProtoVer: latestProtoVer,
+ MaxProtoVer: latestProtoVer,
+ PlayerName: sc.client().name,
+ })
+ time.Sleep(500 * time.Millisecond)
+ }
+ }()
+
+ for {
+ pkt, err := sc.Recv()
+ if err != nil {
+ if errors.Is(err, net.ErrClosed) {
+ sc.log("<->", "disconnect")
+ break
+ }
+
+ sc.log("-->", err.Error())
+ continue
+ }
+
+ switch cmd := pkt.Cmd.(type) {
+ case *mt.ToCltHello:
+ if sc.auth.method != 0 {
+ sc.log("<--", "unexpected authentication")
+ sc.Close()
+ break
+ }
+
+ sc.state++
+
+ if cmd.AuthMethods&mt.FirstSRP == mt.FirstSRP {
+ sc.auth.method = mt.FirstSRP
+ } else {
+ sc.auth.method = mt.SRP
+ }
+
+ if cmd.SerializeVer != latestSerializeVer {
+ sc.log("<--", "invalid serializeVer")
+ break
+ }
+
+ switch sc.auth.method {
+ case mt.SRP:
+ sc.auth.srpA, sc.auth.a, err = srp.InitiateHandshake()
+ if err != nil {
+ sc.log("-->", err.Error())
+ break
+ }
+
+ sc.SendCmd(&mt.ToSrvSRPBytesA{
+ A: sc.auth.srpA,
+ NoSHA1: true,
+ })
+ case mt.FirstSRP:
+ salt, verifier, err := srp.NewClient([]byte(sc.client().name), []byte{})
+ if err != nil {
+ sc.log("-->", err.Error())
+ break
+ }
+
+ sc.SendCmd(&mt.ToSrvFirstSRP{
+ Salt: salt,
+ Verifier: verifier,
+ EmptyPasswd: true,
+ })
+ default:
+ sc.log("<->", "invalid auth method")
+ sc.Close()
+ }
+ case *mt.ToCltSRPBytesSaltB:
+ if sc.auth.method != mt.SRP {
+ sc.log("<--", "multiple authentication attempts")
+ break
+ }
+
+ sc.auth.srpK, err = srp.CompleteHandshake(sc.auth.srpA, sc.auth.a, []byte(sc.client().name), []byte{}, cmd.Salt, cmd.B)
+ if err != nil {
+ sc.log("-->", err.Error())
+ break
+ }
+
+ M := srp.ClientProof([]byte(sc.client().name), cmd.Salt, sc.auth.srpA, cmd.B, sc.auth.srpK)
+ if M == nil {
+ sc.log("<--", "SRP safety check fail")
+ break
+ }
+
+ sc.SendCmd(&mt.ToSrvSRPBytesM{
+ M: M,
+ })
+ case *mt.ToCltDisco:
+ sc.log("<--", fmt.Sprintf("deny access %+v", cmd))
+ case *mt.ToCltAcceptAuth:
+ sc.auth.method = 0
+ sc.SendCmd(&mt.ToSrvInit2{Lang: sc.client().lang})
+ }
+ }
+}