1 /*
2 SPDX-FileCopyrightText: 2020-2021 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "ruqolaloginwidget.h"
8 #include "common/authenticationcombobox.h"
9 #include "misc/passwordlineeditwidget.h"
10 #include "misc/twoauthenticationpasswordwidget.h"
11 #include "rocketchataccount.h"
12 #include "ruqola.h"
13 #include <KBusyIndicatorWidget>
14 #include <KColorScheme>
15 #include <KLocalizedString>
16 #include <KPasswordLineEdit>
17 #include <QCheckBox>
18 #include <QFormLayout>
19 #include <QLabel>
20 #include <QLineEdit>
21 #include <QPushButton>
22 #include <QVBoxLayout>
23
RuqolaLoginWidget(QWidget * parent)24 RuqolaLoginWidget::RuqolaLoginWidget(QWidget *parent)
25 : QWidget(parent)
26 , mAccountName(new QLineEdit(this))
27 , mServerName(new QLineEdit(this))
28 , mUserName(new QLineEdit(this))
29 , mPasswordLineEditWidget(new PasswordLineEditWidget(this))
30 , mLdapCheckBox(new QCheckBox(i18n("Use LDAP"), this))
31 , mLoginButton(new QPushButton(i18n("Login"), this))
32 , mBusyIndicatorWidget(new KBusyIndicatorWidget(this))
33 , mFailedError(new QLabel(this))
34 , mTwoFactorAuthenticationPasswordLineEdit(new TwoAuthenticationPasswordWidget(this))
35 , mAuthenticationWidget(new QWidget(this))
36 , mAuthenticationAccountWidget(new QWidget(this))
37 , mAuthenticationCombobox(new AuthenticationComboBox(this))
38 {
39 auto mainLayout = new QFormLayout(this);
40 mainLayout->setObjectName(QStringLiteral("mainLayout"));
41
42 mAccountName->setObjectName(QStringLiteral("mAccountName"));
43 mainLayout->addRow(i18n("Account Name:"), mAccountName);
44 mAccountName->setPlaceholderText(i18n("Account Name"));
45 connect(mAccountName, &QLineEdit::textChanged, this, &RuqolaLoginWidget::slotUpdateLoginButton);
46
47 mServerName->setObjectName(QStringLiteral("mServerName"));
48 mainLayout->addRow(i18n("Server Name:"), mServerName);
49
50 mUserName->setObjectName(QStringLiteral("mUserName"));
51 mainLayout->addRow(i18n("User Name:"), mUserName);
52
53 // Type of account
54 mAuthenticationAccountWidget->setObjectName(QStringLiteral("mAuthenticationAccountWidget"));
55 mAuthenticationAccountWidget->setVisible(false);
56
57 auto authenticationAccountLayout = new QVBoxLayout(mAuthenticationAccountWidget);
58 authenticationAccountLayout->setObjectName(QStringLiteral("authenticationAccountLayout"));
59
60 auto authenticationAccountLabel = new QLabel(i18n("Authentication Method"), this);
61 authenticationAccountLabel->setTextFormat(Qt::PlainText);
62 authenticationAccountLabel->setObjectName(QStringLiteral("authenticationAccountLabel"));
63 authenticationAccountLayout->addWidget(authenticationAccountLabel);
64
65 mAuthenticationCombobox->setObjectName(QStringLiteral("mAuthenticationCombobox"));
66 authenticationAccountLayout->addWidget(mAuthenticationCombobox);
67 mainLayout->addWidget(mAuthenticationAccountWidget);
68 mAuthenticationAccountWidget->setVisible(false);
69
70 // Password
71 mPasswordLineEditWidget->setObjectName(QStringLiteral("mPasswordLineEditWidget"));
72 connect(mPasswordLineEditWidget->passwordLineEdit()->lineEdit(), &QLineEdit::returnPressed, this, &RuqolaLoginWidget::slotLogin);
73 mainLayout->addRow(i18n("Password:"), mPasswordLineEditWidget);
74 connect(mPasswordLineEditWidget, &PasswordLineEditWidget::resetPasswordRequested, this, &RuqolaLoginWidget::slotResetPasswordRequested);
75
76 mLdapCheckBox->setObjectName(QStringLiteral("mLdapCheckBox"));
77 mainLayout->addWidget(mLdapCheckBox);
78
79 // Two Factor authentication
80 mAuthenticationWidget->setObjectName(QStringLiteral("authenticationWidget"));
81 mAuthenticationWidget->setVisible(false);
82
83 auto twoFactorAuthenticationLayout = new QVBoxLayout(mAuthenticationWidget);
84 twoFactorAuthenticationLayout->setObjectName(QStringLiteral("twoFactorAuthenticationLayout"));
85
86 auto *twoFactorAuthenticationLabel =
87 new QLabel(i18n("You have enabled second factor authentication.\nPlease enter the generated code or a backup code."), this);
88 twoFactorAuthenticationLabel->setObjectName(QStringLiteral("twoFactorAuthenticationLabel"));
89 twoFactorAuthenticationLayout->addWidget(twoFactorAuthenticationLabel);
90
91 mTwoFactorAuthenticationPasswordLineEdit->setObjectName(QStringLiteral("mTwoFactorAuthenticationPasswordLineEdit"));
92 twoFactorAuthenticationLayout->addWidget(mTwoFactorAuthenticationPasswordLineEdit);
93
94 mainLayout->addWidget(mAuthenticationWidget);
95
96 mLoginButton->setObjectName(QStringLiteral("mLoginButton"));
97 mainLayout->addWidget(mLoginButton);
98 connect(mLoginButton, &QPushButton::clicked, this, &RuqolaLoginWidget::slotLogin);
99
100 mBusyIndicatorWidget->setObjectName(QStringLiteral("mBusyIndicatorWidget"));
101 mainLayout->addWidget(mBusyIndicatorWidget);
102 // Hide by default
103 mBusyIndicatorWidget->hide();
104
105 mFailedError->setObjectName(QStringLiteral("mFailedError"));
106 QPalette pal = mFailedError->palette();
107 const KColorScheme colorScheme{QPalette::Active};
108 pal.setColor(foregroundRole(), colorScheme.foreground(KColorScheme::NegativeText).color());
109 mFailedError->setPalette(pal);
110 QFont font = mFailedError->font();
111 font.setBold(true);
112 mFailedError->setFont(font);
113
114 mainLayout->addWidget(mFailedError);
115 // Hide by default
116 mFailedError->hide();
117 }
118
119 RuqolaLoginWidget::~RuqolaLoginWidget() = default;
120
slotUpdateLoginButton()121 void RuqolaLoginWidget::slotUpdateLoginButton()
122 {
123 mLoginButton->setEnabled(!mAccountName->text().isEmpty());
124 }
125
setRocketChatAccount(RocketChatAccount * rocketChatAccount)126 void RuqolaLoginWidget::setRocketChatAccount(RocketChatAccount *rocketChatAccount)
127 {
128 mRocketChatAccount = rocketChatAccount;
129 mAccountName->setText(mRocketChatAccount->displayName());
130 mAccountName->setReadOnly(!mRocketChatAccount->displayName().isEmpty());
131 mServerName->setText(mRocketChatAccount->serverUrl());
132 mUserName->setText(mRocketChatAccount->userName());
133 mLdapCheckBox->setChecked(mRocketChatAccount->useLdap());
134 mPasswordLineEditWidget->passwordLineEdit()->setPassword(mRocketChatAccount->password());
135 mAuthenticationCombobox->switchRocketChatAccount(mRocketChatAccount); // Authentication is rocketchatAccount specific
136 mAuthenticationCombobox->setVisible(mAuthenticationCombobox->count() > 1);
137 mLdapCheckBox->setVisible(rocketChatAccount->ldapEnabled());
138 mTwoFactorAuthenticationPasswordLineEdit->setRocketChatAccount(mRocketChatAccount);
139 }
140
slotLogin()141 void RuqolaLoginWidget::slotLogin()
142 {
143 mRocketChatAccount->setAccountName(mAccountName->isEnabled() ? mAccountName->text() : mRocketChatAccount->accountName());
144 mRocketChatAccount->setServerUrl(mServerName->text());
145 mRocketChatAccount->setUserName(mUserName->text());
146 mRocketChatAccount->setPassword(mPasswordLineEditWidget->passwordLineEdit()->password());
147 mRocketChatAccount->setUseLdap(mLdapCheckBox->isChecked());
148 if (!mAuthenticationWidget->isHidden()) {
149 mRocketChatAccount->setTwoFactorAuthenticationCode(mTwoFactorAuthenticationPasswordLineEdit->code());
150 } else {
151 mTwoFactorAuthenticationPasswordLineEdit->clear();
152 }
153 mRocketChatAccount->tryLogin();
154 }
155
changeWidgetStatus(bool enabled)156 void RuqolaLoginWidget::changeWidgetStatus(bool enabled)
157 {
158 mServerName->setEnabled(enabled);
159 mUserName->setEnabled(enabled);
160 mPasswordLineEditWidget->setEnabled(enabled);
161 mLoginButton->setEnabled(enabled && !mAccountName->text().isEmpty());
162 }
163
setLoginStatus(DDPAuthenticationManager::LoginStatus status)164 void RuqolaLoginWidget::setLoginStatus(DDPAuthenticationManager::LoginStatus status)
165 {
166 mFailedError->setHidden(true);
167 switch (status) {
168 case DDPAuthenticationManager::LoginStatus::Connecting:
169 case DDPAuthenticationManager::LoginStatus::LoginOngoing:
170 mBusyIndicatorWidget->show();
171 changeWidgetStatus(false);
172 mAuthenticationWidget->setVisible(false);
173 break;
174 case DDPAuthenticationManager::LoginStatus::LoggedOut:
175 case DDPAuthenticationManager::LoginStatus::LoggedIn:
176 mBusyIndicatorWidget->hide();
177 changeWidgetStatus(true);
178 mAuthenticationWidget->setVisible(false);
179 break;
180 case DDPAuthenticationManager::LoginStatus::LoginFailedInvalidUserOrPassword:
181 mBusyIndicatorWidget->hide();
182 changeWidgetStatus(true);
183 showError(i18n("Login Failed: invalid username or password"));
184 mAuthenticationWidget->setVisible(false);
185 break;
186 case DDPAuthenticationManager::LoginFailedInvalidOtp:
187 showError(i18n("Login failed: Invalid OTP code."));
188 Q_FALLTHROUGH();
189 case DDPAuthenticationManager::LoginStatus::LoginOtpRequired:
190 mBusyIndicatorWidget->hide();
191 changeWidgetStatus(true);
192 mAuthenticationWidget->setVisible(true);
193 break;
194 case DDPAuthenticationManager::LoginStatus::FailedToLoginPluginProblem:
195 mBusyIndicatorWidget->hide();
196 changeWidgetStatus(true);
197 showError(i18n("Installation Problem found. No plugins found here."));
198 mAuthenticationWidget->setVisible(false);
199 break;
200 case DDPAuthenticationManager::LoginStatus::GenericError:
201 mBusyIndicatorWidget->hide();
202 changeWidgetStatus(true);
203 showError(i18n("Login Failed: generic error"));
204 mAuthenticationWidget->setVisible(false);
205 break;
206 case DDPAuthenticationManager::LoginOtpAuthOngoing:
207 case DDPAuthenticationManager::LogoutOngoing:
208 case DDPAuthenticationManager::LogoutCleanUpOngoing:
209 case DDPAuthenticationManager::LoggedOutAndCleanedUp:
210 // TODO
211 mAuthenticationWidget->setVisible(false);
212 mBusyIndicatorWidget->hide();
213 changeWidgetStatus(true);
214 break;
215 }
216 }
217
showError(const QString & text)218 void RuqolaLoginWidget::showError(const QString &text)
219 {
220 mFailedError->setVisible(true);
221 mFailedError->setText(text);
222 }
223
slotResetPasswordRequested(const QString & email)224 void RuqolaLoginWidget::slotResetPasswordRequested(const QString &email)
225 {
226 mRocketChatAccount->requestNewPassword(email);
227 }
228