/** * @file PswGen/CLI/cli.cpp * @brief Command line interface for the PswGen application * @author Enar Vaikene * * Copyright (c) 2011-2012 Enar Vaikene * * This file is part of the eVaf C++ cross-platform application development framework. * * This file can be used under the terms of the GNU General Public License * version 3.0 as published by the Free Software Foundation and appearing in * the file LICENSE included in the packaging of this file. Please review the * the following information to ensure the GNU General Public License version * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. * * Alternatively, this file may be used in accordance with the Commercial License * Agreement provided with the Software. */ #include "cli.h" #include #include #include #include #include #include #include #include #include #include #if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) # include # include #endif #ifdef Q_OS_WIN32 # include #endif VER_EXPORT_VERSION_INFO() //------------------------------------------------------------------- using namespace eVaf; using namespace eVaf::PswGen::CLI; int const Module::DefaultPasswordLength = 16; Module::Module() : Plugins::iPlugin() , mReady(false) , mGenerator(0) , mStorage(0) , mEvReady(0) { setObjectName(QString("%1-Module").arg(VER_MODULE_NAME_STR)); EVAF_INFO("%s created", qPrintable(objectName())); } Module::~Module() { EVAF_INFO("%s destroyed", qPrintable(objectName())); } bool Module::init(QString const & args) { Q_UNUSED(args); // Get the iGenerator interface EVAF_TEST_X((mGenerator = evafQueryInterface("iGenerator")), "No iGenerator interface"); // Get the optional iStorage interface mStorage = evafQueryInterface("iStorage"); if (!mStorage) EVAF_WARNING("No iStorage interface"); // Get the iEventQueue interface and subscribe to the 'ready' event Common::iEventQueue * eventQueue = evafQueryInterface("iEventQueue"); EVAF_TEST_X(eventQueue, "No iEventQueue interface"); // Subscribe to the 'ready' event EVAF_TEST_X((mEvReady = eventQueue->subscribeEvent(eventQueue->queryEvent(Common::iApp::EV_READY), this)), "No 'ready' event"); mReady = true; EVAF_INFO("%s initialized", qPrintable(objectName())); return true; } void Module::done() { mReady = false; EVAF_INFO("%s finalized", qPrintable(objectName())); } bool Module::event(QEvent * e) { if (e->type() == Common::Event::eVafEvent) { Common::Event * event = static_cast(e); if (event->id() == mEvReady) { // Generate the password generatePassword(); // Quit the application Common::iApp::instance()->quit(); } return false; } else return Plugins::iPlugin::event(e); } QString Module::readPassword() { bool noEcho = false; #if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) termios oldt; tcgetattr(STDIN_FILENO, &oldt); termios newt = oldt; newt.c_lflag &= ~ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &newt); noEcho = true; #elif defined Q_OS_WIN32 HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); DWORD mode = 0; GetConsoleMode(hStdin, &mode); SetConsoleMode(hStdin, mode & (~ENABLE_ECHO_INPUT)); noEcho = true; #endif QTextStream cin(stdin); QString rval = cin.readLine(); if (noEcho) { QTextStream cout(stdout); cout << endl; } #if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) tcsetattr(STDIN_FILENO, TCSANOW, &oldt); #elif defined Q_OS_WIN32 SetConsoleMode(hStdin, mode); #endif return rval; } void Module::generatePassword() { QString masterPassword; QString appName; QString suffix; int passwordLength = 0; uint flags = 0; int alnum = -1; // Process command-line arguments QStringList args = QCoreApplication::arguments(); for (int i = 0; i < args.size(); ++i) { QStringList arg = args.at(i).simplified().split('='); if (QRegExp("-[-]?p(assword)?").exactMatch(arg.at(0)) && arg.size() > 1) masterPassword = arg.at(1); else if (QRegExp("-[-]?n(ame)?").exactMatch(arg.at(0)) && arg.size() > 1) appName = arg.at(1); else if (QRegExp("-[-]?s(uffix)?").exactMatch(arg.at(0)) && arg.size() > 1) suffix = arg.at(1); else if (QRegExp("-[-]?a(lphanumeric)?").exactMatch(arg.at(0))) { if (arg.size() > 1) { if (Common::isTrue(arg.at(1))) alnum = 1; else if (Common::isFalse(arg.at(1))) alnum = 0; } else alnum = 1; } else if (QRegExp("-[-]?l(ength)?").exactMatch(arg.at(0)) && arg.size() > 1) { bool ok; int t = arg.at(1).toInt(&ok); if (!ok) { EVAF_FATAL_ERROR("Invalid argument : %s", qPrintable(args.at(i))); return; } passwordLength = t; } } // Set flags if (alnum != -1) { if (alnum == 1) flags |= uint(iGenerator::ALPHANUMERIC); else flags &= ~uint(iGenerator::ALPHANUMERIC); } QTextStream cin(stdin); QTextStream cout(stdout); // Get missing arguments while (masterPassword.isEmpty()) { cout << tr("Master password : ") << flush; masterPassword = readPassword(); } while (appName.isEmpty()) { cout << tr("Application name : ") << flush; cin >> appName; } // Get more arguments from the storage QExplicitlySharedDataPointer data; if (mStorage) { data = mStorage->query(appName); if (data) { if (passwordLength == 0) passwordLength = data->length(); if (suffix.isEmpty()) suffix = data->suffix(); if (alnum == -1) flags = data->flags(); } } // If the length argument is still not initialized, use the default length value if (!passwordLength) passwordLength = DefaultPasswordLength; // Generate password QString password = mGenerator->generatePassword(appName + suffix, masterPassword, passwordLength); cout << "Generated password : " << password << endl; // Store arguments for this password if (mStorage) { if (!data) data = new Storage::Data(appName, suffix, passwordLength); else { data->setSuffix(suffix); data->setLength(passwordLength); } mStorage->save(appName, data); } }