This change will remove any string-literal keys from non-API `BMessage` assembly and interpretation logic. It will also make the keys consistently use lower- snake string format and will setup the key constants in a common style. Change-Id: I246613d1e88a54fd275f45c55a52c4e9b2ac67e9 Reviewed-on: https://review.haiku-os.org/c/haiku/+/10216 Reviewed-by: Adrien Destugues <[email protected]> Reviewed-by: waddlesplash <[email protected]>
291 lines
7.3 KiB
C++
291 lines
7.3 KiB
C++
/*
|
|
* Copyright 2017-2026, Andrew Lindesay <[email protected]>.
|
|
* All rights reserved. Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
|
|
#include "ServerHelper.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <Alert.h>
|
|
#include <Application.h>
|
|
#include <Catalog.h>
|
|
#include <NetworkInterface.h>
|
|
#include <NetworkRoster.h>
|
|
|
|
#include "Logger.h"
|
|
#include "HaikuDepotConstants.h"
|
|
#include "ServerSettings.h"
|
|
#include "WebAppInterface.h"
|
|
|
|
|
|
#undef B_TRANSLATION_CONTEXT
|
|
#define B_TRANSLATION_CONTEXT "ServerHelper"
|
|
|
|
static const char* const kKeyMinimumVersion = "minimum_version";
|
|
|
|
/*! This is an HTTP header that the sever will send back to the client to inform
|
|
it about a version limit.
|
|
*/
|
|
static const char* const kKeyHeaderMinimumVersion = "X-Desktop-Application-Minimum-Version";
|
|
|
|
|
|
/*! \brief This method will cause an alert to be shown to the user regarding a
|
|
JSON-RPC error that has been sent from the application server. It will
|
|
send a message to the application looper which will then relay the message
|
|
to the looper and then onto the user to see.
|
|
\param responsePayload The top level payload returned from the server.
|
|
*/
|
|
|
|
/*static*/ void
|
|
ServerHelper::NotifyServerJsonRpcError(BMessage& responsePayload)
|
|
{
|
|
BMessage message(MSG_SERVER_ERROR);
|
|
message.AddMessage("error", &responsePayload);
|
|
be_app->PostMessage(&message);
|
|
}
|
|
|
|
|
|
/*static*/ void
|
|
ServerHelper::AlertServerJsonRpcError(BMessage* responseEnvelopeMessage)
|
|
{
|
|
BMessage errorMessage;
|
|
int32 errorCode = 0;
|
|
|
|
if (responseEnvelopeMessage->FindMessage("error", &errorMessage) == B_OK)
|
|
errorCode = WebAppInterface::ErrorCodeFromResponse(errorMessage);
|
|
|
|
BString alertText;
|
|
|
|
switch (errorCode) {
|
|
case ERROR_CODE_VALIDATION:
|
|
// TODO; expand on that message.
|
|
alertText = B_TRANSLATE("A validation error has occurred");
|
|
break;
|
|
case ERROR_CODE_OBJECTNOTFOUND:
|
|
alertText = B_TRANSLATE("A requested object or an object involved"
|
|
" in the request was not found on the server.");
|
|
break;
|
|
case ERROR_CODE_CAPTCHABADRESPONSE:
|
|
alertText = B_TRANSLATE("The response to the captcha was"
|
|
" incorrect.");
|
|
break;
|
|
case ERROR_CODE_AUTHORIZATIONFAILURE:
|
|
case ERROR_CODE_AUTHORIZATIONRULECONFLICT:
|
|
alertText = B_TRANSLATE("Authorization or security issue. Logout"
|
|
" and log back in again to check that your password is correct"
|
|
" and also check that you have agreed to the latest usage"
|
|
" conditions.");
|
|
break;
|
|
default:
|
|
alertText.SetToFormat(
|
|
B_TRANSLATE("An unexpected error has been sent from the"
|
|
" server [%" B_PRIi32 "]"), errorCode);
|
|
break;
|
|
}
|
|
|
|
BAlert* alert = new BAlert(
|
|
B_TRANSLATE("Server error"),
|
|
alertText,
|
|
B_TRANSLATE("OK"));
|
|
|
|
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
|
alert->Go();
|
|
}
|
|
|
|
|
|
/*static*/ void
|
|
ServerHelper::NotifyTransportError(status_t error)
|
|
{
|
|
switch (error) {
|
|
case HD_CLIENT_TOO_OLD:
|
|
// this is handled earlier on because it requires some
|
|
// information from the HTTP request to create a sensible
|
|
// error message.
|
|
break;
|
|
|
|
default:
|
|
{
|
|
BMessage message(MSG_NETWORK_TRANSPORT_ERROR);
|
|
message.AddInt64("errno", (int64) error);
|
|
be_app->PostMessage(&message);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*static*/ void
|
|
ServerHelper::AlertTransportError(BMessage* message)
|
|
{
|
|
if (ServerSettings::ForceNoNetwork()) {
|
|
HDERROR("Even though the user has opted to force no networking, a network transport error"
|
|
" is being alerted.");
|
|
return;
|
|
}
|
|
|
|
status_t error = B_OK;
|
|
int64 errnoInt64;
|
|
message->FindInt64("errno", &errnoInt64);
|
|
error = (status_t) errnoInt64;
|
|
|
|
BString errorDescription("?");
|
|
BString alertText;
|
|
|
|
switch (error) {
|
|
case HD_NETWORK_INACCESSIBLE:
|
|
errorDescription = B_TRANSLATE("Network error");
|
|
break;
|
|
default:
|
|
errorDescription.SetTo(strerror(error));
|
|
break;
|
|
}
|
|
|
|
alertText.SetToFormat(B_TRANSLATE("A network transport error has arisen communicating with the"
|
|
" server system: %s"),
|
|
errorDescription.String());
|
|
|
|
BAlert* alert = new BAlert(B_TRANSLATE("Network transport error"), alertText,
|
|
B_TRANSLATE("Stop network use"), B_TRANSLATE("OK"));
|
|
|
|
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
|
|
|
switch (alert->Go()) {
|
|
case 0:
|
|
HDINFO("user has opted to disable use of networking");
|
|
ServerSettings::SetForceNoNetwork(true);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*static*/ void
|
|
ServerHelper::NotifyClientTooOld(const BHttpHeaders& responseHeaders)
|
|
{
|
|
if (!ServerSettings::IsClientTooOld()) {
|
|
ServerSettings::SetClientTooOld();
|
|
|
|
const char* minimumVersionC = responseHeaders[kKeyHeaderMinimumVersion];
|
|
BMessage message(MSG_CLIENT_TOO_OLD);
|
|
|
|
if (minimumVersionC != NULL && strlen(minimumVersionC) != 0) {
|
|
message.AddString(kKeyMinimumVersion, minimumVersionC);
|
|
}
|
|
|
|
be_app->PostMessage(&message);
|
|
}
|
|
}
|
|
|
|
|
|
/*static*/ void
|
|
ServerHelper::AlertClientTooOld(BMessage* message)
|
|
{
|
|
BString minimumVersion;
|
|
BString alertText;
|
|
|
|
if (message->FindString(kKeyMinimumVersion, &minimumVersion) != B_OK)
|
|
minimumVersion = "???";
|
|
|
|
alertText.SetToFormat(
|
|
B_TRANSLATE("This application is too old to communicate with the"
|
|
" server system. Obtain a newer version of this application"
|
|
" by updating your system. The minimum required version of this"
|
|
" application is \"%s\"."), minimumVersion.String());
|
|
|
|
BAlert* alert = new BAlert(
|
|
B_TRANSLATE("Client version too old"),
|
|
alertText,
|
|
B_TRANSLATE("OK"));
|
|
|
|
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
|
alert->Go();
|
|
}
|
|
|
|
|
|
/*static*/ bool
|
|
ServerHelper::IsNetworkAvailable()
|
|
{
|
|
return !ServerSettings::ForceNoNetwork() && IsPlatformNetworkAvailable();
|
|
}
|
|
|
|
|
|
/*static*/ bool
|
|
ServerHelper::IsPlatformNetworkAvailable()
|
|
{
|
|
BNetworkRoster& roster = BNetworkRoster::Default();
|
|
BNetworkInterface interface;
|
|
uint32 cookie = 0;
|
|
while (roster.GetNextInterface(&cookie, interface) == B_OK) {
|
|
uint32 flags = interface.Flags();
|
|
if ((flags & IFF_LOOPBACK) == 0
|
|
&& (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/*! If the response is an error and the error is a validation failure then
|
|
* various validation errors may be carried in the error data. These are
|
|
* copied into the supplied failures. An abridged example input JSON structure
|
|
* would be;
|
|
*
|
|
* \code
|
|
* {
|
|
* ...
|
|
* "error": {
|
|
* "code": -32800,
|
|
* "data": { "nickname": "required" }
|
|
},
|
|
...
|
|
* }
|
|
* }
|
|
* \endcode
|
|
*
|
|
* \param failures is the object into which the validation failures are to be
|
|
* written.
|
|
* \param responseEnvelopeMessage is a representation of the entire
|
|
* response sent back from the server when the error occurred.
|
|
*
|
|
*/
|
|
|
|
/*static*/ void
|
|
ServerHelper::GetFailuresFromJsonRpcError(
|
|
ValidationFailures& failures, BMessage& responseEnvelopeMessage)
|
|
{
|
|
BMessage errorMessage;
|
|
|
|
if (responseEnvelopeMessage.FindMessage("error", &errorMessage) == B_OK) {
|
|
BMessage dataMessage;
|
|
|
|
if (errorMessage.FindMessage("data", &dataMessage) == B_OK) {
|
|
|
|
// the names and values (strings) are key-value pairs indicating
|
|
// the error.
|
|
|
|
int32 i = 0;
|
|
BMessage dataItemMessage;
|
|
|
|
while (dataMessage.FindMessage(BString() << i, &dataItemMessage)
|
|
== B_OK) {
|
|
BString key;
|
|
BString value;
|
|
if (dataItemMessage.FindString("key", &key) == B_OK
|
|
&& dataItemMessage.FindString("value", &value) == B_OK) {
|
|
failures.AddFailure(key, value);
|
|
} else {
|
|
HDERROR("possibly corrupt validation message missing key "
|
|
"or value");
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|