WebSocketProtocol: Add Identify logic (not tested well)

This commit is contained in:
tt2468 2021-04-29 20:37:28 -07:00
parent f57d03e4bb
commit 09bfea0628
4 changed files with 120 additions and 15 deletions

View File

@ -1 +1,102 @@
#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;
}

View File

@ -9,7 +9,7 @@
namespace WebSocketProtocol {
struct ProcessResult {
WebSocketServer::WebSocketCloseCode closeCode;
WebSocketServer::WebSocketCloseCode closeCode = WebSocketServer::WebSocketCloseCode::DontClose;
std::string closeReason;
json result;
};

View File

@ -81,9 +81,9 @@ void WebSocketServer::Start()
_serverPort = conf->ServerPort;
_serverPassword = conf->ServerPassword;
_debugEnabled = conf->DebugEnabled;
_authenticationRequired = conf->AuthRequired;
_authenticationSalt = Utils::Crypto::GenerateSalt();
_authenticationSecret = Utils::Crypto::GenerateSecret(conf->ServerPassword.toStdString(), _authenticationSalt);
AuthenticationRequired = conf->AuthRequired;
AuthenticationSalt = Utils::Crypto::GenerateSalt();
AuthenticationSecret = Utils::Crypto::GenerateSecret(conf->ServerPassword.toStdString(), AuthenticationSalt);
// Set log levels if debug is enabled
if (_debugEnabled) {
@ -191,7 +191,7 @@ std::vector<WebSocketServer::WebSocketSessionState> WebSocketServer::GetWebSocke
QString WebSocketServer::GetConnectString()
{
QString ret;
if (_authenticationRequired)
if (AuthenticationRequired)
ret = QString("obswebsocket|%1:%2|%3").arg(QString::fromStdString(Utils::Platform::GetLocalAddress())).arg(_serverPort).arg(_serverPassword);
else
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["rpcVersion"] = OBS_WEBSOCKET_RPC_VERSION;
// todo: Add request and event lists
if (_authenticationRequired) {
if (AuthenticationRequired) {
std::string sessionChallenge = Utils::Crypto::GenerateSalt();
session.SetChallenge(sessionChallenge);
helloMessage["authentication"] = {};
helloMessage["authentication"]["challenge"] = sessionChallenge;
helloMessage["authentication"]["salt"] = _authenticationSalt;
helloMessage["authentication"]["salt"] = AuthenticationSalt;
}
// Send object to client
@ -344,7 +344,7 @@ void WebSocketServer::onMessage(websocketpp::connection_hdl hdl, websocketpp::se
if (sessionEncoding == WebSocketEncoding::Json) {
if (opcode != websocketpp::frame::opcode::text) {
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;
}
@ -358,7 +358,7 @@ void WebSocketServer::onMessage(websocketpp::connection_hdl hdl, websocketpp::se
} else if (sessionEncoding == WebSocketEncoding::MsgPack) {
if (opcode != websocketpp::frame::opcode::binary) {
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;
}
@ -376,13 +376,13 @@ void WebSocketServer::onMessage(websocketpp::connection_hdl hdl, websocketpp::se
WebSocketProtocol::ProcessResult ret = WebSocketProtocol::ProcessMessage(hdl, &session, incomingMessage);
if (ret.closeCode) {
if (ret.closeCode != WebSocketCloseCode::DontClose) {
websocketpp::lib::error_code errorCode;
_server.close(hdl, ret.closeCode, ret.closeReason, errorCode);
return;
}
if (ret.result) {
if (!ret.result.is_null()) {
websocketpp::lib::error_code errorCode;
if (sessionEncoding == WebSocketEncoding::Json) {
std::string helloMessageJson = ret.result.dump();

View File

@ -19,10 +19,13 @@ class WebSocketServer : QObject
public:
enum WebSocketCloseCode: uint16_t {
// Internal only
DontClose = 0,
// Reserved
UnknownReason = 4000,
// The server was unable to decode the incoming websocket message
MessageDecodeError = 4001,
// The specified `messageType` was invalid
// The specified `messageType` was invalid or missing
UnknownMessageType = 4002,
// The client sent a websocket message without first sending `Identify` message
NotIdentified = 4003,
@ -74,6 +77,10 @@ class WebSocketServer : QObject
QString GetConnectString();
bool AuthenticationRequired;
std::string AuthenticationSecret;
std::string AuthenticationSalt;
public Q_SLOTS:
void BroadcastEvent(uint64_t requiredIntent, std::string eventType, json eventData = nullptr);
@ -97,7 +104,4 @@ class WebSocketServer : QObject
uint16_t _serverPort;
QString _serverPassword;
bool _debugEnabled;
bool _authenticationRequired;
std::string _authenticationSecret;
std::string _authenticationSalt;
};