work on dynamic ports for oauth redirection handler

This commit is contained in:
Martin Rotter 2020-07-23 20:34:30 +02:00
parent 2fde7621d3
commit 47528a48e9
9 changed files with 56 additions and 50 deletions

View file

@ -53,7 +53,7 @@
#define MIN_CATEGORY_NAME_LENGTH 1 #define MIN_CATEGORY_NAME_LENGTH 1
#define DEFAULT_AUTO_UPDATE_INTERVAL 15 #define DEFAULT_AUTO_UPDATE_INTERVAL 15
#define OAUTH_REDIRECT_URI_PORT 13377 #define OAUTH_REDIRECT_URI_PORT 13377
#define OAUTH_REDIRECT_URI "http://localhost:13377" #define OAUTH_REDIRECT_URI "http://localhost"
#define AUTO_UPDATE_INTERVAL 60000 #define AUTO_UPDATE_INTERVAL 60000
#define STARTUP_UPDATE_DELAY 15.0 // In seconds. #define STARTUP_UPDATE_DELAY 15.0 // In seconds.
#define TIMEZONE_OFFSET_LIMIT 6 #define TIMEZONE_OFFSET_LIMIT 6

View file

@ -45,8 +45,7 @@ Q_GLOBAL_STATIC(OAuthHttpHandler, qz_silent_acmanager)
OAuth2Service::OAuth2Service(const QString& auth_url, const QString& token_url, const QString& client_id, OAuth2Service::OAuth2Service(const QString& auth_url, const QString& token_url, const QString& client_id,
const QString& client_secret, const QString& scope, QObject* parent) const QString& client_secret, const QString& scope, QObject* parent)
: QObject(parent), m_id(QString::number(std::rand())), m_timerId(-1) { : QObject(parent), m_id(QString::number(std::rand())), m_timerId(-1), m_redirectionHandler(new OAuthHttpHandler(this)) {
m_redirectUrl = QSL(OAUTH_REDIRECT_URI);
m_tokenGrantType = QSL("authorization_code"); m_tokenGrantType = QSL("authorization_code");
m_tokenUrl = QUrl(token_url); m_tokenUrl = QUrl(token_url);
m_authUrl = auth_url; m_authUrl = auth_url;
@ -56,13 +55,13 @@ OAuth2Service::OAuth2Service(const QString& auth_url, const QString& token_url,
m_scope = scope; m_scope = scope;
connect(&m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(tokenRequestFinished(QNetworkReply*))); connect(&m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(tokenRequestFinished(QNetworkReply*)));
connect(handler(), &OAuthHttpHandler::authGranted, [this](const QString& auth_code, const QString& id) { connect(m_redirectionHandler, &OAuthHttpHandler::authGranted, [this](const QString& auth_code, const QString& id) {
if (id.isEmpty() || id == m_id) { if (id.isEmpty() || id == m_id) {
// We process this further only if handler (static singleton) responded to our original request. // We process this further only if handler (static singleton) responded to our original request.
retrieveAccessToken(auth_code); retrieveAccessToken(auth_code);
} }
}); });
connect(handler(), &OAuthHttpHandler::authRejected, [this](const QString& error_description, const QString& id) { connect(m_redirectionHandler, &OAuthHttpHandler::authRejected, [this](const QString& error_description, const QString& id) {
Q_UNUSED(error_description) Q_UNUSED(error_description)
if (id.isEmpty() || id == m_id) { if (id.isEmpty() || id == m_id) {
@ -130,10 +129,6 @@ void OAuth2Service::setId(const QString& id) {
m_id = id; m_id = id;
} }
OAuthHttpHandler* OAuth2Service::handler() {
return qz_silent_acmanager();
}
void OAuth2Service::retrieveAccessToken(const QString& auth_code) { void OAuth2Service::retrieveAccessToken(const QString& auth_code) {
QNetworkRequest networkRequest; QNetworkRequest networkRequest;
@ -144,7 +139,9 @@ void OAuth2Service::retrieveAccessToken(const QString& auth_code) {
"client_secret=%2&" "client_secret=%2&"
"code=%3&" "code=%3&"
"redirect_uri=%5&" "redirect_uri=%5&"
"grant_type=%4").arg(m_clientId, m_clientSecret, auth_code, m_tokenGrantType, m_redirectUrl); "grant_type=%4").arg(m_clientId, m_clientSecret,
auth_code, m_tokenGrantType,
m_redirectionHandler->listenAddressPort());
m_networkManager.post(networkRequest, content.toUtf8()); m_networkManager.post(networkRequest, content.toUtf8());
} }
@ -242,11 +239,11 @@ void OAuth2Service::setClientId(const QString& client_id) {
} }
QString OAuth2Service::redirectUrl() const { QString OAuth2Service::redirectUrl() const {
return m_redirectUrl; return m_redirectionHandler->listenAddressPort();
} }
void OAuth2Service::setRedirectUrl(const QString& redirect_url) { void OAuth2Service::setRedirectUrl(const QString& redirect_url) {
m_redirectUrl = redirect_url; m_redirectionHandler->setListenAddressPort(redirect_url);
} }
QString OAuth2Service::refreshToken() const { QString OAuth2Service::refreshToken() const {
@ -305,7 +302,10 @@ void OAuth2Service::retrieveAuthCode() {
"response_type=code&" "response_type=code&"
"state=%4&" "state=%4&"
"prompt=consent&" "prompt=consent&"
"access_type=offline").arg(m_clientId, m_scope, m_redirectUrl, m_id); "access_type=offline").arg(m_clientId,
m_scope,
m_redirectionHandler->listenAddressPort(),
m_id);
// We run login URL in external browser, response is caught by light HTTP server. // We run login URL in external browser, response is caught by light HTTP server.
if (qApp->web()->openUrlInExternalBrowser(auth_url)) { if (qApp->web()->openUrlInExternalBrowser(auth_url)) {

View file

@ -109,14 +109,13 @@ class OAuth2Service : public QObject {
QString m_accessToken; QString m_accessToken;
QString m_refreshToken; QString m_refreshToken;
QString m_tokenGrantType; QString m_tokenGrantType;
QString m_redirectUrl;
QString m_clientId; QString m_clientId;
QString m_clientSecret; QString m_clientSecret;
QUrl m_tokenUrl; QUrl m_tokenUrl;
QString m_authUrl; QString m_authUrl;
QString m_scope; QString m_scope;
SilentNetworkAccessManager m_networkManager; SilentNetworkAccessManager m_networkManager;
static OAuthHttpHandler* handler(); OAuthHttpHandler* m_redirectionHandler;
}; };
#endif // OAUTH2SERVICE_H #endif // OAUTH2SERVICE_H

View file

@ -14,10 +14,7 @@ OAuthHttpHandler::OAuthHttpHandler(QObject* parent) : QObject(parent) {
m_text = tr("You can close this window now. Go back to %1").arg(APP_NAME); m_text = tr("You can close this window now. Go back to %1").arg(APP_NAME);
connect(&m_httpServer, &QTcpServer::newConnection, this, &OAuthHttpHandler::clientConnected); connect(&m_httpServer, &QTcpServer::newConnection, this, &OAuthHttpHandler::clientConnected);
setListenAddressPort(QString(OAUTH_REDIRECT_URI) + QL1C(':') + QString::number(OAUTH_REDIRECT_URI_PORT));
if (!m_httpServer.listen(m_listenAddress, OAUTH_REDIRECT_URI_PORT)) {
qCritical("OAuth HTTP handler: Failed to start listening on port '%d'.", OAUTH_REDIRECT_URI_PORT);
}
} }
OAuthHttpHandler::~OAuthHttpHandler() { OAuthHttpHandler::~OAuthHttpHandler() {
@ -26,6 +23,22 @@ OAuthHttpHandler::~OAuthHttpHandler() {
} }
} }
void OAuthHttpHandler::setListenAddressPort(const QString& full_uri) {
QUrl url = QUrl::fromUserInput(full_uri);
m_listenAddress = QHostAddress(url.host());
m_listenPort = quint16(url.port());
m_listenAddressPort = full_uri;
if (m_httpServer.isListening()) {
m_httpServer.close();
}
if (!m_httpServer.listen(m_listenAddress, m_listenPort)) {
qCritical("OAuth HTTP handler: Failed to start listening on port '%d'.", OAUTH_REDIRECT_URI_PORT);
}
}
void OAuthHttpHandler::clientConnected() { void OAuthHttpHandler::clientConnected() {
QTcpSocket* socket = m_httpServer.nextPendingConnection(); QTcpSocket* socket = m_httpServer.nextPendingConnection();
@ -99,6 +112,7 @@ void OAuthHttpHandler::answerClient(QTcpSocket* socket, const QUrl& url) {
void OAuthHttpHandler::readReceivedData(QTcpSocket* socket) { void OAuthHttpHandler::readReceivedData(QTcpSocket* socket) {
if (!m_connectedClients.contains(socket)) { if (!m_connectedClients.contains(socket)) {
m_connectedClients[socket].m_address = QSL("http://") + m_httpServer.serverAddress().toString();
m_connectedClients[socket].m_port = m_httpServer.serverPort(); m_connectedClients[socket].m_port = m_httpServer.serverPort();
} }
@ -141,6 +155,18 @@ void OAuthHttpHandler::readReceivedData(QTcpSocket* socket) {
} }
} }
QHostAddress OAuthHttpHandler::listenAddress() const {
return m_listenAddress;
}
QString OAuthHttpHandler::listenAddressPort() const {
return m_listenAddressPort;
}
quint16 OAuthHttpHandler::listenPort() const {
return m_listenPort;
}
bool OAuthHttpHandler::QHttpRequest::readMethod(QTcpSocket* socket) { bool OAuthHttpHandler::QHttpRequest::readMethod(QTcpSocket* socket) {
bool finished = false; bool finished = false;
@ -204,7 +230,7 @@ bool OAuthHttpHandler::QHttpRequest::readUrl(QTcpSocket* socket) {
return false; return false;
} }
m_url.setUrl(QStringLiteral("http://localhost:") + QString::number(m_port) + QString::fromUtf8(m_fragment)); m_url.setUrl(m_address + QString::number(m_port) + QString::fromUtf8(m_fragment));
m_state = State::ReadingStatus; m_state = State::ReadingStatus;
if (!m_url.isValid()) { if (!m_url.isValid()) {

View file

@ -15,8 +15,14 @@ class OAuthHttpHandler : public QObject {
explicit OAuthHttpHandler(QObject* parent = nullptr); explicit OAuthHttpHandler(QObject* parent = nullptr);
virtual ~OAuthHttpHandler(); virtual ~OAuthHttpHandler();
quint16 listenPort() const;
QHostAddress listenAddress() const;
QString listenAddressPort() const;
void setListenAddressPort(const QString& full_uri);
signals: signals:
void authRejected(const QString& error_description, const QString& state = QString()); void authRejected(const QString& error_description, const QString& state);
void authGranted(const QString& auth_code, const QString& state); void authGranted(const QString& auth_code, const QString& state);
private slots: private slots:
@ -52,6 +58,7 @@ class OAuthHttpHandler : public QObject {
Delete, Delete,
} m_method = Method::Unknown; } m_method = Method::Unknown;
QString m_address;
quint16 m_port = 0; quint16 m_port = 0;
QByteArray m_fragment; QByteArray m_fragment;
QUrl m_url; QUrl m_url;
@ -62,7 +69,9 @@ class OAuthHttpHandler : public QObject {
QMap<QTcpSocket*, QHttpRequest> m_connectedClients; QMap<QTcpSocket*, QHttpRequest> m_connectedClients;
QTcpServer m_httpServer; QTcpServer m_httpServer;
QHostAddress m_listenAddress = QHostAddress::LocalHost; QHostAddress m_listenAddress;
quint16 m_listenPort;
QString m_listenAddressPort;
QString m_text; QString m_text;
}; };

View file

@ -14,12 +14,8 @@ FormEditGmailAccount::FormEditGmailAccount(QWidget* parent) : QDialog(parent),
QString(), QString(), GMAIL_OAUTH_SCOPE)), m_editableRoot(nullptr) { QString(), QString(), GMAIL_OAUTH_SCOPE)), m_editableRoot(nullptr) {
m_ui.setupUi(this); m_ui.setupUi(this);
GuiUtilities::setLabelAsNotice(*m_ui.m_lblAuthInfo, true);
GuiUtilities::applyDialogProperties(*this, qApp->icons()->miscIcon(QSL("gmail"))); GuiUtilities::applyDialogProperties(*this, qApp->icons()->miscIcon(QSL("gmail")));
m_ui.m_lblAuthInfo->setText(tr("You must use \"%1\" as redirect URL. It is important to leave this "
"URL intact, because %2 is waiting on specified port for "
"service tokens.").arg(OAUTH_REDIRECT_URI, APP_NAME));
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information, m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information,
tr("Not tested yet."), tr("Not tested yet."),
tr("Not tested yet.")); tr("Not tested yet."));

View file

@ -57,16 +57,6 @@
<item row="2" column="1"> <item row="2" column="1">
<widget class="LineEditWithStatus" name="m_txtRedirectUrl" native="true"/> <widget class="LineEditWithStatus" name="m_txtRedirectUrl" native="true"/>
</item> </item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="m_lblAuthInfo">
<property name="text">
<string>Predefined settings DO NOT have to be changed from their default values. Change these values only of you are advanced user and you know what you are doing!</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View file

@ -14,12 +14,8 @@ FormEditInoreaderAccount::FormEditInoreaderAccount(QWidget* parent) : QDialog(pa
INOREADER_OAUTH_CLI_ID, INOREADER_OAUTH_CLI_KEY, INOREADER_OAUTH_SCOPE)), m_editableRoot(nullptr) { INOREADER_OAUTH_CLI_ID, INOREADER_OAUTH_CLI_KEY, INOREADER_OAUTH_SCOPE)), m_editableRoot(nullptr) {
m_ui.setupUi(this); m_ui.setupUi(this);
GuiUtilities::setLabelAsNotice(*m_ui.m_lblAuthInfo, true);
GuiUtilities::applyDialogProperties(*this, qApp->icons()->miscIcon(QSL("inoreader"))); GuiUtilities::applyDialogProperties(*this, qApp->icons()->miscIcon(QSL("inoreader")));
m_ui.m_lblAuthInfo->setText(tr("You must use \"%1\" as redirect URL. It is important to leave this "
"URL intact, because %2 is waiting on specified port for "
"service tokens.").arg(OAUTH_REDIRECT_URI, APP_NAME));
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information, m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information,
tr("Not tested yet."), tr("Not tested yet."),
tr("Not tested yet.")); tr("Not tested yet."));

View file

@ -57,16 +57,6 @@
<item row="2" column="1"> <item row="2" column="1">
<widget class="LineEditWithStatus" name="m_txtRedirectUrl" native="true"/> <widget class="LineEditWithStatus" name="m_txtRedirectUrl" native="true"/>
</item> </item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="m_lblAuthInfo">
<property name="text">
<string>These settings DO NOT have to be changed from their default values. Change these values only of you are advanced user and you know what you are doing!</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>