Updates for beta10

This commit is contained in:
WolverinDEV 2020-02-15 14:03:46 +01:00
parent 423f7a7303
commit 035f23ef23
19 changed files with 242 additions and 218 deletions

View File

@ -90,6 +90,8 @@ include_directories(${LIBEVENT_INCLUDE_DIRS})
include_directories(${StringVariable_INCLUDE_DIR})
add_definitions(-DINET -DINET6)
include_directories(/usr/local/mysql/include/)
add_subdirectory(shared/)
add_subdirectory(server/)
add_subdirectory(license/)

@ -1 +1 @@
Subproject commit 2c3f2a73372c068a9f3c5e44fc950291d56bb042
Subproject commit a6e1c3cf1c97dd45405b08ad05578ea3d5d89e4a

View File

@ -266,8 +266,6 @@ target_link_libraries(TeaSpeakServer
yaml-cpp
${LIBRARY_PATH_PROTOBUF}
#We're forsed to use boringssl caused by the fact that boringssl is already within webrtc!
#Require a so
sqlite3
@ -278,14 +276,15 @@ target_link_libraries(TeaSpeakServer
tomcrypt::static
tommath::static
mysqlclient.a
/usr/local/mysql/lib/libmysqlclient.a
#mysqlclient.a
jsoncpp_lib
${ed25519_LIBRARIES_STATIC}
${DataPipes_LIBRARIES_SHARED} # Also includes glib2.0
)
if (COMPILE_WEB_CLIENT)
target_link_libraries(TeaSpeakServer ffi)
target_link_libraries(TeaSpeakServer ${glib20_DIR}/lib/x86_64-linux-gnu/libffi.so.7 ${nice_DIR}/lib/libnice.so.10)
endif ()
include_directories(${LIBRARY_PATH}/boringssl/include/)
@ -294,7 +293,7 @@ target_link_libraries(TeaSpeakServer
openssl::crypto::shared
dl
z
)
)
set(DISABLE_JEMALLOC ON)
if (NOT DISABLE_JEMALLOC)

View File

@ -278,10 +278,11 @@ int main(int argc, char** argv) {
logConfig->vs_group_size = ts::config::log::vs_size;
logger::setup(logConfig);
threads::timer::function_log = [](const std::string& message, bool debug) {
auto msg = message.find('\n') == std::string::npos ? message : message.substr(0, message.find('\n'));
if(debug)
debugMessage(LOG_GENERAL, message);
debugMessage(LOG_GENERAL, msg);
else
logWarning(LOG_GENERAL, message);
logWarning(LOG_GENERAL, msg);
};
logger::updateLogLevels();

View File

@ -50,6 +50,10 @@ bool config::server::badges::allow_badges;
bool config::server::badges::allow_overwolf;
bool config::server::authentication::name;
bool config::server::clients::teamspeak;
bool config::server::clients::teaweb;
bool config::server::clients::teaspeak;
uint16_t config::voice::default_voice_port;
size_t config::voice::DefaultPuzzlePrecomputeSize;
bool config::server::delete_missing_icon_permissions;
@ -1261,6 +1265,27 @@ std::deque<std::shared_ptr<EntryBinding>> config::create_bindings() {
ADD_NOTE_RELOADABLE();
}
}
{
BIND_GROUP(clients);
{
CREATE_BINDING("teamspeak", FLAG_RELOADABLE);
BIND_BOOL(config::server::clients::teamspeak, true);
ADD_DESCRIPTION("Allow/disallow the TeamSpeak 3 client to join the server.");
ADD_NOTE_RELOADABLE();
}
{
CREATE_BINDING("teaweb", FLAG_RELOADABLE);
BIND_BOOL(config::server::clients::teaweb, true);
ADD_DESCRIPTION("Allow/disallow the TeaSpeak - Web client to join the server.");
ADD_NOTE_RELOADABLE();
}
{
CREATE_BINDING("teaspeak", FLAG_RELOADABLE);
BIND_BOOL(config::server::clients::teaspeak, true);
ADD_DESCRIPTION("Allow/disallow the TeaSpeak - Client to join the server.");
ADD_NOTE_RELOADABLE();
}
}
}
{
BIND_GROUP(web);

View File

@ -13,208 +13,212 @@
namespace YAML {
class Node;
}
namespace ts {
namespace config {
struct EntryBinding {
std::string key;
std::map<std::string, std::deque<std::string>> description;
uint8_t flags = 0;
namespace ts::config {
struct EntryBinding {
std::string key;
std::map<std::string, std::deque<std::string>> description;
uint8_t flags = 0;
int type = 0; /* 0 = unbound | 1 = string | 2 = number | 3 = boolean | 4 = user defined */
int bounded_by = 0; /* 0 = unbound | 1 = config | 2 = command line */
int type = 0; /* 0 = unbound | 1 = string | 2 = number | 3 = boolean | 4 = user defined */
int bounded_by = 0; /* 0 = unbound | 1 = config | 2 = command line */
std::function<std::deque<std::string>()> default_value;
std::function<std::string()> value_description;
std::function<void(YAML::Node&)> set_default;
std::function<void(YAML::Node&)> read_config;
std::function<void(const std::string&)> read_argument;
};
std::function<std::deque<std::string>()> default_value;
std::function<std::string()> value_description;
std::function<void(YAML::Node&)> set_default;
std::function<void(YAML::Node&)> read_config;
std::function<void(const std::string&)> read_argument;
};
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();
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 {
extern std::string url;
namespace sqlite {
extern std::string journal_mode;
extern std::string locking_mode;
extern std::string sync_mode;
}
namespace database {
extern std::string url;
namespace sqlite {
extern std::string journal_mode;
extern std::string locking_mode;
extern std::string sync_mode;
}
}
extern std::shared_ptr<license::License> license;
extern std::shared_ptr<license::License> license_original;
extern bool experimental_31;
extern std::string permission_mapping_file;
namespace binding {
extern bool enforce_default_voice_host;
extern std::string DefaultVoiceHost;
extern std::string DefaultWebHost;
extern std::string DefaultQueryHost;
extern std::string DefaultFileHost;
extern uint16_t DefaultQueryPort;
extern uint16_t DefaultFilePort;
}
namespace server {
extern std::string DefaultServerVersion;
extern std::string DefaultServerPlatform;
extern bool delete_old_bans;
extern bool delete_missing_icon_permissions;
extern LicenseType DefaultServerLicense;
extern bool strict_ut8_mode;
extern bool enable_teamspeak_weblist;
extern bool show_invisible_clients_as_online;
extern bool disable_ip_saving;
namespace badges {
extern bool allow_overwolf;
extern bool allow_badges;
}
extern std::shared_ptr<license::License> license;
extern std::shared_ptr<license::License> license_original;
extern bool experimental_31;
extern std::string permission_mapping_file;
namespace binding {
extern bool enforce_default_voice_host;
extern std::string DefaultVoiceHost;
extern std::string DefaultWebHost;
extern std::string DefaultQueryHost;
extern std::string DefaultFileHost;
extern uint16_t DefaultQueryPort;
extern uint16_t DefaultFilePort;
namespace authentication {
extern bool name;
}
namespace server {
extern std::string DefaultServerVersion;
extern std::string DefaultServerPlatform;
extern bool delete_old_bans;
extern bool delete_missing_icon_permissions;
extern LicenseType DefaultServerLicense;
extern bool strict_ut8_mode;
extern bool enable_teamspeak_weblist;
extern bool show_invisible_clients_as_online;
extern bool disable_ip_saving;
namespace badges {
extern bool allow_overwolf;
extern bool allow_badges;
}
namespace authentication {
extern bool name;
}
extern ssize_t max_virtual_server;
namespace clients {
extern bool teamspeak;
extern bool teaspeak;
extern bool teaweb;
}
namespace voice {
extern size_t DefaultPuzzlePrecomputeSize;
extern int RsaPuzzleLevel;
extern bool enforce_coocie_handshake;
extern ssize_t max_virtual_server;
}
namespace voice {
extern size_t DefaultPuzzlePrecomputeSize;
extern int RsaPuzzleLevel;
extern bool enforce_coocie_handshake;
extern bool notifyMuted;
extern int connectLimit;
extern int clientConnectLimit;
extern bool notifyMuted;
extern int connectLimit;
extern int clientConnectLimit;
extern bool suppress_myts_warnings;
extern uint16_t default_voice_port;
extern bool suppress_myts_warnings;
extern uint16_t default_voice_port;
extern bool warn_on_permission_editor;
extern bool allow_session_reinitialize;
extern bool warn_on_permission_editor;
extern bool allow_session_reinitialize;
}
namespace geo {
extern std::string countryFlag;
extern bool staticFlag;
extern std::string mappingFile;
extern geoloc::ProviderType type;
extern bool vpn_block;
extern std::string vpn_file;
}
namespace query {
extern std::string motd;
extern std::string newlineCharacter;
extern int sslMode;
namespace ssl {
extern std::string keyFile;
extern std::string certFile;
}
}
namespace geo {
extern std::string countryFlag;
extern bool staticFlag;
namespace music {
extern bool enabled;
extern std::string command_prefix;
}
extern std::string mappingFile;
extern geoloc::ProviderType type;
namespace messages {
extern std::string serverStopped;
extern std::string applicationStopped;
extern std::string applicationCrashed;
extern bool vpn_block;
extern std::string vpn_file;
}
extern std::string idle_time_exceeded;
namespace query {
extern std::string motd;
extern std::string newlineCharacter;
extern std::string mute_notify_message;
extern std::string unmute_notify_message;
extern int sslMode;
namespace ssl {
extern std::string keyFile;
extern std::string certFile;
}
extern std::string kick_invalid_hardware_id;
extern std::string kick_invalid_badges;
extern std::string kick_invalid_command;
extern std::string kick_vpn;
extern std::string teamspeak_permission_editor;
namespace shutdown {
extern std::string scheduled;
extern std::string interval;
extern std::string now;
extern std::string canceled;
extern std::vector<std::pair<std::chrono::seconds, std::string>> intervals;
}
namespace music {
extern bool enabled;
extern std::string command_prefix;
extern std::string song_announcement;
}
namespace messages {
extern std::string serverStopped;
extern std::string applicationStopped;
extern std::string applicationCrashed;
namespace timeout {
extern std::string packet_resend_failed;
extern std::string connection_reinitialized;
}
}
extern std::string idle_time_exceeded;
namespace web {
extern bool activated;
extern std::string mute_notify_message;
extern std::string unmute_notify_message;
namespace ssl {
/* servername; private key file; public key file*/
extern std::deque<std::tuple<std::string, std::string, std::string>> certificates;
}
extern std::string kick_invalid_hardware_id;
extern std::string kick_invalid_badges;
extern std::string kick_invalid_command;
extern uint16_t webrtc_port_min;
extern uint16_t webrtc_port_max;
extern std::deque<std::string> ice_servers;
extern bool enable_upnp;
}
extern std::string kick_vpn;
namespace threads {
extern size_t ticking;
extern std::string teamspeak_permission_editor;
namespace voice {
extern size_t execute_per_server;
extern size_t execute_limit;
namespace shutdown {
extern std::string scheduled;
extern std::string interval;
extern std::string now;
extern std::string canceled;
extern size_t events_per_server;
extern size_t io_min;
extern size_t io_per_server;
extern size_t io_limit;
extern std::vector<std::pair<std::chrono::seconds, std::string>> intervals;
}
extern bool bind_io_thread_to_kernel_thread;
}
namespace music {
extern std::string song_announcement;
}
namespace timeout {
extern std::string packet_resend_failed;
extern std::string connection_reinitialized;
}
namespace music {
extern size_t execute_per_bot;
extern size_t execute_limit;
}
namespace web {
extern bool activated;
namespace ssl {
/* servername; private key file; public key file*/
extern std::deque<std::tuple<std::string, std::string, std::string>> certificates;
}
extern uint16_t webrtc_port_min;
extern uint16_t webrtc_port_max;
extern std::deque<std::string> ice_servers;
extern bool enable_upnp;
extern size_t io_loops;
}
namespace threads {
extern size_t ticking;
namespace voice {
extern size_t execute_per_server;
extern size_t execute_limit;
extern size_t events_per_server;
extern size_t io_min;
extern size_t io_per_server;
extern size_t io_limit;
extern bool bind_io_thread_to_kernel_thread;
}
namespace music {
extern size_t execute_per_bot;
extern size_t execute_limit;
}
namespace web {
extern size_t io_loops;
}
}
namespace log {
extern std::string path;
extern size_t vs_size;
extern spdlog::level::level_enum logfileLevel;
extern bool logfileColored;
extern spdlog::level::level_enum terminalLevel;
}
extern std::string crash_path;
}
namespace log {
extern std::string path;
extern size_t vs_size;
extern spdlog::level::level_enum logfileLevel;
extern bool logfileColored;
extern spdlog::level::level_enum terminalLevel;
}
extern std::string crash_path;
}

View File

@ -87,7 +87,6 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
auto permissions = this->calculate_permissions({
permission::i_client_talk_power,
permission::b_client_is_priority_speaker,
permission::b_client_ignore_antiflood,
permission::i_channel_view_power,
permission::b_channel_ignore_view_power
@ -95,15 +94,12 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
permission::v2::PermissionFlaggedValue
permission_talk_power{0, false},
permission_priority_speaker{0, false},
permission_ignore_antiflood{0, false},
permission_channel_view_power{0, false},
permission_channel_ignore_view_power{0, false};
for(const auto& perm : permissions) {
if(perm.first == permission::i_client_talk_power)
permission_talk_power = perm.second;
else if(perm.first == permission::b_client_is_priority_speaker)
permission_priority_speaker = perm.second;
else if(perm.first == permission::b_client_ignore_antiflood)
permission_ignore_antiflood = perm.second;
else if(perm.first == permission::i_channel_view_power)
@ -161,9 +157,10 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
}
}
auto pSpeaker = permission_priority_speaker.has_value && permission_priority_speaker.value > 0;
if(properties()[property::CLIENT_IS_PRIORITY_SPEAKER].as<bool>() != pSpeaker){
properties()[property::CLIENT_IS_PRIORITY_SPEAKER] = pSpeaker;
auto pSpeaker = this->clientPermissions ? this->clientPermissions->channel_permission(permission::b_client_is_priority_speaker, this->getChannelId()) : permission::v2::empty_channel_permission;
auto pSpeakerGranted = permission::v2::permission_granted(1, {pSpeaker.values.value, pSpeaker.flags.value_set});
if(properties()[property::CLIENT_IS_PRIORITY_SPEAKER].as<bool>() != pSpeakerGranted){
properties()[property::CLIENT_IS_PRIORITY_SPEAKER] = pSpeakerGranted;
notifyList.emplace_back(property::CLIENT_IS_PRIORITY_SPEAKER);
}

View File

@ -44,9 +44,9 @@ command_result ConnectedClient::handleCommandChannelGetDescription(Command &cmd)
assert(channel);
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_ignore_description_view_power, channel->channelId()))) {
auto view_power = this->calculate_permission(permission::i_channel_needed_description_view_power, channel->channelId());
if(!channel->permission_granted(permission::i_channel_description_view_power, view_power, false))
command_result{permission::i_channel_description_view_power};
auto view_power = this->calculate_permission(permission::i_channel_description_view_power, channel->channelId());
if(!channel->permission_granted(permission::i_channel_needed_description_view_power, view_power, false))
return command_result{permission::i_channel_description_view_power};
}
this->sendChannelDescription(channel, true);
@ -604,7 +604,7 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
}
}
if(created_total >= this->server->properties()[property::VIRTUALSERVER_MAX_CHANNELS].as<uint64_t>())
if(this->server && created_total >= this->server->properties()[property::VIRTUALSERVER_MAX_CHANNELS].as<uint64_t>())
return command_result{error::channel_limit_reached};
auto max_channels = this->calculate_permission(permission::i_client_max_channels, 0, false, permission_cache);

View File

@ -819,10 +819,8 @@ command_result QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
if(hash.empty()) return command_result{error::parameter_invalid, "Invalid hash (not present)"};
debugMessage(this->getServerId(), "Serversnapshot calculated hash: {}", hash);
bool mapping = cmd.hasParm("mapping");
cmd.disableParm("mapping");
bool ignore_hash = cmd.hasParm("ignorehash");
cmd.disableParm("ignorehash");
cmd.clear_parameters();
cmd.pop_bulk();
auto str = cmd.build().substr(strlen("serversnapshotdeploy "));

View File

@ -76,10 +76,8 @@ void PuzzleManager::generatePuzzle() {
rndNum(&puzzle->n, 64);
puzzle->level = ts::config::voice::RsaPuzzleLevel;
if(!solvePuzzle(puzzle)) {
//logFatal("RSA fail at " + to_string(this->cached.size()));
if(!solvePuzzle(puzzle))
goto generate_new;
}
auto valid_x = mp_unsigned_bin_size(&puzzle->x) <= 64;
auto valid_n = mp_unsigned_bin_size(&puzzle->n) <= 64;

View File

@ -12,11 +12,11 @@ namespace ts {
namespace protocol {
struct Puzzle {
mp_int x{};
mp_int n{};
int level = 0;
mp_int x;
mp_int n;
int level;
mp_int result{};
mp_int result;
uint8_t data_x[64];
uint8_t data_n[64];

View File

@ -74,10 +74,10 @@ namespace ts {
virtual void tick(const std::chrono::system_clock::time_point &time) override;
void handlePacketCommand(const pipes::buffer_view&);
void handlePacketAck(const protocol::IncomingClientPacketParser&);
void handlePacketVoice(const protocol::IncomingClientPacketParser&);
void handlePacketPing(const protocol::IncomingClientPacketParser&);
void handlePacketInit(const protocol::IncomingClientPacketParser&);
void handlePacketAck(const protocol::ClientPacketParser&);
void handlePacketVoice(const protocol::ClientPacketParser&);
void handlePacketPing(const protocol::ClientPacketParser&);
void handlePacketInit(const protocol::ClientPacketParser&);
//Handshake helpers

View File

@ -79,7 +79,7 @@ void VoiceClientConnection::handle_incoming_datagram(const pipes::buffer_view& b
#endif
#endif
IncomingClientPacketParser packet_parser{buffer};
ClientPacketParser packet_parser{buffer};
if(!packet_parser.valid()) {
logTrace(this->client->getServerId(), "{} Received invalid packet. Dropping.", CLIENT_STR_LOG_PREFIX_(this->client));
return;
@ -140,8 +140,8 @@ void VoiceClientConnection::handle_incoming_datagram(const pipes::buffer_view& b
}
decrypt_result = this->crypt_handler.decrypt(
data + IncomingClientPacketParser::kHeaderOffset, IncomingClientPacketParser::kHeaderLength,
data + IncomingClientPacketParser::kPayloadOffset, packet_parser.payload_length(),
data + ClientPacketParser::kHeaderOffset, ClientPacketParser::kHeaderLength,
data + ClientPacketParser::kPayloadOffset, packet_parser.payload_length(),
data,
crypt_key, crypt_nonce,
error
@ -214,7 +214,7 @@ void VoiceClientConnection::handle_incoming_datagram(const pipes::buffer_view& b
}
bool VoiceClientConnection::verify_encryption(const pipes::buffer_view &buffer /* incl. mac etc */) {
IncomingClientPacketParser packet_parser{buffer};
ClientPacketParser packet_parser{buffer};
if(!packet_parser.valid() || !packet_parser.is_encrypted()) return false;
assert(packet_parser.type() >= 0 && packet_parser.type() < this->incoming_generation_estimators.size());

View File

@ -61,7 +61,7 @@ ts::command_result VoiceClient::handleCommandClientInitIv(Command& command) {
state_lock.lock();
this->state = ConnectionState::INIT_HIGH;
} else if(this->state == ConnectionState::INIT_HIGH) {
logTrace(this->getServerId(), "{} Received a duplicated initiv. It seems like our initivexpand2 hasn't yet reached the client. The acknowledge handle should handle this issue for us.", CLIENT_STR_LOG_PREFIX);
logTrace(this->getServerId(), "{} Received a duplicated initiv. It seems like our initivexpand2 hasn't yet reached the client. The acknowledge handler should handle this issue for us.", CLIENT_STR_LOG_PREFIX);
return command_result{error::ok};
} else {
this->state = ConnectionState::INIT_HIGH;
@ -73,6 +73,9 @@ ts::command_result VoiceClient::handleCommandClientInitIv(Command& command) {
this->crypto.protocol_encrypted = false;
bool use_teaspeak = command.hasParm("teaspeak");
if(use_teaspeak ? !config::server::clients::teaspeak : !config::server::clients::teamspeak)
return command_result{error::client_type_is_not_allowed};
if(use_teaspeak) {
debugMessage(this->getServerId(), "{} Client using TeaSpeak with auth type {}", CLIENT_STR_LOG_PREFIX, command["verify_type"].string());
this->properties()[property::CLIENT_TYPE_EXACT] = ClientType::CLIENT_TEASPEAK;

View File

@ -12,7 +12,7 @@ using namespace ts::protocol;
//#define PKT_LOG_PING
/* should never happen! */
void VoiceClient::handlePacketInit(const ts::protocol::IncomingClientPacketParser &) {}
void VoiceClient::handlePacketInit(const ts::protocol::ClientPacketParser &) {}
//TODO Packet handlers -> move back to voice client?
void VoiceClient::handlePacketCommand(const pipes::buffer_view& command_string) {
@ -42,8 +42,7 @@ void VoiceClient::handlePacketCommand(const pipes::buffer_view& command_string)
result.release_details();
}
void VoiceClient::handlePacketPing(const protocol::IncomingClientPacketParser& packet) {
(void) packet.payload().length();
void VoiceClient::handlePacketPing(const protocol::ClientPacketParser& packet) {
if (packet.type() == protocol::PONG) {
if(packet.payload_length() < 2) return;
@ -53,7 +52,7 @@ void VoiceClient::handlePacketPing(const protocol::IncomingClientPacketParser& p
logMessage(this->getServerId(), "{}[Ping] Got a valid pong for ping {}. Required time: {}", CLIENT_STR_LOG_PREFIX, id, duration_cast<microseconds>(system_clock::now() - this->lastPingRequest).count() / 1000.f);
#endif
this->lastPingResponse = system_clock::now();
this->ping = duration_cast<milliseconds>(this->lastPingResponse - this->lastPingRequest);
this->ping = std::chrono::duration_cast<std::chrono::milliseconds>(this->lastPingResponse - this->lastPingRequest);
}
#ifdef PKT_LOG_PING
else {
@ -73,7 +72,7 @@ void VoiceClient::handlePacketPing(const protocol::IncomingClientPacketParser& p
this->connection->sendPacket(pkt);
}
void VoiceClient::handlePacketVoice(const protocol::IncomingClientPacketParser& packet) {
void VoiceClient::handlePacketVoice(const protocol::ClientPacketParser& packet) {
if (packet.type() == protocol::VOICE) {
SpeakingClient::handlePacketVoice(packet.payload(), (packet.flags() & PacketFlag::Compressed) > 0, (packet.flags() & PacketFlag::Fragmented) > 0);
} else if(packet.type() == protocol::VOICE_WHISPER) {
@ -81,8 +80,8 @@ void VoiceClient::handlePacketVoice(const protocol::IncomingClientPacketParser&
}
}
void VoiceClient::handlePacketAck(const protocol::IncomingClientPacketParser& packet) {
string error;
void VoiceClient::handlePacketAck(const protocol::ClientPacketParser& packet) {
string error{};
if(!this->connection->acknowledge_handler.process_acknowledge(packet.type(), packet.payload(), error))
debugMessage(this->getServerId(), "{} Failed to handle acknowledge: {}", CLIENT_STR_LOG_PREFIX, error);
}

View File

@ -1,5 +1,3 @@
#include <tommath.h>
#include <misc/endianness.h>
#include <Definitions.h>
#include <log/LogUtils.h>
#include "../../InstanceHandler.h"

View File

@ -638,6 +638,9 @@ bool WebClient::disconnect(const std::string &reason) {
}
command_result WebClient::handleCommandClientInit(Command &command) {
if(!config::server::clients::teaweb)
return command_result{error::client_type_is_not_allowed};
return SpeakingClient::handleCommandClientInit(command);
}

View File

@ -5,15 +5,12 @@ commands ftinit* activate again!
#Sevrer
##Done
##Bugs
- Default channel visibility!
##TODO
- check client version sign
- server tmp password manager
- snapshot deploy channel passwords (https://hashcat.net/forum/thread-4437-post-25511.html)
##Future
##Feature
- Ghost clients / interception system / client hide
- Permanent|Temp privileges keys
- permissions system improvement

2
shared

@ -1 +1 @@
Subproject commit 3f57ad4678dd1ef1c72a066cc4fdd7bedb84c172
Subproject commit 97fd71b69a88a189d3d24a527bea1c8442810e07