Bug 1553831 Comment 4 Edit History

Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.

> Though, will the signature expire if the server isn't polled for a couple of days (e.g. Firefox isn't run over the weekend)?

I assume a signature never expires as long as the root hash is not changed. And I assume that we'll host all the certificates chains we've ever used for a long time.  **:ulfr** you confirm?

> Presumably RemoteSettings will normally poll sometime soon after first startup for a new profile?

Yes, but there is no timing guarantee. Depending on your code, if you call `.get()` a second time before it syncs, you'll have this `InvalidaSignature` (I'll add unit tests).

> If so, then if it is also storing the metadata on that poll, that is probably reasonable. At the moment, we never seem to store the metadata if the local dump is the same as the server.

Exactly, the records dumps don't contain the collection signature (should they?). 

I can handle the situation in `.get()` and pull the metadata at the moment (implicit network call):

```diff
diff --git a/services/settings/RemoteSettingsClient.jsm b/services/settings/RemoteSettingsClient.jsm
--- a/services/settings/RemoteSettingsClient.jsm
+++ b/services/settings/RemoteSettingsClient.jsm
@@ -229,17 +229,22 @@ class RemoteSettingsClient extends Event
     // Read from the local DB.
     const kintoCollection = await this.openCollection();
     const { data } = await kintoCollection.list({ filters, order });
 
     // Verify signature of local data.
     if (verifySignature) {
       const localRecords = data.map(r => kintoCollection.cleanLocalFields(r));
       const timestamp = await kintoCollection.db.getLastModified();
-      const metadata = await kintoCollection.metadata();
+      let metadata = await kintoCollection.metadata();
+      if (!metadata) {
+        // No sync occured yet, may have records from dump but no metadata.
+        console.debug(`Required metadata for ${this.identifier}, fetching from server.`);
+        metadata = await kintoCollection.pullMetadata();
+      }
       await this._validateCollectionSignature([],
                                               timestamp,
                                               metadata,
                                               { localRecords });
     }
 
     // Filter the records based on `this.filterFunc` results.
     return this._filterEntries(data);
```

But you may prefer handle the case yourself explicitly, since that's probably what you'll have to do if content does not match signature anyway.

```js
while(retry) {
  try {
    // Read local, if empty load dump, if present or sync otherwise.
    return entries = await ignoreListSettings.get({verifySignature: true});
  } catch (e) {
    const kintoCollection = await ignoreListSettings.openCollection();
    await kintoCollection.clear();
  }
}
```
Let me know! You may want to compare performance (re-loading dump vs. fetch metadata + sig verification). For small dumps it should be faster to reload IDK
> Though, will the signature expire if the server isn't polled for a couple of days (e.g. Firefox isn't run over the weekend)?

I assume a signature never expires as long as the root hash is not changed. And I assume that we'll host all the certificates chains we've ever used for a long time.  **:ulfr** you confirm?

> Presumably RemoteSettings will normally poll sometime soon after first startup for a new profile?

Yes, but there is no timing guarantee. Depending on your code, if you call `.get()` a second time before it syncs, you'll have this `InvalidaSignature` (I'll add unit tests).

> If so, then if it is also storing the metadata on that poll, that is probably reasonable. At the moment, we never seem to store the metadata if the local dump is the same as the server.

Exactly, the records dumps don't contain the collection signature (should they?). 

I can handle the situation in `.get()` and pull the metadata at the moment (implicit network call):

```diff
diff --git a/services/settings/RemoteSettingsClient.jsm b/services/settings/RemoteSettingsClient.jsm
--- a/services/settings/RemoteSettingsClient.jsm
+++ b/services/settings/RemoteSettingsClient.jsm
@@ -229,17 +229,22 @@ class RemoteSettingsClient extends Event
     // Read from the local DB.
     const kintoCollection = await this.openCollection();
     const { data } = await kintoCollection.list({ filters, order });
 
     // Verify signature of local data.
     if (verifySignature) {
       const localRecords = data.map(r => kintoCollection.cleanLocalFields(r));
       const timestamp = await kintoCollection.db.getLastModified();
-      const metadata = await kintoCollection.metadata();
+      let metadata = await kintoCollection.metadata();
+      if (!metadata) {
+        // No sync occured yet, may have records from dump but no metadata.
+        console.debug(`Required metadata for ${this.identifier}, fetching from server.`);
+        metadata = await kintoCollection.pullMetadata();
+      }
       await this._validateCollectionSignature([],
                                               timestamp,
                                               metadata,
                                               { localRecords });
     }
 
     // Filter the records based on `this.filterFunc` results.
     return this._filterEntries(data);
```

But you may prefer handle the case yourself explicitly, since that's probably what you'll have to do if content does not match signature anyway.

```js
while(retry) {
  try {
    // Read local, if empty load dump, if present or sync otherwise.
    return await ignoreListSettings.get({verifySignature: true});
  } catch (e) {
    const kintoCollection = await ignoreListSettings.openCollection();
    await kintoCollection.clear();
  }
}
```
Let me know! You may want to compare performance (re-loading dump vs. fetch metadata + sig verification). For small dumps it should be faster to reload IDK
> Though, will the signature expire if the server isn't polled for a couple of days (e.g. Firefox isn't run over the weekend)?

I assume a signature never expires as long as the root hash is not changed. And I assume that we'll host all the certificates chains we've ever used for a long time.  **:ulfr** you confirm?

> Presumably RemoteSettings will normally poll sometime soon after first startup for a new profile?

Yes, but there is no timing guarantee. Depending on your code, if you call `.get()` a second time before it syncs, you'll have this `InvalidaSignature` (I'll add unit tests).

> If so, then if it is also storing the metadata on that poll, that is probably reasonable. At the moment, we never seem to store the metadata if the local dump is the same as the server.

Exactly, the records dumps don't contain the collection signature (should they?). 

I can handle the situation in `.get()` and pull the metadata at the moment (implicit network call):

```diff
diff --git a/services/settings/RemoteSettingsClient.jsm b/services/settings/RemoteSettingsClient.jsm
--- a/services/settings/RemoteSettingsClient.jsm
+++ b/services/settings/RemoteSettingsClient.jsm
@@ -229,17 +229,22 @@ class RemoteSettingsClient extends Event
     // Read from the local DB.
     const kintoCollection = await this.openCollection();
     const { data } = await kintoCollection.list({ filters, order });
 
     // Verify signature of local data.
     if (verifySignature) {
       const localRecords = data.map(r => kintoCollection.cleanLocalFields(r));
       const timestamp = await kintoCollection.db.getLastModified();
-      const metadata = await kintoCollection.metadata();
+      let metadata = await kintoCollection.metadata();
+      if (!metadata) {
+        // No sync occured yet, may have records from dump but no metadata.
+        console.debug(`Required metadata for ${this.identifier}, fetching from server.`);
+        metadata = await kintoCollection.pullMetadata(client);
+      }
       await this._validateCollectionSignature([],
                                               timestamp,
                                               metadata,
                                               { localRecords });
     }
 
     // Filter the records based on `this.filterFunc` results.
     return this._filterEntries(data);
```

But you may prefer handle the case yourself explicitly, since that's probably what you'll have to do if content does not match signature anyway.

```js
while(retry) {
  try {
    // Read local, if empty load dump, if present or sync otherwise.
    return await ignoreListSettings.get({verifySignature: true});
  } catch (e) {
    const kintoCollection = await ignoreListSettings.openCollection();
    await kintoCollection.clear();
  }
}
```
Let me know! You may want to compare performance (re-loading dump vs. fetch metadata + sig verification). For small dumps it should be faster to reload IDK
> Though, will the signature expire if the server isn't polled for a couple of days (e.g. Firefox isn't run over the weekend)?

I assume a signature never expires as long as the root hash is not changed. And I assume that we'll host all the certificates chains we've ever used for a long time.  **:ulfr** you confirm?

> Presumably RemoteSettings will normally poll sometime soon after first startup for a new profile?

Yes, but there is no timing guarantee. Depending on your code, if you call `.get()` a second time before it syncs, you'll have this `InvalidaSignature` (I'll add unit tests).

> If so, then if it is also storing the metadata on that poll, that is probably reasonable. At the moment, we never seem to store the metadata if the local dump is the same as the server.

Exactly, the records dumps don't contain the collection signature (should they?). 

I can handle the situation in `.get()` and pull the metadata at the moment (implicit network call):

```diff
diff --git a/services/settings/RemoteSettingsClient.jsm b/services/settings/RemoteSettingsClient.jsm
--- a/services/settings/RemoteSettingsClient.jsm
+++ b/services/settings/RemoteSettingsClient.jsm
@@ -229,17 +229,22 @@ class RemoteSettingsClient extends Event
     // Read from the local DB.
     const kintoCollection = await this.openCollection();
     const { data } = await kintoCollection.list({ filters, order });
 
     // Verify signature of local data.
     if (verifySignature) {
       const localRecords = data.map(r => kintoCollection.cleanLocalFields(r));
       const timestamp = await kintoCollection.db.getLastModified();
-      const metadata = await kintoCollection.metadata();
+      let metadata = await kintoCollection.metadata();
+      if (!metadata) {
+        // No sync occured yet, may have records from dump but no metadata.
+        console.debug(`Required metadata for ${this.identifier}, fetching from server.`);
+        metadata = await kintoCollection.pullMetadata(client);
+      }
       await this._validateCollectionSignature([],
                                               timestamp,
                                               metadata,
                                               { localRecords });
     }
 
     // Filter the records based on `this.filterFunc` results.
     return this._filterEntries(data);
```

But you may prefer handle the case yourself explicitly, since that's probably what you'll have to do if content does not match signature anyway.

```js
while(retry) {
  try {
    // Read local, if empty and dump present then load else sync.
    return await ignoreListSettings.get({verifySignature: true});
  } catch (e) {
    const kintoCollection = await ignoreListSettings.openCollection();
    await kintoCollection.clear();
  }
}
```
Let me know! You may want to compare performance (re-loading dump vs. fetch metadata + sig verification). For small dumps it should be faster to reload IDK

Back to Bug 1553831 Comment 4