work on dynamic ports for oauth redirection handler
This commit is contained in:
parent
2fde7621d3
commit
47528a48e9
9 changed files with 56 additions and 50 deletions
|
@ -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
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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."));
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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."));
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Add table
Reference in a new issue