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;
2using System.Collections.Generic;
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 Task GET(HttpRequest Request, HttpResponse Response)
69 {
70 string s = Request.RemoteEndPoint;
71 int i = s.IndexOf('/');
72 if (i > 0)
73 s = s.Substring(0, 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 throw new ForbiddenException("Access to block list not granted.");
114
115 HttpFieldAccept Accept = Request.Header.Accept;
116 string Alternative = Accept?.GetBestAlternative(XmlCodec.DefaultContentType,
118 ?? throw new NotAcceptableException("List can be returned in XML or JSON formats only. Choose which one using the Accept header.");
119
120 string[] AllowedCollections = Item?.Groups;
121 int MaxCount = int.MaxValue;
122
123 if (!Request.Header.TryGetQueryParameter("Last", out string Last))
124 Last = null;
125
126 if (Request.Header.TryGetQueryParameter("Max", out s))
127 {
128 if (!int.TryParse(s, out i) || i <= 0)
129 throw new BadRequestException("Invalid maximum number of references to return.");
130
131 MaxCount = i;
132 }
133
134 if (Request.Header.TryGetQueryParameter("Collections", out s))
135 {
136 string[] RequestedCollections = s.Split(',');
137
138 if (!(AllowedCollections is null))
139 {
140 foreach (string Collection in RequestedCollections)
141 {
142 if (Array.IndexOf(AllowedCollections, Collection) < 0)
143 throw new ForbiddenException("Access to collection " + Collection + " denied.");
144 }
145 }
146
147 AllowedCollections = RequestedCollections;
148 }
149
150 if (!(AllowedCollections is null) && AllowedCollections.Length == 0)
151 throw new ForbiddenException("Access to block list not granted.");
152
153 this.ProcessRequest(Response, Alternative, AllowedCollections, Last, MaxCount);
154
155 return Task.CompletedTask;
156 }
157
158 private async void ProcessRequest(HttpResponse Response, string Alternative, string[] AllowedCollections,
159 string Last, int MaxCount)
160 {
161 try
162 {
163 IEnumerable<BlockReference> Blocks;
164
165 if (AllowedCollections is null)
166 {
167 if (string.IsNullOrEmpty(Last))
168 Blocks = await Database.Find<BlockReference>(0, MaxCount, "ObjectId");
169 else
170 Blocks = await Database.Find<BlockReference>(0, MaxCount, new FilterFieldGreaterThan("ObjectId", Last), "ObjectId");
171 }
172 else
173 {
174 Dictionary<string, bool> Collections = new Dictionary<string, bool>();
175
176 foreach (string Collection in AllowedCollections)
177 Collections[Collection] = true;
178
180 (Ref) => Collections.ContainsKey(Ref.Collection));
181
182 if (string.IsNullOrEmpty(Last))
183 Blocks = await Database.Find<BlockReference>(0, MaxCount, CollectionFilter, "ObjectId");
184 else
185 {
186 Blocks = await Database.Find<BlockReference>(0, MaxCount,
187 new FilterAnd(new FilterFieldGreaterThan("ObjectId", Last), CollectionFilter), "ObjectId");
188 }
189 }
190
191 StringBuilder sb = new StringBuilder();
192
193 switch (Alternative)
194 {
197 Response.StatusCode = 200;
198 Response.ContentType = Alternative;
199
200 sb.Append("<blockReferences xmlns=\"");
201 sb.Append(NeuroLedgerClient.NeuroLedgerNamespace);
202 sb.Append("\">");
203
204 await Response.Write(sb.ToString());
205
206 foreach (BlockReference Ref in Blocks)
207 {
208 sb.Clear();
209
210 sb.Append("<ref id='");
211 sb.Append(Ref.ObjectId);
212
213 sb.Append("' d='");
214 sb.Append(Convert.ToBase64String(Ref.Digest));
215 sb.Append("' s='");
216 sb.Append(Convert.ToBase64String(Ref.Signature));
217
218 if (!(Ref.Link is null))
219 {
220 sb.Append("' l='");
221 sb.Append(Convert.ToBase64String(Ref.Link));
222 }
223
224 sb.Append("' cn='");
225 sb.Append(XML.Encode(Ref.Collection));
226 sb.Append("' cr='");
227 sb.Append(XML.Encode(Ref.Creator));
228 sb.Append("' ct='");
229 sb.Append(XML.Encode(Ref.Created));
230
231 if (Ref.Updated != DateTime.MinValue)
232 {
233 sb.Append("' u='");
234 sb.Append(XML.Encode(Ref.Updated));
235 }
236
237 if (Ref.Expires != DateTime.MaxValue)
238 {
239 sb.Append("' x='");
240 sb.Append(XML.Encode(Ref.Expires));
241 }
242
243 if (Ref.Status != BlockStatus.Valid)
244 {
245 sb.Append("' t='");
246 sb.Append(Ref.Status.ToString());
247 }
248
249 sb.Append("' r='");
250 sb.Append("httpx://");
251 sb.Append(this.client.BareJID);
252 sb.Append("/NL/B/");
253 sb.Append(Base64Url.Encode(Ref.Digest));
254 sb.Append("' b='");
255 sb.Append(Ref.Bytes.ToString());
256 sb.Append("'/>");
257
258 await Response.Write(sb.ToString());
259 }
260
261 await Response.Write("</blockReferences>");
262 await Response.SendResponse();
263 break;
264
266 case "text/x-json":
267 Response.StatusCode = 200;
268 Response.ContentType = Alternative;
269
270 List<KeyValuePair<string, object>> Properties = new List<KeyValuePair<string, object>>();
271 bool First = true;
272
273 await Response.Write("[");
274
275 foreach (BlockReference Ref in Blocks)
276 {
277 Properties.Clear();
278 Properties.Add(new KeyValuePair<string, object>("id", Ref.ObjectId));
279 Properties.Add(new KeyValuePair<string, object>("d", Convert.ToBase64String(Ref.Digest)));
280 Properties.Add(new KeyValuePair<string, object>("s", Convert.ToBase64String(Ref.Signature)));
281 Properties.Add(new KeyValuePair<string, object>("cn", Ref.Collection));
282 Properties.Add(new KeyValuePair<string, object>("cr", Ref.Creator));
283 Properties.Add(new KeyValuePair<string, object>("ct", Ref.Created));
284 Properties.Add(new KeyValuePair<string, object>("b", Ref.Bytes));
285
286 if (!(Ref.Link is null))
287 Properties.Add(new KeyValuePair<string, object>("l", Convert.ToBase64String(Ref.Link)));
288
289 if (Ref.Updated != DateTime.MinValue)
290 Properties.Add(new KeyValuePair<string, object>("u", Ref.Updated));
291
292 if (Ref.Expires != DateTime.MaxValue)
293 Properties.Add(new KeyValuePair<string, object>("x", Ref.Expires));
294
295 if (Ref.Status != BlockStatus.Valid)
296 Properties.Add(new KeyValuePair<string, object>("t", Ref.Status.ToString()));
297
298 sb.Clear();
299
300 sb.Append("httpx://");
301 sb.Append(this.client.BareJID);
302 sb.Append("/NL/B/");
303 sb.Append(Base64Url.Encode(Ref.Digest));
304
305 Properties.Add(new KeyValuePair<string, object>("r", sb.ToString()));
306
307 if (First)
308 {
309 First = false;
310 sb.Append(JSON.Encode(Properties.ToArray(), false));
311 }
312 else
313 sb.Append("," + JSON.Encode(Properties.ToArray(), false));
314
315 await Response.Write(sb.ToString());
316 }
317
318 await Response.Write(']');
319 await Response.SendResponse();
320 break;
321
322 default:
323 throw new NotAcceptableException("Desired format not acceptable. Use the Accept header field to select either text/xml or application/json.");
324 }
325
326 await Response.SendResponse();
327 }
328 catch (Exception ex)
329 {
330 await Response.SendResponse(ex);
331 }
332 }
333
334 }
335}
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: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
XML encoder/decoder.
Definition: XmlCodec.cs:16
const string DefaultContentType
Default content type for XML documents.
Definition: XmlCodec.cs:27
const string SchemaContentType
Default content type for XML schema documents.
Definition: XmlCodec.cs:32
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:27
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:18
HttpRequestHeader Header
Request header.
Definition: HttpRequest.cs:134
string RemoteEndPoint
Remote end-point.
Definition: HttpRequest.cs:195
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: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
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.
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:59
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
Definition: Database.cs:247
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:52
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