#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "engine.h" #include "loggingcategories.h" static QHash s_loggingFilters; static QFile s_logFile; static bool s_loggingEnabled = false; static const char *const normal = "\033[0m"; static const char *const warning = "\e[33m"; static const char *const error = "\e[31m"; static void loggingCategoryFilter(QLoggingCategory *category) { if (s_loggingFilters.contains(category->categoryName())) { bool debugEnabled = s_loggingFilters.value(category->categoryName()); category->setEnabled(QtDebugMsg, debugEnabled); category->setEnabled(QtWarningMsg, debugEnabled || s_loggingFilters.value("Warnings")); } else { category->setEnabled(QtDebugMsg, true); category->setEnabled(QtWarningMsg, s_loggingFilters.value("Warnings")); } } static void consoleLogHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { QString messageString; QString timeString = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz"); switch (type) { case QtInfoMsg: messageString = QString(" I %1 | %2: %3").arg(timeString).arg(context.category).arg(message); fprintf(stdout, " I | %s: %s\n", context.category, message.toUtf8().data()); break; case QtDebugMsg: messageString = QString(" I %1 | %2: %3").arg(timeString).arg(context.category).arg(message); fprintf(stdout, " I | %s: %s\n", context.category, message.toUtf8().data()); break; case QtWarningMsg: messageString = QString(" W %1 | %2: %3").arg(timeString).arg(context.category).arg(message); fprintf(stdout, "%s W | %s: %s%s\n", warning, context.category, message.toUtf8().data(), normal); break; case QtCriticalMsg: messageString = QString(" C %1 | %2: %3").arg(timeString).arg(context.category).arg(message); fprintf(stdout, "%s C | %s: %s%s\n", error, context.category, message.toUtf8().data(), normal); break; case QtFatalMsg: messageString = QString(" F %1 | %2: %3").arg(timeString).arg(context.category).arg(message); fprintf(stdout, "%s F | %s: %s%s\n", error, context.category, message.toUtf8().data(), normal); break; } fflush(stdout); if (s_logFile.isOpen()) { QTextStream textStream(&s_logFile); textStream << messageString << endl; } } int main(int argc, char *argv[]) { qInstallMessageHandler(consoleLogHandler); QCoreApplication application(argc, argv); application.setApplicationName("nymea-remoteproxy"); application.setOrganizationName("guh"); application.setApplicationVersion("0.0.1"); s_loggingFilters.insert("Application", true); s_loggingFilters.insert("Engine", true); s_loggingFilters.insert("JsonRpc", true); s_loggingFilters.insert("WebSocketServer", true); s_loggingFilters.insert("Authenticator", true); s_loggingFilters.insert("ConnectionManager", true); s_loggingFilters.insert("Debug", false); // command line parser QCommandLineParser parser; parser.addHelpOption(); parser.setApplicationDescription(QString("\nThe nymea remote proxy server.\n\n" "Copyright %1 2018 Simon Stürz ").arg(QChar(0xA9))); QCommandLineOption logfileOption(QStringList() << "l" << "logging", "Write log file to the given logfile.", "logfile", "/var/log/nymea-remoteproxy.log"); parser.addOption(logfileOption); QCommandLineOption serverOption(QStringList() << "s" << "server", "The authentication server url.", "url", "http://localhost:8000"); parser.addOption(serverOption); QCommandLineOption portOption(QStringList() << "p" << "port", "The proxy server port.", "port", "1212"); parser.addOption(portOption); QCommandLineOption certOption(QStringList() << "c" <<"certificate", "The path to the SSL certificate.", "certificate"); parser.addOption(certOption); QCommandLineOption certKeyOption(QStringList() << "k" << "certificate-key", "The path to the SSL certificate key (KEY).", "certificate-key"); parser.addOption(certKeyOption); QCommandLineOption verboseOption(QStringList() << "v" << "verbose", "Print the whole traffic."); parser.addOption(verboseOption); parser.process(application); if (parser.isSet(verboseOption)) s_loggingFilters["Debug"] = true; QLoggingCategory::installFilter(loggingCategoryFilter); // Open the logfile, if any specified if (parser.isSet(logfileOption)) { QFileInfo fi(parser.value(logfileOption)); QDir logDir(fi.absolutePath()); if (!logDir.exists() && !logDir.mkpath(logDir.absolutePath())) { qCCritical(dcApplication()) << "Error opening log file" << parser.value(logfileOption); return 1; } s_logFile.setFileName(parser.value(logfileOption)); if (!s_logFile.open(QFile::WriteOnly | QFile::Append)) { qCCritical(dcApplication()) << "Error opening log file" << parser.value(logfileOption); return 1; } s_loggingEnabled = true; } qCDebug(dcApplication()) << "=============================================="; qCDebug(dcApplication()) << "Starting" << application.applicationName() << application.applicationVersion(); qCDebug(dcApplication()) << "=============================================="; if (s_loggingEnabled) qCDebug(dcApplication()) << "Logging enabled. Writing logs to" << s_logFile.fileName(); // Authentication server url QUrl serverUrl("http://localhost:8000"); if (parser.isSet(serverOption)) serverUrl = QUrl(parser.value(serverOption)); if (!serverUrl.isValid()) { qCCritical(dcApplication()) << "Invalid authentication server url:" << parser.value(serverOption); exit(-1); } // Port uint port = 1212; if (parser.isSet(portOption)) { bool ok = false; port = parser.value(portOption).toUInt(&ok); if (!ok) { qCCritical(dcApplication()) << "Invalud port value:" << parser.value(portOption); exit(-1); } if (port > 65535) { qCCritical(dcApplication()) << "Port value is out of range:" << parser.value(portOption); exit(-1); } } // SSL certificate QSslConfiguration sslConfiguration; if (parser.isSet(certOption)) { // Load certificate QFile certFile(parser.value(certOption)); if (!certFile.open(QIODevice::ReadOnly)) { qCCritical(dcApplication()) << "Could not open certificate file:" << parser.value(certOption) << certFile.errorString(); exit(-1); } QSslCertificate certificate(&certFile, QSsl::Pem); qCDebug(dcApplication()) << "Loaded successfully certificate" << parser.value(certOption); certFile.close(); // Create SSL configuration sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); sslConfiguration.setLocalCertificate(certificate); sslConfiguration.setProtocol(QSsl::TlsV1_2OrLater); } // SSL key if (parser.isSet(certKeyOption)) { QFile certKeyFile(parser.value(certKeyOption)); if (!certKeyFile.open(QIODevice::ReadOnly)) { qCCritical(dcApplication()) << "ERROR: Could not open certificate key file:" << parser.value(certKeyOption) << certKeyFile.errorString(); exit(-1); } QSslKey sslKey(&certKeyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); qCDebug(dcApplication()) << "Loaded successfully certificate key" << parser.value(certKeyOption); certKeyFile.close(); sslConfiguration.setPrivateKey(sslKey); } Engine::instance()->setAuthenticationServerUrl(serverUrl); Engine::instance()->setPort(static_cast(port)); Engine::instance()->setSslConfiguration(sslConfiguration); Engine::instance()->start(); return application.exec(); }