1212using System . Text . Json . Serialization ;
1313using System . Threading . Tasks ;
1414
15+ using EnsureThat ;
16+
1517using Microsoft . Extensions . Logging ;
1618using Microsoft . Extensions . Logging . Abstractions ;
1719
@@ -96,6 +98,8 @@ public class Bundle
9698 /// <param name="logger">The logger to use for logging.</param>
9799 public Bundle ( string rootPath , string bundleName , ILogger ? logger = null ) : this ( rootPath , logger )
98100 {
101+ Ensure . String . IsNotNullOrEmpty ( bundleName . Trim ( ) , nameof ( bundleName ) ) ;
102+
99103 _bundleName = bundleName ;
100104 }
101105
@@ -106,6 +110,8 @@ public Bundle(string rootPath, string bundleName, ILogger? logger = null) : this
106110 /// <param name="logger">The logger to use for logging.</param>
107111 public Bundle ( string rootPath , ILogger ? logger = null )
108112 {
113+ Ensure . String . IsNotNullOrEmpty ( rootPath . Trim ( ) , nameof ( rootPath ) ) ;
114+
109115 RootPath = Path . GetFullPath ( rootPath ) ;
110116 Logger = logger ?? NullLogger . Instance ;
111117 }
@@ -115,10 +121,16 @@ public Bundle(string rootPath, ILogger? logger = null)
115121 /// </summary>
116122 private void EnsureWritable ( )
117123 {
124+ Logger . LogDebug ( "Checking if bundle is read-only" ) ;
125+
118126 if ( IsReadOnly )
119127 {
120- throw new InvalidOperationException ( "Bundle is read-only" ) ;
128+ Logger . LogError ( "Bundle is read-only" ) ;
129+
130+ throw new InvalidOperationException ( "Bundle is read-only" ) ; ;
121131 }
132+
133+ Logger . LogDebug ( "Bundle is writable" ) ;
122134 }
123135
124136 /// <summary>
@@ -178,6 +190,8 @@ public void LoadFromBytes(byte[] bundleContent)
178190 throw new InvalidOperationException ( "The bundle is already loaded" ) ;
179191 }
180192
193+ Ensure . Collection . HasItems ( bundleContent , nameof ( bundleContent ) ) ;
194+
181195 IsReadOnly = true ;
182196 _rawZipContents = bundleContent ;
183197
@@ -231,6 +245,13 @@ public void AddEntry(string path, string destinationPath = "./", string? rootPat
231245 {
232246 EnsureWritable ( ) ;
233247
248+ Ensure . String . IsNotNullOrEmpty ( path . Trim ( ) , nameof ( path ) ) ;
249+
250+ if ( ! File . Exists ( path ) )
251+ {
252+ throw new FileNotFoundException ( "File not found" , path ) ;
253+ }
254+
234255 Logger . LogInformation ( "Adding file: {path}" , path ) ;
235256
236257 if ( ! destinationPath . EndsWith ( '/' ) )
@@ -267,10 +288,12 @@ public void Sign(X509Certificate2 certificate, RSA privateKey)
267288 {
268289 EnsureWritable ( ) ;
269290
291+ Ensure . Any . IsNotNull ( certificate , nameof ( certificate ) ) ;
292+ Ensure . Any . IsNotNull ( privateKey , nameof ( privateKey ) ) ;
293+
270294 Logger . LogInformation ( "Signing bundle with certificate: {name}" , certificate . Subject ) ;
271295
272- var manifestData = Export ( Manifest , SourceGenerationManifestContext . Default ) ;
273- var signature = privateKey . SignData ( manifestData , HashAlgorithmName . SHA512 , RSASignaturePadding . Pkcs1 ) ;
296+ Logger . LogDebug ( "Exporting certificate" ) ;
274297 var cert = Convert . ToBase64String ( certificate . Export ( X509ContentType . Cert ) ) ;
275298 var name = certificate . GetCertHashString ( ) ;
276299
@@ -280,6 +303,10 @@ public void Sign(X509Certificate2 certificate, RSA privateKey)
280303 pemBuilder . AppendLine ( "-----END CERTIFICATE-----" ) ;
281304 string pemContents = pemBuilder . ToString ( ) ;
282305
306+ Logger . LogDebug ( "Signing manifest" ) ;
307+ var manifestData = Export ( Manifest , SourceGenerationManifestContext . Default ) ;
308+ var signature = privateKey . SignData ( manifestData , HashAlgorithmName . SHA512 , RSASignaturePadding . Pkcs1 ) ;
309+
283310 Logger . LogDebug ( "Embedding file: {name} in the bundle" , name ) ;
284311 _newEmbeddedFiles [ name ] = Encoding . UTF8 . GetBytes ( pemContents ) ;
285312
@@ -294,6 +321,8 @@ public void Sign(X509Certificate2 certificate, RSA privateKey)
294321 /// <returns>True if the file is valid; otherwise, false.</returns>
295322 public bool VerifyFileIntegrity ( string entryName )
296323 {
324+ Ensure . String . IsNotNullOrEmpty ( entryName . Trim ( ) , nameof ( entryName ) ) ;
325+
297326 Logger . LogInformation ( "Verifying file integrity: {name}" , entryName ) ;
298327
299328 byte [ ] hash ;
@@ -328,15 +357,16 @@ public bool VerifyFileIntegrity(string entryName)
328357 /// <returns>True if the signature is valid; otherwise, false.</returns>
329358 public bool VerifySignature ( string certificateHash )
330359 {
360+ Ensure . String . IsNotNullOrEmpty ( certificateHash . Trim ( ) , nameof ( certificateHash ) ) ;
361+ byte [ ] hash = Signatures . Entries [ certificateHash ] ;
362+
331363 X509Certificate2 certificate = GetCertificate ( certificateHash ) ;
332- var pubKey = certificate . GetRSAPublicKey ( ) ;
364+ var pubKey = certificate . GetRSAPublicKey ( ) ?? throw new CryptographicException ( "Public key not found" ) ;
333365
334366 Logger . LogInformation ( "Verifying signature with certificate: {name}" , certificate . Subject ) ;
335367
336- if ( pubKey == null ) return false ;
337-
338368 var manifestData = Export ( Manifest , SourceGenerationManifestContext . Default ) ;
339- bool result = pubKey . VerifyData ( manifestData , Signatures . Entries [ certificateHash ] , HashAlgorithmName . SHA512 , RSASignaturePadding . Pkcs1 ) ;
369+ bool result = pubKey . VerifyData ( manifestData , hash , HashAlgorithmName . SHA512 , RSASignaturePadding . Pkcs1 ) ;
340370
341371 Logger . LogInformation ( "Signature verification result for certificate {name}: {result}" , certificate . Subject , result ) ;
342372
@@ -352,6 +382,8 @@ public bool VerifySignature(string certificateHash)
352382 /// <returns>True if the certificate is valid; otherwise, false.</returns>
353383 public bool VerifyCertificate ( string certificateHash , out X509ChainStatus [ ] statuses , X509ChainPolicy ? policy = null )
354384 {
385+ Ensure . String . IsNotNullOrEmpty ( certificateHash . Trim ( ) , nameof ( certificateHash ) ) ;
386+
355387 X509Certificate2 certificate = GetCertificate ( certificateHash ) ;
356388 return VerifyCertificate ( certificate , out statuses , policy ) ;
357389 }
@@ -376,6 +408,8 @@ public bool VerifyCertificate(string certificateHash, X509ChainPolicy? policy =
376408 /// <returns>True if the certificate is valid; otherwise, false.</returns>
377409 public bool VerifyCertificate ( X509Certificate2 certificate , out X509ChainStatus [ ] statuses , X509ChainPolicy ? policy = null )
378410 {
411+ Ensure . Any . IsNotNull ( certificate , nameof ( certificate ) ) ;
412+
379413 X509Chain chain = new X509Chain
380414 {
381415 ChainPolicy = policy ?? new X509ChainPolicy ( )
@@ -414,6 +448,8 @@ public bool VerifyCertificate(X509Certificate2 certificate, X509ChainPolicy? pol
414448 /// <returns>The certificate.</returns>
415449 public X509Certificate2 GetCertificate ( string certificateHash )
416450 {
451+ Ensure . String . IsNotNullOrEmpty ( certificateHash . Trim ( ) , nameof ( certificateHash ) ) ;
452+
417453 Logger . LogInformation ( "Getting certificate with hash: {hash}" , certificateHash ) ;
418454
419455 if ( ! _certCache . TryGetValue ( certificateHash , out X509Certificate2 ? certificate ) )
@@ -435,7 +471,7 @@ public X509Certificate2 GetCertificate(string certificateHash)
435471 Logger . LogDebug ( "Certificate with hash {hash} found in cache" , certificateHash ) ;
436472 }
437473
438- return certificate ;
474+ return certificate ;
439475 }
440476
441477 /// <summary>
@@ -445,6 +481,8 @@ public X509Certificate2 GetCertificate(string certificateHash)
445481 /// <returns>A stream for the file.</returns>
446482 public Stream GetFileStream ( string entryName )
447483 {
484+ Ensure . String . IsNotNullOrEmpty ( entryName . Trim ( ) , nameof ( entryName ) ) ;
485+
448486 Logger . LogInformation ( "Getting file stream for entry: {name}" , entryName ) ;
449487
450488 if ( Manifest . StoreOriginalFiles )
@@ -471,6 +509,8 @@ public Stream GetFileStream(string entryName)
471509 /// <returns>The bytes of the file.</returns>
472510 public byte [ ] GetFileBytes ( string entryName )
473511 {
512+ Ensure . String . IsNotNullOrEmpty ( entryName . Trim ( ) , nameof ( entryName ) ) ;
513+
474514 Logger . LogInformation ( "Getting file data for entry: {name}" , entryName ) ;
475515
476516 if ( Manifest . StoreOriginalFiles )
@@ -497,6 +537,9 @@ public byte[] GetFileBytes(string entryName)
497537 /// <returns>A byte array containing the exported data.</returns>
498538 protected byte [ ] Export ( object structuredData , JsonSerializerContext jsonSerializerContext )
499539 {
540+ Ensure . Any . IsNotNull ( structuredData , nameof ( structuredData ) ) ;
541+ Ensure . Any . IsNotNull ( jsonSerializerContext , nameof ( jsonSerializerContext ) ) ;
542+
500543 Logger . LogInformation ( "Exporting data from a {type} object as byte array" , structuredData . GetType ( ) . Name ) ;
501544
502545 var data = JsonSerializer . Serialize ( structuredData , structuredData . GetType ( ) , jsonSerializerContext ) ;
@@ -516,6 +559,8 @@ protected byte[] Export(object structuredData, JsonSerializerContext jsonSeriali
516559#endif
517560 protected byte [ ] Export ( object structuredData )
518561 {
562+ Ensure . Any . IsNotNull ( structuredData , nameof ( structuredData ) ) ;
563+
519564 Logger . LogInformation ( "Exporting data from a {type} object as byte array" , structuredData . GetType ( ) . Name ) ;
520565
521566 var data = JsonSerializer . Serialize ( structuredData , SerializerOptions ) ;
@@ -560,6 +605,9 @@ public void Update()
560605 /// <returns>A byte array containing the entry data.</returns>
561606 protected byte [ ] ReadEntry ( ZipArchive zip , string entryName )
562607 {
608+ Ensure . Any . IsNotNull ( zip , nameof ( zip ) ) ;
609+ Ensure . String . IsNotNullOrEmpty ( entryName . Trim ( ) , nameof ( entryName ) ) ;
610+
563611 if ( ! _fileCache . TryGetValue ( entryName , out var data ) )
564612 {
565613 Logger . LogDebug ( "Entry {name} not found in cache" , entryName ) ;
@@ -589,6 +637,8 @@ protected byte[] ReadEntry(ZipArchive zip, string entryName)
589637 /// <returns>A byte array containing the stream data.</returns>
590638 private static byte [ ] ReadStream ( Stream stream )
591639 {
640+ Ensure . Any . IsNotNull ( stream , nameof ( stream ) ) ;
641+
592642 MemoryStream ms = new ( ) ;
593643 stream . CopyTo ( ms ) ;
594644 return ms . ToArray ( ) ;
@@ -603,6 +653,10 @@ private static byte[] ReadStream(Stream stream)
603653 /// <param name="data">The data to write.</param>
604654 protected void WriteEntry ( ZipArchive zip , string entryName , byte [ ] data )
605655 {
656+ Ensure . Any . IsNotNull ( zip , nameof ( zip ) ) ;
657+ Ensure . String . IsNotNullOrEmpty ( entryName . Trim ( ) , nameof ( entryName ) ) ;
658+ Ensure . Collection . HasItems ( data , nameof ( data ) ) ;
659+
606660 Logger . LogDebug ( "Writing entry: {name} to the bundle" , entryName ) ;
607661
608662 ZipArchiveEntry ? tempEntry ;
@@ -635,6 +689,8 @@ protected void WriteEntry(ZipArchive zip, string entryName, byte[] data)
635689 /// <returns>A byte array containing the hash.</returns>
636690 static byte [ ] ComputeSHA512Hash ( Stream stream )
637691 {
692+ Ensure . Any . IsNotNull ( stream , nameof ( stream ) ) ;
693+
638694 using var sha512 = SHA512 . Create ( ) ;
639695 return sha512 . ComputeHash ( stream ) ;
640696 }
@@ -646,6 +702,8 @@ static byte[] ComputeSHA512Hash(Stream stream)
646702 /// <returns>A byte array containing the hash.</returns>
647703 static byte [ ] ComputeSHA512Hash ( byte [ ] data )
648704 {
705+ Ensure . Collection . HasItems ( data , nameof ( data ) ) ;
706+
649707 using var sha512 = SHA512 . Create ( ) ;
650708 return sha512 . ComputeHash ( data ) ;
651709 }
0 commit comments