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;
2using System.Collections.Generic;
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;
25
27{
32 {
33 internal static readonly Regex FromSaveUnsavedRegex = new Regex(@"Waher[.]Persistence[.]Files[.]ObjectBTreeFile[.+]((<SaveUnsaved>\w*[.]\w*)|(SaveUnsavedLocked))",
34 RegexOptions.Compiled | RegexOptions.Singleline);
35 internal static readonly Regex FromUpdateObjectRegex = new Regex(@"Waher[.]Persistence[.]Files[.]ObjectBTreeFile[.+]((<UpdateObject>\w*[.]\w*)|(UpdateObjectLocked))",
36 RegexOptions.Compiled | RegexOptions.Singleline);
37 internal static readonly Regex GatewayStartupRegex = new Regex(@"Waher[.]IoTGateway[.]Gateway([.]Start|[.+]<Start>\w*[.]\w*)",
38 RegexOptions.Compiled | RegexOptions.Singleline);
39 internal static readonly Regex ApplyLegalIdentityRegex = new Regex(@"Waher[.]IoTGateway[.]Setup[.]LegalIdentityConfiguration([.]ApplyLegalIdentity|[.+]<ApplyLegalIdentity>\w*[.]\w*)",
40 RegexOptions.Compiled | RegexOptions.Singleline);
41 internal static readonly Regex ApplyIdRegex = new Regex(@"Waher[.]IoTGateway[.]Setup[.]LegalIdentityConfiguration([.]ApplyId|[.+]<ApplyId>\w*[.]\w*)",
42 RegexOptions.Compiled | RegexOptions.Singleline);
43 internal static readonly Regex GenerateNewKeysRegex = new Regex(@"Waher[.]Networking[.]XMPP[.]Contracts[.]ContractsClient([.]GenerateNewKeys|[.+]<GenerateNewKeys>\w*[.]\w*)",
44 RegexOptions.Compiled | RegexOptions.Singleline);
45 internal static readonly Regex GetAttachmentRegex = new Regex(@"Waher[.]Networking[.]XMPP[.]Contracts[.]ContractsClient[.+]<GetAttachmentAsync>\w*[.]\w*",
46 RegexOptions.Compiled | RegexOptions.Singleline);
47 private static readonly object[] approvedSources = new object[]
48 {
49 "Waher.Persistence.NeuroLedger.NeuroLedgerProvider",
50 typeof(Content.Markdown.Web.MarkdownToHtmlConverter),
51 "Waher.IoTGateway.Setup.LegalIdentityConfiguration.UpdateClients",
52 FromSaveUnsavedRegex,
53 FromUpdateObjectRegex,
54 GatewayStartupRegex
55 };
56 private static readonly object[] approvedContractClientSources = new object[]
57 {
58 "Waher.Service.IoTBroker.Legal.MFA.QuickLogin",
59 "Waher.Service.IoTBroker.Marketplace.MarketplaceProcessor",
60 "Waher.Service.Abc4Io.Model.Actions.Contract.SignContract",
61 ApplyLegalIdentityRegex,
62 ApplyIdRegex,
64 GenerateNewKeysRegex,
65 GetAttachmentRegex
66 };
67
68 private static LegalIdentityConfiguration instance = null;
69 private static LegalIdentity[] allIdentities = null;
70 private static LegalIdentity[] approvedIdentities = null;
71
72 private HttpResource applyLegalIdentity = null;
73 private HttpResource contractAction = null;
74
75 private bool useLegalIdentity = false;
76 private bool protectWithPassword = false;
77 private string firstName = string.Empty;
78 private string middleName = string.Empty;
79 private string lastName = string.Empty;
80 private string personalNumber = string.Empty;
81 private string address = string.Empty;
82 private string address2 = string.Empty;
83 private string postalCode = string.Empty;
84 private string area = string.Empty;
85 private string city = string.Empty;
86 private string region = string.Empty;
87 private string country = string.Empty;
88 private string nationality = string.Empty;
89 private string gender = string.Empty;
90 private string orgName = string.Empty;
91 private string orgDepartment = string.Empty;
92 private string orgRole = string.Empty;
93 private string orgNumber = string.Empty;
94 private string orgAddress = string.Empty;
95 private string orgAddress2 = string.Empty;
96 private string orgPostalCode = string.Empty;
97 private string orgArea = string.Empty;
98 private string orgCity = string.Empty;
99 private string orgRegion = string.Empty;
100 private string orgCountry = string.Empty;
101 private AlternativeField[] altFields = null;
102 private AlternativeField[] passwordHashes = null;
103 private DateTime checkApprovedExpiry = DateTime.MinValue;
104 private DateTime? birthDate = null;
105
110 {
111 }
112
116 public static LegalIdentityConfiguration Instance => instance;
117
121 [DefaultValue(false)]
123 {
124 get => this.useLegalIdentity;
125 set => this.useLegalIdentity = value;
126 }
127
131 [DefaultValueStringEmpty]
132 public string FirstName
133 {
134 get => this.firstName;
135 set => this.firstName = value;
136 }
137
141 [DefaultValueStringEmpty]
142 public string MiddleName
143 {
144 get => this.middleName;
145 set => this.middleName = value;
146 }
147
151 [DefaultValueStringEmpty]
152 public string LastName
153 {
154 get => this.lastName;
155 set => this.lastName = value;
156 }
157
161 [DefaultValueStringEmpty]
162 public string PersonalNumber
163 {
164 get => this.personalNumber;
165 set => this.personalNumber = value;
166 }
167
171 [DefaultValueStringEmpty]
172 public string Address
173 {
174 get => this.address;
175 set => this.address = value;
176 }
177
181 [DefaultValueStringEmpty]
182 public string Address2
183 {
184 get => this.address2;
185 set => this.address2 = value;
186 }
187
191 [DefaultValueStringEmpty]
192 public string PostalCode
193 {
194 get => this.postalCode;
195 set => this.postalCode = value;
196 }
197
201 [DefaultValueStringEmpty]
202 public string Area
203 {
204 get => this.area;
205 set => this.area = value;
206 }
207
211 [DefaultValueStringEmpty]
212 public string City
213 {
214 get => this.city;
215 set => this.city = value;
216 }
217
221 [DefaultValueStringEmpty]
222 public string Region
223 {
224 get => this.region;
225 set => this.region = value;
226 }
227
231 [DefaultValueStringEmpty]
232 public string Country
233 {
234 get => this.country;
235 set => this.country = value;
236 }
237
241 [DefaultValueStringEmpty]
242 public string Nationality
243 {
244 get => this.nationality;
245 set => this.nationality = value;
246 }
247
251 [DefaultValueStringEmpty]
252 public string Gender
253 {
254 get => this.gender;
255 set => this.gender = value;
256 }
257
261 [DefaultValueNull]
262 public DateTime? BirthDate
263 {
264 get => this.birthDate;
265 set => this.birthDate = value;
266 }
267
271 [DefaultValueStringEmpty]
272 public string OrgName
273 {
274 get => this.orgName;
275 set => this.orgName = value;
276 }
277
281 [DefaultValueStringEmpty]
282 public string OrgDepartment
283 {
284 get => this.orgDepartment;
285 set => this.orgDepartment = value;
286 }
287
291 [DefaultValueStringEmpty]
292 public string OrgRole
293 {
294 get => this.orgRole;
295 set => this.orgRole = value;
296 }
297
301 [DefaultValueStringEmpty]
302 public string OrgNumber
303 {
304 get => this.orgNumber;
305 set => this.orgNumber = value;
306 }
307
311 [DefaultValueStringEmpty]
312 public string OrgAddress
313 {
314 get => this.orgAddress;
315 set => this.orgAddress = value;
316 }
317
321 [DefaultValueStringEmpty]
322 public string OrgAddress2
323 {
324 get => this.orgAddress2;
325 set => this.orgAddress2 = value;
326 }
327
331 [DefaultValueStringEmpty]
332 public string OrgPostalCode
333 {
334 get => this.orgPostalCode;
335 set => this.orgPostalCode = value;
336 }
337
341 [DefaultValueStringEmpty]
342 public string OrgArea
343 {
344 get => this.orgArea;
345 set => this.orgArea = value;
346 }
347
351 [DefaultValueStringEmpty]
352 public string OrgCity
353 {
354 get => this.orgCity;
355 set => this.orgCity = value;
356 }
357
361 [DefaultValueStringEmpty]
362 public string OrgRegion
363 {
364 get => this.orgRegion;
365 set => this.orgRegion = value;
366 }
367
371 [DefaultValueStringEmpty]
372 public string OrgCountry
373 {
374 get => this.orgCountry;
375 set => this.orgCountry = value;
376 }
377
381 [DefaultValueNull]
383 {
384 get => this.altFields;
385 set => this.altFields = value;
386 }
387
391 [DefaultValue(false)]
393 {
394 get => this.protectWithPassword;
395 set
396 {
397 if (this.protectWithPassword != value)
398 {
399 if (this.protectWithPassword)
400 Assert.CallFromSource(approvedSources);
401
402 this.protectWithPassword = value;
403 }
404 }
405 }
406
410 [DefaultValueNull]
412 {
413 get
414 {
415 if (!(this.passwordHashes is null))
416 Assert.CallFromSource(approvedSources);
417
418 return this.passwordHashes;
419 }
420
421 set
422 {
423 if (!(this.passwordHashes is null))
424 Assert.CallFromSource(approvedSources);
425
426 this.passwordHashes = value;
427 }
428 }
429
433 public override string Resource => "/Settings/LegalIdentity.md";
434
438 public override int Priority => 320;
439
444 public override void SetStaticInstance(ISystemConfiguration Configuration)
445 {
446 instance = Configuration as LegalIdentityConfiguration;
447 }
448
454 public override Task<string> Title(Language Language)
455 {
456 return Language.GetStringAsync(typeof(Gateway), 10, "Legal Identity");
457 }
458
462 public override async Task ConfigureSystem()
463 {
464 if (this.useLegalIdentity && !(Gateway.ContractsClient is null))
465 await this.AddHandlers();
466 }
467
468 private async Task AddHandlers()
469 {
470 if (!this.handlersAdded || Gateway.ContractsClient != this.prevClient)
471 {
472 this.handlersAdded = true;
473 this.prevClient = Gateway.ContractsClient;
474
475 Gateway.XmppClient.OnStateChanged += this.XmppClient_OnStateChanged;
476
477 Gateway.ContractsClient.ContractDeleted += this.ContractsClient_ContractDeleted;
478 Gateway.ContractsClient.ContractSigned += this.ContractsClient_ContractSigned;
479 Gateway.ContractsClient.ContractUpdated += this.ContractsClient_ContractUpdated;
480 Gateway.ContractsClient.IdentityUpdated += this.ContractsClient_IdentityUpdated;
481 Gateway.ContractsClient.PetitionedIdentityResponseReceived += this.ContractsClient_PetitionedIdentityResponseReceived;
482 Gateway.ContractsClient.PetitionedContractResponseReceived += this.ContractsClient_PetitionedContractResponseReceived;
483
484 Gateway.ContractsClient.SetAllowedSources(approvedContractClientSources);
485
486 if (Gateway.XmppClient.State == XmppState.Connected)
487 await this.GetLegalIdentities();
488 }
489 }
490
491 private bool handlersAdded = false;
492 private ContractsClient prevClient = null;
493
494 private async Task XmppClient_OnStateChanged(object Sender, XmppState NewState)
495 {
496 if (NewState == XmppState.Connected)
497 await this.GetLegalIdentities();
498 }
499
500 private Task GetLegalIdentities()
501 {
502 if (Gateway.ContractsClient is null)
503 return Task.CompletedTask;
504
505 return Gateway.ContractsClient.GetLegalIdentities((Sender, e) =>
506 {
507 if (e.Ok)
508 {
509 approvedIdentities = this.SetLegalIdentities(e.Identities, null, false);
510 allIdentities = this.SetLegalIdentities(e.Identities, null, true);
511 }
512
513 return Task.CompletedTask;
514
515 }, null);
516 }
517
518 private LegalIdentity[] SetLegalIdentities(LegalIdentity[] Identities, LegalIdentity Changed, bool All)
519 {
520 List<LegalIdentity> Result = new List<LegalIdentity>();
521 LegalIdentity ID2;
522 bool Added = false;
523
524 if (!(Identities is null))
525 {
526 foreach (LegalIdentity ID in Identities)
527 {
528 if (Changed is null || ID.Id != Changed.Id)
529 ID2 = ID;
530 else
531 {
532 ID2 = Changed;
533 Added = true;
534 }
535
536 if (All || ID2.State == IdentityState.Approved)
537 Result.Add(ID2);
538 }
539 }
540
541 if (!Added && !(Changed is null) && (All || Changed.State == IdentityState.Approved))
542 Result.Add(Changed);
543
544 Result.Sort((i1, i2) => Math.Sign((i2.Created - i1.Created).Ticks));
545
546 return Result.ToArray();
547 }
548
553 {
554 get
555 {
556 Assert.CallFromSource(approvedSources);
557 return allIdentities;
558 }
559 }
560
564 public static Dictionary<string, object>[] AllIdentitiesJSON
565 {
566 get
567 {
568 List<Dictionary<string, object>> Result = new List<Dictionary<string, object>>();
569
570 if (!(allIdentities is null))
571 {
572 foreach (LegalIdentity ID in allIdentities)
573 {
574 Dictionary<string, object> ID2 = new Dictionary<string, object>()
575 {
576 { "Id", ID.Id },
577 { "Created", ID.Created },
578 { "Properties", ID.Properties },
579 { "Attachments", ID.Attachments },
580 { "From", ID.From },
581 { "To", ID.To },
582 { "State", ID.State },
583 { "ADDR", string.Empty },
584 { "ADDR2", string.Empty },
585 { "ZIP", string.Empty },
586 { "AREA", string.Empty },
587 { "CITY", string.Empty },
588 { "REGION", string.Empty },
589 { "COUNTRY", string.Empty },
590 { "NATIONALITY", string.Empty },
591 { "GENDER", string.Empty },
592 { "BDAY", string.Empty },
593 { "BMONTH", string.Empty },
594 { "BYEAR", string.Empty },
595 { "FIRST", string.Empty },
596 { "MIDDLE", string.Empty },
597 { "LAST", string.Empty },
598 { "PNR", string.Empty },
599 { "ORGADDR", string.Empty },
600 { "ORGADDR2", string.Empty },
601 { "ORGZIP", string.Empty },
602 { "ORGAREA", string.Empty },
603 { "ORGCITY", string.Empty },
604 { "ORGREGION", string.Empty },
605 { "ORGCOUNTRY", string.Empty },
606 { "ORGNAME", string.Empty },
607 { "ORGDEPT", string.Empty },
608 { "ORGROLE", string.Empty },
609 { "ORGNR", string.Empty },
610 { "", string.Empty }
611 };
612
613 foreach (Property P in ID.Properties)
614 ID2[P.Name] = P.Value;
615
616 Result.Add(ID2);
617 }
618 }
619
620 return Result.ToArray();
621 }
622 }
623
628 {
629 get
630 {
631 Assert.CallFromSource(approvedSources);
632 return approvedIdentities;
633 }
634 }
635
641 public static bool IsMe(CaseInsensitiveString LegalId)
642 {
643 return TryGetMyIdentity(LegalId, out _);
644 }
645
652 public static bool TryGetMyIdentity(CaseInsensitiveString LegalId, out LegalIdentity Identity)
653 {
654 Identity = null;
655
656 if (allIdentities is null)
657 return false;
658
659 foreach (LegalIdentity ID in allIdentities)
660 {
661 if (LegalId == ID.Id)
662 {
663 Identity = ID;
664 return true;
665 }
666 }
667
668 return false;
669 }
670
676 public static bool IsMeApproved(CaseInsensitiveString LegalId)
677 {
678 if (approvedIdentities is null)
679 return false;
680
681 foreach (LegalIdentity ID in approvedIdentities)
682 {
683 if (LegalId == ID.Id)
684 return true;
685 }
686
687 return false;
688 }
689
690 private async Task ContractsClient_IdentityUpdated(object Sender, LegalIdentityEventArgs e)
691 {
692 LegalIdentity ID = e.Identity;
693
694 List<KeyValuePair<string, object>> Tags = new List<KeyValuePair<string, object>>()
695 {
696 new KeyValuePair<string, object>("State", ID.State),
697 new KeyValuePair<string, object>("Provider", ID.Provider),
698 new KeyValuePair<string, object>("Created", ID.Created),
699 new KeyValuePair<string, object>("Updated", ID.Updated),
700 new KeyValuePair<string, object>("From", ID.From),
701 new KeyValuePair<string, object>("KeyAlgorithm", ID.ClientKeyName),
702 new KeyValuePair<string, object>("PublicKey", Convert.ToBase64String(ID.ClientPubKey))
703 };
704
705 foreach (Property P in ID.Properties)
706 Tags.Add(new KeyValuePair<string, object>(P.Name, P.Value));
707
708 Log.Notice("Legal Identity updated.", e.Identity.Id, Tags.ToArray());
709
710 await this.UpdateClients(ID);
711 }
712
713 private Task UpdateClients(LegalIdentity ID)
714 {
715 allIdentities = this.SetLegalIdentities(allIdentities, ID, true);
716 approvedIdentities = this.SetLegalIdentities(approvedIdentities, ID, false);
717
718 return this.UpdateClients();
719 }
720
721 private async Task UpdateClients()
722 {
723 string[] TabIDs;
724
726 TabIDs = ClientEvents.GetTabIDs();
727 else
728 TabIDs = ClientEvents.GetTabIDsForLocation("/Settings/LegalIdentity.md");
729
730 if (TabIDs.Length > 0)
731 {
732 string FileName = Path.Combine(Gateway.RootFolder, "Settings", "LegalIdentities.md");
733 if (File.Exists(FileName))
734 {
735 string Markdown = await Resources.ReadAllTextAsync(FileName);
737 v["Config"] = this;
738
740 string HTML = await Doc.GenerateHTML();
741 HTML = HtmlDocument.GetBody(HTML);
742
743 await ClientEvents.PushEvent(TabIDs, "UpdateIdentityTable", HTML);
744 }
745 }
746 }
747
748 private Task ContractsClient_ContractSigned(object Sender, ContractSignedEventArgs e)
749 {
750 Log.Notice("Smart contract signed.", e.ContractId, e.LegalId, new KeyValuePair<string, object>("Role", e.Role));
751 return Task.CompletedTask;
752 }
753
754 private Task ContractsClient_ContractUpdated(object Sender, ContractReferenceEventArgs e)
755 {
756 Log.Notice("Smart contract updated.", e.ContractId);
757 return Task.CompletedTask;
758 }
759
760 private Task ContractsClient_ContractDeleted(object Sender, ContractReferenceEventArgs e)
761 {
762 Log.Notice("Smart contract deleted.", e.ContractId);
763 return Task.CompletedTask;
764 }
765
770 public override Task InitSetup(HttpServer WebServer)
771 {
772 this.applyLegalIdentity = WebServer.Register("/Settings/ApplyLegalIdentity", null, this.ApplyLegalIdentity, true, false, true);
773 this.contractAction = WebServer.Register("/Settings/ContractAction", null, this.ContractAction, true, false, true);
774
775 this.checkApprovedExpiry = Gateway.ScheduleEvent(this.CheckApprovedExpiry, DateTime.Now.AddMinutes(5), true);
776
777 return base.InitSetup(WebServer);
778 }
779
784 public override Task UnregisterSetup(HttpServer WebServer)
785 {
786 WebServer.Unregister(this.applyLegalIdentity);
787 WebServer.Unregister(this.contractAction);
788
789 Gateway.CancelScheduledEvent(this.checkApprovedExpiry);
790 this.checkApprovedExpiry = DateTime.MinValue;
791
792 return base.UnregisterSetup(WebServer);
793 }
794
795 private async Task CheckApprovedExpiry(object State)
796 {
797 if (!(State is bool Reschedule))
798 Reschedule = false;
799
800 DateTime Now = DateTime.Now;
801 DateTime Today = Now.Date;
802
803 if (Reschedule)
804 this.checkApprovedExpiry = Gateway.ScheduleEvent(this.CheckApprovedExpiry, Today.AddDays(1).AddMinutes(5), true);
805
806 if (!this.useLegalIdentity)
807 return;
808
809 if (Gateway.XmppClient.State != XmppState.Connected)
810 {
811 Gateway.ScheduleEvent(this.CheckApprovedExpiry, Now.AddMinutes(5), false);
812 return;
813 }
814
815 DateTime Expires = LatestApprovedLegalIdentityExpires;
816 if (Expires < Now)
817 {
818 await Gateway.SendNotification("No approved Legal Identity registered for the gateway.", string.Empty);
819 return;
820 }
821
822 int Days = (int)(Expires - Today).TotalDays;
823
824 if (Days < 60)
825 {
826 switch (Days)
827 {
828 case 0:
829 await Gateway.SendNotification("The approved Legal Identity for the gateway **expires today**.", string.Empty);
830 return;
831
832 case 1:
833 await Gateway.SendNotification("The approved Legal Identity for the gateway **expires tomorrow**.", string.Empty);
834 return;
835
836 default:
837 await Gateway.SendNotification("The approved Legal Identity for the gateway **expires in " + Days.ToString() + " days**.", string.Empty);
838 return;
839 }
840 }
841 }
842
848 public override async Task<bool> SetupConfiguration(HttpServer WebServer)
849 {
850 if (!this.Complete &&
851 Gateway.XmppClient.State == XmppState.Offline &&
852 !(Gateway.XmppClient is null))
853 {
854 await Gateway.XmppClient.Connect();
855 }
856
857 await this.AddHandlers();
858
859 return await base.SetupConfiguration(WebServer);
860 }
861
865 protected override string ConfigPrivilege => "Admin.Legal.ID";
866
867 private async Task ApplyLegalIdentity(HttpRequest Request, HttpResponse Response)
868 {
869 Gateway.AssertUserAuthenticated(Request, this.ConfigPrivilege);
870
871 if (!Request.HasData)
872 throw new BadRequestException();
873
874 object Obj = await Request.DecodeDataAsync();
875 if (!(Obj is Dictionary<string, object> Parameters))
876 throw new BadRequestException();
877
878 if (!Parameters.TryGetValue("protectWithPassword", out Obj) || !(Obj is bool ProtectWithPassword) ||
879 !Parameters.TryGetValue("password", out Obj) || !(Obj is string Password) ||
880 !Parameters.TryGetValue("password2", out Obj) || !(Obj is string Password2) ||
881 !Parameters.TryGetValue("firstName", out Obj) || !(Obj is string FirstName) ||
882 !Parameters.TryGetValue("middleName", out Obj) || !(Obj is string MiddleName) ||
883 !Parameters.TryGetValue("lastName", out Obj) || !(Obj is string LastName) ||
884 !Parameters.TryGetValue("pNr", out Obj) || !(Obj is string PNr) ||
885 !Parameters.TryGetValue("address", out Obj) || !(Obj is string Address) ||
886 !Parameters.TryGetValue("address2", out Obj) || !(Obj is string Address2) ||
887 !Parameters.TryGetValue("postalCode", out Obj) || !(Obj is string PostalCode) ||
888 !Parameters.TryGetValue("area", out Obj) || !(Obj is string Area) ||
889 !Parameters.TryGetValue("city", out Obj) || !(Obj is string City) ||
890 !Parameters.TryGetValue("region", out Obj) || !(Obj is string Region) ||
891 !Parameters.TryGetValue("country", out Obj) || !(Obj is string Country) ||
892 !Parameters.TryGetValue("nationality", out Obj) || !(Obj is string Nationality) ||
893 !Parameters.TryGetValue("gender", out Obj) || !(Obj is string Gender) ||
894 !Parameters.TryGetValue("birthDate", out Obj) || !(Obj is string BirthDateStr) ||
895 !Parameters.TryGetValue("orgName", out Obj) || !(Obj is string OrgName) ||
896 !Parameters.TryGetValue("orgDepartment", out Obj) || !(Obj is string OrgDepartment) ||
897 !Parameters.TryGetValue("orgRole", out Obj) || !(Obj is string OrgRole) ||
898 !Parameters.TryGetValue("orgNr", out Obj) || !(Obj is string OrgNr) ||
899 !Parameters.TryGetValue("orgAddress", out Obj) || !(Obj is string OrgAddress) ||
900 !Parameters.TryGetValue("orgAddress2", out Obj) || !(Obj is string OrgAddress2) ||
901 !Parameters.TryGetValue("orgPostalCode", out Obj) || !(Obj is string OrgPostalCode) ||
902 !Parameters.TryGetValue("orgArea", out Obj) || !(Obj is string OrgArea) ||
903 !Parameters.TryGetValue("orgCity", out Obj) || !(Obj is string OrgCity) ||
904 !Parameters.TryGetValue("orgRegion", out Obj) || !(Obj is string OrgRegion) ||
905 !Parameters.TryGetValue("orgCountry", out Obj) || !(Obj is string OrgCountry))
906 {
907 throw new BadRequestException();
908 }
909
911 {
912 if (string.IsNullOrEmpty(Password))
913 throw new BadRequestException("Enter a password and try again.");
914
915 if (Password != Password2)
916 throw new BadRequestException("Passwords do not match. Retype, and try again.");
917 }
918
919 List<AlternativeField> AlternativeFields = new List<AlternativeField>();
920
921 if (Parameters.TryGetValue("alternative", out Obj) && Obj is Dictionary<string, object> Alternative)
922 {
923 foreach (KeyValuePair<string, object> P in Alternative)
924 {
925 switch (P.Key.ToUpper())
926 {
927 case "FIRST":
928 case "MIDDLE":
929 case "LAST":
930 case "PNR":
931 case "ADDR":
932 case "ADDR2":
933 case "ZIP":
934 case "AREA":
935 case "CITY":
936 case "REGION":
937 case "COUNTRY":
938 case "NATIONALITY":
939 case "GENDER":
940 case "BDAY":
941 case "BMONTH":
942 case "BYEAR":
943 case "ORGNAME":
944 case "ORGDEPT":
945 case "ORGROLE":
946 case "ORGNR":
947 case "ORGADDR":
948 case "ORGADDR2":
949 case "ORGZIP":
950 case "ORGAREA":
951 case "ORGCITY":
952 case "ORGREGION":
953 case "ORGCOUNTRY":
954 throw new BadRequestException("The following alternative field name is not allowed: " + P.Key);
955
956 default:
957 AlternativeFields.Add(new AlternativeField(P.Key, P.Value.ToString()));
958 break;
959 }
960 }
961 }
962
963 string TabID = Request.Header["X-TabID"];
964 if (string.IsNullOrEmpty(TabID))
965 throw new BadRequestException();
966
967 if (!string.IsNullOrEmpty(BirthDateStr))
968 {
969 if (!DateTime.TryParse(BirthDateStr, out DateTime BirthDate))
970 throw new BadRequestException("Invalid birth date.");
971
972 this.birthDate = BirthDate;
973 }
974 else
975 this.birthDate = null;
976
977 this.useLegalIdentity = true;
978 this.firstName = FirstName;
979 this.middleName = MiddleName;
980 this.lastName = LastName;
981 this.personalNumber = PNr;
982 this.address = Address;
983 this.address2 = Address2;
984 this.postalCode = PostalCode;
985 this.area = Area;
986 this.city = City;
987 this.region = Region;
988 this.country = Country;
989 this.nationality = Nationality;
990 this.gender = Gender;
991 this.orgName = OrgName;
992 this.orgDepartment = OrgDepartment;
993 this.orgRole = OrgRole;
994 this.orgNumber = OrgNr;
995 this.orgAddress = OrgAddress;
996 this.orgAddress2 = OrgAddress2;
997 this.orgPostalCode = OrgPostalCode;
998 this.orgArea = OrgArea;
999 this.orgCity = OrgCity;
1000 this.orgRegion = OrgRegion;
1001 this.orgCountry = OrgCountry;
1002 this.altFields = AlternativeFields.ToArray();
1003
1004 await Database.Update(this);
1005
1006 Response.StatusCode = 200;
1007
1008 await this.ApplyId(Password, TabID, ProtectWithPassword, null);
1009 }
1010
1011 private async Task ApplyId(string Password, string TabID, bool ProtectWithPassword, TaskCompletionSource<bool> Response)
1012 {
1014 await Gateway.ContractsClient.Apply(this.GetProperties(), this.ApplyResponse,
1015 new object[] { Password, TabID, ProtectWithPassword, Response });
1016 }
1017
1018 private async Task ApplyResponse(object Sender, LegalIdentityEventArgs e)
1019 {
1020 object[] P = (object[])e.State;
1021 string Password = (string)P[0];
1022 string TabID = (string)P[1];
1023 bool ProtectWithPassword = (bool)P[2];
1024 TaskCompletionSource<bool> Response = (TaskCompletionSource<bool>)P[3];
1025
1026 if (e.Ok)
1027 {
1028 this.protectWithPassword = ProtectWithPassword;
1029
1031 {
1032 Dictionary<string, AlternativeField> ById = new Dictionary<string, AlternativeField>();
1033
1034 if (!(this.passwordHashes is null))
1035 {
1036 foreach (AlternativeField H in this.passwordHashes)
1037 ById[H.Key] = H;
1038 }
1039
1040 ById[e.Identity.Id] = new AlternativeField(e.Identity.Id, this.CalcPasswordHash(e.Identity, Password));
1041
1042 AlternativeField[] Hashes = new AlternativeField[ById.Count];
1043 ById.Values.CopyTo(Hashes, 0);
1044
1045 this.passwordHashes = Hashes;
1046 }
1047
1048 this.Step = 1;
1049 await Database.Update(this);
1050
1051 if (!string.IsNullOrEmpty(TabID))
1052 await ClientEvents.PushEvent(new string[] { TabID }, "ApplicationOK", string.Empty);
1053
1054 await this.UpdateClients(e.Identity);
1055
1056 Response?.TrySetResult(true);
1057 }
1058 else
1059 {
1060 if (!string.IsNullOrEmpty(TabID))
1061 await ClientEvents.PushEvent(new string[] { TabID }, "ApplicationError", e.ErrorText);
1062
1063 Response?.TrySetResult(false);
1064 }
1065 }
1066
1067 private string CalcPasswordHash(LegalIdentity ID, string Password)
1068 {
1069 StringBuilder sb = new StringBuilder();
1070 SortedDictionary<string, string> Sorted = new SortedDictionary<string, string>();
1071
1072 foreach (Property P in ID.Properties)
1073 {
1074 if (Sorted.TryGetValue(P.Name, out string s))
1075 {
1076 s += ";" + P.Value;
1077 Sorted[P.Name] = s;
1078 }
1079 else
1080 Sorted[P.Name] = P.Value;
1081 }
1082
1083 bool First = true;
1084
1085 foreach (KeyValuePair<string, string> P in Sorted)
1086 {
1087 if (First)
1088 First = false;
1089 else
1090 sb.Append(',');
1091
1092 sb.Append(P.Key);
1093 sb.Append('=');
1094 sb.Append(P.Value);
1095 }
1096
1097 byte[] Digest = Hashes.ComputeHMACSHA256Hash(System.Text.Encoding.UTF8.GetBytes(Password), System.Text.Encoding.UTF8.GetBytes(sb.ToString()));
1098
1099 return Convert.ToBase64String(Digest);
1100 }
1101
1102 private Property[] GetProperties()
1103 {
1104 List<Property> Properties = new List<Property>();
1105
1106 if (!string.IsNullOrEmpty(this.firstName))
1107 Properties.Add(new Property("FIRST", this.firstName));
1108
1109 if (!string.IsNullOrEmpty(this.middleName))
1110 Properties.Add(new Property("MIDDLE", this.middleName));
1111
1112 if (!string.IsNullOrEmpty(this.lastName))
1113 Properties.Add(new Property("LAST", this.lastName));
1114
1115 if (!string.IsNullOrEmpty(this.personalNumber))
1116 Properties.Add(new Property("PNR", this.personalNumber));
1117
1118 if (!string.IsNullOrEmpty(this.address))
1119 Properties.Add(new Property("ADDR", this.address));
1120
1121 if (!string.IsNullOrEmpty(this.address2))
1122 Properties.Add(new Property("ADDR2", this.address2));
1123
1124 if (!string.IsNullOrEmpty(this.postalCode))
1125 Properties.Add(new Property("ZIP", this.postalCode));
1126
1127 if (!string.IsNullOrEmpty(this.area))
1128 Properties.Add(new Property("AREA", this.area));
1129
1130 if (!string.IsNullOrEmpty(this.city))
1131 Properties.Add(new Property("CITY", this.city));
1132
1133 if (!string.IsNullOrEmpty(this.region))
1134 Properties.Add(new Property("REGION", this.region));
1135
1136 if (!string.IsNullOrEmpty(this.country))
1137 Properties.Add(new Property("COUNTRY", this.country));
1138
1139 if (!string.IsNullOrEmpty(this.nationality))
1140 Properties.Add(new Property("NATIONALITY", this.nationality));
1141
1142 if (!string.IsNullOrEmpty(this.gender))
1143 Properties.Add(new Property("GENDER", this.gender));
1144
1145 if (!(this.birthDate is null))
1146 {
1147 Properties.Add(new Property("BDAY", this.birthDate.Value.Day.ToString()));
1148 Properties.Add(new Property("BMONTH", this.birthDate.Value.Month.ToString()));
1149 Properties.Add(new Property("BYEAR", this.birthDate.Value.Year.ToString()));
1150 }
1151
1152 if (!string.IsNullOrEmpty(this.orgName))
1153 Properties.Add(new Property("ORGNAME", this.orgName));
1154
1155 if (!string.IsNullOrEmpty(this.orgDepartment))
1156 Properties.Add(new Property("ORGDEPT", this.orgDepartment));
1157
1158 if (!string.IsNullOrEmpty(this.orgRole))
1159 Properties.Add(new Property("ORGROLE", this.orgRole));
1160
1161 if (!string.IsNullOrEmpty(this.orgNumber))
1162 Properties.Add(new Property("ORGNR", this.orgNumber));
1163
1164 if (!string.IsNullOrEmpty(this.orgAddress))
1165 Properties.Add(new Property("ORGADDR", this.orgAddress));
1166
1167 if (!string.IsNullOrEmpty(this.orgAddress2))
1168 Properties.Add(new Property("ORGADDR2", this.orgAddress2));
1169
1170 if (!string.IsNullOrEmpty(this.orgPostalCode))
1171 Properties.Add(new Property("ORGZIP", this.orgPostalCode));
1172
1173 if (!string.IsNullOrEmpty(this.orgArea))
1174 Properties.Add(new Property("ORGAREA", this.orgArea));
1175
1176 if (!string.IsNullOrEmpty(this.orgCity))
1177 Properties.Add(new Property("ORGCITY", this.orgCity));
1178
1179 if (!string.IsNullOrEmpty(this.orgRegion))
1180 Properties.Add(new Property("ORGREGION", this.orgRegion));
1181
1182 if (!string.IsNullOrEmpty(this.orgCountry))
1183 Properties.Add(new Property("ORGCOUNTRY", this.orgCountry));
1184
1185 if (!(this.altFields is null))
1186 {
1187 foreach (AlternativeField F in this.altFields)
1188 Properties.Add(new Property(F.Key, F.Value));
1189 }
1190
1191 return Properties.ToArray();
1192 }
1193
1194 private async Task ContractAction(HttpRequest Request, HttpResponse Response)
1195 {
1196 Gateway.AssertUserAuthenticated(Request, this.ConfigPrivilege);
1197
1198 if (!Request.HasData)
1199 throw new BadRequestException("No content.");
1200
1201 string Password;
1202 object Obj = await Request.DecodeDataAsync();
1203 if (!(Obj is Dictionary<string, object> Parameters))
1204 throw new UnsupportedMediaTypeException("Invalid content.");
1205
1206 if (!Parameters.TryGetValue("requestId", out Obj) || !(Obj is string RequestId) ||
1207 !Parameters.TryGetValue("sign", out Obj) || !(Obj is bool Sign) ||
1208 !Parameters.TryGetValue("protect", out Obj) || !(Obj is bool Protect))
1209 {
1210 throw new BadRequestException("Invalid request.");
1211 }
1212
1213 if (Protect)
1214 {
1215 if (!Parameters.TryGetValue("password", out Obj) || !(Obj is string s))
1216 throw new BadRequestException("No password.");
1217
1218 Password = s;
1219 }
1220 else
1221 Password = string.Empty;
1222
1223 ContractSignatureRequest SignatureRequest = await Database.TryLoadObject<ContractSignatureRequest>(RequestId) ?? throw new NotFoundException("Content Signature Request not found.");
1224 if (SignatureRequest.Signed.HasValue)
1225 throw new BadRequestException("Contract has already been signed.");
1226
1227 if (Protect)
1228 {
1230 throw new BadRequestException("No approved legal identity found with which to sign the contract.");
1231
1232 string Id = this.GetPasswordLegalId(Password);
1233 if (string.IsNullOrEmpty(Id))
1234 throw new BadRequestException("Invalid password.");
1235 }
1236 else if (this.protectWithPassword)
1237 throw new BadRequestException("Legal identities protected with password.");
1238
1239 if (Sign)
1240 {
1241 Contract Contract = await SignatureRequest.GetContract();
1242 Contract = await Gateway.ContractsClient.SignContractAsync(Contract, SignatureRequest.Role, false);
1243 SignatureRequest.SetContract(Contract);
1244 SignatureRequest.Signed = DateTime.Now;
1245 await Database.Update(SignatureRequest);
1246 }
1247 else
1248 await Database.Delete(SignatureRequest);
1249
1250 Response.StatusCode = 200;
1251 Response.ContentType = JsonCodec.DefaultContentType;
1252 await Response.Write(JSON.Encode(Sign, false));
1253 await Response.SendResponse();
1254 }
1255
1260 {
1261 get => !(approvedIdentities is null) && approvedIdentities.Length > 0;
1262 }
1263
1268 {
1269 get
1270 {
1272 throw new NotFoundException("Gateway has no approved legal identity.");
1273
1274 LegalIdentity Latest = null;
1275
1276 foreach (LegalIdentity Identity in approvedIdentities)
1277 {
1278 if (Latest is null || Identity.Created > Latest.Created)
1279 Latest = Identity;
1280 }
1281
1282 return Latest;
1283 }
1284 }
1285
1290 {
1291 get
1292 {
1294 }
1295 }
1296
1301 {
1302 get
1303 {
1305 return DateTime.MinValue;
1306
1307 return LatestApprovedLegalIdentity?.To ?? DateTime.MinValue;
1308 }
1309 }
1310
1316 public string GetPasswordLegalId(string Password)
1317 {
1318 if (approvedIdentities is null || approvedIdentities.Length == 0)
1319 return null;
1320
1321 foreach (LegalIdentity ID in approvedIdentities)
1322 {
1323 string H = this.CalcPasswordHash(ID, Password);
1324
1325 foreach (AlternativeField F in this.passwordHashes)
1326 {
1327 if (F.Key == ID.Id)
1328 {
1329 if (F.Value == H)
1330 return F.Key;
1331
1332 break;
1333 }
1334 }
1335 }
1336
1337 return null;
1338 }
1339
1349 public Task<bool> PetitionLegalIdentity(string LegalId, string PetitionId, string Purpose,
1350 EventHandlerAsync<LegalIdentityPetitionResponseEventArgs> Callback, TimeSpan Timeout)
1351 {
1352 if (this.protectWithPassword)
1353 throw new ForbiddenException("Petitioning legal identities is protected using passwords on this machine.");
1354
1355 return this.PetitionLegalIdentity(LegalId, PetitionId, Purpose, string.Empty, Callback, Timeout);
1356 }
1357
1368 public async Task<bool> PetitionLegalIdentity(string LegalId, string PetitionId, string Purpose, string Password,
1369 EventHandlerAsync<LegalIdentityPetitionResponseEventArgs> Callback, TimeSpan Timeout)
1370 {
1372 return false;
1373
1374 if (this.protectWithPassword)
1375 {
1376 string Id = this.GetPasswordLegalId(Password);
1377 if (string.IsNullOrEmpty(Id))
1378 return false;
1379 }
1380
1381 lock (this.identityPetitionCallbackMethods)
1382 {
1383 if (this.identityPetitionCallbackMethods.ContainsKey(PetitionId))
1384 throw new ArgumentException("Petition ID already used.", nameof(PetitionId));
1385
1386 this.identityPetitionCallbackMethods[PetitionId] = Callback;
1387 }
1388
1389 try
1390 {
1391 await Gateway.ContractsClient.PetitionIdentityAsync(LegalId, PetitionId, Purpose);
1392
1393 Gateway.ScheduleEvent((P) =>
1394 {
1395 LegalIdentityPetitionResponseEventArgs e = new LegalIdentityPetitionResponseEventArgs(null, null, (string)P, false, string.Empty, null);
1396 this.ContractsClient_PetitionedIdentityResponseReceived(Gateway.ContractsClient, e);
1397 }, DateTime.Now.Add(Timeout), PetitionId);
1398 }
1399 catch (Exception ex)
1400 {
1401 lock (this.identityPetitionCallbackMethods)
1402 {
1403 this.identityPetitionCallbackMethods.Remove(PetitionId);
1404 }
1405
1406 ExceptionDispatchInfo.Capture(ex).Throw();
1407 }
1408
1409 return true;
1410 }
1411
1421 public Task<bool> PetitionContract(string ContractId, string PetitionId, string Purpose,
1422 EventHandlerAsync<ContractPetitionResponseEventArgs> Callback, TimeSpan Timeout)
1423 {
1424 if (this.protectWithPassword)
1425 throw new ForbiddenException("Petitioning legal identities is protected using passwords on this machine.");
1426
1427 return this.PetitionContract(ContractId, PetitionId, Purpose, string.Empty, Callback, Timeout);
1428 }
1429
1440 public async Task<bool> PetitionContract(string ContractId, string PetitionId, string Purpose, string Password,
1441 EventHandlerAsync<ContractPetitionResponseEventArgs> Callback, TimeSpan Timeout)
1442 {
1444 return false;
1445
1446 if (this.protectWithPassword)
1447 {
1448 string Id = this.GetPasswordLegalId(Password);
1449 if (string.IsNullOrEmpty(Id))
1450 return false;
1451 }
1452
1453 lock (this.contractPetitionCallbackMethods)
1454 {
1455 if (this.contractPetitionCallbackMethods.ContainsKey(PetitionId))
1456 throw new ArgumentException("Petition ID already used.", nameof(PetitionId));
1457
1458 this.contractPetitionCallbackMethods[PetitionId] = Callback;
1459 }
1460
1461 try
1462 {
1463 await Gateway.ContractsClient.PetitionContractAsync(ContractId, PetitionId, Purpose);
1464
1465 Gateway.ScheduleEvent((P) =>
1466 {
1467 ContractPetitionResponseEventArgs e = new ContractPetitionResponseEventArgs(null, null, (string)P, false, string.Empty, null);
1468 this.ContractsClient_PetitionedContractResponseReceived(Gateway.ContractsClient, e);
1469 }, DateTime.Now.Add(Timeout), PetitionId);
1470 }
1471 catch (Exception ex)
1472 {
1473 lock (this.contractPetitionCallbackMethods)
1474 {
1475 this.contractPetitionCallbackMethods.Remove(PetitionId);
1476 }
1477
1478 ExceptionDispatchInfo.Capture(ex).Throw();
1479 }
1480
1481 return true;
1482 }
1483
1484 private readonly Dictionary<string, EventHandlerAsync<LegalIdentityPetitionResponseEventArgs>> identityPetitionCallbackMethods = new Dictionary<string, EventHandlerAsync<LegalIdentityPetitionResponseEventArgs>>();
1485 private readonly Dictionary<string, EventHandlerAsync<ContractPetitionResponseEventArgs>> contractPetitionCallbackMethods = new Dictionary<string, EventHandlerAsync<ContractPetitionResponseEventArgs>>();
1486
1487 private Task ContractsClient_PetitionedIdentityResponseReceived(object Sender, LegalIdentityPetitionResponseEventArgs e)
1488 {
1489 EventHandlerAsync<LegalIdentityPetitionResponseEventArgs> Callback;
1490 string PetitionId = e.PetitionId;
1491
1492 lock (this.identityPetitionCallbackMethods)
1493 {
1494 if (!this.identityPetitionCallbackMethods.TryGetValue(PetitionId, out Callback))
1495 return Task.CompletedTask;
1496 else
1497 this.identityPetitionCallbackMethods.Remove(PetitionId);
1498 }
1499
1500 return Callback.Raise(Sender, e);
1501 }
1502
1503 private Task ContractsClient_PetitionedContractResponseReceived(object Sender, ContractPetitionResponseEventArgs e)
1504 {
1505 EventHandlerAsync<ContractPetitionResponseEventArgs> Callback;
1506 string PetitionId = e.PetitionId;
1507
1508 lock (this.contractPetitionCallbackMethods)
1509 {
1510 if (!this.contractPetitionCallbackMethods.TryGetValue(PetitionId, out Callback))
1511 return Task.CompletedTask;
1512 else
1513 this.contractPetitionCallbackMethods.Remove(PetitionId);
1514 }
1515
1516 return Callback.Raise(Sender, e);
1517 }
1518
1523 public override Task<bool> SimplifiedConfiguration()
1524 {
1525 return Task.FromResult(true);
1526 }
1527
1532 public const string GATEWAY_ID_USE = nameof(GATEWAY_ID_USE);
1533
1537 public const string GATEWAY_ID_FIRST = nameof(GATEWAY_ID_FIRST);
1538
1542 public const string GATEWAY_ID_MIDDLE = nameof(GATEWAY_ID_MIDDLE);
1543
1547 public const string GATEWAY_ID_LAST = nameof(GATEWAY_ID_LAST);
1548
1552 public const string GATEWAY_ID_PNR = nameof(GATEWAY_ID_PNR);
1553
1557 public const string GATEWAY_ID_ADDR = nameof(GATEWAY_ID_ADDR);
1558
1562 public const string GATEWAY_ID_ADDR2 = nameof(GATEWAY_ID_ADDR2);
1563
1567 public const string GATEWAY_ID_ZIP = nameof(GATEWAY_ID_ZIP);
1568
1572 public const string GATEWAY_ID_AREA = nameof(GATEWAY_ID_AREA);
1573
1577 public const string GATEWAY_ID_CITY = nameof(GATEWAY_ID_CITY);
1578
1582 public const string GATEWAY_ID_REGION = nameof(GATEWAY_ID_REGION);
1583
1587 public const string GATEWAY_ID_COUNTRY = nameof(GATEWAY_ID_COUNTRY);
1588
1592 public const string GATEWAY_ID_NATIONALITY = nameof(GATEWAY_ID_NATIONALITY);
1593
1597 public const string GATEWAY_ID_GENDER = nameof(GATEWAY_ID_GENDER);
1598
1602 public const string GATEWAY_ID_BDATE = nameof(GATEWAY_ID_BDATE);
1603
1607 public const string GATEWAY_ID_ORGNAME = nameof(GATEWAY_ID_ORGNAME);
1608
1612 public const string GATEWAY_ID_ORGDEPT = nameof(GATEWAY_ID_ORGDEPT);
1613
1617 public const string GATEWAY_ID_ORGROLE = nameof(GATEWAY_ID_ORGROLE);
1618
1622 public const string GATEWAY_ID_ORGNR = nameof(GATEWAY_ID_ORGNR);
1623
1627 public const string GATEWAY_ID_ORGADDR = nameof(GATEWAY_ID_ORGADDR);
1628
1632 public const string GATEWAY_ID_ORGADDR2 = nameof(GATEWAY_ID_ORGADDR2);
1633
1637 public const string GATEWAY_ID_ORGZIP = nameof(GATEWAY_ID_ORGZIP);
1638
1642 public const string GATEWAY_ID_ORGAREA = nameof(GATEWAY_ID_ORGAREA);
1643
1647 public const string GATEWAY_ID_ORGCITY = nameof(GATEWAY_ID_ORGCITY);
1648
1652 public const string GATEWAY_ID_ORGREGION = nameof(GATEWAY_ID_ORGREGION);
1653
1657 public const string GATEWAY_ID_ORGCOUNTRY = nameof(GATEWAY_ID_ORGCOUNTRY);
1658
1662 public const string GATEWAY_ID_ALT = nameof(GATEWAY_ID_ALT);
1663
1667 public const string GATEWAY_ID_ALT_ = nameof(GATEWAY_ID_ALT_);
1668
1672 public const string GATEWAY_ID_PASSWORD = nameof(GATEWAY_ID_PASSWORD);
1673
1678 public override async Task<bool> EnvironmentConfiguration()
1679 {
1680 if (!this.TryGetEnvironmentVariable(GATEWAY_ID_USE, false, out this.useLegalIdentity))
1681 return false;
1682
1683 if (!this.useLegalIdentity)
1684 return true;
1685
1686 this.firstName = Environment.GetEnvironmentVariable(GATEWAY_ID_FIRST) ?? string.Empty;
1687 this.middleName = Environment.GetEnvironmentVariable(GATEWAY_ID_MIDDLE) ?? string.Empty;
1688 this.lastName = Environment.GetEnvironmentVariable(GATEWAY_ID_LAST) ?? string.Empty;
1689 this.personalNumber = Environment.GetEnvironmentVariable(GATEWAY_ID_PNR) ?? string.Empty;
1690 this.address = Environment.GetEnvironmentVariable(GATEWAY_ID_ADDR) ?? string.Empty;
1691 this.address2 = Environment.GetEnvironmentVariable(GATEWAY_ID_ADDR2) ?? string.Empty;
1692 this.postalCode = Environment.GetEnvironmentVariable(GATEWAY_ID_ZIP) ?? string.Empty;
1693 this.area = Environment.GetEnvironmentVariable(GATEWAY_ID_AREA) ?? string.Empty;
1694 this.city = Environment.GetEnvironmentVariable(GATEWAY_ID_CITY) ?? string.Empty;
1695 this.region = Environment.GetEnvironmentVariable(GATEWAY_ID_REGION) ?? string.Empty;
1696 this.country = Environment.GetEnvironmentVariable(GATEWAY_ID_COUNTRY) ?? string.Empty;
1697 this.nationality = Environment.GetEnvironmentVariable(GATEWAY_ID_NATIONALITY) ?? string.Empty;
1698 this.gender = Environment.GetEnvironmentVariable(GATEWAY_ID_GENDER) ?? string.Empty;
1699 this.orgName = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGNAME) ?? string.Empty;
1700 this.orgDepartment = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGDEPT) ?? string.Empty;
1701 this.orgRole = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGROLE) ?? string.Empty;
1702 this.orgNumber = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGNR) ?? string.Empty;
1703 this.orgAddress = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGADDR) ?? string.Empty;
1704 this.orgAddress2 = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGADDR2) ?? string.Empty;
1705 this.orgPostalCode = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGZIP) ?? string.Empty;
1706 this.orgArea = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGAREA) ?? string.Empty;
1707 this.orgCity = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGCITY) ?? string.Empty;
1708 this.orgRegion = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGREGION) ?? string.Empty;
1709 this.orgCountry = Environment.GetEnvironmentVariable(GATEWAY_ID_ORGCOUNTRY) ?? string.Empty;
1710
1711 if (!this.TryGetEnvironmentVariable(GATEWAY_ID_BDATE, false, out this.birthDate))
1712 return false;
1713
1714 List<AlternativeField> Fields = new List<AlternativeField>();
1715
1716 if (this.TryGetEnvironmentVariable(GATEWAY_ID_ALT,false,out string Value))
1717 {
1718 string[] Parts = Value.Split(',');
1719
1720 foreach (string Part in Parts)
1721 {
1722 string Name = GATEWAY_ID_ALT_ + Part;
1723
1724 if (!this.TryGetEnvironmentVariable(Name, true, out Value))
1725 return false;
1726
1727 Fields.Add(new AlternativeField(Part, Value));
1728 }
1729 }
1730
1731 this.altFields = Fields.ToArray();
1732
1733 Value = Environment.GetEnvironmentVariable(GATEWAY_ID_PASSWORD);
1734
1735 TaskCompletionSource<bool> Result = new TaskCompletionSource<bool>();
1736 try
1737 {
1738 Task _ = Task.Delay(30000).ContinueWith(Prev => Result?.TrySetException(new TimeoutException()));
1739
1740 await this.ApplyId(Value, null, !string.IsNullOrEmpty(Value), Result);
1741
1742 if (await Result.Task)
1743 return true;
1744 else
1745 return false;
1746 }
1747 catch (Exception ex)
1748 {
1749 Log.Exception(ex);
1750 return false;
1751 }
1752 }
1753
1754 }
1755}
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:14
static string Encode(string s)
Encodes a string for inclusion in JSON.
Definition: JSON.cs:507
const string DefaultContentType
application/json
Definition: JsonCodec.cs:19
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 loading of resources stored as embedded resources or in content files.
Definition: Resources.cs:15
static async Task< string > ReadAllTextAsync(string FileName)
Reads a text file asynchronously.
Definition: Resources.cs:205
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1647
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:450
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:126
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:3041
static bool Configuring
If the gateway is being configured.
Definition: Gateway.cs:2403
static Task SendNotification(Graph Graph)
Sends a graph as a notification message to configured notification recipients.
Definition: Gateway.cs:3826
static ContractsClient ContractsClient
XMPP Contracts Client, if such a compoent is available on the XMPP broker.
Definition: Gateway.cs:4375
static Emoji1LocalFiles Emoji1_24x24
Emojis.
Definition: Gateway.cs:2398
static DateTime ScheduleEvent(ScheduledEventCallback Callback, DateTime When, object State)
Schedules a one-time event.
Definition: Gateway.cs:3452
static XmppClient XmppClient
XMPP Client connection of gateway.
Definition: Gateway.cs:3187
static string RootFolder
Web root folder.
Definition: Gateway.cs:2379
static bool CancelScheduledEvent(DateTime When)
Cancels a scheduled event.
Definition: Gateway.cs:3474
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:18
HttpRequestHeader Header
Request header.
Definition: HttpRequest.cs:134
bool HasData
If the request has data.
Definition: HttpRequest.cs:74
async Task< object > DecodeDataAsync()
Decodes data sent in request.
Definition: HttpRequest.cs:95
Base class for all HTTP resources.
Definition: HttpResource.cs:23
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:21
async Task SendResponse()
Sends the response back to the client. If the resource is synchronous, there's no need to call this m...
async Task Write(byte[] Data)
Returns binary data in the response.
Implements an HTTP server.
Definition: HttpServer.cs:36
static Variables CreateVariables()
Creates a new collection of variables, that contains access to the global set of variables.
Definition: HttpServer.cs:1604
HttpResource Register(HttpResource Resource)
Registers a resource with the server.
Definition: HttpServer.cs:1287
bool Unregister(HttpResource Resource)
Unregisters a resource from the server.
Definition: HttpServer.cs:1438
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
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:19
static async Task Update(object Object)
Updates an object in the database.
Definition: Database.cs:626
static async Task Delete(object Object)
Deletes an object in the database.
Definition: Database.cs:717
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:1079
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 void CallFromSource(params string[] Sources)
Makes sure the call is made from one of the listed sources.
Definition: Assert.cs:39
Contains methods for simple hash calculations.
Definition: Hashes.cs:59
static byte[] ComputeHMACSHA256Hash(byte[] Key, byte[] Data)
Computes the HMAC-SHA-256 hash of a block of binary data.
Definition: Hashes.cs:585
Interface for system configurations. The gateway will scan all module for system configuration classe...
IdentityState
Lists recognized legal identity states.
XmppState
State of XMPP connection.
Definition: XmppState.cs:7