mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
WebSocketProtocol: Add Identify logic (not tested well)
This commit is contained in:
parent
f57d03e4bb
commit
09bfea0628
@ -1 +1,102 @@
|
|||||||
#include "WebSocketProtocol.h"
|
#include "WebSocketProtocol.h"
|
||||||
|
#include "obs-websocket.h"
|
||||||
|
#include "utils/Utils.h"
|
||||||
|
|
||||||
|
#include "plugin-macros.generated.h"
|
||||||
|
|
||||||
|
WebSocketProtocol::ProcessResult SetSessionParameters(WebSocketSession *session, json incomingMessage)
|
||||||
|
{
|
||||||
|
WebSocketProtocol::ProcessResult ret;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebSocketProtocol::ProcessResult WebSocketProtocol::ProcessMessage(websocketpp::connection_hdl hdl, WebSocketSession *session, json incomingMessage)
|
||||||
|
{
|
||||||
|
WebSocketProtocol::ProcessResult ret;
|
||||||
|
|
||||||
|
if (!incomingMessage.is_object()) {
|
||||||
|
if (!session->IgnoreInvalidMessages()) {
|
||||||
|
ret.closeCode = WebSocketServer::WebSocketCloseCode::MessageDecodeError;
|
||||||
|
ret.closeReason = "You sent a non-object payload.";
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!incomingMessage.contains("messageType")) {
|
||||||
|
if (incomingMessage.contains("request-type")) {
|
||||||
|
ret.closeCode = WebSocketServer::WebSocketCloseCode::UnsupportedProtocolVersion;
|
||||||
|
ret.closeReason = "You appear to be attempting to connect with the pre-5.0.0 plugin protocol. Check to make sure your client is updated.";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!session->IgnoreInvalidMessages()) {
|
||||||
|
ret.closeCode = WebSocketServer::WebSocketCloseCode::UnknownMessageType;
|
||||||
|
ret.closeReason = "Your request is missing a `messageType`";
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string messageType = incomingMessage["messageType"];
|
||||||
|
|
||||||
|
if (!session->IsIdentified() && messageType != "Identify") {
|
||||||
|
ret.closeCode = WebSocketServer::WebSocketCloseCode::NotIdentified;
|
||||||
|
ret.closeReason = "You attempted to send a non-`Identify` message while not identified.";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageType == "Request") {
|
||||||
|
;
|
||||||
|
} else if (messageType == "RequestBatch") {
|
||||||
|
;
|
||||||
|
} else if (messageType == "Identify") {
|
||||||
|
if (session->IsIdentified()) {
|
||||||
|
if (!session->IgnoreInvalidMessages()) {
|
||||||
|
ret.closeCode = WebSocketServer::WebSocketCloseCode::AlreadyIdentified;
|
||||||
|
ret.closeReason = "You are already Identified with the obs-websocket server.";
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto webSocketServer = GetWebSocketServer();
|
||||||
|
if (!webSocketServer) {
|
||||||
|
blog(LOG_ERROR, "[WebSocketProtocol::ProcessMessage] Unable to fetch websocket server instance!");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webSocketServer->AuthenticationRequired) {
|
||||||
|
if (!incomingMessage.contains("authentication")) {
|
||||||
|
ret.closeCode = WebSocketServer::WebSocketCloseCode::InvalidIdentifyParameter;
|
||||||
|
ret.closeReason = "Your `Identify` payload is missing an `authentication` string, however authentication is required.";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!Utils::Crypto::CheckAuthenticationString(webSocketServer->AuthenticationSecret, session->Challenge(), incomingMessage["authentication"])) {
|
||||||
|
ret.closeCode = WebSocketServer::WebSocketCloseCode::AuthenticationFailed;
|
||||||
|
ret.closeReason = "Authentication failed.";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WebSocketProtocol::ProcessResult parameterResult = SetSessionParameters(session, incomingMessage);
|
||||||
|
if (ret.closeCode != WebSocketServer::WebSocketCloseCode::DontClose) {
|
||||||
|
return parameterResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
blog(LOG_INFO, "Identified!");
|
||||||
|
|
||||||
|
session->SetIsIdentified(true);
|
||||||
|
|
||||||
|
ret.result["messageType"] = "Identified";
|
||||||
|
ret.result["negotiatedRpcVersion"] = session->RpcVersion();
|
||||||
|
return ret;
|
||||||
|
} else if (messageType == "Reidentify") {
|
||||||
|
;
|
||||||
|
} else {
|
||||||
|
if (!session->IgnoreInvalidMessages()) {
|
||||||
|
ret.closeCode = WebSocketServer::WebSocketCloseCode::UnknownMessageType;
|
||||||
|
ret.closeReason = std::string("Unknown message type: %s") + messageType;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace WebSocketProtocol {
|
namespace WebSocketProtocol {
|
||||||
struct ProcessResult {
|
struct ProcessResult {
|
||||||
WebSocketServer::WebSocketCloseCode closeCode;
|
WebSocketServer::WebSocketCloseCode closeCode = WebSocketServer::WebSocketCloseCode::DontClose;
|
||||||
std::string closeReason;
|
std::string closeReason;
|
||||||
json result;
|
json result;
|
||||||
};
|
};
|
||||||
|
@ -81,9 +81,9 @@ void WebSocketServer::Start()
|
|||||||
_serverPort = conf->ServerPort;
|
_serverPort = conf->ServerPort;
|
||||||
_serverPassword = conf->ServerPassword;
|
_serverPassword = conf->ServerPassword;
|
||||||
_debugEnabled = conf->DebugEnabled;
|
_debugEnabled = conf->DebugEnabled;
|
||||||
_authenticationRequired = conf->AuthRequired;
|
AuthenticationRequired = conf->AuthRequired;
|
||||||
_authenticationSalt = Utils::Crypto::GenerateSalt();
|
AuthenticationSalt = Utils::Crypto::GenerateSalt();
|
||||||
_authenticationSecret = Utils::Crypto::GenerateSecret(conf->ServerPassword.toStdString(), _authenticationSalt);
|
AuthenticationSecret = Utils::Crypto::GenerateSecret(conf->ServerPassword.toStdString(), AuthenticationSalt);
|
||||||
|
|
||||||
// Set log levels if debug is enabled
|
// Set log levels if debug is enabled
|
||||||
if (_debugEnabled) {
|
if (_debugEnabled) {
|
||||||
@ -191,7 +191,7 @@ std::vector<WebSocketServer::WebSocketSessionState> WebSocketServer::GetWebSocke
|
|||||||
QString WebSocketServer::GetConnectString()
|
QString WebSocketServer::GetConnectString()
|
||||||
{
|
{
|
||||||
QString ret;
|
QString ret;
|
||||||
if (_authenticationRequired)
|
if (AuthenticationRequired)
|
||||||
ret = QString("obswebsocket|%1:%2|%3").arg(QString::fromStdString(Utils::Platform::GetLocalAddress())).arg(_serverPort).arg(_serverPassword);
|
ret = QString("obswebsocket|%1:%2|%3").arg(QString::fromStdString(Utils::Platform::GetLocalAddress())).arg(_serverPort).arg(_serverPassword);
|
||||||
else
|
else
|
||||||
ret = QString("obswebsocket|%1:%2").arg(QString::fromStdString(Utils::Platform::GetLocalAddress())).arg(_serverPort);
|
ret = QString("obswebsocket|%1:%2").arg(QString::fromStdString(Utils::Platform::GetLocalAddress())).arg(_serverPort);
|
||||||
@ -275,12 +275,12 @@ void WebSocketServer::onOpen(websocketpp::connection_hdl hdl)
|
|||||||
helloMessage["obsWebSocketVersion"] = OBS_WEBSOCKET_VERSION;
|
helloMessage["obsWebSocketVersion"] = OBS_WEBSOCKET_VERSION;
|
||||||
helloMessage["rpcVersion"] = OBS_WEBSOCKET_RPC_VERSION;
|
helloMessage["rpcVersion"] = OBS_WEBSOCKET_RPC_VERSION;
|
||||||
// todo: Add request and event lists
|
// todo: Add request and event lists
|
||||||
if (_authenticationRequired) {
|
if (AuthenticationRequired) {
|
||||||
std::string sessionChallenge = Utils::Crypto::GenerateSalt();
|
std::string sessionChallenge = Utils::Crypto::GenerateSalt();
|
||||||
session.SetChallenge(sessionChallenge);
|
session.SetChallenge(sessionChallenge);
|
||||||
helloMessage["authentication"] = {};
|
helloMessage["authentication"] = {};
|
||||||
helloMessage["authentication"]["challenge"] = sessionChallenge;
|
helloMessage["authentication"]["challenge"] = sessionChallenge;
|
||||||
helloMessage["authentication"]["salt"] = _authenticationSalt;
|
helloMessage["authentication"]["salt"] = AuthenticationSalt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send object to client
|
// Send object to client
|
||||||
@ -344,7 +344,7 @@ void WebSocketServer::onMessage(websocketpp::connection_hdl hdl, websocketpp::se
|
|||||||
if (sessionEncoding == WebSocketEncoding::Json) {
|
if (sessionEncoding == WebSocketEncoding::Json) {
|
||||||
if (opcode != websocketpp::frame::opcode::text) {
|
if (opcode != websocketpp::frame::opcode::text) {
|
||||||
if (!session.IgnoreInvalidMessages())
|
if (!session.IgnoreInvalidMessages())
|
||||||
_server.close(hdl, WebSocketCloseCode::MessageDecodeError, "The session encoding is set to Json, but the client sent a binary message.", errorCode);
|
_server.close(hdl, WebSocketCloseCode::MessageDecodeError, "Your session encoding is set to Json, but a binary message was received.", errorCode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,7 +358,7 @@ void WebSocketServer::onMessage(websocketpp::connection_hdl hdl, websocketpp::se
|
|||||||
} else if (sessionEncoding == WebSocketEncoding::MsgPack) {
|
} else if (sessionEncoding == WebSocketEncoding::MsgPack) {
|
||||||
if (opcode != websocketpp::frame::opcode::binary) {
|
if (opcode != websocketpp::frame::opcode::binary) {
|
||||||
if (!session.IgnoreInvalidMessages())
|
if (!session.IgnoreInvalidMessages())
|
||||||
_server.close(hdl, WebSocketCloseCode::MessageDecodeError, "The session encoding is set to MsgPack, but the client sent a text message.", errorCode);
|
_server.close(hdl, WebSocketCloseCode::MessageDecodeError, "Your session encoding is set to MsgPack, but a text message was received.", errorCode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,13 +376,13 @@ void WebSocketServer::onMessage(websocketpp::connection_hdl hdl, websocketpp::se
|
|||||||
|
|
||||||
WebSocketProtocol::ProcessResult ret = WebSocketProtocol::ProcessMessage(hdl, &session, incomingMessage);
|
WebSocketProtocol::ProcessResult ret = WebSocketProtocol::ProcessMessage(hdl, &session, incomingMessage);
|
||||||
|
|
||||||
if (ret.closeCode) {
|
if (ret.closeCode != WebSocketCloseCode::DontClose) {
|
||||||
websocketpp::lib::error_code errorCode;
|
websocketpp::lib::error_code errorCode;
|
||||||
_server.close(hdl, ret.closeCode, ret.closeReason, errorCode);
|
_server.close(hdl, ret.closeCode, ret.closeReason, errorCode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret.result) {
|
if (!ret.result.is_null()) {
|
||||||
websocketpp::lib::error_code errorCode;
|
websocketpp::lib::error_code errorCode;
|
||||||
if (sessionEncoding == WebSocketEncoding::Json) {
|
if (sessionEncoding == WebSocketEncoding::Json) {
|
||||||
std::string helloMessageJson = ret.result.dump();
|
std::string helloMessageJson = ret.result.dump();
|
||||||
|
@ -19,10 +19,13 @@ class WebSocketServer : QObject
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
enum WebSocketCloseCode: uint16_t {
|
enum WebSocketCloseCode: uint16_t {
|
||||||
|
// Internal only
|
||||||
|
DontClose = 0,
|
||||||
|
// Reserved
|
||||||
UnknownReason = 4000,
|
UnknownReason = 4000,
|
||||||
// The server was unable to decode the incoming websocket message
|
// The server was unable to decode the incoming websocket message
|
||||||
MessageDecodeError = 4001,
|
MessageDecodeError = 4001,
|
||||||
// The specified `messageType` was invalid
|
// The specified `messageType` was invalid or missing
|
||||||
UnknownMessageType = 4002,
|
UnknownMessageType = 4002,
|
||||||
// The client sent a websocket message without first sending `Identify` message
|
// The client sent a websocket message without first sending `Identify` message
|
||||||
NotIdentified = 4003,
|
NotIdentified = 4003,
|
||||||
@ -74,6 +77,10 @@ class WebSocketServer : QObject
|
|||||||
|
|
||||||
QString GetConnectString();
|
QString GetConnectString();
|
||||||
|
|
||||||
|
bool AuthenticationRequired;
|
||||||
|
std::string AuthenticationSecret;
|
||||||
|
std::string AuthenticationSalt;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void BroadcastEvent(uint64_t requiredIntent, std::string eventType, json eventData = nullptr);
|
void BroadcastEvent(uint64_t requiredIntent, std::string eventType, json eventData = nullptr);
|
||||||
|
|
||||||
@ -97,7 +104,4 @@ class WebSocketServer : QObject
|
|||||||
uint16_t _serverPort;
|
uint16_t _serverPort;
|
||||||
QString _serverPassword;
|
QString _serverPassword;
|
||||||
bool _debugEnabled;
|
bool _debugEnabled;
|
||||||
bool _authenticationRequired;
|
|
||||||
std::string _authenticationSecret;
|
|
||||||
std::string _authenticationSalt;
|
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user