2using System.Collections.Generic;
3using System.Security.Cryptography;
5using System.Threading.Tasks;
34 : base(
"Account/Recover",
35 new KeyValuePair<Type,
Expression>(typeof(Dictionary<string, object>), new
Expression(jsonPattern)),
65 string UserName = (string)Parameters[
"PUserName"]?.AssociatedObjectValue ??
string.Empty;
66 string PersonalNr = (string)Parameters[
"PPersonalNr"]?.AssociatedObjectValue ??
string.Empty;
67 string Country = (string)Parameters[
"PCountry"]?.AssociatedObjectValue ??
string.Empty;
68 string EMail = (string)Parameters[
"PEMail"]?.AssociatedObjectValue ??
string.Empty;
69 string PhoneNr = (string)Parameters[
"PPhoneNr"]?.AssociatedObjectValue ??
string.Empty;
71 if (
string.IsNullOrEmpty(UserName) &&
string.IsNullOrEmpty(PersonalNr))
72 throw new BadRequestException(
"Either User Name or Personal Number with a corresponding country must be provided.");
74 if (
string.IsNullOrEmpty(EMail) &&
string.IsNullOrEmpty(PhoneNr))
77 Create.AssertUserNameValid(UserName);
79 LinkedList<LegalIdentity> Matches =
new LinkedList<LegalIdentity>();
81 "RecoverResponse",
"https://waher.se/Schema/BrokerAgent.xsd");
84 if (!
string.IsNullOrEmpty(UserName))
93 await Response.
Return(Result);
98 if (
string.IsNullOrEmpty(PersonalNr))
103 Matches.AddLast(Identity);
122 if (Identity is
null)
125 Matches.AddLast(Identity);
129 if (
string.IsNullOrEmpty(UserName))
131 UserName = Identity.Account;
134 else if (UserName != Identity.Account)
136 LoginAuditor.
Fail(
"Account recovery failed. Provided personal number that matches multiple accounts.", UserName, Request.
RemoteEndPoint,
"HTTPS");
138 throw new UnprocessableEntityException(
"Multiple accounts registered for that person on the server. You need to specify which account you want to recover.");
152 LoginAuditor.
Fail(
"Account recovery failed. Provided personal number does not match provided account.", UserName, Request.
RemoteEndPoint,
"HTTPS");
154 await Response.
Return(Result);
167 await Response.
Return(Result);
173 if (!
string.IsNullOrEmpty(EMail) && Account.EMail != EMail)
177 await Response.
Return(Result);
181 if (!
string.IsNullOrEmpty(PhoneNr))
183 bool PhoneNrMatches =
false;
187 string s = Identity[
"PHONE"];
188 if (
string.IsNullOrEmpty(s))
191 if (ComparePhoneNumbers(s, PhoneNr))
193 PhoneNrMatches =
true;
202 await Response.
Return(Result);
212 if (Matches.First is
null)
214 StringBuilder Xml =
new StringBuilder();
216 Xml.Append(
"<Account xmlns=\"http://waher.se/schema/Onboarding/v1.xsd\" userName=\"");
218 Xml.Append(
"\" password=\"");
220 Xml.Append(
"\" domain=\"");
224 byte[] Data = Encoding.UTF8.GetBytes(Xml.ToString());
229 using (Aes Aes = Aes.Create())
233 Aes.Mode = CipherMode.CBC;
234 Aes.Padding = PaddingMode.PKCS7;
236 using (ICryptoTransform Transform = Aes.CreateEncryptor(Key, IV))
238 Encrypted = Transform.TransformFinalBlock(Data, 0, Data.Length);
244 Xml.Append(
"<Info xmlns=\"http://waher.se/schema/Onboarding/v1.xsd\" base64=\"");
245 Xml.Append(Convert.ToBase64String(Encrypted));
246 Xml.Append(
"\" once=\"true\" expires=\"");
247 Xml.Append(
XML.
Encode(DateTime.Now.AddHours(1).ToUniversalTime()));
251 XmlElement E = await
Gateway.
XmppClient.IqSetAsync(
"onboarding." + OnboardingDomainName, Xml.ToString());
252 string Code = E.GetAttribute(
"code");
256 Xml.Append(
"obinfo:");
257 Xml.Append(OnboardingDomainName);
261 Xml.Append(Convert.ToBase64String(Key));
263 Xml.Append(Convert.ToBase64String(IV));
265 string Url = Xml.ToString();
266 StringBuilder Markdown =
new StringBuilder();
268 Markdown.AppendLine(
"Account recovery");
269 Markdown.AppendLine(
"===================");
270 Markdown.AppendLine();
271 Markdown.AppendLine(
"Someone has requested to recover access to your TAG ID account.");
272 Markdown.AppendLine(
"If this is not you, you can ignore this message, and the account will not be affected.");
273 Markdown.AppendLine(
"If it is you that has requested to recover your account, scan the following QR code to get access to the account.");
274 Markdown.AppendLine(
"If you view this e-mail in the phone containing the TAG ID app (or derivative), you can also click on the QR code itself.");
275 Markdown.AppendLine(
"This recovery code is only valid for one hour.");
276 Markdown.AppendLine();
277 Markdown.Append(
";
278 Markdown.Append(
Gateway.
GetUrl(
"/QR/" + HttpUtility.UrlEncode(Url)));
279 Markdown.AppendLine(
")");
280 Markdown.AppendLine();
281 Markdown.Append(
"If you have any questions, please let us know through our [feedback page](");
283 Markdown.AppendLine(
").");
295 if (Latest is
null || Identity.Created > Latest.Created)
301 if (LatestApproved is
null || Identity.Created > LatestApproved.Created)
302 LatestApproved = Identity;
305 if (!(LatestApproved is
null) && !(LatestApproved.Attachments is
null))
306 Reviewers = await
LegalComponent.GetPeerReviewers(LatestApproved);
315 StringBuilder Markdown =
new StringBuilder();
317 Markdown.AppendLine(
"User requests account recovery");
318 Markdown.AppendLine(
"==================================");
319 Markdown.AppendLine();
320 Markdown.AppendLine(
"Someone has requested to recover access to an account.");
321 Markdown.AppendLine(
"Following is some information provided in the request.");
322 Markdown.AppendLine();
323 Markdown.AppendLine(
"| Provided by user ||");
324 Markdown.AppendLine(
"|:--------|:--------|");
325 Markdown.Append(
"| User Name | `");
326 Markdown.Append(UserName);
327 Markdown.AppendLine(
"` |");
328 Markdown.Append(
"| Personal Number | `");
329 Markdown.Append(PersonalNr);
330 Markdown.AppendLine(
"` |");
331 Markdown.Append(
"| Country | `");
332 Markdown.Append(Country);
333 Markdown.AppendLine(
"` |");
334 Markdown.Append(
"| e-mail | <mailto:");
335 Markdown.Append(EMail);
336 Markdown.AppendLine(
"> |");
337 Markdown.Append(
"| Phone Number | <tel:");
338 Markdown.Append(PhoneNr);
339 Markdown.AppendLine(
"> |");
340 Markdown.AppendLine();
343 if (!(Locale is
null))
345 Markdown.AppendLine(
"| Remote Endpoint ||");
346 Markdown.AppendLine(
"|:--------|:--------|");
347 Markdown.Append(
"| Country Code | ");
349 Markdown.AppendLine(
" |");
350 Markdown.Append(
"| Country | ");
352 Markdown.AppendLine(
" |");
353 Markdown.Append(
"| Region | ");
355 Markdown.AppendLine(
" |");
356 Markdown.Append(
"| City | ");
358 Markdown.AppendLine(
" |");
361 Markdown.AppendLine(
"No information found about IP address.");
363 Markdown.AppendLine();
365 if (!(LatestApproved is
null))
367 Markdown.AppendLine(
"| Latest Approved ID ||");
368 Markdown.AppendLine(
"|:---------|:---------|");
369 Markdown.Append(
"| ID | [");
371 Markdown.Append(
"](");
373 Markdown.Append(
"?ID=");
374 Markdown.Append(HttpUtility.UrlEncode(LatestApproved.Id));
375 Markdown.AppendLine(
"&Purpose=Review%20recovery%20application) |");
377 LegalComponent.Output(Markdown, LatestApproved.GetTags(
false),
false);
379 else if (!(Latest is
null))
381 Markdown.AppendLine(
"| Latest ID (not approved) ||");
382 Markdown.AppendLine(
"|:------------|:------------|");
383 Markdown.Append(
"| ID | [");
385 Markdown.Append(
"](");
387 Markdown.Append(
"?ID=");
388 Markdown.Append(HttpUtility.UrlEncode(Latest.Id));
389 Markdown.AppendLine(
"&Purpose=Review%20recovery%20application) |");
394 Markdown.AppendLine(
"No Legal ID found.");
404 await Response.
Return(Result);
407 private static bool ComparePhoneNumbers(
string Nr1,
string Nr2)
409 return OnlyDigits(Nr1) == OnlyDigits(Nr2);
412 private static string OnlyDigits(
string s)
414 StringBuilder sb =
new StringBuilder();
416 foreach (
char ch
in s)
418 if (
char.IsDigit(ch))
422 return sb.ToString();
Contains a markdown document. This markdown document class supports original markdown,...
static string Encode(string s)
Encodes all special characters in a string so that it can be included in a markdown document without ...
A Named dictionary is a dictionary, with a local name and a namespace. Use it to return content that ...
Static class managing loading of resources stored as embedded resources or in content files.
static string LoadResourceAsText(string ResourceName)
Loads a text resource from an embedded resource.
Helps with common XML-related tasks.
static string Encode(string s)
Encodes a string for use in XML.
Static class managing the runtime environment of the IoT Gateway.
static CaseInsensitiveString Domain
Domain name.
static byte[] NextBytes(int NrBytes)
Generates an array of random bytes.
static Task SendNotification(Graph Graph)
Sends a graph as a notification message to configured notification recipients.
static string GetUrl(string LocalResource)
Gets a URL for a resource.
static XmppClient XmppClient
XMPP Client connection of gateway.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
Base class for all HTTP authentication schemes, as defined in RFC-7235: https://datatracker....
Represents an HTTP request.
string RemoteEndPoint
Remote end-point.
Represets a response of an HTTP client request.
async Task Return(object Object)
Returns an object to the client. This method can only be called once per response,...
The server is currently unable to handle the request due to a temporary overloading or maintenance of...
The request was well-formed but was unable to be followed due to semantic errors.
bool IsComponentDomain(CaseInsensitiveString Domain, bool IncludeAlternativeDomains)
Checks if a domain is the component domain, or optionally, an alternative component domain.
override string ToString()
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
This filter selects objects that conform to all child-filters provided.
This filter selects objects that have a named field equal to a given value.
Class managing a script expression.
Class that monitors login events, and help applications determine malicious intent....
static async void Success(string Message, string UserName, string RemoteEndpoint, string Protocol, params KeyValuePair< string, object >[] Tags)
Handles a successful login attempt.
static async void Fail(string Message, string UserName, string RemoteEndpoint, string Protocol, params KeyValuePair< string, object >[] Tags)
Handles a failed login attempt.
Contains information about a broker account.
CaseInsensitiveString EMail
E-mail address associated with account.
CaseInsensitiveString UserName
User Name of account
string Password
Password of account
Provisioning and registry service component.
static Task< string > GetOnboardingNeuronDomainName()
Gets the domain name of the Nnboarding Neuron.
Contains a reference to a legal identity, and its related PNR and COUNTRY fields. Allows for distribu...
CaseInsensitiveString Provider
Provider of identity
CaseInsensitiveString LegalId
Legal ID reference
Creates an account on the server.
Called when a user wants to recover its account.
Recover()
Called when a user wants to recover its account.
override HttpAuthenticationScheme[] GetAuthenticationSchemes(HttpRequest Request)
Any authentication schemes used to authenticate users before access is granted to the corresponding r...
override async Task POST(HttpRequest Request, HttpResponse Response, Dictionary< string, IElement > Parameters)
Executes the POST method on the resource.
Abstract base class for agent resources supporting the POST method.
async Task CheckBlocks(HttpRequest Request)
Checks if the client is blocked.
Service Module hosting the XMPP broker and its components.
static Task< bool > SendMailMessage(string To, string Subject, string Markdown)
Sends a mail message
static Task< IP4Localization > FindIpAddress(string RemoteEndpoint)
Finds locale information about an IP Address.
IdentityState
Lists recognized legal identity states.