Upload image to azure storage using Qt/c++ - c++

Can anyone help me to upload image to azure storage using qt/c++
here's my code. it seems to have an error on constructing the headers.*
QByteArray data;
QFile file("Bg.jpg");
if (file.open(QIODevice::ReadOnly))
{
data.append(file.readAll()); //let's read the file
}
QString date = QDateTime::currentDateTime().toString("ddd, d MMM yyyy HH:mm:ss") + " GMT";
QString header = QString("PUT\n\n\n%1\n\n\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:%2\nx-ms-version:2013-08-15\n/mycontainer/todate/").arg(data.length()).arg(date);
QString urlUri = "http://myaccount.blob.core.windows.net/mycontainer/todate";
QByteArray ba = header.toUtf8();
unsigned char* signature = reinterpret_cast<unsigned char*>(ba.data());
QByteArray kba =
QByteArray::fromBase64("key");
unsigned char* key = (unsigned char*) kba.data();
unsigned char result[EVP_MAX_MD_SIZE];
unsigned int result_len;
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, key, strlen((const char*)key), EVP_sha256(), NULL);
HMAC_Update(&ctx, signature, strlen((const char*)signature));
HMAC_Final(&ctx, result, &result_len);
HMAC_CTX_cleanup(&ctx);
QByteArray array = QByteArray::fromRawData((char*)result, result_len);
array = array.toBase64();
String version = "2013-08-15";
QNetworkAccessManager* manager = new QNetworkAccessManager();
QNetworkRequest request;
request.setUrl(QUrl(urlUri));
request.setRawHeader("Content- Length",QString::number(data.length()).toStdString().c_str());
request.setRawHeader("Content-Type","application/octet-stream");
request.setRawHeader("x-ms-blob-type","BlockBlob");
request.setRawHeader("x-ms-date", date.toStdString().c_str());
request.setRawHeader("x-ms-version", version.toStdString().c_str());
request.setRawHeader("Authorization","SharedKey myaccount:"+array);
manager->post(request,data);
connect(manager, SIGNAL(finished(QNetworkReply*)), this,SLOT(manageCloudReply(QNetworkReply*)));
and this is the response on the request
AuthenticationFailed Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:82eb03cb-adf1-4797-bbc0-86c3e5ca3ec6
Time:2014-03-19T03:52:35.4790761ZThe MAC signature found in the HTTP request '3Dk7laN3XW+ASbQj0XddfmSnnuYfVSkhg/oRfSJekKY=' is not the same as any computed signature. Server used following string to sign: 'POST
87163
application/octet-stream
x-ms-blob-type:BlockBlob
x-ms-date:Wed, 19 Mar 2014 11:52:05 GMT
x-ms-version:2013-08-15
/logboxstorage/mycontainer/todate'.
any help will be appreciated..thanks!!!!

Looking at the following line of code:
QString header = QString("PUT\n\n\n%1\n\n\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:%2\nx-ms-version:2013-08-15\n/mycontainer/todate/").arg(data.length()).arg(date);
I see an extra slash (/) in mycontainer/todate/. Can you try by removing that?
Also look at the following code:
QString date = QDateTime::currentDateTime().toString("ddd, d MMM yyyy HH:mm:ss") + " GMT";
currentDateTime() will return the local date/time based on your computer. It should be UTC/GMT date/time. Try using currentDateTimeUtc().
Another thing I noticed is that your request is going as POST to the server. It should be a PUT request.

Related

How to create Password Digest for ONVIF in C++?

Following ONVIF documentation, the password digest for making ONVIF Soap request should be like this.
PasswordDigest = B64ENCODE( SHA1( B64DECODE( Nonce ) + Date + Password ) )
For example:
Nonce – LKqI6G/AikKCQrN0zqZFlg==
Date – 2010-09-16T07:50:45Z
Password – userpassword
Resulting Digest – tuOSpGlFlIXsozq4HFNeeGeFLEI=
Below is how I have written in C++, which resulted in an invalid user token.
std::string dateTime = "2022-09-10T10:10:59.000Z";
std::string nonce = "secret";
std::string password = "mypassword";
std::string str = decode_str(nonce) + dateTime + password;
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1((const unsigned char *) str.c_str(), strlen(str.c_str()) - 1, hash);
uint8_t * hash_ptr = hash;
std::string psswrd = encode_str(hash_ptr, sizeof(hash));
std::cout << psswrd << std::endl; // +cz8/SJS89Uee7cTjW9aiMG9CTE=
But the above password is invalid, resulted the request to fail after timeout.
How to create Password Digest for ONVIF in C++?
I believe your problem is in the call to SHA1. The second parameter (length of the string to be hashed) is strlen(str) - 1, meaning you cut off the final character of the password, which will then result in an invalid hash.
Please either use the length function of std::string or strlen without that decrement (which does not include the \0).
The second 'problem' is in the string nonce, which is not a Base64 string at all, however I am willing to assume this to be a plain 'example value' because you do not wish you disclose your actual nonce value.
Below is a valid digest password.
std::string dateTime = "2022-09-10T10:10:59.000Z";
std::string nonce = "secret";
std::string password = "mypassword";
std::string str = nonce + dateTime + password;
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1((const unsigned char *) str.c_str(), str.size(), hash);
uint8_t * hash_ptr = hash;
std::string psswrd = encode_str(hash_ptr, sizeof(hash));

Getting an unsupported media type error while having a json object posted and content-type set to application/json

I'm doing a small test projet, the goal is to log throught Keycloak API and get my access token.
The problem i'm facing is that i got a 415 error "unsupported media type" as the following :
HTTP error
I've tried content type header as
text/plain
application/x-www-form-urlencoded
application/json
Here is my code :
void MainWindow::on_realmButton_clicked()
{
QNetworkRequest req{QUrl(QString("http://localhost:8080/realms/demo/protocol/openid-connect/token"))};
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QJsonObject body;
body["client_id"] = "demo-client";
body["grant_type"] = "password";
body["client_secret"] = "CLIENT_SECRET";
body["scope"] = "openid";
body["username"] = "user";
body["password"] = "password";
QJsonDocument document(body);
QByteArray bytes = document.toJson();
qDebug() << "JSON Object :" << bytes.toStdString().c_str();
netReply = netManager->post(req, bytes);
connect(netReply, &QNetworkReply::readyRead, this, &MainWindow::readData);
connect(netReply, &QNetworkReply::finished, this, &MainWindow::finishReading);
}
Try something like. Edit: add this note for clarity. "The protocol/openid-connect/token endpoint expects form encoded body, not a JSON body."
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QUrl body;
body.addQueryItem("client_id","demo-client");
.
.
.
networkManager->post(req, body.toString(QUrl::FullyEncoded).toUtf8());

Json serializing in C++ (ESP32)

I'm writing some script for ESP32 and struggling to serialize a json.
Used libraries are HTTPClient and ArduinoJson.
String payload = http.getString();
Serial.println(payload);
deserializeJson(result, payload);
const char* usuario = result["user"];
Serial.println("##########");
Serial.println(usuario);
The received payload is:
{"ip":"10.57.39.137","area":"[{\"id\":\"3\",\"text\":\"BOX\"}]","user":"[{\"id\":\"6270\",\"text\":\"ANDRE LARA OLIVEIRA E SILVA\"}]","teamId":6,"id":4,"siteId":2,"userCreate":"100059527","dateCreate":"2020-11-19T08:49:03.957","userUpdate":null,"dateUpdate":null}
I need to retrieve id and text from "user" key. It's fine to deserialize and retrieve user object. But result["user"] returns: [{"id":"6270","text":"ANDRE LARA OLIVEIRA E SILVA"}] to the char array. So it's something like a json nested in an array... and it's not working out to deserialize.
Can anyone help me how to properly get the "id" and "text" values from "user" object?
The library doesn't know the content of that string is valid JSON, so you have re-parse it. This code worked for me on my PC, though I don't have an Arduino to test it on:
auto payload = "..."; // JSON content here
StaticJsonDocument<1024> result;
deserializeJson(result, payload);
auto user = result["user"].as<const char*>();
StaticJsonDocument<256> userObj;
deserializeJson(userObj, user);
auto id = userObj[0]["id"].as<int>();
auto text = userObj[0]["text"].as<const char*>();
"Can anyone help me how to properly get the "id" and "text" values from "user" object?" You can access them with
const char *id = result["user"]["id"];
const char *text = result["user"]["text"];
Try:
const int id = result["user"]["id"];
const char* text = result["user"]["text"];

AWS query through Qt (mac - OSX) is not getting any result

I'm currently trying to create a C++ program to track prices for a bunch of ASINs.
I'm using C++ with Qt (Version 5.5), compiling on mac OSX through Xcode (5.1.1).
When compiling, it's running but no output is given. I have the following warning message instead (I encrypted AccessKey & AssociateTag for privacy reasons as "/////////////")
*QUrl("http://ecs.amazonaws.com/onca/xml?AWSAccessKeyId=///////////////&AssociateTag=/////////////&ItemId=B00181T20O&Operation=ItemLookup&ResponseGroup=OfferSummary&Service=AWSECommerceService&Signature=1K69SLmTkZ9hZwwt5ualR4uDRwY%3D&SignatureMethod=HmacSHA1&Timestamp=2017-01-04T10%3A21%3A46Z")
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
"<?xml version=\"1.0\"?>\n<ItemLookupErrorResponse
xmlns=\"http://ecs.amazonaws.com/doc/2005-10-05/\"><Error>
<Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated
does not match the signature you provided. Check your AWS Secret Access Key and
signing method. Consult the service documentation for details.</Message></Error>
<RequestId>f4626242-a110-43f1-9b56-b8a696b3f299</RequestId>
</ItemLookupErrorResponse>"
RET:
("", "")*
To test it again, I copied URL (first few rows of warning message) in the browser and I get the same error as well:
"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."
Can anyone give me a hint of what's wrong in the URL?
Thanks in advance!
this is the most relevant part of the code. I suspect I cannot embed .zip file
AWSQueryRequest::AWSQueryRequest(QObject *parent) :
QObject(parent)
{
m_netManager = new QNetworkAccessManager(this);
}
QString AWSQueryRequest::hmacSha1(QByteArray key, QByteArray baseString)
{
int blockSize = 64; // HMAC-SHA-1 block size, defined in SHA-1 standard
if (key.length() > blockSize)
{
// if key is longer than block size (64), reduce key length with SHA-1 compression
key = QCryptographicHash::hash(key, QCryptographicHash::Sha1);
}
QByteArray innerPadding(blockSize, char(0x36)); // initialize inner padding with char "6"
QByteArray outerPadding(blockSize, char(0x5c)); // initialize outer padding with char "quot;
// ascii characters 0x36 ("6") and 0x5c ("quot;) are selected because they have large
// Hamming distance (http://en.wikipedia.org/wiki/Hamming_distance)
for (int i = 0; i < key.length(); i++)
{
innerPadding[i] = innerPadding[i] ^ key.at(i); // XOR operation between every byte in key and innerpadding, of key length
outerPadding[i] = outerPadding[i] ^ key.at(i); // XOR operation between every byte in key and outerpadding, of key length
}
// result = hash ( outerPadding CONCAT hash ( innerPadding CONCAT baseString ) ).toBase64
QByteArray total = outerPadding;
QByteArray part = innerPadding;
part.append(baseString);
total.append(QCryptographicHash::hash(part, QCryptographicHash::Sha1));
QByteArray hashed = QCryptographicHash::hash(total, QCryptographicHash::Sha1);
return hashed.toBase64();
}
QByteArray AWSQueryRequest::getTimeStamp()
{
QDateTime dateTime = QDateTime::currentDateTimeUtc();
return dateTime.toString(Qt::ISODate).toUtf8();
}
QByteArray AWSQueryRequest::createSignature(const QMap<QString,QString> & queryItems)
{
QUrl url(END_POINT);
QString stringToSign = "GET\n";
stringToSign.append(url.host() + "\n");
stringToSign.append(url.path() + "\n");
QList<QString> keys = queryItems.keys();
for( int i=0; i < keys.count() ; ++i )
{
stringToSign.append(keys[i]+"="+queryItems[keys[i]]);
if( i != keys.count() -1 )
stringToSign.append("&");
}
QString signature = hmacSha1(AWS_PASS, stringToSign.toUtf8());
return QUrl::toPercentEncoding(signature);
}
#if 0
QByteArray AWSQueryRequest::createSignature(const QList< QPair<QString,QString> > & queryItems)
{
QUrl url(END_POINT);
QString stringToSign = "GET\n";
stringToSign.append(url.host() + "\n");
stringToSign.append(url.path() + "\n");
for (int i=0; i<queryItems.count(); ++i)
{
QPair<QString,QString> pairValue = queryItems[i];
stringToSign.append(pairValue.first+"="+pairValue.second);
if( i != queryItems.count() -1)
stringToSign.append("&");
}
QString signature = hmacSha1(AWS_PASS, stringToSign.toUtf8());
return QUrl::toPercentEncoding(signature);
}
#endif
QUrl AWSQueryRequest::createUrl( const QMap< QString,QString >& queryItems )
{
QUrl url(END_POINT);
QUrlQuery query;
QMapIterator<QString, QString> it(queryItems);
while (it.hasNext())
{
it.next();
query.addQueryItem(it.key().toUtf8(), it.value().toUtf8());
}
url.setQuery(query);
return url;
}

gsoap c++ android device encoding

8.15,
I can connect my microsoft web service and I can insert record with this service easily.
I get a confirmation code as a response for record insert. But I have a problem with encoding. The response message must like this 1Exa9GwOIO6pP35l4TJ1Bw== but instead of this I get a response like this 4�� u #
When I try this service on a browser I get the expected response as
in 1Exa9GwOIO6pP35l4TJ1Bw==
But when I try it on an android device with gsoap I get a response such as this one 4�� u #
How can I solve this encoding problem?
TheGameSoapProxy service;
_ns1__PlayerRegisterResponse* response = new _ns1__PlayerRegisterResponse();
std::string telNO =m_pEditTel->getText();
std::string telefonIME = "111";
std::string simCardID = "222";
std::string Username = m_pEditName->getText();
std::string takim = Takim.c_str();
_ns1__PlayerRegister* ps = new _ns1__PlayerRegister();
ps->telefonNumarasi = &telNO;
ps->telefonIME = &telefonIME;
ps->simCardID = &simCardID;
ps->Username = &Username;
ps->takim = &takim;
if (service.PlayerRegister(ps, response) == SOAP_OK)
{
string *ptrSonuc = response->PlayerRegisterResult;
CCLog( (char*)ptrSonuc );
}
As per other question here on SO:
add the line below to your typemap.dat file:
xsd__string = | wchar_t* | wchar_t*
And then use wstrings instead of strings.