Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/owncloud/client.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Molkentin <danimo@owncloud.com>2014-09-17 01:52:28 +0400
committerDaniel Molkentin <danimo@owncloud.com>2014-09-17 01:52:28 +0400
commitfe023e2229dedbc646ab7e701ecd1a457dadef16 (patch)
tree6d5043bab768c9d09d0afe91cd63fbe48315159c /src/owncloudcmd
parent97cc05eeea3da08ee01578b1604ed0bc3b0b7d7e (diff)
Allow passing user/pass explicitly or via netrc
#2211
Diffstat (limited to 'src/owncloudcmd')
-rw-r--r--src/owncloudcmd/netrcparser.cpp97
-rw-r--r--src/owncloudcmd/netrcparser.h41
-rw-r--r--src/owncloudcmd/owncloudcmd.cpp144
3 files changed, 255 insertions, 27 deletions
diff --git a/src/owncloudcmd/netrcparser.cpp b/src/owncloudcmd/netrcparser.cpp
new file mode 100644
index 000000000..7db8d2be4
--- /dev/null
+++ b/src/owncloudcmd/netrcparser.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <QDir>
+#include <QFile>
+#include <QTextStream>
+
+#include "netrcparser.h"
+
+namespace Mirall {
+
+namespace {
+QString defaultKeyword = QLatin1String("default");
+QString machineKeyword = QLatin1String("machine");
+QString loginKeyword = QLatin1String("login");
+QString passwordKeyword = QLatin1String("password");
+
+}
+
+NetrcParser::NetrcParser(const QString &fileName)
+ : _fileName(fileName)
+{
+ if (_fileName.isEmpty()) {
+ _fileName = QDir::homePath()+QLatin1String("/.netrc");
+ }
+}
+
+void NetrcParser::tryAddEntryAndClear(QString& machine, LoginPair& pair, bool& isDefault) {
+ if (isDefault) {
+ _default = pair;
+ } else if (!machine.isEmpty() && !pair.first.isEmpty()){
+ _entries.insert(machine, pair);
+ }
+ pair = qMakePair(QString(), QString());
+ machine.clear();
+ isDefault = false;
+}
+
+bool NetrcParser::parse()
+{
+ QFile netrc(_fileName);
+ if (!netrc.open(QIODevice::ReadOnly)) {
+ return false;
+ }
+
+ QTextStream ts(&netrc);
+ LoginPair pair;
+ QString machine;
+ bool isDefault = false;
+ while (!ts.atEnd()) {
+ QString next;
+ ts >> next;
+ if (next == defaultKeyword) {
+ tryAddEntryAndClear(machine, pair, isDefault);
+ isDefault = true;
+ }
+ if (next == machineKeyword) {
+ tryAddEntryAndClear(machine, pair, isDefault);
+ ts >> machine;
+ } else if (next == loginKeyword) {
+ ts >> pair.first;
+ } else if (next == passwordKeyword) {
+ ts >> pair.second;
+ } // ignore unsupported tokens
+
+ }
+ tryAddEntryAndClear(machine, pair, isDefault);
+
+ if (!_entries.isEmpty() || _default != qMakePair(QString(), QString())) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+NetrcParser::LoginPair NetrcParser::find(const QString &machine)
+{
+ QHash<QString, LoginPair>::const_iterator it = _entries.find(machine);
+ if (it != _entries.end()) {
+ return *it;
+ } else {
+ return _default;
+ }
+}
+
+} // namespace Mirall
diff --git a/src/owncloudcmd/netrcparser.h b/src/owncloudcmd/netrcparser.h
new file mode 100644
index 000000000..355333d43
--- /dev/null
+++ b/src/owncloudcmd/netrcparser.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef NETRCPARSER_H
+#define NETRCPARSER_H
+
+#include <QHash>
+#include <QPair>
+
+namespace Mirall {
+
+class NetrcParser
+{
+public:
+ typedef QPair<QString, QString> LoginPair;
+
+ NetrcParser(const QString &fileName = QString::null);
+ bool parse();
+ LoginPair find(const QString &machine);
+
+private:
+ void tryAddEntryAndClear(QString &machine, LoginPair &pair, bool &isDefault);
+ QHash<QString, LoginPair> _entries;
+ LoginPair _default;
+ QString _fileName;
+};
+
+} // namespace Mirall
+
+#endif // NETRCPARSER_H
diff --git a/src/owncloudcmd/owncloudcmd.cpp b/src/owncloudcmd/owncloudcmd.cpp
index c95755240..bfdcae637 100644
--- a/src/owncloudcmd/owncloudcmd.cpp
+++ b/src/owncloudcmd/owncloudcmd.cpp
@@ -31,15 +31,26 @@
#include "owncloudcmd.h"
#include "simplesslerrorhandler.h"
+#include "netrcparser.h"
+
+#ifdef Q_OS_WIN32
+#include <windows.h>
+#else
+#include <termios.h>
+#endif
+
using namespace Mirall;
struct CmdOptions {
QString source_dir;
QString target_url;
QString config_directory;
+ QString user;
+ QString password;
QString proxy;
bool silent;
bool trustSSL;
+ bool useNetrc;
QString exclude;
};
@@ -47,21 +58,59 @@ struct CmdOptions {
// So we have to use a global variable
CmdOptions *opts = 0;
-int getauth(const char* prompt, char* buf, size_t len, int a, int b, void *userdata)
+class EchoDisabler
{
- Q_UNUSED(a) Q_UNUSED(b) Q_UNUSED(userdata)
+public:
+ EchoDisabler()
+ {
+#ifdef Q_OS_WIN
+ HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
+ GetConsoleMode(hStdin, &mode);
+ SetConsoleMode(hStdin, mode & (~ENABLE_ECHO_INPUT));
+#else
+ tcgetattr(STDIN_FILENO, &tios);
+ termios tios_new = tios;
+ tios_new.c_lflag &= ~ECHO;
+ tcsetattr(STDIN_FILENO, TCSANOW, &tios_new);
+#endif
+ }
- std::cout << "** Authentication required: \n" << prompt << std::endl;
- std::string s;
- if(opts && opts->trustSSL) {
- s = "yes";
- } else {
- std::getline(std::cin, s);
+ ~EchoDisabler()
+ {
+#ifdef Q_OS_WIN
+ SetConsoleMode(hStdin, mode);
+#else
+ tcsetattr(STDIN_FILENO, TCSANOW, &tios);
+#endif
}
- strncpy( buf, s.c_str(), len );
- return 0;
+private:
+#ifdef Q_OS_WIN
+ DWORD mode = 0;
+#else
+ termios tios;
+#endif
+};
+
+QString queryPassword(const QString &user)
+{
+ EchoDisabler disabler;
+ std::cout << "Password for user " << qPrintable(user) << ": ";
+ std::string s;
+ std::getline(std::cin, s);
+ return QString::fromStdString(s);
}
+class HttpCredentialsText : public HttpCredentials {
+public:
+ HttpCredentialsText(const QString& user, const QString& password) : HttpCredentials(user, password) {}
+ QString queryPassword(bool *ok) {
+ if (ok) {
+ *ok = true;
+ }
+ return ::queryPassword(user());
+ }
+};
+
void help()
{
std::cout << "owncloudcmd - command line ownCloud client tool." << std::endl;
@@ -72,12 +121,15 @@ void help()
std::cout << "uses the setting from a configured sync client." << std::endl;
std::cout << std::endl;
std::cout << "Options:" << std::endl;
- std::cout << " --silent Don't be so verbose" << std::endl;
+ std::cout << " --silent, -s Don't be so verbose" << std::endl;
std::cout << " --confdir = configdir: Read config from there." << std::endl;
std::cout << " --httpproxy = proxy: Specify a http proxy to use." << std::endl;
std::cout << " Proxy is http://server:port" << std::endl;
std::cout << " --trust Trust the SSL certification." << std::endl;
std::cout << " --exclude [file] exclude list file" << std::endl;
+ std::cout << " --user, -u [name] Use [name] as the login name" << std::endl;
+ std::cout << " --password, -p [pass] Use [pass] as password" << std::endl;
+ std::cout << " -n Use netrc (5) for login" << std::endl;
std::cout << "" << std::endl;
exit(1);
@@ -118,10 +170,16 @@ void parseOptions( const QStringList& app_args, CmdOptions *options )
options->config_directory = it.next();
} else if( option == "--httpproxy" && !it.peekNext().startsWith("-")) {
options->proxy = it.next();
- } else if( option == "--silent") {
+ } else if( option == "-s" || option == "--silent") {
options->silent = true;
} else if( option == "--trust") {
options->trustSSL = true;
+ } else if( option == "-n") {
+ options->useNetrc = true;
+ } else if( (option == "-u" || option == "--user") && !it.peekNext().startsWith("-") ) {
+ options->user = it.next();
+ } else if( (option == "-p" || option == "--password") && !it.peekNext().startsWith("-") ) {
+ options->user = it.next();
} else if( option == "--exclude" && !it.peekNext().startsWith("-") ) {
options->exclude = it.next();
} else {
@@ -140,27 +198,55 @@ int main(int argc, char **argv) {
CmdOptions options;
options.silent = false;
options.trustSSL = false;
+ options.useNetrc = false;
ClientProxy clientProxy;
parseOptions( app.arguments(), &options );
- QUrl url(options.target_url.toUtf8());
+ QUrl url = QUrl::fromUserInput(options.target_url);
+
+ // Fetch username and password. If empty, try to retrieve
+ // from URL and strip URL
+ QString user;
+ QString password;
+
+ if (options.useNetrc) {
+ NetrcParser parser;
+ if (parser.parse()) {
+ NetrcParser::LoginPair pair = parser.find(url.host());
+ user = pair.first;
+ password = pair.second;
+ }
+ } else {
+ user = options.user;
+ if (user.isEmpty()) {
+ user = url.userName();
+ }
+ password = options.password;
+ if (password.isEmpty()) {
+ password = url.password();
+ }
+
+ if (user.isEmpty()) {
+ std::cout << "Please enter user name: ";
+ std::string s;
+ std::getline(std::cin, s);
+ user = QString::fromStdString(s);
+ }
+ if (password.isEmpty()) {
+ password = queryPassword(user);
+ }
+ }
+
+ // ### ensure URL is free of credentials
if (url.userName().isEmpty()) {
- std::cout << "** Please enter the username:" << std::endl;
- std::string s;
- std::getline(std::cin, s);
- url.setUserName(QString::fromStdString(s));
+ url.setUserName(user);
}
if (url.password().isEmpty()) {
- std::cout << "** Please enter the password:" << std::endl;
- std::string s;
- std::getline(std::cin, s);
- url.setPassword(QString::fromStdString(s));
+ url.setPassword(password);
}
- QUrl originalUrl = url;
-
Account account;
// Find the folder and the original owncloud url
@@ -171,16 +257,19 @@ int main(int argc, char **argv) {
SimpleSslErrorHandler *sslErrorHandler = new SimpleSslErrorHandler;
+ HttpCredentials *cred = new HttpCredentialsText(user, password);
+
account.setUrl(url);
- account.setCredentials(new HttpCredentials(url.userName(), url.password()));
+ account.setCredentials(cred);
account.setSslErrorHandler(sslErrorHandler);
+
AccountManager::instance()->setAccount(&account);
restart_sync:
CSYNC *_csync_ctx;
if( csync_create( &_csync_ctx, options.source_dir.toUtf8(),
- originalUrl.toEncoded().constData()) < 0 ) {
+ url.toEncoded().constData()) < 0 ) {
qFatal("Unable to create csync-context!");
return EXIT_FAILURE;
}
@@ -192,7 +281,7 @@ restart_sync:
csync_set_log_level(options.silent ? 1 : 11);
opts = &options;
- csync_set_auth_callback( _csync_ctx, getauth );
+ cred->syncContextPreInit(_csync_ctx);
if( csync_init( _csync_ctx ) < 0 ) {
qFatal("Could not initialize csync!");
@@ -239,8 +328,9 @@ restart_sync:
csync_add_exclude_list(_csync_ctx, options.exclude.toLocal8Bit());
}
- OwncloudCmd owncloudCmd;
+ cred->syncContextPreStart(_csync_ctx);
+ OwncloudCmd owncloudCmd;
SyncJournalDb db(options.source_dir);
SyncEngine engine(_csync_ctx, options.source_dir, QUrl(options.target_url).path(), folder, &db);
QObject::connect(&engine, SIGNAL(finished()), &app, SLOT(quit()));