A lot of updates
This commit is contained in:
parent
44fe958f31
commit
0d3d3cfc53
@ -1,249 +0,0 @@
|
||||
# Musik bot websocket protocol
|
||||
## General structure
|
||||
Transmitted data is in json format
|
||||
The json format has the structure as following:
|
||||
```
|
||||
{
|
||||
"type": <PacketType>,
|
||||
"data": [
|
||||
{
|
||||
<key>: value
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
Example:
|
||||
```
|
||||
{
|
||||
"type": "showMessage",
|
||||
"data": [
|
||||
{
|
||||
"message": "A simple info modal",
|
||||
"type": "info"
|
||||
},
|
||||
{
|
||||
"message": "A simple error modal",
|
||||
"type": "error"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
## TODO list
|
||||
* Music bot queue
|
||||
* Music bot ts3 access rights (allow other clients to use this music bot etc.)
|
||||
|
||||
## Packet types
|
||||
### General types
|
||||
#### Server `showMessage`:
|
||||
This packet should show up a message modal.
|
||||
* **[~]**
|
||||
* `message`: <msg>
|
||||
* `type`: {info|error}
|
||||
|
||||
|
||||
#### Server `reqError`:
|
||||
The server sends this if you applay a invalid request
|
||||
* **[1]**
|
||||
* `message`: <msg>
|
||||
* `requestId`: <reqestId>
|
||||
|
||||
|
||||
#### Server `disconnect`
|
||||
I send this packet before i close the comunication
|
||||
* **[1]**
|
||||
* `message`
|
||||
|
||||
___
|
||||
### Login packets
|
||||
#### Client `login`
|
||||
Try login
|
||||
* **[1]**
|
||||
* `username`
|
||||
* `password`
|
||||
* `requestId`
|
||||
|
||||
|
||||
#### Server `notifylogin`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `succeeded`: {0|1}
|
||||
* `uid` own uid. only set if login failed
|
||||
* `message` only set if login failed
|
||||
|
||||
#### Client `logout`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
|
||||
#### Server `notifylogout`
|
||||
Could be send at any time (force logout)
|
||||
* **[1]**
|
||||
* `requestId` (empty of not requested)
|
||||
* `succeeded`: {0|1}
|
||||
|
||||
___
|
||||
### Server Management
|
||||
#### Client `serverlist`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
|
||||
#### Server `notifyserverlist`
|
||||
Sends when requested or list updated
|
||||
(Lists online avariable server for the client view)
|
||||
* **[~]**
|
||||
* [1] `requestId` (empty of not requested)
|
||||
* `name`
|
||||
* `uid`
|
||||
* `serverId`
|
||||
* `status`: {online|offline}
|
||||
* `clientOnline`
|
||||
* `maxClients`
|
||||
|
||||
#### Server `notifyserverupdate`
|
||||
Sends when a server changes display properties
|
||||
* **[1]**
|
||||
* `serverId`
|
||||
* `key`: {name|onlineClients|maxClients}
|
||||
* `value`
|
||||
|
||||
___
|
||||
### Channel Management
|
||||
#### Client `channellist`
|
||||
Request a channel list
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
|
||||
#### Server `notifychannellist`
|
||||
The channel response is ordered:
|
||||
This packet would also be send if the channel tree gets updated
|
||||
```
|
||||
root
|
||||
- sub 1
|
||||
- sub sub 1
|
||||
- sub sub 2
|
||||
- sub 2
|
||||
root 2
|
||||
...
|
||||
```
|
||||
* **[~]**
|
||||
* [1] `requestId` (empty of not requested)
|
||||
* [1] `serverId`
|
||||
* `name`
|
||||
* `channelId`
|
||||
* `channelParent`
|
||||
* `channelOrder`
|
||||
|
||||
___
|
||||
### Music bot management
|
||||
#### Client `musicbotlist`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
|
||||
#### Server `notifymusikmusicbotlist`
|
||||
* **[~]**
|
||||
* [1] `requestId` (empty of not requested)
|
||||
* [1] `serverId`
|
||||
* `id`
|
||||
* `connected`: {1|0}
|
||||
* `name`
|
||||
* `channelId`
|
||||
* `ownerUid` (its your own if its matching with our own id)
|
||||
* `ownerCldbid`
|
||||
|
||||
#### Client `musicbotcreate`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `name`
|
||||
* `channelId`
|
||||
|
||||
#### Server `notifymusikbotcreated`
|
||||
* **[1]**
|
||||
* `requestId` (empty of not requested)
|
||||
* `serverId`
|
||||
* `id`
|
||||
* `connected`: {1|0}
|
||||
* `name`
|
||||
* `channelId`
|
||||
* `ownerUid` (its your own if its matching with our own id)
|
||||
* `ownerCldbid`
|
||||
|
||||
#### Client `musicbotdelete`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `name`
|
||||
* `channelId`
|
||||
|
||||
#### Server `notifymusikbotdelete`
|
||||
* **[1]**
|
||||
* `requestId` (empty of not requested)
|
||||
* `serverId`
|
||||
* `id`
|
||||
|
||||
#### Client `musicbotinfo`
|
||||
Request music bot info
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `id`
|
||||
|
||||
#### Server `notifymusicbotinfo`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `id`
|
||||
* `name`
|
||||
* `connected`
|
||||
* `phoeticName`
|
||||
* `channelId`
|
||||
* `playing`
|
||||
* `playingInfo`: <string|Current playing title etc. May need to be inproved> Empty if noting selected
|
||||
* `description`
|
||||
* `textCurrentSong`
|
||||
|
||||
#### Client `musicbotedit`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `id`
|
||||
* `key`
|
||||
* `value`
|
||||
|
||||
#### Server `notifymusicbotedit`
|
||||
* **[~]**
|
||||
* [1] `requestId` (empty of not requested)
|
||||
* [1] `serverId`
|
||||
* `id`
|
||||
* `key`: {connected|name|channelId|description|playing|playingInfo}
|
||||
|
||||
#### Client `musicbotplay`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `id`
|
||||
* `type`: {yt|file}
|
||||
* `value`
|
||||
|
||||
#### Server `notifymusicbotplay`
|
||||
Send only as answer for `musicbotplay`
|
||||
You would recive the play state update via `notifymusicbotedit`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `succeeded`
|
||||
*
|
||||
#### Client `musicbotstop`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `id`
|
||||
* `paused`: {1|0}
|
||||
|
||||
#### Server `notifymusicbotstop`
|
||||
Send only as answer for `musicbotstop`
|
||||
You would recive the play state update via `notifymusicbotedit`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `succeeded`
|
@ -16,7 +16,7 @@ void log::log(const Level& lvl, const std::string& msg) {
|
||||
|
||||
void AbstractMusicPlayer::registerEventHandler(const std::string& key, const std::function<void(MusicEvent)>& function) {
|
||||
threads::MutexLock lock(this->eventLock);
|
||||
this->eventHandlers.push_back({key, function});
|
||||
this->eventHandlers.emplace_back(key, function);
|
||||
}
|
||||
|
||||
void AbstractMusicPlayer::unregisterEventHandler(const std::string& string) {
|
||||
@ -111,5 +111,11 @@ void manager::loadProviders(const std::string& path) {
|
||||
}
|
||||
|
||||
void manager::register_provider(const std::shared_ptr<music::manager::PlayerProvider> &provider) {
|
||||
threads::MutexLock l(staticLock);
|
||||
types.push_back(provider);
|
||||
}
|
||||
|
||||
void manager::finalizeProviders() {
|
||||
threads::MutexLock l(staticLock);
|
||||
types.clear();
|
||||
}
|
@ -40,31 +40,50 @@ add_executable(TeaLicenseServer ${LICENCE_SOURCE_FILES} ${PROTO_SRCS} ${PROTO_HD
|
||||
server/WebAPI.cpp
|
||||
server/StatisticManager.cpp
|
||||
server/UserManager.cpp
|
||||
MySQLLibSSLFix.c
|
||||
)
|
||||
|
||||
target_link_libraries(TeaLicenseServer
|
||||
TeaSpeak #Static
|
||||
${LIBRARY_PATH_DATA_PIPES}
|
||||
${LIBRARY_PATH_TERMINAL} #Static
|
||||
${LIBRARY_PATH_THREAD_POOL} #Static
|
||||
${PROJECT_SOURCE_DIR}/../../libraries/event/build/lib/libevent.a
|
||||
${PROJECT_SOURCE_DIR}/../../libraries/event/build/lib/libevent_pthreads.a
|
||||
pthread
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
TeaSpeak #Static
|
||||
TeaLicenseHelper #Static
|
||||
${LIBRARY_PATH_TERMINAL} #Static
|
||||
${LIBRARY_PATH_VARIBALES}
|
||||
${LIBRARY_PATH_YAML}
|
||||
pthread
|
||||
stdc++fs
|
||||
${LIBEVENT_PATH}/libevent.a
|
||||
${LIBEVENT_PATH}/libevent_pthreads.a
|
||||
${LIBRARY_PATH_OPUS}
|
||||
${LIBRARY_PATH_JSON}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
#We're forsed to use boringssl caused by the fact that boringssl is already within webrtc!
|
||||
|
||||
#Require a so
|
||||
sqlite3
|
||||
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
${LIBRARY_TOM_MATH}
|
||||
#${LIBWEBRTC_LIBRARIES} #ATTENTIAN! WebRTC does not work with crypto! (Already contains a crypto version)
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
${LIBRARY_TOM_MATH}
|
||||
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${TOM_LIBRARIES}
|
||||
${LIBRARY_PATH_JDBC}
|
||||
jsoncpp.a
|
||||
stdc++fs.a
|
||||
mysqlclient.a
|
||||
|
||||
${LIBRARY_PATH_ED255}
|
||||
|
||||
${LIBRARY_PATH_DATA_PIPES}
|
||||
${LIBRARY_PATH_NICE}
|
||||
${LIBRARY_PATH_GLIBC}
|
||||
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
dl
|
||||
z
|
||||
)
|
||||
include_directories(${LIBRARY_PATH}/boringssl/include/)
|
||||
|
||||
#The test license client
|
||||
add_executable(TeaLicenseClient
|
||||
|
@ -1,18 +1,16 @@
|
||||
#include <iostream>
|
||||
#include <shared/License.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <server/LicenseServer.h>
|
||||
#include <log/LogUtils.h>
|
||||
#include <CXXTerminal/Terminal.h>
|
||||
#include <sql/mysql/MySQL.h>
|
||||
#include <pipes/misc/http.h>
|
||||
#include "server/WebAPI.h"
|
||||
#include "server/StatisticManager.h"
|
||||
#include <event2/thread.h>
|
||||
#include "server/UserManager.h"
|
||||
|
||||
#include <misc/base64.h>
|
||||
#include <misc/digest.h>
|
||||
#include <fstream>
|
||||
#include <misc/hex.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
@ -43,6 +41,59 @@ shared_ptr<license::web::WebStatistics> web_server;
|
||||
shared_ptr<LicenseServer> license_server;
|
||||
shared_ptr<UserManager> user_manager;
|
||||
|
||||
inline std::shared_ptr<WebCertificate> load_web_certificate() {
|
||||
std::string certificate_file{"web_certificate.txt"}, certificate{};
|
||||
std::string key_file{"web_key.txt"}, key{};
|
||||
std::string error{};
|
||||
|
||||
auto context = ssl_manager->initializeContext("web_shared_cert", key_file, certificate_file, error);
|
||||
if(!context) {
|
||||
logError(0, "Failed to load web certificated: {}", error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<BIO> bio{nullptr};
|
||||
const uint8_t* mem_ptr{nullptr};
|
||||
size_t length{0};
|
||||
|
||||
{
|
||||
bio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
|
||||
if(PEM_write_bio_PrivateKey(&*bio, &*context->privateKey, nullptr, nullptr, 0, nullptr, nullptr) != 1) {
|
||||
logError(0, "Failed to export certificate");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(!BIO_mem_contents(&*bio, &mem_ptr, &length)) {
|
||||
logError(0, "Failed to receive memptr to private key");
|
||||
return nullptr;
|
||||
}
|
||||
key.resize(length);
|
||||
memcpy(key.data(), mem_ptr, length);
|
||||
}
|
||||
|
||||
{
|
||||
bio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
|
||||
if(PEM_write_bio_X509(&*bio, &*context->certificate) != 1) {
|
||||
logError(0, "Failed to export certificate");
|
||||
return nullptr;
|
||||
}
|
||||
if(!BIO_mem_contents(&*bio, &mem_ptr, &length)) {
|
||||
logError(0, "Failed to receive memptr to certificate");
|
||||
return nullptr;
|
||||
}
|
||||
certificate.resize(length);
|
||||
memcpy(certificate.data(), mem_ptr, length);
|
||||
}
|
||||
|
||||
auto response = std::make_shared<WebCertificate>();
|
||||
response->key = key;
|
||||
response->certificate = certificate;
|
||||
response->revision = digest::sha512(response->key + response->certificate);
|
||||
logMessage(0, "Web certificate revision: {}", hex::hex(response->revision));
|
||||
return response;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if(argc < 2) {
|
||||
cerr << "Invalid arguments! Need MySQL connection" << endl;
|
||||
@ -50,7 +101,6 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
evthread_use_pthreads();
|
||||
http::decode_url("xxx");
|
||||
srand(system_clock::now().time_since_epoch().count());
|
||||
terminal::install();
|
||||
if(!terminal::active()){ cerr << "could not setup terminal!" << endl; return -1; }
|
||||
@ -213,6 +263,7 @@ int main(int argc, char** argv) {
|
||||
listen_addr.sin_port = htons(27786);
|
||||
|
||||
license_server = make_shared<LicenseServer>(listen_addr, license_manager, statistic_manager, web_server, user_manager);
|
||||
license_server->web_certificate = load_web_certificate();
|
||||
license_server->startServer();
|
||||
}
|
||||
|
||||
|
107
license/MySQLLibSSLFix.c
Normal file
107
license/MySQLLibSSLFix.c
Normal file
@ -0,0 +1,107 @@
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cfb1(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_192_cfb1(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_256_cfb1(void){ return 0; }
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cfb8(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_192_cfb8(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_256_cfb8(void){ return 0; }
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cfb128(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_192_cfb128(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_256_cfb128(void){ return 0; }
|
||||
|
||||
int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
|
||||
return EVP_EncryptFinal_ex(ctx, out, out_len);
|
||||
}
|
||||
|
||||
int EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {
|
||||
return EVP_DecryptFinal_ex(ctx, out, out_len);
|
||||
}
|
||||
|
||||
int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DTLSv1_get_timeout DTLSv1_get_timeout
|
||||
#define DTLSv1_handle_timeout DTLSv1_handle_timeout
|
||||
#define SSL_CTX_add0_chain_cert SSL_CTX_add0_chain_cert
|
||||
#define SSL_CTX_add1_chain_cert SSL_CTX_add1_chain_cert
|
||||
#define SSL_CTX_add_extra_chain_cert SSL_CTX_add_extra_chain_cert
|
||||
#define SSL_CTX_clear_extra_chain_certs SSL_CTX_clear_extra_chain_certs
|
||||
#define SSL_CTX_clear_chain_certs SSL_CTX_clear_chain_certs
|
||||
#define SSL_CTX_clear_mode SSL_CTX_clear_mode
|
||||
#define SSL_CTX_clear_options SSL_CTX_clear_options
|
||||
#define SSL_CTX_get0_chain_certs SSL_CTX_get0_chain_certs
|
||||
#define SSL_CTX_get_extra_chain_certs SSL_CTX_get_extra_chain_certs
|
||||
#define SSL_CTX_get_max_cert_list SSL_CTX_get_max_cert_list
|
||||
#define SSL_CTX_get_mode SSL_CTX_get_mode
|
||||
#define SSL_CTX_get_options SSL_CTX_get_options
|
||||
#define SSL_CTX_get_read_ahead SSL_CTX_get_read_ahead
|
||||
#define SSL_CTX_get_session_cache_mode SSL_CTX_get_session_cache_mode
|
||||
#define SSL_CTX_get_tlsext_ticket_keys SSL_CTX_get_tlsext_ticket_keys
|
||||
#define SSL_CTX_need_tmp_RSA SSL_CTX_need_tmp_RSA
|
||||
#define SSL_CTX_sess_get_cache_size SSL_CTX_sess_get_cache_size
|
||||
#define SSL_CTX_sess_number SSL_CTX_sess_number
|
||||
#define SSL_CTX_sess_set_cache_size SSL_CTX_sess_set_cache_size
|
||||
#define SSL_CTX_set0_chain SSL_CTX_set0_chain
|
||||
#define SSL_CTX_set1_chain SSL_CTX_set1_chain
|
||||
#define SSL_CTX_set1_curves SSL_CTX_set1_curves
|
||||
#define SSL_CTX_set_max_cert_list SSL_CTX_set_max_cert_list
|
||||
#define SSL_CTX_set_max_send_fragment SSL_CTX_set_max_send_fragment
|
||||
#define SSL_CTX_set_mode SSL_CTX_set_mode
|
||||
#define SSL_CTX_set_msg_callback_arg SSL_CTX_set_msg_callback_arg
|
||||
#define SSL_CTX_set_options SSL_CTX_set_options
|
||||
#define SSL_CTX_set_read_ahead SSL_CTX_set_read_ahead
|
||||
#define SSL_CTX_set_session_cache_mode SSL_CTX_set_session_cache_mode
|
||||
#define SSL_CTX_set_tlsext_servername_arg SSL_CTX_set_tlsext_servername_arg
|
||||
#define SSL_CTX_set_tlsext_servername_callback \
|
||||
SSL_CTX_set_tlsext_servername_callback
|
||||
#define SSL_CTX_set_tlsext_ticket_key_cb SSL_CTX_set_tlsext_ticket_key_cb
|
||||
#define SSL_CTX_set_tlsext_ticket_keys SSL_CTX_set_tlsext_ticket_keys
|
||||
#define SSL_CTX_set_tmp_dh SSL_CTX_set_tmp_dh
|
||||
#define SSL_CTX_set_tmp_ecdh SSL_CTX_set_tmp_ecdh
|
||||
#define SSL_CTX_set_tmp_rsa SSL_CTX_set_tmp_rsa
|
||||
#define SSL_add0_chain_cert SSL_add0_chain_cert
|
||||
#define SSL_add1_chain_cert SSL_add1_chain_cert
|
||||
#define SSL_clear_chain_certs SSL_clear_chain_certs
|
||||
#define SSL_clear_mode SSL_clear_mode
|
||||
#define SSL_clear_options SSL_clear_options
|
||||
#define SSL_get0_certificate_types SSL_get0_certificate_types
|
||||
#define SSL_get0_chain_certs SSL_get0_chain_certs
|
||||
#define SSL_get_max_cert_list SSL_get_max_cert_list
|
||||
#define SSL_get_mode SSL_get_mode
|
||||
#define SSL_get_options SSL_get_options
|
||||
#define SSL_get_secure_renegotiation_support \
|
||||
SSL_get_secure_renegotiation_support
|
||||
#define SSL_need_tmp_RSA SSL_need_tmp_RSA
|
||||
#define SSL_num_renegotiations SSL_num_renegotiations
|
||||
#define SSL_session_reused SSL_session_reused
|
||||
#define SSL_set0_chain SSL_set0_chain
|
||||
#define SSL_set1_chain SSL_set1_chain
|
||||
#define SSL_set1_curves SSL_set1_curves
|
||||
#define SSL_set_max_cert_list SSL_set_max_cert_list
|
||||
#define SSL_set_max_send_fragment SSL_set_max_send_fragment
|
||||
#define SSL_set_mode SSL_set_mode
|
||||
#define SSL_set_msg_callback_arg SSL_set_msg_callback_arg
|
||||
#define SSL_set_mtu SSL_set_mtu
|
||||
#define SSL_set_options SSL_set_options
|
||||
#define SSL_set_tlsext_host_name SSL_set_tlsext_host_name
|
||||
#define SSL_set_tmp_dh SSL_set_tmp_dh
|
||||
#define SSL_set_tmp_ecdh SSL_set_tmp_ecdh
|
||||
#define SSL_set_tmp_rsa SSL_set_tmp_rsa
|
||||
#define SSL_total_renegotiations SSL_total_renegotiations
|
||||
|
||||
long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
@ -60,6 +60,14 @@ message PropertyUpdateRequest {
|
||||
required int64 bots_online = 9;
|
||||
required int64 queries_online = 10;
|
||||
required int64 servers_online = 11;
|
||||
|
||||
optional bytes web_cert_revision = 12;
|
||||
}
|
||||
|
||||
message WebCertificate {
|
||||
required bytes revision = 1;
|
||||
required string key = 2;
|
||||
required string certificate = 3;
|
||||
}
|
||||
|
||||
message PropertyUpdateResponse {
|
||||
@ -68,4 +76,5 @@ message PropertyUpdateResponse {
|
||||
required int64 speach_varianz_corrector = 3;
|
||||
|
||||
optional bool reset_speach = 4;
|
||||
optional WebCertificate web_certificate = 5;
|
||||
}
|
@ -136,7 +136,13 @@ void LicenseServer::handleEventWrite(int fd, short, void* ptrServer) {
|
||||
if(!buffer) return;
|
||||
|
||||
auto writtenBytes = send(fd, &buffer->buffer[buffer->index], buffer->length - buffer->index, 0);
|
||||
buffer->index += writtenBytes;
|
||||
if(writtenBytes <= 0) {
|
||||
if(writtenBytes == -1 && errno == EAGAIN)
|
||||
return;
|
||||
logError(LOG_LICENSE_CONTROLL, "Invalid write. Disconnecting remote client. Message: {}/{}", errno, strerror(errno));
|
||||
} else {
|
||||
buffer->index += writtenBytes;
|
||||
}
|
||||
|
||||
if(buffer->index >= buffer->length) {
|
||||
TAILQ_REMOVE(&client->network.writeQueue, buffer, tail);
|
||||
@ -202,7 +208,7 @@ void LicenseServer::handleEventRead(int fd, short, void* ptrServer) {
|
||||
|
||||
if(read < 0){
|
||||
if(errno == EWOULDBLOCK) return;
|
||||
logError(LOG_LICENSE_CONTROLL, "Invalid read. Disconnecting remote manager. Message: {}/{}", errno, strerror(errno));
|
||||
logError(LOG_LICENSE_CONTROLL, "Invalid read. Disconnecting remote client. Message: {}/{}", errno, strerror(errno));
|
||||
event_del_noblock(client->network.readEvent);
|
||||
server->closeConnection(client);
|
||||
return;
|
||||
|
@ -58,6 +58,12 @@ namespace license {
|
||||
inline std::string address() { return inet_ntoa(network.remoteAddr.sin_addr); }
|
||||
};
|
||||
|
||||
struct WebCertificate {
|
||||
std::string revision;
|
||||
std::string key;
|
||||
std::string certificate;
|
||||
};
|
||||
|
||||
class LicenseServer {
|
||||
public:
|
||||
explicit LicenseServer(const sockaddr_in&, const std::shared_ptr<server::LicenseManager>&, const std::shared_ptr<stats::StatisticManager>& /* stats */, const std::shared_ptr<web::WebStatistics>& /* web stats */, const std::shared_ptr<UserManager>& /* user manager */);
|
||||
@ -75,6 +81,8 @@ namespace license {
|
||||
std::lock_guard lock(this->lock);
|
||||
return currentClients;
|
||||
}
|
||||
|
||||
std::shared_ptr<WebCertificate> web_certificate{nullptr};
|
||||
private:
|
||||
void unregisterClient(const std::shared_ptr<ConnectedClient>&);
|
||||
void cleanup_clients();
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <misc/endianness.h>
|
||||
#include <misc/base64.h>
|
||||
#include <misc/hex.h>
|
||||
#include <log/LogUtils.h>
|
||||
#include <LicenseManager.pb.h>
|
||||
#include <shared/License.h>
|
||||
@ -224,7 +225,7 @@ bool LicenseServer::handlePacketPropertyUpdate(shared_ptr<ConnectedClient> &clie
|
||||
if(client->invalid_license) {
|
||||
ts::proto::license::PropertyUpdateResponse response;
|
||||
response.set_accepted(true);
|
||||
response.set_reset_speach(0);
|
||||
response.set_reset_speach(false);
|
||||
response.set_speach_total_remote(0);
|
||||
response.set_speach_varianz_corrector(0);
|
||||
client->sendPacket(protocol::packet{protocol::PACKET_SERVER_PROPERTY_ADJUSTMENT, response});
|
||||
@ -247,18 +248,34 @@ bool LicenseServer::handlePacketPropertyUpdate(shared_ptr<ConnectedClient> &clie
|
||||
logMessage("[CLIENT][" + client->address() + "] Bots online : " + to_string(pkt.bots_online()));
|
||||
logMessage("[CLIENT][" + client->address() + "] Servers : " + to_string(pkt.servers_online()));
|
||||
this->manager->logStatistic(client->key, client->unique_identifier, client->address(), pkt);
|
||||
//TODO test stuff!
|
||||
//TODO test stuff if its possible!
|
||||
|
||||
ts::proto::license::WebCertificate* web_certificate{nullptr};
|
||||
if(pkt.has_web_cert_revision()) {
|
||||
logMessage("[CLIENT][" + client->address() + "] -------------------------------");
|
||||
logMessage("[CLIENT][" + client->address() + "] Web cert revision : " + hex::hex(pkt.web_cert_revision()));
|
||||
|
||||
auto cert = this->web_certificate;
|
||||
if(cert && cert->revision != pkt.web_cert_revision()) {
|
||||
web_certificate = new ts::proto::license::WebCertificate{};
|
||||
web_certificate->set_key(cert->key);
|
||||
web_certificate->set_certificate(cert->certificate);
|
||||
web_certificate->set_revision(cert->revision);
|
||||
}
|
||||
}
|
||||
|
||||
ts::proto::license::PropertyUpdateResponse response;
|
||||
response.set_accepted(true);
|
||||
response.set_reset_speach(pkt.speach_total() < 0);
|
||||
response.set_speach_total_remote(pkt.speach_total());
|
||||
response.set_speach_varianz_corrector(0);
|
||||
response.set_allocated_web_certificate(web_certificate);
|
||||
client->sendPacket(protocol::packet{protocol::PACKET_SERVER_PROPERTY_ADJUSTMENT, response});
|
||||
this->disconnectClient(client, "finished");
|
||||
|
||||
if(this->statistics)
|
||||
this->statistics->reset_cache_general();
|
||||
|
||||
if(this->web_statistics)
|
||||
this->web_statistics->async_broadcast_notify_general_update();
|
||||
return true;
|
||||
|
@ -382,9 +382,6 @@ inline pipes::buffer json_dump(const Json::Value& value) {
|
||||
return pipes::buffer((void*) json.c_str(), json.length());
|
||||
}
|
||||
|
||||
Json::Value::Value(long value) : Value(to_string(value)) {}
|
||||
Json::Value::Value(unsigned long value) : Value(to_string(value)) {}
|
||||
|
||||
bool WebStatistics::handle_message(const std::shared_ptr<license::web::WebStatistics::Client> &client, const pipes::WSMessage &raw_message) {
|
||||
if(this->update_flood(client, 10)) {
|
||||
static pipes::buffer _response;
|
||||
|
@ -393,8 +393,8 @@ namespace license {
|
||||
|
||||
struct packet {
|
||||
struct {
|
||||
PacketType packetId;
|
||||
mutable uint16_t length;
|
||||
PacketType packetId{0};
|
||||
mutable uint16_t length{0};
|
||||
} header;
|
||||
std::string data;
|
||||
|
||||
|
@ -190,10 +190,18 @@ void LicenceRequest::handleConnected() {
|
||||
}
|
||||
|
||||
void LicenceRequest::handleMessage(const std::string& message) {
|
||||
if(message.length() < sizeof(protocol::packet::header)) LICENSE_FERR(this, ConnectionException, "Invalid packet size");
|
||||
this->buffer += message;
|
||||
if(this->buffer.length() < sizeof(protocol::packet::header))
|
||||
return;
|
||||
|
||||
protocol::packet packet{protocol::PACKET_DISCONNECT, ""};
|
||||
memcpy(&packet.header, message.data(), sizeof(protocol::packet::header));
|
||||
packet.data = message.substr(sizeof(protocol::packet::header));
|
||||
memcpy(&packet.header, this->buffer.data(), sizeof(protocol::packet::header));
|
||||
if(packet.header.length <= this->buffer.length() - sizeof(protocol::packet::header)) {
|
||||
packet.data = this->buffer.substr(sizeof(protocol::packet::header), packet.header.length);
|
||||
this->buffer = this->buffer.substr(sizeof(protocol::packet::header) + packet.header.length);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this->cryptKey.empty()) {
|
||||
xorBuffer((char*) packet.data.data(), packet.data.length(), this->cryptKey.data(), this->cryptKey.length());
|
||||
@ -209,6 +217,9 @@ void LicenceRequest::handleMessage(const std::string& message) {
|
||||
this->handlePacketInfoAdjustment(packet.data);
|
||||
} else
|
||||
LICENSE_FERR(this, ConnectionException, "Invalid packet id (" + to_string(packet.header.packetId) + ")");
|
||||
|
||||
if(!this->buffer.empty() && this->state != protocol::DISCONNECTING && this->state != protocol::UNCONNECTED)
|
||||
this->handleMessage("");
|
||||
}
|
||||
|
||||
void LicenceRequest::disconnect(const std::string& message) {
|
||||
|
@ -60,8 +60,10 @@ namespace license {
|
||||
};
|
||||
|
||||
struct LicenseRequestData {
|
||||
std::shared_ptr<License> license = nullptr;
|
||||
std::shared_ptr<ServerInfo> info = nullptr;
|
||||
std::shared_ptr<License> license{nullptr};
|
||||
std::shared_ptr<ServerInfo> info{nullptr};
|
||||
|
||||
std::string web_certificate_revision{};
|
||||
|
||||
int64_t speach_total = 0;
|
||||
int64_t speach_dead = 0;
|
||||
@ -75,6 +77,12 @@ namespace license {
|
||||
int64_t servers_online = 0;
|
||||
};
|
||||
|
||||
struct WebCertificate {
|
||||
std::string revision;
|
||||
std::string key;
|
||||
std::string certificate;
|
||||
};
|
||||
|
||||
class LicenceRequest {
|
||||
public:
|
||||
typedef threads::Future<std::shared_ptr<LicenseRequestResponse>> ResponseFuture;
|
||||
@ -88,6 +96,7 @@ namespace license {
|
||||
|
||||
void sendPacket(const protocol::packet&);
|
||||
|
||||
std::function<void(const WebCertificate&)> callback_update_certificate{nullptr};
|
||||
bool verbose = true;
|
||||
private:
|
||||
std::shared_ptr<LicenseRequestData> data;
|
||||
@ -100,6 +109,8 @@ namespace license {
|
||||
|
||||
sockaddr_in remote_address;
|
||||
|
||||
std::string buffer{};
|
||||
|
||||
int file_descriptor = 0;
|
||||
std::thread event_dispatch;
|
||||
threads::Thread* closeThread = nullptr;
|
||||
|
@ -97,17 +97,28 @@ void LicenceRequest::handlePacketLicenseInfo(const std::string& message) {
|
||||
infos.set_queries_online(this->data->queries_online);
|
||||
infos.set_servers_online(this->data->servers_online);
|
||||
infos.set_web_clients_online(this->data->web_clients_online);
|
||||
|
||||
infos.set_web_cert_revision(this->data->web_certificate_revision);
|
||||
this->sendPacket({protocol::PACKET_CLIENT_PROPERTY_ADJUSTMENT, infos});
|
||||
this->state = protocol::PROPERTY_ADJUSTMENT;
|
||||
}
|
||||
|
||||
void LicenceRequest::handlePacketInfoAdjustment(const std::string& message) {
|
||||
ts::proto::license::PropertyUpdateResponse response;
|
||||
ts::proto::license::PropertyUpdateResponse response{};
|
||||
if(!response.ParseFromString(message)) LICENSE_FERR(this, InvalidResponseException, "Could not parse response");
|
||||
|
||||
this->response->properties_valid = response.accepted();
|
||||
this->response->speach_varianz_adjustment = response.speach_varianz_corrector();
|
||||
this->response->speach_reset = response.reset_speach();
|
||||
|
||||
if(response.has_web_certificate() && this->callback_update_certificate) {
|
||||
WebCertificate cert{};
|
||||
cert.revision = response.web_certificate().revision();
|
||||
cert.key = response.web_certificate().key();
|
||||
cert.certificate = response.web_certificate().certificate();
|
||||
this->callback_update_certificate(cert);
|
||||
}
|
||||
|
||||
this->currentFuture->executionSucceed(this->response);
|
||||
this->response = nullptr;
|
||||
|
||||
|
2
music
2
music
@ -1 +1 @@
|
||||
Subproject commit af7918a243bcdfb9d32ec5a220cc2a6018bbe325
|
||||
Subproject commit ef030797a2a997704b9bd126cbbe1d209205e8f0
|
@ -14,6 +14,7 @@
|
||||
#include "src/server/file/FileServer.h"
|
||||
#include "src/terminal/CommandHandler.h"
|
||||
#include "src/client/InternalClient.h"
|
||||
#include "src/music/MusicBotManager.h"
|
||||
#include "src/SignalHandler.h"
|
||||
#include "src/build.h"
|
||||
|
||||
@ -366,7 +367,7 @@ int main(int argc, char** argv) {
|
||||
auto password = arguments.cmdOptionExists("-q") ? arguments.get_option("-q") : arguments.get_option("--set_query_password");
|
||||
if(!password.empty()) {
|
||||
logMessageFmt(true, LOG_GENERAL, "Updating server admin query password to \"{}\"", password);
|
||||
auto accounts = serverInstance->getQueryServer()->find_query_accounts_by_unique_id(serverInstance->getInitalServerAdmin()->getUid());
|
||||
auto accounts = serverInstance->getQueryServer()->find_query_accounts_by_unique_id(serverInstance->getInitialServerAdmin()->getUid());
|
||||
bool found = false;
|
||||
for(const auto& account : accounts) {
|
||||
if(account->bound_server != 0) continue;
|
||||
@ -395,12 +396,14 @@ int main(int argc, char** argv) {
|
||||
|
||||
stopApp:
|
||||
logMessageFmt(true, LOG_GENERAL, "Stopping application");
|
||||
::music::manager::finalizeProviders();
|
||||
|
||||
if(serverInstance)
|
||||
serverInstance->stopInstance();
|
||||
delete serverInstance;
|
||||
serverInstance = nullptr;
|
||||
|
||||
|
||||
ts::music::MusicBotManager::shutdown();
|
||||
if(sql)
|
||||
sql->finalize();
|
||||
delete sql;
|
||||
@ -410,19 +413,4 @@ int main(int argc, char** argv) {
|
||||
terminal::uninstall();
|
||||
mainThreadDone = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
[02][OUT] (188.225.34.225:9988) ftinitdownload clientftfid=4096 name=\/icon_166694597 cid=0 cpw seekpos=0 proto=1 return_code=
|
||||
[02][OUT] (188.225.34.225:9988) ftinitdownload clientftfid=4095 name=\/icon_4113966246 cid=0 cpw seekpos=0 proto=1 return_code=
|
||||
[02][OUT] (188.225.34.225:9988) ftinitdownload clientftfid=4094 name=\/icon_3002705295 cid=0 cpw seekpos=0 proto=1 return_code=
|
||||
[02][OUT] (188.225.34.225:9988) ftinitdownload clientftfid=4093 name=\/icon_494035633 cid=0 cpw seekpos=0 proto=1 return_code=
|
||||
[02][OUT] (188.225.34.225:9988) ftinitdownload clientftfid=4092 name=\/icon_847789427 cid=0 cpw seekpos=0 proto=1 return_code=
|
||||
[02][ IN] (188.225.34.225:9988) notifyclientupdated clid=5 client_version=3.2.0\s[Build:\s1533739581] client_platform=Linux client_login_name=WolverinDEV client_created=1536521950 client_lastconnected=1536522252 client_totalconnections=2 client_month_bytes_uploaded=0 client_month_bytes_downloaded=0 client_total_bytes_uploaded=0 client_total_bytes_downloaded=0 client_icon_id=0 client_country=DE
|
||||
[02][ IN] (188.225.34.225:9988) notifystartdownload clientftfid=4096 proto=1 serverftfid=1 ftkey=R0Vcnx4fNdrXuMFg port=30303 size=1086
|
||||
[02][ IN] (188.225.34.225:9988) notifystartdownload clientftfid=4095 proto=1 serverftfid=1 ftkey=3eYwsuviQvTWme42 port=30303 size=822
|
||||
[02][ IN] (188.225.34.225:9988) notifystartdownload clientftfid=4094 proto=1 serverftfid=1 ftkey=dM5oaVuLYLwia2me port=30303 size=852
|
||||
[02][ IN] (188.225.34.225:9988) notifystartdownload clientftfid=4093 proto=1 serverftfid=1 ftkey=60BltUu8fbUqgLhj port=30303 size=3441
|
||||
[02][ IN] (188.225.34.225:9988) notifystartdownload clientftfid=4092 proto=1 serverftfid=1 ftkey=a0wmURVHqhNE71H2 port=30303 size=1452
|
||||
|
||||
*/
|
||||
}
|
@ -133,6 +133,7 @@ std::string config::music::command_prefix;
|
||||
#define CREATE_IF_NOT_EXISTS 0b00000001
|
||||
#define PREMIUM_ONLY 0b00000010
|
||||
#define FLAG_REQUIRE 0b00000100
|
||||
#define FLAG_RELOADABLE 0b00001000
|
||||
|
||||
#define COMMENT(path, comment) commentMapping[path].emplace_back(comment)
|
||||
#define WARN_SENSITIVE(path) COMMENT(path, "Do NOT TOUCH unless you're 100% sure!")
|
||||
@ -288,9 +289,11 @@ void build_comments(map<string,deque<string>>& map, const std::deque<std::shared
|
||||
}
|
||||
}
|
||||
|
||||
void read_bindings(YAML::Node& root, const std::deque<std::shared_ptr<EntryBinding>>& bindings) {
|
||||
void read_bindings(YAML::Node& root, const std::deque<std::shared_ptr<EntryBinding>>& bindings, uint8_t required_flags = 0) {
|
||||
for(const auto& entry : bindings) {
|
||||
if(entry->bounded_by != 0) continue;
|
||||
if(entry->bounded_by == 2) continue;
|
||||
if(required_flags > 0 && (entry->flags & required_flags) == 0) continue;
|
||||
|
||||
auto nodes = resolveNode(root, entry->key);
|
||||
assert(!nodes.empty());
|
||||
assert(entry->read_config);
|
||||
@ -313,8 +316,10 @@ inline string apply_comments(stringstream &in, map<string, deque<string>>& comme
|
||||
std::deque<std::shared_ptr<EntryBinding>> create_local_bindings(int& version, std::string& license);
|
||||
|
||||
#define CURRENT_CONFIG_VERSION 14
|
||||
static std::string _config_path;
|
||||
vector<string> config::parseConfig(const std::string& path) {
|
||||
//FIXME test for premium!
|
||||
_config_path = path;
|
||||
|
||||
vector<string> errors;
|
||||
saveConfig = false;
|
||||
|
||||
@ -426,15 +431,10 @@ vector<string> config::parseConfig(const std::string& path) {
|
||||
}
|
||||
|
||||
if(!config::license){
|
||||
#if true
|
||||
logErrorFmt(true, LOG_GENERAL, strobf("The given license isnt valid!").string());
|
||||
logErrorFmt(true, LOG_GENERAL, strobf("The given license isn't valid!").string());
|
||||
logErrorFmt(true, LOG_GENERAL, strobf("Falling back to the default license.").string());
|
||||
teaspeak_license = "none";
|
||||
goto license_parsing;
|
||||
#else
|
||||
errors.push_back("Invalid license code! (" + err + ")");
|
||||
return errors;
|
||||
#endif
|
||||
}
|
||||
if(!config::license){
|
||||
errors.emplace_back(strobf("Invalid license code!").string());
|
||||
@ -446,7 +446,7 @@ vector<string> config::parseConfig(const std::string& path) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
logErrorFmt(true, LOG_GENERAL, strobf("The given license isnt valid!").string());
|
||||
logErrorFmt(true, LOG_GENERAL, strobf("The given license isn't valid!").string());
|
||||
logErrorFmt(true, LOG_GENERAL, strobf("Falling back to the default license.").string());
|
||||
teaspeak_license = "none";
|
||||
goto license_parsing;
|
||||
@ -516,6 +516,48 @@ vector<string> config::parseConfig(const std::string& path) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
std::vector<std::string> config::reload() {
|
||||
|
||||
vector<string> errors;
|
||||
saveConfig = false;
|
||||
|
||||
ifstream cfgStream(_config_path);
|
||||
YAML::Node config;
|
||||
try {
|
||||
config = YAML::Load(cfgStream);
|
||||
} catch (const YAML::ParserException& ex){
|
||||
errors.emplace_back("Could not load config file: " + ex.msg + " @" + to_string(ex.mark.line) + ":" + to_string(ex.mark.column));
|
||||
return errors;
|
||||
}
|
||||
|
||||
try {
|
||||
int config_version;
|
||||
string teaspeak_license;
|
||||
{
|
||||
auto bindings = create_local_bindings(config_version, teaspeak_license);
|
||||
read_bindings(config, bindings, 0);
|
||||
}
|
||||
if(config_version != CURRENT_CONFIG_VERSION) {
|
||||
errors.emplace_back("Given config version is no equal to the initial one!");
|
||||
return errors;
|
||||
}
|
||||
|
||||
auto bindings = create_bindings();
|
||||
read_bindings(config, bindings, FLAG_RELOADABLE);
|
||||
} catch(const YAML::Exception& ex) {
|
||||
errors.emplace_back("Could not read config: " + ex.msg + " @" + to_string(ex.mark.line) + ":" + to_string(ex.mark.column));
|
||||
return errors;
|
||||
} catch(const ConfigParseError& ex) {
|
||||
errors.emplace_back("Failed to parse config entry \"" + ex.entry()->key + "\": " + ex.what());
|
||||
return errors;
|
||||
} catch(const PathNodeError& ex) {
|
||||
errors.emplace_back("Expected sequence for path " + ex.path() + ": " + ex.message());
|
||||
return errors;
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
void bind_string_description(const shared_ptr<EntryBinding>& _entry, std::string& target, const std::string& default_value) {
|
||||
_entry->default_value = [default_value]() -> std::deque<std::string> { return { default_value }; };
|
||||
_entry->value_description = [] { return "The value must be a string"; };
|
||||
@ -760,7 +802,7 @@ inline std::string join_path(const deque<string>& stack, const std::string& entr
|
||||
#define CREATE_BINDING(name, _flags) \
|
||||
auto binding = make_shared<EntryBinding>(); \
|
||||
binding->key = join_path(group_stack, name); \
|
||||
binding->flags = _flags; \
|
||||
binding->flags = (_flags); \
|
||||
result.push_back(binding)
|
||||
|
||||
#define BIND_STRING(target, default) \
|
||||
@ -797,6 +839,9 @@ inline std::string join_path(const deque<string>& stack, const std::string& entr
|
||||
for(const auto& entry : {desc, ##__VA_ARGS__}) \
|
||||
binding->description["Notes"].emplace_back(entry)
|
||||
|
||||
#define ADD_NOTE_RELOADABLE() \
|
||||
binding->description["Notes"].emplace_back("This option could be reloaded while the instance is running.")
|
||||
|
||||
#define ADD_WARN(desc, ...) \
|
||||
for(const auto& entry : {desc, ##__VA_ARGS__}) \
|
||||
binding->description["Warning"].emplace_back(entry)
|
||||
@ -1011,12 +1056,12 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
{
|
||||
BIND_GROUP(ssl);
|
||||
{
|
||||
CREATE_BINDING("certificate", 0);
|
||||
CREATE_BINDING("certificate", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::query::ssl::certFile, "certs/query_certificate.pem");
|
||||
ADD_DESCRIPTION("The SSL certificate for the query client");
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("privatekey", 0);
|
||||
CREATE_BINDING("privatekey", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::query::ssl::keyFile, "certs/query_privatekey.pem");
|
||||
ADD_DESCRIPTION("The SSL private key for the query client (You have to export the key without a password!)");
|
||||
}
|
||||
@ -1099,19 +1144,21 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
{
|
||||
BIND_GROUP(server)
|
||||
{
|
||||
CREATE_BINDING("platform", PREMIUM_ONLY);
|
||||
CREATE_BINDING("platform", PREMIUM_ONLY | FLAG_RELOADABLE);
|
||||
BIND_STRING(config::server::DefaultServerPlatform, strobf("Linux").string());
|
||||
ADD_DESCRIPTION("The displayed platform to the client");
|
||||
ADD_NOTE("This option is only for the premium version.");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("version", PREMIUM_ONLY);
|
||||
CREATE_BINDING("version", PREMIUM_ONLY | FLAG_RELOADABLE);
|
||||
BIND_STRING(config::server::DefaultServerVersion, strobf("TeaSpeak ").string() + build::version()->string(true));
|
||||
ADD_DESCRIPTION("The displayed version to the client");
|
||||
ADD_NOTE("This option is only for the premium version.");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("licence", PREMIUM_ONLY);
|
||||
CREATE_BINDING("licence", PREMIUM_ONLY | FLAG_RELOADABLE);
|
||||
BIND_INTEGRAL(config::server::DefaultServerLicense, LicenseType::LICENSE_AUTOMATIC_SERVER, LicenseType::_LicenseType_MIN, LicenseType::_LicenseType_MAX);
|
||||
ADD_DESCRIPTION("The displayed licence type to every TeaSpeak 3 Client");
|
||||
ADD_DESCRIPTION("Available types:");
|
||||
@ -1125,6 +1172,7 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
ADD_DESCRIPTION(" 7: Auto-License (Instance based)");
|
||||
ADD_NOTE("This option just work for non 3.2 clients!");
|
||||
ADD_NOTE("This option is only for the premium version.");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("delete_old_bans", 0);
|
||||
@ -1158,9 +1206,10 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
ADD_DESCRIPTION("Disable the saving of IP addresses within the database");
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("max_virtual_servers", 0);
|
||||
CREATE_BINDING("max_virtual_servers", FLAG_RELOADABLE);
|
||||
BIND_INTEGRAL(config::server::max_virtual_server, 16, -1, 999999);
|
||||
ADD_DESCRIPTION("Set the limit for maximal virtual servers. -1 means unlimited.");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
/*
|
||||
@ -1180,9 +1229,10 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
{
|
||||
BIND_GROUP(authentication);
|
||||
{
|
||||
CREATE_BINDING("name", 0);
|
||||
CREATE_BINDING("name", FLAG_RELOADABLE);
|
||||
BIND_BOOL(config::server::authentication::name, false);
|
||||
ADD_DESCRIPTION("Allow or disallow client authentication just by their name");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1203,7 +1253,8 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
{
|
||||
BIND_GROUP(ssl)
|
||||
{
|
||||
CREATE_BINDING("certificate", 0);
|
||||
CREATE_BINDING("certificate", FLAG_RELOADABLE);
|
||||
ADD_NOTE_RELOADABLE();
|
||||
binding->type = 4;
|
||||
|
||||
/* no terminal handling */
|
||||
@ -1212,6 +1263,7 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
};
|
||||
binding->default_value = []() -> deque<string> { return {}; };
|
||||
|
||||
//Unused :)
|
||||
binding->set_default = [](YAML::Node& node) {
|
||||
auto default_node = node["default"];
|
||||
default_node["certificate"] = "default_certificate.pem";
|
||||
@ -1221,11 +1273,11 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
weak_ptr<EntryBinding> _binding = binding;
|
||||
binding->read_config = [_binding](YAML::Node& node) {
|
||||
auto b = _binding.lock();
|
||||
if(!b)
|
||||
return;
|
||||
if(!b) return;
|
||||
config::web::ssl::certificates.clear();
|
||||
|
||||
if(!node.IsDefined() || node.IsNull())
|
||||
b->set_default(node);
|
||||
return;
|
||||
|
||||
for(auto it = node.begin(); it != node.end(); it++) {
|
||||
auto node_cert = it->second["certificate"];
|
||||
@ -1239,7 +1291,7 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
continue;
|
||||
}
|
||||
|
||||
config::web::ssl::certificates.push_back({it->first.as<string>(), node_key.as<string>(), node_cert.as<string>()});
|
||||
config::web::ssl::certificates.emplace_back(it->first.as<string>(), node_key.as<string>(), node_cert.as<string>());
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1280,14 +1332,16 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
{
|
||||
BIND_GROUP(geolocation);
|
||||
{
|
||||
CREATE_BINDING("fallback_country", 0);
|
||||
CREATE_BINDING("fallback_country", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::geo::countryFlag, "DE");
|
||||
ADD_DESCRIPTION("The fallback country if lookup fails");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("force_fallback_country", 0);
|
||||
CREATE_BINDING("force_fallback_country", FLAG_RELOADABLE);
|
||||
BIND_BOOL(config::geo::staticFlag, false);
|
||||
ADD_DESCRIPTION("Enforce the default country and disable resolve");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
|
||||
{
|
||||
@ -1329,70 +1383,84 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
{
|
||||
BIND_GROUP(messages);
|
||||
{
|
||||
CREATE_BINDING("voice.server_stop", 0);
|
||||
CREATE_BINDING("voice.server_stop", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::serverStopped, "Server stopped");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("application.stop", 0);
|
||||
CREATE_BINDING("application.stop", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::applicationStopped, "Application stopped");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("application.crash", 0);
|
||||
CREATE_BINDING("application.crash", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::applicationCrashed, "Application crashed");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("idle_time", 0);
|
||||
CREATE_BINDING("idle_time", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::idle_time_exceeded, "Idle time exceeded");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("teamspeak_permission_editor", 0);
|
||||
CREATE_BINDING("teamspeak_permission_editor", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::teamspeak_permission_editor, "\n[b][COLOR=#aa0000]ATTENTION[/COLOR][/b]:\nIt seems like you're trying to edit the TeaSpeak permissions with the TeamSpeak 3 client!\nThis is [b]really[/b] buggy due a bug within the client you're using.\n\nWe recommand to [b]use the [url=https://web.teaspeak.de/]TeaSpeak-Web[/url][/b] client or the [b][url=https://teaspeak.de/]TeaSpeak client[/url][/b].\nYatQA is a good option as well.\n\nTo disable/edit this message please edit the config.yml\nPlease note: Permission bugs, which will be reported wound be accepted.");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
BIND_GROUP(mute);
|
||||
{
|
||||
CREATE_BINDING("mute_message", 0);
|
||||
CREATE_BINDING("mute_message", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::mute_notify_message, "Hey!\nI muted you!");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("unmute_message", 0);
|
||||
CREATE_BINDING("unmute_message", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::unmute_notify_message, "Hey!\nI unmuted you!");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
}
|
||||
{
|
||||
BIND_GROUP(kick_invalid);
|
||||
{
|
||||
CREATE_BINDING("hardware_id", 0);
|
||||
CREATE_BINDING("hardware_id", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::kick_invalid_hardware_id, "Invalid hardware id. Protocol hacked?");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("command", 0);
|
||||
CREATE_BINDING("command", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::kick_invalid_hardware_id, "Invalid command. Protocol hacked?");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("badges", 0);
|
||||
CREATE_BINDING("badges", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::kick_invalid_hardware_id, "Invalid badges. Protocol hacked?");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("vpn.kick", 0);
|
||||
CREATE_BINDING("vpn.kick", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::kick_vpn, "Please disable your VPN! (Provider: ${provider.name})");
|
||||
ADD_DESCRIPTION("This is the kick/ban message when a client tries to connect with a vpn");
|
||||
|
||||
ADD_DESCRIPTION("Variables are enabled. Available:");
|
||||
ADD_DESCRIPTION(" - provider.name => Contains the provider of the ip which has been flaged as vps");
|
||||
ADD_DESCRIPTION(" - provider.website => Contains the website provider of the ip which has been flaged as vps");
|
||||
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
BIND_GROUP(shutdown);
|
||||
{
|
||||
CREATE_BINDING("scheduled", 0);
|
||||
CREATE_BINDING("scheduled", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::shutdown::scheduled, "[b][color=#DA9100]Scheduled shutdown at ${time}(%Y-%m-%d %H:%M:%S)[/color][/b]");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("interval", 0);
|
||||
CREATE_BINDING("interval", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::shutdown::interval, "[b][color=red]Server instance shutting down in ${interval}[/color][/b]");
|
||||
ADD_DESCRIPTION("${interval} is defined via map in 'intervals'");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("intervals", 0);
|
||||
@ -1448,18 +1516,20 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
ADD_DESCRIPTION("Add or delete intervals as you want");
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("now", 0);
|
||||
CREATE_BINDING("now", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::shutdown::now, "[b][color=red]Server instance shutting down in now[/color][/b]");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("canceled", 0);
|
||||
CREATE_BINDING("canceled", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::shutdown::canceled, "[b][color=green]Scheduled instance shutdown canceled![/color][/b]");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
}
|
||||
{
|
||||
BIND_GROUP(music);
|
||||
{
|
||||
CREATE_BINDING("song_announcement", 0);
|
||||
CREATE_BINDING("song_announcement", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::music::song_announcement, "Now replaying ${title} (${url}) added by ${invoker}");
|
||||
ADD_DESCRIPTION("${title} title of the song");
|
||||
ADD_DESCRIPTION("${description} description of the song");
|
||||
@ -1470,12 +1540,14 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
|
||||
{
|
||||
BIND_GROUP(timeout);
|
||||
{
|
||||
CREATE_BINDING("connection_reinitialized", 0);
|
||||
CREATE_BINDING("connection_reinitialized", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::timeout::connection_reinitialized, "Connection lost");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
{
|
||||
CREATE_BINDING("packet_resend_failed", 0);
|
||||
CREATE_BINDING("packet_resend_failed", FLAG_RELOADABLE);
|
||||
BIND_STRING(config::messages::timeout::packet_resend_failed, "Packet resend failed");
|
||||
ADD_NOTE_RELOADABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ namespace ts {
|
||||
};
|
||||
|
||||
extern std::vector<std::string> parseConfig(const std::string& /* path */);
|
||||
extern std::vector<std::string> reload();
|
||||
extern std::deque<std::shared_ptr<EntryBinding>> create_bindings();
|
||||
|
||||
namespace database {
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "build.h"
|
||||
#include <misc/digest.h>
|
||||
#include <misc/base64.h>
|
||||
#include <misc/hex.h>
|
||||
#include <misc/rnd.h>
|
||||
#include <misc/strobf.h>
|
||||
#include <jemalloc/jemalloc.h>
|
||||
@ -28,7 +29,6 @@
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#undef _POSIX_SOURCE
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
@ -37,11 +37,7 @@ using namespace ts::server;
|
||||
|
||||
#define INSTANCE_TICK_NAME "instance"
|
||||
|
||||
#define _STRINGIFY(x) #x
|
||||
#define STRINGIFY(x) _STRINGIFY(x)
|
||||
|
||||
extern bool mainThreadActive;
|
||||
extern InstanceHandler* serverInstance;
|
||||
InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) {
|
||||
serverInstance = this;
|
||||
this->tick_manager = make_shared<threads::Scheduler>(config::threads::ticking, "tick task ");
|
||||
@ -226,19 +222,6 @@ inline string strip(std::string message) {
|
||||
return message;
|
||||
}
|
||||
|
||||
inline sockaddr_in* resolveAddress(const string& host, uint16_t port) {
|
||||
hostent* record = gethostbyname(host.c_str());
|
||||
if (!record) {
|
||||
cerr << "Cant resolve bind host! (" << host << ")" << endl;
|
||||
return nullptr;
|
||||
}
|
||||
auto addr = new sockaddr_in{};
|
||||
addr->sin_addr.s_addr = ((in_addr *) record->h_addr)->s_addr;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = htons(port);
|
||||
return addr;
|
||||
}
|
||||
|
||||
inline vector<string> split_hosts(const std::string& message, char delimiter) {
|
||||
vector<string> result;
|
||||
size_t found, index = 0;
|
||||
@ -275,6 +258,19 @@ bool InstanceHandler::startInstance() {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
vector<string> errors;
|
||||
if(!this->reloadConfig(errors, false)) {
|
||||
logCritical(LOG_GENERAL, "Failed to initialize config:");
|
||||
for(auto& error : errors)
|
||||
logCritical(LOG_GENERAL, "{}", error);
|
||||
return false;
|
||||
}
|
||||
for(auto& error : errors)
|
||||
logError(LOG_GENERAL, "{}", error);
|
||||
}
|
||||
|
||||
this->loadWebCertificate();
|
||||
fileServer = new ts::server::FileServer();
|
||||
{
|
||||
auto bindings_string = this->properties()[property::SERVERINSTANCE_FILETRANSFER_HOST].as<string>();
|
||||
@ -303,13 +299,8 @@ bool InstanceHandler::startInstance() {
|
||||
}
|
||||
|
||||
if(config::query::sslMode > 0) {
|
||||
string error;
|
||||
auto result = this->sslMgr->initializeContext("query", config::query::ssl::keyFile, config::query::ssl::certFile, error, false, make_shared<ssl::SSLGenerator>(ssl::SSLGenerator{
|
||||
.subjects = {},
|
||||
.issues = {{"O", "TeaSpeak"}, {"OU", "Query server"}, {"creator", "WolverinDEV"}}
|
||||
}));
|
||||
if(!result) {
|
||||
logCritical(LOG_QUERY, "Failed to initialize query certificate! (" + error + ")");
|
||||
if(!this->sslMgr->getContext("query")) {
|
||||
logCritical(LOG_QUERY, "Missing query SSL certificate.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -360,17 +351,6 @@ bool InstanceHandler::startInstance() {
|
||||
#ifdef COMPILE_WEB_CLIENT
|
||||
if(config::web::activated) {
|
||||
string error;
|
||||
for(auto& certificate : config::web::ssl::certificates) {
|
||||
auto result = this->sslMgr->initializeContext("web_" + get<0>(certificate), get<1>(certificate), get<2>(certificate), error, false, make_shared<ts::ssl::SSLGenerator>(ts::ssl::SSLGenerator{
|
||||
.subjects = {},
|
||||
.issues = {{"O", "TeaSpeak"}, {"OU", "Web server"}, {"creator", "WolverinDEV"}}
|
||||
}));
|
||||
if(!result) {
|
||||
logError(LOG_INSTANCE, "Failed to initialize web certificate for servername {}! (Private key: {}, Certificate: {})", get<0>(certificate), get<1>(certificate), get<2>(certificate));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto rsa = this->sslMgr->initializeSSLKey("teaforo_sign", R"(
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsfsTByPTE0aIqi6pJl4f
|
||||
@ -438,9 +418,6 @@ void InstanceHandler::stopInstance() {
|
||||
threads::MutexLock lock_tick(this->lock_tick);
|
||||
this->scheduler()->cancelTask(INSTANCE_TICK_NAME);
|
||||
|
||||
this->save_channel_permissions();
|
||||
this->save_group_permissions();
|
||||
|
||||
debugMessage(LOG_INSTANCE, "Stopping all virtual servers");
|
||||
if (this->voiceServerManager)
|
||||
this->voiceServerManager->shutdownAll(ts::config::messages::applicationStopped);
|
||||
@ -460,6 +437,9 @@ void InstanceHandler::stopInstance() {
|
||||
this->fileServer = nullptr;
|
||||
debugMessage(LOG_FT, "File server stopped");
|
||||
|
||||
this->save_channel_permissions();
|
||||
this->save_group_permissions();
|
||||
|
||||
delete this->sslMgr;
|
||||
this->sslMgr = nullptr;
|
||||
|
||||
@ -614,13 +594,11 @@ void InstanceHandler::resetSpeechTime() {
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
|
||||
string get_mac_address() {
|
||||
struct ifreq ifr;
|
||||
struct ifconf ifc;
|
||||
struct ifreq ifr{};
|
||||
struct ifconf ifc{};
|
||||
char buf[1024];
|
||||
int success = 0;
|
||||
|
||||
@ -637,14 +615,13 @@ string get_mac_address() {
|
||||
for (; it != end; ++it) {
|
||||
strcpy(ifr.ifr_name, it->ifr_name);
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
|
||||
if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback
|
||||
if (!(ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback
|
||||
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
|
||||
success = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { return "undefined"; }
|
||||
} else { return "undefined"; }
|
||||
}
|
||||
|
||||
return success ? base64::encode(ifr.ifr_hwaddr.sa_data, 6) : "undefined";
|
||||
@ -652,18 +629,20 @@ string get_mac_address() {
|
||||
|
||||
#define SN_BUFFER 1024
|
||||
std::shared_ptr<license::LicenseRequestData> InstanceHandler::generateLicenseData() {
|
||||
auto response = make_shared<license::LicenseRequestData>();
|
||||
response->license = config::license;
|
||||
response->servers_online = this->voiceServerManager->runningServers();
|
||||
auto request = make_shared<license::LicenseRequestData>();
|
||||
request->license = config::license;
|
||||
request->servers_online = this->voiceServerManager->runningServers();
|
||||
auto report = this->voiceServerManager->clientReport();
|
||||
response->client_online = report.clients_ts;
|
||||
response->web_clients_online = report.clients_web;
|
||||
response->bots_online = report.bots;
|
||||
response->queries_online = report.queries;
|
||||
response->speach_total = this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_TOTAL].as<uint64_t>();
|
||||
response->speach_varianz = this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_VARIANZ].as<uint64_t>();
|
||||
response->speach_online = this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_ALIVE].as<uint64_t>();
|
||||
response->speach_dead = this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_DELETED].as<uint64_t>();
|
||||
request->client_online = report.clients_ts;
|
||||
request->web_clients_online = report.clients_web;
|
||||
request->bots_online = report.bots;
|
||||
request->queries_online = report.queries;
|
||||
request->speach_total = this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_TOTAL].as<uint64_t>();
|
||||
request->speach_varianz = this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_VARIANZ].as<uint64_t>();
|
||||
request->speach_online = this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_ALIVE].as<uint64_t>();
|
||||
request->speach_dead = this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_DELETED].as<uint64_t>();
|
||||
|
||||
request->web_certificate_revision = this->web_cert_revision;
|
||||
|
||||
{
|
||||
auto info = make_shared<license::ServerInfo>();
|
||||
@ -672,7 +651,7 @@ std::shared_ptr<license::LicenseRequestData> InstanceHandler::generateLicenseDat
|
||||
|
||||
{ /* uname */
|
||||
utsname retval{};
|
||||
if(uname(&retval) < 0) { // <----
|
||||
if(uname(&retval) < 0) {
|
||||
info->uname = "unknown (" + string(strerror(errno)) + ")";
|
||||
} else {
|
||||
char buffer[SN_BUFFER];
|
||||
@ -692,9 +671,9 @@ std::shared_ptr<license::LicenseRequestData> InstanceHandler::generateLicenseDat
|
||||
info->unique_identifier = base64::encode(hash);
|
||||
}
|
||||
|
||||
response->info = info;
|
||||
request->info = info;
|
||||
}
|
||||
return response;
|
||||
return request;
|
||||
}
|
||||
|
||||
bool InstanceHandler::resetMonthlyStats() {
|
||||
@ -722,4 +701,166 @@ bool InstanceHandler::resetMonthlyStats() {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InstanceHandler::reloadConfig(std::vector<std::string>& errors, bool reload_file) {
|
||||
if(reload_file) {
|
||||
auto cfg_errors = config::reload();
|
||||
if(!cfg_errors.empty()) {
|
||||
errors.emplace_back("Failed to load config:");
|
||||
errors.insert(errors.begin(), cfg_errors.begin(), cfg_errors.end());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
string error;
|
||||
#ifdef COMPILE_WEB_CLIENT
|
||||
if(config::web::activated) {
|
||||
this->sslMgr->unregister_web_contexts();
|
||||
//TODO: Generate default certificate (con-gate.work)
|
||||
|
||||
string error;
|
||||
for (auto &certificate : config::web::ssl::certificates) {
|
||||
if(get<0>(certificate) == "default") {
|
||||
logWarning(LOG_GENERAL, "Default Web certificate will be ignored. Using internal one!");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto result = this->sslMgr->initializeContext(
|
||||
"web_" + get<0>(certificate), get<1>(certificate), get<2>(certificate), error, false, make_shared<ts::ssl::SSLGenerator>(
|
||||
ts::ssl::SSLGenerator{
|
||||
.subjects = {},
|
||||
.issues = {{"O", "TeaSpeak"},
|
||||
{"OU", "Web server"},
|
||||
{"creator", "WolverinDEV"}}
|
||||
}
|
||||
));
|
||||
if (!result) {
|
||||
errors.push_back("Failed to initialize web certificate for servername " + get<0>(certificate) + "! (Key: " + get<1>(certificate) + ", Certificate: " + get<2>(certificate) + ")");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
auto result = this->sslMgr->initializeContext("query_new", config::query::ssl::keyFile, config::query::ssl::certFile, error, false, make_shared<ssl::SSLGenerator>(ssl::SSLGenerator{
|
||||
.subjects = {},
|
||||
.issues = {{"O", "TeaSpeak"}, {"OU", "Query server"}, {"creator", "WolverinDEV"}}
|
||||
}));
|
||||
if(!result)
|
||||
errors.push_back("Failed to initialize query certificate! (" + error + ")");
|
||||
this->sslMgr->rename_context("query_new", "query"); //Will not succeed if the query_new context failed
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstanceHandler::setWebCertRoot(const std::string &key, const std::string &certificate, const std::string &revision) {
|
||||
std::string error{};
|
||||
|
||||
logMessage(LOG_INSTANCE, strobf("Received new web default certificate. Revision {}").string(), hex::hex(revision));
|
||||
|
||||
std::string _key{key}, _cert{certificate}, _revision{revision};
|
||||
auto result = this->sslMgr->initializeContext(strobf("web_default_new").string(), _key, _cert, error, true);
|
||||
if(!result) {
|
||||
logError(LOG_INSTANCE, strobf("Failed to use web default certificate: {}").string(), error);
|
||||
return;
|
||||
}
|
||||
|
||||
this->sslMgr->rename_context(strobf("web_default_new").string(), strobf("web_default").string());
|
||||
|
||||
//https://127-0-0-1.con-gate.work:9987
|
||||
{ /* "Crypt" */
|
||||
auto& xor_short = _key.length() < _cert.length() ? _key : _cert;
|
||||
auto& xor_long = _key.length() < _cert.length() ? _cert : _key;
|
||||
for(size_t index = 0; index < xor_short.length(); index++)
|
||||
xor_short[index] ^= xor_long[index];
|
||||
for(size_t index = 0; index < xor_long.length(); index++)
|
||||
xor_long[index] ^= ((index << 4) & 0xFF) | ((index >> 4) & 0xFF);
|
||||
}
|
||||
|
||||
for(auto& e : _cert)
|
||||
e ^= 0x8A;
|
||||
for(auto& e : _key)
|
||||
e ^= 0x8A;
|
||||
|
||||
_key = base64::encode(_key);
|
||||
_cert = base64::encode(_cert);
|
||||
_revision = base64::encode(_revision);
|
||||
|
||||
auto response = sql::command(this->sql->sql(),
|
||||
strobf("DELETE FROM `general` WHERE `key` = 'webcert-revision' or `key` = 'webcert-cert' or `key` = 'webcert-key'").string()).execute();
|
||||
if(!response) {
|
||||
logError(LOG_INSTANCE, strobf("Failed to delete old default web certificate in database: {}").string(), response.fmtStr());
|
||||
return;
|
||||
}
|
||||
|
||||
response = sql::command(this->sql->sql(), strobf("INSERT INTO `general` (`key`, `value`) VALUES ('webcert-revision', :rev), ('webcert-cert', :cert), ('webcert-key', :key)").string(),
|
||||
variable{":rev", _revision},
|
||||
variable{":cert", _cert},
|
||||
variable{":key", _key}
|
||||
).execute();
|
||||
if(!response) {
|
||||
logError(LOG_INSTANCE, strobf("Failed to insert new default web certificate in database: {}").string(), response.fmtStr());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceHandler::loadWebCertificate() {
|
||||
std::string revision{}, cert{}, _key{}, error{};
|
||||
|
||||
sql::command(this->sql->sql(), strobf("SELECT * FROM `general` WHERE `key` = 'webcert-revision' or `key` = 'webcert-cert' or `key` = 'webcert-key'").string())
|
||||
.query([&](int count, std::string* values, std::string* names) {
|
||||
std::string key{}, value{};
|
||||
for(int index = 0; index < count; index++) {
|
||||
if(names[index] == "key")
|
||||
key = values[index];
|
||||
else if(names[index] == "value")
|
||||
value = values[index];
|
||||
}
|
||||
|
||||
if(!value.empty() && !key.empty()) {
|
||||
if(key == strobf("webcert-revision").string())
|
||||
revision = value;
|
||||
else if(key == strobf("webcert-cert").string())
|
||||
cert = value;
|
||||
else if(key == strobf("webcert-key").string())
|
||||
_key = value;
|
||||
}
|
||||
});
|
||||
|
||||
_key = base64::decode(_key);
|
||||
cert = base64::decode(cert);
|
||||
revision = base64::decode(revision);
|
||||
|
||||
if(revision.empty() || cert.empty() || _key.empty()) {
|
||||
if(!revision.empty() || !cert.empty() || !_key.empty())
|
||||
logWarning(LOG_INSTANCE, strobf("Failed to load default web certificate from database.").string());
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto& e : cert)
|
||||
e ^= 0x8A;
|
||||
for(auto& e : _key)
|
||||
e ^= 0x8A;
|
||||
|
||||
|
||||
{ /* "Crypt" */
|
||||
auto& xor_short = _key.length() < cert.length() ? _key : cert;
|
||||
auto& xor_long = _key.length() < cert.length() ? cert : _key;
|
||||
|
||||
for(size_t index = 0; index < xor_long.length(); index++)
|
||||
xor_long[index] ^= ((index << 4) & 0xFF) | ((index >> 4) & 0xFF);
|
||||
|
||||
for(size_t index = 0; index < xor_short.length(); index++)
|
||||
xor_short[index] ^= xor_long[index];
|
||||
}
|
||||
|
||||
|
||||
auto result = this->sslMgr->initializeContext(strobf("web_default_new").string(), _key, cert, error, true);
|
||||
if(!result) {
|
||||
logError(LOG_INSTANCE, strobf("Failed to use web default certificate from db: {}").string(), error);
|
||||
return;
|
||||
}
|
||||
|
||||
this->web_cert_revision = revision;
|
||||
}
|
@ -32,7 +32,7 @@ namespace ts {
|
||||
return *_properties;
|
||||
}
|
||||
|
||||
std::shared_ptr<ts::server::InternalClient> getInitalServerAdmin(){ return globalServerAdmin; }
|
||||
std::shared_ptr<ts::server::InternalClient> getInitialServerAdmin(){ return globalServerAdmin; }
|
||||
std::shared_ptr<ts::GroupManager> getGroupManager(){ return groupManager; }
|
||||
|
||||
std::shared_ptr<ts::ServerChannelTree> getChannelTree() { return this->default_tree; }
|
||||
@ -51,6 +51,9 @@ namespace ts {
|
||||
void executeTick(TSServer*);
|
||||
void cancelExecute(TSServer*);
|
||||
|
||||
bool reloadConfig(std::vector<std::string>& /* errors */, bool /* reload file */);
|
||||
void setWebCertRoot(const std::string& /* key */, const std::string& /* certificate */, const std::string& /* revision */);
|
||||
|
||||
const std::shared_ptr<ConnectedClient>& musicRoot() { return this->_musicRoot; }
|
||||
|
||||
std::chrono::milliseconds calculateSpokenTime();
|
||||
@ -112,6 +115,8 @@ namespace ts {
|
||||
std::shared_ptr<permission::PermissionNameMapper> permission_mapper = nullptr;
|
||||
std::shared_ptr<TeamSpeakLicense> teamspeak_license = nullptr;
|
||||
|
||||
std::string web_cert_revision{};
|
||||
|
||||
threads::Mutex lock_tick;
|
||||
private:
|
||||
bool setupDefaultGroups();
|
||||
@ -119,6 +124,8 @@ namespace ts {
|
||||
|
||||
void save_group_permissions();
|
||||
void save_channel_permissions();
|
||||
|
||||
void loadWebCertificate();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -15,22 +15,27 @@ bool shuttingDown = false;
|
||||
void ts::server::shutdownInstance(const std::string& message) {
|
||||
if(shuttingDown) return;
|
||||
shuttingDown = true;
|
||||
threads::Thread(THREAD_EXECUTE_LATER, [](){
|
||||
|
||||
auto hangup_controller = std::thread([]{
|
||||
threads::self::sleep_for(chrono::seconds(30));
|
||||
logCritical("Could not shutdown server within 30 seconds! (Hangup!)");
|
||||
logCritical("Killing server!");
|
||||
logCriticalFmt(true, 0, "Could not shutdown server within 30 seconds! (Hangup!)");
|
||||
logCriticalFmt(true, 0, "Killing server!");
|
||||
|
||||
threads::Thread(THREAD_EXECUTE_LATER, [](){
|
||||
auto force_kill = std::thread([]{
|
||||
threads::self::sleep_for(chrono::seconds(5));
|
||||
logCritical("Failed to exit normally!");
|
||||
logCritical("executing raise(SIGKILL);");
|
||||
logCriticalFmt(true, 0, "Failed to exit normally!");
|
||||
logCriticalFmt(true, 0, "executing raise(SIGKILL);");
|
||||
raise(SIGKILL);
|
||||
}).name("Stop exit controller").execute().detach();
|
||||
});
|
||||
threads::name(force_kill, "force stopper");
|
||||
force_kill.detach();
|
||||
|
||||
exit(2);
|
||||
}).name("Stop controller").execute().detach();
|
||||
});
|
||||
threads::name(hangup_controller, "stop controller");
|
||||
hangup_controller.detach();
|
||||
|
||||
|
||||
logMessage("Stopping all server instances!");
|
||||
logMessage(LOG_GENERAL, "Stopping all server instances!");
|
||||
if(serverInstance && serverInstance->getVoiceServerManager())
|
||||
serverInstance->getVoiceServerManager()->shutdownAll(message);
|
||||
|
||||
|
@ -372,7 +372,7 @@ CommandResult ConnectedClient::handleCommand(Command &cmd) {
|
||||
if (this->getType() == ClientType::CLIENT_TEAMSPEAK)
|
||||
if (command.empty() || command.find_first_not_of(' ') == -1) {
|
||||
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_allow_invalid_packet, 1, this->currentChannel))
|
||||
((VoiceClient *) this)->disconnect(VREASON_SERVER_KICK, config::messages::kick_invalid_command, this->server ? this->server->serverAdmin : static_pointer_cast<ConnectedClient>(serverInstance->getInitalServerAdmin()), true);
|
||||
((VoiceClient *) this)->disconnect(VREASON_SERVER_KICK, config::messages::kick_invalid_command, this->server ? this->server->serverAdmin : static_pointer_cast<ConnectedClient>(serverInstance->getInitialServerAdmin()), true);
|
||||
}
|
||||
|
||||
logError(this->getServerId(), "Missing command '{}'", command);
|
||||
@ -4865,7 +4865,7 @@ CommandResult ConnectedClient::handleCommandClientEdit(Command &cmd, const std::
|
||||
} while (index < str.length() && index != 0);
|
||||
if (badgesTags >= 2) {
|
||||
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_allow_invalid_badges, 1, this->currentChannel))
|
||||
((VoiceClient *) this)->disconnect(VREASON_SERVER_KICK, config::messages::kick_invalid_badges, this->server ? this->server->serverAdmin : dynamic_pointer_cast<ConnectedClient>(serverInstance->getInitalServerAdmin()), true);
|
||||
((VoiceClient *) this)->disconnect(VREASON_SERVER_KICK, config::messages::kick_invalid_badges, this->server ? this->server->serverAdmin : dynamic_pointer_cast<ConnectedClient>(serverInstance->getInitialServerAdmin()), true);
|
||||
return {findError("parameter_invalid"), "Invalid badges"};
|
||||
}
|
||||
//FIXME stuff here
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <log/LogUtils.h>
|
||||
#include <misc/strobf.h>
|
||||
#include <misc/hex.h>
|
||||
#include <src/Configuration.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <src/SignalHandler.h>
|
||||
@ -13,6 +14,8 @@ using namespace std::chrono;
|
||||
using namespace ts;
|
||||
using namespace ts::server;
|
||||
|
||||
#define DO_LOCAL_REQUEST
|
||||
|
||||
LicenseHelper::LicenseHelper() {
|
||||
this->scheduled_request = system_clock::now() + seconds(rand() % 30); //Check in one minute
|
||||
}
|
||||
@ -28,6 +31,7 @@ LicenseHelper::~LicenseHelper() {
|
||||
lock.unlock();
|
||||
|
||||
request->abortRequest();
|
||||
request->callback_update_certificate = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,6 +169,7 @@ void LicenseHelper::do_request(bool verbose) {
|
||||
auto license_data = serverInstance->generateLicenseData();
|
||||
auto request = make_shared<license::LicenceRequest>(license_data, server_addr);
|
||||
request->verbose = false;
|
||||
request->callback_update_certificate = [&](const auto& update) { this->callback_certificate_update(update); };
|
||||
{
|
||||
lock_guard lock(this->request.current_lock);
|
||||
this->request.current = request;
|
||||
@ -195,4 +200,8 @@ void LicenseHelper::handle_request_failed(bool verbose, const std::string& error
|
||||
this->scheduled_request = this->last_request + next_request;
|
||||
if(verbose)
|
||||
logMessage(LOG_INSTANCE, strobf("Scheduling next check at {}").c_str(), format_time(this->scheduled_request));
|
||||
}
|
||||
|
||||
void LicenseHelper::callback_certificate_update(const license::WebCertificate &certificate) {
|
||||
serverInstance->setWebCertRoot(certificate.key, certificate.certificate, certificate.revision);
|
||||
}
|
@ -35,5 +35,6 @@ namespace license {
|
||||
|
||||
void do_request(bool /* verbose */);
|
||||
void handle_request_failed(bool /* verbose */, const std::string& /* error */);
|
||||
void callback_certificate_update(const license::WebCertificate&);
|
||||
};
|
||||
}
|
@ -45,7 +45,7 @@ if(!result && result.msg().find(ignore) == string::npos){
|
||||
#define RESIZE_COLUMN(tblName, rowName, size) up vote EXECUTE("Could not change column size", "ALTER TABLE " tblName " ALTER COLUMN " rowName " varchar(" size ")");
|
||||
|
||||
#define CURRENT_DATABASE_VERSION 11
|
||||
#define CURRENT_PERMISSION_VERSION 0
|
||||
#define CURRENT_PERMISSION_VERSION 1
|
||||
|
||||
#define CLIENT_UID_LENGTH "64"
|
||||
#define CLIENT_NAME_LENGTH "128"
|
||||
@ -517,6 +517,18 @@ bool SqlDataManager::update_permissions(std::string &error) {
|
||||
|
||||
perm_version(0);
|
||||
|
||||
case 0:
|
||||
result = sql::command(this->sql(), "DELETE FROM `permissions` WHERE `permId` = :permid", variable{":permid", "b_client_music_create"}).execute();
|
||||
if(!result) {
|
||||
LOG_SQL_CMD(result);
|
||||
return false;
|
||||
}
|
||||
result = sql::command(this->sql(), "DELETE FROM `permissions` WHERE `permId` = :permid", variable{":permid", "b_client_music_delete_own"}).execute();
|
||||
if(!result) {
|
||||
LOG_SQL_CMD(result);
|
||||
return false;
|
||||
}
|
||||
perm_version(1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ namespace ts {
|
||||
SqlDataManager();
|
||||
virtual ~SqlDataManager();
|
||||
|
||||
inline int get_database_version() const { return this->_database_version; }
|
||||
inline int get_permissions_version() const { return this->_database_version; }
|
||||
[[nodiscard]] inline int get_database_version() const { return this->_database_version; }
|
||||
[[nodiscard]] inline int get_permissions_version() const { return this->_database_version; }
|
||||
bool initialize(std::string&);
|
||||
void finalize();
|
||||
|
||||
|
@ -26,6 +26,11 @@ void MusicBotManager::adjustTickPool() {
|
||||
tick_music.setThreads(min(config::threads::music::execute_limit, bots * config::threads::music::execute_per_bot));
|
||||
}
|
||||
|
||||
void MusicBotManager::shutdown() {
|
||||
tick_music.shutdown();
|
||||
load_music.shutdown();
|
||||
}
|
||||
|
||||
MusicBotManager::MusicBotManager(const shared_ptr<server::TSServer>& server) : handle(server) { }
|
||||
|
||||
MusicBotManager::~MusicBotManager() { }
|
||||
|
@ -21,6 +21,7 @@ namespace ts {
|
||||
public:
|
||||
static threads::ThreadPool tick_music;
|
||||
static threads::ThreadPool load_music;
|
||||
static void shutdown();
|
||||
|
||||
static void adjustTickPool();
|
||||
|
||||
|
@ -77,7 +77,9 @@ namespace terminal {
|
||||
else if(cmd.lcommand == "memflush")
|
||||
handleCommandMemFlush(cmd);
|
||||
else if(cmd.lcommand == "statsreset")
|
||||
handleStatsReset(cmd);
|
||||
handleCommandStatsReset(cmd);
|
||||
else if(cmd.lcommand == "reload")
|
||||
handleCommandReload(cmd);
|
||||
else logError("Missing command " + cmd.command + "/" + cmd.line);
|
||||
}
|
||||
|
||||
@ -100,6 +102,7 @@ namespace terminal {
|
||||
bool handleCommandHelp(TerminalCommand& args){
|
||||
logMessage("§aAvariable commands:");
|
||||
logMessage(" §7- §eend §7| §eshutdown");
|
||||
logMessage(" §7- §ereload config");
|
||||
logMessage(" §7- §echat");
|
||||
logMessage(" §7- §einfo");
|
||||
logMessage(" §7- §epermgrant");
|
||||
@ -455,7 +458,7 @@ namespace terminal {
|
||||
}
|
||||
|
||||
|
||||
extern bool handleStatsReset(TerminalCommand& cmd) {
|
||||
extern bool handleCommandStatsReset(TerminalCommand& cmd) {
|
||||
serverInstance->properties()[property::SERVERINSTANCE_MONTHLY_TIMESTAMP] = 0;
|
||||
logMessage("Monthly statistics will be reset");
|
||||
return true;
|
||||
@ -493,5 +496,28 @@ namespace terminal {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool handleCommandReload(TerminalCommand& cmd) {
|
||||
if(cmd.larguments.size() < 1 || cmd.larguments[0] != "config") {
|
||||
logMessage("Invalid target. Available: config");
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<string> error;
|
||||
if(!serverInstance->reloadConfig(error, true)) {
|
||||
logError("Failed to reload instance ({}):", error.size());
|
||||
for(auto& msg : error)
|
||||
logError(" - {}", msg);
|
||||
} else if(!error.empty()) {
|
||||
logMessage("Reloaded successfully. Messages:");
|
||||
for(auto& msg : error)
|
||||
logMessage(" - {}", msg);
|
||||
} else {
|
||||
logMessage("Reloaded successfully.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -33,6 +33,8 @@ namespace terminal {
|
||||
|
||||
extern bool handleCommandPasswd(TerminalCommand&);
|
||||
|
||||
extern bool handleStatsReset(TerminalCommand&);
|
||||
extern bool handleCommandStatsReset(TerminalCommand&);
|
||||
|
||||
extern bool handleCommandReload(TerminalCommand&);
|
||||
}
|
||||
}
|
2
shared
2
shared
@ -1 +1 @@
|
||||
Subproject commit 2cae73c51ad8f70e37b6dac9ca7781c8eee2fb20
|
||||
Subproject commit 4d64f60f189ff15ccb1ad20fd439b545ef887c3a
|
Loading…
Reference in New Issue
Block a user