зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1453690
- Fail nicely when RemoteSetting collection is not signed r=mgoodwin
MozReview-Commit-ID: ESP7GXfmYzU --HG-- extra : rebase_source : 659f97e6d5317a5662c5d7f09fcf770d5928b444
This commit is contained in:
Родитель
74229456be
Коммит
5aa6d86d41
|
@ -35,6 +35,7 @@ const PREF_SETTINGS_LOAD_DUMP = "services.settings.load_dump";
|
||||||
const TELEMETRY_HISTOGRAM_KEY = "settings-changes-monitoring";
|
const TELEMETRY_HISTOGRAM_KEY = "settings-changes-monitoring";
|
||||||
|
|
||||||
const INVALID_SIGNATURE = "Invalid content/signature";
|
const INVALID_SIGNATURE = "Invalid content/signature";
|
||||||
|
const MISSING_SIGNATURE = "Missing signature";
|
||||||
|
|
||||||
|
|
||||||
function mergeChanges(collection, localRecords, changes) {
|
function mergeChanges(collection, localRecords, changes) {
|
||||||
|
@ -57,15 +58,15 @@ function mergeChanges(collection, localRecords, changes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function fetchCollectionMetadata(remote, collection) {
|
async function fetchCollectionMetadata(remote, collection) {
|
||||||
const client = new KintoHttpClient(remote);
|
const client = new KintoHttpClient(remote);
|
||||||
return client.bucket(collection.bucket).collection(collection.name).getData()
|
const { signature } = await client.bucket(collection.bucket)
|
||||||
.then(result => {
|
.collection(collection.name)
|
||||||
return result.signature;
|
.getData();
|
||||||
});
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchRemoteCollection(remote, collection) {
|
async function fetchRemoteCollection(remote, collection) {
|
||||||
const client = new KintoHttpClient(remote);
|
const client = new KintoHttpClient(remote);
|
||||||
return client.bucket(collection.bucket)
|
return client.bucket(collection.bucket)
|
||||||
.collection(collection.name)
|
.collection(collection.name)
|
||||||
|
@ -302,8 +303,11 @@ class RemoteSettingsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// The sync has thrown, it can be a network or a general error.
|
// The sync has thrown, it can be related to metadata, network or a general error.
|
||||||
if (/NetworkError/.test(e.message)) {
|
if (e.message == MISSING_SIGNATURE) {
|
||||||
|
// Collection metadata has no signature info, no need to retry.
|
||||||
|
reportStatus = UptakeTelemetry.STATUS.SIGNATURE_ERROR;
|
||||||
|
} else if (/NetworkError/.test(e.message)) {
|
||||||
reportStatus = UptakeTelemetry.STATUS.NETWORK_ERROR;
|
reportStatus = UptakeTelemetry.STATUS.NETWORK_ERROR;
|
||||||
} else if (/Backoff/.test(e.message)) {
|
} else if (/Backoff/.test(e.message)) {
|
||||||
reportStatus = UptakeTelemetry.STATUS.BACKOFF;
|
reportStatus = UptakeTelemetry.STATUS.BACKOFF;
|
||||||
|
@ -367,9 +371,12 @@ class RemoteSettingsClient {
|
||||||
|
|
||||||
async _validateCollectionSignature(remote, payload, collection, options = {}) {
|
async _validateCollectionSignature(remote, payload, collection, options = {}) {
|
||||||
const {ignoreLocal} = options;
|
const {ignoreLocal} = options;
|
||||||
|
|
||||||
// this is a content-signature field from an autograph response.
|
// this is a content-signature field from an autograph response.
|
||||||
const {x5u, signature} = await fetchCollectionMetadata(remote, collection);
|
const signaturePayload = await fetchCollectionMetadata(remote, collection);
|
||||||
|
if (!signaturePayload) {
|
||||||
|
throw new Error(MISSING_SIGNATURE);
|
||||||
|
}
|
||||||
|
const {x5u, signature} = signaturePayload;
|
||||||
const certChainResponse = await fetch(x5u);
|
const certChainResponse = await fetch(x5u);
|
||||||
const certChain = await certChainResponse.text();
|
const certChain = await certChainResponse.text();
|
||||||
|
|
||||||
|
|
|
@ -262,6 +262,19 @@ add_task(async function test_check_signatures() {
|
||||||
const RESPONSE_BODY_META_EMPTY_SIG = makeMetaResponseBody(1000,
|
const RESPONSE_BODY_META_EMPTY_SIG = makeMetaResponseBody(1000,
|
||||||
"vxuAg5rDCB-1pul4a91vqSBQRXJG_j7WOYUTswxRSMltdYmbhLRH8R8brQ9YKuNDF56F-w6pn4HWxb076qgKPwgcEBtUeZAO_RtaHXRkRUUgVzAr86yQL4-aJTbv3D6u");
|
"vxuAg5rDCB-1pul4a91vqSBQRXJG_j7WOYUTswxRSMltdYmbhLRH8R8brQ9YKuNDF56F-w6pn4HWxb076qgKPwgcEBtUeZAO_RtaHXRkRUUgVzAr86yQL4-aJTbv3D6u");
|
||||||
|
|
||||||
|
const RESPONSE_META_NO_SIG = {
|
||||||
|
sampleHeaders: [
|
||||||
|
"Content-Type: application/json; charset=UTF-8",
|
||||||
|
`ETag: \"123456\"`
|
||||||
|
],
|
||||||
|
status: {status: 200, statusText: "OK"},
|
||||||
|
responseBody: JSON.stringify({
|
||||||
|
data: {
|
||||||
|
last_modified: 123456
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
// The collection metadata containing the signature for the empty
|
// The collection metadata containing the signature for the empty
|
||||||
// collection.
|
// collection.
|
||||||
const RESPONSE_META_EMPTY_SIG =
|
const RESPONSE_META_EMPTY_SIG =
|
||||||
|
@ -563,6 +576,31 @@ add_task(async function test_check_signatures() {
|
||||||
endHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
|
endHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
|
||||||
expectedIncrements = {[UptakeTelemetry.STATUS.SIGNATURE_RETRY_ERROR]: 1};
|
expectedIncrements = {[UptakeTelemetry.STATUS.SIGNATURE_RETRY_ERROR]: 1};
|
||||||
checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
|
checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
|
||||||
|
|
||||||
|
|
||||||
|
const missingSigResponses = {
|
||||||
|
// In this test, we deliberately serve metadata without the signature attribute.
|
||||||
|
// As if the collection was not signed.
|
||||||
|
"GET:/v1/buckets/blocklists/collections/certificates?":
|
||||||
|
[RESPONSE_META_NO_SIG],
|
||||||
|
};
|
||||||
|
|
||||||
|
startHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
|
||||||
|
registerHandlers(missingSigResponses);
|
||||||
|
try {
|
||||||
|
await OneCRLBlocklistClient.maybeSync(6000, startTime);
|
||||||
|
do_throw("Sync should fail (the signature is missing)");
|
||||||
|
} catch (e) {
|
||||||
|
await checkRecordCount(OneCRLBlocklistClient, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the failure is reflected in the accumulated telemetry:
|
||||||
|
endHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
|
||||||
|
expectedIncrements = {
|
||||||
|
[UptakeTelemetry.STATUS.SIGNATURE_ERROR]: 1,
|
||||||
|
[UptakeTelemetry.STATUS.SIGNATURE_RETRY_ERROR]: 0 // Not retried since missing.
|
||||||
|
};
|
||||||
|
checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
|
||||||
});
|
});
|
||||||
|
|
||||||
function run_test() {
|
function run_test() {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче