diff --git a/Examples/VapidHeaders.cs b/Examples/VapidHeaders.cs
new file mode 100644
index 0000000..c651e16
--- /dev/null
+++ b/Examples/VapidHeaders.cs
@@ -0,0 +1,22 @@
+#!/usr/bin/env dotnet
+#:package ClosureOSS.WebPush@2.4.1
+using WebPush;
+
+var uri = new Uri("https://server.example.com/notify");
+var audience = uri.Scheme + Uri.SchemeDelimiter + uri.Host;
+var vapidKeys = VapidHelper.GenerateVapidKeys();
+
+
+var headers = VapidHelper.GetVapidHeaders(
+ audience,
+ @"mailto: example@example.com",
+ vapidKeys.PublicKey,
+ vapidKeys.PrivateKey,
+ DateTime.Now.AddDays(2),
+ ContentEncoding.Aes128gcm
+);
+
+foreach (var header in headers)
+{
+ Console.WriteLine($"{header.Key}: {header.Value}");
+}
diff --git a/Examples/VapidKeys.cs b/Examples/VapidKeys.cs
new file mode 100644
index 0000000..10ed000
--- /dev/null
+++ b/Examples/VapidKeys.cs
@@ -0,0 +1,8 @@
+#!/usr/bin/env dotnet
+#:package ClosureOSS.WebPush@2.4.1
+using WebPush;
+
+var vapidKeys = VapidHelper.GenerateVapidKeys();
+Console.WriteLine($"Public key: {vapidKeys.PublicKey}");
+Console.WriteLine($"Private key: {vapidKeys.PrivateKey}");
+
diff --git a/Examples/WebPushMessage.cs b/Examples/WebPushMessage.cs
new file mode 100644
index 0000000..4aecb18
--- /dev/null
+++ b/Examples/WebPushMessage.cs
@@ -0,0 +1,30 @@
+#!/usr/bin/env dotnet
+#:package ClosureOSS.WebPush@2.4.1
+using WebPush;
+
+var vapidKeys = VapidHelper.GenerateVapidKeys();
+vapidKeys.Subject = @"mailto:user@example.net";
+// example keys
+var p256dh = @"BIwCq8tz028CFq9YFQ56kipZ633EK628l4-u6FcPHTGkS_cqTsV-9MRRAGEu56UmfXQ-8lIg7QXgUTFmzedzMHM";
+var auth = @"eSZCfw7d6bXE0erlgnLe_Q";
+var webPushClient = new WebPushClient();
+var subscription = new PushSubscription("https://server.example.com/notify/Avv3mSO...", p256dh, auth);
+var options = new WebPushOptions
+{
+ VapidDetails = vapidKeys,
+ Topic = "Example",
+};
+
+
+var message = webPushClient.GenerateRequestDetails(subscription, "A payload", options);
+
+Console.WriteLine($"{message.Method} {message.RequestUri}");
+Console.WriteLine();
+foreach (var header in message.Headers){
+ foreach (var value in header.Value)
+ {
+ Console.WriteLine($"{header.Key} : {value}");
+ }
+}
+Console.WriteLine();
+Console.WriteLine($"{Convert.ToBase64String(await message.Content!.ReadAsByteArrayAsync())}");
diff --git a/Examples/packages.lock.json b/Examples/packages.lock.json
new file mode 100644
index 0000000..a57656f
--- /dev/null
+++ b/Examples/packages.lock.json
@@ -0,0 +1,95 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net10.0": {
+ "ClosureOSS.WebPush": {
+ "type": "Direct",
+ "requested": "[2.4.1, )",
+ "resolved": "2.4.1",
+ "contentHash": "iraAOpOOyz+MafRKEBYPQuq7uCKAS3du4o+bK8SUFCi5C6pm1UCh/Yl4N2vDmZojM2875/QQ18oUWARBxaopWQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.4",
+ "Microsoft.IdentityModel.JsonWebTokens": "8.16.0",
+ "Microsoft.IdentityModel.Tokens": "8.16.0"
+ }
+ },
+ "Microsoft.DotNet.ILCompiler": {
+ "type": "Direct",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "2H7j1NltkQx04sPWBkUtFrZNBtro7vwsxRtdThP0oDj6Sn3ouGHCQlxATZ4Me2aJE67+KiXMX2V1IHDjt1uIpw=="
+ },
+ "Microsoft.NET.ILLink.Tasks": {
+ "type": "Direct",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "AA/yhzFHNtQZXLdqjzujPy25G8EWwGWsAnxOE2zYSBoT/8QHP6ketN3CToD3DFreO653ipUwnKHo22B8AlBMCw=="
+ },
+ "Nerdbank.GitVersioning": {
+ "type": "Direct",
+ "requested": "[3.9.50, )",
+ "resolved": "3.9.50",
+ "contentHash": "HtOgGF6jZ+WYbXnCUCYPT8Y2d6mIJo9ozjK/FINTRsXdm4Zgv9GehUMa7EFoGQkqrMcDJNOIDwCmENnvXg4UbA=="
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.4",
+ "contentHash": "SIe9zlVQJecnk/DTmevIcl6+aEDYhoVLc2eG2AKwVeNEC8CSyxHAbh4lf0xtHq9JUum0vVTEByGNTK+b6oihTQ=="
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.4",
+ "contentHash": "PDMMt7fvBatv6hcxxyJtXIzSwn7Dy00W6I2vDAOTYrQqNM2dF5A2L9n0uMzdPz2IPoNZWkAmYjoOCEdDLq0i4w==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.4"
+ }
+ },
+ "Microsoft.IdentityModel.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.16.0",
+ "contentHash": "gSxKLWRZzBpIsEoeUPkxfywNCCvRvl7hkq146XHPk5vOQc9izSf1I+uL1vh4y2U19QPxd9Z8K/8AdWyxYz2lSg=="
+ },
+ "Microsoft.IdentityModel.JsonWebTokens": {
+ "type": "Transitive",
+ "resolved": "8.16.0",
+ "contentHash": "prBU72cIP4V8E9fhN+o/YdskTsLeIcnKPbhZf0X6mD7fdxoZqnS/NdEkSr+9Zp+2q7OZBOMfNBKGbTbhXODO4w==",
+ "dependencies": {
+ "Microsoft.IdentityModel.Tokens": "8.16.0"
+ }
+ },
+ "Microsoft.IdentityModel.Logging": {
+ "type": "Transitive",
+ "resolved": "8.16.0",
+ "contentHash": "MTzXmETkNQPACR7/XCXM1OGM6oU9RkyibqeJRtO9Ndew2LnGjMf9Atqj2VSf4XC27X0FQycUAlzxxEgQMWn2xQ==",
+ "dependencies": {
+ "Microsoft.IdentityModel.Abstractions": "8.16.0"
+ }
+ },
+ "Microsoft.IdentityModel.Tokens": {
+ "type": "Transitive",
+ "resolved": "8.16.0",
+ "contentHash": "rtViGJcGsN7WcfUNErwNeQgjuU5cJNl6FDQsfi9TncwO+Epzn0FTfBsg3YuFW1Q0Ch/KPxaVdjLw3/+5Z5ceFQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.0",
+ "Microsoft.IdentityModel.Logging": "8.16.0"
+ }
+ }
+ },
+ "net10.0/win-x64": {
+ "Microsoft.DotNet.ILCompiler": {
+ "type": "Direct",
+ "requested": "[10.0.7, )",
+ "resolved": "10.0.7",
+ "contentHash": "2H7j1NltkQx04sPWBkUtFrZNBtro7vwsxRtdThP0oDj6Sn3ouGHCQlxATZ4Me2aJE67+KiXMX2V1IHDjt1uIpw==",
+ "dependencies": {
+ "runtime.win-x64.Microsoft.DotNet.ILCompiler": "10.0.7"
+ }
+ },
+ "runtime.win-x64.Microsoft.DotNet.ILCompiler": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "pdlgAPDgcAMCi1XMrgKTPcovBzM0IG9j8LbsIyXS8XXXIrPRyygByqJPJnPtTPDIHxXsLmd3tlMEDULglbBdKA=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 6581aa1..d03201e 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,6 @@
[](https://github.com/closureOSS/webpush-csharp/actions/workflows/dotnet.yml)

-
# Why
To deliver generic events using HTTP Push as outlined in [Generic Event Delivery Using HTTP](https://datatracker.ietf.org/doc/html/rfc8030), backend-triggered push messages must be encrypted. This is accomplished using the [Message Encryption for Web Push](https://datatracker.ietf.org/doc/html/rfc8291) standard, which relies on [Voluntary Application Server Identification (VAPID) for Web Push (RFC8292)](https://datatracker.ietf.org/doc/html/rfc8292) for authentication. Furthermore, any data included with the push message must be separately encrypted following the rules of [Encrypted Content-Encoding for HTTP (RFC8188)](https://datatracker.ietf.org/doc/html/rfc8188).
@@ -12,6 +11,8 @@ This package makes it easy to send push notifications from an application server
## Purpose of fork
+Support for message topic and message urgency flag.
+
Support for the "aes128gcm" HTTP Content Coding.
Rewrite using System.Security.Crytography, Microsoft.IdentityModel and other first party interfaces.
@@ -43,12 +44,17 @@ var publicKey = @"BDjASz8kkVBQJgWcD05uX3VxIs_gSHyuS023jnBoHBgUbg8zIJvTSQytR8MP4Z
var privateKey = @"mryM-krWj_6IsIMGsd8wNFXGBxnx...............";
var subscription = new PushSubscription(pushEndpoint, p256dh, auth);
-var vapidDetails = new VapidDetails(subject, publicKey, privateKey);
+var options = new WebPushOptions
+{
+ VapidDetails = new VapidDetails(subject, publicKey, privateKey),
+ ContentEncoding = ContentEncoding.Aes128gcm,
+ Urgency = Urgency.High,
+};
var webPushClient = new WebPushClient();
try
{
- await webPushClient.SendNotificationAsync(subscription, "payload", vapidDetails);
+ await webPushClient.SendNotificationAsync(subscription, "payload", options);
}
catch (WebPushException exception)
{
@@ -114,14 +120,43 @@ Options is an optional argument that if defined should be an Dictionary