4using System.Runtime.ExceptionServices;
5using System.Threading.Tasks;
19 private static int expectedBlockSignature = 0;
22 : base(
"/UploadSignature")
26 public override bool HandlesSubPaths =>
false;
27 public override bool UserSessions =>
true;
32 KeyValuePair<bool, int> P = await
UploadPackage.Upload(Request, Response, expectedBlockSignature, signatureFilePerSession,
"signature",
false);
33 expectedBlockSignature = P.Value;
37 UploadPackage.UploadRec PackageRec;
38 UploadPackage.UploadRec SignatureRec;
49 SignatureRec = GetAndRemoveFile(
HttpSessionID, signatureFilePerSession);
51 CopyPackage(PackageRec, SignatureRec, TabID, Request.
Session[
"packageFileName"]?.ToString(), Request.
RemoteEndPoint);
55 private static UploadPackage.UploadRec GetAndRemoveFile(
string SessionID, Dictionary<string, UploadPackage.UploadRec> Files)
61 Files.Remove(SessionID);
69 private static async
void CopyPackage(UploadPackage.UploadRec PackageRec, UploadPackage.UploadRec SignatureRec,
string TabID,
70 string PackageFileName,
string RemoteEndPoint)
74 if (PackageRec.File.Length >
int.MaxValue)
75 throw new Exception(
"Package file too large.");
77 XmlDocument Doc =
new XmlDocument()
79 PreserveWhitespace =
true
81 SignatureRec.File.Position = 0;
82 Doc.Load(SignatureRec.File);
84 if (Doc.DocumentElement is
null ||
85 Doc.DocumentElement.LocalName !=
"Signatures" ||
86 Doc.DocumentElement.NamespaceURI !=
"http://waher.se/Schema/Signatures.xsd")
88 throw new Exception(
"Invalid signature file.");
91 byte[] Signature =
null;
93 foreach (XmlNode N
in Doc.DocumentElement.ChildNodes)
95 if (N is XmlElement E && E.LocalName ==
"Signature" &&
XML.
Attribute(E,
"fileName") == PackageFileName)
99 Signature = Convert.FromBase64String(E.InnerText);
103 throw new Exception(
"Invalid signature.");
109 if (Signature is
null)
110 throw new Exception(
"Signature for corresponding package file not included in uploaded signature file.");
112 await CopyPackage(PackageRec, Signature, TabID, PackageFileName, RemoteEndPoint);
122 PackageRec.File.Dispose();
123 SignatureRec.File.Dispose();
127 internal static async Task CopyPackage(UploadPackage.UploadRec PackageRec,
byte[] Signature,
string TabID,
128 string PackageFileName,
string RemoteEndPoint)
130 DateTime Now = DateTime.UtcNow;
131 Package Package = await Provisioning.ProvisioningComponent.GetPackage(PackageFileName);
132 long Size = PackageRec.File.Length;
133 bool PrevDownloadable;
134 bool Downloadable = PackageRec.MakeDownloadable;
138 PrevDownloadable =
false;
142 FileName = PackageFileName,
143 Signature = Signature,
144 RemoteEndPoint = RemoteEndPoint,
146 Supersedes = DateTime.MinValue,
150 Installed = DateTime.MinValue,
161 Package.Signature = Signature;
162 Package.RemoteEndPoint = RemoteEndPoint;
164 Package.Published = Now;
165 Package.Bytes = Size;
166 Package.Downloadable = Downloadable;
175 bool InstallPackage = Package.Installed > DateTime.MinValue;
181 PackageRec.File.Position = 0;
183 throw new Exception(
"Invalid IoT Broker package. Signature invalid.");
186 using (FileStream f = File.Create(Path.Combine(
XmppServerModule.PackagesFolder, PackageFileName)))
188 PackageRec.File.Position = 0;
189 await PackageRec.File.CopyToAsync(f);
192 if (PackageRec.MakeDownloadable)
196 if (!Directory.Exists(DownloadsFolder))
197 Directory.CreateDirectory(DownloadsFolder);
199 using (FileStream f = File.Create(Path.Combine(DownloadsFolder, PackageFileName)))
201 PackageRec.File.Position = 0;
202 await PackageRec.File.CopyToAsync(f);
209 ExceptionDispatchInfo.Capture(ex).Throw();
212 if (PrevDownloadable && !Downloadable)
216 if (File.Exists(FullPath))
217 File.Delete(FullPath);
226 "\", \"supersedes\": \"" + (Package.Supersedes == DateTime.MinValue ? string.Empty :
Package.
Supersedes.ToString()) +
229 "\", \"signature\": \"<a href='javascript:Popup.Alert(\\\"" + s +
"\\\")'>" + s.Substring(0, 10) +
"...</a>" +
230 "\", \"button\": \"<button class='negButtonSm' onclick='DeletePackage(\\\"" +
Package.
FileName.
Replace(
"\"",
"\\\"") +
"\\\")'>Delete</button>" +
231 "\", \"message\": \"Package successfully uploaded.\"}",
true,
"User");
235 if (NewSoftware || InstallPackage)
Helps with parsing of commong data types.
static string JsonStringEncode(string s)
Encodes a string for inclusion in JSON.
Helps with common XML-related tasks.
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
The ClientEvents class allows applications to push information asynchronously to web clients connecte...
static Task< int > PushEvent(string[] TabIDs, string Type, object Data)
Puses an event to a set of Tabs, given their Tab IDs.
Static class managing data export.
static string FormatBytes(double Bytes)
Formats a file size using appropriate unit.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
Base class for all HTTP fields.
Represents an HTTP request.
HttpRequestHeader Header
Request header.
string RemoteEndPoint
Remote end-point.
SessionVariables Session
Contains session states, if the resource requires sessions, or null otherwise.
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"
Represets a response of an HTTP client request.
Base class for all synchronous HTTP resources. A synchronous resource responds within the method hand...
CaseInsensitiveString Replace(CaseInsensitiveString oldValue, CaseInsensitiveString newValue)
Returns a new string in which all occurrences of a specified string in the current instance are repla...
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static async Task Update(object Object)
Updates an object in the database.
static async Task Delete(object Object)
Deletes an object in the database.
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
Identity of the IoT Broker package.
const string FileName
IoTBroker.package
Contains information about a software package.
bool Downloadable
If package should be made downloadable via web interface.
string RemoteEndPoint
Remote Endpoint from where the package was downloaded or uploaded.
byte[] Signature
Cryptographic signature of package, as calculated by the issuer of the package.
CaseInsensitiveString FileName
Filename of package.
DateTime Published
When package was published.
byte[] AesKey
Symmetric cipher used to encrypt package file.
long Bytes
Number of bytes of package.
DateTime Supersedes
Timestamp of superceded package.
string RelativeUrl
Relative URL of package.
DateTime Created
When package record was created
bool AllowsPOST
If the POST method is allowed.
async Task POST(HttpRequest Request, HttpResponse Response)
Executes the POST method on the resource.
Service Module hosting the XMPP broker and its components.
static bool IsContentPackage(Package Package)
Checks if a Package is a Content-Only package.
POST Interface for HTTP resources.