UI: Properly verify state parameter for YouTube auth
Very low risk of anything bad here since we use a random port and the chance of a CSRF attack is tiny, but this is a best practie to do when using OAuth.master
parent
608cd3867e
commit
0a13ce851d
|
@ -45,6 +45,11 @@ quint16 AuthListener::GetPort()
|
||||||
return server ? server->serverPort() : 0;
|
return server ? server->serverPort() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AuthListener::SetState(QString state)
|
||||||
|
{
|
||||||
|
this->state = state;
|
||||||
|
}
|
||||||
|
|
||||||
void AuthListener::NewConnection()
|
void AuthListener::NewConnection()
|
||||||
{
|
{
|
||||||
QTcpSocket *socket = server->nextPendingConnection();
|
QTcpSocket *socket = server->nextPendingConnection();
|
||||||
|
@ -60,12 +65,34 @@ void AuthListener::NewConnection()
|
||||||
QString redirect = QString::fromLatin1(buffer);
|
QString redirect = QString::fromLatin1(buffer);
|
||||||
blog(LOG_DEBUG, "redirect: %s", QT_TO_UTF8(redirect));
|
blog(LOG_DEBUG, "redirect: %s", QT_TO_UTF8(redirect));
|
||||||
|
|
||||||
QRegularExpression re("(&|\\?)code=(?<code>[^&]+)");
|
QRegularExpression re_state(
|
||||||
QRegularExpressionMatch match = re.match(redirect);
|
"(&|\\?)state=(?<state>[^&]+)");
|
||||||
if (!match.hasMatch())
|
QRegularExpression re_code(
|
||||||
blog(LOG_DEBUG, "no 'code' in server redirect");
|
"(&|\\?)code=(?<code>[^&]+)");
|
||||||
|
|
||||||
QString code = match.captured("code");
|
QRegularExpressionMatch match =
|
||||||
|
re_state.match(redirect);
|
||||||
|
|
||||||
|
QString code;
|
||||||
|
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
if (state == match.captured("state")) {
|
||||||
|
match = re_code.match(redirect);
|
||||||
|
if (!match.hasMatch())
|
||||||
|
blog(LOG_DEBUG, "no 'code' "
|
||||||
|
"in server "
|
||||||
|
"redirect");
|
||||||
|
|
||||||
|
code = match.captured("code");
|
||||||
|
} else {
|
||||||
|
blog(LOG_WARNING, "state mismatch "
|
||||||
|
"while handling "
|
||||||
|
"redirect");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
blog(LOG_DEBUG, "no 'state' in "
|
||||||
|
"server redirect");
|
||||||
|
}
|
||||||
|
|
||||||
if (code.isEmpty()) {
|
if (code.isEmpty()) {
|
||||||
auto data = QTStr("YouTube.Auth.NoCode");
|
auto data = QTStr("YouTube.Auth.NoCode");
|
||||||
|
|
|
@ -7,6 +7,7 @@ class AuthListener : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
QTcpServer *server;
|
QTcpServer *server;
|
||||||
|
QString state;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void ok(const QString &code);
|
void ok(const QString &code);
|
||||||
|
@ -18,4 +19,5 @@ protected:
|
||||||
public:
|
public:
|
||||||
explicit AuthListener(QObject *parent = 0);
|
explicit AuthListener(QObject *parent = 0);
|
||||||
quint16 GetPort();
|
quint16 GetPort();
|
||||||
|
void SetState(QString state);
|
||||||
};
|
};
|
||||||
|
|
|
@ -231,6 +231,10 @@ std::shared_ptr<Auth> YoutubeAuth::Login(QWidget *owner,
|
||||||
deobfuscate_str(&clientid[0], YOUTUBE_CLIENTID_HASH);
|
deobfuscate_str(&clientid[0], YOUTUBE_CLIENTID_HASH);
|
||||||
deobfuscate_str(&secret[0], YOUTUBE_SECRET_HASH);
|
deobfuscate_str(&secret[0], YOUTUBE_SECRET_HASH);
|
||||||
|
|
||||||
|
QString state;
|
||||||
|
state = auth->GenerateState();
|
||||||
|
server.SetState(state);
|
||||||
|
|
||||||
QString url_template;
|
QString url_template;
|
||||||
url_template += "%1";
|
url_template += "%1";
|
||||||
url_template += "?response_type=code";
|
url_template += "?response_type=code";
|
||||||
|
@ -239,7 +243,7 @@ std::shared_ptr<Auth> YoutubeAuth::Login(QWidget *owner,
|
||||||
url_template += "&state=%4";
|
url_template += "&state=%4";
|
||||||
url_template += "&scope=https://www.googleapis.com/auth/youtube";
|
url_template += "&scope=https://www.googleapis.com/auth/youtube";
|
||||||
QString url = url_template.arg(YOUTUBE_AUTH_URL, clientid.c_str(),
|
QString url = url_template.arg(YOUTUBE_AUTH_URL, clientid.c_str(),
|
||||||
redirect_uri, auth->GenerateState());
|
redirect_uri, state);
|
||||||
|
|
||||||
QString text = QTStr("YouTube.Auth.WaitingAuth.Text");
|
QString text = QTStr("YouTube.Auth.WaitingAuth.Text");
|
||||||
text = text.arg(
|
text = text.arg(
|
||||||
|
|
Loading…
Reference in New Issue