diff --git a/.travis.yml b/.travis.yml
index fd30ea6..7e5b8d0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,10 @@
language: csharp
dist: trusty
mono: none
-dotnet: 2.0.0
+dotnet: 3.1
install:
- dotnet restore
script:
- - dotnet test --framework=netcoreapp2.0 WebPush.Test/WebPush.Test.csproj
\ No newline at end of file
+ - dotnet test --framework=netcoreapp3.0 WebPush.Test/WebPush.Test.csproj
diff --git a/WebPush.Test/ECKeyHelperTest.cs b/WebPush.Test/ECKeyHelperTest.cs
index ae2ef6d..747d49c 100644
--- a/WebPush.Test/ECKeyHelperTest.cs
+++ b/WebPush.Test/ECKeyHelperTest.cs
@@ -1,6 +1,6 @@
using System.Linq;
+using System.Security.Cryptography;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Org.BouncyCastle.Crypto.Parameters;
using WebPush.Util;
namespace WebPush.Test
@@ -17,9 +17,8 @@ public class ECKeyHelperTest
public void TestGenerateKeys()
{
var keys = ECKeyHelper.GenerateKeys();
-
- var publicKey = ((ECPublicKeyParameters) keys.Public).Q.GetEncoded(false);
- var privateKey = ((ECPrivateKeyParameters) keys.Private).D.ToByteArrayUnsigned();
+ var publicKey = keys.PublicKey;
+ var privateKey = keys.PrivateKey;
var publicKeyLength = publicKey.Length;
var privateKeyLength = privateKey.Length;
@@ -31,14 +30,14 @@ public void TestGenerateKeys()
[TestMethod]
public void TestGenerateKeysNoCache()
{
- var keys1 = ECKeyHelper.GenerateKeys();
- var keys2 = ECKeyHelper.GenerateKeys();
+ var keys = ECKeyHelper.GenerateKeys();
+ var publicKey1 = keys.PublicKey;
+ var privateKey1 = keys.PrivateKey;
- var publicKey1 = ((ECPublicKeyParameters) keys1.Public).Q.GetEncoded(false);
- var privateKey1 = ((ECPrivateKeyParameters) keys1.Private).D.ToByteArrayUnsigned();
+ var keys2 = ECKeyHelper.GenerateKeys();
+ var publicKey2 = keys2.PublicKey;
+ var privateKey2 = keys2.PrivateKey;
- var publicKey2 = ((ECPublicKeyParameters) keys2.Public).Q.GetEncoded(false);
- var privateKey2 = ((ECPrivateKeyParameters) keys2.Private).D.ToByteArrayUnsigned();
Assert.IsFalse(publicKey1.SequenceEqual(publicKey2));
Assert.IsFalse(privateKey1.SequenceEqual(privateKey2));
@@ -47,12 +46,14 @@ public void TestGenerateKeysNoCache()
[TestMethod]
public void TestGetPrivateKey()
{
+#if NET48
var privateKey = UrlBase64.Decode(TestPrivateKey);
var privateKeyParams = ECKeyHelper.GetPrivateKey(privateKey);
- var importedPrivateKey = UrlBase64.Encode(privateKeyParams.D.ToByteArrayUnsigned());
+ var importedPrivateKey = UrlBase64.Encode((privateKeyParams as ECDsaCng).ExportParameters(true).D);
Assert.AreEqual(TestPrivateKey, importedPrivateKey);
+#endif
}
[TestMethod]
@@ -61,7 +62,7 @@ public void TestGetPublicKey()
var publicKey = UrlBase64.Decode(TestPublicKey);
var publicKeyParams = ECKeyHelper.GetPublicKey(publicKey);
- var importedPublicKey = UrlBase64.Encode(publicKeyParams.Q.GetEncoded(false));
+ var importedPublicKey = UrlBase64.Encode(publicKeyParams.GetECPublicKey());
Assert.AreEqual(TestPublicKey, importedPublicKey);
}
diff --git a/WebPush.Test/WebPush.Test.csproj b/WebPush.Test/WebPush.Test.csproj
index e49096a..7624825 100755
--- a/WebPush.Test/WebPush.Test.csproj
+++ b/WebPush.Test/WebPush.Test.csproj
@@ -1,15 +1,15 @@
- netcoreapp1.0;netcoreapp1.1;netcoreapp2.0
+ net45;net46;net48;netcoreapp3.0
false
-
+
-
-
+
+
@@ -17,4 +17,10 @@
+
+
+ 5.0.0
+
+
+
diff --git a/WebPush/Model/AsymmetricKeyPair.cs b/WebPush/Model/AsymmetricKeyPair.cs
new file mode 100644
index 0000000..a9049a8
--- /dev/null
+++ b/WebPush/Model/AsymmetricKeyPair.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WebPush
+{
+ public class AsymmetricKeyPair
+ {
+ public byte[] PublicKey;
+ public byte[] PrivateKey;
+ }
+}
diff --git a/WebPush/Properties/PublishProfiles/FolderProfile.pubxml b/WebPush/Properties/PublishProfiles/FolderProfile.pubxml
index 8af1ca3..04b211c 100644
--- a/WebPush/Properties/PublishProfiles/FolderProfile.pubxml
+++ b/WebPush/Properties/PublishProfiles/FolderProfile.pubxml
@@ -1,13 +1,13 @@
FileSystem
Release
- netstandard1.1
- bin\Release\PublishOutput
+ net45
+ C:\net\NugetPackage
+ Any CPU
\ No newline at end of file
diff --git a/WebPush/Util/ECKeyHelper.cs b/WebPush/Util/ECKeyHelper.cs
index 5655908..91218a9 100644
--- a/WebPush/Util/ECKeyHelper.cs
+++ b/WebPush/Util/ECKeyHelper.cs
@@ -1,64 +1,126 @@
-using System;
-using System.IO;
-using Org.BouncyCastle.Asn1;
-using Org.BouncyCastle.Asn1.Nist;
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.OpenSsl;
-using Org.BouncyCastle.Security;
+using System.Security.Cryptography;
+using System.Linq;
namespace WebPush.Util
{
internal static class ECKeyHelper
{
- public static ECPrivateKeyParameters GetPrivateKey(byte[] privateKey)
+ public static byte[] GetECPublicKey(this CngKey key)
{
- Asn1Object version = new DerInteger(1);
- Asn1Object derEncodedKey = new DerOctetString(privateKey);
- Asn1Object keyTypeParameters = new DerTaggedObject(0, new DerObjectIdentifier(@"1.2.840.10045.3.1.7"));
+ var cngKey = key.Export(CngKeyBlobFormat.EccPublicBlob);
+ return new byte[] { 0x04 }.Concat(cngKey.Skip(8)).ToArray();
+ }
- Asn1Object derSequence = new DerSequence(version, derEncodedKey, keyTypeParameters);
+ public static byte[] GetECPrivateKey(this CngKey key)
+ {
+ var cngKey = key.Export(CngKeyBlobFormat.EccPrivateBlob);
+ return cngKey.Skip(8 + 32 + 32).Take(32).ToArray();
+ }
- var base64EncodedDerSequence = Convert.ToBase64String(derSequence.GetDerEncoded());
- var pemKey = "-----BEGIN EC PRIVATE KEY-----\n";
- pemKey += base64EncodedDerSequence;
- pemKey += "\n-----END EC PRIVATE KEY----";
+ public static CngKey GetPublicKey(byte[] key)
+ {
+ var keyType = new byte[] { 0x45, 0x43, 0x4B, 0x31 };
+ var keyLength = new byte[] { 0x20, 0x00, 0x00, 0x00 };
- var reader = new StringReader(pemKey);
- var pemReader = new PemReader(reader);
- var keyPair = (AsymmetricCipherKeyPair) pemReader.ReadObject();
+ var keyImport = keyType.Concat(keyLength).Concat(key.Skip(1)).ToArray();
- return (ECPrivateKeyParameters) keyPair.Private;
+ return CngKey.Import(keyImport, CngKeyBlobFormat.EccPublicBlob);
}
+#if NET48
+ public static AsymmetricAlgorithm GetPrivateKey(byte[] privateKey)
+ {
+ return ECDsaCng.Create(new ECParameters
+ {
+ Curve = ECCurve.NamedCurves.nistP256,
+ D = privateKey,
+ Q = new ECPoint(){ X = new byte[32],Y = new byte[32]}
+ });
+ }
+ public static AsymmetricKeyPair GenerateKeys()
+ {
- public static ECPublicKeyParameters GetPublicKey(byte[] publicKey)
+ using (var cng = new ECDiffieHellmanCng(ECCurve.NamedCurves.nistP256))
+ {
+ cng.GenerateKey(ECCurve.NamedCurves.nistP256);
+ var parameters = cng.ExportParameters(true);
+ var pr = parameters.D.ToArray();
+ var pub = new byte[] { 0x04 }.Concat(parameters.Q.X).Concat(parameters.Q.Y).ToArray();
+ return new AsymmetricKeyPair() { PublicKey = pub,PrivateKey = pr };
+ }
+ }
+#else
+ private static CngKey ImportPrivCngKey(byte[] pubKey, byte[] privKey)
{
- Asn1Object keyTypeParameters = new DerSequence(new DerObjectIdentifier(@"1.2.840.10045.2.1"),
- new DerObjectIdentifier(@"1.2.840.10045.3.1.7"));
- Asn1Object derEncodedKey = new DerBitString(publicKey);
+ // to import keys to CngKey in ECCPublicKeyBlob and ECCPrivateKeyBlob format, keys should be form in specific formats as noted here :
+ // https://stackoverflow.com/a/24255090
+ // magic prefixes : https://referencesource.microsoft.com/#system.core/System/Security/Cryptography/BCryptNative.cs,fde0749a0a5f70d8,references
+ var keyType = new byte[] { 0x45, 0x43, 0x53, 0x32 };
+ var keyLength = new byte[] { 0x20, 0x00, 0x00, 0x00 };
- Asn1Object derSequence = new DerSequence(keyTypeParameters, derEncodedKey);
+ var key = pubKey.Skip(1);
- var base64EncodedDerSequence = Convert.ToBase64String(derSequence.GetDerEncoded());
- var pemKey = "-----BEGIN PUBLIC KEY-----\n";
- pemKey += base64EncodedDerSequence;
- pemKey += "\n-----END PUBLIC KEY-----";
+ var keyImport = keyType.Concat(keyLength).Concat(key).Concat(privKey).ToArray();
- var reader = new StringReader(pemKey);
- var pemReader = new PemReader(reader);
- var keyPair = pemReader.ReadObject();
- return (ECPublicKeyParameters) keyPair;
+ var cngKey = CngKey.Import(keyImport, CngKeyBlobFormat.EccPrivateBlob);
+ return cngKey;
}
+ public static ECDsaCng GetPrivateKey(byte[] privateKey)
+ {
+ var fakePubKey = new byte[64];
+ var publicKey = (new byte[] { 0x04 }).Concat(fakePubKey).ToArray();
- public static AsymmetricCipherKeyPair GenerateKeys()
+ var cngKey = ImportPrivCngKey(publicKey, privateKey);
+ var ecDsaCng = new ECDsaCng(cngKey);
+ ecDsaCng.HashAlgorithm = CngAlgorithm.ECDsaP256;
+ return ecDsaCng;
+ }
+
+ public static bool CngKeyExists(string keyName, CngProvider cp)
{
- var ecParameters = NistNamedCurves.GetByName("P-256");
- var ecSpec = new ECDomainParameters(ecParameters.Curve, ecParameters.G, ecParameters.N, ecParameters.H,
- ecParameters.GetSeed());
- var keyPairGenerator = GeneratorUtilities.GetKeyPairGenerator("ECDH");
- keyPairGenerator.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
+ if (string.IsNullOrEmpty(keyName))
+ return false;
+ try
+ {
+ return CngKey.Exists(keyName, cp);
+ }
+ catch (CryptographicException) { }
+ return false;
+ }
- return keyPairGenerator.GenerateKeyPair();
+ public static AsymmetricKeyPair GenerateKeys()
+ {
+ //CngProvider cp = CngProvider.MicrosoftSoftwareKeyStorageProvider;
+ //string keyName = "tempvapidkey";
+ //if (CngKeyExists(keyName, cp))
+ //{
+ // using (CngKey cngKey = CngKey.Open(keyName, cp))
+ // cngKey.Delete();
+ //}
+ CngKeyCreationParameters kcp = new CngKeyCreationParameters
+ {
+ //Provider = cp,
+ ExportPolicy = CngExportPolicies.AllowPlaintextExport
+ };
+ try
+ {
+ using (CngKey myKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256, null, kcp))
+ {
+ return new AsymmetricKeyPair()
+ {
+ PublicKey = myKey.GetECPublicKey(),
+ PrivateKey = myKey.GetECPrivateKey()
+ };
+ }
+ }
+ finally
+ {
+ //if (CngKeyExists(keyName, cp))
+ //{
+ // using (CngKey cngKey = CngKey.Open(keyName, cp))
+ // cngKey.Delete();
+ //}
+ }
}
+#endif
}
}
\ No newline at end of file
diff --git a/WebPush/Util/Encryptor.cs b/WebPush/Util/Encryptor.cs
index d8b294f..59957ce 100644
--- a/WebPush/Util/Encryptor.cs
+++ b/WebPush/Util/Encryptor.cs
@@ -1,25 +1,22 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
+using System.Security.Cryptography;
using System.Text;
-using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.Engines;
-using Org.BouncyCastle.Crypto.Macs;
-using Org.BouncyCastle.Crypto.Modes;
-using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Security;
+using Security.Cryptography;
namespace WebPush.Util
{
// @LogicSoftware
// Originally from https://github.com/LogicSoftware/WebPushEncryption/blob/master/src/Encryptor.cs
- internal static class Encryptor
+ public static class Encryptor
{
public static EncryptionResult Encrypt(string userKey, string userSecret, string payload)
{
- var userKeyBytes = UrlBase64.Decode(userKey);
- var userSecretBytes = UrlBase64.Decode(userSecret);
- var payloadBytes = Encoding.UTF8.GetBytes(payload);
+ byte[] userKeyBytes = UrlBase64.Decode(userKey);
+ byte[] userSecretBytes = UrlBase64.Decode(userSecret);
+ byte[] payloadBytes = Encoding.UTF8.GetBytes(payload);
return Encrypt(userKeyBytes, userSecretBytes, payloadBytes);
}
@@ -27,21 +24,27 @@ public static EncryptionResult Encrypt(string userKey, string userSecret, string
public static EncryptionResult Encrypt(byte[] userKey, byte[] userSecret, byte[] payload)
{
var salt = GenerateSalt(16);
- var serverKeyPair = ECKeyHelper.GenerateKeys();
- var ecdhAgreement = AgreementUtilities.GetBasicAgreement("ECDH");
- ecdhAgreement.Init(serverKeyPair.Private);
+ byte[] serverPublicKey = null;
+ byte[] key = null;
- var userPublicKey = ECKeyHelper.GetPublicKey(userKey);
+ var cgnKey = ImportCngKeyFromPublicKey(userKey);
+ using (ECDiffieHellmanCng alice = new ECDiffieHellmanCng(256))
+ {
+ alice.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hmac;
+ alice.HashAlgorithm = CngAlgorithm.Sha256;
+ alice.HmacKey = userSecret;
- var key = ecdhAgreement.CalculateAgreement(userPublicKey).ToByteArrayUnsigned();
- var serverPublicKey = ((ECPublicKeyParameters) serverKeyPair.Public).Q.GetEncoded(false);
+ serverPublicKey = ImportPublicKeyFromCngKey(alice.PublicKey.ToByteArray());
+ key = alice.DeriveKeyMaterial(cgnKey);
+ }
- var prk = HKDF(userSecret, key, Encoding.UTF8.GetBytes("Content-Encoding: auth\0"), 32);
- var cek = HKDF(salt, prk, CreateInfoChunk("aesgcm", userKey, serverPublicKey), 16);
- var nonce = HKDF(salt, prk, CreateInfoChunk("nonce", userKey, serverPublicKey), 12);
+ var prk = HKDFSecondStep(key, Encoding.UTF8.GetBytes("Content-Encoding: auth\0"), 32);
+ byte[] cek = HKDF(salt, prk, CreateInfoChunk("aesgcm", userKey, serverPublicKey), 16);
+ byte[] nonce = HKDF(salt, prk, CreateInfoChunk("nonce", userKey, serverPublicKey), 12);
var input = AddPaddingToInput(payload);
+
var encryptedMessage = EncryptAes(nonce, cek, input);
return new EncryptionResult
@@ -52,6 +55,23 @@ public static EncryptionResult Encrypt(byte[] userKey, byte[] userSecret, byte[]
};
}
+ private static CngKey ImportCngKeyFromPublicKey(byte[] userKey)
+ {
+ var keyType = new byte[] { 0x45, 0x43, 0x4B, 0x31 };
+ var keyLength = new byte[] { 0x20, 0x00, 0x00, 0x00 };
+
+ var keyImport = keyType.Concat(keyLength).Concat(userKey.Skip(1)).ToArray();
+
+ return CngKey.Import(keyImport, CngKeyBlobFormat.EccPublicBlob);
+ }
+
+ private static byte[] ImportPublicKeyFromCngKey(byte[] cngKey)
+ {
+ var keyImport = (new byte[] { 0x04 }).Concat(cngKey.Skip(8)).ToArray();
+
+ return keyImport;
+ }
+
private static byte[] GenerateSalt(int length)
{
var salt = new byte[length];
@@ -68,25 +88,39 @@ private static byte[] AddPaddingToInput(byte[] data)
return input;
}
+
private static byte[] EncryptAes(byte[] nonce, byte[] cek, byte[] message)
{
- var cipher = new GcmBlockCipher(new AesEngine());
- var parameters = new AeadParameters(new KeyParameter(cek), 128, nonce);
- cipher.Init(true, parameters);
+ using (AuthenticatedAesCng aes = new AuthenticatedAesCng())
+ {
+ aes.CngMode = CngChainingMode.Gcm;
+
+ aes.Key = cek;
- //Generate Cipher Text With Auth Tag
- var cipherText = new byte[cipher.GetOutputSize(message.Length)];
- var len = cipher.ProcessBytes(message, 0, message.Length, cipherText, 0);
- cipher.DoFinal(cipherText, len);
+ aes.IV = nonce;
- //byte[] tag = cipher.GetMac();
- return cipherText;
+ using (MemoryStream ms = new MemoryStream())
+ using (var encryptor = aes.CreateAuthenticatedEncryptor())
+ using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
+ {
+ // Encrypt the secret message
+ cs.Write(message, 0, message.Length);
+
+ // Finish the encryption and get the output authentication tag and ciphertext
+ cs.FlushFinalBlock();
+ var ciphertext = ms.ToArray();
+
+ var tag = encryptor.GetTag();
+
+ return ciphertext.Concat(tag).ToArray();
+ }
+ }
}
public static byte[] HKDFSecondStep(byte[] key, byte[] info, int length)
{
- var hmac = new HmacSha256(key);
- var infoAndOne = info.Concat(new byte[] {0x01}).ToArray();
+ var hmac = new HMACSHA256(key);
+ var infoAndOne = info.Concat(new byte[] { 0x01 }).ToArray();
var result = hmac.ComputeHash(infoAndOne);
if (result.Length > length)
@@ -99,7 +133,7 @@ public static byte[] HKDFSecondStep(byte[] key, byte[] info, int length)
public static byte[] HKDF(byte[] salt, byte[] prk, byte[] info, int length)
{
- var hmac = new HmacSha256(salt);
+ var hmac = new HMACSHA256(salt);
var key = hmac.ComputeHash(prk);
return HKDFSecondStep(key, info, length);
@@ -127,24 +161,4 @@ public static byte[] CreateInfoChunk(string type, byte[] recipientPublicKey, byt
return output.ToArray();
}
}
-
- public class HmacSha256
- {
- private readonly HMac _hmac;
-
- public HmacSha256(byte[] key)
- {
- _hmac = new HMac(new Sha256Digest());
- _hmac.Init(new KeyParameter(key));
- }
-
- public byte[] ComputeHash(byte[] value)
- {
- var resBuf = new byte[_hmac.GetMacSize()];
- _hmac.BlockUpdate(value, 0, value.Length);
- _hmac.DoFinal(resBuf, 0);
-
- return resBuf;
- }
- }
}
\ No newline at end of file
diff --git a/WebPush/Util/JwsSigner.cs b/WebPush/Util/JwsSigner.cs
index f000ff2..a165e8c 100644
--- a/WebPush/Util/JwsSigner.cs
+++ b/WebPush/Util/JwsSigner.cs
@@ -1,19 +1,16 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using Newtonsoft.Json;
-using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Crypto.Signers;
+using System.Security.Cryptography;
namespace WebPush.Util
{
internal class JwsSigner
{
- private readonly ECPrivateKeyParameters _privateKey;
+ private readonly AsymmetricAlgorithm _privateKey;
- public JwsSigner(ECPrivateKeyParameters privateKey)
+ public JwsSigner(AsymmetricAlgorithm privateKey)
{
_privateKey = privateKey;
}
@@ -30,24 +27,17 @@ public string GenerateSignature(Dictionary header, Dictionary GetVapidHeaders(string audience, string
ValidatePublicKey(publicKey);
ValidatePrivateKey(privateKey);
+ var decodedPublicKey = UrlBase64.Decode(publicKey);
var decodedPrivateKey = UrlBase64.Decode(privateKey);
if (expiration == -1)
@@ -50,25 +50,27 @@ public static Dictionary GetVapidHeaders(string audience, string
}
else
{
- ValidateExpiration(expiration);
+ ValidateExpiration(expiration);
}
- var header = new Dictionary {{"typ", "JWT"}, {"alg", "ES256"}};
+ var header = new Dictionary { { "typ", "JWT" }, { "alg", "ES256" } };
- var jwtPayload = new Dictionary {{"aud", audience}, {"exp", expiration}, {"sub", subject}};
+ var jwtPayload = new Dictionary { { "aud", audience }, { "exp", expiration }, { "sub", subject } };
- var signingKey = ECKeyHelper.GetPrivateKey(decodedPrivateKey);
+ using (var signingKey = ECKeyHelper.GetPrivateKey(decodedPrivateKey))
+ {
- var signer = new JwsSigner(signingKey);
- var token = signer.GenerateSignature(header, jwtPayload);
+ var signer = new JwsSigner(signingKey);
+ var token = signer.GenerateSignature(header, jwtPayload);
- var results = new Dictionary
- {
- {"Authorization", "WebPush " + token}, {"Crypto-Key", "p256ecdsa=" + publicKey}
- };
+ var results = new Dictionary
+ {
+ {"Authorization", "WebPush " + token}, {"Crypto-Key", "p256ecdsa=" + publicKey}
+ };
- return results;
+ return results;
+ }
}
public static void ValidateAudience(string audience)
@@ -152,7 +154,7 @@ private static void ValidateExpiration(long expiration)
private static long UnixTimeNow()
{
var timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0);
- return (long) timeSpan.TotalSeconds;
+ return (long)timeSpan.TotalSeconds;
}
private static byte[] ByteArrayPadLeft(byte[] src, int size)
diff --git a/WebPush/WebPush.csproj b/WebPush/WebPush.csproj
index 016d102..6db90d8 100755
--- a/WebPush/WebPush.csproj
+++ b/WebPush/WebPush.csproj
@@ -1,7 +1,7 @@
- netstandard1.1;netstandard2.0;net45;net46
+ net45;net46;net48;netcoreapp3.0;
true
1.0.11
Cory Thompson
@@ -24,8 +24,15 @@
-
+
-
-
+
+
+
+
+
+ 5.0.0
+
+
+
\ No newline at end of file
diff --git a/WebPush/WebPushClient.cs b/WebPush/WebPushClient.cs
index 547d1e6..c57306e 100755
--- a/WebPush/WebPushClient.cs
+++ b/WebPush/WebPushClient.cs
@@ -26,14 +26,14 @@ public class WebPushClient : IDisposable
public WebPushClient()
{
-
+
}
public WebPushClient(HttpClient httpClient)
{
_httpClient = httpClient;
}
-
+
public WebPushClient(HttpClientHandler httpClientHandler)
{
_httpClientHandler = httpClientHandler;
@@ -142,7 +142,7 @@ public HttpRequestMessage GenerateRequestDetails(PushSubscription subscription,
if (options != null)
{
- var validOptionsKeys = new List {"headers", "gcmAPIKey", "vapidDetails", "TTL"};
+ var validOptionsKeys = new List { "headers", "gcmAPIKey", "vapidDetails", "TTL" };
foreach (var key in options.Keys)
{
if (!validOptionsKeys.Contains(key))
@@ -181,7 +181,7 @@ public HttpRequestMessage GenerateRequestDetails(PushSubscription subscription,
}
//at this stage ttl cannot be null.
- timeToLive = (int) ttl;
+ timeToLive = (int)ttl;
}
}
@@ -277,7 +277,7 @@ public void SendNotification(PushSubscription subscription, string payload = nul
/// The vapid details for the notification.
public void SendNotification(PushSubscription subscription, string payload, VapidDetails vapidDetails)
{
- var options = new Dictionary {["vapidDetails"] = vapidDetails};
+ var options = new Dictionary { ["vapidDetails"] = vapidDetails };
SendNotification(subscription, payload, options);
}
@@ -290,7 +290,7 @@ public void SendNotification(PushSubscription subscription, string payload, Vapi
/// The GCM API key
public void SendNotification(PushSubscription subscription, string payload, string gcmApiKey)
{
- var options = new Dictionary {["gcmAPIKey"] = gcmApiKey};
+ var options = new Dictionary { ["gcmAPIKey"] = gcmApiKey };
SendNotification(subscription, payload, options);
}
@@ -323,7 +323,7 @@ public async Task SendNotificationAsync(PushSubscription subscription, string pa
public async Task SendNotificationAsync(PushSubscription subscription, string payload,
VapidDetails vapidDetails)
{
- var options = new Dictionary {["vapidDetails"] = vapidDetails};
+ var options = new Dictionary { ["vapidDetails"] = vapidDetails };
await SendNotificationAsync(subscription, payload, options);
}
@@ -336,7 +336,7 @@ public async Task SendNotificationAsync(PushSubscription subscription, string pa
/// The GCM API key
public async Task SendNotificationAsync(PushSubscription subscription, string payload, string gcmApiKey)
{
- var options = new Dictionary {["gcmAPIKey"] = gcmApiKey};
+ var options = new Dictionary { ["gcmAPIKey"] = gcmApiKey };
await SendNotificationAsync(subscription, payload, options);
}
@@ -355,7 +355,7 @@ private static void HandleResponse(HttpResponseMessage response, PushSubscriptio
}
// Error
- var message = @"Received unexpected response code: " + (int) response.StatusCode;
+ var message = @"Received unexpected response code: " + (int)response.StatusCode;
switch (response.StatusCode)
{
case HttpStatusCode.BadRequest:
@@ -366,7 +366,7 @@ private static void HandleResponse(HttpResponseMessage response, PushSubscriptio
message = "Payload too large";
break;
- case (HttpStatusCode) 429:
+ case (HttpStatusCode)429:
message = "Too many request.";
break;
@@ -378,7 +378,7 @@ private static void HandleResponse(HttpResponseMessage response, PushSubscriptio
throw new WebPushException(message, response.StatusCode, response.Headers, subscription);
}
-
+
public void Dispose()
{
if (_httpClient != null && _isHttpClientInternallyCreated)