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