Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
BlockListResource.cs
1using System;
3using System.Text;
4using System.Threading.Tasks;
5using Waher.Content;
15using Waher.Script;
16using Waher.Security;
17
19{
24 {
25 private readonly XmppClient client;
26 private readonly HttpServer webServer;
27 private readonly string userVariable;
28 private readonly string[] userPrivileges;
29
38 public BlockListResource(string ResourceName, XmppClient Client, HttpServer WebServer, string UserVariable, params string[] UserPrivileges)
39 : base(ResourceName)
40 {
41 this.client = Client;
42 this.webServer = WebServer;
43 this.userVariable = UserVariable;
44 this.userPrivileges = UserPrivileges;
45 }
46
50 public override bool HandlesSubPaths => false;
51
55 public override bool UserSessions => false;
56
60 public bool AllowsGET => true;
61
68 public async Task GET(HttpRequest Request, HttpResponse Response)
69 {
70 string s = Request.RemoteEndPoint;
71 int i = s.IndexOf('/');
72 if (i > 0)
73 s = s[..i];
74
75 RosterItem Item = this.client[s];
76 bool Forbidden = false;
77
78 if (Item is null)
79 {
80 string HttpSessionID = GetSessionId(Request, Response);
81
82 if (string.IsNullOrEmpty(HttpSessionID))
83 Forbidden = true;
84 else
85 {
86 Variables Session = this.webServer.GetSession(HttpSessionID, false);
87 if (Session is null ||
88 !Session.TryGetVariable(this.userVariable, out Variable v) ||
89 !(v.ValueObject is IUser User))
90 {
91 Forbidden = true;
92 }
93 else
94 {
95 foreach (string Privilege in this.userPrivileges)
96 {
97 if (!User.HasPrivilege(Privilege))
98 {
99 Forbidden = true;
100 break;
101 }
102 }
103 }
104 }
105 }
106 else
107 {
108 if ((Item.State != SubscriptionState.Both && Item.State != SubscriptionState.From))
109 Forbidden = true;
110 }
111
112 if (Forbidden)
113 {
114 await Response.SendResponse(new ForbiddenException(Request, "Access to block list not granted."));
115 return;
116 }
117
118 HttpFieldAccept Accept = Request.Header.Accept;
119 string Alternative = Accept?.GetBestAlternative(XmlCodec.DefaultContentType,
121
122 if (Alternative is null)
123 {
124 await Response.SendResponse(new NotAcceptableException("List can be returned in XML or JSON formats only. Choose which one using the Accept header."));
125 return;
126 }
127
128 string[] AllowedCollections = Item?.Groups;
129 int MaxCount = int.MaxValue;
130
131 if (!Request.Header.TryGetQueryParameter("Last", out string Last))
132 Last = null;
133
134 if (Request.Header.TryGetQueryParameter("Max", out s))
135 {
136 if (!int.TryParse(s, out i) || i <= 0)
137 {
138 await Response.SendResponse(new BadRequestException("Invalid maximum number of references to return."));
139 return;
140 }
141
142 MaxCount = i;
143 }
144
145 if (Request.Header.TryGetQueryParameter("Collections", out s))
146 {
147 string[] RequestedCollections = s.Split(',');
148
149 if (!(AllowedCollections is null))
150 {
151 foreach (string Collection in RequestedCollections)
152 {
153 if (Array.IndexOf(AllowedCollections, Collection) < 0)
154 {
155 await Response.SendResponse(new ForbiddenException(Request, "Access to collection " + Collection + " denied."));
156 return;
157 }
158 }
159 }
160
161 AllowedCollections = RequestedCollections;
162 }
163
164 if (!(AllowedCollections is null) && AllowedCollections.Length == 0)
165 {
166 await Response.SendResponse(new ForbiddenException(Request, "Access to block list not granted."));
167 return;
168 }
169
170 this.ProcessRequest(Response, Alternative, AllowedCollections, Last, MaxCount);
171 }
172
173 private async void ProcessRequest(HttpResponse Response, string Alternative, string[] AllowedCollections,
174 string Last, int MaxCount)
175 {
176 try
177 {
178 IEnumerable<BlockReference> Blocks;
179
180 if (AllowedCollections is null)
181 {
182 if (string.IsNullOrEmpty(Last))
183 Blocks = await Database.Find<BlockReference>(0, MaxCount, "ObjectId");
184 else
185 Blocks = await Database.Find<BlockReference>(0, MaxCount, new FilterFieldGreaterThan("ObjectId", Last), "ObjectId");
186 }
187 else
188 {
189 Dictionary<string, bool> Collections = new Dictionary<string, bool>();
190
191 foreach (string Collection in AllowedCollections)
192 Collections[Collection] = true;
193
195 (Ref) => Collections.ContainsKey(Ref.Collection));
196
197 if (string.IsNullOrEmpty(Last))
198 Blocks = await Database.Find<BlockReference>(0, MaxCount, CollectionFilter, "ObjectId");
199 else
200 {
201 Blocks = await Database.Find<BlockReference>(0, MaxCount,
202 new FilterAnd(new FilterFieldGreaterThan("ObjectId", Last), CollectionFilter), "ObjectId");
203 }
204 }
205
206 StringBuilder sb = new StringBuilder();
207
208 switch (Alternative)
209 {
212 Response.StatusCode = 200;
213 Response.StatusMessage = "OK";
214 Response.ContentType = Alternative;
215
216 sb.Append("<blockReferences xmlns=\"");
217 sb.Append(NeuroLedgerClient.NeuroLedgerNamespace);
218 sb.Append("\">");
219
220 await Response.Write(sb.ToString());
221
222 foreach (BlockReference Ref in Blocks)
223 {
224 sb.Clear();
225
226 sb.Append("<ref id='");
227 sb.Append(Ref.ObjectId);
228
229 sb.Append("' d='");
230 sb.Append(Convert.ToBase64String(Ref.Digest));
231 sb.Append("' s='");
232 sb.Append(Convert.ToBase64String(Ref.Signature));
233
234 if (!(Ref.Link is null))
235 {
236 sb.Append("' l='");
237 sb.Append(Convert.ToBase64String(Ref.Link));
238 }
239
240 sb.Append("' cn='");
241 sb.Append(XML.Encode(Ref.Collection));
242 sb.Append("' cr='");
243 sb.Append(XML.Encode(Ref.Creator));
244 sb.Append("' ct='");
245 sb.Append(XML.Encode(Ref.Created));
246
247 if (Ref.Updated != DateTime.MinValue)
248 {
249 sb.Append("' u='");
250 sb.Append(XML.Encode(Ref.Updated));
251 }
252
253 if (Ref.Expires != DateTime.MaxValue)
254 {
255 sb.Append("' x='");
256 sb.Append(XML.Encode(Ref.Expires));
257 }
258
259 if (Ref.Status != BlockStatus.Valid)
260 {
261 sb.Append("' t='");
262 sb.Append(Ref.Status.ToString());
263 }
264
265 sb.Append("' r='");
266 sb.Append("httpx://");
267 sb.Append(this.client.BareJID);
268 sb.Append("/NL/B/");
269 sb.Append(Base64Url.Encode(Ref.Digest));
270 sb.Append("' b='");
271 sb.Append(Ref.Bytes.ToString());
272 sb.Append("'/>");
273
274 await Response.Write(sb.ToString());
275 }
276
277 await Response.Write("</blockReferences>");
278 await Response.SendResponse();
279 break;
280
282 case "text/x-json":
283 Response.StatusCode = 200;
284 Response.StatusMessage = "OK";
285 Response.ContentType = Alternative;
286
287 List<KeyValuePair<string, object>> Properties = new List<KeyValuePair<string, object>>();
288 bool First = true;
289
290 await Response.Write("[");
291
292 foreach (BlockReference Ref in Blocks)
293 {
294 Properties.Clear();
295 Properties.Add(new KeyValuePair<string, object>("id", Ref.ObjectId));
296 Properties.Add(new KeyValuePair<string, object>("d", Convert.ToBase64String(Ref.Digest)));
297 Properties.Add(new KeyValuePair<string, object>("s", Convert.ToBase64String(Ref.Signature)));
298 Properties.Add(new KeyValuePair<string, object>("cn", Ref.Collection));
299 Properties.Add(new KeyValuePair<string, object>("cr", Ref.Creator));
300 Properties.Add(new KeyValuePair<string, object>("ct", Ref.Created));
301 Properties.Add(new KeyValuePair<string, object>("b", Ref.Bytes));
302
303 if (!(Ref.Link is null))
304 Properties.Add(new KeyValuePair<string, object>("l", Convert.ToBase64String(Ref.Link)));
305
306 if (Ref.Updated != DateTime.MinValue)
307 Properties.Add(new KeyValuePair<string, object>("u", Ref.Updated));
308
309 if (Ref.Expires != DateTime.MaxValue)
310 Properties.Add(new KeyValuePair<string, object>("x", Ref.Expires));
311
312 if (Ref.Status != BlockStatus.Valid)
313 Properties.Add(new KeyValuePair<string, object>("t", Ref.Status.ToString()));
314
315 sb.Clear();
316
317 sb.Append("httpx://");
318 sb.Append(this.client.BareJID);
319 sb.Append("/NL/B/");
320 sb.Append(Base64Url.Encode(Ref.Digest));
321
322 Properties.Add(new KeyValuePair<string, object>("r", sb.ToString()));
323
324 if (First)
325 {
326 First = false;
327 sb.Append(JSON.Encode(Properties.ToArray(), false));
328 }
329 else
330 sb.Append("," + JSON.Encode(Properties.ToArray(), false));
331
332 await Response.Write(sb.ToString());
333 }
334
335 await Response.Write(']');
336 await Response.SendResponse();
337 break;
338
339 default:
340 await Response.SendResponse(new NotAcceptableException("Desired format not acceptable. Use the Accept header field to select either text/xml or application/json."));
341 return;
342 }
343
344 await Response.SendResponse();
345 }
346 catch (Exception ex)
347 {
348 await Response.SendResponse(ex);
349 }
350 }
351
352 }
353}
Static class that does BASE64URL encoding (using URL and filename safe alphabet), as defined in RFC46...
Definition: Base64Url.cs:11
static string Encode(byte[] Data)
Converts a binary block of data to a Base64URL-encoded string.
Definition: Base64Url.cs:48
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
XML encoder/decoder.
Definition: XmlCodec.cs:19
const string DefaultContentType
Default content type for XML documents.
Definition: XmlCodec.cs:30
const string SchemaContentType
Default content type for XML schema documents.
Definition: XmlCodec.cs:35
Helps with common XML-related tasks.
Definition: XML.cs:21
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:29
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...
Accept HTTP Field header. (RFC 2616, §14.1)
string GetBestAlternative(params string[] Alternatives)
Gets the best alternative acceptable to the client.
Base class for all asynchronous HTTP resources. An asynchronous resource responds outside of the meth...
HttpFieldAccept Accept
Accept HTTP Field header. (RFC 2616, §14.1)
bool TryGetQueryParameter(string QueryParameter, out string Value)
Tries to get the value of an individual query parameter, if available.
Represents an HTTP request.
Definition: HttpRequest.cs:22
HttpRequestHeader Header
Request header.
Definition: HttpRequest.cs:182
string RemoteEndPoint
Remote end-point.
Definition: HttpRequest.cs:243
static string GetSessionId(HttpRequest Request, HttpResponse Response)
Gets the session ID used for a request.
const string HttpSessionID
The Cookie Key for HTTP Session Identifiers: "HttpSessionID"
Definition: HttpResource.cs:27
string ResourceName
Name of resource.
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
The resource identified by the request is only capable of generating response entities which have con...
Provides authenticated and authorized clients with lists of available blocks.
BlockListResource(string ResourceName, XmppClient Client, HttpServer WebServer, string UserVariable, params string[] UserPrivileges)
Provides authenticated and authorized clients with binary blocks.
override bool HandlesSubPaths
If the resource handles sub-paths.
async Task GET(HttpRequest Request, HttpResponse Response)
Executes the GET method on the resource.
override bool UserSessions
If the resource uses user sessions.
Maintains information about an item in the roster.
Definition: RosterItem.cs:75
SubscriptionState State
roup Current subscription state.
Definition: RosterItem.cs:268
string[] Groups
Any groups the roster item belongs to.
Definition: RosterItem.cs:186
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:58
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:21
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
Definition: Database.cs:238
This filter selects objects that conform to all child-filters provided.
Definition: FilterAnd.cs:10
Custom filter used to filter objects using an external expression.
Definition: FilterCustom.cs:10
This filter selects objects that have a named field greater than a given value.
byte[] Link
Link to updated block (in case Status shows the block has been updated).
Definition: BlockHeader.cs:120
string Creator
Creator of the block.
Definition: BlockHeader.cs:55
BlockStatus Status
Claimed status of block.
Definition: BlockHeader.cs:108
DateTime Created
When the block was created.
Definition: BlockHeader.cs:75
DateTime Expires
When the block expires.
Definition: BlockHeader.cs:97
DateTime Updated
When the block was updated (in case Status shows the block has been updated or deleted).
Definition: BlockHeader.cs:87
Contains a reference to a block in the ledger.
Contains information about a variable.
Definition: Variable.cs:10
Collection of variables.
Definition: Variables.cs:25
virtual bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
Definition: Variables.cs:56
GET Interface for HTTP resources.
Basic interface for a user.
Definition: IUser.cs:7
SubscriptionState
State of a presence subscription.
Definition: RosterItem.cs:16
BlockStatus
Status of the block.
Definition: BlockHeader.cs:12