I am in the process of writing a new Betfair bot in C++ using Qt but I am falling at the first hurdle with the login process. After a lot of reading around I decided to use QNetworkAccessManager and this is what I currently have:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
BetfairManager bet_man;
QNetworkAccessManager *manager = new QNetworkAccessManager();
QObject::connect(manager, SIGNAL(finished(QNetworkReply*)),
&bet_man,SLOT(replyFinished(QNetworkReply*)));
QObject::connect(manager,SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
&bet_man,SLOT(replySSLErrors(QNetworkReply*,QList<QSslError>)));
QObject::connect(manager,SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
&bet_man,SLOT(replyAuthenticationRequired(QNetworkReply*,QAuthenticator*)));
QObject::connect(manager,SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&,QAuthenticator*)),
&bet_man,SLOT(replyProxyAuthenticationRequired(const QNetworkProxy&,QAuthenticator*)));
QNetworkRequest request;
QByteArray payload("username=myusername&password=mypassword");
QString url("https://identitysso.betfair.com/api/certlogin");
QSslConfiguration config;
QString pemfile("../../client-2048.pem");
QFile file(pemfile);
if(!file.exists()) {
qWarning("Filename %s doesn't exists.", qPrintable(pemfile));
}
if(!file.open(QIODevice::ReadOnly)) {
qWarning("Cannot open filename %s.", qPrintable(pemfile));
}
QByteArray data = file.readAll();
QSslCertificate sslcert(data, QSsl::Pem);
if(sslcert.isNull()) {
qWarning("The certificate has no content.");
}
config.setLocalCertificate(sslcert);
request.setSslConfiguration(config);
request.setUrl(url);
request.setRawHeader("X-Application","mykey");
request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
manager->post(request,payload);
return a.exec();
}
The BetfairManager class is just a dummy class that I have created to have slots for the QNetworkAccessManager signals - they just dump some debug info to the screen to see what signals have been emitted.
When I run the above, I see that the QNetworkAccessManager::finished() signal has fired, but I have an empty response - there are not even any HTTP headers.
When I stop setting the certificate by commenting out the line
request.setSslConfiguration(config);
I get the response
"{"loginStatus":"CERT_AUTH_REQUIRED"}"
which is unsurprising but shows that I am passing the correct parameters in my request, so I am convinced that the problem lies with my certificate passing mechanism/creation with the Qt classes.
I have created the .pem file according to the betfair documentation (which says to create it from appending the generated .crt and the .key files) and I know they are fine as I also have a Python bot that works perfectly using the same files.
I am new to Qt and not a SSL expert and I get the impression that I am missing something fundamental here.
In case it is useful here is my Python equivalent code which works perfectly using urllib2 package
un = "myusername";
pw = "mypassword";
app_key = 'mykey'
payload = 'username=' + un + '&password=' + pw
login_headers = {'X-Application': app_key, 'Content-Type': 'application/x-www-form-urlencoded'}
resp = requests.post('https://identitysso.betfair.com/api/certlogin', data=payload, cert=('client-2048.crt', 'client-2048.key'), headers=login_headers)
I am developing this with Qt 5.2.1 on Ubuntu 14.04