Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
NetworkModel.cs
1using EDaler;
7using NeuroFeatures;
8using System;
9using System.Collections.Generic;
10using System.Security.Cryptography;
11using System.Text;
12using System.Threading.Tasks;
13using System.Windows;
14using System.Windows.Input;
15using System.Xml;
16using Waher.Events;
26
28{
32 [Singleton]
34 {
35 private readonly PersistedProperty<string> savedAccounts;
36 private readonly PersistedProperty<string> selectedAccount;
37 private readonly PersistedProperty<string> xmppServer;
38 private readonly PersistedProperty<string> account;
39 private readonly PersistedProperty<string> password;
40 private readonly PersistedProperty<string> passwordMethod;
41 private readonly PersistedProperty<string> apiKey;
42 private readonly PersistedProperty<string> apiKeySecret;
43 private readonly PersistedProperty<string> legalComponentJid;
44 private readonly PersistedProperty<string> eDalerComponentJid;
45 private readonly PersistedProperty<string> neuroFeaturesComponentJid;
46 private readonly PersistedProperty<string> httpFileUploadComponentJid;
47 private readonly PersistedProperty<long> httpFileUploadMaxSize;
48 private readonly PersistedProperty<bool> createAccount;
49 private readonly PersistedProperty<bool> trustServerCertificate;
50 private readonly PersistedProperty<bool> allowInsecureAlgorithms;
51 private readonly PersistedProperty<bool> storePasswordInsteadOfDigest;
52 private readonly PersistedProperty<bool> connectOnStartup;
53 private readonly Property<string> password2;
54 private readonly Property<XmppState> state;
55 private readonly Property<bool> connected;
56
57 private readonly Command connect;
58 private readonly Command disconnect;
59 private readonly Command randomizePassword;
60 private readonly ParametrizedCommand copySnifferItem;
61 private readonly ParametrizedCommand removeSnifferItem;
62 private readonly Command clearSniffer;
63 private readonly Command saveCredentials;
64 private readonly Command deleteCredentials;
65 private readonly Command newAccount;
66
67 private XmppClient client;
68 private LegalModel legalModel;
69 private WalletModel walletModel;
70 private TokensModel tokensModel;
71
72 private bool loading = false;
73
74
75 public NetworkModel()
76 : base()
77 {
78 this.loading = true;
79 try
80 {
81 this.Add(this.savedAccounts = new PersistedProperty<string>("Accounts", nameof(this.SavedAccounts), true, string.Empty, this));
82 this.Add(this.selectedAccount = new PersistedProperty<string>("Accounts", nameof(this.SelectedAccount), true, string.Empty, this));
83 this.Add(this.xmppServer = new PersistedProperty<string>("XMPP", nameof(this.XmppServer), false, string.Empty, this));
84 this.Add(this.account = new PersistedProperty<string>("XMPP", nameof(this.Account), false, string.Empty, this));
85 this.Add(this.password = new PersistedProperty<string>("XMPP", nameof(this.Password), false, string.Empty, this));
86 this.Add(this.passwordMethod = new PersistedProperty<string>("XMPP", nameof(this.PasswordMethod), false, string.Empty, this));
87 this.Add(this.apiKey = new PersistedProperty<string>("XMPP", nameof(this.ApiKey), false, string.Empty, this));
88 this.Add(this.apiKeySecret = new PersistedProperty<string>("XMPP", nameof(this.ApiKeySecret), false, string.Empty, this));
89 this.Add(this.createAccount = new PersistedProperty<bool>("XMPP", nameof(this.CreateAccount), false, false, this));
90 this.Add(this.trustServerCertificate = new PersistedProperty<bool>("XMPP", nameof(this.TrustServerCertificate), false, false, this));
91 this.Add(this.allowInsecureAlgorithms = new PersistedProperty<bool>("XMPP", nameof(this.AllowInsecureAlgorithms), false, false, this));
92 this.Add(this.storePasswordInsteadOfDigest = new PersistedProperty<bool>("XMPP", nameof(this.StorePasswordInsteadOfDigest), false, false, this));
93 this.Add(this.connectOnStartup = new PersistedProperty<bool>("XMPP", nameof(this.ConnectOnStartup), false, false, this));
94
95 this.Add(this.legalComponentJid = new PersistedProperty<string>("XMPP", nameof(this.LegalComponentJid), true, string.Empty, this));
96 this.Add(this.eDalerComponentJid = new PersistedProperty<string>("XMPP", nameof(this.EDalerComponentJid), true, string.Empty, this));
97 this.Add(this.neuroFeaturesComponentJid = new PersistedProperty<string>("XMPP", nameof(this.NeuroFeaturesComponentJid), true, string.Empty, this));
98 this.Add(this.httpFileUploadComponentJid = new PersistedProperty<string>("XMPP", nameof(this.HttpFileUploadComponentJid), true, string.Empty, this));
99 this.Add(this.httpFileUploadMaxSize = new PersistedProperty<long>("XMPP", nameof(this.HttpFileUploadMaxSize), true, 0L, this));
100
101 this.password2 = new Property<string>(nameof(this.Password2), string.Empty, this);
102 this.state = new Property<XmppState>(nameof(this.State), XmppState.Offline, this);
103 this.connected = new Property<bool>(nameof(this.Connected), false, this);
104
105 this.connect = new Command(this.CanExecuteConnect, this.ExecuteConnect);
106 this.disconnect = new Command(this.CanExecuteDisconnect, this.ExecuteDisconnect);
107 this.randomizePassword = new Command(this.CanExecuteRandomizePassword, ExecuteRandomizePassword);
108 this.copySnifferItem = new ParametrizedCommand(this.CanExecuteCopy, this.ExecuteCopy);
109 this.removeSnifferItem = new ParametrizedCommand(this.CanExecuteRemove, this.ExecuteRemove);
110 this.clearSniffer = new Command(this.CanExecuteClearAll, this.ExecuteClearAll);
111 this.saveCredentials = new Command(this.CanExecuteSaveCredentials, this.ExecuteSaveCredentials);
112 this.deleteCredentials = new Command(this.CanExecuteDeleteCredentials, this.ExecuteDeleteCredentials);
113 this.newAccount = new Command(this.ExecuteNewAccount);
114 }
115 finally
116 {
117 this.loading = false;
118 }
119 }
120
124 public string[] SavedAccounts
125 {
126 get
127 {
128 string s = this.savedAccounts.Value;
129 if (string.IsNullOrEmpty(s))
130 return Array.Empty<string>();
131 else
132 return s.Split('|');
133 }
134
135 set
136 {
137 StringBuilder sb = new();
138 bool First = true;
139
140 foreach (string Item in value)
141 {
142 if (First)
143 First = false;
144 else
145 sb.Append('|');
146
147 sb.Append(Item);
148 }
149
150 this.savedAccounts.Value = sb.ToString();
151 }
152 }
153
157 public string SelectedAccount
158 {
159 get => this.selectedAccount.Value;
160 set
161 {
162 this.selectedAccount.Value = value;
163
164 this.deleteCredentials.RaiseCanExecuteChanged();
165
166 if (!this.loading && !string.IsNullOrEmpty(value))
167 Task.Run(() => MainWindow.UpdateGui(async () => await this.LoadCredentials(value)));
168 }
169 }
170
171 private async Task LoadCredentials(string Account)
172 {
173 int i = Account.IndexOf('@');
174 if (i < 0)
175 return;
176
177 string Prefix = "Credentials." + Account + ".";
178 bool Connect = this.Connected;
179
180 this.Account = Account[..i];
181 this.XmppServer = Account[(i + 1)..];
182 this.Password = await RuntimeSettings.GetAsync(Prefix + "Password", string.Empty);
183 this.PasswordMethod = await RuntimeSettings.GetAsync(Prefix + "PasswordMethod", string.Empty);
184 this.ApiKey = await RuntimeSettings.GetAsync(Prefix + "ApiKey", string.Empty);
185 this.ApiKeySecret = await RuntimeSettings.GetAsync(Prefix + "ApiKeySecret", string.Empty);
186 this.LegalComponentJid = await RuntimeSettings.GetAsync(Prefix + "LegalComponentJid", string.Empty);
187 this.EDalerComponentJid = await RuntimeSettings.GetAsync(Prefix + "EDalerComponentJid", string.Empty);
188 this.NeuroFeaturesComponentJid = await RuntimeSettings.GetAsync(Prefix + "NeuroFeaturesComponentJid", string.Empty);
189 this.HttpFileUploadComponentJid = await RuntimeSettings.GetAsync(Prefix + "HttpFileUploadComponentJid", string.Empty);
190 this.HttpFileUploadMaxSize = await RuntimeSettings.GetAsync(Prefix + "HttpFileUploadMaxSize", 0L);
191 this.TrustServerCertificate = await RuntimeSettings.GetAsync(Prefix + "TrustServerCertificate", false);
192 this.AllowInsecureAlgorithms = await RuntimeSettings.GetAsync(Prefix + "AllowInsecureAlgorithms", false);
193 this.StorePasswordInsteadOfDigest = await RuntimeSettings.GetAsync(Prefix + "StorePasswordInsteadOfDigest", false);
194 this.ConnectOnStartup = await RuntimeSettings.GetAsync(Prefix + "ConnectOnStartup", false);
195 this.CreateAccount = false;
196 this.Password2 = string.Empty;
197
198 await this.ExecuteDisconnect();
199 await this.ExecuteClearAll();
200
201 if (Connect)
202 await this.ExecuteConnect();
203 }
204
208 public string XmppServer
209 {
210 get => this.xmppServer.Value;
211 set => this.xmppServer.Value = value;
212 }
213
217 public string Account
218 {
219 get => this.account.Value;
220 set => this.account.Value = value;
221 }
222
226 public string Password
227 {
228 get => this.password.Value;
229 set
230 {
231 if (this.password.Value != value)
232 {
233 this.password.Value = value;
234 this.PasswordMethod = string.Empty;
235 }
236 }
237 }
238
242 public string PasswordMethod
243 {
244 get => this.passwordMethod.Value;
245 set => this.passwordMethod.Value = value;
246 }
247
251 public string ApiKey
252 {
253 get => this.apiKey.Value;
254 set => this.apiKey.Value = value;
255 }
256
260 public string ApiKeySecret
261 {
262 get => this.apiKeySecret.Value;
263 set => this.apiKeySecret.Value = value;
264 }
265
269 public bool CreateAccount
270 {
271 get => this.createAccount.Value;
272 set
273 {
274 this.createAccount.Value = value;
275 this.connect.RaiseCanExecuteChanged();
276 this.randomizePassword.RaiseCanExecuteChanged();
277 }
278 }
279
284 {
285 get => this.trustServerCertificate.Value;
286 set => this.trustServerCertificate.Value = value;
287 }
288
293 {
294 get => this.allowInsecureAlgorithms.Value;
295 set => this.allowInsecureAlgorithms.Value = value;
296 }
297
302 {
303 get => this.storePasswordInsteadOfDigest.Value;
304 set => this.storePasswordInsteadOfDigest.Value = value;
305 }
306
311 {
312 get => this.connectOnStartup.Value;
313 set => this.connectOnStartup.Value = value;
314 }
315
319 public string LegalComponentJid
320 {
321 get => this.legalComponentJid.Value;
322 set => this.legalComponentJid.Value = value;
323 }
324
328 public string EDalerComponentJid
329 {
330 get => this.eDalerComponentJid.Value;
331 set => this.eDalerComponentJid.Value = value;
332 }
333
338 {
339 get => this.neuroFeaturesComponentJid.Value;
340 set => this.neuroFeaturesComponentJid.Value = value;
341 }
342
347 {
348 get => this.httpFileUploadComponentJid.Value;
349 set => this.httpFileUploadComponentJid.Value = value;
350 }
351
356 {
357 get => this.httpFileUploadMaxSize.Value;
358 set => this.httpFileUploadMaxSize.Value = value;
359 }
360
364 public ICommand Connect => this.connect;
365
369 public ICommand Disconnect => this.disconnect;
370
374 public ICommand RandomizePassword => this.randomizePassword;
375
379 public string Password2
380 {
381 get => this.password2.Value;
382 set
383 {
384 this.password2.Value = value;
385 this.connect.RaiseCanExecuteChanged();
386 }
387 }
388
393 {
394 get => this.state.Value;
395 set
396 {
397 this.state.Value = value;
398 this.connect.RaiseCanExecuteChanged();
399 this.disconnect.RaiseCanExecuteChanged();
400 }
401 }
402
406 public bool Connected
407 {
408 get => this.connected.Value;
409 set
410 {
411 this.connected.Value = value;
412 this.connect.RaiseCanExecuteChanged();
413 this.disconnect.RaiseCanExecuteChanged();
414 this.randomizePassword.RaiseCanExecuteChanged();
415 this.saveCredentials.RaiseCanExecuteChanged();
416 }
417 }
418
422 public LegalModel Legal => this.legalModel;
423
427 public WalletModel Wallet => this.walletModel;
428
432 public TokensModel Tokens => this.tokensModel;
433
437 public override async Task Start()
438 {
440 {
441 MainWindow.currentInstance.NetworkTab.DataContext = this;
442 MainWindow.currentInstance.XmppState.DataContext = this;
443
444 MainWindow.currentInstance.NetworkTab.XmppPassword.Password = this.Password;
445 MainWindow.currentInstance.NetworkTab.ApiKeySecret.Password = this.ApiKeySecret;
446
447 MainWindow.currentInstance.NetworkTab.XmppPassword.PasswordChanged += this.PasswordChanged;
448 MainWindow.currentInstance.NetworkTab.XmppPassword2.PasswordChanged += this.Password2Changed;
449 MainWindow.currentInstance.NetworkTab.ApiKeySecret.PasswordChanged += this.ApiKeySecretChanged;
450
451 return Task.CompletedTask;
452 });
453
454 if (this.ConnectOnStartup)
455 await this.ExecuteConnect();
456
457 await base.Start();
458 }
459
463 public override async Task Stop()
464 {
465 MainWindow.currentInstance.NetworkTab.XmppPassword.PasswordChanged -= this.PasswordChanged;
466 MainWindow.currentInstance.NetworkTab.XmppPassword2.PasswordChanged -= this.Password2Changed;
467 MainWindow.currentInstance.NetworkTab.ApiKeySecret.PasswordChanged -= this.ApiKeySecretChanged;
468
469 if (this.legalModel is not null)
470 {
471 await this.legalModel.Stop();
472 this.legalModel.Dispose();
473 this.legalModel = null;
474 }
475
476 if (this.walletModel is not null)
477 {
478 await this.walletModel.Stop();
479 this.walletModel.Dispose();
480 this.walletModel = null;
481 }
482
483 if (this.client is not null)
484 {
485 await this.client.DisposeAsync();
486 this.client = null;
487 }
488
489 await base.Stop();
490 }
491
492 private void PasswordChanged(object sender, RoutedEventArgs e)
493 {
494 this.Password = MainWindow.currentInstance.NetworkTab.XmppPassword.Password;
495 }
496
497 private void Password2Changed(object sender, RoutedEventArgs e)
498 {
499 this.Password2 = MainWindow.currentInstance.NetworkTab.XmppPassword.Password;
500 }
501
502 private void ApiKeySecretChanged(object sender, RoutedEventArgs e)
503 {
504 this.ApiKeySecret = MainWindow.currentInstance.NetworkTab.ApiKeySecret.Password;
505 }
506
507 private bool CanExecuteRandomizePassword()
508 {
509 return this.client is null && this.CreateAccount;
510 }
511
512 public static Task ExecuteRandomizePassword()
513 {
514 using RandomNumberGenerator Rnd = RandomNumberGenerator.Create();
515 byte[] Bin = new byte[28];
516 Rnd.GetBytes(Bin);
517 string Password = Convert.ToBase64String(Bin);
518
520 {
521 MainWindow.currentInstance.NetworkTab.XmppPassword.Password = Password;
522 MainWindow.currentInstance.NetworkTab.XmppPassword2.Password = Password;
523
524 return Task.CompletedTask;
525 });
526
527 return Task.CompletedTask;
528 }
529
530 private bool CanExecuteConnect()
531 {
532 return this.client is null && (!this.CreateAccount || this.Password == this.Password2);
533 }
534
538 public async Task ExecuteConnect()
539 {
540 try
541 {
542 string Host;
543 int Port;
544
546
547 try
548 {
549 SRV Record = await DnsResolver.LookupServiceEndpoint(this.XmppServer, "xmpp-client", "tcp");
550
551 Host = Record.TargetHost;
552 Port = Record.Port;
553 }
554 catch (Exception ex)
555 {
556 Log.Exception(ex);
557
558 Host = this.XmppServer;
559 Port = 5222; // Default XMPP Client-to-Server port.
560 }
561
562 if (this.legalModel is not null)
563 {
564 await this.legalModel.Stop();
565 this.legalModel.Dispose();
566 this.legalModel = null;
567 }
568
569 if (this.walletModel is not null)
570 {
571 await this.walletModel.Stop();
572 this.walletModel.Dispose();
573 this.walletModel = null;
574 }
575
576 ListViewSniffer Sniffer = new(MainWindow.currentInstance.NetworkTab.SnifferListView, 1000);
577 Sniffer.SelectionChanged += this.Sniffer_SelectionChanged;
578
579 if (string.IsNullOrEmpty(this.PasswordMethod))
580 this.client = new XmppClient(Host, Port, this.Account, this.Password, "en", typeof(MainWindow).Assembly, Sniffer);
581 else
582 this.client = new XmppClient(Host, Port, this.Account, this.Password, this.PasswordMethod, "en", typeof(MainWindow).Assembly, Sniffer);
583
584 if (this.CreateAccount)
585 this.client.AllowRegistration(this.ApiKey, this.ApiKeySecret);
586
587 this.client.TrustServer = this.TrustServerCertificate;
588 this.client.AllowEncryption = true;
589
590 if (!this.AllowInsecureAlgorithms)
591 {
592 this.client.AllowCramMD5 = false;
593 this.client.AllowDigestMD5 = false;
594 this.client.AllowPlain = false;
595 this.client.AllowScramSHA1 = false;
596 }
597
598 this.client.OnStateChanged += this.Client_OnStateChanged;
599 this.client.OnConnectionError += this.Client_OnConnectionError;
600 this.client.OnChatMessage += this.Client_OnChatMessage;
601
602 await this.client.Connect(this.XmppServer);
603 }
604 catch (Exception ex)
605 {
607 MainWindow.ErrorBox("Unable to connect to the XMPP network. Error reported: " + ex.Message);
608 }
609 }
610
611 private Task Client_OnChatMessage(object Sender, MessageEventArgs e)
612 {
613 MainWindow.MessageBox(e.Body, "Message from " + e.From, MessageBoxButton.OK, MessageBoxImage.Information);
614 return Task.CompletedTask;
615 }
616
617 private async Task Client_OnConnectionError(object Sender, Exception Exception)
618 {
619 if (this.CreateAccount || !this.ConnectOnStartup)
620 {
621 if (this.client is not null)
622 {
623 await this.client.DisposeAsync();
624 this.client = null;
625 }
626 }
627
628 this.connect.RaiseCanExecuteChanged();
629
630 MainWindow.ErrorBox(Exception.Message);
631 }
632
633 private async Task Client_OnStateChanged(object Sender, XmppState NewState)
634 {
635 try
636 {
637 this.State = NewState;
638
639 switch (NewState)
640 {
641 case XmppState.Connected:
642 this.Connected = true;
643
645 this.client.OnConnectionError -= this.Client_OnConnectionError;
646
647 this.ConnectOnStartup = true;
648 this.CreateAccount = false;
649 this.ApiKey = string.Empty;
650 this.ApiKeySecret = string.Empty;
651
652 if (string.IsNullOrEmpty(this.PasswordMethod) && !this.StorePasswordInsteadOfDigest)
653 {
654 this.Password = this.client.PasswordHash;
655 this.PasswordMethod = this.client.PasswordHashMethod;
656 }
657
658 await this.Save();
659
660 if (this.legalModel is null || this.legalModel.Contracts.ComponentAddress != this.LegalComponentJid ||
661 this.walletModel is null || this.walletModel.EDaler.ComponentAddress != this.EDalerComponentJid ||
662 this.tokensModel is null || this.tokensModel.NeuroFeaturesClient.ComponentAddress != this.NeuroFeaturesComponentJid ||
663 this.legalModel.FileUpload.FileUploadJid != this.HttpFileUploadComponentJid)
664 {
665 if (string.IsNullOrEmpty(this.LegalComponentJid) ||
666 string.IsNullOrEmpty(this.EDalerComponentJid) ||
667 string.IsNullOrEmpty(this.NeuroFeaturesComponentJid) ||
668 string.IsNullOrEmpty(this.HttpFileUploadComponentJid))
669 {
670 ServiceItemsDiscoveryEventArgs e = await this.client.ServiceItemsDiscoveryAsync(string.Empty);
671 if (e.Ok)
672 {
673 foreach (Item Component in e.Items)
674 {
675 ServiceDiscoveryEventArgs e2 = await this.client.ServiceDiscoveryAsync(Component.JID);
676
679 {
680 this.LegalComponentJid = Component.JID;
681 }
682
684 this.EDalerComponentJid = Component.JID;
685
687 this.NeuroFeaturesComponentJid = Component.JID;
688
690 {
691 this.HttpFileUploadComponentJid = Component.JID;
692 this.HttpFileUploadMaxSize = HttpFileUploadClient.FindMaxFileSize(this.client, e2) ?? 0;
693 }
694 }
695 }
696 }
697
698 if (!string.IsNullOrEmpty(this.LegalComponentJid))
699 {
700 if (this.legalModel is null || this.legalModel.Contracts.ComponentAddress != this.LegalComponentJid)
701 {
702 this.legalModel?.Dispose();
703 this.legalModel = null;
704
705 this.legalModel = new LegalModel(this.client, this.LegalComponentJid, this.HttpFileUploadComponentJid,
706 this.HttpFileUploadMaxSize <= 0 ? null : this.HttpFileUploadMaxSize);
707
708 await this.legalModel.Load();
709 await this.legalModel.Start();
710 }
711
712 if (!string.IsNullOrEmpty(this.EDalerComponentJid) &&
713 (this.walletModel is null || this.walletModel.EDaler.ComponentAddress != this.EDalerComponentJid))
714 {
715 this.walletModel?.Dispose();
716 this.walletModel = null;
717
718 this.walletModel = new WalletModel(this.client, this.legalModel.Contracts, this.EDalerComponentJid, this);
719 await this.walletModel.Load();
720 await this.walletModel.Start();
721 }
722
723 if (!string.IsNullOrEmpty(this.NeuroFeaturesComponentJid) &&
724 (this.tokensModel is null || this.tokensModel.NeuroFeaturesClient.ComponentAddress != this.NeuroFeaturesComponentJid))
725 {
726 this.tokensModel?.Dispose();
727 this.tokensModel = null;
728
729 this.tokensModel = new TokensModel(this.client, this.legalModel.Contracts, this.NeuroFeaturesComponentJid);
730 await this.tokensModel.Load();
731 await this.tokensModel.Start();
732 }
733 }
734 }
735 break;
736
737 case XmppState.Error:
738 case XmppState.Offline:
739 this.Connected = false;
740 break;
741 }
742
743 EventHandlerAsync<XmppState> h = this.OnStateChanged;
744 if (h is not null)
745 await h(this, NewState);
746 }
747 catch (Exception ex)
748 {
749 Log.Exception(ex);
750 }
751 }
752
756 public event EventHandlerAsync<XmppState> OnStateChanged;
757
758 private bool CanExecuteDisconnect()
759 {
760 return this.client is not null;
761 }
762
766 public async Task ExecuteDisconnect()
767 {
768 this.LegalComponentJid = string.Empty;
769 this.EDalerComponentJid = string.Empty;
770 this.NeuroFeaturesComponentJid = string.Empty;
771
772 this.legalModel?.Dispose();
773 this.legalModel = null;
774
775 if (this.client is not null)
776 {
777 await this.client.DisposeAsync();
778 this.client = null;
779 }
780
781 this.State = XmppState.Offline;
782 this.Connected = false;
783 this.ConnectOnStartup = false;
784 }
785
789 public ICommand CopySnifferItem => this.copySnifferItem;
790
791 private bool CanExecuteCopy(object Item) => SelectedItem(Item) is SniffItem SniffItem && SniffItem.IsSelected;
792
793 private static object SelectedItem(object Item)
794 {
795 return Item ?? MainWindow.currentInstance.NetworkTab.SnifferListView.SelectedItem;
796 }
797
798 private void ExecuteCopy(object Item)
799 {
800 if (SelectedItem(Item) is SniffItem SniffItem)
801 {
802 StringBuilder Output = new();
803
804 Output.Append("Date:\t");
805 Output.AppendLine(SniffItem.Timestamp.Date.ToShortDateString());
806
807 Output.Append("Time:\t");
808 Output.AppendLine(SniffItem.Timestamp.ToLongTimeString());
809
810 Output.Append("Type:\t");
811 Output.AppendLine(SniffItem.Type.ToString());
812
813 Output.AppendLine();
814
815 try
816 {
817 (string PrettyXml, XmlElement _) = SniffItem.Message.ToPrettyXml();
818 Output.AppendLine(PrettyXml);
819 }
820 catch (Exception)
821 {
822 Output.AppendLine(SniffItem.Message);
823 }
824
825 Clipboard.SetText(Output.ToString());
826 }
827 }
828
832 public ICommand RemoveSnifferItem => this.removeSnifferItem;
833
834 private bool CanExecuteRemove(object Item) => SelectedItem(Item) is SniffItem SniffItem && SniffItem.IsSelected;
835
836 private void ExecuteRemove(object Item)
837 {
838 if (SelectedItem(Item) is SniffItem SniffItem)
839 MainWindow.currentInstance.NetworkTab.SnifferListView.Items.Remove(SniffItem);
840 }
841
842 private void Sniffer_SelectionChanged(object sender, EventArgs e)
843 {
844 this.copySnifferItem?.RaiseCanExecuteChanged();
845 this.removeSnifferItem?.RaiseCanExecuteChanged();
846 }
847
851 public ICommand ClearSniffer => this.clearSniffer;
852
853 private bool CanExecuteClearAll() => true;
854
855 private Task ExecuteClearAll()
856 {
857 MainWindow.currentInstance.NetworkTab.SnifferListView.Items.Clear();
858 return Task.CompletedTask;
859 }
860
864 public ICommand SaveCredentials => this.saveCredentials;
865
866 private bool CanExecuteSaveCredentials() => this.Connected;
867
868 private async Task ExecuteSaveCredentials()
869 {
870 SortedDictionary<string, bool> Sorted = new();
871
872 foreach (string Account in this.SavedAccounts)
873 Sorted[Account] = true;
874
875 string Jid = this.Account + "@" + this.XmppServer;
876 Sorted[Jid] = true;
877
878 string Prefix = "Credentials." + Jid + ".";
879
880 await RuntimeSettings.SetAsync(Prefix + "Password", this.Password);
881 await RuntimeSettings.SetAsync(Prefix + "PasswordMethod", this.PasswordMethod);
882 await RuntimeSettings.SetAsync(Prefix + "ApiKey", this.ApiKey);
883 await RuntimeSettings.SetAsync(Prefix + "ApiKeySecret", this.ApiKeySecret);
884 await RuntimeSettings.SetAsync(Prefix + "LegalComponentJid", this.LegalComponentJid);
885 await RuntimeSettings.SetAsync(Prefix + "EDalerComponentJid", this.EDalerComponentJid);
886 await RuntimeSettings.SetAsync(Prefix + "NeuroFeaturesComponentJid", this.NeuroFeaturesComponentJid);
887 await RuntimeSettings.SetAsync(Prefix + "HttpFileUploadComponentJid", this.HttpFileUploadComponentJid);
888 await RuntimeSettings.SetAsync(Prefix + "HttpFileUploadMaxSize", this.HttpFileUploadMaxSize);
889 await RuntimeSettings.SetAsync(Prefix + "TrustServerCertificate", this.TrustServerCertificate);
890 await RuntimeSettings.SetAsync(Prefix + "AllowInsecureAlgorithms", this.AllowInsecureAlgorithms);
891 await RuntimeSettings.SetAsync(Prefix + "StorePasswordInsteadOfDigest", this.StorePasswordInsteadOfDigest);
892 await RuntimeSettings.SetAsync(Prefix + "ConnectOnStartup", this.ConnectOnStartup);
893
894 string[] Accounts = new string[Sorted.Count];
895 Sorted.Keys.CopyTo(Accounts, 0);
896
897 this.loading = true;
898 try
899 {
900 this.SavedAccounts = Accounts;
901 this.SelectedAccount = Jid;
902 }
903 finally
904 {
905 this.loading = false;
906 }
907
908 await MainWindow.MessageBox("Credentials saved.", "Information", MessageBoxButton.OK, MessageBoxImage.Information);
909 }
910
914 public ICommand NewAccount => this.newAccount;
915
916 private async Task ExecuteNewAccount()
917 {
918 await this.ExecuteDisconnect();
919
920 this.SelectedAccount = string.Empty;
921 this.XmppServer = string.Empty;
922 this.Account = string.Empty;
923 this.Password = string.Empty;
924 this.PasswordMethod = string.Empty;
925 this.ApiKey = string.Empty;
926 this.ApiKeySecret = string.Empty;
927 this.LegalComponentJid = string.Empty;
928 this.EDalerComponentJid = string.Empty;
929 this.NeuroFeaturesComponentJid = string.Empty;
930 this.EDalerComponentJid = string.Empty;
931 this.TrustServerCertificate = false;
932 this.AllowInsecureAlgorithms = false;
933 this.StorePasswordInsteadOfDigest = false;
934 this.ConnectOnStartup = false;
935 this.CreateAccount = false;
936 this.Password2 = string.Empty;
937
938 await this.ExecuteClearAll();
939 }
940
944 public ICommand DeleteCredentials => this.deleteCredentials;
945
946 private bool CanExecuteDeleteCredentials() => !string.IsNullOrEmpty(this.SelectedAccount);
947
948 private async Task ExecuteDeleteCredentials()
949 {
950 SortedDictionary<string, bool> Sorted = new();
951
952 foreach (string Account in this.SavedAccounts)
953 {
954 if (Account != this.SelectedAccount)
955 Sorted[Account] = true;
956 }
957
958 string Jid = this.Account + "@" + this.XmppServer;
959 string Prefix = "Credentials." + Jid + ".";
960
961 await RuntimeSettings.DeleteAsync(Prefix + "Password");
962 await RuntimeSettings.DeleteAsync(Prefix + "PasswordMethod");
963 await RuntimeSettings.DeleteAsync(Prefix + "ApiKey");
964 await RuntimeSettings.DeleteAsync(Prefix + "ApiKeySecret");
965 await RuntimeSettings.DeleteAsync(Prefix + "LegalComponentJid");
966 await RuntimeSettings.DeleteAsync(Prefix + "EDalerComponentJid");
967 await RuntimeSettings.DeleteAsync(Prefix + "NeuroFeaturesComponentJid");
968 await RuntimeSettings.DeleteAsync(Prefix + "EDalerComponentJid");
969 await RuntimeSettings.DeleteAsync(Prefix + "TrustServerCertificate");
970 await RuntimeSettings.DeleteAsync(Prefix + "AllowInsecureAlgorithms");
971 await RuntimeSettings.DeleteAsync(Prefix + "StorePasswordInsteadOfDigest");
972 await RuntimeSettings.DeleteAsync(Prefix + "ConnectOnStartup");
973
974 string[] Accounts = new string[Sorted.Count];
975 Sorted.Keys.CopyTo(Accounts, 0);
976
977 this.loading = true;
978 try
979 {
980 this.SelectedAccount = string.Empty;
981 this.SavedAccounts = Accounts;
982 }
983 finally
984 {
985 this.loading = false;
986 }
987
988 await MainWindow.MessageBox("Credentials deleted.", "Information", MessageBoxButton.OK, MessageBoxImage.Information);
989 }
990
991 }
992}
eDaler XMPP client.
Definition: EDalerClient.cs:24
const string NamespaceEDaler
Namespace of eDaler component.
Definition: EDalerClient.cs:28
string ComponentAddress
Address of eDaler component
Definition: EDalerClient.cs:89
const string NamespaceNeuroFeatures
Namespace for Neuro-Features.
string ComponentAddress
Address of eDaler component
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
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.
Definition: Log.cs:1647
DNS resolver, as defined in:
Definition: DnsResolver.cs:32
static Task< SRV > LookupServiceEndpoint(string DomainName, string ServiceName, string Protocol)
Looks up a service endpoint for a domain. If multiple are available, an appropriate one is selected a...
Definition: DnsResolver.cs:825
Adds support for legal identities, smart contracts and signatures to an XMPP client.
static readonly string[] NamespacesSmartContracts
Namespaces supported for smart contracts.
static readonly string[] NamespacesLegalIdentities
Namespaces supported for legal identities.
bool Ok
If the response is an OK result response (true), or an error response (false).
Event arguments for message events.
string From
From where the message was received.
Class managing HTTP File uploads, as defined in XEP-0363.
static ? long FindMaxFileSize(XmppClient Client, ServiceDiscoveryEventArgs e)
Finds the maximum file size supported by the file upload service.
Contains information about an item of an entity.
Definition: Item.cs:11
bool HasFeature(string Feature)
Checks if the remote entity supports a specific feature.
bool HasAnyFeature(params string[] Features)
Checks if the remote entity supports any of a set of features.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:59
Task< ServiceItemsDiscoveryEventArgs > ServiceItemsDiscoveryAsync(string To)
Performs an asynchronous service items discovery request
Definition: XmppClient.cs:6241
async Task DisposeAsync()
Closes the connection and disposes of all resources.
Definition: XmppClient.cs:1164
Task< ServiceDiscoveryEventArgs > ServiceDiscoveryAsync(string To)
Performs an asynchronous service discovery request
Definition: XmppClient.cs:6003
string PasswordHashMethod
Password hash method.
Definition: XmppClient.cs:3445
string PasswordHash
Hash value of password. Depends on method used to authenticate user.
Definition: XmppClient.cs:3436
Task Connect()
Connects the client.
Definition: XmppClient.cs:641
void AllowRegistration()
If registration of a new account is allowed. Requires a password. Having a password hash is not suffi...
Definition: XmppClient.cs:3533
Static class managing persistent settings.
static async Task< string > GetAsync(string Key, string DefaultValue)
Gets a string-valued setting.
static async Task< bool > DeleteAsync(string Key)
Deletes a runtime setting
static async Task< bool > SetAsync(string Key, string Value)
Sets a string-valued setting.
XmppState
State of XMPP connection.
Definition: XmppState.cs:7