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 DEFAULT_AUTO_UPDATE_INTERVAL 15
#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 STARTUP_UPDATE_DELAY 15.0 // In seconds.
#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,
const QString& client_secret, const QString& scope, QObject* parent)
: QObject(parent), m_id(QString::number(std::rand())), m_timerId(-1) {
m_redirectUrl = QSL(OAUTH_REDIRECT_URI);
: QObject(parent), m_id(QString::number(std::rand())), m_timerId(-1), m_redirectionHandler(new OAuthHttpHandler(this)) {
m_tokenGrantType = QSL("authorization_code");
m_tokenUrl = QUrl(token_url);
m_authUrl = auth_url;
@ -56,13 +55,13 @@ OAuth2Service::OAuth2Service(const QString& auth_url, const QString& token_url,
m_scope = scope;
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) {
// We process this further only if handler (static singleton) responded to our original request.
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)
if (id.isEmpty() || id == m_id) {
@ -130,10 +129,6 @@ void OAuth2Service::setId(const QString& id) {
m_id = id;
}
OAuthHttpHandler* OAuth2Service::handler() {
return qz_silent_acmanager();
}
void OAuth2Service::retrieveAccessToken(const QString& auth_code) {
QNetworkRequest networkRequest;
@ -144,7 +139,9 @@ void OAuth2Service::retrieveAccessToken(const QString& auth_code) {
"client_secret=%2&"
"code=%3&"
"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());
}
@ -242,11 +239,11 @@ void OAuth2Service::setClientId(const QString& client_id) {
}
QString OAuth2Service::redirectUrl() const {
return m_redirectUrl;
return m_redirectionHandler->listenAddressPort();
}
void OAuth2Service::setRedirectUrl(const QString& redirect_url) {
m_redirectUrl = redirect_url;
m_redirectionHandler->setListenAddressPort(redirect_url);
}
QString OAuth2Service::refreshToken() const {
@ -305,7 +302,10 @@ void OAuth2Service::retrieveAuthCode() {
"response_type=code&"
"state=%4&"
"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.
if (qApp->web()->openUrlInExternalBrowser(auth_url)) {

View File

@ -109,14 +109,13 @@ class OAuth2Service : public QObject {
QString m_accessToken;
QString m_refreshToken;
QString m_tokenGrantType;
QString m_redirectUrl;
QString m_clientId;
QString m_clientSecret;
QUrl m_tokenUrl;
QString m_authUrl;
QString m_scope;
SilentNetworkAccessManager m_networkManager;
static OAuthHttpHandler* handler();
OAuthHttpHandler* m_redirectionHandler;
};
#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);
connect(&m_httpServer, &QTcpServer::newConnection, this, &OAuthHttpHandler::clientConnected);
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);
}
setListenAddressPort(QString(OAUTH_REDIRECT_URI) + QL1C(':') + QString::number(OAUTH_REDIRECT_URI_PORT));
}
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() {
QTcpSocket* socket = m_httpServer.nextPendingConnection();
@ -99,6 +112,7 @@ void OAuthHttpHandler::answerClient(QTcpSocket* socket, const QUrl& url) {
void OAuthHttpHandler::readReceivedData(QTcpSocket* 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();
}
@ -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 finished = false;
@ -204,7 +230,7 @@ bool OAuthHttpHandler::QHttpRequest::readUrl(QTcpSocket* socket) {
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;
if (!m_url.isValid()) {

View File

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

View File

@ -14,12 +14,8 @@ FormEditGmailAccount::FormEditGmailAccount(QWidget* parent) : QDialog(parent),
QString(), QString(), GMAIL_OAUTH_SCOPE)), m_editableRoot(nullptr) {
m_ui.setupUi(this);
GuiUtilities::setLabelAsNotice(*m_ui.m_lblAuthInfo, true);
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,
tr("Not tested yet."),
tr("Not tested yet."));

View File

@ -57,16 +57,6 @@
<item row="2" column="1">
<widget class="LineEditWithStatus" name="m_txtRedirectUrl" native="true"/>
</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>
</widget>
</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) {
m_ui.setupUi(this);
GuiUtilities::setLabelAsNotice(*m_ui.m_lblAuthInfo, true);
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,
tr("Not tested yet."),
tr("Not tested yet."));

View File

@ -57,16 +57,6 @@
<item row="2" column="1">
<widget class="LineEditWithStatus" name="m_txtRedirectUrl" native="true"/>
</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>
</widget>
</item>