Updated locale variables names + WIP Dynamic Server Settings

This commit is contained in:
Palakis 2017-02-23 21:01:24 +01:00
parent f8b1cae0c9
commit 3d68b7c9e5
12 changed files with 224 additions and 93 deletions

View File

@ -19,22 +19,41 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <mbedtls/base64.h>
#include <mbedtls/sha256.h>
#include <obs-frontend-api.h>
#include <util/config-file.h>
#include "Config.h"
#define CONFIG_SECTION_NAME "obs-websocket"
#define CONFIG_PARAM_SECRET "auth_hash"
#define CONFIG_PARAM_SALT "auth_salt"
#define CONFIG_PARAM_AUTHREQUIRED "auth_required"
#define SECTION_NAME "obs-websocket"
#define PARAM_ENABLE "server_enabled"
#define PARAM_PORT "server_port"
#define PARAM_SECRET "auth_hash"
#define PARAM_SALT "auth_salt"
#define PARAM_AUTHREQUIRED "auth_required"
Config *Config::_instance = new Config();
Config::Config() {
Config::Config()
{
// Default settings
ServerEnabled = true;
ServerPort = 4444;
AuthRequired = false;
Secret = "";
Salt = "";
SettingsLoaded = false;
// OBS Config defaults
config_t* obs_config = obs_frontend_get_global_config();
if (obs_config)
{
config_set_default_bool(obs_config, SECTION_NAME, PARAM_ENABLE, ServerEnabled);
config_set_default_uint(obs_config, SECTION_NAME, PARAM_PORT, ServerPort);
config_set_default_bool(obs_config, SECTION_NAME, PARAM_AUTHREQUIRED, AuthRequired);
config_set_default_string(obs_config, SECTION_NAME, PARAM_SECRET, Secret);
config_set_default_string(obs_config, SECTION_NAME, PARAM_SALT, Salt);
}
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&rng);
mbedtls_ctr_drbg_seed(&rng, mbedtls_entropy_func, &entropy, nullptr, 0);
@ -43,12 +62,40 @@ Config::Config() {
SessionChallenge = GenerateSalt();
}
Config::~Config() {
Config::~Config()
{
mbedtls_ctr_drbg_free(&rng);
mbedtls_entropy_free(&entropy);
}
const char* Config::GenerateSalt() {
void Config::Load()
{
config_t* obs_config = obs_frontend_get_global_config();
ServerEnabled = config_get_bool(obs_config, SECTION_NAME, PARAM_ENABLE);
ServerPort = config_get_uint(obs_config, SECTION_NAME, PARAM_PORT);
AuthRequired = config_get_bool(obs_config, SECTION_NAME, PARAM_AUTHREQUIRED);
Secret = config_get_string(obs_config, SECTION_NAME, PARAM_SECRET);
Salt = config_get_string(obs_config, SECTION_NAME, PARAM_SALT);
}
void Config::Save()
{
config_t* obs_config = obs_frontend_get_global_config();
config_set_bool(obs_config, SECTION_NAME, PARAM_ENABLE, ServerEnabled);
config_set_uint(obs_config, SECTION_NAME, PARAM_PORT, ServerPort);
config_set_bool(obs_config, SECTION_NAME, PARAM_AUTHREQUIRED, AuthRequired);
config_set_string(obs_config, SECTION_NAME, PARAM_SECRET, Secret);
config_set_string(obs_config, SECTION_NAME, PARAM_SALT, Salt);
config_save(obs_config);
}
const char* Config::GenerateSalt()
{
// Generate 32 random chars
unsigned char *random_chars = (unsigned char *)bzalloc(32);
mbedtls_ctr_drbg_random(&rng, random_chars, 32);
@ -63,7 +110,8 @@ const char* Config::GenerateSalt() {
return (char *)salt;
}
const char* Config::GenerateSecret(const char *password, const char *salt) {
const char* Config::GenerateSecret(const char *password, const char *salt)
{
size_t passwordLength = strlen(password);
size_t saltLength = strlen(salt);
@ -88,7 +136,8 @@ const char* Config::GenerateSecret(const char *password, const char *salt) {
return (char*)challenge;
}
void Config::SetPassword(const char *password) {
void Config::SetPassword(const char *password)
{
const char *new_salt = GenerateSalt();
const char *new_challenge = GenerateSecret(password, new_salt);
@ -96,7 +145,8 @@ void Config::SetPassword(const char *password) {
this->Secret = new_challenge;
}
bool Config::CheckAuth(const char *response) {
bool Config::CheckAuth(const char *response)
{
size_t secretLength = strlen(this->Secret);
size_t sessChallengeLength = strlen(this->SessionChallenge);
@ -125,29 +175,7 @@ bool Config::CheckAuth(const char *response) {
}
}
void Config::OBSSaveCallback(obs_data_t *save_data, bool saving, void *private_data) {
Config *conf = static_cast<Config *>(private_data);
if (saving) {
obs_data_t *settings = obs_data_create();
obs_data_set_bool(settings, CONFIG_PARAM_AUTHREQUIRED, conf->AuthRequired);
obs_data_set_string(settings, CONFIG_PARAM_SECRET, conf->Secret);
obs_data_set_string(settings, CONFIG_PARAM_SALT, conf->Salt);
obs_data_set_obj(save_data, CONFIG_SECTION_NAME, settings);
}
else {
obs_data_t *settings = obs_data_get_obj(save_data, CONFIG_SECTION_NAME);
if (settings) {
conf->AuthRequired = obs_data_get_bool(settings, CONFIG_PARAM_AUTHREQUIRED);
conf->Secret = obs_data_get_string(settings, CONFIG_PARAM_SECRET);
conf->Salt = obs_data_get_string(settings, CONFIG_PARAM_SALT);
conf->SettingsLoaded = true;
}
}
}
Config* Config::Current() {
Config* Config::Current()
{
return _instance;
}

View File

@ -23,15 +23,21 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
class Config {
class Config
{
public:
Config();
~Config();
void Load();
void Save();
void SetPassword(const char *password);
bool CheckAuth(const char *userChallenge);
const char* GenerateSalt();
static const char* GenerateSecret(const char *password, const char *salt);
static void OBSSaveCallback(obs_data_t *save_data, bool saving, void *);
bool ServerEnabled;
uint64_t ServerPort;
bool AuthRequired;
const char *Secret;

View File

@ -19,8 +19,8 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include "WSEvents.h"
WSEvents::WSEvents(WSServer *server) {
_srv = server;
WSEvents::WSEvents(WSServer *srv) {
_srv = srv;
obs_frontend_add_event_callback(WSEvents::FrontendEventHandler, this);
QTimer *statusTimer = new QTimer();
@ -39,6 +39,9 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private
{
WSEvents *owner = static_cast<WSEvents *>(private_data);
if (!owner->_srv)
return;
// TODO : implement SourceChanged, SourceOrderChanged and RepopulateSources
if (event == OBS_FRONTEND_EVENT_SCENE_CHANGED) {

View File

@ -31,7 +31,7 @@ class WSEvents : public QObject
Q_OBJECT
public:
explicit WSEvents(WSServer *server);
explicit WSEvents(WSServer *srv);
~WSEvents();
static void FrontendEventHandler(enum obs_frontend_event event, void *private_data);

View File

@ -29,7 +29,9 @@ with this program. If not, see <https://www.gnu.org/licenses/>
QT_USE_NAMESPACE
WSServer::WSServer(quint16 port, QObject *parent) :
WSServer* WSServer::Instance = new WSServer();
WSServer::WSServer(QObject *parent) :
QObject(parent),
_wsServer(Q_NULLPTR),
_clients(),
@ -44,6 +46,22 @@ WSServer::WSServer(quint16 port, QObject *parent) :
_wsServer->moveToThread(_serverThread);
_serverThread->start();
}
WSServer::~WSServer()
{
Stop();
delete _serverThread;
}
void WSServer::Start(quint16 port)
{
if (port == _wsServer->serverPort())
return;
if(_wsServer->isListening())
Stop();
bool serverStarted = _wsServer->listen(QHostAddress::Any, port);
if (serverStarted)
@ -52,15 +70,18 @@ WSServer::WSServer(quint16 port, QObject *parent) :
}
}
WSServer::~WSServer()
void WSServer::Stop()
{
_wsServer->close();
_clMutex.lock();
Q_FOREACH(QWebSocket *pClient, _clients)
{
pClient->close();
}
qDeleteAll(_clients.begin(), _clients.end());
_clMutex.unlock();
delete _serverThread;
_wsServer->close();
}
void WSServer::broadcast(QString message)

View File

@ -34,9 +34,12 @@ class WSServer : public QObject
Q_OBJECT
public:
explicit WSServer(quint16 port, QObject *parent = Q_NULLPTR);
explicit WSServer(QObject *parent = Q_NULLPTR);
virtual ~WSServer();
void Start(quint16 port);
void Stop();
void broadcast(QString message);
static WSServer* Instance;
private Q_SLOTS:
void onNewConnection();

View File

@ -1,4 +1,4 @@
Menu.SettingsItem="Websocket-Server Einstellungen"
Settings.DialogTitle="Websocket-Server Einstellungen"
Settings.AuthRequired="Authentifizierung erforderlich"
Settings.Password="Passwort"
OBSWebsocket.Menu.SettingsItem="Websocket-Server Einstellungen"
OBSWebsocket.Settings.DialogTitle="Websocket-Server Einstellungen"
OBSWebsocket.Settings.AuthRequired="Authentifizierung erforderlich"
OBSWebsocket.Settings.Password="Passwort"

View File

@ -1,4 +1,6 @@
Menu.SettingsItem="Websocket server settings"
Settings.DialogTitle="obs-websocket"
Settings.AuthRequired="Enable authentication"
Settings.Password="Password"
OBSWebsocket.Menu.SettingsItem="Websocket server settings"
OBSWebsocket.Settings.DialogTitle="obs-websocket"
OBSWebsocket.Settings.ServerEnable="Enable Websocket server"
OBSWebsocket.Settings.ServerPort="Server Port"
OBSWebsocket.Settings.AuthRequired="Enable authentication"
OBSWebsocket.Settings.Password="Password"

View File

@ -1,4 +1,6 @@
Menu.SettingsItem="Paramètres du serveur Websocket"
Settings.DialogTitle="obs-websocket"
Settings.AuthRequired="Activer l'authentification"
Settings.Password="Mot de passe"
OBSWebsocket.Menu.SettingsItem="Paramètres du serveur Websocket"
OBSWebsocket.Settings.DialogTitle="obs-websocket"
OBSWebsocket.Settings.ServerEnable="Activer le serveur Websockets"
OBSWebsocket.Settings.ServerPort="Port du serveur"
OBSWebsocket.Settings.AuthRequired="Activer l'authentification"
OBSWebsocket.Settings.Password="Mot de passe"

View File

@ -17,9 +17,12 @@ with this program. If not, see <https://www.gnu.org/licenses/>
*/
#include <obs-frontend-api.h>
#include "obs-websocket.h"
#include "Config.h"
#include "WSServer.h"
#include "settings-dialog.h"
#include "ui_settings-dialog.h"
#include "Config.h"
#define CHANGE_ME "changeme"
@ -35,12 +38,19 @@ SettingsDialog::SettingsDialog(QWidget *parent) :
AuthCheckboxChanged();
}
void SettingsDialog::showEvent(QShowEvent *event) {
ui->authRequired->setChecked(Config::Current()->AuthRequired);
void SettingsDialog::showEvent(QShowEvent *event)
{
Config* conf = Config::Current();
ui->serverEnabled->setChecked(conf->ServerEnabled);
ui->serverPort->setValue(conf->ServerPort);
ui->authRequired->setChecked(conf->AuthRequired);
ui->password->setText(CHANGE_ME);
}
void SettingsDialog::ToggleShowHide() {
void SettingsDialog::ToggleShowHide()
{
if (!isVisible()) {
setVisible(true);
}
@ -49,7 +59,8 @@ void SettingsDialog::ToggleShowHide() {
}
}
void SettingsDialog::AuthCheckboxChanged() {
void SettingsDialog::AuthCheckboxChanged()
{
if (ui->authRequired->isChecked()) {
ui->password->setEnabled(true);
}
@ -58,28 +69,48 @@ void SettingsDialog::AuthCheckboxChanged() {
}
}
void SettingsDialog::FormAccepted() {
if (ui->authRequired->isChecked()) {
if (ui->password->text() != CHANGE_ME) {
void SettingsDialog::FormAccepted()
{
Config* conf = Config::Current();
conf->ServerEnabled = ui->serverEnabled->isChecked();
conf->ServerPort = ui->serverPort->value();
if (ui->authRequired->isChecked())
{
if (ui->password->text() != CHANGE_ME)
{
QByteArray pwd = ui->password->text().toLocal8Bit();
const char *new_password = pwd;
blog(LOG_INFO, "new password : %s", new_password);
Config::Current()->SetPassword(new_password);
conf->SetPassword(new_password);
}
if (strcmp(Config::Current()->Secret, "") != 0) {
Config::Current()->AuthRequired = true;
if (strcmp(Config::Current()->Secret, "") != 0)
{
conf->AuthRequired = true;
}
else {
Config::Current()->AuthRequired = false;
else
{
conf->AuthRequired = false;
}
}
else {
Config::Current()->AuthRequired = false;
else
{
conf->AuthRequired = false;
}
conf->Save();
if (conf->ServerEnabled)
{
WSServer::Instance->Start(conf->ServerPort);
}
else
{
WSServer::Instance->Stop();
}
obs_frontend_save();
}
SettingsDialog::~SettingsDialog()

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>354</width>
<height>110</height>
<width>407</width>
<height>155</height>
</rect>
</property>
<property name="sizePolicy">
@ -17,7 +17,7 @@
</sizepolicy>
</property>
<property name="windowTitle">
<string>Settings.DialogTitle</string>
<string>OBSWebsocket.Settings.DialogTitle</string>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
@ -28,24 +28,54 @@
</property>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="3" column="0">
<widget class="QLabel" name="lbl_password">
<item row="3" column="1">
<widget class="QCheckBox" name="authRequired">
<property name="text">
<string>Settings.Password</string>
<string>OBSWebsocket.Settings.AuthRequired</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="0">
<widget class="QLabel" name="lbl_password">
<property name="text">
<string>OBSWebsocket.Settings.Password</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="password">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="authRequired">
<item row="1" column="1">
<widget class="QCheckBox" name="serverEnabled">
<property name="text">
<string>Settings.AuthRequired</string>
<string>OBSWebsocket.Settings.ServerEnable</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_serverPort">
<property name="text">
<string>OBSWebsocket.Settings.ServerPort</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="serverPort">
<property name="minimum">
<number>1024</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>4444</number>
</property>
</widget>
</item>

View File

@ -21,8 +21,8 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <QAction>
#include "obs-websocket.h"
#include "WSEvents.h"
#include "WSServer.h"
#include "WSEvents.h"
#include "Config.h"
#include "forms/settings-dialog.h"
@ -30,19 +30,21 @@ OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("obs-websocket", "en-US")
WSEvents *eventHandler;
WSServer *server;
SettingsDialog *settings_dialog;
bool obs_module_load(void)
{
blog(LOG_INFO, "[obs-websockets] you can haz websockets (version %s)", OBS_WEBSOCKET_VERSION);
server = new WSServer(4444);
eventHandler = new WSEvents(server);
obs_frontend_add_save_callback(Config::OBSSaveCallback, Config::Current());
// Core setup
Config* config = Config::Current();
config->Load();
QAction *menu_action = (QAction*)obs_frontend_add_tools_menu_qaction(obs_module_text("Menu.SettingsItem"));
if (config->ServerEnabled)
WSServer::Instance->Start(config->ServerPort);
eventHandler = new WSEvents(WSServer::Instance);
// UI setup
QAction *menu_action = (QAction*)obs_frontend_add_tools_menu_qaction(obs_module_text("OBSWebsocket.Menu.SettingsItem"));
obs_frontend_push_ui_translation(obs_module_get_string);
settings_dialog = new SettingsDialog();
@ -53,6 +55,9 @@ bool obs_module_load(void)
};
menu_action->connect(menu_action, &QAction::triggered, menu_cb);
// Loading finished
blog(LOG_INFO, "[obs-websockets] you can haz websockets (version %s)", OBS_WEBSOCKET_VERSION);
return true;
}