5using System.Threading.Tasks;
35 private string firebaseServiceAccountJson =
string.Empty;
36 private string firebaseApiKey =
string.Empty;
37 private string firebaseAuthDomain =
string.Empty;
38 private string firebaseProjectId =
string.Empty;
39 private string firebaseStorageBucket =
string.Empty;
40 private string firebaseMessagingSenderId =
string.Empty;
41 private string firebaseAppId =
string.Empty;
42 private string firebaseWebPushPublicKey =
string.Empty;
44 private DateTime firebaseServiceAccountJsonUploaded = DateTime.MinValue;
45 private bool useFirebase =
false;
54 [DefaultValueStringEmpty]
57 get => this.firebaseServiceAccountJson;
58 set => this.firebaseServiceAccountJson = value;
64 [DefaultValueStringEmpty]
67 get => this.firebaseApiKey;
68 set => this.firebaseApiKey = value;
74 [DefaultValueStringEmpty]
77 get => this.firebaseAuthDomain;
78 set => this.firebaseAuthDomain = value;
84 [DefaultValueStringEmpty]
87 get => this.firebaseProjectId;
88 set => this.firebaseProjectId = value;
94 [DefaultValueStringEmpty]
97 get => this.firebaseStorageBucket;
98 set => this.firebaseStorageBucket = value;
104 [DefaultValueStringEmpty]
107 get => this.firebaseMessagingSenderId;
108 set => this.firebaseMessagingSenderId = value;
114 [DefaultValueStringEmpty]
117 get => this.firebaseAppId;
118 set => this.firebaseAppId = value;
126 get => this.firebaseWebPushPublicKey;
127 set => this.firebaseWebPushPublicKey = value;
133 [DefaultValueDateTimeMinValue]
136 get => this.firebaseServiceAccountJsonUploaded;
137 set => this.firebaseServiceAccountJsonUploaded = value;
143 [DefaultValue(
false)]
146 get => this.useFirebase;
147 set => this.useFirebase = value;
163 public override string Resource =>
"/Settings/PushNotification.md";
186 firebaseClient =
null;
188 if (this.useFirebase && !
string.IsNullOrEmpty(this.firebaseServiceAccountJson))
189 firebaseClient = await GetClient(this.firebaseServiceAccountJson);
192 private static async Task<FirebaseClient> GetClient(
string ServiceAccountJson)
197 "Firebase Log %YEAR%-%MONTH%-%DAY%T%HOUR%.xml",
222 this.firebaseWebPushJavascript = WebServer.
Register(
"/Settings/FirebaseWebPush.js",
223 this.FirebaseWebPushJs,
true,
false,
false);
224 this.testFirebaseConnection = WebServer.
Register(
"/Settings/TestFirebaseConnection",
225 null, this.TestFirebaseConnection,
true,
false,
true);
226 this.testFirebaseNotification = WebServer.
Register(
"/Settings/TestFirebaseNotification",
227 null, this.TestFirebaseNotification,
true,
false,
true);
229 return base.InitSetup(WebServer);
238 WebServer.
Unregister(this.testFirebaseConnection);
239 WebServer.
Unregister(this.testFirebaseNotification);
241 return base.UnregisterSetup(WebServer);
251 Response.StatusCode = 200;
252 Response.StatusMessage =
"OK";
255 StringBuilder sb =
new StringBuilder();
257 sb.AppendLine(
"import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.12.4/firebase-app.js';");
258 sb.AppendLine(
"import { getMessaging, getToken } from 'https://www.gstatic.com/firebasejs/10.12.4/firebase-messaging.js';");
260 sb.AppendLine(
"const firebaseConfig =");
262 sb.Append(
"\tapiKey: '");
263 sb.Append(this.firebaseApiKey);
265 sb.Append(
"\tauthDomain: '");
266 sb.Append(this.firebaseAuthDomain);
268 sb.Append(
"\tprojectId: '");
269 sb.Append(this.firebaseProjectId);
271 sb.Append(
"\tstorageBucket: '");
272 sb.Append(this.firebaseStorageBucket);
274 sb.Append(
"\tmessagingSenderId: '");
275 sb.Append(this.firebaseMessagingSenderId);
277 sb.Append(
"\tappId: '");
278 sb.Append(this.firebaseAppId);
282 sb.AppendLine(
"const app = initializeApp(firebaseConfig);");
283 sb.AppendLine(
"const messaging = getMessaging(app);");
285 sb.AppendLine(
"window.GetFirebaseToken = function GetFirebaseToken()");
287 sb.AppendLine(
"\tgetToken(messaging, { vapidKey: '" + this.firebaseWebPushPublicKey +
"'}).then(");
288 sb.AppendLine(
"\t\t(token) =>");
289 sb.AppendLine(
"\t\t{");
290 sb.AppendLine(
"\t\t\tif (token)");
291 sb.AppendLine(
"\t\t\t\tFirebaseTokenReceived(token);");
292 sb.AppendLine(
"\t\t\telse");
293 sb.AppendLine(
"\t\t\t\tFirebaseTokenRejected();");
294 sb.AppendLine(
"\t\t}).catch((error) => FirebaseTokenFailure(error));");
297 await Response.
Write(sb.ToString());
312 !(Content.
Decoded is Dictionary<string, object> Form) ||
313 !Form.TryGetValue(
"useFirebase", out
object Obj) || !(Obj is
bool UseFirebase))
319 if (!Form.TryGetValue(
"firebaseWebConfig", out Obj) ||
320 !(Obj is
string FirebaseWebConfigJson) ||
321 string.IsNullOrEmpty(FirebaseWebConfigJson))
323 FirebaseWebConfigJson =
null;
326 if (!Form.TryGetValue(
"firebaseWebPushPublicKey", out Obj) ||
335 if (!Form.TryGetValue(
"serviceAccountJson", out Obj) ||
336 !(Obj is
string ServiceAccountJson) ||
337 string.IsNullOrEmpty(ServiceAccountJson))
339 ServiceAccountJson = this.firebaseServiceAccountJson;
342 if (Form.TryGetValue(
"firebaseMessagingSwJsContents", out Obj) &&
343 Obj is
string FirebaseMessagingSwJsContents)
346 FirebaseMessagingSwJsContents);
349 string TabID = Request.
Header[
"X-TabID"];
350 if (
string.IsNullOrEmpty(TabID))
356 bool Ok = await this.Test(
UseFirebase, FirebaseWebConfigJson, ServiceAccountJson, TabID);
358 string TimestampHtml = await
MarkdownToHtml.
ToHtml(
"JSON file uploaded: **{{Config.FirebaseServiceAccountJsonUploaded}}**.",
364 Response.StatusCode = 200;
365 Response.StatusMessage =
"OK";
366 await Response.
Return(
new Dictionary<string, object>()
369 {
"timestampHtml", TimestampHtml }
373 private async Task<bool> Test(
bool UseFirebase,
string FirebaseWebConfigJson,
string ServiceAccountJson, params
string[] TabIDs)
379 if (this.firebaseServiceAccountJson != ServiceAccountJson)
381 this.firebaseServiceAccountJson = ServiceAccountJson;
382 this.firebaseServiceAccountJsonUploaded = DateTime.Now;
385 if (!
string.IsNullOrEmpty(FirebaseWebConfigJson))
387 if (!(
JSON.
Parse(FirebaseWebConfigJson) is Dictionary<string, object> FirebaseWebConfig))
388 throw new Exception(
"Invalid Web Configuration JSON object.");
390 foreach (KeyValuePair<string, object> P
in FirebaseWebConfig)
392 if (!(P.Value is
string Value))
393 throw new Exception(
"Web Configuration object values must be strings.");
398 this.firebaseApiKey = Value;
402 this.firebaseAuthDomain = Value;
406 this.firebaseProjectId = Value;
409 case "storageBucket":
410 this.firebaseStorageBucket = Value;
413 case "messagingSenderId":
414 this.firebaseMessagingSenderId = Value;
418 this.firebaseAppId = Value;
422 throw new Exception(
"Unrecognized property: " + P.Key);
435 Client = await GetClient(ServiceAccountJson);
437 if (Client.
ProjectId !=
this.firebaseProjectId)
438 throw new Exception(
"Inconsistency between mobile phone and web Project IDs");
443 firebaseClient = Client;
456 firebaseClient =
null;
481 !(Content.
Decoded is Dictionary<string, object> Form) ||
482 !Form.TryGetValue(
"token", out
object Obj) || !(Obj is
string Token) ||
483 !Form.TryGetValue(
"title", out Obj) || !(Obj is
string Title) ||
484 !Form.TryGetValue(
"body", out Obj) || !(Obj is
string Body))
490 using FirebaseClient Client = await GetClient(this.firebaseServiceAccountJson);
497 Response.StatusCode = 200;
498 Response.StatusMessage =
"OK";
503 {
"ok", FirebaseResponse.Ok },
504 {
"errorMessage", FirebaseResponse.ErrorMessage }
514 return Task.FromResult(
true);
533 StringBuilder sb =
new StringBuilder();
534 sb.AppendLine(
"Push notification payload could not be parsed.");
536 sb.AppendLine(
"Pattern-Matching Script");
537 sb.AppendLine(
"--------------------------");
539 sb.AppendLine(
"```");
541 sb.AppendLine(
"```");
543 sb.AppendLine(
"Content Script");
544 sb.AppendLine(
"-----------");
546 sb.AppendLine(
"```");
548 sb.AppendLine(
"```");
551 new KeyValuePair<string, object>(
"BareJid", Rule.
BareJid.
Value),
552 new KeyValuePair<string, object>(
"MessageType", Rule.
MessageType),
553 new KeyValuePair<string, object>(
"Namespace", Rule.
Namespace),
554 new KeyValuePair<string, object>(
"LocalName", Rule.
LocalName),
555 new KeyValuePair<string, object>(
"Channel", Rule.
Channel),
556 new KeyValuePair<string, object>(
"MessageVariable", Rule.
MessageVariable),
557 new KeyValuePair<string, object>(
"Service", Token.
Service),
558 new KeyValuePair<string, object>(
"ClientType", Token.
ClientType),
559 new KeyValuePair<string, object>(
"Token", Token.
Token));
566 if (!(Client is
null))
587 public const string BROKER_FIREBASE_USE = nameof(BROKER_FIREBASE_USE);
592 public const string BROKER_FIREBASE_SERVICE_JSON = nameof(BROKER_FIREBASE_SERVICE_JSON);
597 public const string BROKER_FIREBASE_API_KEY = nameof(BROKER_FIREBASE_API_KEY);
602 public const string BROKER_FIREBASE_AUTH_DOMAIN = nameof(BROKER_FIREBASE_AUTH_DOMAIN);
607 public const string BROKER_FIREBASE_PROJECT_ID = nameof(BROKER_FIREBASE_PROJECT_ID);
612 public const string BROKER_FIREBASE_STORAGE_BUCKET = nameof(BROKER_FIREBASE_STORAGE_BUCKET);
617 public const string BROKER_FIREBASE_MESSAGING_SENDER_ID = nameof(BROKER_FIREBASE_MESSAGING_SENDER_ID);
622 public const string BROKER_FIREBASE_APP_ID = nameof(BROKER_FIREBASE_APP_ID);
630 if (!this.TryGetEnvironmentVariable(BROKER_FIREBASE_USE,
false, out this.useFirebase))
633 if (!this.useFirebase)
636 if (!this.TryGetEnvironmentVariable(BROKER_FIREBASE_SERVICE_JSON,
true, out
string FileName) ||
637 !File.Exists(FileName))
647 this.firebaseServiceAccountJson = Json;
648 this.firebaseServiceAccountJsonUploaded = DateTime.Now;
650 if (!this.TryGetEnvironmentVariable(BROKER_FIREBASE_API_KEY,
true, out this.firebaseApiKey) ||
651 !this.TryGetEnvironmentVariable(BROKER_FIREBASE_AUTH_DOMAIN,
true, out this.firebaseAuthDomain) ||
652 !this.TryGetEnvironmentVariable(BROKER_FIREBASE_PROJECT_ID,
true, out this.firebaseProjectId) ||
653 !this.TryGetEnvironmentVariable(BROKER_FIREBASE_STORAGE_BUCKET,
true, out this.firebaseStorageBucket) ||
654 !this.TryGetEnvironmentVariable(BROKER_FIREBASE_MESSAGING_SENDER_ID,
true, out this.firebaseMessagingSenderId) ||
655 !this.TryGetEnvironmentVariable(BROKER_FIREBASE_APP_ID,
true, out this.firebaseAppId))
660 return Client.ProjectId == this.firebaseProjectId;
Contains information about a response to a content request.
bool HasError
If an error occurred.
object Decoded
Decoded object.
JavaScript encoder/decoder.
const string DefaultContentType
application/javascript
Helps with common JSON-related tasks.
static object Parse(string Json)
Parses a JSON string.
static string Encode(string s)
Encodes a string for inclusion in JSON.
const string DefaultContentType
application/json
static Task< string > ToHtml(string Markdown)
Converts a Markdown snippet to a HTML snippet.
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
The ClientEvents class allows applications to push information asynchronously to web clients connecte...
static Task< int > PushEvent(string[] TabIDs, string Type, object Data)
Puses an event to a set of Tabs, given their Tab IDs.
static Task< bool > SetSettingAsync(IHostReference HostRef, string Key, string Value)
Sets a setting that may vary depending on domain.
Static class managing the runtime environment of the IoT Gateway.
static IUser AssertUserAuthenticated(HttpRequest Request, string Privilege)
Makes sure a request is being made from a session with a successful user login.
static string AppDataFolder
Application data folder.
static string RootFolder
Web root folder.
Abstract base class for multi-step system configurations.
static XmppConfiguration Instance
Current instance of configuration.
bool Sniffer
If communication should be sniffed.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
HTTP-based Firebase client.
static async Task< FirebaseClient > CreateAsync(string GoogleServiceAccountJson, bool Test, params ISniffer[] Sniffers)
Creates an HTTP-based Firebase client.
Task< NotificationResponse > SendNotification(string To, NotificationMessage Message)
Sends a push notification
void Dispose()
IDisposable.Dispose
string ProjectId
Project ID, as from Service Account JSON.
Builds Firebase Cloud Messaging notifications with platform-specific validation
NotificationBuilder ApplyPayload(PushNotificationPayload Payload)
Apply a transport-agnostic push payload to the underlying message/options/data.
Base class for Notification messages
Firebase response to sending a notification message.
Represents an HTTP request.
HttpRequestHeader Header
Request header.
bool HasData
If the request has data.
async Task< ContentResponse > DecodeDataAsync()
Decodes data sent in request.
Base class for all HTTP resources.
Represets a response of an HTTP client request.
async Task SendResponse()
Sends the response back to the client. If the resource is synchronous, there's no need to call this m...
Task Write(byte[] Data)
Returns binary data in the response.
Task Return(Exception ex)
Returns an error to the client.
Implements an HTTP server.
HttpResource Register(HttpResource Resource)
Registers a resource with the server.
bool Unregister(HttpResource Resource)
Unregisters a resource from the server.
Outputs sniffed data to an XML file.
Transport-agnostic push notification payload describing notification intent.
static bool TryParse(object Content, out PushNotificationPayload Payload)
Attempts to parse a payload from a script or serialized object.
Push Notification settings.
string Namespace
Namespace of XML content element in message
string PatternMatchingScript
Pattern-matching script used to extract information from the message being forwarded.
string MessageType
Message tpye
string Channel
Push Notification Channel to use
CaseInsensitiveString BareJid
Bare JID of device
string ContentScript
Content-building script to use when building content to include in notification message.
string MessageVariable
Variable to put the Message XML in, before pattern matching or content script is executed.
string LocalName
Local Name of XML content element in message
Push Notification settings.
string Token
Push notification service
ClientType ClientType
Service used for push notification
PushMessagingService Service
Service used for push notification
string Value
String-representation of the case-insensitive string. (Representation is case sensitive....
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static async Task Update(object Object)
Updates an object in the database.
static async Task< string > ReadAllTextAsync(string FileName)
Reads a text file asynchronously.
Contains information about a language.
Task< string > GetStringAsync(Type Type, int Id, string Default)
Gets the string value of a string ID. If no such string exists, a string is created with the default ...
Provides the user configuration options regarding use of Push Notification to reach offline clients.
string FirebaseProjectId
Firebase Project ID (Web Push)
string FirebaseApiKey
Firebase API Key (Web Push)
override void SetStaticInstance(ISystemConfiguration Configuration)
Sets the static instance of the configuration.
string FirebaseAuthDomain
Firebase Authentication Domain (Web Push)
override string ConfigPrivilege
Minimum required privilege for a user to be allowed to change the configuration defined by the class.
override async Task< bool > EnvironmentConfiguration()
Environment configuration by configuring values available in environment variables.
string FirebaseServiceAccountJson
Firebase Service Acccount JSON
override Task< bool > SimplifiedConfiguration()
Simplified configuration by configuring simple default values.
string FirebaseWebPushPublicKey
Firebase public Web Push (VAPID) key.
override int Priority
Priority of the setting. Configurations are sorted in ascending order.
static PushNotificationConfiguration Instance
Current instance of configuration.
string FirebaseAppId
Firebase App ID (Web Push)
override Task< string > Title(Language Language)
Gets a title for the system configuration.
string FirebaseStorageBucket
Firebase Storage Bucket (Web Push)
override async Task ConfigureSystem()
Is called during startup to configure the system.
bool UseFirebase
If Firebase is to be used to push notifications to offline clients.
override Task InitSetup(HttpServer WebServer)
Initializes the setup object.
string FirebaseMessagingSenderId
Firebase Messaging Sender ID (Web Push)
override Task UnregisterSetup(HttpServer WebServer)
Unregisters the setup object.
DateTime FirebaseServiceAccountJsonUploaded
When Firebase Service Account JSON was uploaded
Service Module hosting the XMPP broker and its components.
Interface for system configurations. The gateway will scan all module for system configuration classe...
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
BinaryPresentationMethod
How binary data is to be presented.
PushMessagingService
Push messaging service used.