Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ContactSupportViewModel.cs
1using System.ComponentModel;
2using System.Security.Cryptography;
3using System.Text;
4using System.Xml;
5using CommunityToolkit.Mvvm.ComponentModel;
6using CommunityToolkit.Mvvm.Input;
7using Mopups.Services;
14using Waher.Content;
15using System.Globalization;
21
23{
24 public partial class ContactSupportViewModel : BaseRegistrationViewModel, ICodeVerification
25 {
26
27 public ContactSupportViewModel() : base(RegistrationStep.ContactSupport)
28 {
29 this.SupportEmail = "neuro-access@trustanchorgroup.com";
30 }
31
32 [ObservableProperty]
33 private string supportEmail;
34
35 [RelayCommand]
36 private async Task ContactSupport()
37 {
38 string email = this.SupportEmail;
39 string subject = ServiceRef.Localizer[nameof(AppResources.SupportEmailSubject)];
40
41 string mailtoUri = $"mailto:{email}?subject={Uri.EscapeDataString(subject)}";
42
43 try
44 {
45 if(!await Launcher.OpenAsync(new Uri(mailtoUri)))
46 {
48 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)],
49 ServiceRef.Localizer[nameof(AppResources.EmailClientNotAvailable), this.SupportEmail],
50 ServiceRef.Localizer[nameof(AppResources.Ok)]);
51 }
52 }
53 catch (Exception)
54 {
56 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)],
57 ServiceRef.Localizer[nameof(AppResources.EmailClientNotAvailable), this.SupportEmail],
58 ServiceRef.Localizer[nameof(AppResources.Ok)]);
59 }
60 }
61 protected override async Task OnInitialize()
62 {
63 await base.OnInitialize();
64
65 LocalizationManager.Current.PropertyChanged += this.LocalizationManagerEventHandler;
66
67 if (App.Current is not null)
68 {
69 this.CountDownTimer = App.Current.Dispatcher.CreateTimer();
70 this.CountDownTimer.Interval = TimeSpan.FromMilliseconds(1000);
71 this.CountDownTimer.Tick += this.CountDownEventHandler;
72 }
73
74 try
75 {
76 object Result = await InternetContent.PostAsync(
77 new Uri("https://" + Constants.Domains.IdDomain + "/ID/CountryCode.ws"), string.Empty,
78 new KeyValuePair<string, string>("Accept", "application/json"));
79
80 if ((Result is Dictionary<string, object> Response) &&
81 Response.TryGetValue("CountryCode", out object? cc) &&
82 (cc is string CountryCode))
83 {
84 if (ISO_3166_1.TryGetCountryByCode(CountryCode, out ISO_3166_Country? Country))
85 this.SelectedCountry = Country;
86 }
87 }
88 catch (Exception ex)
89 {
90 ServiceRef.LogService.LogException(ex);
91 }
92 }
93
94 public void LocalizationManagerEventHandler(object? sender, PropertyChangedEventArgs e)
95 {
96 this.OnPropertyChanged(nameof(this.LocalizedSendCodeText));
97 }
98
99 protected override void OnPropertyChanged(PropertyChangedEventArgs e)
100 {
101 base.OnPropertyChanged(e);
102
103 if (e.PropertyName == nameof(this.IsBusy))
104 this.SendCommand.NotifyCanExecuteChanged();
105 }
106
107
108 [ObservableProperty]
109 [NotifyPropertyChangedFor(nameof(CanSend))]
110 [NotifyPropertyChangedFor(nameof(EmailValidationError))]
111 [NotifyCanExecuteChangedFor(nameof(this.SendCommand))]
112 private bool emailIsValid;
113
114 [ObservableProperty]
115 [NotifyPropertyChangedFor(nameof(CanSend))]
116 [NotifyPropertyChangedFor(nameof(PhoneValidationError))]
117 [NotifyCanExecuteChangedFor(nameof(this.SendCommand))]
118 private bool phoneIsValid;
119
120 [ObservableProperty]
121 [NotifyPropertyChangedFor(nameof(CanSend))]
122 [NotifyCanExecuteChangedFor(nameof(this.SendCommand))]
123 private string emailText = string.Empty;
124
125 [ObservableProperty]
126 [NotifyPropertyChangedFor(nameof(CanSend))]
127 [NotifyCanExecuteChangedFor(nameof(this.SendCommand))]
128 private string phoneText = string.Empty;
129
130 public string EmailValidationError => !this.EmailIsValid ? ServiceRef.Localizer[nameof(AppResources.EmailValidationFormat)] : string.Empty;
131
132 public string PhoneValidationError => !this.PhoneIsValid ? ServiceRef.Localizer[nameof(AppResources.PhoneValidationDigits)] : string.Empty;
133
134 [ObservableProperty]
135 [NotifyPropertyChangedFor(nameof(LocalizedSendCodeText))]
136 [NotifyCanExecuteChangedFor(nameof(SendCommand))]
137 [NotifyCanExecuteChangedFor(nameof(ResendCodeCommand))]
138 private int countDownSeconds;
139
140 [ObservableProperty]
141 private IDispatcherTimer? countDownTimer;
142
143 public bool CanSend => this.EmailIsValid && this.PhoneIsValid &&
144 !this.IsBusy &&
145 (this.CountDownSeconds <= 0) &&
146 !string.IsNullOrEmpty(this.EmailText) && !string.IsNullOrEmpty(this.PhoneText);
147
148 [ObservableProperty]
150
151
152 [ObservableProperty]
153 private string? localizedPhoneValidationError;
154 public string LocalizedSendCodeText
155 {
156 get
157 {
158 if (this.CountDownSeconds > 0)
159 return ServiceRef.Localizer[nameof(AppResources.SendSeconds), this.CountDownSeconds];
160
161 return ServiceRef.Localizer[nameof(AppResources.Send)];
162 }
163 }
164
165
166
167 [RelayCommand]
168 private async Task SelectPhoneCode()
169 {
170 SelectPhoneCodePopup Page = new();
171 await MopupService.Instance.PushAsync(Page);
172
173 ISO_3166_Country? Result = await Page.Result;
174
175 if (Result is not null)
176 this.SelectedCountry = Result;
177
178 return;
179 }
180 public bool CanResendCode => this.CountDownSeconds <= 0;
181
182 [RelayCommand(CanExecute = nameof(this.CanSend))]
183 private async Task Send()
184 {
185 IsBusy = true;
186 try
187 {
188 if (!ServiceRef.NetworkService.IsOnline)
189 {
191 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)],
192 ServiceRef.Localizer[nameof(AppResources.NetworkSeemsToBeMissing)]);
193 return;
194 }
195
196 string fullPhoneNumber = $"+{SelectedCountry.DialCode}{PhoneText}";
197
198 if (SelectedCountry.DialCode == "46") // Adjust for Swedish numbers
199 fullPhoneNumber = $"+{SelectedCountry.DialCode}{PhoneText.TrimStart('0')}";
200
201 // Send phone verification code
202 object phoneSendResult = await InternetContent.PostAsync(
203 new Uri("https://" + Constants.Domains.IdDomain + "/ID/SendVerificationMessage.ws"),
204 new Dictionary<string, object>
205 {
206 { "Nr", fullPhoneNumber },
207 { "AppName", Constants.Application.Name },
208 { "Language", CultureInfo.CurrentCulture.TwoLetterISOLanguageName }
209 }, new KeyValuePair<string, string>("Accept", "application/json"));
210
211
212 bool phoneSent = phoneSendResult is Dictionary<string, object> phoneResponse &&
213 phoneResponse.TryGetValue("Status", out var phoneObj) &&
214 phoneObj is bool phoneStatus && phoneStatus;
215
216 if (phoneSent)
217 {
218 StartTimer();
219
220 // Navigate to VerifyCodePage for phone code
221 if (!await this.VerifyCodeAsync(fullPhoneNumber, isEmail: false))
222 {
223 return;
224 }
225
226 // Verification successful - DO STUFF
227 }
228
229
230 }
231 catch (Exception ex)
232 {
233 ServiceRef.LogService.LogException(ex);
235 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)], ex.Message,
236 ServiceRef.Localizer[nameof(AppResources.Ok)]);
237 }
238 finally
239 {
240 this.IsBusy = false;
241 }
242 }
243
244 [RelayCommand(CanExecute = nameof(CanResendCode))]
245 private async Task ResendCode()
246 {
247
248 }
249
250 private async Task<bool> VerifyCodeAsync(string identifier, bool isEmail)
251 {
252 VerifyCodeNavigationArgs navigationArgs = new(this, identifier);
253 await ServiceRef.UiService.GoToAsync(nameof(VerifyCodePage), navigationArgs, BackMethod.Pop);
254 string? code = await navigationArgs.VarifyCode!.Task;
255
256 if (!string.IsNullOrEmpty(code))
257 {
258 var parameters = new Dictionary<string, object>
259 {
260 { isEmail ? "EMail" : "Nr", identifier },
261 { "Code", int.Parse(code, NumberStyles.None, CultureInfo.InvariantCulture) }
262 };
263
264 object verifyResult = await InternetContent.PostAsync(
265 new Uri("https://" + Constants.Domains.IdDomain + "/ID/VerifyNumber.ws"),
266 parameters, new KeyValuePair<string, string>("Accept", "application/json"));
267
268 bool verified = verifyResult is Dictionary<string, object> verifyResponse &&
269 verifyResponse.TryGetValue("Status", out var obj) &&
270 obj is bool status && status;
271
272 return verified;
273 }
274
275 return false;
276 }
277
278
279 private void StartTimer()
280 {
281 if (this.CountDownTimer is not null)
282 {
283 this.CountDownSeconds = 300;
284
285 if (!this.CountDownTimer.IsRunning)
286 this.CountDownTimer.Start();
287 }
288 }
289
290 private void CountDownEventHandler(object? sender, EventArgs e)
291 {
292 if (this.CountDownTimer is not null)
293 {
294 if (this.CountDownSeconds > 0)
295 this.CountDownSeconds--;
296 else
297 this.CountDownTimer.Stop();
298 }
299 }
300
301 public bool CanScanQrCode => !this.IsBusy;
302
303
304 [RelayCommand(CanExecute = nameof(CanScanQrCode))]
305 private async Task ScanQrCode()
306 {
307 string? Url = await Services.UI.QR.QrCode.ScanQrCode(nameof(AppResources.QrPageTitleScanInvitation),
309
310 if (string.IsNullOrEmpty(Url))
311 return;
312
313 string Scheme = Constants.UriSchemes.GetScheme(Url) ?? string.Empty;
314
315 if (!string.Equals(Scheme, Constants.UriSchemes.Onboarding, StringComparison.OrdinalIgnoreCase))
316 return;
317
318 string[] Parts = Url.Split(':');
319
320 if (Parts.Length != 5)
321 {
323 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)],
324 ServiceRef.Localizer[nameof(AppResources.InvalidInvitationCode)],
325 ServiceRef.Localizer[nameof(AppResources.Ok)]);
326
327 return;
328 }
329
330 string Domain = Parts[1];
331 string Code = Parts[2];
332 string KeyStr = Parts[3];
333 string IVStr = Parts[4];
334 string EncryptedStr;
335 Uri Uri;
336
337 try
338 {
339 Uri = new Uri("https://" + Domain + "/Onboarding/GetInfo");
340 }
341 catch (Exception ex)
342 {
343 ServiceRef.LogService.LogException(ex);
344
346 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)],
347 ServiceRef.Localizer[nameof(AppResources.InvalidInvitationCode)],
348 ServiceRef.Localizer[nameof(AppResources.Ok)]);
349
350 return;
351 }
352
353 this.IsBusy = true;
354
355 try
356 {
357 try
358 {
359 KeyValuePair<byte[], string> P = await InternetContent.PostAsync(Uri, Encoding.ASCII.GetBytes(Code), "text/plain",
360 new KeyValuePair<string, string>("Accept", "text/plain"));
361
362 object Decoded = await InternetContent.DecodeAsync(P.Value, P.Key, Uri);
363
364 EncryptedStr = (string)Decoded;
365 }
366 catch (Exception ex)
367 {
368 ServiceRef.LogService.LogException(ex);
369
371 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)],
372 ServiceRef.Localizer[nameof(AppResources.UnableToAccessInvitation)],
373 ServiceRef.Localizer[nameof(AppResources.Ok)]);
374 this.IsBusy = false;
375 return;
376 }
377
378 try
379 {
380 byte[] Key = Convert.FromBase64String(KeyStr);
381 byte[] IV = Convert.FromBase64String(IVStr);
382 byte[] Encrypted = Convert.FromBase64String(EncryptedStr);
383
384 using Aes Aes = Aes.Create();
385 Aes.BlockSize = 128;
386 Aes.KeySize = 256;
387 Aes.Mode = CipherMode.CBC;
388 Aes.Padding = PaddingMode.PKCS7;
389
390 using ICryptoTransform Decryptor = Aes.CreateDecryptor(Key, IV);
391 byte[] Decrypted = Decryptor.TransformFinalBlock(Encrypted, 0, Encrypted.Length);
392 string Xml = Encoding.UTF8.GetString(Decrypted);
393
394 XmlDocument Doc = new()
395 {
396 PreserveWhitespace = true
397 };
398
399 Doc.LoadXml(Xml);
400
401 if ((Doc.DocumentElement is null) || (Doc.DocumentElement.NamespaceURI != ContractsClient.NamespaceOnboarding))
402 throw new Exception("Invalid Invitation XML");
403
404 LinkedList<XmlElement> ToProcess = new();
405 ToProcess.AddLast(Doc.DocumentElement);
406
407 bool AccountDone = false;
408 XmlElement? LegalIdDefinition = null;
409 string? Pin = null;
410
411 while (ToProcess.First is not null)
412 {
413 XmlElement E = ToProcess.First.Value;
414 ToProcess.RemoveFirst();
415
416 switch (E.LocalName)
417 {
418 case "ApiKey":
419 KeyStr = XML.Attribute(E, "key");
420 string Secret = XML.Attribute(E, "secret");
421 Domain = XML.Attribute(E, "domain");
422
423 await SelectDomain(Domain, KeyStr, Secret);
424
426 ServiceRef.Localizer[nameof(AppResources.InvitationAccepted)],
427 ServiceRef.Localizer[nameof(AppResources.InvitedToCreateAccountOnDomain), Domain],
428 ServiceRef.Localizer[nameof(AppResources.Ok)]);
429 break;
430
431 case "Account":
432 string UserName = XML.Attribute(E, "userName");
433 string Password = XML.Attribute(E, "password");
434 string PasswordMethod = XML.Attribute(E, "passwordMethod");
435 Domain = XML.Attribute(E, "domain");
436
437 string DomainBak = ServiceRef.TagProfile?.Domain ?? string.Empty;
438 bool DefaultConnectivityBak = ServiceRef.TagProfile?.DefaultXmppConnectivity ?? false;
439 string ApiKeyBak = ServiceRef.TagProfile?.ApiKey ?? string.Empty;
440 string ApiSecretBak = ServiceRef.TagProfile?.ApiSecret ?? string.Empty;
441
442 await SelectDomain(Domain, string.Empty, string.Empty);
443
444 if (!await this.ConnectToAccount(UserName, Password, PasswordMethod, string.Empty, LegalIdDefinition, Pin ?? string.Empty))
445 {
446 ServiceRef.TagProfile?.SetDomain(DomainBak, DefaultConnectivityBak, ApiKeyBak, ApiSecretBak);
447 throw new Exception("Invalid account.");
448 }
449
450 LegalIdDefinition = null;
451 AccountDone = true;
452 break;
453
454 case "LegalId":
455 LegalIdDefinition = E;
456 break;
457
458 case "Pin":
459 Pin = XML.Attribute(E, "pin");
460 break;
461
462 case "Transfer":
463 foreach (XmlNode N in E.ChildNodes)
464 {
465 if (N is XmlElement E2)
466 {
467 ToProcess.AddLast(E2);
468 }
469 }
470 break;
471
472 default:
473 throw new Exception("Invalid Invitation XML");
474 }
475 }
476
477 if (AccountDone && LegalIdDefinition is not null)
478 {
479 await ServiceRef.XmppService.ImportSigningKeys(LegalIdDefinition);
480 GoToRegistrationStep(RegistrationStep.Finalize);
481 }
482 else if (AccountDone)
483 {
484 GoToRegistrationStep(RegistrationStep.ValidatePhone);
485 }
486 else
487 GoToRegistrationStep(RegistrationStep.ChooseProvider);
488 }
489 catch (Exception ex)
490 {
491 ServiceRef.LogService.LogException(ex);
492
494 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)],
495 ServiceRef.Localizer[nameof(AppResources.InvalidInvitationCode)],
496 ServiceRef.Localizer[nameof(AppResources.Ok)]);
497 }
498 }
499 finally
500 {
501 this.IsBusy = false;
502 }
503 }
504
505 private static async Task SelectDomain(string Domain, string Key, string Secret)
506 {
507 bool DefaultConnectivity;
508
509 try
510 {
511 (string HostName, int PortNumber, bool IsIpAddress) = await ServiceRef.NetworkService.LookupXmppHostnameAndPort(Domain);
512 DefaultConnectivity = HostName == Domain && PortNumber == XmppCredentials.DefaultPort;
513 }
514 catch (Exception ex)
515 {
516 ServiceRef.LogService.LogException(ex);
517 DefaultConnectivity = false;
518 }
519
520 ServiceRef.TagProfile.SetDomain(Domain, DefaultConnectivity, Key, Secret);
521 }
522
523
524 private async Task<bool> ConnectToAccount(string AccountName, string Password, string PasswordMethod, string LegalIdentityJid, XmlElement? LegalIdDefinition, string Pin)
525 {
526 try
527 {
528 async Task OnConnected(XmppClient client)
529 {
530 DateTime now = DateTime.Now;
531 LegalIdentity? createdIdentity = null;
532 LegalIdentity? approvedIdentity = null;
533
534 bool serviceDiscoverySucceeded;
535
537 {
538 serviceDiscoverySucceeded = await ServiceRef.XmppService.DiscoverServices(client);
539 }
540 else
541 {
542 serviceDiscoverySucceeded = true;
543 }
544
545 if (serviceDiscoverySucceeded && !string.IsNullOrEmpty(ServiceRef.TagProfile.LegalJid))
546 {
547 bool DestroyContractsClient = false;
548
549 if (!client.TryGetExtension(typeof(ContractsClient), out IXmppExtension Extension) ||
550 Extension is not ContractsClient ContractsClient)
551 {
553 DestroyContractsClient = true;
554 }
555
556 try
557 {
558 if (LegalIdDefinition is not null)
559 await ContractsClient.ImportKeys(LegalIdDefinition);
560
562
563 foreach (LegalIdentity Identity in Identities)
564 {
565 try
566 {
567 if ((string.IsNullOrEmpty(LegalIdentityJid) || string.Compare(LegalIdentityJid, Identity.Id, StringComparison.OrdinalIgnoreCase) == 0) &&
568 Identity.HasClientSignature &&
569 Identity.HasClientPublicKey &&
570 Identity.From <= now &&
571 Identity.To >= now &&
572 (Identity.State == IdentityState.Approved || Identity.State == IdentityState.Created) &&
573 Identity.ValidateClientSignature() &&
574 await ContractsClient.HasPrivateKey(Identity))
575 {
576 if (Identity.State == IdentityState.Approved)
577 {
578 approvedIdentity = Identity;
579 break;
580 }
581
582 createdIdentity ??= Identity;
583 }
584 }
585 catch (Exception)
586 {
587 // Keys might not be available. Ignore at this point. Keys will be generated later.
588 }
589 }
590
591 /*
592 if (approvedIdentity is not null)
593 {
594 this.LegalIdentity = approvedIdentity;
595 }
596 else if (createdIdentity is not null)
597 {
598 this.LegalIdentity = createdIdentity;
599 }*/
600 LegalIdentity? selectedIdentity = approvedIdentity ?? createdIdentity;
601
602 string SelectedId;
603
604 if (selectedIdentity is not null)
605 {
606 await ServiceRef.TagProfile.SetAccountAndLegalIdentity(AccountName, client.PasswordHash, client.PasswordHashMethod, selectedIdentity);
607 SelectedId = selectedIdentity.Id;
608 }
609 else
610 {
612 SelectedId = string.Empty;
613 }
614
615 if (!string.IsNullOrEmpty(Pin))
616 {
617 ServiceRef.TagProfile.LocalPassword = Pin;
618 }
619
620 foreach (LegalIdentity Identity in Identities)
621 {
622 if (Identity.Id == SelectedId)
623 {
624 continue;
625 }
626
627 switch (Identity.State)
628 {
629 case IdentityState.Approved:
630 case IdentityState.Created:
632 break;
633 }
634 }
635 }
636 finally
637 {
638 if (DestroyContractsClient)
639 {
641 }
642 }
643 }
644 }
645
646 (string hostName, int portNumber, bool isIpAddress) = await ServiceRef.NetworkService.LookupXmppHostnameAndPort(
647 ServiceRef.TagProfile?.Domain ?? string.Empty);
648
649 (bool succeeded, string? errorMessage, string[]? alternatives) = await ServiceRef.XmppService.TryConnectAndConnectToAccount(
650 ServiceRef.TagProfile?.Domain ?? string.Empty,
651 isIpAddress, hostName, portNumber, AccountName, Password, PasswordMethod, Constants.LanguageCodes.Default,
652 typeof(App).Assembly, OnConnected);
653
654 if (!succeeded)
655 {
657 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)],
658 errorMessage ?? string.Empty,
659 ServiceRef.Localizer[nameof(AppResources.Ok)]);
660 }
661 return succeeded;
662 }
663 catch (Exception ex)
664 {
665 ServiceRef.LogService.LogException(ex);
666
668 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)],
669 ServiceRef.Localizer[nameof(AppResources.UnableToConnectTo), ServiceRef.TagProfile?.Domain ?? string.Empty],
670 ServiceRef.Localizer[nameof(AppResources.Ok)]);
671 }
672
673 return false;
674 }
675 }
676}
The Application class, representing an instance of the Neuro-Access app.
Definition: App.xaml.cs:69
static new? App Current
Gets the current application, type casted to App.
Definition: App.xaml.cs:99
const string IdDomain
Neuro-Access domain.
Definition: Constants.cs:253
const string Default
The default language code.
Definition: Constants.cs:83
const string Onboarding
Onboarding URI Scheme (obinfo)
Definition: Constants.cs:129
static ? string GetScheme(string Url)
Gets the predefined scheme from an IoT Code
Definition: Constants.cs:146
A set of never changing property constants and helpful values.
Definition: Constants.cs:7
Conversion between Country Names and ISO-3166-1 country codes.
Definition: ISO_3166_1.cs:10
static bool TryGetCountryByCode(string? CountryCode, [NotNullWhen(true)] out ISO_3166_Country? Country)
Tries to get the country, given its country code.
Definition: ISO_3166_1.cs:71
static ISO_3166_Country DefaultCountry
This collection built from Wikipedia entry on ISO3166-1 on 9th Feb 2016
Definition: ISO_3166_1.cs:32
Base class that references services in the app.
Definition: ServiceRef.cs:31
static ILogService LogService
Log service.
Definition: ServiceRef.cs:91
static INetworkService NetworkService
Network service.
Definition: ServiceRef.cs:103
static IUiService UiService
Service serializing and managing UI-related tasks.
Definition: ServiceRef.cs:55
static ITagProfile TagProfile
TAG Profile service.
Definition: ServiceRef.cs:79
static IStringLocalizer Localizer
Localization service
Definition: ServiceRef.cs:235
static IXmppService XmppService
The XMPP service for XMPP communication.
Definition: ServiceRef.cs:67
Task< ISO_3166_Country?> Result
Task waiting for result. null means dialog was closed without selection.
Static class managing encoding and decoding of internet content.
static Task< object > DecodeAsync(string ContentType, byte[] Data, Encoding Encoding, KeyValuePair< string, string >[] Fields, Uri BaseUri)
Decodes an object.
static Task< object > PostAsync(Uri Uri, object Data, params KeyValuePair< string, string >[] Headers)
Posts to a resource, using a Uniform Resource Identifier (or Locator).
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
Adds support for legal identities, smart contracts and signatures to an XMPP client.
Task< bool > ImportKeys(string Xml)
Imports keys
Task< LegalIdentity > ObsoleteLegalIdentityAsync(string LegalIdentityId)
Obsoletes one of the legal identities of the account, given its ID.
Task< bool > HasPrivateKey(LegalIdentity Identity)
Checks if the private key of a legal identity is available. Private keys are required to be able to s...
const string NamespaceOnboarding
http://waher.se/schema/Onboarding/v1.xsd
Task< LegalIdentity[]> GetLegalIdentitiesAsync()
Gets legal identities registered with the account.
override void Dispose()
Disposes of the extension.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:59
string PasswordHashMethod
Password hash method.
Definition: XmppClient.cs:3445
bool TryGetExtension(Type Type, out IXmppExtension Extension)
Tries to get a registered extension of a specific type from the client.
Definition: XmppClient.cs:7318
string PasswordHash
Hash value of password. Depends on method used to authenticate user.
Definition: XmppClient.cs:3436
Class containing credentials for an XMPP client connection.
const int DefaultPort
Default XMPP Server port.
void SetDomain(string DomainName, bool DefaultXmppConnectivity, string Key, string Secret)
Set the domain name to connect to.
string? ApiKey
API Key, for creating new account.
Definition: ITagProfile.cs:61
string? LegalJid
The Jabber Legal JID for this user/profile.
Definition: ITagProfile.cs:116
string? ApiSecret
API Secret, for creating new account.
Definition: ITagProfile.cs:66
bool DefaultXmppConnectivity
If connecting to the domain can be done using default parameters (host=domain, default c2s port).
Definition: ITagProfile.cs:56
bool NeedsUpdating()
Returns true if the current ITagProfile needs to have its values updated, false otherwise.
void SetAccount(string AccountName, string ClientPasswordHash, string ClientPasswordHashMethod)
Set the account name and password for a new account.
string? Domain
The domain this profile is connected to.
Definition: ITagProfile.cs:51
Task SetAccountAndLegalIdentity(string AccountName, string ClientPasswordHash, string ClientPasswordHashMethod, LegalIdentity Identity)
Set the account name and password for an existing account.
Task GoToAsync(string Route, BackMethod BackMethod=BackMethod.Inherited, string? UniqueId=null)
Navigates the AppShell to the specified route, with page arguments to match.
Task< bool > DisplayAlert(string Title, string Message, string? Accept=null, string? Cancel=null)
Displays an alert/message box to the user.
class ISO_3166_Country(string Name, string Alpha2, string Alpha3, int NumericCode, string DialCode, EmojiInfo? EmojiInfo=null)
Representation of an ISO3166-1 Country
RegistrationStep
The different steps of a TAG Profile registration journey.
BackMethod
Navigation Back Method
Definition: BackMethod.cs:7
IdentityState
Lists recognized legal identity states.