diff --git a/go.mod b/go.mod index 72bb5ce..e8deff9 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.24.0 require ( github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/pion/datachannel v1.6.0 // indirect github.com/pion/dtls/v2 v2.2.7 // indirect github.com/pion/dtls/v3 v3.1.2 // indirect diff --git a/go.sum b/go.sum index 0d53c3a..a0f8295 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= diff --git a/main.go b/main.go index d4f024e..01f1d74 100644 --- a/main.go +++ b/main.go @@ -1,16 +1,25 @@ package main import ( + "g365sfu/logger" "g365sfu/socket" "net/http" "os" + + "github.com/joho/godotenv" ) func main() { + godotenv.Load() + if os.Getenv("SECRET") == "" { + logger.LogErrorMessage("server failed to start because not set secret key in .env variables") + return + } http.HandleFunc("/", socket.HandleWebSocket) port := os.Getenv("PORT") if port == "" { port = "1001" } + logger.LogInfoMessage("server started at x.x.x.x:" + port) http.ListenAndServe(":"+port, nil) } diff --git a/socket/socket.go b/socket/socket.go index 8006d32..45911a5 100644 --- a/socket/socket.go +++ b/socket/socket.go @@ -1,8 +1,10 @@ package socket import ( - "fmt" + "g365sfu/logger" + "math/rand" "net/http" + "os" "github.com/gorilla/websocket" ) @@ -16,6 +18,10 @@ var upgrader = websocket.Upgrader{ }, } +func getSecret() string { + return os.Getenv("SECRET") +} + // Обработчик WebSocket соединений func HandleWebSocket(w http.ResponseWriter, r *http.Request) { conn, _ := upgrader.Upgrade(w, r, nil) @@ -24,8 +30,16 @@ func HandleWebSocket(w http.ResponseWriter, r *http.Request) { // Канал для передачи байтов dataChan := make(chan []byte) + var connection = &Connection{ + Identificator: randomSocketIdentifier(), + Socket: conn, + } + AddSocket(connection) + // Удаление сокета из хранилища при закрытии соединения + defer RemoveSocket(connection.Identificator) + // Запуск обработчика в горутине - go processData(dataChan) + go processData(dataChan, connection) for { messageType, p, err := conn.ReadMessage() @@ -37,11 +51,46 @@ func HandleWebSocket(w http.ResponseWriter, r *http.Request) { } } -func processData(data <-chan []byte) { +// Генерация случайного идентификатора для сокета +func randomSocketIdentifier() string { + // Генерация случайного идентификатора для сокета + return "sock_" + randomString(10) +} + +// Генерация случайной строки заданной длины +func randomString(n int) string { + const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + b := make([]byte, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} + +func processData(data <-chan []byte, connection *Connection) { for bytes := range data { // Логика обработки байтов if bytes[0] == 0x01 { - fmt.Print("Type 0x01 received") + // Это рукопожатие, дальше сравниваем секретные ключи + // Секретный ключ идет сразу после первого байта и до конца сообщения + receivedSecret := string(bytes[1:]) + if receivedSecret == getSecret() { + logger.LogSuccessMessage("success handshake from " + connection.Socket.RemoteAddr().String()) + AddSocket(connection) + connection.Socket.WriteMessage(websocket.BinaryMessage, []byte{0x01}) + return + } + connection.Socket.WriteMessage(websocket.BinaryMessage, []byte{0xFF}) + logger.LogWarnMessage("failed handshake from " + connection.Socket.RemoteAddr().String() + " because of invalid secret key") + return } + + // Так как следующие пакеты требуют обязательного завершения рукопожатия, нужно проверять, что сокет уже прошел рукопожатие + if _, exists := GetSocket(connection.Identificator); !exists { + logger.LogWarnMessage("received data from " + connection.Socket.RemoteAddr().String() + " but it has not completed handshake") + return + } + + // Следующие типы сообщений } }