Fix crash in Twitter populateRoster with Swiften3; Commite spectru2_manager changes

This commit is contained in:
Jan Kaluza 2016-01-02 20:30:26 +01:00
parent a63920e965
commit bd9219797e
8 changed files with 329 additions and 67 deletions

View file

@ -85,6 +85,11 @@ TwitterPlugin::TwitterPlugin(Config *config, Swift::SimpleEventLoop *loop, Stora
tweet_timer->start();
message_timer->start();
#if HAVE_SWIFTEN_3
cryptoProvider = boost::shared_ptr<Swift::CryptoProvider>(Swift::PlatformCryptoProvider::create());
#endif
LOG4CXX_INFO(logger, "Starting the plugin.");
}
@ -438,7 +443,7 @@ bool TwitterPlugin::setTwitterMode(const std::string user, int m)
//int type;
std::string s_m = std::string(1,m+'0');
LOG4CXX_ERROR(logger, "Storing mode " << m <<" for user " << user)
LOG4CXX_INFO(logger, "Storing mode " << m <<" for user " << user)
storagebackend->updateUserSetting((long)info.id, MODE, s_m);
return true;
}

View file

@ -1,15 +1,15 @@
cmake_minimum_required(VERSION 2.6)
FILE(GLOB SRC *.cpp *.c)
ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../libtransport/Config.cpp ../../libtransport/Util.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc)
ADD_EXECUTABLE(spectrum2_manager ${SRC})
ADD_DEPENDENCIES(spectrum2_manager pb)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1)
target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES})
target_link_libraries(spectrum2_manager transport ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES})
if(APPLE)
target_link_libraries(spectrum2_manager ${APPLE_FRAMEWORKS})
target_link_libraries(spectrum2_manager transport ${APPLE_FRAMEWORKS})
endif()
INSTALL(TARGETS spectrum2_manager RUNTIME DESTINATION bin)

View file

@ -142,7 +142,7 @@ int main(int argc, char **argv)
return restart_instances(&config);
}
else if (command[0] == "server") {
Server server(&config);
Server server(&config, config_file);
if (server.start() == false) {
std::cerr << "Can't set up server handler.\n";
return 1;

View file

@ -33,8 +33,15 @@ bool ManagerConfig::load(const std::string &configfile, boost::program_options::
("service.admin_password", value<std::string>()->default_value(""), "Administrator password.")
("service.port", value<int>()->default_value(8081), "Web interface port.")
("service.config_directory", value<std::string>()->default_value("/etc/spectrum2/transports/"), "Directory with spectrum2 configuration files. One .cfg file per one instance")
("service.data_dir", value<std::string>()->default_value("/var/lib/spectrum2_manager"), "Directory to store Spectrum 2 manager data")
("service.data_dir", value<std::string>()->default_value("/var/lib/spectrum2_manager/html"), "Directory to store Spectrum 2 manager data")
("servers.server", value<std::vector<std::string> >()->multitoken(), "Server.")
("database.type", value<std::string>()->default_value("none"), "Database type.")
("database.database", value<std::string>()->default_value("/var/lib/spectrum2/$jid/database.sql"), "Database used to store data")
("database.server", value<std::string>()->default_value("localhost"), "Database server.")
("database.user", value<std::string>()->default_value(""), "Database user.")
("database.password", value<std::string>()->default_value(""), "Database Password.")
("database.port", value<int>()->default_value(0), "Database port.")
("database.prefix", value<std::string>()->default_value(""), "Prefix of tables in database")
;
store(parse_config_file(ifs, opts), m_variables);

View file

@ -51,7 +51,7 @@ static void _event_handler(struct mg_connection *nc, int ev, void *p) {
static_cast<Server *>(nc->mgr->user_data)->event_handler(nc, ev, p);
}
Server::Server(ManagerConfig *config) {
Server::Server(ManagerConfig *config, const std::string &config_file) {
srand((unsigned) time(0));
m_config = config;
m_user = CONFIG_STRING(m_config, "service.admin_username");
@ -80,10 +80,29 @@ Server::Server(ManagerConfig *config) {
footer.read(&m_footer[0], m_footer.size());
footer.close();
}
m_storageCfg = new Config();
m_storageCfg->load(config_file);
std::string error;
m_storage = StorageBackend::createBackend(m_storageCfg, error);
if (m_storage == NULL) {
std::cerr << "Error creating StorageBackend! " << error << "\n";
std::cerr << "Registering new Spectrum 2 manager users won't work" << "\n";
}
else if (!m_storage->connect()) {
delete m_storage;
m_storage = NULL;
std::cerr << "Can't connect to database!\n";
}
}
Server::~Server() {
mg_mgr_free(&m_mgr);
if (m_storage) {
delete m_storage;
}
delete m_storageCfg;
}
bool Server::start() {
@ -95,7 +114,16 @@ bool Server::start() {
}
bool Server::check_password(const std::string &user, const std::string &password) {
return (m_user == user && m_password == password);
if (m_user == user && m_password == password) {
return true;
}
UserInfo info;
if (m_storage && m_storage->getUser(user, info) == true && info.password == password) {
return true;
}
return false;
}
// Allocate new session object
@ -192,6 +220,25 @@ void Server::print_html(struct mg_connection *conn, struct http_message *hm, con
(int) html.size() + m_header.size() + m_footer.size(), m_header.c_str(), html.c_str(), m_footer.c_str());
}
std::string Server::send_command(const std::string &jid, const std::string &cmd) {
Swift::SimpleEventLoop eventLoop;
Swift::BoostNetworkFactories networkFactories(&eventLoop);
ask_local_server(m_config, networkFactories, jid, cmd);
eventLoop.runUntilEvents();
struct timeval td_start,td_end;
float elapsed = 0;
gettimeofday(&td_start, NULL);
time_t started = time(NULL);
while(get_response().empty() && td_end.tv_sec - td_start.tv_sec < 1) {
gettimeofday(&td_end, NULL);
eventLoop.runOnce();
}
return get_response();
}
void Server::serve_onlineusers(struct mg_connection *conn, struct http_message *hm) {
std::string html;
std::string jid = get_http_var(hm, "jid");
@ -244,18 +291,80 @@ void Server::serve_cmd(struct mg_connection *conn, struct http_message *hm) {
print_html(conn, hm, html);
}
void Server::serve_users_add(struct mg_connection *conn, struct http_message *hm) {
std::string user = get_http_var(hm, "user");
std::string password = get_http_var(hm, "password");
void Server::serve_start(struct mg_connection *conn, struct http_message *hm) {
std::string html;
std::string jid = get_http_var(hm, "jid");
if (!user.empty() && !password.empty()) {
UserInfo info;
info.jid = user;
info.password = password;
if (m_storage) {
m_storage->setUser(info);
}
}
redirect_to(conn, hm, "/users");
}
void Server::serve_users(struct mg_connection *conn, struct http_message *hm) {
std::string html = "<h2>Spectrum 2 manager users</h2>";
html += "<p>Here, you can add new users who will have access to this web interface. "
"These users will be able to register new accounts on all Spectrum 2 instances "
"running on these server. They won't be able to change any Spectrum 2 instance "
"configuration influencing other users.</p>";
if (!m_storage) {
print_html(conn, hm, html);
return;
}
html += "<form action=\"/users/add\" class=\"basic-grey\" method=\"POST\"> \
<h1>Add user \
<span>Add new user to Spectrum 2 manager web interface.</span> \
</h1> \
<label> \
<span>Username:</span> \
<input type=\"text\" id=\"user\" name=\"user\"placeholder=\"Username\"></textarea> \
</label> \
<label><span>Password:</span> \
<input type=\"password\" id=\"password\" name=\"password\" placeholder=\"Password\"></textarea> \
</label> \
<label> \
<span>&nbsp;</span> \
<input type=\"submit\" class=\"button\" value=\"Add user\" />\
</label> \
</form><br/>";
std::vector<std::string> users;
m_storage->getUsers(users);
html += "<table><tr><th>User<th>Action</th></tr>";
BOOST_FOREACH(std::string &jid, users) {
html += "<tr>";
html += "<td><a href=\"/users?jid=" + jid + "\">" + jid + "</a></td>";
html += "<td> </td>";
html += "</tr>";
}
html += "</table>";
start_instances(m_config, jid);
html += "<b>" + get_response() + "</b><br/><a href=\"/\">Back to main page</a>";
html += "</body></html>";
print_html(conn, hm, html);
}
void Server::serve_stop(struct mg_connection *conn, struct http_message *hm) {
void Server::serve_instances_start(struct mg_connection *conn, struct http_message *hm) {
std::string html;
std::string jid = get_http_var(hm, "jid");
if (jid.empty()) {
redirect_to(conn, hm, "/");
return;
}
start_instances(m_config, jid);
html += "<h2>Starting Spectrum 2 instance</h2>";
html += "<b>" + get_response() + "</b><br/><a href=\"/\">Back to main page</a>";
print_html(conn, hm, html);
}
void Server::serve_instances_stop(struct mg_connection *conn, struct http_message *hm) {
std::string html;
std::string jid = get_http_var(hm, "jid");
@ -264,44 +373,154 @@ void Server::serve_stop(struct mg_connection *conn, struct http_message *hm) {
html += "</body></html>";
print_html(conn, hm, html);
}
void Server::serve_root(struct mg_connection *conn, struct http_message *hm) {
std::vector<std::string> list = show_list(m_config, false);
std::string html = "<h2>List of instances</h2>";
if (list.empty()) {
html += "<p>There are no Spectrum 2 instances yet. You can create new instance by adding configuration files into <pre>/etc/spectrum2/transports</pre> directory. You can then maintain the Spectrum 2 instance here.</p>";
void Server::serve_instance(struct mg_connection *conn, struct http_message *hm, const std::string &jid) {
std::string html = "<h2>Spectrum 2 instance: " + jid + "</h2>";
print_html(conn, hm, html);
}
void Server::serve_instances_unregister(struct mg_connection *conn, struct http_message *hm) {
}
void Server::serve_instances_register(struct mg_connection *conn, struct http_message *hm) {
std::string instance = get_http_var(hm, "instance");
if (!instance.empty()) {
serve_instance(conn, hm, instance);
return;
}
std::string jid = get_http_var(hm, "jid");
std::string uin = get_http_var(hm, "uin");
std::string password = get_http_var(hm, "password");
Server:session *session = get_session(hm);
UserInfo info;
m_storage->getUser(session->user, info);
if (uin.empty() || password.empty()) {
std::string html = "<h2>Register Spectrum 2 instance</h2>";
html += "<form action=\"/instances/register\" class=\"basic-grey\" method=\"POST\"> \
<h1>Register Spectrum 2 instance \
<span>Write the Slack team name, 3rd-party network username and password.</span> \
</h1> \
<label> \
<span>Slack team name:</span> \
<input type=\"text\" id=\"jid\" name=\"jid\"placeholder=\"Slack team name\"></textarea> \
</label> \
<label> \
<span>3rd-party network username:</span> \
<input type=\"text\" id=\"uin\" name=\"uin\"placeholder=\"3rd-party network username\"></textarea> \
</label> \
<label><span>Password:</span> \
<input type=\"password\" id=\"password\" name=\"password\" placeholder=\"3rd-party network password\"></textarea> \
</label> \
<label> \
<span>&nbsp;</span> \
<input type=\"submit\" class=\"button\" value=\"Register\" />\
</label> \
</form><br/>";
print_html(conn, hm, html);
}
else {
html += "<table><tr><th>JID<th>Status</th><th>Command</th><th>Run command</th></tr>";
BOOST_FOREACH(std::string &instance, list) {
html += "<tr>";
html += "<td><a href=\"/onlineusers?jid=" + instance + "\">" + instance + "</a></td>";
Swift::SimpleEventLoop eventLoop;
Swift::BoostNetworkFactories networkFactories(&eventLoop);
ask_local_server(m_config, networkFactories, instance, "status");
eventLoop.runUntilEvents();
while(get_response().empty()) {
eventLoop.runUntilEvents();
}
html += "<td>" + get_response() + "</td>";
if (get_response().find("Running") == 0) {
html += "<td><a href=\"/stop?jid=" + instance + "\">Stop</a></td>";
html += "<td><form action=\"/cmd\">";
html += "<input type=\"hidden\" name=\"jid\" value=\"" + instance + "\"></input>";
html += "<input type=\"text\" name=\"cmd\"></input>";
html += "<input type=\"submit\" value=\"Run\"></input>";
html += "</form></td>";
}
else {
html += "<td><a href=\"/start?jid=" + instance + "\">Start</a></td>";
html += "<td></td>";
}
html += "</tr>";
std::string response = send_command(jid, "register " + jid + " " + uin + " " + password);
if (!response.empty()) {
std::string value = jid;
int type = (int) TYPE_STRING;
m_storage->updateUserSetting(info.id, jid, value);
}
redirect_to(conn, hm, "/instances");
}
html += "</table>";
}
void Server::serve_instances(struct mg_connection *conn, struct http_message *hm) {
std::string jid = get_http_var(hm, "jid");
if (!jid.empty()) {
serve_instance(conn, hm, jid);
return;
}
std::vector<std::string> list = show_list(m_config, false);
std::string html = "<h2>List of Spectrum 2 instances</h2>";
Server:session *session = get_session(hm);
if (session->admin) {
if (list.empty()) {
html += "<p>There are no Spectrum 2 instances yet. You can create new instance by adding configuration files into <pre>/etc/spectrum2/transports</pre> directory. You can then maintain the Spectrum 2 instance here.</p>";
}
else {
html += "<table><tr><th>Hostname<th>Status</th><th>Command</th><th>Run command</th></tr>";
BOOST_FOREACH(std::string &instance, list) {
html += "<tr>";
html += "<td><a href=\"/instances?jid=" + instance + "\">" + instance + "</a></td>";
std::string response = send_command(instance, "status");
if (response.empty()) {
response = "Cannot get the server status";
}
html += "<td>" + response + "</td>";
if (response.find("Running") == 0) {
html += "<td><a href=\"/instances/stop?jid=" + instance + "\">Stop</a></td>";
html += "<td><form action=\"/cmd\">";
html += "<input type=\"hidden\" name=\"jid\" value=\"" + instance + "\"></input>";
html += "<input type=\"text\" name=\"cmd\"></input>";
html += "<input type=\"submit\" value=\"Run\"></input>";
html += "</form></td>";
}
else {
html += "<td><a href=\"/instances/start?jid=" + instance + "\">Start</a></td>";
html += "<td></td>";
}
html += "</tr>";
}
html += "</table>";
}
}
else {
UserInfo info;
m_storage->getUser(session->user, info);
if (list.empty()) {
html += "<p>There are no Spectrum 2 instances yet.</p>";
}
else {
html += "<table><tr><th>Hostname<th>Status</th><th>Action</th></tr>";
BOOST_FOREACH(std::string &instance, list) {
html += "<tr>";
html += "<td><a href=\"/instances?jid=" + instance + "\">" + instance + "</a></td>";
std::string response = send_command(instance, "status");
if (response.empty()) {
response = "Cannot get the server status";
}
html += "<td>" + response + "</td>";
if (response.find("Running") == 0) {
std::string value = "";
int type = (int) TYPE_STRING;
m_storage->getUserSetting(info.id, instance, type, value);
if (!value.empty()) {
html += "<td><a href=\"/instances/unregister?instance=" + instance + "\">Unregister</a></td>";
}
else {
html += "<td><a href=\"/instances/register?instance=" + instance + "\">Register</a></td>";
}
}
else {
html += "<td>No available action</td>";
}
html += "</tr>";
}
html += "</table>";
}
}
print_html(conn, hm, html);
}
@ -318,15 +537,25 @@ void Server::event_handler(struct mg_connection *conn, int ev, void *p) {
} else if (mg_vcmp(&hm->uri, "/authorize") == 0) {
authorize(conn, hm);
} else if (mg_vcmp(&hm->uri, "/") == 0) {
serve_root(conn, hm);
serve_instances(conn, hm);
} else if (mg_vcmp(&hm->uri, "/instances") == 0) {
serve_instances(conn, hm);
} else if (mg_vcmp(&hm->uri, "/onlineusers") == 0) {
serve_onlineusers(conn, hm);
} else if (mg_vcmp(&hm->uri, "/cmd") == 0) {
serve_cmd(conn, hm);
} else if (mg_vcmp(&hm->uri, "/start") == 0) {
serve_start(conn, hm);
} else if (mg_vcmp(&hm->uri, "/stop") == 0) {
serve_stop(conn, hm);
} else if (mg_vcmp(&hm->uri, "/instances/start") == 0) {
serve_instances_start(conn, hm);
} else if (mg_vcmp(&hm->uri, "/instances/stop") == 0) {
serve_instances_stop(conn, hm);
} else if (mg_vcmp(&hm->uri, "/instances/register") == 0) {
serve_instances_register(conn, hm);
} else if (mg_vcmp(&hm->uri, "/instances/unregister") == 0) {
serve_instances_unregister(conn, hm);
} else if (mg_vcmp(&hm->uri, "/users") == 0) {
serve_users(conn, hm);
} else if (mg_vcmp(&hm->uri, "/users/add") == 0) {
serve_users_add(conn, hm);
} else {
mg_serve_http(conn, hm, s_http_server_opts);
}

View file

@ -31,6 +31,14 @@
#include "mongoose.h"
#include "managerconfig.h"
#include "transport/Config.h"
#include "transport/SQLite3Backend.h"
#include "transport/MySQLBackend.h"
#include "transport/PQXXBackend.h"
#include "transport/StorageBackend.h"
using namespace Transport;
class Server {
public:
struct session {
@ -42,7 +50,7 @@ class Server {
};
/// Constructor.
Server(ManagerConfig *config);
Server(ManagerConfig *config, const std::string &config_file);
/// Destructor
virtual ~Server();
@ -52,12 +60,18 @@ class Server {
void event_handler(struct mg_connection *nc, int ev, void *p);
private:
void serve_root(struct mg_connection *conn, struct http_message *hm);
void serve_start(struct mg_connection *conn, struct http_message *hm);
void serve_stop(struct mg_connection *conn, struct http_message *hm);
void serve_instance(struct mg_connection *conn, struct http_message *hm, const std::string &jid);
void serve_instances(struct mg_connection *conn, struct http_message *hm);
void serve_instances_start(struct mg_connection *conn, struct http_message *hm);
void serve_instances_stop(struct mg_connection *conn, struct http_message *hm);
void serve_instances_register(struct mg_connection *conn, struct http_message *hm);
void serve_instances_unregister(struct mg_connection *conn, struct http_message *hm);
void serve_users(struct mg_connection *conn, struct http_message *hm);
void serve_users_add(struct mg_connection *conn, struct http_message *hm);
void serve_onlineusers(struct mg_connection *conn, struct http_message *hm);
void serve_cmd(struct mg_connection *conn, struct http_message *hm);
void print_html(struct mg_connection *conn, struct http_message *hm, const std::string &html);
std::string send_command(const std::string &jid, const std::string &cmd);
private:
bool check_password(const std::string &user, const std::string &password);
@ -80,4 +94,6 @@ class Server {
ManagerConfig *m_config;
std::string m_header;
std::string m_footer;
Config *m_storageCfg;
StorageBackend *m_storage;
};

View file

@ -3,6 +3,10 @@ admin_username=admin
admin_password=test
config_directory=/etc/spectrum2/transports/
[database]
type=sqlite3
database=/var/lib/spectrum2_manager/database.sql
[servers]
server=localhost
#server=icq.spectrum.im

View file

@ -36,6 +36,7 @@ class Client(sleekxmpp.ClientXMPP):
self.tests["friends"] = ["#friends command", False]
self.tests["unfollow"] = ["#unfollow command", False]
self.tests["friends2"] = ["#friends after unfollow command", False]
self.tests["mode1"] = ["#mode 1", False]
self.status = "timeline"
self.timestamp = int(time.time())
@ -60,16 +61,16 @@ class Client(sleekxmpp.ClientXMPP):
self.tests["follow"][1] = True
self.send_message(mto=msg['from'], mbody="#friends")
elif self.status == "friends" and msg['body'].find("USER LIST") != -1 and msg['body'].find("colinpwheeler") != -1:
self.status = "unfollow"
self.tests["friends"][1] = True
self.send_message(mto=msg['from'], mbody="#unfollow colinpwheeler")
elif self.status == "unfollow" and msg['body'] == "You are not following colinpwheeler anymore":
self.status = "friends2"
self.tests["unfollow"][1] = True
self.send_message(mto=msg['from'], mbody="#friends")
elif self.status == "friends2" and msg['body'].find("USER LIST") != -1 and msg['body'].find("colinpwheeler") == -1:
self.tests["friends2"][1] = True
self.finished = True
#self.status = "unfollow"
#self.tests["friends"][1] = True
#self.send_message(mto=msg['from'], mbody="#unfollow colinpwheeler")
#elif self.status == "unfollow" and msg['body'] == "You are not following colinpwheeler anymore":
#self.status = "friends2"
#self.tests["unfollow"][1] = True
#self.send_message(mto=msg['from'], mbody="#friends")
#elif self.status == "friends2" and msg['body'].find("USER LIST") != -1 and msg['body'].find("colinpwheeler") == -1:
#self.tests["friends2"][1] = True
self.send_message(mto=msg['from'], mbody="#mode 1")
def start(self, event):
self.getRoster()