reid 2 éve
szülő
commit
a212a2c5e9
5 módosított fájl, 98 hozzáadás és 91 törlés
  1. 38 60
      auth/auth.go
  2. 1 1
      broadcast/broadcast.go
  3. 1 0
      structs/ws.go
  4. 1 1
      system/system.go
  5. 57 29
      ws/ws.go

+ 38 - 60
auth/auth.go

@@ -1,4 +1,5 @@
 package auth
+
 // package for authenticating websockets
 // we use a homespun jwt knock-off because no tls on lan
 // authentication adds you to the AuthenticatedClients map
@@ -27,84 +28,61 @@ var (
 	// maps a websocket conn to a tokenid
 	// tokenid's can be referenced from the global conf
 	AuthenticatedClients = struct {
-		Conns map[*websocket.Conn]string
+		Conns map[string]*websocket.Conn
 		sync.RWMutex
 	}{
-		Conns: make(map[*websocket.Conn]string),
+		Conns: make(map[string]*websocket.Conn),
 	}
 	UnauthClients = struct {
-		Conns map[*websocket.Conn]string
+		Conns map[string]*websocket.Conn
 		sync.RWMutex
 	}{
-		Conns: make(map[*websocket.Conn]string),
+		Conns: make(map[string]*websocket.Conn),
 	}
 )
 
-// check if websocket session is in the auth map
-func WsIsAuthenticated(conn *websocket.Conn) bool {
-	AuthenticatedClients.Lock()
-	defer AuthenticatedClients.Unlock()
-	_, exists := AuthenticatedClients.Conns[conn]
-	return exists
-}
-
-// check if a hash is in the auth map
-func hashAuthenticated(hash string) bool {
-	AuthenticatedClients.RLock() // Acquire read lock
+// check if websocket-token pair is auth'd
+func WsIsAuthenticated(conn *websocket.Conn, token string) bool {
+	AuthenticatedClients.RLock()         // Acquire read lock
 	defer AuthenticatedClients.RUnlock() // Release read lock
-	for _, v := range AuthenticatedClients.Conns {
-		if v == hash {
-			return true
-		}
+	if AuthenticatedClients.Conns[token] == conn {
+		return true
+	} else {
+		return false
 	}
-	return false
 }
 
 // check the validity of the token
-func CheckToken(token string, conn *websocket.Conn, r *http.Request, setup bool) (bool, string, error) {
-	// no token? we have problem.
-	if token == "" {
-		authStatus := false
-		if setup {
-			authStatus = true
-		}
-		// you take token.
-		newToken, err := CreateToken(conn, r, setup)
-		if err != nil {
-			return false, "", err
-		}
-		return authStatus, newToken["token"], nil
+func CheckToken(token map[string]string, conn *websocket.Conn, r *http.Request, setup bool) (bool, string, error) {
+	// great you have token. we see if valid.
+	conf := config.Conf()
+	key := conf.KeyFile
+	res, err := KeyfileDecrypt(token["token"], key)
+	if err != nil {
+		config.Logger.Warn("Invalid token provided")
+		return false, "", err
 	} else {
-		// great you have token. we see if valid.
-		conf := config.Conf()
-		key := conf.KeyFile
-		res, err := KeyfileDecrypt(token, key)
-		if err != nil {
-			config.Logger.Warn("Invalid token provided")
-			return false, "", err
+		// so you decrypt. now we see the useragent and ip.
+		var ip string
+		if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
+			ip = strings.Split(forwarded, ",")[0]
 		} else {
-			// so you decrypt. now we see the useragent and ip.
-			var ip string
-			if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
-				ip = strings.Split(forwarded, ",")[0]
-			} else {
-				ip, _, _ = net.SplitHostPort(r.RemoteAddr)
-			}
-			userAgent := r.Header.Get("User-Agent")
-			hashed := sha256.Sum256([]byte(token))
-			hash := hex.EncodeToString(hashed[:])
-			// you in auth map?
-			if hashAuthenticated(hash) {
-				if ip == res["ip"] && userAgent == res["user_agent"] {
-					return true, res["id"], nil
-				} else {
-					config.Logger.Warn("Token doesn't match session!")
-					return false, res["id"], err
-				}
+			ip, _, _ = net.SplitHostPort(r.RemoteAddr)
+		}
+		userAgent := r.Header.Get("User-Agent")
+		hashed := sha256.Sum256([]byte(token["token"]))
+		hash := hex.EncodeToString(hashed[:])
+		// you in auth map?
+		if WsIsAuthenticated(conn, hash) {
+			if ip == res["ip"] && userAgent == res["user_agent"] {
+				return true, res["id"], nil
 			} else {
-				config.Logger.Warn("Token isn't an authenticated session")
+				config.Logger.Warn("Token doesn't match session!")
 				return false, res["id"], err
 			}
+		} else {
+			config.Logger.Warn("Token isn't an authenticated session")
+			return false, res["id"], err
 		}
 	}
 	return false, "", nil
@@ -255,7 +233,7 @@ func AuthenticateLogin(password string) bool {
 	if hash == conf.PwHash {
 		return true
 	} else {
-		config.Logger.Warn(fmt.Sprintf("debug: failed pw hash: %v",hash))
+		config.Logger.Warn(fmt.Sprintf("debug: failed pw hash: %v", hash))
 		return false
 	}
 }

+ 1 - 1
broadcast/broadcast.go

@@ -345,7 +345,7 @@ func BroadcastToClients() error {
 	auth.AuthenticatedClients.Lock()
 	defer auth.AuthenticatedClients.Unlock()
 	for client := range auth.AuthenticatedClients.Conns {
-		if err := client.WriteMessage(websocket.TextMessage, authJson); err != nil {
+		if err := auth.AuthenticatedClients.Conns[client].WriteMessage(websocket.TextMessage, authJson); err != nil {
 			config.Logger.Error(fmt.Sprintf("Error writing response: %v", err))
 			return err
 		}

+ 1 - 0
structs/ws.go

@@ -8,6 +8,7 @@ type WsType struct {
 
 type WsPayload struct {
 	ID      string        `json:"id"`
+	Type    string        `json:"type"`
 	Payload interface{}   `json:"payload"`
 	Token   WsTokenStruct `json:"token"`
 }

+ 1 - 1
system/system.go

@@ -4,10 +4,10 @@ package system
 
 import (
 	"fmt"
-	"goseg/config"
 	"github.com/shirou/gopsutil/cpu"
 	"github.com/shirou/gopsutil/disk"
 	"github.com/shirou/gopsutil/mem"
+	"goseg/config"
 	"io/ioutil"
 	"strconv"
 	"strings"

+ 57 - 29
ws/ws.go

@@ -75,21 +75,41 @@ func WsHandler(w http.ResponseWriter, r *http.Request) {
 		if err != nil {
 			return
 		}
-		var prelim structs.WsType
 		var payload structs.WsPayload
-		if err := json.Unmarshal(msg, &prelim); err != nil {
-			fmt.Println("Error unmarshalling message:", err)
+		// if it fails to marshal, assume that means no token
+		// "verify" action is implicit
+		if err := json.Unmarshal(msg, &payload); err != nil {
+			// auth.CreateToken also adds to unauth map
+			newToken, err := auth.CreateToken(conn, r, false)
+			if err != nil {
+				config.Logger.Error("Unable to create token")
+				continue
+			}
+			result := map[string]interface{}{
+				"type":     "activity",
+				"id":       payload.ID, // this is like the action id
+				"error":    "null",
+				"response": "ack",
+				"token":    newToken,
+			}
+			respJson, err := json.Marshal(result)
+			if err != nil {
+				errmsg := fmt.Sprintf("Error marshalling token: %v", err)
+				config.Logger.Error(errmsg)
+				continue
+			}
+			if err := conn.WriteMessage(websocket.TextMessage, respJson); err != nil {
+				config.Logger.Error(fmt.Sprintf("Error writing response: %v", err))
+				continue
+			}
 			continue
 		}
-		switch prelim.Payload.Type {
+		payload.Payload = structs.WsLoginPayload{}
+		switch payload.Type {
 		case "login":
 			if err = loginHandler(msg, payload); err != nil {
 				config.Logger.Error(fmt.Sprintf("%v", err))
 			}
-		case "verify":
-			if err = verifyHandler(msg, payload, r, conn); err != nil {
-				config.Logger.Error(fmt.Sprintf("%v", err))
-			}
 		case "setup":
 			config.Logger.Info("Setup")
 			// setup.Setup(payload)
@@ -115,7 +135,7 @@ func WsHandler(w http.ResponseWriter, r *http.Request) {
 				config.Logger.Error(errmsg)
 			}
 		default:
-			errmsg := fmt.Sprintf("Unknown request type: %s", prelim.Payload.Type)
+			errmsg := fmt.Sprintf("Unknown request type: %s", payload.Type)
 			config.Logger.Warn(errmsg)
 		}
 	}
@@ -140,30 +160,38 @@ func loginHandler(msg []byte, payload structs.WsPayload) error {
 		}
 	} else {
 		config.Logger.Info("Login failed")
+		return fmt.Errorf("Failed auth")
 	}
 	return nil
 }
 
-// create tokens for those who have not auth
-func verifyHandler(msg []byte, payload structs.WsPayload, r *http.Request, conn *websocket.Conn) error {
-	config.Logger.Info("Verify")
-	payload.Payload = structs.WsLoginPayload{}
-	// if we can't unmarshal, assume no token
-	if err := json.Unmarshal(msg, &payload); err != nil {
-		resp, err := auth.CreateToken(conn, r, false)
-		if err != nil {
-			fmt.Errorf("Couldn't create token: %v", err)
-		}
-		respJson, err := json.Marshal(resp)
-		if err != nil {
-			return fmt.Errorf("Error marshalling token: %v", err)
-		}
-		if err := conn.WriteMessage(websocket.TextMessage, respJson); err != nil {
-			return fmt.Errorf("Error writing response: %v", err)
-		}
-	}
-	return nil
-}
+// client send:
+// {
+// 	"type": "verify",
+// 	"id": "jsgeneratedid",
+// 	"token<optional>": {
+// 	  "id": "servergeneratedid",
+// 	  "token": "encryptedtext"
+// 	}
+// }
+
+// 1. we decrypt the token
+// 2. we modify token['authorized'] to true
+// 3. remove it from 'unauthorized' in system.json
+// 4. hash and add to 'authozired' in system.json
+// 5. encrypt that, and send it back to the user
+
+// server respond:
+// {
+// 	"type": "activity",
+// 	"response": "ack/nack",
+// 	"error": "null/<some_error>",
+// 	"id": "jsgeneratedid",
+// 	"token": { (either new token or the token the user sent us)
+// 	  "id": "relevant_token_id",
+// 	  "token": "encrypted_text"
+// 	}
+// }
 
 func supportHandler(msg []byte, payload structs.WsPayload, r *http.Request, conn *websocket.Conn) error {
 	config.Logger.Info("Support")