Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
AgentApi.cs
1using System;
3using System.Threading.Tasks;
4using Waher.Content;
5using Waher.Events;
16
18{
22 public class AgentApi : IModule
23 {
24 private IAgentResource[] resources;
25 private readonly LoginAuditor auditor;
26
30 public AgentApi()
31 : this(null, null)
32 {
33 }
34
41 {
42 AgentResource.Factory = Factory;
43 this.auditor = Auditor ?? Gateway.LoginAuditor;
44 }
45
49 public LoginAuditor Auditor => this.auditor;
50
54 public Task Start()
55 {
56 return this.Start(Gateway.HttpServer);
57 }
58
63 public async Task Start(HttpServer WebServer)
64 {
65 List<IAgentResource> Resources = new List<IAgentResource>();
66
67 foreach (Type T in Types.GetTypesImplementingInterface(typeof(IAgentResource)))
68 {
69 if (T.IsAbstract)
70 continue;
71
72 try
73 {
75
76 await Resource.Register(WebServer, this);
77 }
78 catch (Exception ex)
79 {
80 Log.Exception(ex, T.FullName);
81 }
82 }
83
84 this.resources = Resources.ToArray();
85 }
86
90 public Task Stop()
91 {
92 return this.Stop(Gateway.HttpServer);
93 }
94
99 public async Task Stop(HttpServer WebServer)
100 {
101 if (!(this.resources is null))
102 {
103 foreach (IAgentResource Resource in this.resources)
104 await Resource.Unregister(WebServer);
105 }
106 }
107
113 public async Task<ApiKey> GetApiKey(string ApiKey)
114 {
115 PersistenceLayer PersistenceLayer = XmppServerModule.PersistenceLayer ?? new PersistenceLayer();
116 return await PersistenceLayer.GetApiKey(ApiKey);
117 }
118
123 public static async Task<ApiKey> GetAgentApiApiKey()
124 {
125 return await Database.FindFirstDeleteRest<ApiKey>(
126 new FilterFieldEqualTo("Owner", "Agent API"));
127 }
128
133 {
139 : this(Code, string.Empty)
140 {
141 }
146 public CreateAccountResult(int Code, string Message)
147 {
148 this.Code = Code;
149 this.Account = null;
150 this.ErrorMessage = Message;
151 this.Token = null;
152 }
153
158 public CreateAccountResult(Exception ex)
159 {
160 this.Code = 4;
161 this.Account = null;
162 this.ErrorMessage = ex.Message;
163 this.Token = null;
164 }
165
173 public CreateAccountResult(DataStorage.Account Account, string Token,
174 int IssuedAt, int Expires)
175 {
176 this.Code = 0;
177 this.Account = Account;
178 this.ErrorMessage = null;
179 this.Token = Token;
180 this.IssuedAt = IssuedAt;
181 this.Expires = Expires;
182 }
183
195 public int Code;
196
201
205 public string ErrorMessage;
206
210 public string Token;
211
215 public int IssuedAt;
216
220 public int Expires;
221 }
222
235 public static async Task<CreateAccountResult> CreateAccount(
236 string UserName, string Password, string EMail, string PhoneNr, string Language,
237 int Seconds, HttpRequest Request)
238 {
239 DataStorage.Account Account = await Database.FindFirstIgnoreRest<DataStorage.Account>(
240 new FilterFieldEqualTo("UserName", UserName));
241
242 if (!(Account is null))
243 return new CreateAccountResult(1);
244
246 if (ApiKey is null)
247 return new CreateAccountResult(2);
248
249 if (ApiKey.NrCreated - ApiKey.NrDeleted >= ApiKey.MaxAccounts)
250 return new CreateAccountResult(3);
251
252 Account = new DataStorage.Account()
253 {
254 ApiKey = ApiKey.Key,
255 UserName = UserName,
256 Password = Password,
257 EMail = EMail,
258 EMailVerified = null,
259 PhoneNr = PhoneNr,
260 PhoneNrVerified = null,
261 Enabled = false,
262 CanRelayMessages = false,
263 Created = DateTime.UtcNow
264 };
265
266 await Database.Insert(Account);
267 await RuntimeCounters.IncrementCounter(DataStorage.Account.AccountCreatedCounterName);
268
269 ApiKey.NrCreated++;
270 await Database.Update(ApiKey);
271
273 Request.RemoteEndPoint);
274
275 try
276 {
277 string OnboardingDomainName = await LegalComponent.GetOnboardingNeuronDomainName();
278
279 // Sending verification e-mail
280
281 ContentResponse OnboardingResponse = await InternetContent.PostAsync(
282 new Uri("https://" + OnboardingDomainName + "/ID/SendVerificationMessage.ws"),
283 new Dictionary<string, object>()
284 {
285 { "EMail", EMail },
286 { "Language", Language }
287 },
288 new KeyValuePair<string, string>("Accept", "application/json"));
289
290 if (OnboardingResponse.HasError)
291 return new CreateAccountResult(OnboardingResponse.Error);
292
293 if (!(OnboardingResponse.Decoded is Dictionary<string, object> Response))
294 return new CreateAccountResult(4);
295
296 if (!Response.TryGetValue("Status", out object Obj) ||
297 !(Obj is bool Status) ||
298 !Status)
299 {
300 if (Response.TryGetValue("Message", out Obj) && Obj is string Message)
301 return new CreateAccountResult(4, Message);
302 else
303 return new CreateAccountResult(4);
304 }
305
306 // Sending verification SMS
307
308 OnboardingResponse = await InternetContent.PostAsync(
309 new Uri("https://" + OnboardingDomainName + "/ID/SendVerificationMessage.ws"),
310 new Dictionary<string, object>()
311 {
312 { "Nr", PhoneNr },
313 { "Language", Language }
314 },
315 new KeyValuePair<string, string>("Accept", "application/json"));
316
317 if (OnboardingResponse.HasError)
318 return new CreateAccountResult(OnboardingResponse.Error);
319
320 if (!(OnboardingResponse.Decoded is Dictionary<string, object> Response2))
321 return new CreateAccountResult(5);
322
323 if (!Response2.TryGetValue("Status", out Obj) ||
324 !(Obj is bool Status2) ||
325 !Status2)
326 {
327 if (Response2.TryGetValue("Message", out Obj) && Obj is string Message)
328 return new CreateAccountResult(5, Message);
329 else
330 return new CreateAccountResult(5);
331 }
332
333 int IssuedAt = (int)Math.Round(DateTime.UtcNow.Subtract(JSON.UnixEpoch).TotalSeconds);
334 int Expires = IssuedAt + (int)Seconds;
335
336 if (Seconds < 60)
337 Seconds = 60;
338 else if (Seconds > 3600)
339 Seconds = 3600;
340
341 string Token = AgentResource.Factory.Create(
342 new KeyValuePair<string, object>(JwtClaims.JwtId, Convert.ToBase64String(Gateway.NextBytes(32))),
343 new KeyValuePair<string, object>(JwtClaims.Issuer, Gateway.Domain?.Value ?? string.Empty),
344 new KeyValuePair<string, object>(JwtClaims.Subject, Account.UserName.Value + "@" + (Gateway.Domain?.Value ?? string.Empty)),
345 new KeyValuePair<string, object>(JwtClaims.IssueTime, IssuedAt),
346 new KeyValuePair<string, object>(JwtClaims.ExpirationTime, Expires));
347
348 return new CreateAccountResult(Account, Token, IssuedAt, Expires);
349 }
350 catch (Exception ex)
351 {
352 return new CreateAccountResult(ex);
353 }
354 }
355 }
356}
Contains information about a response to a content request.
bool HasError
If an error occurred.
object Decoded
Decoded object.
Exception Error
Error response.
Static class managing encoding and decoding of internet content.
static Task< ContentResponse > PostAsync(Uri Uri, object Data, params KeyValuePair< string, string >[] Headers)
Posts to a resource, using a Uniform Resource Identifier (or Locator).
Helps with common JSON-related tasks.
Definition: JSON.cs:16
static readonly DateTime UnixEpoch
Unix Date and Time epoch, starting at 1970-01-01T00:00:00Z
Definition: JSON.cs:20
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 class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:147
static CaseInsensitiveString Domain
Domain name.
Definition: Gateway.cs:3087
static HttpServer HttpServer
HTTP Server
Definition: Gateway.cs:4118
static LoginAuditor LoginAuditor
Current Login Auditor. Should be used by modules accepting user logins, to protect the system from un...
Definition: Gateway.cs:3860
static byte[] NextBytes(int NrBytes)
Generates an array of random bytes.
Definition: Gateway.cs:4335
Represents an HTTP request.
Definition: HttpRequest.cs:22
string RemoteEndPoint
Remote end-point.
Definition: HttpRequest.cs:243
string Host
Host reference. (Value of Host header, without the port number)
Definition: HttpRequest.cs:263
Implements an HTTP server.
Definition: HttpServer.cs:41
string Value
String-representation of the case-insensitive string. (Representation is case sensitive....
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 Insert(object Object)
Inserts an object into the default collection of the database.
Definition: Database.cs:97
This filter selects objects that have a named field equal to a given value.
Static class managing persistent counters.
static Task< long > IncrementCounter(CaseInsensitiveString Key)
Increments a counter.
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:15
static object Instantiate(Type Type, params object[] Arguments)
Returns an instance of the type Type . If one needs to be created, it is. If the constructor requires...
Definition: Types.cs:1454
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
Definition: Types.cs:85
Static class containing predefined JWT claim names.
Definition: JwtClaims.cs:10
const string Issuer
Issuer of the JWT
Definition: JwtClaims.cs:14
const string IssueTime
Time at which the JWT was issued; can be used to determine age of the JWT
Definition: JwtClaims.cs:39
const string JwtId
Unique identifier; can be used to prevent the JWT from being replayed (allows a token to be used only...
Definition: JwtClaims.cs:44
const string Subject
Subject of the JWT (the user)
Definition: JwtClaims.cs:19
const string ExpirationTime
Time after which the JWT expires
Definition: JwtClaims.cs:29
A factory that can create and validate JWT tokens.
Definition: JwtFactory.cs:66
string Create(params KeyValuePair< string, object >[] Claims)
Creates a new JWT token.
Definition: JwtFactory.cs:379
Class that monitors login events, and help applications determine malicious intent....
Definition: LoginAuditor.cs:26
Contains information about a broker account.
Definition: Account.cs:41
CaseInsensitiveString UserName
User Name of account
Definition: Account.cs:141
Account()
Contains information about a broker account.
Definition: Account.cs:114
static async Task AccountCreated(Account Account, ApiKey ApiKeyObject, string Domain, string RemoteEndPoint)
Notifies operators of a new account being created.
CreateAccountResult(int Code, string Message)
Result from the CreateAccount method.
Definition: AgentApi.cs:146
CreateAccountResult(DataStorage.Account Account, string Token, int IssuedAt, int Expires)
Result from the CreateAccount method.
Definition: AgentApi.cs:173
CreateAccountResult(int Code)
Result from the CreateAccount method.
Definition: AgentApi.cs:138
string Token
Agent API token for the created account.
Definition: AgentApi.cs:210
string ErrorMessage
Error message, if code=-1, or specification of error, if applicable.
Definition: AgentApi.cs:205
CreateAccountResult(Exception ex)
Result from the CreateAccount method.
Definition: AgentApi.cs:158
static async Task< ApiKey > GetAgentApiApiKey()
Gets API Key for the Agent API.
Definition: AgentApi.cs:123
AgentApi(JwtFactory Factory, LoginAuditor Auditor)
Agent API Module.
Definition: AgentApi.cs:40
async Task< ApiKey > GetApiKey(string ApiKey)
Gets an API Key
Definition: AgentApi.cs:113
async Task Start(HttpServer WebServer)
Starts the module using a specific web server.
Definition: AgentApi.cs:63
static async Task< CreateAccountResult > CreateAccount(string UserName, string Password, string EMail, string PhoneNr, string Language, int Seconds, HttpRequest Request)
Creates an account for use with the Agent API.
Definition: AgentApi.cs:235
async Task Stop(HttpServer WebServer)
Stops the module using a specific web server.
Definition: AgentApi.cs:99
Abstract base class for agent resources
Interface for late-bound modules loaded at runtime.
Definition: IModule.cs:9