void CardReader::onSocketError(QAbstractSocket::SocketError error) { // See http://stackoverflow.com/a/16390227 const QMetaObject & metaObject = QAbstractSocket::staticMetaObject; QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("SocketError")); frontend_error(QStringLiteral("Socket error: ") + metaEnum.valueToKey(error), false); }
bool CardReader::setupSsl(QString certificatePath, QString keyPath) { // FIXME: This function leaks both QFile objects QFile *certificateFile = new QFile(certificatePath); certificateFile->open(QIODevice::ReadOnly); if(!certificateFile->exists()) { frontend_error("Certificate file doesn't exist", false); return false; } QList<QSslCertificate> certificateChain = QSslCertificate::fromDevice(certificateFile); certificateFile->close(); if (certificateChain.size() == 0) { frontend_error("Invalid certificate chain specified", false); return false; } QFile *keyFile = new QFile(keyPath); keyFile->open(QIODevice::ReadOnly); if(!keyFile->exists()) { frontend_error("Key file doesn't exist", false); return false; } QSslKey key(keyFile, QSsl::Rsa); keyFile->close(); if(key.isNull()) { frontend_error("Invalid key specified", false); return false; } QSslConfiguration sslConfiguration = QSslConfiguration::defaultConfiguration(); sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); sslConfiguration.setProtocol(QSsl::SecureProtocols); sslConfiguration.setLocalCertificateChain(certificateChain); sslConfiguration.setPrivateKey(key); server = new QWebSocketServer(QStringLiteral("Arago Card Reader"), QWebSocketServer::SecureMode, this); server->setSslConfiguration(sslConfiguration); return true; }
void CardReader::setup() { // Load configuration QString configurationFile = QCoreApplication::applicationDirPath() + QDir::separator() + "arago-card-reader.ini"; QSettings settings(configurationFile, QSettings::IniFormat); quint64 port = settings.value("websocket/port", 3000).toInt(); bool wants_tls = settings.value("websocket/tls", false).toBool(); if(wants_tls && !QSslSocket::supportsSsl()) { frontend_message("Requested TLS, but TLS not supported by Qt platform..."); wants_tls = false; } if(wants_tls && this->setupSsl(settings.value("websocket/certificate", "").toString(), settings.value("websocket/key", "").toString())) { frontend_message("Enabling TLS on server..."); } else { server = new QWebSocketServer(QStringLiteral("Arago Card Reader"), QWebSocketServer::NonSecureMode, this); frontend_message("Not enabling TLS on server..."); } // Setup socket server frontend_message(QStringLiteral("Starting websocket server on port %1...").arg(port)); if(!server->listen(QHostAddress::Any, port)) { frontend_error(QStringLiteral("Failed to setup server: %1").arg(server->errorString()), true); return; } connect(server, &QWebSocketServer::newConnection, this, &CardReader::onNewConnection); connect(server, &QWebSocketServer::acceptError, this, &CardReader::onSocketError); connect(server, &QWebSocketServer::serverError, this, &CardReader::onServerError); connect(server, &QWebSocketServer::sslErrors, this, &CardReader::onSslError); nfcThread = new NfcThread(settings.value("nfc/device", "").toString()); connect(nfcThread, &NfcThread::cardScanned, this, &CardReader::onCardScanned); connect(nfcThread, &NfcThread::finished, nfcThread, &QObject::deleteLater); nfcThread->start(); frontend_message("Started all processes..."); emit started(); }
foreach(QSslError error, errors) { frontend_error(QStringLiteral("SSL error: ") + error.errorString(), false); }
void CardReader::onServerError(QWebSocketProtocol::CloseCode closeCode) { frontend_error(QStringLiteral("Server error: ") + QString(closeCode), false); }
//////////////////////////////////////////////////////////// // Argument Parsing //////////////////////////////////////////////////////////// void Sigil::parseOptions(int argc, char *argv[]) { /* custom parsing, by order of the arguments */ ArgGroup arg_group; /* Pass through args to frontend/backend. */ arg_group.addGroup(frontend, false); arg_group.addGroup(backend, true); arg_group.addGroup(executable, true); arg_group.parse(argc, argv); /* The number of 'threads' Sigil2 will use */ /* MDL20160805 Currently only valid with DynamoRIO frontend. * This will cause 'n' event streams between Sigil2 and DynamoRIO * to be generated, and 'n' separate backend instances will * read from those event streams as separate threads */ num_threads = 1; if (arg_group.getOpt(numthreads).empty() == false) { num_threads = stoi(arg_group.getOpt(numthreads)); if (num_threads > 16 || num_threads < 1) { SigiLog::fatal("Invalid number of threads specified"); } } /* check frontend */ std::string frontend_name; if (arg_group.getGroup(frontend).empty() == false) { frontend_name = arg_group.getGroup(frontend)[0]; } else /*set default*/ { frontend_name = "valgrind"; //default } std::transform(frontend_name.begin(), frontend_name.end(), frontend_name.begin(), ::tolower); if (frontend_registry.find(frontend_name) != frontend_registry.cend()) { start_frontend = [this, arg_group, frontend_name]() mutable { Sigil::Args args; if (arg_group.getGroup(frontend).size() > 1) { auto start = arg_group.getGroup(frontend).cbegin() + 1; auto end = arg_group.getGroup(frontend).cend(); args = {start, end}; } frontend_registry[frontend_name](arg_group.getGroup(executable), args, num_threads, instance_id); }; } else { std::string frontend_error(" invalid frontend argument "); frontend_error.append(frontend_name).append("\n"); frontend_error.append("\tAvailable frontends: "); for (auto p : frontend_registry) { frontend_error.append("\n\t").append(p.first); } SigiLog::fatal(frontend_error); } /* check backend */ std::string backend_name = arg_group.getGroup(backend)[0]; std::transform(backend_name.begin(), backend_name.end(), backend_name.begin(), ::tolower); if (backend_registry.find(backend_name) != backend_registry.cend()) { /* send args to backend */ Sigil::Args args; if (arg_group.getGroup(backend).size() > 1) { auto start = arg_group.getGroup(backend).cbegin() + 1; auto end = arg_group.getGroup(backend).cend(); args = {start, end}; } /* Register the backend * * Each backend thread creates a new * backend instance via 'create_backend' */ parse_backend = [this, backend_name, args]() { std::get<1>(backend_registry[backend_name])(args); }; create_backend = std::get<0>(backend_registry[backend_name]); exit_backend = std::get<2>(backend_registry[backend_name]); } else { std::string backend_error(" invalid backend argument "); backend_error.append(backend_name).append("\n"); backend_error.append("\tAvailable backends: "); for (auto p : backend_registry) { backend_error.append("\n\t").append(p.first); } SigiLog::fatal(backend_error); } }