1 /**
2 * UGENE - Integrated Bioinformatics Tools.
3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4 * http://ugene.net
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include <qglobal.h>
23 #ifdef Q_OS_WIN
24 # include <conio.h>
25 #endif
26
27 #ifdef Q_OS_UNIX
28 # include <termios.h>
29 #endif
30
31 #include <iostream>
32 #include <stdio.h>
33
34 #include <U2Core/AppContext.h>
35 #include <U2Core/U2DbiUtils.h>
36 #include <U2Core/U2SafePoints.h>
37
38 #include "CredentialsAskerCli.h"
39
40 #ifdef Q_OS_UNIX // source: http://stackoverflow.com/questions/7469139/what-is-equivalent-to-getch-getche-in-linux
41 static struct termios oldTerm, newTerm;
42
43 /* Initialize new terminal i/o settings */
initTermios(int echo)44 static void initTermios(int echo) {
45 tcgetattr(0, &oldTerm); /* grab old terminal i/o settings */
46 newTerm = oldTerm; /* make new settings same as old settings */
47 newTerm.c_lflag &= ~ICANON; /* disable buffered i/o */
48 newTerm.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
49 tcsetattr(0, TCSANOW, &newTerm); /* use these new terminal i/o settings now */
50 }
51
52 /* Restore old terminal i/o settings */
resetTermios(void)53 void resetTermios(void) {
54 tcsetattr(0, TCSANOW, &oldTerm);
55 }
56
57 /* Read 1 character - echo defines echo mode */
getchExt(int echo)58 char getchExt(int echo) {
59 char ch;
60 initTermios(echo);
61 ch = getchar();
62 resetTermios();
63 return ch;
64 }
65
66 /* Read 1 character without echo */
_getch(void)67 char _getch(void) {
68 return getchExt(0);
69 }
70
71 #endif
72
73 static const QString BACKSPACE_PRINT_STR = "\b";
74 static const QString NEW_LINE_STR = "\n";
75 #ifdef Q_OS_WIN
76 static const QString BACKSPACE_STR = "\b";
77 static const QString RETURN_STR = "\r";
78 #else
79 static const QString BACKSPACE_STR = "\177";
80 static const QString RETURN_STR = "\n";
81 #endif
82
83 static const QString ASTERISC_STR = "*";
84 static const QString YES_STR = "Y";
85 static const QString NO_STR = "N";
86
87 namespace U2 {
88
89 namespace {
90
printString(const QString & str)91 static void printString(const QString &str) {
92 std::cout << str.toLocal8Bit().constData();
93 }
94
getChar()95 static QString getChar() {
96 const char c = _getch();
97 return QString::fromLocal8Bit(QByteArray(1, c));
98 }
99
getLine()100 static QString getLine() {
101 std::string result;
102 getline(std::cin, result);
103 return QString::fromStdString(result);
104 }
105
askYesNoQuestion(const QString & question)106 static bool askYesNoQuestion(const QString &question) {
107 QString readKey;
108 int yes = -1;
109 int no = -1;
110 do {
111 printString(question + QString(" (%1/%2)").arg(YES_STR).arg(NO_STR));
112 readKey = getChar();
113 yes = QString::compare(readKey, YES_STR, Qt::CaseInsensitive);
114 no = QString::compare(readKey, NO_STR, Qt::CaseInsensitive);
115 printString(NEW_LINE_STR);
116 } while (0 != yes && 0 != no);
117
118 return 0 == yes;
119 }
120
inputFinish(const QString & key)121 static bool inputFinish(const QString &key) {
122 return (NEW_LINE_STR == key) || (RETURN_STR == key) || (RETURN_STR + NEW_LINE_STR == key);
123 }
124
askPwd()125 static QString askPwd() {
126 printString(QObject::tr("Enter password: "));
127
128 QString pwd;
129
130 QString readKey;
131 do {
132 readKey = getChar();
133
134 if (readKey != BACKSPACE_STR && readKey != RETURN_STR) {
135 pwd += readKey;
136 printString(ASTERISC_STR);
137 } else if (readKey == BACKSPACE_STR && !pwd.isEmpty()) {
138 pwd.truncate(pwd.length() - 1);
139 printString(BACKSPACE_PRINT_STR + " " + BACKSPACE_PRINT_STR);
140 }
141 } while (!inputFinish(readKey));
142
143 printString(NEW_LINE_STR);
144 return pwd;
145 }
146
147 } // namespace
148
askWithFixedLogin(const QString & resourceUrl) const149 bool CredentialsAskerCli::askWithFixedLogin(const QString &resourceUrl) const {
150 SAFE_POINT(!AppContext::isGUIMode(), "Unexpected application run mode", false);
151
152 QString userName;
153 QString shortDbiUrl = U2DbiUtils::full2shortDbiUrl(resourceUrl, userName);
154
155 printString(QObject::tr("Connect to the '%1' ...\n").arg(shortDbiUrl));
156 printString(QObject::tr("You are going to log in as '%1'.\n").arg(userName));
157
158 QString pwd = askPwd();
159 bool isRemembered = askYesNoQuestion(QObject::tr("Would you like UGENE to remember the password?"));
160
161 saveCredentials(resourceUrl, pwd, isRemembered);
162 return true;
163 }
164
askWithModifiableLogin(QString & resourceUrl) const165 bool CredentialsAskerCli::askWithModifiableLogin(QString &resourceUrl) const {
166 SAFE_POINT(!AppContext::isGUIMode(), "Unexpected application run mode", false);
167
168 QString userName;
169 QString shortDbiUrl = U2DbiUtils::full2shortDbiUrl(resourceUrl, userName);
170
171 printString(QObject::tr("Connect to the '%1' ...\n").arg(shortDbiUrl));
172 printString(QObject::tr("You are going to log in as '%1'.\n").arg(userName));
173 bool logAsAnotherUser = askYesNoQuestion(QObject::tr("Would you like to log in as another user?"));
174
175 if (logAsAnotherUser) {
176 do {
177 printString(QObject::tr("Enter user name: "));
178 userName = getLine();
179 } while (!userName.isEmpty());
180 printString(NEW_LINE_STR);
181 }
182
183 QString pwd = askPwd();
184 bool isRemembered = askYesNoQuestion(QObject::tr("Would you like UGENE to remember the password?"));
185
186 resourceUrl = U2DbiUtils::createFullDbiUrl(userName, shortDbiUrl);
187 saveCredentials(resourceUrl, pwd, isRemembered);
188 return true;
189 }
190
191 } // namespace U2
192