Skip to content

Commit 662a4cf

Browse files
author
jamie
committed
Merge remote-tracking branch 'upstream/master'
# Conflicts: # src/main/java/nl/martijndwars/webpush/Notification.java
2 parents d9478c7 + 2510b7b commit 662a4cf

File tree

3 files changed

+121
-5
lines changed

3 files changed

+121
-5
lines changed

src/main/java/nl/martijndwars/webpush/Notification.java

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ public class Notification {
4545
*/
4646
private final int ttl;
4747

48+
private static final int ONE_DAY_DURATION_IN_SECONDS = 86400;
49+
private static int DEFAULT_TTL = 28 * ONE_DAY_DURATION_IN_SECONDS;
50+
4851

4952
public Notification(String endpoint, ECPublicKey userPublicKey, byte[] userAuth, byte[] payload, int ttl, Urgency urgency) {
5053
this.endpoint = endpoint;
@@ -59,8 +62,12 @@ public Notification(String endpoint, PublicKey userPublicKey, byte[] userAuth, b
5962
this(endpoint, (ECPublicKey) userPublicKey, userAuth, payload, ttl, null);
6063
}
6164

65+
public Notification(String endpoint, String userPublicKey, String userAuth, byte[] payload, int ttl) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
66+
this(endpoint, Utils.loadPublicKey(userPublicKey), Base64Encoder.decode(userAuth), payload, ttl);
67+
}
68+
6269
public Notification(String endpoint, PublicKey userPublicKey, byte[] userAuth, byte[] payload) {
63-
this(endpoint, userPublicKey, userAuth, payload, 2419200);
70+
this(endpoint, userPublicKey, userAuth, payload, DEFAULT_TTL);
6471
}
6572

6673
public Notification(String endpoint, String userPublicKey, String userAuth, byte[] payload) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
@@ -135,4 +142,59 @@ public String getOrigin() throws MalformedURLException {
135142

136143
return url.getProtocol() + "://" + url.getHost();
137144
}
145+
146+
public static NotificationBuilder builder() {
147+
return new Notification.NotificationBuilder();
148+
}
149+
150+
public static class NotificationBuilder {
151+
private String endpoint = null;
152+
private ECPublicKey userPublicKey = null;
153+
private byte[] userAuth = null;
154+
private byte[] payload = null;
155+
private int ttl = DEFAULT_TTL;
156+
157+
private NotificationBuilder() {
158+
}
159+
160+
public Notification build() {
161+
return new Notification(endpoint, userPublicKey, userAuth, payload, ttl);
162+
}
163+
164+
public NotificationBuilder endpoint(String endpoint) {
165+
this.endpoint = endpoint;
166+
return this;
167+
}
168+
169+
public NotificationBuilder userPublicKey(PublicKey publicKey) {
170+
this.userPublicKey = (ECPublicKey) publicKey;
171+
return this;
172+
}
173+
174+
public NotificationBuilder userPublicKey(String publicKey) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
175+
this.userPublicKey = (ECPublicKey) Utils.loadPublicKey(publicKey);
176+
return this;
177+
}
178+
179+
public NotificationBuilder userAuth(String userAuth) {
180+
this.userAuth = Base64Encoder.decode(userAuth);
181+
return this;
182+
}
183+
184+
public NotificationBuilder userAuth(byte[] userAuth) {
185+
this.userAuth = userAuth;
186+
return this;
187+
}
188+
189+
public NotificationBuilder payload(byte[] payload) {
190+
this.payload = payload;
191+
return this;
192+
}
193+
194+
public NotificationBuilder ttl(int ttl) {
195+
this.ttl = ttl;
196+
return this;
197+
}
198+
}
199+
138200
}

src/main/java/nl/martijndwars/webpush/PushService.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ public class PushService {
3434
private String gcmApiKey;
3535

3636
/**
37-
* Subject used in the JWT payload (for VAPID)
37+
* Subject used in the JWT payload (for VAPID). When left as null, then no subject will be used
38+
* (RFC-8292 2.1 says that it is optional)
3839
*/
3940
private String subject;
4041

@@ -55,15 +56,23 @@ public PushService(String gcmApiKey) {
5556
this.gcmApiKey = gcmApiKey;
5657
}
5758

58-
public PushService(KeyPair keyPair, String subject) {
59+
public PushService(KeyPair keyPair) {
5960
this.publicKey = keyPair.getPublic();
6061
this.privateKey = keyPair.getPrivate();
62+
}
63+
64+
public PushService(KeyPair keyPair, String subject) {
65+
this(keyPair);
6166
this.subject = subject;
6267
}
6368

64-
public PushService(String publicKey, String privateKey, String subject) throws GeneralSecurityException {
69+
public PushService(String publicKey, String privateKey) throws GeneralSecurityException {
6570
this.publicKey = Utils.loadPublicKey(publicKey);
6671
this.privateKey = Utils.loadPrivateKey(privateKey);
72+
}
73+
74+
public PushService(String publicKey, String privateKey, String subject) throws GeneralSecurityException {
75+
this(publicKey, privateKey);
6776
this.subject = subject;
6877
}
6978

@@ -226,7 +235,9 @@ public HttpPost preparePost(Notification notification, Encoding encoding) throws
226235
JwtClaims claims = new JwtClaims();
227236
claims.setAudience(notification.getOrigin());
228237
claims.setExpirationTimeMinutesInTheFuture(12 * 60);
229-
claims.setSubject(subject);
238+
if (subject != null) {
239+
claims.setSubject(subject);
240+
}
230241

231242
JsonWebSignature jws = new JsonWebSignature();
232243
jws.setHeader("typ", "JWT");
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package nl.martijndwars.webpush;
2+
3+
import java.security.GeneralSecurityException;
4+
import java.security.Security;
5+
import java.time.Duration;
6+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
7+
import org.junit.jupiter.api.BeforeAll;
8+
import org.junit.jupiter.api.Test;
9+
10+
import static org.junit.jupiter.api.Assertions.assertEquals;
11+
12+
class NotificationTest {
13+
14+
private static final String endpoint = "https://the-url.co.uk";
15+
private static final String publicKey = "BGu3hOwCLOBfdMReXf7-SD2x5tKs_vPapOneyngBOnu6PgNYdgLPKFAodfBnG60MqkXC0McPFehN2Kyuh6TKm14=";
16+
private static int oneDayDurationInSeconds = 86400;
17+
18+
@BeforeAll
19+
public static void addSecurityProvider() {
20+
Security.addProvider(new BouncyCastleProvider());
21+
}
22+
23+
@Test
24+
public void testNotificationBuilder() throws GeneralSecurityException {
25+
Notification notification = Notification.builder()
26+
.endpoint(endpoint)
27+
.userPublicKey(publicKey)
28+
.payload(new byte[16])
29+
.ttl((int) Duration.ofDays(15).getSeconds())
30+
.build();
31+
assertEquals(endpoint, notification.getEndpoint());
32+
assertEquals(15 * oneDayDurationInSeconds, notification.getTTL());
33+
}
34+
35+
@Test
36+
public void testDefaultTtl() throws GeneralSecurityException {
37+
Notification notification = Notification.builder()
38+
.userPublicKey(publicKey)
39+
.payload(new byte[16])
40+
.build();
41+
assertEquals(28 * oneDayDurationInSeconds, notification.getTTL());
42+
}
43+
}

0 commit comments

Comments
 (0)