private async void UpdateTheme(ThemeDefinition Def, string TabID) { try { this.themeId = Def.Id; if (this.Step <= 0) { this.Step = 1; } this.Updated = DateTime.Now; await Database.Update(this); Gateway.HttpServer.ETagSalt = this.Updated.Ticks.ToString(); ClientEvents.PushEvent(new string[] { TabID }, "ThemeOk", JSON.Encode(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("themeId", Def.Id), new KeyValuePair <string, object>("cssUrl", Def.CSSX), }, false), true, "User"); } catch (Exception ex) { Log.Critical(ex); } }
/// <summary> /// Evaluates the function. /// </summary> /// <param name="Arguments">Function arguments.</param> /// <param name="Variables">Variables collection.</param> /// <returns>Function result.</returns> public override IElement Evaluate(IElement[] Arguments, Variables Variables) { int c = Arguments.Length; int d = c - 2; IElement[] A = new IElement[d]; Array.Copy(Arguments, 0, A, 0, d); string[] TabIDs = GetTabIDs.GetTabs(A, this); if (TabIDs.Length > 0) { object Data = Arguments[c - 1].AssociatedObjectValue; if (Data is string s) { ClientEvents.PushEvent(TabIDs, Arguments[c - 2].AssociatedObjectValue?.ToString(), s, false); } else { ClientEvents.PushEvent(TabIDs, Arguments[c - 2].AssociatedObjectValue?.ToString(), JSON.Encode(Data, false), true); } } return(new ObjectVector(TabIDs)); }
/// <summary> /// Evaluates the function. /// </summary> /// <param name="Arguments">Function arguments.</param> /// <param name="Variables">Variables collection.</param> /// <returns>Function result.</returns> public override IElement Evaluate(IElement[] Arguments, Variables Variables) { string[] TabIDs = GetTabIDs.GetTabs(Arguments, this); if (TabIDs.Length > 0) { ClientEvents.PushEvent(TabIDs, "Reload", ""); } return(new ObjectVector(TabIDs)); }
/// <summary> /// Removes a file from all pages viewing backup files /// </summary> /// <param name="FileName">Name of file</param> public static void UpdateClientsFileDeleted(string FileName) { StringBuilder sb = new StringBuilder(); sb.Append("{\"fileName\":\""); sb.Append(CommonTypes.JsonStringEncode(FileName)); sb.Append("\"}"); string[] TabIDs = ClientEvents.GetTabIDsForLocation("/Settings/Backup.md"); Task _ = ClientEvents.PushEvent(TabIDs, "FileDeleted", sb.ToString(), true, "User"); }
private void RosterItemRemoved(string BareJid) { string[] TabIDs = this.GetTabIDs(); if (TabIDs.Length > 0) { string Json = JSON.Encode(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("bareJid", BareJid) }, false); Task _ = ClientEvents.PushEvent(TabIDs, "RemoveRosterItem", Json, true, "User"); } }
private void XmppClient_OnRosterItemUpdated(object Sender, RosterItem Item) { string[] TabIDs = this.GetTabIDs(); if (TabIDs.Length > 0) { string Json = JSON.Encode(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("bareJid", Item.BareJid), new KeyValuePair <string, object>("html", this.RosterItemsHtml(new RosterItem[] { Item }, new PresenceEventArgs[0])) }, false); ClientEvents.PushEvent(TabIDs, "UpdateRosterItem", Json, true, "User"); } }
private async Task Push(DateTime Timestamp, string Message, string Function, bool CloseIfNoTabs) { try { DateTime Now = DateTime.Now; if ((Now - this.tabIdTimestamp).TotalSeconds > 2 || this.tabIds is null || this.tabIds.Length == 0) { this.tabIds = ClientEvents.GetTabIDsForLocation(this.resource, true, "SnifferId", this.snifferId); this.tabIdTimestamp = Now; } if (this.feedbackCheck && Message.StartsWith("{") && Message.EndsWith("}")) { try { object Parsed = JSON.Parse(Message); if (Parsed is IDictionary <string, object> Obj && Obj.TryGetValue("data", out object Temp) && Temp is IDictionary <string, object> Obj2 && Obj2.TryGetValue("timestamp", out object Timestamp2) && Obj2.TryGetValue("message", out object Message2) && (this.outgoing?.ContainsKey(this.ToJson(Timestamp2, Message2)) ?? true)) { return; } } catch (Exception) { // Ignore } } string Data = this.ToJson(XML.Encode(Timestamp), Message); this.outgoing?.Add(Data, true); int Tabs = await ClientEvents.PushEvent(this.tabIds, Function, Data, true, this.userVariable, this.privileges); if (CloseIfNoTabs && Tabs <= 0 && (Now - this.created).TotalSeconds >= 5) { await this.Close(); } } catch (Exception ex) { Log.Critical(ex); } }
private void XmppClient_OnStateChanged(object Sender, XmppState NewState) { if (NewState == XmppState.Offline || NewState == XmppState.Error || NewState == XmppState.Connected) { string[] TabIDs = this.GetTabIDs(); if (TabIDs.Length > 0 && !(Gateway.XmppClient is null)) { string Json = JSON.Encode(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("html", this.RosterItemsHtml(Gateway.XmppClient.Roster, Gateway.XmppClient.SubscriptionRequests)) }, false); ClientEvents.PushEvent(TabIDs, "UpdateRoster", Json, true, "User"); } } }
private async Task <bool> Test(string TabID, string DomainName) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Testing " + DomainName + "...", false, "User"); this.token = Hashes.BinaryToString(Gateway.NextBytes(32)); using (HttpClient HttpClient = new HttpClient() { Timeout = TimeSpan.FromMilliseconds(10000) }) { try { HttpResponseMessage Response = await HttpClient.GetAsync("http://" + DomainName + "/Settings/TestDomainName"); if (!Response.IsSuccessStatusCode) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Domain name does not point to this machine.", false, "User"); return(false); } byte[] Bin = await Response.Content.ReadAsByteArrayAsync(); string Token = Encoding.ASCII.GetString(Bin); if (Token != this.token) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unexpected response returned. Domain name does not point to this machine.", false, "User"); return(false); } } catch (TimeoutException) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Time-out. Check that the domain name points to this machine.", false, "User"); return(false); } catch (Exception ex) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unable to validate domain name: " + ex.Message, false, "User"); return(false); } } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Domain name valid.", false, "User"); return(true); }
private async void Test(string TabID) { try { if (!string.IsNullOrEmpty(this.domain)) { if (!await this.Test(TabID, this.domain)) { ClientEvents.PushEvent(new string[] { TabID }, "NameNotValid", this.domain, false, "User"); return; } } if (this.alternativeDomains != null) { foreach (string AltDomainName in this.alternativeDomains) { if (!await this.Test(TabID, AltDomainName)) { ClientEvents.PushEvent(new string[] { TabID }, "NameNotValid", AltDomainName, false, "User"); return; } } } if (this.Step < 1) { this.Step = 1; } this.Updated = DateTime.Now; await Database.Update(this); ClientEvents.PushEvent(new string[] { TabID }, "NamesOK", string.Empty, false, "User"); } catch (Exception ex) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", ex.Message, false, "User"); } }
private void XmppClient_OnPresenceSubscribe(object Sender, PresenceEventArgs e) { StringBuilder Markdown = new StringBuilder(); Markdown.Append("Presence subscription request received from **"); Markdown.Append(MarkdownDocument.Encode(e.FromBareJID)); Markdown.Append("**. You can accept or decline the request from the roster configuration in the Administration portal."); Gateway.SendNotification(Markdown.ToString()); string[] TabIDs = this.GetTabIDs(); if (TabIDs.Length > 0) { string Json = JSON.Encode(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("bareJid", e.FromBareJID), new KeyValuePair <string, object>("html", this.RosterItemsHtml(new RosterItem[0], new PresenceEventArgs[] { e })) }, false); ClientEvents.PushEvent(TabIDs, "UpdateRosterItem", Json, true, "User"); } }
/// <summary> /// Updates the status of a file on all pages viewing backup files /// </summary> /// <param name="FileName">Name of file</param> /// <param name="Length">Size of file</param> /// <param name="Created">When file was created</param> public static void UpdateClientsFileUpdated(string FileName, long Length, DateTime Created) { StringBuilder sb = new StringBuilder(); sb.Append("{\"fileName\":\""); sb.Append(CommonTypes.JsonStringEncode(FileName)); sb.Append("\", \"size\": \""); if (Length >= 0) { sb.Append(CommonTypes.JsonStringEncode(Export.FormatBytes(Length))); } sb.Append("\", \"created\": \""); sb.Append(CommonTypes.JsonStringEncode(Created.ToString())); sb.Append("\", \"button\": \""); sb.Append(CommonTypes.JsonStringEncode("<button class=\"posButtonSm\" onclick=\"DeleteExport('" + FileName + "');\">Delete</button>")); sb.Append("\", \"isKey\": "); sb.Append(FileName.EndsWith(".key", StringComparison.CurrentCultureIgnoreCase) ? "true" : "false"); sb.Append("}"); string[] TabIDs = ClientEvents.GetTabIDsForLocation("/Settings/Backup.md"); Task _ = ClientEvents.PushEvent(TabIDs, "UpdateExport", sb.ToString(), true, "User"); }
internal async Task <bool> CreateCertificate(string TabID) { try { string URL = this.customCA ? this.acmeDirectory : "https://acme-v02.api.letsencrypt.org/directory"; RSAParameters Parameters; CspParameters CspParams = new CspParameters() { Flags = CspProviderFlags.UseMachineKeyStore, KeyContainerName = "IoTGateway:" + URL }; try { bool Ok; using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(4096, CspParams)) { Parameters = RSA.ExportParameters(true); if (RSA.KeySize < 4096) { RSA.PersistKeyInCsp = false; RSA.Clear(); Ok = false; } else { Ok = true; } } if (!Ok) { using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(4096, CspParams)) { Parameters = RSA.ExportParameters(true); } } } catch (CryptographicException ex) { throw new CryptographicException("Unable to get access to cryptographic key for \"IoTGateway:" + URL + "\". Was the database created using another user?", ex); } using (AcmeClient Client = new AcmeClient(new Uri(URL), Parameters)) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Connecting to directory.", false, "User"); AcmeDirectory AcmeDirectory = await Client.GetDirectory(); if (AcmeDirectory.ExternalAccountRequired) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "An external account is required.", false, "User"); } if (AcmeDirectory.TermsOfService != null) { URL = AcmeDirectory.TermsOfService.ToString(); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Terms of service available on: " + URL, false, "User"); ClientEvents.PushEvent(new string[] { TabID }, "TermsOfService", URL, false, "User"); this.urlToS = URL; if (!this.acceptToS) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "You need to accept the terms of service.", false, "User"); return(false); } } if (AcmeDirectory.Website != null) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Web site available on: " + AcmeDirectory.Website.ToString(), false, "User"); } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Getting account.", false, "User"); List <string> Names = new List <string>(); if (!string.IsNullOrEmpty(this.domain)) { Names.Add(this.domain); } if (this.alternativeDomains != null) { foreach (string Name in this.alternativeDomains) { if (!Names.Contains(Name)) { Names.Add(Name); } } } string[] DomainNames = Names.ToArray(); AcmeAccount Account; try { Account = await Client.GetAccount(); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Account found.", false, "User"); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Created: " + Account.CreatedAt.ToString(), false, "User"); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Initial IP: " + Account.InitialIp, false, "User"); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Status: " + Account.Status.ToString(), false, "User"); if (string.IsNullOrEmpty(this.contactEMail)) { if (Account.Contact != null && Account.Contact.Length != 0) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Updating contact URIs in account.", false, "User"); Account = await Account.Update(new string[0]); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Account updated.", false, "User"); } } else { if (Account.Contact is null || Account.Contact.Length != 1 || Account.Contact[0] != "mailto:" + this.contactEMail) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Updating contact URIs in account.", false, "User"); Account = await Account.Update(new string[] { "mailto:" + this.contactEMail }); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Account updated.", false, "User"); } } } catch (AcmeAccountDoesNotExistException) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Account not found.", false, "User"); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Creating account.", false, "User"); Account = await Client.CreateAccount(string.IsNullOrEmpty(this.contactEMail)?new string[0] : new string[] { "mailto:" + this.contactEMail }, this.acceptToS); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Account created.", false, "User"); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Status: " + Account.Status.ToString(), false, "User"); } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Generating new key.", false, "User"); await Account.NewKey(); using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(4096, CspParams)) { RSA.ImportParameters(Client.ExportAccountKey(true)); } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "New key generated.", false, "User"); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Creating order.", false, "User"); AcmeOrder Order = await Account.OrderCertificate(DomainNames, null, null); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Order created.", false, "User"); foreach (AcmeAuthorization Authorization in await Order.GetAuthorizations()) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Processing authorization for " + Authorization.Value, false, "User"); AcmeChallenge Challenge; bool Acknowledged = false; int Index = 1; int NrChallenges = Authorization.Challenges.Length; for (Index = 1; Index <= NrChallenges; Index++) { Challenge = Authorization.Challenges[Index - 1]; if (Challenge is AcmeHttpChallenge HttpChallenge) { this.challenge = "/" + HttpChallenge.Token; this.token = HttpChallenge.KeyAuthorization; ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Acknowleding challenge.", false, "User"); Challenge = await HttpChallenge.AcknowledgeChallenge(); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Challenge acknowledged: " + Challenge.Status.ToString(), false, "User"); Acknowledged = true; } } if (!Acknowledged) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "No automated method found to respond to any of the authorization challenges.", false, "User"); return(false); } AcmeAuthorization Authorization2 = Authorization; do { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Waiting to poll authorization status.", false, "User"); await Task.Delay(5000); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Polling authorization.", false, "User"); Authorization2 = await Authorization2.Poll(); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Authorization polled: " + Authorization2.Status.ToString(), false, "User"); }while (Authorization2.Status == AcmeAuthorizationStatus.pending); if (Authorization2.Status != AcmeAuthorizationStatus.valid) { switch (Authorization2.Status) { case AcmeAuthorizationStatus.deactivated: throw new Exception("Authorization deactivated."); case AcmeAuthorizationStatus.expired: throw new Exception("Authorization expired."); case AcmeAuthorizationStatus.invalid: throw new Exception("Authorization invalid."); case AcmeAuthorizationStatus.revoked: throw new Exception("Authorization revoked."); default: throw new Exception("Authorization not validated."); } } } using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(4096)) // TODO: Make configurable { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Finalizing order.", false, "User"); SignatureAlgorithm SignAlg = new RsaSha256(RSA); Order = await Order.FinalizeOrder(new CertificateRequest(SignAlg) { CommonName = this.domain, SubjectAlternativeNames = DomainNames, EMailAddress = this.contactEMail }); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Order finalized: " + Order.Status.ToString(), false, "User"); if (Order.Status != AcmeOrderStatus.valid) { switch (Order.Status) { case AcmeOrderStatus.invalid: throw new Exception("Order invalid."); default: throw new Exception("Unable to validate oder."); } } if (Order.Certificate is null) { throw new Exception("No certificate URI provided."); } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Downloading certificate.", false, "User"); X509Certificate2[] Certificates = await Order.DownloadCertificate(); X509Certificate2 Certificate = Certificates[0]; ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Exporting certificate.", false, "User"); this.certificate = Certificate.Export(X509ContentType.Cert); this.privateKey = RSA.ExportCspBlob(true); this.pfx = null; this.password = string.Empty; ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Adding private key.", false, "User"); try { Certificate.PrivateKey = RSA; } catch (PlatformNotSupportedException) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Platform does not support adding of private key.", false, "User"); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Searching for OpenSSL on machine.", false, "User"); string[] Files; string Password = Hashes.BinaryToString(Gateway.NextBytes(32)); string CertFileName = null; string CertFileName2 = null; string KeyFileName = null; if (string.IsNullOrEmpty(this.openSslPath) || !File.Exists(this.openSslPath)) { Files = GetFiles(new string(Path.DirectorySeparatorChar, 1), "openssl.exe"); if (Files is null) { List <string> Files2 = new List <string>(); Files = GetFiles(Environment.SpecialFolder.ProgramFiles, "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = GetFiles(Environment.SpecialFolder.CommonProgramFilesX86, "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = GetFiles(Environment.SpecialFolder.Programs, "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = GetFiles(Environment.SpecialFolder.System, "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = GetFiles(Environment.SpecialFolder.SystemX86, "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = GetFiles(Environment.SpecialFolder.Windows, "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = GetFiles(Environment.SpecialFolder.CommonProgramFiles, "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = GetFiles(Environment.SpecialFolder.CommonProgramFilesX86, "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = GetFiles(Environment.SpecialFolder.CommonPrograms, "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = GetFiles(Path.DirectorySeparatorChar + "OpenSSL-Win32", "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = GetFiles(Path.DirectorySeparatorChar + "OpenSSL-Win64", "openssl.exe"); if (Files != null) { Files2.AddRange(Files); } Files = Files2.ToArray(); } } else { Files = new string[] { this.openSslPath } }; try { if (Files.Length == 0) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unable to join certificate with private key. Try installing <a target=\"_blank\" href=\"https://wiki.openssl.org/index.php/Binaries\">OpenSSL</a> and try again.", false, "User"); return(false); } else { foreach (string OpenSslFile in Files) { if (CertFileName is null) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Generating temporary certificate file.", false, "User"); StringBuilder PemOutput = new StringBuilder(); byte[] Bin = Certificate.Export(X509ContentType.Cert); PemOutput.AppendLine("-----BEGIN CERTIFICATE-----"); PemOutput.AppendLine(Convert.ToBase64String(Bin, Base64FormattingOptions.InsertLineBreaks)); PemOutput.AppendLine("-----END CERTIFICATE-----"); CertFileName = Path.Combine(Gateway.AppDataFolder, "Certificate.pem"); File.WriteAllText(CertFileName, PemOutput.ToString(), Encoding.ASCII); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Generating temporary key file.", false, "User"); DerEncoder KeyOutput = new DerEncoder(); SignAlg.ExportPrivateKey(KeyOutput); PemOutput.Clear(); PemOutput.AppendLine("-----BEGIN RSA PRIVATE KEY-----"); PemOutput.AppendLine(Convert.ToBase64String(KeyOutput.ToArray(), Base64FormattingOptions.InsertLineBreaks)); PemOutput.AppendLine("-----END RSA PRIVATE KEY-----"); KeyFileName = Path.Combine(Gateway.AppDataFolder, "Certificate.key"); File.WriteAllText(KeyFileName, PemOutput.ToString(), Encoding.ASCII); } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Converting to PFX using " + OpenSslFile, false, "User"); Process P = new Process() { StartInfo = new ProcessStartInfo() { FileName = OpenSslFile, Arguments = "pkcs12 -nodes -export -out Certificate.pfx -inkey Certificate.key -in Certificate.pem -password pass:"******"ShowStatus", "Output: " + P.StandardOutput.ReadToEnd(), false, "User"); } if (!P.StandardError.EndOfStream) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Error: " + P.StandardError.ReadToEnd(), false, "User"); } continue; } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Loading PFX.", false, "User"); CertFileName2 = Path.Combine(Gateway.AppDataFolder, "Certificate.pfx"); this.pfx = File.ReadAllBytes(CertFileName2); this.password = Password; this.openSslPath = OpenSslFile; ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "PFX successfully generated using OpenSSL.", false, "User"); break; } if (this.pfx is null) { this.openSslPath = string.Empty; ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unable to convert to PFX using OpenSSL.", false, "User"); return(false); } } } finally { if (CertFileName != null && File.Exists(CertFileName)) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Deleting temporary certificate file.", false, "User"); File.Delete(CertFileName); } if (KeyFileName != null && File.Exists(KeyFileName)) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Deleting temporary key file.", false, "User"); File.Delete(KeyFileName); } if (CertFileName2 != null && File.Exists(CertFileName2)) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Deleting temporary pfx file.", false, "User"); File.Delete(CertFileName2); } } } if (this.Step < 2) { this.Step = 2; } this.Updated = DateTime.Now; await Database.Update(this); ClientEvents.PushEvent(new string[] { TabID }, "CertificateOk", string.Empty, false, "User"); Gateway.UpdateCertificate(this); return(true); } } } catch (Exception ex) { Log.Critical(ex); ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unable to create certificate: " + XML.HtmlValueEncode(ex.Message), false, "User"); return(false); } finally { this.inProgress = false; } }
/// <summary> /// Exports gateway data /// </summary> /// <param name="Output">Export Output</param> /// <param name="Database">If the contents of the database is to be exported.</param> /// <param name="WebContent">If web content is to be exported.</param> /// <param name="Folders">Root subfolders to export.</param> public static async Task DoExport(IExportFormat Output, bool Database, bool WebContent, string[] Folders) { try { List <KeyValuePair <string, object> > Tags = new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("Database", Database) }; foreach (string Folder in Folders) { Tags.Add(new KeyValuePair <string, object>(Folder, true)); } Log.Informational("Starting export.", Output.FileName, Tags.ToArray()); await Output.Start(); if (Database) { StringBuilder Temp = new StringBuilder(); using (XmlWriter w = XmlWriter.Create(Temp, XML.WriterSettings(false, true))) { await Persistence.Database.Analyze(w, string.Empty, Path.Combine(Gateway.RootFolder, "Data"), false, true); } await Persistence.Database.Export(Output); } if (WebContent || Folders.Length > 0) { await Output.StartFiles(); try { string[] FileNames; string Folder2; if (WebContent) { FileNames = Directory.GetFiles(Gateway.RootFolder, "*.*", SearchOption.TopDirectoryOnly); foreach (string FileName in FileNames) { await ExportFile(FileName, Output); } Export.FolderCategory[] ExportFolders = Export.GetRegisteredFolders(); foreach (string Folder in Directory.GetDirectories(Gateway.RootFolder, "*.*", SearchOption.TopDirectoryOnly)) { bool IsWebContent = true; foreach (Export.FolderCategory FolderCategory in ExportFolders) { foreach (string Folder3 in FolderCategory.Folders) { if (string.Compare(Folder3, Folder, true) == 0) { IsWebContent = false; break; } } if (!IsWebContent) { break; } } if (IsWebContent) { FileNames = Directory.GetFiles(Folder, "*.*", SearchOption.AllDirectories); foreach (string FileName in FileNames) { await ExportFile(FileName, Output); } } } } foreach (string Folder in Folders) { if (Directory.Exists(Folder2 = Path.Combine(Gateway.RootFolder, Folder))) { FileNames = Directory.GetFiles(Folder2, "*.*", SearchOption.AllDirectories); foreach (string FileName in FileNames) { await ExportFile(FileName, Output); } } } } finally { await Output.EndFiles(); } } Log.Informational("Export successfully completed.", Output.FileName); } catch (Exception ex) { Log.Critical(ex); string[] Tabs = ClientEvents.GetTabIDsForLocation("/Backup.md"); ClientEvents.PushEvent(Tabs, "BackupFailed", "{\"fileName\":\"" + CommonTypes.JsonStringEncode(Output.FileName) + "\", \"message\": \"" + CommonTypes.JsonStringEncode(ex.Message) + "\"}", true, "User"); } finally { try { await Output.End(); Output.Dispose(); } catch (Exception ex) { Log.Critical(ex); } lock (synchObject) { exporting = false; } } }
private async void Client_OnStateChanged(object Sender, XmppState NewState) { if (!(Sender is XmppClient Client)) { return; } if (!Client.TryGetTag("TabID", out object Obj) || !(Obj is string TabID)) { return; } try { string Msg; switch (NewState) { case XmppState.Authenticating: Client.SetTag("StartedAuthentication", true); Client.SetTag("EncyptionSuccessful", true); if (this.Step == 0) { ClientEvents.PushEvent(new string[] { TabID }, "ConnectionOK0", "Connection established.", false, "User"); this.client.Dispose(); this.client = null; this.Step = 1; this.Updated = DateTime.Now; await Database.Update(this); return; } else { Msg = "Authenticating user."; } break; case XmppState.Binding: Msg = "Binding to resource."; break; case XmppState.Connected: this.bareJid = Client.BareJID; if (this.createAccount && !string.IsNullOrEmpty(this.accountHumanReadableName)) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Setting vCard.", false, "User"); StringBuilder Xml = new StringBuilder(); Xml.Append("<vCard xmlns='vcard-temp'>"); Xml.Append("<FN>"); Xml.Append(XML.Encode(this.accountHumanReadableName)); Xml.Append("</FN>"); Xml.Append("<JABBERID>"); Xml.Append(XML.Encode(this.client.BareJID)); Xml.Append("</JABBERID>"); Xml.Append("</vCard>"); await Client.IqSetAsync(this.client.BareJID, Xml.ToString()); } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Checking server features.", false, "User"); ServiceDiscoveryEventArgs e = await Client.ServiceDiscoveryAsync(null, string.Empty, string.Empty); if (e.Ok) { this.offlineMessages = e.HasFeature("msgoffline"); this.blocking = e.HasFeature(Networking.XMPP.Abuse.AbuseClient.NamespaceBlocking); this.reporting = e.HasFeature(Networking.XMPP.Abuse.AbuseClient.NamespaceReporting); this.abuse = e.HasFeature(Networking.XMPP.Abuse.AbuseClient.NamespaceAbuseReason); this.spam = e.HasFeature(Networking.XMPP.Abuse.AbuseClient.NamespaceSpamReason); this.mail = e.HasFeature("urn:xmpp:smtp"); } else { this.offlineMessages = false; this.blocking = false; this.reporting = false; this.abuse = false; this.spam = false; this.mail = false; } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Checking account features.", false, "User"); e = await Client.ServiceDiscoveryAsync(null, Client.BareJID, string.Empty); this.pep = e.Ok && this.ContainsIdentity("pep", "pubsub", e); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Checking server components.", false, "User"); ServiceItemsDiscoveryEventArgs e2 = await Client.ServiceItemsDiscoveryAsync(null, string.Empty, string.Empty); this.thingRegistry = string.Empty; this.provisioning = string.Empty; this.events = string.Empty; this.pubSub = string.Empty; this.legal = string.Empty; this.software = string.Empty; if (e2.Ok) { foreach (Item Item in e2.Items) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Checking component features for " + Item.JID, false, "User"); e = await Client.ServiceDiscoveryAsync(null, Item.JID, string.Empty); if (e.HasFeature(Networking.XMPP.Provisioning.ThingRegistryClient.NamespaceDiscovery)) { this.thingRegistry = Item.JID; } if (e.HasFeature(Networking.XMPP.Provisioning.ProvisioningClient.NamespaceProvisioningDevice)) { this.provisioning = Item.JID; } if (e.HasFeature(Networking.XMPP.PubSub.PubSubClient.NamespacePubSub) && this.ContainsIdentity("service", "pubsub", e)) { this.pubSub = Item.JID; } if (e.HasFeature(Waher.Events.XMPP.XmppEventSink.NamespaceEventLogging)) { this.events = Item.JID; } if (e.HasFeature(Networking.XMPP.Contracts.ContractsClient.NamespaceLegalIdentities)) { this.legal = Item.JID; } if (e.HasFeature(Networking.XMPP.Software.SoftwareUpdateClient.NamespaceSoftwareUpdates)) { this.software = Item.JID; } } } Dictionary <string, object> ConnectionInfo = new Dictionary <string, object>() { { "msg", "Connection successful." }, { "offlineMsg", this.offlineMessages }, { "blocking", this.blocking }, { "reporting", this.reporting }, { "abuse", this.abuse }, { "spam", this.spam }, { "mail", this.mail }, { "pep", this.pep ? this.bareJid : string.Empty }, { "thingRegistry", this.thingRegistry }, { "provisioning", this.provisioning }, { "eventLog", this.events }, { "pubSub", this.pubSub }, { "legal", this.legal }, { "software", this.software } }; ClientEvents.PushEvent(new string[] { TabID }, "ConnectionOK1", JSON.Encode(ConnectionInfo, false), true, "User"); this.client.Dispose(); this.client = null; this.Step = 2; this.Updated = DateTime.Now; await Database.Update(this); return; case XmppState.Connecting: Msg = "Connecting to server."; break; case XmppState.Error: bool Error = false; Msg = string.Empty; if (this.Step == 0 && this.transportMethod == XmppTransportMethod.C2S) { this.customBinding = true; ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Unable to connect properly. Looking for alternative ways to connect.", false, "User"); ClientEvents.PushEvent(new string[] { TabID }, "ShowCustomProperties", "{\"visible\":true}", true, "User"); using (HttpClient HttpClient = new HttpClient(new HttpClientHandler() { #if !NETFW ServerCertificateCustomValidationCallback = this.RemoteCertificateValidationCallback, #endif UseCookies = false }) { Timeout = TimeSpan.FromMilliseconds(60000) }) { try { HttpResponseMessage Response = await HttpClient.GetAsync("http://" + this.host + "/.well-known/host-meta"); Response.EnsureSuccessStatusCode(); Stream Stream = await Response.Content.ReadAsStreamAsync(); // Regardless of status code, we check for XML content. byte[] Bin = await Response.Content.ReadAsByteArrayAsync(); string CharSet = Response.Content.Headers.ContentType.CharSet; Encoding Encoding; if (string.IsNullOrEmpty(CharSet)) { Encoding = Encoding.UTF8; } else { Encoding = InternetContent.GetEncoding(CharSet); } string XmlResponse = Encoding.GetString(Bin); XmlDocument Doc = new XmlDocument(); Doc.LoadXml(XmlResponse); if (Doc.DocumentElement != null && Doc.DocumentElement.LocalName == "XRD") { string BoshUrl = null; string WsUrl = null; foreach (XmlNode N in Doc.DocumentElement.ChildNodes) { if (N is XmlElement E && E.LocalName == "Link") { switch (XML.Attribute(E, "rel")) { case "urn:xmpp:alt-connections:xbosh": BoshUrl = XML.Attribute(E, "href"); break; case "urn:xmpp:alt-connections:websocket": WsUrl = XML.Attribute(E, "href"); break; } } } if (!string.IsNullOrEmpty(WsUrl)) { this.wsUrl = WsUrl; this.transportMethod = XmppTransportMethod.WS; ClientEvents.PushEvent(new string[] { TabID }, "ShowTransport", "{\"method\":\"WS\"}", true, "User"); this.Connect(TabID); return; } else if (!string.IsNullOrEmpty(BoshUrl)) { this.boshUrl = BoshUrl; this.transportMethod = XmppTransportMethod.BOSH; ClientEvents.PushEvent(new string[] { TabID }, "ShowTransport", "{\"method\":\"BOSH\"}", true, "User"); this.Connect(TabID); return; } } } catch (Exception) { // Ignore. } Msg = "No alternative binding methods found."; Error = true; } } else { Msg = "Unable to connect properly."; Error = true; if (Client.TryGetTag("StartedAuthentication", out Obj) && Obj is bool b && b) { if (this.createAccount) { ClientEvents.PushEvent(new string[] { TabID }, "ShowFail2", Msg, false, "User"); } else { ClientEvents.PushEvent(new string[] { TabID }, "ShowFail1", Msg, false, "User"); } return; } } if (Error) { ClientEvents.PushEvent(new string[] { TabID }, "ConnectionError", Msg, false, "User"); this.client.Dispose(); this.client = null; return; } break; case XmppState.FetchingRoster: Msg = "Fetching roster from server."; break; case XmppState.Offline: Msg = "Offline."; break; case XmppState.Registering: Msg = "Registering account."; break; case XmppState.RequestingSession: Msg = "Requesting session."; break; case XmppState.SettingPresence: Msg = "Setting presence."; break; case XmppState.StartingEncryption: Msg = "Starting encryption."; Client.SetTag("StartedEncryption", true); break; case XmppState.StreamNegotiation: Msg = "Negotiating stream."; break; case XmppState.StreamOpened: Msg = "Stream opened."; break; default: Msg = NewState.ToString(); break; } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", Msg, false, "User"); } catch (Exception ex) { Log.Critical(ex); ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", ex.Message, false, "User"); } }
/// <summary> /// Analyzes the object database /// </summary> /// <param name="FullPath">Full path of report file</param> /// <param name="FileName">Filename of report</param> /// <param name="Created">Time when report file was created</param> /// <param name="XmlOutput">XML Output</param> /// <param name="fs">File stream</param> /// <param name="Repair">If database should be repaired, if errors are found</param> public static async Task DoAnalyze(string FullPath, string FileName, DateTime Created, XmlWriter XmlOutput, FileStream fs, bool Repair) { try { Log.Informational("Starting analyzing database.", FileName); ExportFormats.ExportFormat.UpdateClientsFileUpdated(FileName, 0, Created); await Database.Analyze(XmlOutput, Path.Combine(Gateway.AppDataFolder, "Transforms", "DbStatXmlToHtml.xslt"), Gateway.AppDataFolder, false, Repair); XmlOutput.Flush(); fs.Flush(); ExportFormats.ExportFormat.UpdateClientsFileUpdated(FileName, fs.Length, Created); XmlOutput.Dispose(); XmlOutput = null; fs.Dispose(); fs = null; if (xslt is null) { xslt = XSL.LoadTransform(typeof(Gateway).Namespace + ".Transforms.DbStatXmlToHtml.xslt"); } string s = File.ReadAllText(FullPath); s = XSL.Transform(s, xslt); byte[] Bin = utf8Bom.GetBytes(s); string FullPath2 = FullPath.Substring(0, FullPath.Length - 4) + ".html"; File.WriteAllBytes(FullPath2, Bin); ExportFormats.ExportFormat.UpdateClientsFileUpdated(FileName.Substring(0, FileName.Length - 4) + ".html", Bin.Length, Created); Log.Informational("Database analysis successfully completed.", FileName); } catch (Exception ex) { Log.Critical(ex); string[] Tabs = ClientEvents.GetTabIDsForLocation("/Settings/Backup.md"); ClientEvents.PushEvent(Tabs, "BackupFailed", "{\"fileName\":\"" + CommonTypes.JsonStringEncode(FileName) + "\", \"message\": \"" + CommonTypes.JsonStringEncode(ex.Message) + "\"}", true, "User"); } finally { try { XmlOutput?.Dispose(); fs?.Dispose(); } catch (Exception ex) { Log.Critical(ex); } lock (synchObject) { analyzing = false; } } }
/// <summary> /// Queues an event to be output. /// </summary> /// <param name="Event">Event to queue.</param> public override async Task Queue(Event Event) { try { DateTime Now = DateTime.Now; if ((Now - this.tabIdTimestamp).TotalSeconds > 2 || this.tabIds is null || this.tabIds.Length == 0) { this.tabIds = ClientEvents.GetTabIDsForLocation(this.resource, true); this.tabIdTimestamp = Now; } Dictionary <string, object>[] Tags; if (Event.Tags is null) { Tags = null; } else { int i, c = Event.Tags.Length; Tags = new Dictionary <string, object> [c]; for (i = 0; i < c; i++) { Tags[i] = new Dictionary <string, object>() { { "name", Event.Tags[i].Key }, { "value", Event.Tags[i].Value } }; } } string Data = JSON.Encode(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("date", XML.Encode(Event.Timestamp.Date, true)), new KeyValuePair <string, object>("time", Event.Timestamp.TimeOfDay.ToString()), new KeyValuePair <string, object>("type", Event.Type.ToString()), new KeyValuePair <string, object>("level", Event.Level.ToString()), new KeyValuePair <string, object>("id", Event.EventId), new KeyValuePair <string, object>("object", Event.Object), new KeyValuePair <string, object>("actor", Event.Actor), new KeyValuePair <string, object>("module", Event.Module), new KeyValuePair <string, object>("facility", Event.Facility), new KeyValuePair <string, object>("message", Event.Message), new KeyValuePair <string, object>("stackTrace", Event.StackTrace), new KeyValuePair <string, object>("tags", Tags) }, false); int Tabs = await ClientEvents.PushEvent(this.tabIds, "NewEvent", Data, true, this.userVariable, this.privileges); if (Now >= this.expires || (Tabs <= 0 && (Now - this.created).TotalSeconds >= 5)) { await ClientEvents.PushEvent(this.tabIds, "SinkClosed", string.Empty, false, this.userVariable, this.privileges); Log.Unregister(this); this.Dispose(); } } catch (Exception ex) { Log.Critical(ex); } }
private async Task <bool> Test(string TabID, string DomainName) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Testing " + DomainName + "...", false, "User"); if (!await this.CheckDynamicIp(TabID, DomainName)) { return(false); } this.token = Hashes.BinaryToString(Gateway.NextBytes(32)); using (HttpClient HttpClient = new HttpClient() { Timeout = TimeSpan.FromMilliseconds(10000) }) { try { StringBuilder Url = new StringBuilder(); int[] HttpPorts = Gateway.GetConfigPorts("HTTP"); Url.Append("http://"); Url.Append(DomainName); if (Array.IndexOf <int>(HttpPorts, 80) < 0 && HttpPorts.Length > 0) { Url.Append(':'); Url.Append(HttpPorts[0].ToString()); } Url.Append("/Settings/TestDomainName"); HttpResponseMessage Response = await HttpClient.GetAsync("http://" + DomainName + "/Settings/TestDomainName"); if (!Response.IsSuccessStatusCode) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Domain name does not point to this machine.", false, "User"); return(false); } byte[] Bin = await Response.Content.ReadAsByteArrayAsync(); string Token = Encoding.ASCII.GetString(Bin); if (Token != this.token) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unexpected response returned. Domain name does not point to this machine.", false, "User"); return(false); } } catch (TimeoutException) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Time-out. Check that the domain name points to this machine.", false, "User"); return(false); } catch (Exception ex) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unable to validate domain name: " + ex.Message, false, "User"); return(false); } } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Domain name valid.", false, "User"); return(true); }
internal async Task <bool> CheckDynamicIp(string TabID, string DomainName) { if (!this.dynamicDns) { return(true); } Expression CheckIpScript; Expression UpdateIpScript; try { CheckIpScript = new Expression(this.checkIpScript); } catch (Exception ex) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unable to parse script checking current IP Address: " + ex.Message, false, "User"); return(false); } try { UpdateIpScript = new Expression(this.updateIpScript); } catch (Exception ex) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unable to parse script updating the dynamic DNS server: " + ex.Message, false, "User"); return(false); } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Checking current IP Address.", false, "User"); Variables Variables = new Variables(); object Result; try { Result = CheckIpScript.Evaluate(Variables); } catch (Exception ex) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unable to get current IP Address: " + ex.Message, false, "User"); return(false); } if (!(Result is string CurrentIP) || !IPAddress.TryParse(CurrentIP, out IPAddress _)) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unable to get current IP Address. Unexpected response.", false, "User"); return(false); } ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Current IP Address: " + CurrentIP, false, "User"); string LastIP = await RuntimeSettings.GetAsync("Last.IP." + DomainName, string.Empty); if (LastIP == CurrentIP) { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "IP Address has not changed for " + DomainName + ".", false, "User"); } else { try { ClientEvents.PushEvent(new string[] { TabID }, "ShowStatus", "Updating IP address for " + DomainName + " to " + CurrentIP + ".", false, "User"); Variables["Account"] = this.dynDnsAccount; Variables["Password"] = this.dynDnsPassword; Variables["IP"] = CurrentIP; Variables["Domain"] = DomainName; Result = UpdateIpScript.Evaluate(Variables); await RuntimeSettings.SetAsync("Last.IP." + DomainName, CurrentIP); } catch (Exception ex) { ClientEvents.PushEvent(new string[] { TabID }, "CertificateError", "Unable to register new dynamic IP Address: " + ex.Message, false, "User"); return(false); } } return(true); }