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;
2using System.Collections.Generic;
3using System.IO;
4using System.Security.Cryptography;
5using System.Threading.Tasks;
14
16{
18 {
19 private readonly HttpAuthenticationScheme[] authentication;
20 private readonly LegalComponent legalComponent;
21
23 : base("/Attachments")
24 {
25 this.legalComponent = LegalComponent;
26 this.authentication = new HttpAuthenticationScheme[]
27 {
28 new LegalSignature(this.legalComponent.MainDomain.Address.Value, this.legalComponent)
29 };
30 }
31
32 public override bool HandlesSubPaths => true;
33 public override bool UserSessions => true;
34
35 public bool AllowsGET => true;
36
37 public async Task GET(HttpRequest Request, HttpResponse Response)
38 {
39 string AttachmentId = Request.SubPath.Substring(1);
40 int i = AttachmentId.IndexOf('@');
41
42 if (i > 0)
43 {
44 string AttachmentDomain = AttachmentId.Substring(i + 1);
45 AttachmentId = AttachmentId.Substring(0, i);
46
47 if (AttachmentDomain != this.legalComponent.MainDomain.Address.Value)
48 {
49 if (!Request.Header.TryGetQueryParameter("Url", out string AttachmentUrl))
50 throw new BadRequestException("Attachment URL required for accessing attachment hosted by other nodes.");
51
52 KeyValuePair<string, TemporaryFile> P = await Gateway.ContractsClient.GetAttachmentAsync(AttachmentUrl, Networking.XMPP.Contracts.SignWith.LatestApprovedId, 30000);
53 using (TemporaryFile File = P.Value)
54 {
55 Response.ContentType = P.Key;
56 File.Position = 0;
57
58 long c = File.Length;
59 int BufferSize = (int)Math.Min(65536, c);
60 byte[] Buffer = new byte[BufferSize];
61
62 while (c > 0)
63 {
64 i = await File.TryReadAllAsync(Buffer, 0, (int)Math.Min(BufferSize, c));
65 if (i <= 0)
66 throw new IOException("Unexpected end of file.");
67
68 await Response.Write(Buffer, 0, i);
69 c -= i;
70 }
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 && Attachment.UploaderLegalId.EndsWith("@" + this.legalComponent.MainDomain.Address.Value))
89 {
90 LegalIdentity Identity = await Database.FindFirstDeleteRest<LegalIdentity>(
91 new FilterFieldEqualTo("Id", Attachment.UploaderLegalId), "Created");
92
93 if (User.From.Account == Identity.Account && this.legalComponent.Server.IsServerDomain(User.From.Domain, true))
94 {
95 Authorized = true;
96 this.legalComponent.IdentityAuthorization(User.From.BareJid, User.From.BareJid, Attachment.UploaderLegalId, true);
97 }
98 }
99 }
100 else // Attachment to smart contract.
101 {
102 Authorized = this.legalComponent.IsAccessToContractAuthorized(User.From.BareJid, Attachment.ContractId);
103
104 if (!Authorized && Attachment.ContractId.EndsWith("@" + this.legalComponent.MainDomain.Address.Value))
105 {
106 Contract Contract = await Database.FindFirstDeleteRest<Contract>(
107 new FilterFieldEqualTo("ContractId", Attachment.ContractId), "Created");
108
109 if (!(Contract is null))
110 {
111 Authorized = await Contract.CanRead(User.From, this.legalComponent.Server, this.legalComponent);
112 if (Authorized)
113 this.legalComponent.ContractAuthorization(User.From.BareJid, User.From.BareJid, Attachment.ContractId, true);
114 }
115 }
116 }
117 }
118 else
119 {
120 if (string.IsNullOrEmpty(Attachment.ContractId)) // Attachment to legal identity.
121 Authorized = Request.User?.HasPrivilege("Legal.Id." + Attachment.UploaderLegalId) ?? false;
122 else // Attachment to smart contract.
123 Authorized = Request.User?.HasPrivilege("Legal.Contract." + Attachment.ContractId) ?? false;
124 }
125
126 if (!Authorized)
127 throw new ForbiddenException("Not authorized to access attachment.");
128
129 Response.ContentType = Attachment.ContentType;
130
131 using (FileStream AttachmentFile = File.OpenRead(Attachment.LocalFileName))
132 {
133 Aes Aes = Aes.Create();
134
135 Aes.BlockSize = 128;
136 Aes.KeySize = 256;
137 Aes.Mode = CipherMode.CBC;
138 Aes.Padding = PaddingMode.Zeros;
139
140 byte[] Key = new byte[32];
141 byte[] IV = new byte[16];
142
143 Array.Copy(Attachment.Salt, 0, Key, 0, 32);
144 Array.Copy(Attachment.Salt, 32, IV, 0, 16);
145
146 using (ICryptoTransform Decryptor = Aes.CreateDecryptor(Key, IV))
147 {
148 using (CryptoStream DecryptedAttachmentFile = new CryptoStream(AttachmentFile, Decryptor, CryptoStreamMode.Read))
149 {
150 byte[] Buffer = new byte[65536];
151 long c = Attachment.Size;
152
153 while (c > 0)
154 {
155 if (c > 65536)
156 i = await DecryptedAttachmentFile.TryReadAllAsync(Buffer, 0, 65536);
157 else
158 i = await DecryptedAttachmentFile.TryReadAllAsync(Buffer, 0, (int)c);
159
160 if (i <= 0)
161 throw new IOException("Unexpected end of file.");
162
163 await Response.Write(Buffer, 0, i);
164
165 c -= i;
166 }
167 }
168 }
169 }
170 }
171
173 {
174 return this.authentication;
175 }
176
177 }
178}
Static class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:126
static ContractsClient ContractsClient
XMPP Contracts Client, if such a compoent is available on the XMPP broker.
Definition: Gateway.cs:4375
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:18
HttpRequestHeader Header
Request header.
Definition: HttpRequest.cs:134
string SubPath
Sub-path. If a resource is found handling the request, this property contains the trailing sub-path o...
Definition: HttpRequest.cs:146
IUser User
Authenticated user, if available, or null if not available.
Definition: HttpRequest.cs:155
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:21
async 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...
bool EndsWith(CaseInsensitiveString value, StringComparison comparisonType)
Determines whether the end of this string instance matches the specified string when compared using t...
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
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:1079
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.