Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
AttachmentsResource.cs
1using System;
3using System.IO;
5using System.Threading.Tasks;
15
17{
19 {
20 private readonly HttpAuthenticationScheme[] authentication;
21 private readonly LegalComponent legalComponent;
22
24 : base("/Attachments")
25 {
26 this.legalComponent = LegalComponent;
27 this.authentication = new HttpAuthenticationScheme[]
28 {
29 new LegalSignature(this.legalComponent.MainDomain.Address.Value, this.legalComponent)
30 };
31 }
32
33 public override bool HandlesSubPaths => true;
34 public override bool UserSessions => true;
35
36 public bool AllowsGET => true;
37
38 public async Task GET(HttpRequest Request, HttpResponse Response)
39 {
40 string AttachmentId = Request.SubPath[1..];
41 int i = AttachmentId.IndexOf('@');
42
43 if (i > 0)
44 {
45 string AttachmentDomain = AttachmentId[(i + 1)..];
46 AttachmentId = AttachmentId[..i];
47
48 if (AttachmentDomain != this.legalComponent.MainDomain.Address.Value)
49 {
50 if (!Request.Header.TryGetQueryParameter("Url", out string AttachmentUrl))
51 throw new BadRequestException("Attachment URL required for accessing attachment hosted by other nodes.");
52
53 KeyValuePair<string, TemporaryFile> P = await Gateway.ContractsClient.GetAttachmentAsync(AttachmentUrl, Networking.XMPP.Contracts.SignWith.LatestApprovedId, 30000);
54 using TemporaryFile File = P.Value;
55
56 Response.ContentType = P.Key;
57 File.Position = 0;
58
59 long c = File.Length;
60 int BufferSize = (int)Math.Min(65536, c);
61 byte[] Buffer = new byte[BufferSize];
62
63 while (c > 0)
64 {
65 i = await File.TryReadAllAsync(Buffer, 0, (int)Math.Min(BufferSize, c));
66 if (i <= 0)
67 throw new IOException("Unexpected end of file.");
68
69 await Response.Write(true, Buffer, 0, i);
70 c -= i;
71 }
72
73 return;
74 }
75 }
76
78 ?? throw new NotFoundException("Attachment not found.");
79
80 bool Authorized;
81
82 if (Request.User is LegalIdentityUser User)
83 {
84 if (string.IsNullOrEmpty(Attachment.ContractId)) // Attachment to legal identity.
85 {
86 Authorized = this.legalComponent.IsAccessToIdentityAuthorized(User.From.BareJid, Attachment.UploaderLegalId);
87
88 if (!Authorized)
89 {
91
92 if (this.legalComponent.IsComponentDomain(Addr.Domain, true))
93 {
94 LegalIdentity Identity = await Database.FindFirstDeleteRest<LegalIdentity>(
95 new FilterFieldEqualTo("Id", Attachment.UploaderLegalId), "Created");
96
97 if (User.From.Account == Identity.Account && this.legalComponent.Server.IsServerDomain(User.From.Domain, true))
98 {
99 Authorized = true;
100 this.legalComponent.IdentityAuthorization(User.From.BareJid, User.From.BareJid, Attachment.UploaderLegalId, true);
101 }
102 }
103 }
104 }
105 else // Attachment to smart contract.
106 {
107 Authorized = this.legalComponent.IsAccessToContractAuthorized(User.From.BareJid, Attachment.ContractId);
108
109 if (!Authorized)
110 {
112
113 if (this.legalComponent.IsComponentDomain(Addr.Domain, true))
114 {
115 Contract Contract = await Database.FindFirstDeleteRest<Contract>(
116 new FilterFieldEqualTo("ContractId", Attachment.ContractId), "Created");
117
118 if (!(Contract is null))
119 {
120 switch (Contract.Visibility)
121 {
122 case ContractVisibility.Public:
123 case ContractVisibility.PublicSearchable:
124 Authorized = true;
125 break;
126
127 default:
128 Authorized = await Contract.CanRead(User.From, this.legalComponent.Server, this.legalComponent);
129 break;
130 }
131
132 if (Authorized)
133 this.legalComponent.ContractAuthorization(User.From.BareJid, User.From.BareJid, Attachment.ContractId, true);
134 }
135 }
136 }
137 }
138 }
139 else
140 {
141 if (string.IsNullOrEmpty(Attachment.ContractId)) // Attachment to legal identity.
142 Authorized = Request.User?.HasPrivilege("Legal.Id." + Attachment.UploaderLegalId) ?? false;
143 else // Attachment to smart contract.
144 {
145 Contract Contract = await Database.FindFirstDeleteRest<Contract>(
146 new FilterFieldEqualTo("ContractId", Attachment.ContractId), "Created");
147
148 if (!(Contract is null))
149 {
150 switch (Contract.Visibility)
151 {
152 case ContractVisibility.Public:
153 case ContractVisibility.PublicSearchable:
154 Authorized = true;
155 break;
156
157 default:
158 Authorized = Request.User?.HasPrivilege("Legal.Contract." + Attachment.ContractId) ?? false;
159 break;
160 }
161 }
162 else
163 Authorized = false;
164 }
165 }
166
167 if (!Authorized)
168 throw new ForbiddenException(Request, "Not authorized to access attachment.");
169
170 Response.ContentType = Attachment.ContentType;
171
172 using FileStream AttachmentFile = File.OpenRead(Attachment.LocalFileName);
173 Aes Aes = Aes.Create();
174
175 Aes.BlockSize = 128;
176 Aes.KeySize = 256;
177 Aes.Mode = CipherMode.CBC;
178 Aes.Padding = PaddingMode.Zeros;
179
180 byte[] Key = new byte[32];
181 byte[] IV = new byte[16];
182
183 Buffer.BlockCopy(Attachment.Salt, 0, Key, 0, 32);
184 Buffer.BlockCopy(Attachment.Salt, 32, IV, 0, 16);
185
186 using ICryptoTransform Decryptor = Aes.CreateDecryptor(Key, IV);
187 using (CryptoStream DecryptedAttachmentFile = new CryptoStream(AttachmentFile, Decryptor, CryptoStreamMode.Read))
188 {
189 byte[] Buffer = new byte[65536];
190 long c = Attachment.Size;
191
192 while (c > 0)
193 {
194 if (c > 65536)
195 i = await DecryptedAttachmentFile.TryReadAllAsync(Buffer, 0, 65536);
196 else
197 i = await DecryptedAttachmentFile.TryReadAllAsync(Buffer, 0, (int)c);
198
199 if (i <= 0)
200 throw new IOException("Unexpected end of file.");
201
202 await Response.Write(false, Buffer, 0, i);
203
204 c -= i;
205 }
206 }
207 }
208
210 {
211 return this.authentication;
212 }
213
214 }
215}
Static class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:147
static ContractsClient ContractsClient
XMPP Contracts Client, if such a compoent is available on the XMPP broker.
Definition: Gateway.cs:5299
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...
Base class for all HTTP authentication schemes, as defined in RFC-7235: https://datatracker....
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 SubPath
Sub-path. If a resource is found handling the request, this property contains the trailing sub-path o...
Definition: HttpRequest.cs:194
IUser User
Authenticated user, if available, or null if not available.
Definition: HttpRequest.cs:203
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:23
Task Write(byte[] Data)
Returns binary data in the response.
Base class for all synchronous HTTP resources. A synchronous resource responds within the method hand...
The server has not found anything matching the Request-URI. No indication is given of whether the con...
Contains information about one XMPP address.
Definition: XmppAddress.cs:9
CaseInsensitiveString Domain
Domain
Definition: XmppAddress.cs:97
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:21
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:1838
This filter selects objects that have a named field equal to a given value.
Class managing the contents of a temporary file. When the class is disposed, the temporary file is de...
GET Interface for HTTP resources.