Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
LegalIdentityConfiguration.cs
1using System;
3using System.IO;
4using System.Runtime.ExceptionServices;
5using System.Text;
6using System.Text.RegularExpressions;
7using System.Threading.Tasks;
8using Waher.Content;
12using Waher.Events;
22using Waher.Script;
23using Waher.Security;
26
28{
33 {
34 internal static readonly Regex FromSaveUnsavedRegex = new Regex(@"Waher[.]Persistence[.]Files[.]ObjectBTreeFile[.+]((<SaveUnsaved>\w*[.]\w*)|(SaveUnsavedLocked))",
35 RegexOptions.Compiled | RegexOptions.Singleline);
36 internal static readonly Regex FromUpdateObjectRegex = new Regex(@"Waher[.]Persistence[.]Files[.]ObjectBTreeFile[.+]((<UpdateObject>\w*[.]\w*)|(UpdateObjectLocked))",
37 RegexOptions.Compiled | RegexOptions.Singleline);
38 internal static readonly Regex GatewayStartupRegex = new Regex(@"Waher[.]IoTGateway[.]Gateway([.]Start|[.+]<?Start>?\w*[.]\w*)",
39 RegexOptions.Compiled | RegexOptions.Singleline);
40 internal static readonly Regex ApplyLegalIdentityRegex = new Regex(@"Waher[.]IoTGateway[.]Setup[.]LegalIdentityConfiguration([.]ApplyLegalIdentity|[.+]<?ApplyLegalIdentity>?\w*[.]\w*)",
41 RegexOptions.Compiled | RegexOptions.Singleline);
42 internal static readonly Regex ApplyIdRegex = new Regex(@"Waher[.]IoTGateway[.]Setup[.]LegalIdentityConfiguration([.]ApplyId|[.+]<?ApplyId>?\w*[.]\w*)",
43 RegexOptions.Compiled | RegexOptions.Singleline);
44 internal static readonly Regex GenerateNewKeysRegex = new Regex(@"Waher[.]Networking[.]XMPP[.]Contracts[.]ContractsClient([.]GenerateNewKeys|[.+]<?GenerateNewKeys>?\w*[.]\w*)",
45 RegexOptions.Compiled | RegexOptions.Singleline);
46 internal static readonly Regex GetAttachmentRegex = new Regex(@"Waher[.]Networking[.]XMPP[.]Contracts[.]ContractsClient[.+]<?GetAttachmentAsync>?\w*[.]\w*",
47 RegexOptions.Compiled | RegexOptions.Singleline);
48 internal static readonly Regex CreateCredentialRegex = new Regex(@"Waher[.]Security[.]TOTP[.]ExternalCredential[.+](CreateAsync|<?CreateAsync>?\w*[.]\w*)",
49 RegexOptions.Compiled | RegexOptions.Singleline);
50 internal static readonly Regex ExportCredentialsRegex = new Regex(@"Waher[.]Security[.]TOTP[.]ExternalCredential[.+](ExportAsync|<?ExportAsync>?\w*[.]\w*)",
51 RegexOptions.Compiled | RegexOptions.Singleline);
52 private static readonly ICallStackCheck[] approvedSources = Assert.Convert(new object[]
53 {
54 "Waher.Persistence.NeuroLedger.NeuroLedgerProvider",
55 typeof(Content.Markdown.Web.MarkdownToHtmlConverter),
56 "Waher.IoTGateway.Setup.LegalIdentityConfiguration.UpdateClients",
57 FromSaveUnsavedRegex,
58 FromUpdateObjectRegex,
59 GatewayStartupRegex
60 });
61 private static readonly ICallStackCheck[] approvedContractClientSources = Assert.Convert(new object[]
62 {
63 "Waher.Service.IoTBroker.Legal.MFA.QuickLogin",
64 "Waher.Service.IoTBroker.Marketplace.MarketplaceProcessor",
65 "Waher.Service.IoTBroker.WebServices.Agent.Account.RemoteQuickLogin",
66 "Waher.Service.Abc4Io.Model.Actions.Contract.SignContract",
67 ApplyLegalIdentityRegex,
68 ApplyIdRegex,
70 GenerateNewKeysRegex,
71 GetAttachmentRegex
72 });
73 private static readonly ICallStackCheck[] approvedOtpSources = Assert.Convert(new object[]
74 {
75 typeof(Content.Markdown.Web.MarkdownToHtmlConverter),
76 FromSaveUnsavedRegex,
77 FromUpdateObjectRegex,
78 GatewayStartupRegex,
79 CreateCredentialRegex,
80 ExportCredentialsRegex
81 });
82
83 private static LegalIdentityConfiguration instance = null;
84 private static LegalIdentity[] allIdentities = null;
85 private static LegalIdentity[] approvedIdentities = null;
86
87 private HttpResource applyLegalIdentity = null;
88 private HttpResource contractAction = null;
89
90 private bool useLegalIdentity = false;
91 private bool protectWithPassword = false;
92 private string firstName = string.Empty;
93 private string middleName = string.Empty;
94 private string lastName = string.Empty;
95 private string personalNumber = string.Empty;
96 private string address = string.Empty;
97 private string address2 = string.Empty;
98 private string postalCode = string.Empty;
99 private string area = string.Empty;
100 private string city = string.Empty;
101 private string region = string.Empty;
102 private string country = string.Empty;
103 private string nationality = string.Empty;
104 private string gender = string.Empty;
105 private string orgName = string.Empty;
106 private string orgDepartment = string.Empty;
107 private string orgRole = string.Empty;
108 private string orgNumber = string.Empty;
109 private string orgAddress = string.Empty;
110 private string orgAddress2 = string.Empty;
111 private string orgPostalCode = string.Empty;
112 private string orgArea = string.Empty;
113 private string orgCity = string.Empty;
114 private string orgRegion = string.Empty;
115 private string orgCountry = string.Empty;
116 private AlternativeField[] altFields = null;
117 private AlternativeField[] passwordHashes = null;
118 private DateTime checkApprovedExpiry = DateTime.MinValue;
119 private DateTime? birthDate = null;
120
125 {
126 }
127
131 public static LegalIdentityConfiguration Instance => instance;
132
136 [DefaultValue(false)]
138 {
139 get => this.useLegalIdentity;
140 set => this.useLegalIdentity = value;
141 }
142
146 [DefaultValueStringEmpty]
147 public string FirstName
148 {
149 get => this.firstName;
150 set => this.firstName = value;
151 }
152
156 [DefaultValueStringEmpty]
157 public string MiddleName
158 {
159 get => this.middleName;
160 set => this.middleName = value;
161 }
162
166 [DefaultValueStringEmpty]
167 public string LastName
168 {
169 get => this.lastName;
170 set => this.lastName = value;
171 }
172
176 [DefaultValueStringEmpty]
177 public string PersonalNumber
178 {
179 get => this.personalNumber;
180 set => this.personalNumber = value;
181 }
182
186 [DefaultValueStringEmpty]
187 public string Address
188 {
189 get => this.address;
190 set => this.address = value;
191 }
192
196 [DefaultValueStringEmpty]
197 public string Address2
198 {
199 get => this.address2;
200 set => this.address2 = value;
201 }
202
206 [DefaultValueStringEmpty]
207 public string PostalCode
208 {
209 get => this.postalCode;
210 set => this.postalCode = value;
211 }
212
216 [DefaultValueStringEmpty]
217 public string Area
218 {
219 get => this.area;
220 set => this.area = value;
221 }
222
226 [DefaultValueStringEmpty]
227 public string City
228 {
229 get => this.city;
230 set => this.city = value;
231 }
232
236 [DefaultValueStringEmpty]
237 public string Region
238 {
239 get => this.region;
240 set => this.region = value;
241 }
242
246 [DefaultValueStringEmpty]
247 public string Country
248 {
249 get => this.country;
250 set => this.country = value;
251 }
252
256 [DefaultValueStringEmpty]
257 public string Nationality
258 {
259 get => this.nationality;
260 set => this.nationality = value;
261 }
262
266 [DefaultValueStringEmpty]
267 public string Gender
268 {
269 get => this.gender;
270 set => this.gender = value;
271 }
272
276 [DefaultValueNull]
277 public DateTime? BirthDate
278 {
279 get => this.birthDate;
280 set => this.birthDate = value;
281 }
282
286 [DefaultValueStringEmpty]
287 public string OrgName
288 {
289 get => this.orgName;
290 set => this.orgName = value;
291 }
292
296 [DefaultValueStringEmpty]
297 public string OrgDepartment
298 {
299 get => this.orgDepartment;
300 set => this.orgDepartment = value;
301 }
302
306 [DefaultValueStringEmpty]
307 public string OrgRole
308 {
309 get => this.orgRole;
310 set => this.orgRole = value;
311 }
312
316 [DefaultValueStringEmpty]
317 public string OrgNumber
318 {
319 get => this.orgNumber;
320 set => this.orgNumber = value;
321 }
322
326 [DefaultValueStringEmpty]
327 public string OrgAddress
328 {
329 get => this.orgAddress;
330 set => this.orgAddress = value;
331 }
332
336 [DefaultValueStringEmpty]
337 public string OrgAddress2
338 {
339 get => this.orgAddress2;
340 set => this.orgAddress2 = value;
341 }
342
346 [DefaultValueStringEmpty]
347 public string OrgPostalCode
348 {
349 get => this.orgPostalCode;
350 set => this.orgPostalCode = value;
351 }
352
356 [DefaultValueStringEmpty]
357 public string OrgArea
358 {
359 get => this.orgArea;
360 set => this.orgArea = value;
361 }
362
366 [DefaultValueStringEmpty]
367 public string OrgCity
368 {
369 get => this.orgCity;
370 set => this.orgCity = value;
371 }
372
376 [DefaultValueStringEmpty]
377 public string OrgRegion
378 {
379 get => this.orgRegion;
380 set => this.orgRegion = value;
381 }
382
386 [DefaultValueStringEmpty]
387 public string OrgCountry
388 {
389 get => this.orgCountry;
390 set => this.orgCountry = value;
391 }
392
396 [DefaultValueNull]
398 {
399 get => this.altFields;
400 set => this.altFields = value;
401 }
402
406 [DefaultValue(false)]
408 {
409 get => this.protectWithPassword;
410 set
411 {
412 if (this.protectWithPassword != value)
413 {
414 if (this.protectWithPassword)
415 Assert.CallFromSource(approvedSources);
416
417 this.protectWithPassword = value;
418 }
419 }
420 }
421
425 [DefaultValueNull]
427 {
428 get
429 {
430 if (!(this.passwordHashes is null))
431 Assert.CallFromSource(approvedSources);
432
433 return this.passwordHashes;
434 }
435
436 set
437 {
438 if (!(this.passwordHashes is null))
439 Assert.CallFromSource(approvedSources);
440
441 this.passwordHashes = value;
442 }
443 }
444
448 public override string Resource => "/Settings/LegalIdentity.md";
449
453 public override int Priority => 320;
454
459 public override void SetStaticInstance(ISystemConfiguration Configuration)
460 {
461 instance = Configuration as LegalIdentityConfiguration;
462 }
463
469 public override Task<string> Title(Language Language)
470 {
471 return Language.GetStringAsync(typeof(Gateway), 10, "Legal Identity");
472 }
473
477 public override async Task ConfigureSystem()
478 {
479 if (this.useLegalIdentity && !(Gateway.ContractsClient is null))
480 await this.AddHandlers();
481 }
482
483 private async Task AddHandlers()
484 {
485 if (!this.handlersAdded || Gateway.ContractsClient != this.prevClient)
486 {
487 this.handlersAdded = true;
488 this.prevClient = Gateway.ContractsClient;
489
490 Gateway.XmppClient.OnStateChanged += this.XmppClient_OnStateChanged;
491
492 Gateway.ContractsClient.ContractDeleted += this.ContractsClient_ContractDeleted;
493 Gateway.ContractsClient.ContractSigned += this.ContractsClient_ContractSigned;
494 Gateway.ContractsClient.ContractUpdated += this.ContractsClient_ContractUpdated;
495 Gateway.ContractsClient.IdentityUpdated += this.ContractsClient_IdentityUpdated;
496 Gateway.ContractsClient.PetitionedIdentityResponseReceived += this.ContractsClient_PetitionedIdentityResponseReceived;
497 Gateway.ContractsClient.PetitionedContractResponseReceived += this.ContractsClient_PetitionedContractResponseReceived;
498
499 Gateway.ContractsClient.SetAllowedSources(approvedContractClientSources);
500 ExternalCredential.SetAllowedSources(approvedOtpSources);
501
502 if (Gateway.XmppClient.State == XmppState.Connected)
503 await this.GetLegalIdentities(null);
504 }
505 }
506
507 private bool handlersAdded = false;
508 private ContractsClient prevClient = null;
509
510 private async Task XmppClient_OnStateChanged(object Sender, XmppState NewState)
511 {
512 if (NewState == XmppState.Connected)
513 await this.GetLegalIdentities(null);
514 }
515
516 private Task GetLegalIdentities(object P)
517 {
518 if (Gateway.ContractsClient is null || Gateway.XmppClient.State != XmppState.Connected)
519 return Task.CompletedTask;
520
521 return Gateway.ContractsClient.GetLegalIdentities((Sender, e) =>
522 {
523 if (e.Ok)
524 {
525 approvedIdentities = this.SetLegalIdentities(e.Identities, null, false);
526 allIdentities = this.SetLegalIdentities(e.Identities, null, true);
527 }
528 else
529 Gateway.ScheduleEvent(this.GetLegalIdentities, DateTime.Now.AddMinutes(1), null);
530
531 return Task.CompletedTask;
532
533 }, null);
534 }
535
536 private LegalIdentity[] SetLegalIdentities(LegalIdentity[] Identities, LegalIdentity Changed, bool All)
537 {
538 List<LegalIdentity> Result = new List<LegalIdentity>();
539 LegalIdentity ID2;
540 bool Added = false;
541
542 if (!(Identities is null))
543 {
544 foreach (LegalIdentity ID in Identities)
545 {
546 if (Changed is null || ID.Id != Changed.Id)
547 ID2 = ID;
548 else
549 {
550 ID2 = Changed;
551 Added = true;
552 }
553
554 if (All || ID2.State == Networking.XMPP.Contracts.IdentityState.Approved)
555 Result.Add(ID2);
556 }
557 }
558
559 if (!Added && !(Changed is null) && (All || Changed.State == Networking.XMPP.Contracts.IdentityState.Approved))
560 Result.Add(Changed);
561
562 Result.Sort((i1, i2) => Math.Sign((i2.Created - i1.Created).Ticks));
563
564 return Result.ToArray();
565 }
566
571 {
572 get
573 {
574 Assert.CallFromSource(approvedSources);
575 return allIdentities;
576 }
577 }
578
582 public static Dictionary<string, object>[] AllIdentitiesJSON
583 {
584 get
585 {
586 List<Dictionary<string, object>> Result = new List<Dictionary<string, object>>();
587
588 if (!(allIdentities is null))
589 {
590 foreach (LegalIdentity ID in allIdentities)
591 {
592 Dictionary<string, object> ID2 = new Dictionary<string, object>()
593 {
594 { "Id", ID.Id },
595 { "Created", ID.Created },
596 { "Properties", ID.Properties },
597 { "Attachments", ID.Attachments },
598 { "From", ID.From },
599 { "To", ID.To },
600 { "State", ID.State },
601 { PersonalInformation.AddressTag, string.Empty },
602 { PersonalInformation.Address2Tag, string.Empty },
603 { PersonalInformation.PostalCodeTag, string.Empty },
604 { PersonalInformation.AreaTag, string.Empty },
605 { PersonalInformation.CityTag, string.Empty },
606 { PersonalInformation.RegionTag, string.Empty },
607 { PersonalInformation.CountryTag, string.Empty },
608 { PersonalInformation.NationalityTag, string.Empty },
609 { PersonalInformation.GenderTag, string.Empty },
610 { PersonalInformation.BirthDayTag, string.Empty },
611 { PersonalInformation.BirthMonthTag, string.Empty },
612 { PersonalInformation.BirthYearTag, string.Empty },
613 { PersonalInformation.PersonalNumberTag, string.Empty },
625 { "", string.Empty }
626 };
627
628 foreach (Property P in ID.Properties)
629 ID2[P.Name] = P.Value;
630
635
636 Result.Add(ID2);
637 }
638 }
639
640 return Result.ToArray();
641 }
642 }
643
648 {
649 get
650 {
651 Assert.CallFromSource(approvedSources);
652 return approvedIdentities;
653 }
654 }
655
661 public static bool IsMe(CaseInsensitiveString LegalId)
662 {
663 return TryGetMyIdentity(LegalId, out _);
664 }
665
672 public static bool TryGetMyIdentity(CaseInsensitiveString LegalId, out LegalIdentity Identity)
673 {
674 Identity = null;
675
676 if (allIdentities is null)
677 return false;
678
679 foreach (LegalIdentity ID in allIdentities)
680 {
681 if (LegalId == ID.Id)
682 {
683 Identity = ID;
684 return true;
685 }
686 }
687
688 return false;
689 }
690
696 public static bool IsMeApproved(CaseInsensitiveString LegalId)
697 {
698 if (approvedIdentities is null)
699 return false;
700
701 foreach (LegalIdentity ID in approvedIdentities)
702 {
703 if (LegalId == ID.Id)
704 return true;
705 }
706
707 return false;
708 }
709
710 private async Task ContractsClient_IdentityUpdated(object Sender, LegalIdentityEventArgs e)
711 {
712 LegalIdentity ID = e.Identity;
713
714 List<KeyValuePair<string, object>> Tags = new List<KeyValuePair<string, object>>()
715 {
716 new KeyValuePair<string, object>("State", ID.State),
717 new KeyValuePair<string, object>("Provider", ID.Provider),
718 new KeyValuePair<string, object>("Created", ID.Created),
719 new KeyValuePair<string, object>("Updated", ID.Updated),
720 new KeyValuePair<string, object>("From", ID.From),
721 new KeyValuePair<string, object>("KeyAlgorithm", ID.ClientKeyName),
722 new KeyValuePair<string, object>("PublicKey", Convert.ToBase64String(ID.ClientPubKey))
723 };
724
725 foreach (Property P in ID.Properties)
726 Tags.Add(new KeyValuePair<string, object>(P.Name, P.Value));
727
728 Log.Notice("Legal Identity updated.", e.Identity.Id, Tags.ToArray());
729
730 await this.UpdateClients(ID);
731 }
732
733 private Task UpdateClients(LegalIdentity ID)
734 {
735 allIdentities = this.SetLegalIdentities(allIdentities, ID, true);
736 approvedIdentities = this.SetLegalIdentities(approvedIdentities, ID, false);
737
738 return this.UpdateClients();
739 }
740
741 private async Task UpdateClients()
742 {
743 string[] TabIDs;
744
746 TabIDs = ClientEvents.GetTabIDs();
747 else
748 TabIDs = ClientEvents.GetTabIDsForLocation("/Settings/LegalIdentity.md");
749
750 if (TabIDs.Length > 0)
751 {
752 string FileName = Path.Combine(Gateway.RootFolder, "Settings", "LegalIdentities.md");
753 if (File.Exists(FileName))
754 {
755 string Markdown = await Files.ReadAllTextAsync(FileName);
757 v["Config"] = this;
758
760 string HTML = await Doc.GenerateHTML();
761 HTML = HtmlDocument.GetBody(HTML);
762
763 await ClientEvents.PushEvent(TabIDs, "UpdateIdentityTable", HTML);
764 }
765 }
766 }
767
768 private Task ContractsClient_ContractSigned(object Sender, ContractSignedEventArgs e)
769 {
770 Log.Notice("Smart contract signed.", e.ContractId, e.LegalId, new KeyValuePair<string, object>("Role", e.Role));
771 return Task.CompletedTask;
772 }
773
774 private Task ContractsClient_ContractUpdated(object Sender, ContractReferenceEventArgs e)
775 {
776 Log.Notice("Smart contract updated.", e.ContractId);
777 return Task.CompletedTask;
778 }
779
780 private Task ContractsClient_ContractDeleted(object Sender, ContractReferenceEventArgs e)
781 {
782 Log.Notice("Smart contract deleted.", e.ContractId);
783 return Task.CompletedTask;
784 }
785
790 public override Task InitSetup(HttpServer WebServer)
791 {
792 this.applyLegalIdentity = WebServer.Register("/Settings/ApplyLegalIdentity", null, this.ApplyLegalIdentity, true, false, true);
793 this.contractAction = WebServer.Register("/Settings/ContractAction", null, this.ContractAction, true, false, true);
794
795 this.checkApprovedExpiry = Gateway.ScheduleEvent(this.CheckApprovedExpiry, DateTime.Now.AddMinutes(5), true);
796
797 return base.InitSetup(WebServer);
798 }
799
804 public override Task UnregisterSetup(HttpServer WebServer)
805 {
806 WebServer.Unregister(this.applyLegalIdentity);
807 WebServer.Unregister(this.contractAction);
808
809 Gateway.CancelScheduledEvent(this.checkApprovedExpiry);
810 this.checkApprovedExpiry = DateTime.MinValue;
811
812 return base.UnregisterSetup(WebServer);
813 }
814
815 private async Task CheckApprovedExpiry(object State)
816 {
817 if (!(State is bool Reschedule))
818 Reschedule = false;
819
820 DateTime Now = DateTime.Now;
821 DateTime Today = Now.Date;
822
823 if (Reschedule)
824 this.checkApprovedExpiry = Gateway.ScheduleEvent(this.CheckApprovedExpiry, Today.AddDays(1).AddMinutes(5), true);
825
826 if (!this.useLegalIdentity)
827 return;
828
829 if (Gateway.XmppClient.State != XmppState.Connected)
830 {
831 Gateway.ScheduleEvent(this.CheckApprovedExpiry, Now.AddMinutes(5), false);
832 return;
833 }
834
835 DateTime Expires = LatestApprovedLegalIdentityExpires;
836 if (Expires < Now)
837 {
838 await Gateway.SendNotification("No approved Legal Identity registered for the gateway.", string.Empty);
839 return;
840 }
841
842 int Days = (int)(Expires - Today).TotalDays;
843
844 if (Days < 60)
845 {
846 switch (Days)
847 {
848 case 0:
849 await Gateway.SendNotification("The approved Legal Identity for the gateway **expires today**.", string.Empty);
850 return;
851
852 case 1:
853 await Gateway.SendNotification("The approved Legal Identity for the gateway **expires tomorrow**.", string.Empty);
854 return;
855
856 default:
857 await Gateway.SendNotification("The approved Legal Identity for the gateway **expires in " + Days.ToString() + " days**.", string.Empty);
858 return;
859 }
860 }
861 }
862
868 public override async Task<bool> SetupConfiguration(HttpServer WebServer)
869 {
870 if (!this.Complete &&
871 Gateway.XmppClient.State == XmppState.Offline &&
872 !(Gateway.XmppClient is null))
873 {
874 await Gateway.XmppClient.Connect();
875 }
876
877 await this.AddHandlers();
878
879 return await base.SetupConfiguration(WebServer);
880 }
881
885 protected override string ConfigPrivilege => "Admin.Legal.ID";
886
887 private async Task ApplyLegalIdentity(HttpRequest Request, HttpResponse Response)
888 {
889 Gateway.AssertUserAuthenticated(Request, this.ConfigPrivilege);
890
891 if (!Request.HasData)
892 {
893 await Response.SendResponse(new BadRequestException());
894 return;
895 }
896
897 ContentResponse Content = await Request.DecodeDataAsync();
898 if (Content.HasError || !(Content.Decoded is Dictionary<string, object> Parameters))
899 {
900 await Response.SendResponse(new BadRequestException());
901 return;
902 }
903
904 if (!Parameters.TryGetValue("protectWithPassword", out object Obj) || !(Obj is bool ProtectWithPassword) ||
905 !Parameters.TryGetValue("password", out Obj) || !(Obj is string Password) ||
906 !Parameters.TryGetValue("password2", out Obj) || !(Obj is string Password2) ||
907 !Parameters.TryGetValue("firstName", out Obj) || !(Obj is string FirstName) ||
908 !Parameters.TryGetValue("middleName", out Obj) || !(Obj is string MiddleName) ||
909 !Parameters.TryGetValue("lastName", out Obj) || !(Obj is string LastName) ||
910 !Parameters.TryGetValue("pNr", out Obj) || !(Obj is string PNr) ||
911 !Parameters.TryGetValue("address", out Obj) || !(Obj is string Address) ||
912 !Parameters.TryGetValue("address2", out Obj) || !(Obj is string Address2) ||
913 !Parameters.TryGetValue("postalCode", out Obj) || !(Obj is string PostalCode) ||
914 !Parameters.TryGetValue("area", out Obj) || !(Obj is string Area) ||
915 !Parameters.TryGetValue("city", out Obj) || !(Obj is string City) ||
916 !Parameters.TryGetValue("region", out Obj) || !(Obj is string Region) ||
917 !Parameters.TryGetValue("country", out Obj) || !(Obj is string Country) ||
918 !Parameters.TryGetValue("nationality", out Obj) || !(Obj is string Nationality) ||
919 !Parameters.TryGetValue("gender", out Obj) || !(Obj is string Gender) ||
920 !Parameters.TryGetValue("birthDate", out Obj) || !(Obj is string BirthDateStr) ||
921 !Parameters.TryGetValue("orgName", out Obj) || !(Obj is string OrgName) ||
922 !Parameters.TryGetValue("orgDepartment", out Obj) || !(Obj is string OrgDepartment) ||
923 !Parameters.TryGetValue("orgRole", out Obj) || !(Obj is string OrgRole) ||
924 !Parameters.TryGetValue("orgNr", out Obj) || !(Obj is string OrgNr) ||
925 !Parameters.TryGetValue("orgAddress", out Obj) || !(Obj is string OrgAddress) ||
926 !Parameters.TryGetValue("orgAddress2", out Obj) || !(Obj is string OrgAddress2) ||
927 !Parameters.TryGetValue("orgPostalCode", out Obj) || !(Obj is string OrgPostalCode) ||
928 !Parameters.TryGetValue("orgArea", out Obj) || !(Obj is string OrgArea) ||
929 !Parameters.TryGetValue("orgCity", out Obj) || !(Obj is string OrgCity) ||
930 !Parameters.TryGetValue("orgRegion", out Obj) || !(Obj is string OrgRegion) ||
931 !Parameters.TryGetValue("orgCountry", out Obj) || !(Obj is string OrgCountry))
932 {
933 await Response.SendResponse(new BadRequestException());
934 return;
935 }
936
938 {
939 if (string.IsNullOrEmpty(Password))
940 {
941 await Response.SendResponse(new BadRequestException("Enter a password and try again."));
942 return;
943 }
944
945 if (Password != Password2)
946 {
947 await Response.SendResponse(new BadRequestException("Passwords do not match. Retype, and try again."));
948 return;
949 }
950 }
951
952 List<AlternativeField> AlternativeFields = new List<AlternativeField>();
953
954 if (Parameters.TryGetValue("alternative", out Obj) && Obj is Dictionary<string, object> Alternative)
955 {
956 foreach (KeyValuePair<string, object> P in Alternative)
957 {
958 switch (P.Key.ToUpper())
959 {
987 await Response.SendResponse(new BadRequestException("The following alternative field name is not allowed: " + P.Key));
988 return;
989
990 default:
991 AlternativeFields.Add(new AlternativeField(P.Key, P.Value.ToString()));
992 break;
993 }
994 }
995 }
996
997 string TabID = Request.Header["X-TabID"];
998 if (string.IsNullOrEmpty(TabID))
999 {
1000 await Response.SendResponse(new BadRequestException());
1001 return;
1002 }
1003
1004 if (!string.IsNullOrEmpty(BirthDateStr))
1005 {
1006 if (!DateTime.TryParse(BirthDateStr, out DateTime BirthDate))
1007 {
1008 await Response.SendResponse(new BadRequestException("Invalid birth date."));
1009 return;
1010 }
1011
1012 this.birthDate = BirthDate;
1013 }
1014 else
1015 this.birthDate = null;
1016
1017 this.useLegalIdentity = true;
1018 this.firstName = FirstName;
1019 this.middleName = MiddleName;
1020 this.lastName = LastName;
1021 this.personalNumber = PNr;
1022 this.address = Address;
1023 this.address2 = Address2;
1024 this.postalCode = PostalCode;
1025 this.area = Area;
1026 this.city = City;
1027 this.region = Region;
1028 this.country = Country;
1029 this.nationality = Nationality;
1030 this.gender = Gender;
1031 this.orgName = OrgName;
1032 this.orgDepartment = OrgDepartment;
1033 this.orgRole = OrgRole;
1034 this.orgNumber = OrgNr;
1035 this.orgAddress = OrgAddress;
1036 this.orgAddress2 = OrgAddress2;
1037 this.orgPostalCode = OrgPostalCode;
1038 this.orgArea = OrgArea;
1039 this.orgCity = OrgCity;
1040 this.orgRegion = OrgRegion;
1041 this.orgCountry = OrgCountry;
1042 this.altFields = AlternativeFields.ToArray();
1043
1044 await Database.Update(this);
1045
1046 Response.StatusCode = 200;
1047 Response.StatusMessage = "OK";
1048
1049 await this.ApplyId(Password, TabID, ProtectWithPassword, false, null);
1050 }
1051
1056 public Task Reapply(TaskCompletionSource<bool> Response)
1057 {
1058 return this.ApplyId(null, null, false, true, Response);
1059 }
1060
1061 internal async Task ApplyId(string Password, string TabID, bool ProtectWithPassword,
1062 bool Reapplication, TaskCompletionSource<bool> Response)
1063 {
1065 await Gateway.ContractsClient.Apply(this.GetProperties(), this.ApplyResponse,
1066 new object[] { Password, TabID, ProtectWithPassword, Reapplication, Response });
1067 }
1068
1069 private async Task ApplyResponse(object Sender, LegalIdentityEventArgs e)
1070 {
1071 object[] P = (object[])e.State;
1072 string Password = (string)P[0];
1073 string TabID = (string)P[1];
1074 bool ProtectWithPassword = (bool)P[2];
1075 bool Reapplication = (bool)P[3];
1076 TaskCompletionSource<bool> Response = (TaskCompletionSource<bool>)P[4];
1077
1078 if (e.Ok)
1079 {
1080 if (!Reapplication)
1081 {
1082 this.protectWithPassword = ProtectWithPassword;
1083
1085 {
1086 Dictionary<string, AlternativeField> ById = new Dictionary<string, AlternativeField>();
1087
1088 if (!(this.passwordHashes is null))
1089 {
1090 foreach (AlternativeField H in this.passwordHashes)
1091 ById[H.Key] = H;
1092 }
1093
1094 ById[e.Identity.Id] = new AlternativeField(e.Identity.Id, this.CalcPasswordHash(e.Identity, Password));
1095
1096 AlternativeField[] Hashes = new AlternativeField[ById.Count];
1097 ById.Values.CopyTo(Hashes, 0);
1098
1099 this.passwordHashes = Hashes;
1100 }
1101
1102 this.Step = 1;
1103 await Database.Update(this);
1104
1105 if (!string.IsNullOrEmpty(TabID))
1106 await ClientEvents.PushEvent(new string[] { TabID }, "ApplicationOK", string.Empty);
1107 }
1108
1109 await this.UpdateClients(e.Identity);
1110
1111 Response?.TrySetResult(true);
1112 }
1113 else
1114 {
1115 if (!string.IsNullOrEmpty(TabID))
1116 await ClientEvents.PushEvent(new string[] { TabID }, "ApplicationError", e.ErrorText);
1117
1118 Response?.TrySetResult(false);
1119 }
1120 }
1121
1122 private string CalcPasswordHash(LegalIdentity ID, string Password)
1123 {
1124 StringBuilder sb = new StringBuilder();
1125 SortedDictionary<string, string> Sorted = new SortedDictionary<string, string>();
1126
1127 foreach (Property P in ID.Properties)
1128 {
1129 if (Sorted.TryGetValue(P.Name, out string s))
1130 {
1131 s += ";" + P.Value;
1132 Sorted[P.Name] = s;
1133 }
1134 else
1135 Sorted[P.Name] = P.Value;
1136 }
1137
1138 bool First = true;
1139
1140 foreach (KeyValuePair<string, string> P in Sorted)
1141 {
1142 if (First)
1143 First = false;
1144 else
1145 sb.Append(',');
1146
1147 sb.Append(P.Key);
1148 sb.Append('=');
1149 sb.Append(P.Value);
1150 }
1151
1152 byte[] Digest = Hashes.ComputeHMACSHA256Hash(System.Text.Encoding.UTF8.GetBytes(Password), System.Text.Encoding.UTF8.GetBytes(sb.ToString()));
1153
1154 return Convert.ToBase64String(Digest);
1155 }
1156
1157 private Property[] GetProperties()
1158 {
1159 List<Property> Properties = new List<Property>();
1160
1161 if (!string.IsNullOrEmpty(this.firstName))
1162 Properties.Add(new Property(PersonalInformation.FirstNameTag, this.firstName));
1163
1164 if (!string.IsNullOrEmpty(this.middleName))
1165 Properties.Add(new Property(PersonalInformation.MiddleNamesTag, this.middleName));
1166
1167 if (!string.IsNullOrEmpty(this.lastName))
1168 Properties.Add(new Property(PersonalInformation.LastNamesTag, this.lastName));
1169
1170 if (!string.IsNullOrEmpty(this.personalNumber))
1171 Properties.Add(new Property(PersonalInformation.PersonalNumberTag, this.personalNumber));
1172
1173 if (!string.IsNullOrEmpty(this.address))
1174 Properties.Add(new Property(PersonalInformation.AddressTag, this.address));
1175
1176 if (!string.IsNullOrEmpty(this.address2))
1177 Properties.Add(new Property(PersonalInformation.Address2Tag, this.address2));
1178
1179 if (!string.IsNullOrEmpty(this.postalCode))
1180 Properties.Add(new Property(PersonalInformation.PostalCodeTag, this.postalCode));
1181
1182 if (!string.IsNullOrEmpty(this.area))
1183 Properties.Add(new Property(PersonalInformation.AreaTag, this.area));
1184
1185 if (!string.IsNullOrEmpty(this.city))
1186 Properties.Add(new Property(PersonalInformation.CityTag, this.city));
1187
1188 if (!string.IsNullOrEmpty(this.region))
1189 Properties.Add(new Property(PersonalInformation.RegionTag, this.region));
1190
1191 if (!string.IsNullOrEmpty(this.country))
1192 Properties.Add(new Property(PersonalInformation.CountryTag, this.country));
1193
1194 if (!string.IsNullOrEmpty(this.nationality))
1195 Properties.Add(new Property(PersonalInformation.NationalityTag, this.nationality));
1196
1197 if (!string.IsNullOrEmpty(this.gender))
1198 Properties.Add(new Property(PersonalInformation.GenderTag, this.gender));
1199
1200 if (!(this.birthDate is null))
1201 {
1202 Properties.Add(new Property(PersonalInformation.BirthDayTag, this.birthDate.Value.Day.ToString()));
1203 Properties.Add(new Property(PersonalInformation.BirthMonthTag, this.birthDate.Value.Month.ToString()));
1204 Properties.Add(new Property(PersonalInformation.BirthYearTag, this.birthDate.Value.Year.ToString()));
1205 }
1206
1207 if (!string.IsNullOrEmpty(this.orgName))
1208 Properties.Add(new Property(PersonalInformation.OrganizationNameTag, this.orgName));
1209
1210 if (!string.IsNullOrEmpty(this.orgDepartment))
1211 Properties.Add(new Property(PersonalInformation.OrganizationDepartmentTag, this.orgDepartment));
1212
1213 if (!string.IsNullOrEmpty(this.orgRole))
1214 Properties.Add(new Property(PersonalInformation.OrganizationRoleTag, this.orgRole));
1215
1216 if (!string.IsNullOrEmpty(this.orgNumber))
1217 Properties.Add(new Property(PersonalInformation.OrganizationNumberTag, this.orgNumber));
1218
1219 if (!string.IsNullOrEmpty(this.orgAddress))
1220 Properties.Add(new Property(PersonalInformation.OrganizationAddressTag, this.orgAddress));
1221
1222 if (!string.IsNullOrEmpty(this.orgAddress2))
1223 Properties.Add(new Property(PersonalInformation.OrganizationAddress2Tag, this.orgAddress2));
1224
1225 if (!string.IsNullOrEmpty(this.orgPostalCode))
1226 Properties.Add(new Property(PersonalInformation.OrganizationPostalCodeTag, this.orgPostalCode));
1227
1228 if (!string.IsNullOrEmpty(this.orgArea))
1229 Properties.Add(new Property(PersonalInformation.OrganizationAreaTag, this.orgArea));
1230
1231 if (!string.IsNullOrEmpty(this.orgCity))
1232 Properties.Add(new Property(PersonalInformation.OrganizationCityTag, this.orgCity));
1233
1234 if (!string.IsNullOrEmpty(this.orgRegion))
1235 Properties.Add(new Property(PersonalInformation.OrganizationRegionTag, this.orgRegion));
1236
1237 if (!string.IsNullOrEmpty(this.orgCountry))
1238 Properties.Add(new Property(PersonalInformation.OrganizationCountryTag, this.orgCountry));
1239
1240 if (!(this.altFields is null))
1241 {
1242 foreach (AlternativeField F in this.altFields)
1243 Properties.Add(new Property(F.Key, F.Value));
1244 }
1245
1246 return Properties.ToArray();
1247 }
1248
1249 private async Task ContractAction(HttpRequest Request, HttpResponse Response)
1250 {
1251 Gateway.AssertUserAuthenticated(Request, this.ConfigPrivilege);
1252
1253 if (!Request.HasData)
1254 {
1255 await Response.SendResponse(new BadRequestException("No content."));
1256 return;
1257 }
1258
1259 string Password;
1260 ContentResponse Content = await Request.DecodeDataAsync();
1261 if (Content.HasError || !(Content.Decoded is Dictionary<string, object> Parameters))
1262 {
1263 await Response.SendResponse(new UnsupportedMediaTypeException("Invalid content."));
1264 return;
1265 }
1266
1267 if (!Parameters.TryGetValue("requestId", out object Obj) || !(Obj is string RequestId) ||
1268 !Parameters.TryGetValue("sign", out Obj) || !(Obj is bool Sign) ||
1269 !Parameters.TryGetValue("protect", out Obj) || !(Obj is bool Protect))
1270 {
1271 await Response.SendResponse(new BadRequestException("Invalid request."));
1272 return;
1273 }
1274
1275 if (Protect)
1276 {
1277 if (!Parameters.TryGetValue("password", out Obj) || !(Obj is string s))
1278 {
1279 await Response.SendResponse(new BadRequestException("No password."));
1280 return;
1281 }
1282
1283 Password = s;
1284 }
1285 else
1286 Password = string.Empty;
1287
1288 ContractSignatureRequest SignatureRequest = await Database.TryLoadObject<ContractSignatureRequest>(RequestId);
1289 if (SignatureRequest is null)
1290 {
1291 await Response.SendResponse(new NotFoundException("Content Signature Request not found."));
1292 return;
1293 }
1294
1295 if (SignatureRequest.Signed.HasValue)
1296 {
1297 await Response.SendResponse(new BadRequestException("Contract has already been signed."));
1298 return;
1299 }
1300
1301 if (Protect)
1302 {
1304 {
1305 await Response.SendResponse(new BadRequestException("No approved legal identity found with which to sign the contract."));
1306 return;
1307 }
1308
1309 string Id = this.GetPasswordLegalId(Password);
1310 if (string.IsNullOrEmpty(Id))
1311 {
1312 await Response.SendResponse(new BadRequestException("Invalid password."));
1313 return;
1314 }
1315 }
1316 else if (this.protectWithPassword)
1317 {
1318 await Response.SendResponse(new BadRequestException("Legal identities protected with password."));
1319 return;
1320 }
1321
1322 if (Sign)
1323 {
1324 Contract Contract = await SignatureRequest.GetContract();
1325 Contract = await Gateway.ContractsClient.SignContractAsync(Contract, SignatureRequest.Role, false);
1326 SignatureRequest.SetContract(Contract);
1327 SignatureRequest.Signed = DateTime.Now;
1328 await Database.Update(SignatureRequest);
1329 }
1330 else
1331 await Database.Delete(SignatureRequest);
1332
1333 Response.StatusCode = 200;
1334 Response.StatusMessage = "OK";
1335 Response.ContentType = JsonCodec.DefaultContentType;
1336 await Response.Write(JSON.Encode(Sign, false));
1337 await Response.SendResponse();
1338 }
1339
1344 {
1345 get => !(approvedIdentities is null) && approvedIdentities.Length > 0;
1346 }
1347
1352 {
1353 get
1354 {
1356 throw new NotFoundException("Gateway has no approved legal identity.");
1357
1358 LegalIdentity Latest = null;
1359
1360 foreach (LegalIdentity Identity in approvedIdentities)
1361 {
1362 if (Latest is null || Identity.Created > Latest.Created)
1363 Latest = Identity;
1364 }
1365
1366 return Latest;
1367 }
1368 }
1369
1374 {
1375 get
1376 {
1378 }
1379 }
1380
1385 {
1386 get
1387 {
1389 return DateTime.MinValue;
1390
1391 return LatestApprovedLegalIdentity?.To ?? DateTime.MinValue;
1392 }
1393 }
1394
1400 public string GetPasswordLegalId(string Password)
1401 {
1402 if (approvedIdentities is null || approvedIdentities.Length == 0)
1403 return null;
1404
1405 foreach (LegalIdentity ID in approvedIdentities)
1406 {
1407 string H = this.CalcPasswordHash(ID, Password);
1408
1409 foreach (AlternativeField F in this.passwordHashes)
1410 {
1411 if (F.Key == ID.Id)
1412 {
1413 if (F.Value == H)
1414 return F.Key;
1415
1416 break;
1417 }
1418 }
1419 }
1420
1421 return null;
1422 }
1423
1434 public Task<bool> PetitionLegalIdentity(string LegalId, string PetitionId, string Purpose,
1435 EventHandlerAsync<LegalIdentityPetitionResponseEventArgs> Callback, TimeSpan Timeout,
1436 HttpRequest Request)
1437 {
1438 if (this.protectWithPassword)
1439 throw new ForbiddenException(Request, "Petitioning legal identities is protected using passwords on this machine.");
1440
1441 return this.PetitionLegalIdentity(LegalId, PetitionId, Purpose, string.Empty, Callback, Timeout);
1442 }
1443
1454 public async Task<bool> PetitionLegalIdentity(string LegalId, string PetitionId, string Purpose, string Password,
1455 EventHandlerAsync<LegalIdentityPetitionResponseEventArgs> Callback, TimeSpan Timeout)
1456 {
1458 return false;
1459
1460 if (this.protectWithPassword)
1461 {
1462 string Id = this.GetPasswordLegalId(Password);
1463 if (string.IsNullOrEmpty(Id))
1464 return false;
1465 }
1466
1467 lock (this.identityPetitionCallbackMethods)
1468 {
1469 if (this.identityPetitionCallbackMethods.ContainsKey(PetitionId))
1470 throw new ArgumentException("Petition ID already used.", nameof(PetitionId));
1471
1472 this.identityPetitionCallbackMethods[PetitionId] = Callback;
1473 }
1474
1475 try
1476 {
1477 await Gateway.ContractsClient.PetitionIdentityAsync(LegalId, PetitionId, Purpose);
1478
1479 Gateway.ScheduleEvent((P) =>
1480 {
1481 LegalIdentityPetitionResponseEventArgs e = new LegalIdentityPetitionResponseEventArgs(null, null, (string)P, false, string.Empty, null);
1482 this.ContractsClient_PetitionedIdentityResponseReceived(Gateway.ContractsClient, e);
1483 }, DateTime.Now.Add(Timeout), PetitionId);
1484 }
1485 catch (Exception ex)
1486 {
1487 lock (this.identityPetitionCallbackMethods)
1488 {
1489 this.identityPetitionCallbackMethods.Remove(PetitionId);
1490 }
1491
1492 ExceptionDispatchInfo.Capture(ex).Throw();
1493 }
1494
1495 return true;
1496 }
1497
1509 public Task<bool> PetitionContract(string ContractId, string PetitionId, string Purpose,
1510 EventHandlerAsync<ContractPetitionResponseEventArgs> Callback, TimeSpan Timeout,
1511 HttpRequest Request)
1512 {
1513 if (this.protectWithPassword)
1514 throw new ForbiddenException(Request, "Petitioning legal identities is protected using passwords on this machine.");
1515
1516 return this.PetitionContract(ContractId, PetitionId, Purpose, string.Empty, Callback, Timeout);
1517 }
1518
1529 public async Task<bool> PetitionContract(string ContractId, string PetitionId, string Purpose, string Password,
1530 EventHandlerAsync<ContractPetitionResponseEventArgs> Callback, TimeSpan Timeout)
1531 {
1533 return false;
1534
1535 if (this.protectWithPassword)
1536 {
1537 string Id = this.GetPasswordLegalId(Password);
1538 if (string.IsNullOrEmpty(Id))
1539 return false;
1540 }
1541
1542 lock (this.contractPetitionCallbackMethods)
1543 {
1544 if (this.contractPetitionCallbackMethods.ContainsKey(PetitionId))
1545 throw new ArgumentException("Petition ID already used.", nameof(PetitionId));
1546
1547 this.contractPetitionCallbackMethods[PetitionId] = Callback;
1548 }
1549
1550 try
1551 {
1552 await Gateway.ContractsClient.PetitionContractAsync(ContractId, PetitionId, Purpose);
1553
1554 Gateway.ScheduleEvent((P) =>
1555 {
1556 ContractPetitionResponseEventArgs e = new ContractPetitionResponseEventArgs(null, null, (string)P, false, string.Empty, null);
1557 this.ContractsClient_PetitionedContractResponseReceived(Gateway.ContractsClient, e);
1558 }, DateTime.Now.Add(Timeout), PetitionId);
1559 }
1560 catch (Exception ex)
1561 {
1562 lock (this.contractPetitionCallbackMethods)
1563 {
1564 this.contractPetitionCallbackMethods.Remove(PetitionId);
1565 }
1566
1567 ExceptionDispatchInfo.Capture(ex).Throw();
1568 }
1569
1570 return true;
1571 }
1572
1573 private readonly Dictionary<string, EventHandlerAsync<LegalIdentityPetitionResponseEventArgs>> identityPetitionCallbackMethods = new Dictionary<string, EventHandlerAsync<LegalIdentityPetitionResponseEventArgs>>();
1574 private readonly Dictionary<string, EventHandlerAsync<ContractPetitionResponseEventArgs>> contractPetitionCallbackMethods = new Dictionary<string, EventHandlerAsync<ContractPetitionResponseEventArgs>>();
1575
1576 private Task ContractsClient_PetitionedIdentityResponseReceived(object Sender, LegalIdentityPetitionResponseEventArgs e)
1577 {
1578 EventHandlerAsync<LegalIdentityPetitionResponseEventArgs> Callback;
1579 string PetitionId = e.PetitionId;
1580
1581 lock (this.identityPetitionCallbackMethods)
1582 {
1583 if (!this.identityPetitionCallbackMethods.TryGetValue(PetitionId, out Callback))
1584 return Task.CompletedTask;
1585 else
1586 this.identityPetitionCallbackMethods.Remove(PetitionId);
1587 }
1588
1589 return Callback.Raise(Sender, e);
1590 }
1591
1592 private Task ContractsClient_PetitionedContractResponseReceived(object Sender, ContractPetitionResponseEventArgs e)
1593 {
1594 EventHandlerAsync<ContractPetitionResponseEventArgs> Callback;
1595 string PetitionId = e.PetitionId;
1596
1597 lock (this.contractPetitionCallbackMethods)
1598 {
1599 if (!this.contractPetitionCallbackMethods.TryGetValue(PetitionId, out Callback))
1600 return Task.CompletedTask;
1601 else
1602 this.contractPetitionCallbackMethods.Remove(PetitionId);
1603 }
1604
1605 return Callback.Raise(Sender, e);
1606 }
1607
1612 public override Task<bool> SimplifiedConfiguration()
1613 {
1614 return Task.FromResult(true);
1615 }
1616
1621 public const string GATEWAY_ID_USE = nameof(GATEWAY_ID_USE);
1622
1626 public const string GATEWAY_ID_FIRST = nameof(GATEWAY_ID_FIRST);
1627
1631 public const string GATEWAY_ID_MIDDLE = nameof(GATEWAY_ID_MIDDLE);
1632
1636 public const string GATEWAY_ID_LAST = nameof(GATEWAY_ID_LAST);
1637
1641 public const string GATEWAY_ID_PNR = nameof(GATEWAY_ID_PNR);
1642
1646 public const string GATEWAY_ID_ADDR = nameof(GATEWAY_ID_ADDR);
1647
1651 public const string GATEWAY_ID_ADDR2 = nameof(GATEWAY_ID_ADDR2);
1652
1656 public const string GATEWAY_ID_ZIP = nameof(GATEWAY_ID_ZIP);
1657
1661 public const string GATEWAY_ID_AREA = nameof(GATEWAY_ID_AREA);
1662
1666 public const string GATEWAY_ID_CITY = nameof(GATEWAY_ID_CITY);
1667
1671 public const string GATEWAY_ID_REGION = nameof(GATEWAY_ID_REGION);
1672
1676 public const string GATEWAY_ID_COUNTRY = nameof(GATEWAY_ID_COUNTRY);
1677
1681 public const string GATEWAY_ID_NATIONALITY = nameof(GATEWAY_ID_NATIONALITY);
1682
1686 public const string GATEWAY_ID_GENDER = nameof(GATEWAY_ID_GENDER);
1687
1691 public const string GATEWAY_ID_BDATE = nameof(GATEWAY_ID_BDATE);
1692
1696 public const string GATEWAY_ID_ORGNAME = nameof(GATEWAY_ID_ORGNAME);
1697
1701 public const string GATEWAY_ID_ORGDEPT = nameof(GATEWAY_ID_ORGDEPT);
1702
1706 public const string GATEWAY_ID_ORGROLE = nameof(GATEWAY_ID_ORGROLE);
1707
1711 public const string GATEWAY_ID_ORGNR = nameof(GATEWAY_ID_ORGNR);
1712
1716 public const string GATEWAY_ID_ORGADDR = nameof(GATEWAY_ID_ORGADDR);
1717
1721 public const string GATEWAY_ID_ORGADDR2 = nameof(GATEWAY_ID_ORGADDR2);
1722
1726 public const string GATEWAY_ID_ORGZIP = nameof(GATEWAY_ID_ORGZIP);
1727
1731 public const string GATEWAY_ID_ORGAREA = nameof(GATEWAY_ID_ORGAREA);
1732
1736 public const string GATEWAY_ID_ORGCITY = nameof(GATEWAY_ID_ORGCITY);
1737
1741 public const string GATEWAY_ID_ORGREGION = nameof(GATEWAY_ID_ORGREGION);
1742
1746 public const string GATEWAY_ID_ORGCOUNTRY = nameof(GATEWAY_ID_ORGCOUNTRY);
1747
1751 public const string GATEWAY_ID_ALT = nameof(GATEWAY_ID_ALT);
1752
1756 public const string GATEWAY_ID_ALT_ = nameof(GATEWAY_ID_ALT_);
1757
1761 public const string GATEWAY_ID_PASSWORD = nameof(GATEWAY_ID_PASSWORD);
1762
1767 public override async Task<bool> EnvironmentConfiguration()
1768 {
1769 if (!this.TryGetEnvironmentVariable(GATEWAY_ID_USE, false, out this.useLegalIdentity))
1770 return false;
1771
1772 if (!this.useLegalIdentity)
1773 return true;
1774
1775 this.firstName = Environment.GetEnvironmentVariable(GATEWAY_ID_FIRST) ?? string.Empty;
1776 this.middleName = Environment.GetEnvironmentVariable(GATEWAY_ID_MIDDLE) ?? string.Empty;
1777 this.lastName = Environment.GetEnvironmentVariable(GATEWAY_ID_LAST) ?? string.Empty;
1778 this.personalNumber = Environment.GetEnvironmentVariable(GATEWAY_ID_PNR) ?? string.Empty;
1779 this.address = Environment.GetEnvironmentVariable(GATEWAY_ID_ADDR) ?? string.Empty;
1780 this.address2 = Environment.GetEnvironmentVariable(GATEWAY_ID_ADDR2) ?? string.Empty;
1781 this.postalCode = Environment.GetEnvironmentVariable(GATEWAY_ID_ZIP) ?? string.Empty;
1782 this.area = Environment.GetEnvironmentVariable(GATEWAY_ID_AREA) ?? string.Empty;
1783 this.city = Environment.GetEnvironmentVariable(GATEWAY_ID_CITY) ?? string.Empty;
1784 this.region = Environment.GetEnvironmentVariable(GATEWAY_ID_REGION) ?? string.Empty;
1785 this.country = Environment.GetEnvironmentVariable(GATEWAY_ID_COUNTRY) ?? string.Empty;
1786 this.nationality = Environment.GetEnvironmentVariable(GATEWAY_ID_NATIONALITY) ?? string.Empty;
1787 this.gender = Environment.GetEnvironmentVariable(GATEWAY_ID_GENDER) ?? string.Empty;
1788 this.orgName = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGNAME) ?? string.Empty;
1789 this.orgDepartment = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGDEPT) ?? string.Empty;
1790 this.orgRole = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGROLE) ?? string.Empty;
1791 this.orgNumber = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGNR) ?? string.Empty;
1792 this.orgAddress = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGADDR) ?? string.Empty;
1793 this.orgAddress2 = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGADDR2) ?? string.Empty;
1794 this.orgPostalCode = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGZIP) ?? string.Empty;
1795 this.orgArea = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGAREA) ?? string.Empty;
1796 this.orgCity = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGCITY) ?? string.Empty;
1797 this.orgRegion = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGREGION) ?? string.Empty;
1798 this.orgCountry = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGCOUNTRY) ?? string.Empty;
1799
1800 if (!this.TryGetEnvironmentVariable(GATEWAY_ID_BDATE, false, out this.birthDate))
1801 return false;
1802
1803 List<AlternativeField> Fields = new List<AlternativeField>();
1804
1805 if (this.TryGetEnvironmentVariable(GATEWAY_ID_ALT,false,out string Value))
1806 {
1807 string[] Parts = Value.Split(',');
1808
1809 foreach (string Part in Parts)
1810 {
1811 string Name = GATEWAY_ID_ALT_ + Part;
1812
1813 if (!this.TryGetEnvironmentVariable(Name, true, out Value))
1814 return false;
1815
1816 Fields.Add(new AlternativeField(Part, Value));
1817 }
1818 }
1819
1820 this.altFields = Fields.ToArray();
1821
1822 Value = Environment.GetEnvironmentVariable(GATEWAY_ID_PASSWORD);
1823
1824 TaskCompletionSource<bool> Result = new TaskCompletionSource<bool>();
1825 try
1826 {
1827 Task _ = Task.Delay(30000).ContinueWith(Prev => Result?.TrySetException(new TimeoutException()));
1828
1829 await this.ApplyId(Value, null, !string.IsNullOrEmpty(Value), false, Result);
1830
1831 if (await Result.Task)
1832 return true;
1833 else
1834 return false;
1835 }
1836 catch (Exception ex)
1837 {
1838 Log.Exception(ex);
1839 return false;
1840 }
1841 }
1842
1843 }
1844}
Contains information about a response to a content request.
bool HasError
If an error occurred.
object Decoded
Decoded object.
static string GetBody(string Html)
Extracts the contents of the BODY element in a HTML string.
Helps with common JSON-related tasks.
Definition: JSON.cs:16
static string Encode(string s)
Encodes a string for inclusion in JSON.
Definition: JSON.cs:537
const string DefaultContentType
application/json
Definition: JsonCodec.cs:20
Contains a markdown document. This markdown document class supports original markdown,...
async Task< string > GenerateHTML()
Generates HTML from the markdown text.
static Task< MarkdownDocument > CreateAsync(string MarkdownText, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
Contains settings that the Markdown parser uses to customize its behavior.
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
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:1657
static void Notice(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a notice event.
Definition: Log.cs:460
The ClientEvents class allows applications to push information asynchronously to web clients connecte...
Definition: ClientEvents.cs:51
static string[] GetTabIDsForLocation(string Location)
Gets the Tab IDs of all tabs that display a particular resource.
static Task< int > PushEvent(string[] TabIDs, string Type, object Data)
Puses an event to a set of Tabs, given their Tab IDs.
static string[] GetTabIDs()
Gets all open Tab IDs.
Static class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:147
static IUser AssertUserAuthenticated(HttpRequest Request, string Privilege)
Makes sure a request is being made from a session with a successful user login.
Definition: Gateway.cs:3868
static bool Configuring
If the gateway is being configured.
Definition: Gateway.cs:3171
static Task SendNotification(Graph Graph)
Sends a graph as a notification message to configured notification recipients.
Definition: Gateway.cs:4677
static ContractsClient ContractsClient
XMPP Contracts Client, if such a compoent is available on the XMPP broker.
Definition: Gateway.cs:5299
static DateTime ScheduleEvent(Action< object > Callback, DateTime When, object State)
Schedules a one-time event.
Definition: Gateway.cs:4253
static Emoji1LocalFiles Emoji1_24x24
Emojis.
Definition: Gateway.cs:3166
static XmppClient XmppClient
XMPP Client connection of gateway.
Definition: Gateway.cs:4038
static string RootFolder
Web root folder.
Definition: Gateway.cs:3142
static bool CancelScheduledEvent(DateTime When)
Cancels a scheduled event.
Definition: Gateway.cs:4275
Represents an alternative field in a legal identity.
string Key
Alternative field name.
bool Complete
If the configuration is complete.
bool TryGetEnvironmentVariable(string VariableName, bool Required, out string Value)
Tries to get a string-valued environment variable.
Abstract base class for multi-step system configurations.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
The server understood the request, but is refusing to fulfill it. Authorization will not help and the...
Represents an HTTP request.
Definition: HttpRequest.cs:22
HttpRequestHeader Header
Request header.
Definition: HttpRequest.cs:182
bool HasData
If the request has data.
Definition: HttpRequest.cs:113
async Task< ContentResponse > DecodeDataAsync()
Decodes data sent in request.
Definition: HttpRequest.cs:139
Base class for all HTTP resources.
Definition: HttpResource.cs:23
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:23
async Task SendResponse()
Sends the response back to the client. If the resource is synchronous, there's no need to call this m...
Task Write(byte[] Data)
Returns binary data in the response.
Implements an HTTP server.
Definition: HttpServer.cs:41
static SessionVariables CreateSessionVariables()
Creates a new collection of variables, that contains access to the global set of variables.
Definition: HttpServer.cs:2130
HttpResource Register(HttpResource Resource)
Registers a resource with the server.
Definition: HttpServer.cs:1568
bool Unregister(HttpResource Resource)
Unregisters a resource from the server.
Definition: HttpServer.cs:1743
The server has not found anything matching the Request-URI. No indication is given of whether the con...
The server is refusing to service the request because the entity of the request is in a format not su...
Contains the definition of a contract
Definition: Contract.cs:22
Adds support for legal identities, smart contracts and signatures to an XMPP client.
async Task GenerateNewKeys()
Generates new keys for the contracts clients.
Task PetitionIdentityAsync(string LegalId, string PetitionId, string Purpose)
Sends a petition to the owner of a legal identity, to access the information in the identity....
void SetAllowedSources(object[] ApprovedSources)
If access to sensitive methods is only accessible from a set of approved sources.
Task PetitionContractAsync(string ContractId, string PetitionId, string Purpose)
Sends a petition to the parts of a smart contract, to access the information in the contract....
Task< Contract > SignContractAsync(Contract Contract, string Role, bool Transferable)
Signs a contract
Task GetLegalIdentities(EventHandlerAsync< LegalIdentitiesEventArgs > Callback, object State)
Gets legal identities registered with the account.
Task Apply(Property[] Properties, EventHandlerAsync< LegalIdentityEventArgs > Callback, object State)
Applies for a legal identity to be registered.
Class defining a part in a contract
Definition: Part.cs:30
Contains personal information found in a legal identity.
bool Ok
If the response is an OK result response (true), or an error response (false).
object State
State object passed to the original request.
XmppState State
Current state of connection.
Definition: XmppClient.cs:985
Task Connect()
Connects the client.
Definition: XmppClient.cs:641
Represents a case-insensitive string.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:21
static async Task Update(object Object)
Updates an object in the database.
Definition: Database.cs:1211
static async Task Delete(object Object)
Deletes an object in the database.
Definition: Database.cs:1291
static Task< object > TryLoadObject(string CollectionName, object ObjectId)
Tries to load an object given its Object ID ObjectId and its collection name CollectionName .
Definition: Database.cs:1838
Contains static methods
Definition: Files.cs:14
static async Task< string > ReadAllTextAsync(string FileName)
Reads a text file asynchronously.
Definition: Files.cs:84
Contains information about a language.
Definition: Language.cs:17
Task< string > GetStringAsync(Type Type, int Id, string Default)
Gets the string value of a string ID. If no such string exists, a string is created with the default ...
Definition: Language.cs:209
Collection of variables.
Definition: Variables.cs:25
Static class containing methods that can be used to make sure calls are made from appropriate locatio...
Definition: Assert.cs:15
static ICallStackCheck[] Convert(params object[] Sources)
Converts an array of objects into an array of ICallStackCheck objects, assuming each listed source is...
Definition: Assert.cs:99
static void CallFromSource(params string[] Sources)
Makes sure the call is made from one of the listed sources.
Definition: Assert.cs:54
Contains methods for simple hash calculations.
Definition: Hashes.cs:57
static byte[] ComputeHMACSHA256Hash(byte[] Key, byte[] Data)
Computes the HMAC-SHA-256 hash of a block of binary data.
Definition: Hashes.cs:735
Contains OTP secret information for an OTP endpoint.
static void SetAllowedSources(ICallStackCheck[] ApprovedSources)
If access to sensitive methods is only accessible from a set of approved sources.
Interface for system configurations. The gateway will scan all module for system configuration classe...
Interface for call stack checks.
Definition: ImplTypes.g.cs:58
Gender
Gender classification in a legal ID.
Definition: Gender.cs:7
XmppState
State of XMPP connection.
Definition: XmppState.cs:7