9using System.Collections.Generic;
10using System.Security.Cryptography;
12using System.Threading.Tasks;
14using System.Windows.Input;
57 private readonly
Command connect;
58 private readonly
Command disconnect;
59 private readonly
Command randomizePassword;
62 private readonly
Command clearSniffer;
63 private readonly
Command saveCredentials;
64 private readonly
Command deleteCredentials;
65 private readonly
Command newAccount;
72 private bool loading =
false;
107 this.randomizePassword =
new Command(this.CanExecuteRandomizePassword, ExecuteRandomizePassword);
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);
117 this.loading =
false;
128 string s = this.savedAccounts.Value;
129 if (
string.IsNullOrEmpty(s))
130 return Array.Empty<
string>();
137 StringBuilder sb =
new();
140 foreach (
string Item in value)
150 this.savedAccounts.Value = sb.ToString();
159 get => this.selectedAccount.Value;
162 this.selectedAccount.Value = value;
164 this.deleteCredentials.RaiseCanExecuteChanged();
166 if (!this.loading && !
string.IsNullOrEmpty(value))
171 private async Task LoadCredentials(
string Account)
177 string Prefix =
"Credentials." +
Account +
".";
181 this.XmppServer =
Account[(i + 1)..];
188 this.NeuroFeaturesComponentJid = await
RuntimeSettings.
GetAsync(Prefix +
"NeuroFeaturesComponentJid",
string.Empty);
189 this.HttpFileUploadComponentJid = await
RuntimeSettings.
GetAsync(Prefix +
"HttpFileUploadComponentJid",
string.Empty);
193 this.StorePasswordInsteadOfDigest = await
RuntimeSettings.
GetAsync(Prefix +
"StorePasswordInsteadOfDigest",
false);
195 this.CreateAccount =
false;
196 this.Password2 =
string.Empty;
199 await this.ExecuteClearAll();
210 get => this.xmppServer.Value;
211 set => this.xmppServer.Value = value;
219 get => this.account.Value;
220 set => this.account.Value = value;
228 get => this.password.Value;
231 if (this.password.Value != value)
233 this.password.Value = value;
234 this.PasswordMethod =
string.Empty;
244 get => this.passwordMethod.Value;
245 set => this.passwordMethod.Value = value;
253 get => this.apiKey.Value;
254 set => this.apiKey.Value = value;
262 get => this.apiKeySecret.Value;
263 set => this.apiKeySecret.Value = value;
271 get => this.createAccount.Value;
274 this.createAccount.Value = value;
275 this.connect.RaiseCanExecuteChanged();
276 this.randomizePassword.RaiseCanExecuteChanged();
285 get => this.trustServerCertificate.Value;
286 set => this.trustServerCertificate.Value = value;
294 get => this.allowInsecureAlgorithms.Value;
295 set => this.allowInsecureAlgorithms.Value = value;
303 get => this.storePasswordInsteadOfDigest.Value;
304 set => this.storePasswordInsteadOfDigest.Value = value;
312 get => this.connectOnStartup.Value;
313 set => this.connectOnStartup.Value = value;
321 get => this.legalComponentJid.Value;
322 set => this.legalComponentJid.Value = value;
330 get => this.eDalerComponentJid.Value;
331 set => this.eDalerComponentJid.Value = value;
339 get => this.neuroFeaturesComponentJid.Value;
340 set => this.neuroFeaturesComponentJid.Value = value;
348 get => this.httpFileUploadComponentJid.Value;
349 set => this.httpFileUploadComponentJid.Value = value;
357 get => this.httpFileUploadMaxSize.Value;
358 set => this.httpFileUploadMaxSize.Value = value;
381 get => this.password2.Value;
384 this.password2.Value = value;
385 this.connect.RaiseCanExecuteChanged();
394 get => this.state.Value;
397 this.state.Value = value;
398 this.connect.RaiseCanExecuteChanged();
399 this.disconnect.RaiseCanExecuteChanged();
408 get => this.connected.Value;
411 this.connected.Value = value;
412 this.connect.RaiseCanExecuteChanged();
413 this.disconnect.RaiseCanExecuteChanged();
414 this.randomizePassword.RaiseCanExecuteChanged();
415 this.saveCredentials.RaiseCanExecuteChanged();
441 MainWindow.currentInstance.NetworkTab.DataContext =
this;
442 MainWindow.currentInstance.XmppState.DataContext =
this;
444 MainWindow.currentInstance.NetworkTab.XmppPassword.Password = this.
Password;
445 MainWindow.currentInstance.NetworkTab.ApiKeySecret.Password = this.
ApiKeySecret;
447 MainWindow.currentInstance.NetworkTab.XmppPassword.PasswordChanged += this.PasswordChanged;
448 MainWindow.currentInstance.NetworkTab.XmppPassword2.PasswordChanged += this.Password2Changed;
449 MainWindow.currentInstance.NetworkTab.ApiKeySecret.PasswordChanged += this.ApiKeySecretChanged;
451 return Task.CompletedTask;
463 public override async Task
Stop()
465 MainWindow.currentInstance.NetworkTab.XmppPassword.PasswordChanged -= this.PasswordChanged;
466 MainWindow.currentInstance.NetworkTab.XmppPassword2.PasswordChanged -= this.Password2Changed;
467 MainWindow.currentInstance.NetworkTab.ApiKeySecret.PasswordChanged -= this.ApiKeySecretChanged;
469 if (this.legalModel is not
null)
471 await this.legalModel.
Stop();
473 this.legalModel =
null;
476 if (this.walletModel is not
null)
478 await this.walletModel.
Stop();
480 this.walletModel =
null;
483 if (this.client is not
null)
492 private void PasswordChanged(
object sender, RoutedEventArgs e)
494 this.Password =
MainWindow.currentInstance.NetworkTab.XmppPassword.Password;
497 private void Password2Changed(
object sender, RoutedEventArgs e)
499 this.Password2 =
MainWindow.currentInstance.NetworkTab.XmppPassword.Password;
502 private void ApiKeySecretChanged(
object sender, RoutedEventArgs e)
504 this.ApiKeySecret =
MainWindow.currentInstance.NetworkTab.ApiKeySecret.Password;
507 private bool CanExecuteRandomizePassword()
512 public static Task ExecuteRandomizePassword()
514 using RandomNumberGenerator Rnd = RandomNumberGenerator.Create();
515 byte[] Bin =
new byte[28];
517 string Password = Convert.ToBase64String(Bin);
521 MainWindow.currentInstance.NetworkTab.XmppPassword.Password =
Password;
522 MainWindow.currentInstance.NetworkTab.XmppPassword2.Password =
Password;
524 return Task.CompletedTask;
527 return Task.CompletedTask;
530 private bool CanExecuteConnect()
532 return this.client is
null && (!this.CreateAccount || this.Password == this.
Password2);
562 if (this.legalModel is not
null)
564 await this.legalModel.
Stop();
566 this.legalModel =
null;
569 if (this.walletModel is not
null)
571 await this.walletModel.
Stop();
573 this.walletModel =
null;
577 Sniffer.SelectionChanged += this.Sniffer_SelectionChanged;
580 this.client =
new XmppClient(Host, Port, this.Account, this.Password,
"en", typeof(
MainWindow).Assembly, Sniffer);
588 this.client.AllowEncryption =
true;
592 this.client.AllowCramMD5 =
false;
593 this.client.AllowDigestMD5 =
false;
594 this.client.AllowPlain =
false;
595 this.client.AllowScramSHA1 =
false;
598 this.client.OnStateChanged += this.Client_OnStateChanged;
599 this.client.OnConnectionError += this.Client_OnConnectionError;
600 this.client.OnChatMessage += this.Client_OnChatMessage;
607 MainWindow.
ErrorBox(
"Unable to connect to the XMPP network. Error reported: " + ex.Message);
614 return Task.CompletedTask;
617 private async Task Client_OnConnectionError(
object Sender, Exception Exception)
621 if (this.client is not
null)
628 this.connect.RaiseCanExecuteChanged();
633 private async Task Client_OnStateChanged(
object Sender,
XmppState NewState)
637 this.State = NewState;
642 this.Connected =
true;
645 this.client.OnConnectionError -= this.Client_OnConnectionError;
647 this.ConnectOnStartup =
true;
648 this.CreateAccount =
false;
649 this.ApiKey =
string.Empty;
650 this.ApiKeySecret =
string.Empty;
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)
680 this.LegalComponentJid = Component.
JID;
684 this.EDalerComponentJid = Component.
JID;
687 this.NeuroFeaturesComponentJid = Component.
JID;
691 this.HttpFileUploadComponentJid = Component.
JID;
703 this.legalModel =
null;
708 await this.legalModel.
Load();
709 await this.legalModel.
Start();
716 this.walletModel =
null;
718 this.walletModel =
new WalletModel(this.client, this.legalModel.
Contracts,
this.EDalerComponentJid,
this);
719 await this.walletModel.
Load();
720 await this.walletModel.
Start();
727 this.tokensModel =
null;
729 this.tokensModel =
new TokensModel(this.client, this.legalModel.
Contracts,
this.NeuroFeaturesComponentJid);
730 await this.tokensModel.
Load();
731 await this.tokensModel.
Start();
739 this.Connected =
false;
745 await h(
this, NewState);
758 private bool CanExecuteDisconnect()
760 return this.client is not
null;
768 this.LegalComponentJid =
string.Empty;
769 this.EDalerComponentJid =
string.Empty;
770 this.NeuroFeaturesComponentJid =
string.Empty;
773 this.legalModel =
null;
775 if (this.client is not
null)
782 this.Connected =
false;
783 this.ConnectOnStartup =
false;
793 private static object SelectedItem(
object Item)
795 return Item ??
MainWindow.currentInstance.NetworkTab.SnifferListView.SelectedItem;
798 private void ExecuteCopy(
object Item)
802 StringBuilder Output =
new();
804 Output.Append(
"Date:\t");
807 Output.Append(
"Time:\t");
810 Output.Append(
"Type:\t");
818 Output.AppendLine(PrettyXml);
825 Clipboard.SetText(Output.ToString());
836 private void ExecuteRemove(
object Item)
842 private void Sniffer_SelectionChanged(
object sender, EventArgs e)
844 this.copySnifferItem?.RaiseCanExecuteChanged();
845 this.removeSnifferItem?.RaiseCanExecuteChanged();
853 private bool CanExecuteClearAll() =>
true;
855 private Task ExecuteClearAll()
857 MainWindow.currentInstance.NetworkTab.SnifferListView.Items.Clear();
858 return Task.CompletedTask;
866 private bool CanExecuteSaveCredentials() => this.
Connected;
868 private async Task ExecuteSaveCredentials()
870 SortedDictionary<string, bool> Sorted =
new();
875 string Jid = this.Account +
"@" + this.
XmppServer;
878 string Prefix =
"Credentials." + Jid +
".";
894 string[] Accounts =
new string[Sorted.Count];
895 Sorted.Keys.CopyTo(Accounts, 0);
900 this.SavedAccounts = Accounts;
901 this.SelectedAccount = Jid;
905 this.loading =
false;
908 await
MainWindow.
MessageBox(
"Credentials saved.",
"Information", MessageBoxButton.OK, MessageBoxImage.Information);
916 private async Task ExecuteNewAccount()
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;
938 await this.ExecuteClearAll();
946 private bool CanExecuteDeleteCredentials() => !
string.IsNullOrEmpty(this.
SelectedAccount);
948 private async Task ExecuteDeleteCredentials()
950 SortedDictionary<string, bool> Sorted =
new();
958 string Jid = this.Account +
"@" + this.
XmppServer;
959 string Prefix =
"Credentials." + Jid +
".";
974 string[] Accounts =
new string[Sorted.Count];
975 Sorted.Keys.CopyTo(Accounts, 0);
980 this.SelectedAccount =
string.Empty;
981 this.SavedAccounts = Accounts;
985 this.loading =
false;
988 await
MainWindow.
MessageBox(
"Credentials deleted.",
"Information", MessageBoxButton.OK, MessageBoxImage.Information);
const string NamespaceEDaler
Namespace of eDaler component.
string ComponentAddress
Address of eDaler component
Interaction logic for MainWindow.xaml
static void MouseHourglass()
Displays an hourglass cursor (or similar for waiting purposes).
static void ErrorBox(string ErrorMessage)
Displays an error message on the screen, on the main UI thread.
static Task< MessageBoxResult > MessageBox(string Text, string Caption, MessageBoxButton Button, MessageBoxImage Icon)
Displays a message box on the screen, on the main UI thread.
static void UpdateGui(GuiDelegate Method)
Calls a method from the Main UI thread.
static void MouseDefault()
Returns to default mouse pointer.
Defines a custom command.
bool IsSelected
If the node is selected.
ContractsClient Contracts
Contracts client.
override async Task Start()
Starts the model.
virtual Task Stop()
Stops the model.
string[] SavedAccounts
Saved accounts
ICommand RemoveSnifferItem
Remove Sniffer Item Command
string SelectedAccount
Selected account
string Password
Password of account (or digest of password).
async Task ExecuteDisconnect()
Disconnects from the network
XmppState State
Connection state.
LegalModel Legal
Legal ID model
long HttpFileUploadMaxSize
HTTP File Upload Maximum size
async Task ExecuteConnect()
Connects to the network
ICommand ClearSniffer
Clear Sniffer Command
WalletModel Wallet
Wallet model
ICommand CopySnifferItem
Copy Sniffer Item Command
bool CreateAccount
If an account can be created
ICommand NewAccount
New ACcount command
string Account
Account name of XMPP Server
string EDalerComponentJid
eDaler® Component JID
bool TrustServerCertificate
If server certificates should be trusted (even if they don't validate).
string LegalComponentJid
Legal Component JID
ICommand Disconnect
Disconnection command
ICommand SaveCredentials
Save Credentials command
bool ConnectOnStartup
If the application should connect to the XMPP network on startup.
string PasswordMethod
Method of digest, if password digest is used.
override async Task Start()
Starts the model.
string Password2
Second entry of password
bool StorePasswordInsteadOfDigest
If passwords are to be stored, insteaed of digests
bool AllowInsecureAlgorithms
If insecure algorithms should be allowed or not.
ICommand DeleteCredentials
Delete Credentials command
string ApiKey
API Key, if used to create an account.
string HttpFileUploadComponentJid
HTTP File Upload Component JID
TokensModel Tokens
Tokens model
EventHandlerAsync< XmppState > OnStateChanged
Event raised when connection state changes.
ICommand Connect
Connection command
string NeuroFeaturesComponentJid
Neuro-Features Component JID
bool Connected
If the client is connected.
string ApiKeySecret
API Key Secret, if used to create an account.
string XmppServer
Domain name of XMPP Server
override async Task Stop()
Stops the model.
ICommand RandomizePassword
Password randomization command
Sniffer, that outputs items to a ListView control. From the IoTGateway project, with permission.
Represents one item in a sniffer output. From the IoTGateway project, with permission.
DateTime Timestamp
Timestamp of event.
SniffItemType Type
Sniff item type.
Defines a custom parametrized command.
Abstract base class for persistant view models
async Task Save()
Saves properties to persisted storage.
async Task Load()
Loads properties from persisted storage.
void Add(IPersistedProperty Property)
Adds a persistant property
Generic class for persistant properties
Generic class for properties
override async Task Start()
Starts the model.
NeuroFeaturesClient NeuroFeaturesClient
Neuro-Features client
override async Task Start()
Starts the model.
EDalerClient EDaler
eDaler® client.
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 ...
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.
DNS resolver, as defined in:
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...
string TargetHost
Target Host
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.
string ComponentAddress
Component address.
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.
string Body
Human readable body.
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.
const string Namespace
urn:xmpp:http:upload:0
Contains information about an item of an entity.
Event arguments for service discovery responses.
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.
Event arguments for service items discovery responses.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Task< ServiceItemsDiscoveryEventArgs > ServiceItemsDiscoveryAsync(string To)
Performs an asynchronous service items discovery request
async Task DisposeAsync()
Closes the connection and disposes of all resources.
Task< ServiceDiscoveryEventArgs > ServiceDiscoveryAsync(string To)
Performs an asynchronous service discovery request
string PasswordHashMethod
Password hash method.
string PasswordHash
Hash value of password. Depends on method used to authenticate user.
Task Connect()
Connects the client.
void AllowRegistration()
If registration of a new account is allowed. Requires a password. Having a password hash is not suffi...
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.