Bug 1266433 - Indicate push subscriptions created by privileged code. r=dragana draft
authorKit Cambridge <kcambridge@mozilla.com>
Sat, 23 Apr 2016 19:41:59 -0700
changeset 356166 85eba396613441c4508056fb34ca4525212b32f7
parent 356165 a3385be2b31d67291a816570fac47e5bfd3dd5f9
child 356167 ca46f748a40ffe287a17ee68591d30c493a84db6
push id16465
push userkcambridge@mozilla.com
push dateMon, 25 Apr 2016 21:50:28 +0000
reviewersdragana
bugs1266433
milestone48.0a1
Bug 1266433 - Indicate push subscriptions created by privileged code. r=dragana MozReview-Commit-ID: HYKndQiU98U
dom/interfaces/push/nsIPushService.idl
dom/push/PushComponents.js
dom/push/PushRecord.jsm
dom/push/test/xpcshell/test_service_child.js
--- a/dom/interfaces/push/nsIPushService.idl
+++ b/dom/interfaces/push/nsIPushService.idl
@@ -13,16 +13,17 @@ interface nsIPrincipal;
  */
 [scriptable, uuid(1de32d5c-ea88-4c9e-9626-b032bd87f415)]
 interface nsIPushSubscription : nsISupports
 {
   readonly attribute DOMString endpoint;
   readonly attribute long long pushCount;
   readonly attribute long long lastPush;
   readonly attribute long quota;
+  readonly attribute bool isSystemSubscription;
 
   bool quotaApplies();
   bool isExpired();
 
   void getKey(in DOMString name,
               [optional] out uint32_t keyLen,
               [array, size_is(keyLen), retval] out uint8_t key);
 };
--- a/dom/push/PushComponents.js
+++ b/dom/push/PushComponents.js
@@ -243,17 +243,17 @@ Object.assign(PushServiceParent.prototyp
       throw new Error("Invalid page record: missing principal");
     }
     if (principal.isNullPrincipal || principal.isExpandedPrincipal) {
       throw new Error("Invalid page record: unsupported principal");
     }
 
     // System subscriptions can only be created by chrome callers, and are
     // exempt from the background message quota and permission checks. They
-    // also use XPCOM observer notifications instead of service worker events.
+    // also do not fire service worker events.
     data.systemRecord = principal.isSystemPrincipal;
 
     data.originAttributes =
       ChromeUtils.originAttributesToSuffix(principal.originAttributes);
 
     return data;
   },
 
@@ -485,16 +485,25 @@ PushSubscription.prototype = {
   /** The number of remaining background messages that can be sent to this
    * subscription, or -1 of the subscription is exempt from the quota.
    */
   get quota() {
     return this._props.quota;
   },
 
   /**
+   * Indicates whether this subscription was created with the system principal.
+   * System subscriptions are exempt from the background message quota and
+   * permission checks.
+   */
+  get isSystemSubscription() {
+    return !!this._props.systemRecord;
+  },
+
+  /**
    * Indicates whether this subscription is subject to the background message
    * quota.
    */
   quotaApplies() {
     return this.quota >= 0;
   },
 
   /**
--- a/dom/push/PushRecord.jsm
+++ b/dom/push/PushRecord.jsm
@@ -247,16 +247,17 @@ PushRecord.prototype = {
     return {
       endpoint: this.pushEndpoint,
       lastPush: this.lastPush,
       pushCount: this.pushCount,
       p256dhKey: this.p256dhPublicKey,
       authenticationSecret: this.authenticationSecret,
       appServerKey: this.appServerKey,
       quota: this.quotaApplies() ? this.quota : -1,
+      systemRecord: this.systemRecord,
     };
   },
 };
 
 // Define lazy getters for the principal and scope URI. IndexedDB can't store
 // `nsIPrincipal` objects, so we keep them in a private weak map.
 var principals = new WeakMap();
 Object.defineProperties(PushRecord.prototype, {
--- a/dom/push/test/xpcshell/test_service_child.js
+++ b/dom/push/test/xpcshell/test_service_child.js
@@ -40,16 +40,17 @@ if (isParent) {
 
 add_test(function test_subscribe_success() {
   do_test_pending();
   PushServiceComponent.subscribe(
     'https://example.com/sub/ok',
     Services.scriptSecurityManager.getSystemPrincipal(),
     (result, subscription) => {
       ok(Components.isSuccessCode(result), 'Error creating subscription');
+      ok(subscription.isSystemSubscription, 'Expected system subscription');
       ok(subscription.endpoint.startsWith('https://example.org/push'), 'Wrong endpoint prefix');
       equal(subscription.pushCount, 0, 'Wrong push count');
       equal(subscription.lastPush, 0, 'Wrong last push time');
       equal(subscription.quota, -1, 'Wrong quota for system subscription');
 
       do_test_finished();
       run_next_test();
     }
@@ -235,49 +236,53 @@ add_test(function test_subscribe_app_pri
     true /* browserOnly */
   );
 
   do_test_pending();
   PushServiceComponent.subscribe('https://example.net/scope/1', principal, (result, subscription) => {
     ok(Components.isSuccessCode(result), 'Error creating subscription');
     ok(subscription.endpoint.startsWith('https://example.org/push'),
       'Wrong push endpoint in app subscription');
+    ok(!subscription.isSystemSubscription,
+      'Unexpected system subscription for app principal');
     equal(subscription.quota, 16, 'Wrong quota for app subscription');
 
     do_test_finished();
     run_next_test();
   });
 });
 
 add_test(function test_subscribe_origin_principal() {
   let scope = 'https://example.net/origin-principal';
   let principal =
     Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(scope);
 
   do_test_pending();
   PushServiceComponent.subscribe(scope, principal, (result, subscription) => {
     ok(Components.isSuccessCode(result),
       'Expected error creating subscription with origin principal');
+    ok(!subscription.isSystemSubscription,
+      'Unexpected system subscription for origin principal');
     equal(subscription.quota, 16, 'Wrong quota for origin subscription');
 
     do_test_finished();
     run_next_test();
   });
 });
 
 add_test(function test_subscribe_null_principal() {
   do_test_pending();
   PushServiceComponent.subscribe(
     'chrome://push/null-principal',
     Services.scriptSecurityManager.createNullPrincipal({}),
     (result, subscription) => {
       ok(!Components.isSuccessCode(result),
-        'Expected error creating subscription with expanded principal');
+        'Expected error creating subscription with null principal');
       strictEqual(subscription, null,
-        'Unexpected subscription with expanded principal');
+        'Unexpected subscription with null principal');
 
       do_test_finished();
       run_next_test();
     }
   );
 });
 
 add_test(function test_subscribe_missing_principal() {