154312619SAndrew Lindesay /*
2dfbcbde1SAndrew Lindesay * Copyright 2017-2021, Andrew Lindesay <apl@lindesay.co.nz>.
354312619SAndrew Lindesay * All rights reserved. Distributed under the terms of the MIT License.
454312619SAndrew Lindesay */
554312619SAndrew Lindesay
63369e03dSAndrew Lindesay
754312619SAndrew Lindesay #include "ServerHelper.h"
854312619SAndrew Lindesay
954312619SAndrew Lindesay #include <stdio.h>
1054312619SAndrew Lindesay #include <stdlib.h>
1154312619SAndrew Lindesay
1254312619SAndrew Lindesay #include <Alert.h>
1354312619SAndrew Lindesay #include <Application.h>
1454312619SAndrew Lindesay #include <Catalog.h>
1554312619SAndrew Lindesay #include <NetworkInterface.h>
1654312619SAndrew Lindesay #include <NetworkRoster.h>
1754312619SAndrew Lindesay
1821df7324SAndrew Lindesay #include "Logger.h"
1954312619SAndrew Lindesay #include "HaikuDepotConstants.h"
2054312619SAndrew Lindesay #include "ServerSettings.h"
21a9edb9bfSAndrew Lindesay #include "WebAppInterface.h"
2254312619SAndrew Lindesay
2354312619SAndrew Lindesay
2454312619SAndrew Lindesay #undef B_TRANSLATION_CONTEXT
2554312619SAndrew Lindesay #define B_TRANSLATION_CONTEXT "ServerHelper"
263369e03dSAndrew Lindesay
2754312619SAndrew Lindesay #define KEY_MSG_MINIMUM_VERSION "minimumVersion"
2854312619SAndrew Lindesay #define KEY_HEADER_MINIMUM_VERSION "X-Desktop-Application-Minimum-Version"
2954312619SAndrew Lindesay
3054312619SAndrew Lindesay
31835e7239SAndrew Lindesay /*! \brief This method will cause an alert to be shown to the user regarding a
32a9edb9bfSAndrew Lindesay JSON-RPC error that has been sent from the application server. It will
33a9edb9bfSAndrew Lindesay send a message to the application looper which will then relay the message
34a9edb9bfSAndrew Lindesay to the looper and then onto the user to see.
35835e7239SAndrew Lindesay \param responsePayload The top level payload returned from the server.
36a9edb9bfSAndrew Lindesay */
37a9edb9bfSAndrew Lindesay
383369e03dSAndrew Lindesay /*static*/ void
NotifyServerJsonRpcError(BMessage & responsePayload)39835e7239SAndrew Lindesay ServerHelper::NotifyServerJsonRpcError(BMessage& responsePayload)
40a9edb9bfSAndrew Lindesay {
41a9edb9bfSAndrew Lindesay BMessage message(MSG_SERVER_ERROR);
42835e7239SAndrew Lindesay message.AddMessage("error", &responsePayload);
43a9edb9bfSAndrew Lindesay be_app->PostMessage(&message);
44a9edb9bfSAndrew Lindesay }
45a9edb9bfSAndrew Lindesay
46a9edb9bfSAndrew Lindesay
473369e03dSAndrew Lindesay /*static*/ void
AlertServerJsonRpcError(BMessage * responseEnvelopeMessage)48835e7239SAndrew Lindesay ServerHelper::AlertServerJsonRpcError(BMessage* responseEnvelopeMessage)
49a9edb9bfSAndrew Lindesay {
50835e7239SAndrew Lindesay BMessage errorMessage;
51a9edb9bfSAndrew Lindesay int32 errorCode = 0;
52a9edb9bfSAndrew Lindesay
53835e7239SAndrew Lindesay if (responseEnvelopeMessage->FindMessage("error", &errorMessage) == B_OK)
54835e7239SAndrew Lindesay errorCode = WebAppInterface::ErrorCodeFromResponse(errorMessage);
55a9edb9bfSAndrew Lindesay
56a9edb9bfSAndrew Lindesay BString alertText;
57a9edb9bfSAndrew Lindesay
58a9edb9bfSAndrew Lindesay switch (errorCode) {
59a9edb9bfSAndrew Lindesay case ERROR_CODE_VALIDATION:
60a9edb9bfSAndrew Lindesay // TODO; expand on that message.
61a9edb9bfSAndrew Lindesay alertText = B_TRANSLATE("A validation error has occurred");
62a9edb9bfSAndrew Lindesay break;
63a9edb9bfSAndrew Lindesay case ERROR_CODE_OBJECTNOTFOUND:
64a9edb9bfSAndrew Lindesay alertText = B_TRANSLATE("A requested object or an object involved"
65a9edb9bfSAndrew Lindesay " in the request was not found on the server.");
66a9edb9bfSAndrew Lindesay break;
67a9edb9bfSAndrew Lindesay case ERROR_CODE_CAPTCHABADRESPONSE:
68d17c92f7SAndrew Lindesay alertText = B_TRANSLATE("The response to the captcha was"
69d17c92f7SAndrew Lindesay " incorrect.");
70a9edb9bfSAndrew Lindesay break;
71a9edb9bfSAndrew Lindesay case ERROR_CODE_AUTHORIZATIONFAILURE:
72a9edb9bfSAndrew Lindesay case ERROR_CODE_AUTHORIZATIONRULECONFLICT:
73d17c92f7SAndrew Lindesay alertText = B_TRANSLATE("Authorization or security issue. Logout"
74d17c92f7SAndrew Lindesay " and log back in again to check that your password is correct"
75d17c92f7SAndrew Lindesay " and also check that you have agreed to the latest usage"
76d17c92f7SAndrew Lindesay " conditions.");
77a9edb9bfSAndrew Lindesay break;
78a9edb9bfSAndrew Lindesay default:
79a9edb9bfSAndrew Lindesay alertText.SetToFormat(
80a9edb9bfSAndrew Lindesay B_TRANSLATE("An unexpected error has been sent from the"
81548467a9SAndrew Lindesay " server [%" B_PRIi32 "]"), errorCode);
82a9edb9bfSAndrew Lindesay break;
83a9edb9bfSAndrew Lindesay }
84a9edb9bfSAndrew Lindesay
85a9edb9bfSAndrew Lindesay BAlert* alert = new BAlert(
86548467a9SAndrew Lindesay B_TRANSLATE("Server error"),
87a9edb9bfSAndrew Lindesay alertText,
88a9edb9bfSAndrew Lindesay B_TRANSLATE("OK"));
89a9edb9bfSAndrew Lindesay
90a9edb9bfSAndrew Lindesay alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
91a9edb9bfSAndrew Lindesay alert->Go();
92a9edb9bfSAndrew Lindesay }
93a9edb9bfSAndrew Lindesay
94a9edb9bfSAndrew Lindesay
953369e03dSAndrew Lindesay /*static*/ void
NotifyTransportError(status_t error)96a9edb9bfSAndrew Lindesay ServerHelper::NotifyTransportError(status_t error)
97a9edb9bfSAndrew Lindesay {
98a9edb9bfSAndrew Lindesay switch (error) {
99a9edb9bfSAndrew Lindesay case HD_CLIENT_TOO_OLD:
100a9edb9bfSAndrew Lindesay // this is handled earlier on because it requires some
101a9edb9bfSAndrew Lindesay // information from the HTTP request to create a sensible
102a9edb9bfSAndrew Lindesay // error message.
103a9edb9bfSAndrew Lindesay break;
104a9edb9bfSAndrew Lindesay
105a9edb9bfSAndrew Lindesay default:
106a9edb9bfSAndrew Lindesay {
107a9edb9bfSAndrew Lindesay BMessage message(MSG_NETWORK_TRANSPORT_ERROR);
108a9edb9bfSAndrew Lindesay message.AddInt64("errno", (int64) error);
109a9edb9bfSAndrew Lindesay be_app->PostMessage(&message);
110a9edb9bfSAndrew Lindesay break;
111a9edb9bfSAndrew Lindesay }
112a9edb9bfSAndrew Lindesay }
113a9edb9bfSAndrew Lindesay }
114a9edb9bfSAndrew Lindesay
115a9edb9bfSAndrew Lindesay
1163369e03dSAndrew Lindesay /*static*/ void
AlertTransportError(BMessage * message)117a9edb9bfSAndrew Lindesay ServerHelper::AlertTransportError(BMessage* message)
118a9edb9bfSAndrew Lindesay {
119*91a0b530SAugustin Cavalier status_t error = B_OK;
120a9edb9bfSAndrew Lindesay int64 errnoInt64;
121a9edb9bfSAndrew Lindesay message->FindInt64("errno", &errnoInt64);
122*91a0b530SAugustin Cavalier error = (status_t) errnoInt64;
123a9edb9bfSAndrew Lindesay
124a9edb9bfSAndrew Lindesay BString errorDescription("?");
125a9edb9bfSAndrew Lindesay BString alertText;
126a9edb9bfSAndrew Lindesay
127*91a0b530SAugustin Cavalier switch (error) {
128a9edb9bfSAndrew Lindesay case HD_NETWORK_INACCESSIBLE:
129548467a9SAndrew Lindesay errorDescription = B_TRANSLATE("Network error");
130a9edb9bfSAndrew Lindesay break;
131a9edb9bfSAndrew Lindesay default:
132*91a0b530SAugustin Cavalier errorDescription.SetTo(strerror(error));
133a9edb9bfSAndrew Lindesay break;
134a9edb9bfSAndrew Lindesay }
135a9edb9bfSAndrew Lindesay
136a9edb9bfSAndrew Lindesay alertText.SetToFormat(B_TRANSLATE("A network transport error has arisen"
137548467a9SAndrew Lindesay " communicating with the server system: %s"),
138a9edb9bfSAndrew Lindesay errorDescription.String());
139a9edb9bfSAndrew Lindesay
140a9edb9bfSAndrew Lindesay BAlert* alert = new BAlert(
141548467a9SAndrew Lindesay B_TRANSLATE("Network transport error"),
142a9edb9bfSAndrew Lindesay alertText,
143a9edb9bfSAndrew Lindesay B_TRANSLATE("OK"));
144a9edb9bfSAndrew Lindesay
145a9edb9bfSAndrew Lindesay alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
146a9edb9bfSAndrew Lindesay alert->Go();
147a9edb9bfSAndrew Lindesay }
148a9edb9bfSAndrew Lindesay
149a9edb9bfSAndrew Lindesay
1503369e03dSAndrew Lindesay /*static*/ void
NotifyClientTooOld(const BHttpHeaders & responseHeaders)15154312619SAndrew Lindesay ServerHelper::NotifyClientTooOld(const BHttpHeaders& responseHeaders)
15254312619SAndrew Lindesay {
15354312619SAndrew Lindesay if (!ServerSettings::IsClientTooOld()) {
15454312619SAndrew Lindesay ServerSettings::SetClientTooOld();
15554312619SAndrew Lindesay
15654312619SAndrew Lindesay const char* minimumVersionC = responseHeaders[KEY_HEADER_MINIMUM_VERSION];
15754312619SAndrew Lindesay BMessage message(MSG_CLIENT_TOO_OLD);
15854312619SAndrew Lindesay
15954312619SAndrew Lindesay if (minimumVersionC != NULL && strlen(minimumVersionC) != 0) {
16054312619SAndrew Lindesay message.AddString(KEY_MSG_MINIMUM_VERSION, minimumVersionC);
16154312619SAndrew Lindesay }
16254312619SAndrew Lindesay
16354312619SAndrew Lindesay be_app->PostMessage(&message);
16454312619SAndrew Lindesay }
16554312619SAndrew Lindesay }
16654312619SAndrew Lindesay
16754312619SAndrew Lindesay
1683369e03dSAndrew Lindesay /*static*/ void
AlertClientTooOld(BMessage * message)16954312619SAndrew Lindesay ServerHelper::AlertClientTooOld(BMessage* message)
17054312619SAndrew Lindesay {
17154312619SAndrew Lindesay BString minimumVersion;
17254312619SAndrew Lindesay BString alertText;
17354312619SAndrew Lindesay
17454312619SAndrew Lindesay if (message->FindString(KEY_MSG_MINIMUM_VERSION, &minimumVersion) != B_OK)
17554312619SAndrew Lindesay minimumVersion = "???";
17654312619SAndrew Lindesay
17754312619SAndrew Lindesay alertText.SetToFormat(
17854312619SAndrew Lindesay B_TRANSLATE("This application is too old to communicate with the"
179548467a9SAndrew Lindesay " server system. Obtain a newer version of this application"
180548467a9SAndrew Lindesay " by updating your system. The minimum required version of this"
181548467a9SAndrew Lindesay " application is \"%s\"."), minimumVersion.String());
18254312619SAndrew Lindesay
18354312619SAndrew Lindesay BAlert* alert = new BAlert(
184f5cdaacdSHumdinger B_TRANSLATE("Client version too old"),
18554312619SAndrew Lindesay alertText,
18654312619SAndrew Lindesay B_TRANSLATE("OK"));
18754312619SAndrew Lindesay
18854312619SAndrew Lindesay alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
18954312619SAndrew Lindesay alert->Go();
19054312619SAndrew Lindesay }
19154312619SAndrew Lindesay
19254312619SAndrew Lindesay
1933369e03dSAndrew Lindesay /*static*/ bool
IsNetworkAvailable()19454312619SAndrew Lindesay ServerHelper::IsNetworkAvailable()
19554312619SAndrew Lindesay {
19654312619SAndrew Lindesay return !ServerSettings::ForceNoNetwork() && IsPlatformNetworkAvailable();
19754312619SAndrew Lindesay }
19854312619SAndrew Lindesay
19954312619SAndrew Lindesay
2003369e03dSAndrew Lindesay /*static*/ bool
IsPlatformNetworkAvailable()20154312619SAndrew Lindesay ServerHelper::IsPlatformNetworkAvailable()
20254312619SAndrew Lindesay {
20354312619SAndrew Lindesay BNetworkRoster& roster = BNetworkRoster::Default();
20454312619SAndrew Lindesay BNetworkInterface interface;
20554312619SAndrew Lindesay uint32 cookie = 0;
20654312619SAndrew Lindesay while (roster.GetNextInterface(&cookie, interface) == B_OK) {
20754312619SAndrew Lindesay uint32 flags = interface.Flags();
20854312619SAndrew Lindesay if ((flags & IFF_LOOPBACK) == 0
20954312619SAndrew Lindesay && (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) {
21054312619SAndrew Lindesay return true;
21154312619SAndrew Lindesay }
21254312619SAndrew Lindesay }
21354312619SAndrew Lindesay
21454312619SAndrew Lindesay return false;
21554312619SAndrew Lindesay }
216835e7239SAndrew Lindesay
217835e7239SAndrew Lindesay
218835e7239SAndrew Lindesay /*! If the response is an error and the error is a validation failure then
219835e7239SAndrew Lindesay * various validation errors may be carried in the error data. These are
220835e7239SAndrew Lindesay * copied into the supplied failures. An abridged example input JSON structure
221835e7239SAndrew Lindesay * would be;
222835e7239SAndrew Lindesay *
223835e7239SAndrew Lindesay * \code
224835e7239SAndrew Lindesay * {
225835e7239SAndrew Lindesay * ...
226835e7239SAndrew Lindesay * "error": {
227835e7239SAndrew Lindesay * "code": -32800,
22821df7324SAndrew Lindesay * "data": { "nickname": "required" }
229835e7239SAndrew Lindesay },
230835e7239SAndrew Lindesay ...
231835e7239SAndrew Lindesay * }
232835e7239SAndrew Lindesay * }
233835e7239SAndrew Lindesay * \endcode
234835e7239SAndrew Lindesay *
235835e7239SAndrew Lindesay * \param failures is the object into which the validation failures are to be
236835e7239SAndrew Lindesay * written.
23721df7324SAndrew Lindesay * \param responseEnvelopeMessage is a representation of the entire
238835e7239SAndrew Lindesay * response sent back from the server when the error occurred.
239835e7239SAndrew Lindesay *
240835e7239SAndrew Lindesay */
241835e7239SAndrew Lindesay
242835e7239SAndrew Lindesay /*static*/ void
GetFailuresFromJsonRpcError(ValidationFailures & failures,BMessage & responseEnvelopeMessage)243835e7239SAndrew Lindesay ServerHelper::GetFailuresFromJsonRpcError(
244835e7239SAndrew Lindesay ValidationFailures& failures, BMessage& responseEnvelopeMessage)
245835e7239SAndrew Lindesay {
246835e7239SAndrew Lindesay BMessage errorMessage;
247835e7239SAndrew Lindesay
248835e7239SAndrew Lindesay if (responseEnvelopeMessage.FindMessage("error", &errorMessage) == B_OK) {
249835e7239SAndrew Lindesay BMessage dataMessage;
250835e7239SAndrew Lindesay
251835e7239SAndrew Lindesay if (errorMessage.FindMessage("data", &dataMessage) == B_OK) {
252835e7239SAndrew Lindesay
25321df7324SAndrew Lindesay // the names and values (strings) are key-value pairs indicating
25421df7324SAndrew Lindesay // the error.
255835e7239SAndrew Lindesay
25621df7324SAndrew Lindesay int32 i = 0;
25721df7324SAndrew Lindesay BMessage dataItemMessage;
258835e7239SAndrew Lindesay
25921df7324SAndrew Lindesay while (dataMessage.FindMessage(BString() << i, &dataItemMessage)
26021df7324SAndrew Lindesay == B_OK) {
26121df7324SAndrew Lindesay BString key;
26221df7324SAndrew Lindesay BString value;
26321df7324SAndrew Lindesay if (dataItemMessage.FindString("key", &key) == B_OK
26421df7324SAndrew Lindesay && dataItemMessage.FindString("value", &value) == B_OK) {
26521df7324SAndrew Lindesay failures.AddFailure(key, value);
26621df7324SAndrew Lindesay } else {
26721df7324SAndrew Lindesay HDERROR("possibly corrupt validation message missing key "
26821df7324SAndrew Lindesay "or value");
26921df7324SAndrew Lindesay }
27021df7324SAndrew Lindesay i++;
27121df7324SAndrew Lindesay }
272835e7239SAndrew Lindesay }
273835e7239SAndrew Lindesay }
274835e7239SAndrew Lindesay }
275