2using System.Collections.Generic;
5using System.Threading.Tasks;
34 private string firebaseServiceAccountJson =
string.Empty;
35 private string firebaseApiKey =
string.Empty;
36 private string firebaseAuthDomain =
string.Empty;
37 private string firebaseProjectId =
string.Empty;
38 private string firebaseStorageBucket =
string.Empty;
39 private string firebaseMessagingSenderId =
string.Empty;
40 private string firebaseAppId =
string.Empty;
41 private string firebaseWebPushPublicKey =
string.Empty;
43 private DateTime firebaseServiceAccountJsonUploaded = DateTime.MinValue;
44 private bool useFirebase =
false;
53 [DefaultValueStringEmpty]
56 get => this.firebaseServiceAccountJson;
57 set => this.firebaseServiceAccountJson = value;
63 [DefaultValueStringEmpty]
66 get => this.firebaseApiKey;
67 set => this.firebaseApiKey = value;
73 [DefaultValueStringEmpty]
76 get => this.firebaseAuthDomain;
77 set => this.firebaseAuthDomain = value;
83 [DefaultValueStringEmpty]
86 get => this.firebaseProjectId;
87 set => this.firebaseProjectId = value;
93 [DefaultValueStringEmpty]
96 get => this.firebaseStorageBucket;
97 set => this.firebaseStorageBucket = value;
103 [DefaultValueStringEmpty]
106 get => this.firebaseMessagingSenderId;
107 set => this.firebaseMessagingSenderId = value;
113 [DefaultValueStringEmpty]
116 get => this.firebaseAppId;
117 set => this.firebaseAppId = value;
125 get => this.firebaseWebPushPublicKey;
126 set => this.firebaseWebPushPublicKey = value;
132 [DefaultValueDateTimeMinValue]
135 get => this.firebaseServiceAccountJsonUploaded;
136 set => this.firebaseServiceAccountJsonUploaded = value;
142 [DefaultValue(
false)]
145 get => this.useFirebase;
146 set => this.useFirebase = value;
162 public override string Resource =>
"/Settings/PushNotification.md";
185 firebaseClient =
null;
187 if (this.useFirebase && !
string.IsNullOrEmpty(this.firebaseServiceAccountJson))
188 firebaseClient = await GetClient(this.firebaseServiceAccountJson);
191 private static async Task<FirebaseClient> GetClient(
string ServiceAccountJson)
196 "Firebase Log %YEAR%-%MONTH%-%DAY%T%HOUR%.xml",
221 this.firebaseWebPushJavascript = WebServer.
Register(
"/Settings/FirebaseWebPush.js",
222 this.FirebaseWebPushJs,
true,
false,
false);
223 this.testFirebaseConnection = WebServer.
Register(
"/Settings/TestFirebaseConnection",
224 null, this.TestFirebaseConnection,
true,
false,
true);
225 this.testFirebaseNotification = WebServer.
Register(
"/Settings/TestFirebaseNotification",
226 null, this.TestFirebaseNotification,
true,
false,
true);
228 return base.InitSetup(WebServer);
237 WebServer.
Unregister(this.testFirebaseConnection);
238 WebServer.
Unregister(this.testFirebaseNotification);
240 return base.UnregisterSetup(WebServer);
250 Response.StatusCode = 200;
253 StringBuilder sb =
new StringBuilder();
255 sb.AppendLine(
"import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.12.4/firebase-app.js';");
256 sb.AppendLine(
"import { getMessaging, getToken } from 'https://www.gstatic.com/firebasejs/10.12.4/firebase-messaging.js';");
258 sb.AppendLine(
"const firebaseConfig =");
260 sb.Append(
"\tapiKey: '");
261 sb.Append(this.firebaseApiKey);
263 sb.Append(
"\tauthDomain: '");
264 sb.Append(this.firebaseAuthDomain);
266 sb.Append(
"\tprojectId: '");
267 sb.Append(this.firebaseProjectId);
269 sb.Append(
"\tstorageBucket: '");
270 sb.Append(this.firebaseStorageBucket);
272 sb.Append(
"\tmessagingSenderId: '");
273 sb.Append(this.firebaseMessagingSenderId);
275 sb.Append(
"\tappId: '");
276 sb.Append(this.firebaseAppId);
280 sb.AppendLine(
"const app = initializeApp(firebaseConfig);");
281 sb.AppendLine(
"const messaging = getMessaging(app);");
283 sb.AppendLine(
"window.GetFirebaseToken = function GetFirebaseToken()");
285 sb.AppendLine(
"\tgetToken(messaging, { vapidKey: '" + this.firebaseWebPushPublicKey +
"'}).then(");
286 sb.AppendLine(
"\t\t(token) =>");
287 sb.AppendLine(
"\t\t{");
288 sb.AppendLine(
"\t\t\tif (token)");
289 sb.AppendLine(
"\t\t\t\tFirebaseTokenReceived(token);");
290 sb.AppendLine(
"\t\t\telse");
291 sb.AppendLine(
"\t\t\t\tFirebaseTokenRejected();");
292 sb.AppendLine(
"\t\t}).catch((error) => FirebaseTokenFailure(error));");
295 await Response.
Write(sb.ToString());
306 if (!(Obj is Dictionary<string, object> Form) ||
307 !Form.TryGetValue(
"useFirebase", out Obj) || !(Obj is
bool UseFirebase))
312 if (!Form.TryGetValue(
"firebaseWebConfig", out Obj) ||
313 !(Obj is
string FirebaseWebConfigJson) ||
314 string.IsNullOrEmpty(FirebaseWebConfigJson))
316 FirebaseWebConfigJson =
null;
319 if (!Form.TryGetValue(
"firebaseWebPushPublicKey", out Obj) ||
327 if (!Form.TryGetValue(
"serviceAccountJson", out Obj) ||
328 !(Obj is
string ServiceAccountJson) ||
329 string.IsNullOrEmpty(ServiceAccountJson))
331 ServiceAccountJson = this.firebaseServiceAccountJson;
334 if (Form.TryGetValue(
"firebaseMessagingSwJsContents", out Obj) &&
335 Obj is
string FirebaseMessagingSwJsContents)
338 FirebaseMessagingSwJsContents);
341 string TabID = Request.
Header[
"X-TabID"];
342 if (
string.IsNullOrEmpty(TabID))
345 bool Ok = await this.Test(
UseFirebase, FirebaseWebConfigJson, ServiceAccountJson, TabID);
347 string TimestampHtml = await
MarkdownToHtml.
ToHtml(
"JSON file uploaded: **{{Config.FirebaseServiceAccountJsonUploaded}}**.",
353 Response.StatusCode = 200;
354 await Response.
Return(
new Dictionary<string, object>()
357 {
"timestampHtml", TimestampHtml }
361 private async Task<bool> Test(
bool UseFirebase,
string FirebaseWebConfigJson,
string ServiceAccountJson, params
string[] TabIDs)
367 if (this.firebaseServiceAccountJson != ServiceAccountJson)
369 this.firebaseServiceAccountJson = ServiceAccountJson;
370 this.firebaseServiceAccountJsonUploaded = DateTime.Now;
373 if (!
string.IsNullOrEmpty(FirebaseWebConfigJson))
375 if (!(
JSON.
Parse(FirebaseWebConfigJson) is Dictionary<string, object> FirebaseWebConfig))
376 throw new Exception(
"Invalid Web Configuration JSON object.");
378 foreach (KeyValuePair<string, object> P
in FirebaseWebConfig)
380 if (!(P.Value is
string Value))
381 throw new Exception(
"Web Configuration object values must be strings.");
386 this.firebaseApiKey = Value;
390 this.firebaseAuthDomain = Value;
394 this.firebaseProjectId = Value;
397 case "storageBucket":
398 this.firebaseStorageBucket = Value;
401 case "messagingSenderId":
402 this.firebaseMessagingSenderId = Value;
406 this.firebaseAppId = Value;
410 throw new Exception(
"Unrecognized property: " + P.Key);
423 Client = await GetClient(ServiceAccountJson);
425 if (Client.
ProjectId !=
this.firebaseProjectId)
426 throw new Exception(
"Inconsistency between mobile phone and web Project IDs");
431 firebaseClient = Client;
444 firebaseClient =
null;
465 if (!(Obj is Dictionary<string, object> Form) ||
466 !Form.TryGetValue(
"token", out Obj) || !(Obj is
string Token) ||
467 !Form.TryGetValue(
"title", out Obj) || !(Obj is
string Title) ||
468 !Form.TryGetValue(
"body", out Obj) || !(Obj is
string Body))
473 using (
FirebaseClient Client = await GetClient(this.firebaseServiceAccountJson))
481 Response.StatusCode = 200;
486 {
"ok", FirebaseResponse.Ok },
487 {
"errorMessage", FirebaseResponse.ErrorMessage }
498 return Task.FromResult(
true);
513 Dictionary<string, object> Data =
null;
537 if (Content is Dictionary<string, object> JsonObject)
539 foreach (KeyValuePair<string, object> P
in JsonObject)
540 SetProperty(Message, Options, ref Data, P.Key, P.Value);
542 else if (Content is Dictionary<string, IElement> ScriptObject)
544 foreach (KeyValuePair<string, IElement> P
in ScriptObject)
545 SetProperty(Message, Options, ref Data, P.Key, P.Value.AssociatedObjectValue);
548 Message.Body = Content?.ToString();
551 if (!(Client is
null))
563 string Key,
object Value)
568 Data =
new Dictionary<string, object>();
570 if (Key ==
"data" && Value is Dictionary<string, object> DataItems)
572 foreach (KeyValuePair<string, object> P
in DataItems)
573 Data[P.Key] = P.Value;
583 public const string BROKER_FIREBASE_USE = nameof(BROKER_FIREBASE_USE);
588 public const string BROKER_FIREBASE_SERVICE_JSON = nameof(BROKER_FIREBASE_SERVICE_JSON);
593 public const string BROKER_FIREBASE_API_KEY = nameof(BROKER_FIREBASE_API_KEY);
598 public const string BROKER_FIREBASE_AUTH_DOMAIN = nameof(BROKER_FIREBASE_AUTH_DOMAIN);
603 public const string BROKER_FIREBASE_PROJECT_ID = nameof(BROKER_FIREBASE_PROJECT_ID);
608 public const string BROKER_FIREBASE_STORAGE_BUCKET = nameof(BROKER_FIREBASE_STORAGE_BUCKET);
613 public const string BROKER_FIREBASE_MESSAGING_SENDER_ID = nameof(BROKER_FIREBASE_MESSAGING_SENDER_ID);
618 public const string BROKER_FIREBASE_APP_ID = nameof(BROKER_FIREBASE_APP_ID);
626 if (!this.TryGetEnvironmentVariable(BROKER_FIREBASE_USE,
false, out this.useFirebase))
629 if (!this.useFirebase)
632 if (!this.TryGetEnvironmentVariable(BROKER_FIREBASE_SERVICE_JSON,
true, out
string FileName) ||
633 !File.Exists(FileName))
643 this.firebaseServiceAccountJson = Json;
644 this.firebaseServiceAccountJsonUploaded = DateTime.Now;
646 if (!this.TryGetEnvironmentVariable(BROKER_FIREBASE_API_KEY,
true, out this.firebaseApiKey) ||
647 !this.TryGetEnvironmentVariable(BROKER_FIREBASE_AUTH_DOMAIN,
true, out this.firebaseAuthDomain) ||
648 !this.TryGetEnvironmentVariable(BROKER_FIREBASE_PROJECT_ID,
true, out this.firebaseProjectId) ||
649 !this.TryGetEnvironmentVariable(BROKER_FIREBASE_STORAGE_BUCKET,
true, out this.firebaseStorageBucket) ||
650 !this.TryGetEnvironmentVariable(BROKER_FIREBASE_MESSAGING_SENDER_ID,
true, out this.firebaseMessagingSenderId) ||
651 !this.TryGetEnvironmentVariable(BROKER_FIREBASE_APP_ID,
true, out this.firebaseAppId))
656 return Client.ProjectId == this.firebaseProjectId;
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 loading of resources stored as embedded resources or in content files.
static async Task< string > ReadAllTextAsync(string FileName)
Reads a text file asynchronously.
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.
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.
Notification message for Android
Notification message for Apple
Base class for Notification messages
virtual bool TrySetProperty(string Name, object Value)
Tries to set a property value.
Notification message for Web
bool TrySetProperty(string Name, object Value)
Tries to set a property value.
Firebase response to sending a notification message.
Represents an HTTP request.
HttpRequestHeader Header
Request header.
bool HasData
If the request has data.
async Task< object > DecodeDataAsync()
Decodes data sent in request.
Base class for all HTTP resources.
Represets a response of an HTTP client request.
async Task Return(object Object)
Returns an object to the client. This method can only be called once per response,...
async Task Write(byte[] Data)
Returns binary data in the response.
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.
Push Notification settings.
string Token
Push notification service
ClientType ClientType
Service used for push notification
PushMessagingService Service
Service used for push notification
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.
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)
override string Resource
Resource to be redirected to, to perform the configuration.
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.
ClientType
Type of client requesting notification.