xref: /haiku/src/apps/haikudepot/server/ServerHelper.cpp (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
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