summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebPushSubscription.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebPushSubscription.java')
-rw-r--r--mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebPushSubscription.java180
1 files changed, 180 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebPushSubscription.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebPushSubscription.java
new file mode 100644
index 0000000000..7ce9a3d60c
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebPushSubscription.java
@@ -0,0 +1,180 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * vim: ts=4 sw=4 expandtab:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.geckoview;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import androidx.annotation.AnyThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import java.util.Arrays;
+import org.mozilla.gecko.util.GeckoBundle;
+
+/**
+ * This class represents a single Web Push subscription, as described in the <a
+ * href="https://www.w3.org/TR/push-api/">Web Push API</a> specification.
+ *
+ * <p>This is a low-level interface, allowing applications to do all of the heavy lifting
+ * themselves. It is recommended that consumers have a thorough understanding of the Web Push API,
+ * especially <a href="https://tools.ietf.org/html/rfc8291">RFC 8291</a>.
+ *
+ * <p>Only trivial sanity checks are performed on the values held here. The application must ensure
+ * it is generating compliant keys/secrets itself.
+ */
+public class WebPushSubscription implements Parcelable {
+ private static final int P256_PUBLIC_KEY_LENGTH = 65;
+
+ /**
+ * The Service Worker scope associated with this subscription.
+ *
+ * @see <a
+ * href="https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register">ServiceWorker
+ * registration</a>
+ */
+ @NonNull public final String scope;
+
+ /**
+ * The Web Push endpoint for this subscription. This is the URL of a web service which implements
+ * the Web Push protocol.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc8030#section-5">RFC 8030</a>
+ */
+ @NonNull public final String endpoint;
+
+ /**
+ * This is an optional public key provided by the application server to authenticate itself with
+ * the endpoint, formatted according to X9.62.
+ *
+ * <p>This key is used for VAPID, the Voluntary Application Server Identification (VAPID) for Web
+ * Push, from <a href="https://tools.ietf.org/html/rfc8292">RFC 8292</a>.
+ *
+ * @see <a
+ * href="https://www.w3.org/TR/push-api/#dom-pushsubscriptionoptions-applicationserverkey">applicationServerKey</a>
+ * @see <a href="https://tools.ietf.org/html/rfc8291">Message Encryption for Web Push</a>
+ */
+ @Nullable public final byte[] appServerKey;
+
+ /**
+ * The P-256 EC public key, formatted as X9.62, generated by the embedder, to be provided to the
+ * app server for message encryption.
+ *
+ * @see <a
+ * href="https://www.w3.org/TR/push-api/#dom-pushencryptionkeyname-p256dh">PushEncryptionKeyName
+ * - p256dh</a>
+ * @see <a href="https://tools.ietf.org/html/rfc8291#section-3.1">RFC 8291 section 3.1</a>
+ */
+ @NonNull public final byte[] browserPublicKey;
+
+ /**
+ * 16 byte secret key, generated by the embedder, to be provided to the app server for use in
+ * encrypting and authenticating messages sent to the {@link #endpoint}.
+ *
+ * @see <a
+ * href="https://www.w3.org/TR/push-api/#dom-pushencryptionkeyname-auth">PushEncryptionKeyName
+ * - auth</a>
+ * @see <a href="https://tools.ietf.org/html/rfc8291#section-3.2">RFC 8291, section 3.2</a>
+ */
+ @NonNull public final byte[] authSecret;
+
+ @SuppressWarnings("checkstyle:javadocmethod")
+ public WebPushSubscription(
+ final @NonNull String scope,
+ final @NonNull String endpoint,
+ final @Nullable byte[] appServerKey,
+ final @NonNull byte[] browserPublicKey,
+ final @NonNull byte[] authSecret) {
+ this.scope = scope;
+ this.endpoint = endpoint;
+ this.appServerKey = appServerKey;
+ this.browserPublicKey = browserPublicKey;
+ this.authSecret = authSecret;
+
+ if (appServerKey != null) {
+ if (appServerKey.length != P256_PUBLIC_KEY_LENGTH) {
+ throw new IllegalArgumentException(
+ String.format("appServerKey should be %d bytes", P256_PUBLIC_KEY_LENGTH));
+ }
+
+ if (Arrays.equals(appServerKey, browserPublicKey)) {
+ throw new IllegalArgumentException("appServerKey and browserPublicKey must differ");
+ }
+ }
+
+ if (browserPublicKey.length != P256_PUBLIC_KEY_LENGTH) {
+ throw new IllegalArgumentException(
+ String.format("browserPublicKey should be %d bytes", P256_PUBLIC_KEY_LENGTH));
+ }
+
+ if (authSecret.length != 16) {
+ throw new IllegalArgumentException("authSecret must be 128 bits");
+ }
+ }
+
+ private WebPushSubscription(final Parcel in) {
+ this.scope = in.readString();
+ this.endpoint = in.readString();
+
+ if (ParcelableUtils.readBoolean(in)) {
+ this.appServerKey = new byte[P256_PUBLIC_KEY_LENGTH];
+ in.readByteArray(this.appServerKey);
+ } else {
+ appServerKey = null;
+ }
+
+ this.browserPublicKey = new byte[P256_PUBLIC_KEY_LENGTH];
+ in.readByteArray(this.browserPublicKey);
+
+ this.authSecret = new byte[16];
+ in.readByteArray(this.authSecret);
+ }
+
+ /* package */ GeckoBundle toBundle() {
+ final GeckoBundle bundle = new GeckoBundle(5);
+ bundle.putString("scope", scope);
+ bundle.putString("endpoint", endpoint);
+ if (appServerKey != null) {
+ bundle.putString("appServerKey", Base64Utils.encode(appServerKey));
+ }
+ bundle.putString("browserPublicKey", Base64Utils.encode(browserPublicKey));
+ bundle.putString("authSecret", Base64Utils.encode(authSecret));
+ return bundle;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(final Parcel out, final int flags) {
+ out.writeString(scope);
+ out.writeString(endpoint);
+
+ ParcelableUtils.writeBoolean(out, appServerKey != null);
+ if (appServerKey != null) {
+ out.writeByteArray(appServerKey);
+ }
+
+ out.writeByteArray(browserPublicKey);
+ out.writeByteArray(authSecret);
+ }
+
+ public static final Parcelable.Creator<WebPushSubscription> CREATOR =
+ new Parcelable.Creator<WebPushSubscription>() {
+ @Override
+ @AnyThread
+ public WebPushSubscription createFromParcel(final Parcel parcel) {
+ return new WebPushSubscription(parcel);
+ }
+
+ @Override
+ @AnyThread
+ public WebPushSubscription[] newArray(final int size) {
+ return new WebPushSubscription[size];
+ }
+ };
+}