diff --git a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/JweMetricType.kt b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/JweMetricType.kt deleted file mode 100644 index dd20eef12..000000000 --- a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/JweMetricType.kt +++ /dev/null @@ -1,194 +0,0 @@ -/* 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 mozilla.telemetry.glean.private - -import androidx.annotation.VisibleForTesting -import com.sun.jna.StringArray -import mozilla.telemetry.glean.Dispatchers -import mozilla.telemetry.glean.rust.LibGleanFFI -import mozilla.telemetry.glean.rust.getAndConsumeRustString -import mozilla.telemetry.glean.rust.toBoolean -import mozilla.telemetry.glean.rust.toByte -import mozilla.telemetry.glean.testing.ErrorType -import org.json.JSONObject - -/** - * A representation of a JWE value. - */ -data class JweData( - val header: String, - val key: String, - val initVector: String, - val cipherText: String, - val authTag: String -) - -/** - * This implements the developer facing API for recording JWE metrics. - * - * Instances of this class type are automatically generated by the parsers at build time, - * allowing developers to record values that were previously registered in the metrics.yaml file. - * - * The JWE API exposes the [set] and [setWithCompactRepresentation] methods, - * which take care of validating the input data. - */ -class JweMetricType internal constructor( - private var handle: Long, - private val disabled: Boolean, - private val sendInPings: List -) { - /** - * The public constructor used by automatically generated metrics. - */ - constructor( - disabled: Boolean, - category: String, - lifetime: Lifetime, - name: String, - sendInPings: List - ) : this(handle = 0, disabled = disabled, sendInPings = sendInPings) { - val ffiPingsList = StringArray(sendInPings.toTypedArray(), "utf-8") - this.handle = LibGleanFFI.INSTANCE.glean_new_jwe_metric( - category = category, - name = name, - send_in_pings = ffiPingsList, - send_in_pings_len = sendInPings.size, - lifetime = lifetime.ordinal, - disabled = disabled.toByte() - ) - } - - /** - * Set a JWE value. - * - * @param value The compact representation of a JWE value. - */ - fun setWithCompactRepresentation(value: String) { - if (disabled) { - return - } - - @Suppress("EXPERIMENTAL_API_USAGE") - Dispatchers.API.launch { - LibGleanFFI.INSTANCE.glean_jwe_set_with_compact_representation(this@JweMetricType.handle, value) - } - } - - /** - * Build a JWE value from its elements and set to it. - * - * @param header A variable-size JWE protected header. - * @param key A variable-size encrypted key. - * This can be an empty octet sequence. - * @param initVector A fixed-size, 96-bit, base64 encoded Jwe initialization vector. - * If not required by the encryption algorithm, can be an empty octet sequence. - * @param cipherText The variable-size base64 encoded cipher text. - * @param authTag A fixed-size, 132-bit, base64 encoded authentication tag. - * Can be an empty octet sequence. - */ - fun set(header: String, key: String, initVector: String, cipherText: String, authTag: String) { - if (disabled) { - return - } - - @Suppress("EXPERIMENTAL_API_USAGE") - Dispatchers.API.launch { - LibGleanFFI.INSTANCE.glean_jwe_set(this@JweMetricType.handle, header, key, initVector, cipherText, authTag) - } - } - - /** - * Tests whether a value is stored for the metric for testing purposes only. This function will - * attempt to await the last task (if any) writing to the the metric's storage engine before - * returning a value. - * - * @param pingName represents the name of the ping to retrieve the metric for. - * Defaults to the first value in `sendInPings`. - * @return true if metric value exists, otherwise false - */ - @VisibleForTesting(otherwise = VisibleForTesting.NONE) - @JvmOverloads - fun testHasValue(pingName: String = sendInPings.first()): Boolean { - @Suppress("EXPERIMENTAL_API_USAGE") - Dispatchers.API.assertInTestingMode() - - return LibGleanFFI.INSTANCE - .glean_jwe_test_has_value(this.handle, pingName) - .toBoolean() - } - - /** - * Returns the stored value for testing purposes only. This function will attempt to await the - * last task (if any) writing to the the metric's storage engine before returning a value. - * - * @param pingName represents the name of the ping to retrieve the metric for. - * Defaults to the first value in `sendInPings`. - * @return value of the stored metric - * @throws [NullPointerException] if no value is stored - */ - @VisibleForTesting(otherwise = VisibleForTesting.NONE) - @JvmOverloads - fun testGetValue(pingName: String = sendInPings.first()): JweData { - @Suppress("EXPERIMENTAL_API_USAGE") - Dispatchers.API.assertInTestingMode() - - if (!testHasValue(pingName)) { - throw NullPointerException("Metric has no value") - } - - val ptr = LibGleanFFI.INSTANCE.glean_jwe_test_get_value_as_json_string(this.handle, pingName)!! - val json = JSONObject(ptr.getAndConsumeRustString()) - - return JweData( - header = json.get("header") as String, - key = json.get("key") as String, - initVector = json.get("init_vector") as String, - cipherText = json.get("cipher_text") as String, - authTag = json.get("auth_tag") as String - ) - } - - /** - * Returns the stored value in the compact representation for testing purposes only. - * This function will attempt to await the last task (if any) - * writing to the the metric's storage engine before returning a value. - * - * @param pingName represents the name of the ping to retrieve the metric for. - * Defaults to the first value in `sendInPings`. - * @return value of the stored metric - * @throws [NullPointerException] if no value is stored - */ - @VisibleForTesting(otherwise = VisibleForTesting.NONE) - @JvmOverloads - fun testGetCompactRepresentation(pingName: String = sendInPings.first()): String { - @Suppress("EXPERIMENTAL_API_USAGE") - Dispatchers.API.assertInTestingMode() - - if (!testHasValue(pingName)) { - throw NullPointerException("Metric has no value") - } - val ptr = LibGleanFFI.INSTANCE.glean_jwe_test_get_value(this.handle, pingName)!! - return ptr.getAndConsumeRustString() - } - - /** - * Returns the number of errors recorded for the given metric. - * - * @param errorType The type of the error recorded. - * @param pingName represents the name of the ping to retrieve the metric for. - * Defaults to the first value in `sendInPings`. - * @return the number of errors recorded for the metric. - */ - @VisibleForTesting(otherwise = VisibleForTesting.NONE) - @JvmOverloads - fun testGetNumRecordedErrors(errorType: ErrorType, pingName: String = sendInPings.first()): Int { - @Suppress("EXPERIMENTAL_API_USAGE") - Dispatchers.API.assertInTestingMode() - - return LibGleanFFI.INSTANCE.glean_jwe_test_get_num_recorded_errors( - this.handle, errorType.ordinal, pingName - ) - } -} diff --git a/glean-core/android/src/test/java/mozilla/telemetry/glean/private/JweMetricTypeTest.kt b/glean-core/android/src/test/java/mozilla/telemetry/glean/private/JweMetricTypeTest.kt deleted file mode 100644 index 733761a59..000000000 --- a/glean-core/android/src/test/java/mozilla/telemetry/glean/private/JweMetricTypeTest.kt +++ /dev/null @@ -1,163 +0,0 @@ -/* 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/. */ - -/* This file is based on the tests in the Glean android-components implentation. - * - * Care should be taken to not reorder elements in this file so it will be easier - * to track changes in Glean android-components. - */ - -package mozilla.telemetry.glean.private - -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import mozilla.telemetry.glean.testing.ErrorType -import mozilla.telemetry.glean.testing.GleanTestRule -import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import java.lang.NullPointerException - -@RunWith(AndroidJUnit4::class) -@Suppress("MaxLineLength") -class JweMetricTypeTest { - companion object { - const val HEADER: String = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ" - const val KEY: String = "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg" - const val INIT_VECTOR: String = "48V1_ALb6US04U3b" - const val CIPHER_TEXT: String = "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A" - const val AUTH_TAG: String = "XFBoMYUZodetZdvTiFvSkQ" - const val JWE: String = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ" - const val MINIMUM_JWE: String = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ...5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A." - } - - @get:Rule - val gleanRule = GleanTestRule(ApplicationProvider.getApplicationContext()) - - @Test - fun `The API saves to its storage engine`() { - // Define a 'jweMetric' jwe metric, which will be stored in "store1" - val jweMetric = JweMetricType( - disabled = false, - category = "telemetry", - lifetime = Lifetime.Application, - name = "jwe_metric", - sendInPings = listOf("store1") - ) - - // Record two JWEs of the same type, with a little delay. - jweMetric.set(HEADER, KEY, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG) - - // Check that data was properly recorded. - assertTrue(jweMetric.testHasValue()) - assertEquals(JWE, jweMetric.testGetCompactRepresentation()) - - jweMetric.set(HEADER, "", "", CIPHER_TEXT, "") - // Check that data was properly recorded. - assertTrue(jweMetric.testHasValue()) - assertEquals(MINIMUM_JWE, jweMetric.testGetCompactRepresentation()) - } - - @Test - fun `disabled JWEs must not record data`() { - // Define a 'jweMetric' jwe metric, which will be stored in "store1". It's disabled - // so it should not record anything. - val jweMetric = JweMetricType( - disabled = true, - category = "telemetry", - lifetime = Lifetime.Application, - name = "jwe_metric", - sendInPings = listOf("store1") - ) - - // Attempt to store the JWE. - jweMetric.set(HEADER, KEY, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG) - // Check that nothing was recorded. - assertFalse( - "JWEs must not be recorded if they are disabled", - jweMetric.testHasValue() - ) - } - - @Test(expected = NullPointerException::class) - fun `testGetValue() throws NullPointerException if nothing is stored`() { - val jweMetric = JweMetricType( - disabled = true, - category = "telemetry", - lifetime = Lifetime.Application, - name = "jwe_metric", - sendInPings = listOf("store1") - ) - jweMetric.testGetValue() - } - - @Test - fun `testGetValue() returns correct JweData representation`() { - // Define a 'jweMetric' jwe metric, which will be stored in "store1". - val jweMetric = JweMetricType( - disabled = false, - category = "telemetry", - lifetime = Lifetime.Application, - name = "jwe_metric", - sendInPings = listOf("store1") - ) - - // Attempt to store the JWE. - jweMetric.set(HEADER, KEY, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG) - - val data = jweMetric.testGetValue() - assertEquals(data.header, HEADER) - assertEquals(data.key, KEY) - assertEquals(data.initVector, INIT_VECTOR) - assertEquals(data.cipherText, CIPHER_TEXT) - assertEquals(data.authTag, AUTH_TAG) - } - - @Test - fun `The API saves to secondary pings`() { - // Define a 'jweMetric' jwe metric, which will be stored in "store1" and "store2" - val jweMetric = JweMetricType( - disabled = false, - category = "telemetry", - lifetime = Lifetime.Application, - name = "jwe_metric", - sendInPings = listOf("store1", "store2") - ) - - // Record two JWEs, with a little delay. - jweMetric.set(HEADER, KEY, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG) - - // Check that data was properly recorded in the second ping. - assertTrue(jweMetric.testHasValue("store2")) - assertEquals(JWE, jweMetric.testGetCompactRepresentation("store2")) - - jweMetric.set(HEADER, "", "", CIPHER_TEXT, "") - // Check that data was properly recorded in the second ping. - assertTrue(jweMetric.testHasValue("store2")) - assertEquals(MINIMUM_JWE, jweMetric.testGetCompactRepresentation()) - } - - @Test - fun `Trying to set invalid values records errors`() { - // Define a 'jweMetric' jwe metric, which will be stored in "store1" and "store2" - val jweMetric = JweMetricType( - disabled = false, - category = "telemetry", - lifetime = Lifetime.Application, - name = "jwe_metric", - sendInPings = listOf("store1", "store2") - ) - - // Too long elements should yield a InvalidOverflow error - jweMetric.set("X".repeat(1025), KEY, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG) - assertEquals(1, jweMetric.testGetNumRecordedErrors(ErrorType.InvalidOverflow)) - - // Invalid compact string representation yield a InvalidValue error - jweMetric.setWithCompactRepresentation("") - assertEquals(1, jweMetric.testGetNumRecordedErrors(ErrorType.InvalidValue)) - } -} diff --git a/glean-core/ffi/src/jwe.rs b/glean-core/ffi/src/jwe.rs deleted file mode 100644 index f8a46c8b6..000000000 --- a/glean-core/ffi/src/jwe.rs +++ /dev/null @@ -1,83 +0,0 @@ -// 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 https://mozilla.org/MPL/2.0/. - -use std::os::raw::c_char; - -use ffi_support::FfiStr; - -use crate::ffi_string_ext::FallibleToString; -use crate::{define_metric, handlemap_ext::HandleMapExtension, with_glean_value, Lifetime}; - -define_metric!(JweMetric => JWE_METRICS { - new -> glean_new_jwe_metric(), - test_get_num_recorded_errors -> glean_jwe_test_get_num_recorded_errors, - destroy -> glean_destroy_jwe_metric, -}); - -#[no_mangle] -pub extern "C" fn glean_jwe_set_with_compact_representation(metric_id: u64, value: FfiStr) { - with_glean_value(|glean| { - JWE_METRICS.call_with_log(metric_id, |metric| { - let value = value.to_string_fallible()?; - metric.set_with_compact_representation(glean, value); - Ok(()) - }) - }) -} - -#[no_mangle] -pub extern "C" fn glean_jwe_set( - metric_id: u64, - header: FfiStr, - key: FfiStr, - init_vector: FfiStr, - cipher_text: FfiStr, - auth_tag: FfiStr, -) { - with_glean_value(|glean| { - JWE_METRICS.call_with_log(metric_id, |metric| { - let header = header.to_string_fallible()?; - let key = key.to_string_fallible()?; - let init_vector = init_vector.to_string_fallible()?; - let cipher_text = cipher_text.to_string_fallible()?; - let auth_tag = auth_tag.to_string_fallible()?; - metric.set(glean, header, key, init_vector, cipher_text, auth_tag); - Ok(()) - }) - }) -} - -#[no_mangle] -pub extern "C" fn glean_jwe_test_has_value(metric_id: u64, storage_name: FfiStr) -> u8 { - with_glean_value(|glean| { - JWE_METRICS.call_infallible(metric_id, |metric| { - metric - .test_get_value(glean, storage_name.as_str()) - .is_some() - }) - }) -} - -#[no_mangle] -pub extern "C" fn glean_jwe_test_get_value(metric_id: u64, storage_name: FfiStr) -> *mut c_char { - with_glean_value(|glean| { - JWE_METRICS.call_infallible(metric_id, |metric| { - metric.test_get_value(glean, storage_name.as_str()).unwrap() - }) - }) -} - -#[no_mangle] -pub extern "C" fn glean_jwe_test_get_value_as_json_string( - metric_id: u64, - storage_name: FfiStr, -) -> *mut c_char { - with_glean_value(|glean| { - JWE_METRICS.call_infallible(metric_id, |metric| { - metric - .test_get_value_as_json_string(glean, storage_name.as_str()) - .unwrap() - }) - }) -} diff --git a/glean-core/ffi/src/lib.rs b/glean-core/ffi/src/lib.rs index d5d57e9fe..9457886a9 100644 --- a/glean-core/ffi/src/lib.rs +++ b/glean-core/ffi/src/lib.rs @@ -32,7 +32,6 @@ mod event; mod ffi_string_ext; mod from_raw; mod handlemap_ext; -mod jwe; mod labeled; mod memory_distribution; pub mod ping_type; diff --git a/glean-core/ios/Glean.xcodeproj/project.pbxproj b/glean-core/ios/Glean.xcodeproj/project.pbxproj index 42415f357..78a1af781 100644 --- a/glean-core/ios/Glean.xcodeproj/project.pbxproj +++ b/glean-core/ios/Glean.xcodeproj/project.pbxproj @@ -25,8 +25,6 @@ 1FB8F8382326EABD00618E47 /* ConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FB8F8372326EABD00618E47 /* ConfigurationTests.swift */; }; 1FD4527523395B4500F4C7E8 /* UuidMetric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD4527423395B4500F4C7E8 /* UuidMetric.swift */; }; 1FD4527723395EEB00F4C7E8 /* UuidMetricTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD4527623395EEB00F4C7E8 /* UuidMetricTests.swift */; }; - 5FE1C4CF24C0A676000CAA1A /* JweMetricTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE1C4CE24C0A676000CAA1A /* JweMetricTests.swift */; }; - 5FE1C4D124C0A6A2000CAA1A /* JweMetric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE1C4D024C0A6A2000CAA1A /* JweMetric.swift */; }; 97C5C1A423708C6700B79C93 /* ErrorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97C5C1A323708C6700B79C93 /* ErrorType.swift */; }; AC06529C26E032E300D92D5E /* QuantityMetric.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC06529B26E032E300D92D5E /* QuantityMetric.swift */; }; AC06529E26E034BF00D92D5E /* QuantityMetricTypeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC06529D26E034BF00D92D5E /* QuantityMetricTypeTest.swift */; }; @@ -119,8 +117,6 @@ 1FB8F8372326EABD00618E47 /* ConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationTests.swift; sourceTree = ""; }; 1FD4527423395B4500F4C7E8 /* UuidMetric.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UuidMetric.swift; sourceTree = ""; }; 1FD4527623395EEB00F4C7E8 /* UuidMetricTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UuidMetricTests.swift; sourceTree = ""; }; - 5FE1C4CE24C0A676000CAA1A /* JweMetricTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JweMetricTests.swift; sourceTree = ""; }; - 5FE1C4D024C0A6A2000CAA1A /* JweMetric.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JweMetric.swift; sourceTree = ""; }; 97C5C1A323708C6700B79C93 /* ErrorType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorType.swift; sourceTree = ""; }; AC06529B26E032E300D92D5E /* QuantityMetric.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuantityMetric.swift; sourceTree = ""; }; AC06529D26E034BF00D92D5E /* QuantityMetricTypeTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuantityMetricTypeTest.swift; sourceTree = ""; }; @@ -354,7 +350,6 @@ BF6C53B1232F870C00E3B43A /* Ping.swift */, BF30FDC3233260B500840607 /* TimespanMetric.swift */, BF30FDC72332640400840607 /* TimeUnit.swift */, - 5FE1C4D024C0A6A2000CAA1A /* JweMetric.swift */, BF10007D23548AF400064051 /* MemoryUnit.swift */, BFAED5072369751100DF293D /* StringListMetric.swift */, BF89055E232BC213003CA2BA /* StringMetric.swift */, @@ -373,7 +368,6 @@ isa = PBXGroup; children = ( AC06529D26E034BF00D92D5E /* QuantityMetricTypeTest.swift */, - 5FE1C4CE24C0A676000CAA1A /* JweMetricTests.swift */, 1F6A8FF1233C068A007837D5 /* BooleanMetricTypeTest.swift */, BF43A8CC232A615200545310 /* CounterMetricTests.swift */, 1F6A8FF5233C1555007837D5 /* DatetimeMetricTypeTests.swift */, @@ -609,7 +603,6 @@ BF43A8C7232A4BA400545310 /* CounterMetric.swift in Sources */, BFFE33AB232927C3005348FE /* Utils.swift in Sources */, BFE1CDC4233B63A70019EE47 /* LabeledMetric.swift in Sources */, - 5FE1C4D124C0A6A2000CAA1A /* JweMetric.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -639,7 +632,6 @@ BFFE183A2350A61F0068D97B /* TimingDistributionMetricTests.swift in Sources */, BF3DE3A02243A2F20018E23F /* GleanTests.swift in Sources */, BF2E57072334BD7600364D92 /* EventMetricTests.swift in Sources */, - 5FE1C4CF24C0A676000CAA1A /* JweMetricTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/glean-core/ios/Glean/Metrics/JweMetric.swift b/glean-core/ios/Glean/Metrics/JweMetric.swift deleted file mode 100644 index 062358a86..000000000 --- a/glean-core/ios/Glean/Metrics/JweMetric.swift +++ /dev/null @@ -1,179 +0,0 @@ -/* 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/. */ - -import Foundation - -/// A representation of a JWE value. -public struct JweData { - let header: String - let key: String - let initVector: String - let cipherText: String - let authTag: String -} - -/// This implements the developer facing API for recording JWE metrics. -/// -/// Instances of this class type are automatically generated by the parsers at build time, -/// allowing developers to record values that were previously registered in the metrics.yaml file. -/// -/// The JWE API exposes the `JweMetricType.set(_:)` and `JweMetricType.setWithCompactRepresentation(_:)` methods, -/// which takes care of validating the input data. -public class JweMetricType { - let handle: UInt64 - let disabled: Bool - let sendInPings: [String] - - /// The public constructor used by automatically generated metrics. - public init(category: String, name: String, sendInPings: [String], lifetime: Lifetime, disabled: Bool) { - self.disabled = disabled - self.sendInPings = sendInPings - self.handle = withArrayOfCStrings(sendInPings) { pingArray in - glean_new_jwe_metric( - category, - name, - pingArray, - Int32(sendInPings.count), - lifetime.rawValue, - disabled.toByte() - ) - } - } - - /// Destroy this metric. - deinit { - if self.handle != 0 { - glean_destroy_jwe_metric(self.handle) - } - } - - /// Set a JWE value. - /// - /// - parameters: - /// * header: value The [`compact representation`](https://tools.ietf.org/html/rfc7516#appendix-A.2.7) of a JWE value. - public func setWithCompactRepresentation(_ value: String) { - guard !self.disabled else { return } - - Dispatchers.shared.launchAPI { - glean_jwe_set_with_compact_representation(self.handle, value) - } - } - - /// Build a JWE value from it's elements and set to it. - /// - /// - parameters: - /// * header: A variable-size JWE protected header. - /// * key: A variable-size encrypted key. - /// This can be an empty octet sequence. - /// * initVector: A fixed-size, 96-bit, base64 encoded Jwe initialization vector. - /// If not required by the encryption algorithm, can be an empty octet sequence. - /// * cipherText: The variable-size base64 encoded cipher text. - /// * authTag: A fixed-size, 132-bit, base64 encoded authentication tag. - /// Can be an empty octet sequence. - public func set(_ header: String, _ key: String, _ initVector: String, _ cipherText: String, _ authTag: String) { - guard !self.disabled else { return } - - Dispatchers.shared.launchAPI { - glean_jwe_set(self.handle, header, key, initVector, cipherText, authTag) - } - } - - /// Tests whether a value is stored for the metric for testing purposes only. This function will - /// attempt to await the last task (if any) writing to the the metric's storage engine before - /// returning a value. - /// - /// - parameters: - /// * pingName: represents the name of the ping to retrieve the metric for. - /// Defaults to the first value in `sendInPings`. - /// - returns: true if metric value exists, otherwise false - public func testHasValue(_ pingName: String? = nil) -> Bool { - Dispatchers.shared.assertInTestingMode() - - let pingName = pingName ?? self.sendInPings[0] - return glean_jwe_test_has_value(self.handle, pingName).toBool() - } - - // swiftlint:disable force_cast - /// Returns the stored value for testing purposes only. This function will attempt to await the - /// last task (if any) writing to the the metric's storage engine before returning a value. - /// - /// Throws a "Missing value" exception if no value is stored. - /// - /// - parameters: - /// * pingName: represents the name of the ping to retrieve the metric for. - /// Defaults to the first value in `sendInPings`. - /// - /// - returns: value of the stored metric - public func testGetValue(_ pingName: String? = nil) throws -> JweData { - Dispatchers.shared.assertInTestingMode() - - let pingName = pingName ?? self.sendInPings[0] - - if !testHasValue(pingName) { - throw "Missing value" - } - - var data: JweData? - - let jsonString = String(freeingGleanString: glean_jwe_test_get_value_as_json_string(self.handle, pingName)) - if let jsonData: Data = jsonString.data(using: .utf8, allowLossyConversion: false) { - if let json = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] { - data = JweData( - header: json["header"] as! String, - key: json["key"] as! String, - initVector: json["init_vector"] as! String, - cipherText: json["cipher_text"] as! String, - authTag: json["auth_tag"] as! String - ) - } - } - - return data! - } - - // swiftlint:enable force_cast - - /// Returns the stored value in the compact representation for testing purposes only. - /// This function will attempt to await the last task (if any) - /// writing to the metric's storage engine before returning a value. - /// - /// Throws a "Missing value" exception if no value is stored. - /// - /// - parameters: - /// * pingName: represents the name of the ping to retrieve the metric for. - /// Defaults to the first value in `sendInPings`. - /// - /// - returns: value of the stored metric - public func testGetCompactRepresentation(_ pingName: String? = nil) throws -> String { - Dispatchers.shared.assertInTestingMode() - - let pingName = pingName ?? self.sendInPings[0] - - if !testHasValue(pingName) { - throw "Missing value" - } - - return String(freeingGleanString: glean_jwe_test_get_value(self.handle, pingName)) - } - - /// Returns the number of errors recorded for the given metric. - /// - /// - parameters: - /// * errorType: The type of error recorded. - /// * pingName: represents the name of the ping to retrieve the metric for. - /// Defaults to the first value in `sendInPings`. - /// - /// - returns: The number of errors recorded for the metric for the given error type. - public func testGetNumRecordedErrors(_ errorType: ErrorType, pingName: String? = nil) -> Int32 { - Dispatchers.shared.assertInTestingMode() - - let pingName = pingName ?? self.sendInPings[0] - - return glean_jwe_test_get_num_recorded_errors( - self.handle, - errorType.rawValue, - pingName - ) - } -} diff --git a/glean-core/ios/GleanTests/Metrics/JweMetricTests.swift b/glean-core/ios/GleanTests/Metrics/JweMetricTests.swift deleted file mode 100644 index 895c4a3fd..000000000 --- a/glean-core/ios/GleanTests/Metrics/JweMetricTests.swift +++ /dev/null @@ -1,137 +0,0 @@ -/* 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/. */ - -@testable import Glean -import XCTest - -// swiftlint:disable force_cast -// REASON: Used in a test -class JweMetricTests: XCTestCase { - // swiftlint:disable line_length - private let header: String = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ" - private let key: String = "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg" - private let initVector: String = "48V1_ALb6US04U3b" - private let cipherText: String = "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A" - private let authTag: String = "XFBoMYUZodetZdvTiFvSkQ" - private let jwe: String = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ" - private let minimumJwe: String = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ...5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A." - // swiftlint:enable line_length - - override func setUp() { - resetGleanDiscardingInitialPings(testCase: self, tag: "JweMetricTests") - } - - override func tearDown() { - tearDownStubs() - } - - func testJweSavesToStorage() { - let jweMetric = JweMetricType( - category: "telemetry", - name: "jwe_metric", - sendInPings: ["store1"], - lifetime: .application, - disabled: false - ) - - XCTAssertFalse(jweMetric.testHasValue()) - - jweMetric.set(self.header, self.key, self.initVector, self.cipherText, self.authTag) - - XCTAssert(jweMetric.testHasValue()) - XCTAssertEqual(self.jwe, try jweMetric.testGetCompactRepresentation()) - - jweMetric.set(self.header, "", "", self.cipherText, "") - - XCTAssert(jweMetric.testHasValue()) - XCTAssertEqual(self.minimumJwe, try jweMetric.testGetCompactRepresentation()) - } - - func testJweMustNotRecordIfDisabled() { - let jweMetric = JweMetricType( - category: "telemetry", - name: "jwe_metric", - sendInPings: ["store1"], - lifetime: .application, - disabled: true - ) - - XCTAssertFalse(jweMetric.testHasValue()) - - jweMetric.setWithCompactRepresentation(self.jwe) - - XCTAssertFalse(jweMetric.testHasValue(), "JWEs must not be recorded if they are disabled") - } - - func testJweGetValueThrowsExceptionIfNothingIsStored() { - let jweMetric = JweMetricType( - category: "telemetry", - name: "jwe_metric", - sendInPings: ["store1"], - lifetime: .application, - disabled: false - ) - - XCTAssertThrowsError(try jweMetric.testGetValue()) { error in - XCTAssertEqual(error as! String, "Missing value") - } - } - - func testJweGetValueReturnsCorrectJweDataRepresentation() { - let jweMetric = JweMetricType( - category: "telemetry", - name: "jwe_metric", - sendInPings: ["store1"], - lifetime: .application, - disabled: false - ) - - jweMetric.set(self.header, self.key, self.initVector, self.cipherText, self.authTag) - - let data = try! jweMetric.testGetValue() - XCTAssertEqual(data.header, self.header) - XCTAssertEqual(data.key, self.key) - XCTAssertEqual(data.initVector, self.initVector) - XCTAssertEqual(data.cipherText, self.cipherText) - XCTAssertEqual(data.authTag, self.authTag) - } - - func testJweSavesToSecondaryPings() { - let jweMetric = JweMetricType( - category: "telemetry", - name: "jwe_metric", - sendInPings: ["store1", "store2"], - lifetime: .application, - disabled: false - ) - - jweMetric.set(self.header, self.key, self.initVector, self.cipherText, self.authTag) - - XCTAssert(jweMetric.testHasValue("store2")) - XCTAssertEqual(jwe, try jweMetric.testGetCompactRepresentation()) - - jweMetric.set(self.header, "", "", self.cipherText, "") - - XCTAssert(jweMetric.testHasValue()) - XCTAssertEqual(self.minimumJwe, try jweMetric.testGetCompactRepresentation()) - } - - func testSettingInvalidValuesRecordsErrors() { - let jweMetric = JweMetricType( - category: "telemetry", - name: "jwe_metric", - sendInPings: ["store1"], - lifetime: .application, - disabled: false - ) - - // Too long elements should yield a InvalidOverflow error - jweMetric.set(String(repeating: "X", count: 1025), self.key, self.initVector, self.cipherText, self.authTag) - XCTAssertEqual(1, jweMetric.testGetNumRecordedErrors(ErrorType.invalidOverflow)) - - // Invalid compact string representation yield a InvalidValue error - jweMetric.setWithCompactRepresentation("") - XCTAssertEqual(1, jweMetric.testGetNumRecordedErrors(ErrorType.invalidValue)) - } -} diff --git a/glean-core/python/glean/metrics/jwe.py b/glean-core/python/glean/metrics/jwe.py deleted file mode 100644 index 6f8b5481b..000000000 --- a/glean-core/python/glean/metrics/jwe.py +++ /dev/null @@ -1,221 +0,0 @@ -# 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/. - - -from typing import List, Optional -import json - - -from .. import _ffi -from .._dispatcher import Dispatcher -from ..testing import ErrorType - - -from .lifetime import Lifetime - - -class JweData: - """ - A representation of a JWE value. - """ - - def __init__( - self, header: str, key: str, init_vector: str, cipher_text: str, auth_tag: str - ): - - self.header = header - self.key = key - self.init_vector = init_vector - self.cipher_text = cipher_text - self.auth_tag = auth_tag - - -class JweMetricType: - """ - This implements the developer facing API for recording JWE metrics. - - Instances of this class type are automatically generated by - `glean.load_metrics`, allowing developers to record values that were - previously registered in the metrics.yaml file. - - The string API exposes the `JweMetricType.set` and - `JweMetricType.setWithCompactRepresentation` methods, - which take care of validating the input data - and making sure that limits are enforced. - """ - - def __init__( - self, - disabled: bool, - category: str, - lifetime: Lifetime, - name: str, - send_in_pings: List[str], - ): - self._disabled = disabled - self._send_in_pings = send_in_pings - - self._handle = _ffi.lib.glean_new_jwe_metric( - _ffi.ffi_encode_string(category), - _ffi.ffi_encode_string(name), - _ffi.ffi_encode_vec_string(send_in_pings), - len(send_in_pings), - lifetime.value, - disabled, - ) - - def __del__(self): - if getattr(self, "_handle", 0) != 0: - _ffi.lib.glean_destroy_jwe_metric(self._handle) - - def set_with_compact_representation(self, value: str): - """ - Set to the specified JWE value. - - Args: - value (str): the compact representation of a JWE value. - """ - if self._disabled: - return - - @Dispatcher.launch - def set(): - _ffi.lib.glean_jwe_set_with_compact_representation( - self._handle, _ffi.ffi_encode_string(value) - ) - - def set( - self, header: str, key: str, init_vector: str, cipher_text: str, auth_tag: str - ) -> None: - """ - Build a JWE value from its elements and set to it. - - Args: - header (str): A variable-size JWE protected header. - key (str): A variable-size encrypted key. - This can be an empty octet sequence. - init_vector (str): A fixed-size, 96-bit, base64 encoded Jwe initialization vector. - If not required by the encryption algorithm, can be an empty octet sequence. - cipher_text (str): The variable-size base64 encoded cipher text. - auth_tag (str): A fixed-size, 132-bit, base64 encoded authentication tag. - Can be an empty octet sequence. - """ - if self._disabled: - return - - @Dispatcher.launch - def set(): - _ffi.lib.glean_jwe_set( - self._handle, - _ffi.ffi_encode_string(header), - _ffi.ffi_encode_string(key), - _ffi.ffi_encode_string(init_vector), - _ffi.ffi_encode_string(cipher_text), - _ffi.ffi_encode_string(auth_tag), - ) - - def test_has_value(self, ping_name: Optional[str] = None) -> bool: - """ - Tests whether a value is stored for the metric for testing purposes - only. - - Args: - ping_name (str): (default: first value in send_in_pings) The name - of the ping to retrieve the metric for. - - Returns: - has_value (bool): True if the metric value exists. - """ - if ping_name is None: - ping_name = self._send_in_pings[0] - - return bool( - _ffi.lib.glean_jwe_test_has_value( - self._handle, _ffi.ffi_encode_string(ping_name) - ) - ) - - def test_get_value(self, ping_name: Optional[str] = None) -> JweData: - """ - Returns the stored value for testing purposes only. - - Args: - ping_name (str): (default: first value in send_in_pings) The name - of the ping to retrieve the metric for. - - Returns: - value (JweData): value of the stored metric. - """ - if ping_name is None: - ping_name = self._send_in_pings[0] - - if not self.test_has_value(ping_name): - raise ValueError("metric has no value") - - json_payload = json.loads( - _ffi.ffi_decode_string( - _ffi.lib.glean_jwe_test_get_value_as_json_string( - self._handle, _ffi.ffi_encode_string(ping_name) - ) - ) - ) - - return JweData( - json_payload["header"], - json_payload["key"], - json_payload["init_vector"], - json_payload["cipher_text"], - json_payload["auth_tag"], - ) - - def test_get_compact_representation(self, ping_name: Optional[str] = None) -> str: - """ - Returns the stored value as the compact representation - for testing purposes only. - - Args: - ping_name (str): (default: first value in send_in_pings) The name - of the ping to retrieve the metric for. - - Returns: - value (JweData): value of the stored metric. - """ - if ping_name is None: - ping_name = self._send_in_pings[0] - - if not self.test_has_value(ping_name): - raise ValueError("metric has no value") - - return _ffi.ffi_decode_string( - _ffi.lib.glean_jwe_test_get_value( - self._handle, _ffi.ffi_encode_string(ping_name) - ) - ) - - def test_get_num_recorded_errors( - self, error_type: ErrorType, ping_name: Optional[str] = None - ) -> int: - """ - Returns the number of errors recorded for the given metric. - - Args: - error_type (ErrorType): The type of error recorded. - ping_name (str): (default: first value in send_in_pings) The name - of the ping to retrieve the metric for. - - Returns: - num_errors (int): The number of errors recorded for the metric for - the given error type. - """ - if ping_name is None: - ping_name = self._send_in_pings[0] - - return _ffi.lib.glean_jwe_test_get_num_recorded_errors( - self._handle, - error_type.value, - _ffi.ffi_encode_string(ping_name), - ) - - -__all__ = ["JweMetricType"] diff --git a/glean-core/python/tests/metrics/test_jwe.py b/glean-core/python/tests/metrics/test_jwe.py deleted file mode 100644 index f9c3dfa4d..000000000 --- a/glean-core/python/tests/metrics/test_jwe.py +++ /dev/null @@ -1,108 +0,0 @@ -# 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/. - -# flake8: noqa E501 - -from glean import metrics -from glean.metrics import Lifetime -from glean import testing - -header = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ" -key = "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg" -init_vector = "48V1_ALb6US04U3b" -cipher_text = "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A" -auth_tag = "XFBoMYUZodetZdvTiFvSkQ" -jwe = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ" -minimum_jwe = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ...5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A." - - -def test_the_api_saves_to_its_storage_engine(): - jwe_metric = metrics.JweMetricType( - disabled=False, - category="telemetry", - lifetime=Lifetime.APPLICATION, - name="jwe_metric", - send_in_pings=["store1"], - ) - - jwe_metric.set(header, key, init_vector, cipher_text, auth_tag) - - assert jwe_metric.test_has_value() - assert jwe == jwe_metric.test_get_compact_representation() - - jwe_metric.set(header, "", "", cipher_text, "") - - assert jwe_metric.test_has_value() - assert minimum_jwe == jwe_metric.test_get_compact_representation() - - -def test_disabled_jwes_must_not_record_data(): - jwe_metric = metrics.JweMetricType( - disabled=True, - category="telemetry", - lifetime=Lifetime.APPLICATION, - name="jwe_metric", - send_in_pings=["store1"], - ) - - jwe_metric.set(header, key, init_vector, cipher_text, auth_tag) - - assert not jwe_metric.test_has_value() - - -def test_jwe_get_value_returns_correct_jwe_data_representation(): - jwe_metric = metrics.JweMetricType( - disabled=False, - category="telemetry", - lifetime=Lifetime.APPLICATION, - name="jwe_metric", - send_in_pings=["store1"], - ) - - jwe_metric.set(header, key, init_vector, cipher_text, auth_tag) - - data = jwe_metric.test_get_value() - assert data.header == header - assert data.key == key - assert data.init_vector == init_vector - assert data.cipher_text == cipher_text - assert data.auth_tag == auth_tag - - -def test_the_api_saves_to_secondary_pings(): - jwe_metric = metrics.JweMetricType( - disabled=False, - category="telemetry", - lifetime=Lifetime.APPLICATION, - name="jwe_metric", - send_in_pings=["store1", "store2"], - ) - - jwe_metric.set(header, key, init_vector, cipher_text, auth_tag) - - assert jwe_metric.test_has_value("store2") - assert jwe == jwe_metric.test_get_compact_representation("store2") - - jwe_metric.set(header, "", "", cipher_text, "") - - assert jwe_metric.test_has_value("store2") - assert minimum_jwe == jwe_metric.test_get_compact_representation("store2") - - -def test_setting_invalid_values_record_errors(): - jwe_metric = metrics.JweMetricType( - disabled=False, - category="telemetry", - lifetime=Lifetime.APPLICATION, - name="jwe_metric", - send_in_pings=["store1", "store2"], - ) - - jwe_metric.set("X" * 1025, key, init_vector, cipher_text, auth_tag) - assert 1 == jwe_metric.test_get_num_recorded_errors( - testing.ErrorType.INVALID_OVERFLOW - ) - - jwe_metric.set_with_compact_representation("") - assert 1 == jwe_metric.test_get_num_recorded_errors(testing.ErrorType.INVALID_VALUE) diff --git a/glean-core/src/metrics/jwe.rs b/glean-core/src/metrics/jwe.rs deleted file mode 100644 index d737bb073..000000000 --- a/glean-core/src/metrics/jwe.rs +++ /dev/null @@ -1,469 +0,0 @@ -// 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 https://mozilla.org/MPL/2.0/. - -use std::fmt; -use std::str::FromStr; - -use serde::Serialize; - -use crate::error_recording::{record_error, ErrorType}; -use crate::metrics::{Metric, MetricType}; -use crate::storage::StorageManager; -use crate::CommonMetricData; -use crate::Glean; - -const DEFAULT_MAX_CHARS_PER_VARIABLE_SIZE_ELEMENT: usize = 1024; - -/// Verifies if a string is [`BASE64URL`](https://tools.ietf.org/html/rfc4648#section-5) compliant. -/// -/// As such, the string must match the regex: `[a-zA-Z0-9\-\_]*`. -/// -/// > **Note** As described in the [JWS specification](https://tools.ietf.org/html/rfc7515#section-2), -/// > the BASE64URL encoding used by JWE discards any padding, -/// > that is why we can ignore that for this validation. -/// -/// The regex crate isn't used here because it adds to the binary size, -/// and the Glean SDK doesn't use regular expressions anywhere else. -fn validate_base64url_encoding(value: &str) -> bool { - let mut iter = value.chars(); - - loop { - match iter.next() { - // We are done, so the whole expression is valid. - None => return true, - // Valid characters. - Some('_') | Some('-') | Some('a'..='z') | Some('A'..='Z') | Some('0'..='9') => (), - // An invalid character. - Some(_) => return false, - } - } -} - -/// Representation of a [JWE](https://tools.ietf.org/html/rfc7516). -/// -/// **Note** Variable sized elements will be constrained to a length of DEFAULT_MAX_CHARS_PER_VARIABLE_SIZE_ELEMENT, -/// this is a constraint introduced by Glean to prevent abuses and not part of the spec. -#[derive(Serialize)] -struct Jwe { - /// A variable-size JWE protected header. - header: String, - /// A variable-size [encrypted key](https://tools.ietf.org/html/rfc7516#appendix-A.1.3). - /// This can be an empty octet sequence. - key: String, - /// A fixed-size, 96-bit, base64 encoded [JWE Initialization vector](https://tools.ietf.org/html/rfc7516#appendix-A.1.4) (e.g. “48V1_ALb6US04U3b”). - /// If not required by the encryption algorithm, can be an empty octet sequence. - init_vector: String, - /// The variable-size base64 encoded cipher text. - cipher_text: String, - /// A fixed-size, 132-bit, base64 encoded authentication tag. - /// Can be an empty octet sequence. - auth_tag: String, -} - -// IMPORTANT: -// -// When changing this implementation, make sure all the operations are -// also declared in the related trait in `../traits/`. -impl Jwe { - /// Create a new JWE struct. - fn new>( - header: S, - key: S, - init_vector: S, - cipher_text: S, - auth_tag: S, - ) -> Result { - let mut header = header.into(); - header = Self::validate_non_empty("header", header)?; - header = Self::validate_max_size("header", header)?; - header = Self::validate_base64url_encoding("header", header)?; - - let mut key = key.into(); - key = Self::validate_max_size("key", key)?; - key = Self::validate_base64url_encoding("key", key)?; - - let mut init_vector = init_vector.into(); - init_vector = Self::validate_fixed_size_or_empty("init_vector", init_vector, 96)?; - init_vector = Self::validate_base64url_encoding("init_vector", init_vector)?; - - let mut cipher_text = cipher_text.into(); - cipher_text = Self::validate_non_empty("cipher_text", cipher_text)?; - cipher_text = Self::validate_max_size("cipher_text", cipher_text)?; - cipher_text = Self::validate_base64url_encoding("cipher_text", cipher_text)?; - - let mut auth_tag = auth_tag.into(); - auth_tag = Self::validate_fixed_size_or_empty("auth_tag", auth_tag, 128)?; - auth_tag = Self::validate_base64url_encoding("auth_tag", auth_tag)?; - - Ok(Self { - header, - key, - init_vector, - cipher_text, - auth_tag, - }) - } - - fn validate_base64url_encoding( - name: &str, - value: String, - ) -> Result { - if !validate_base64url_encoding(&value) { - return Err(( - ErrorType::InvalidValue, - format!("`{}` element in JWE value is not valid BASE64URL.", name), - )); - } - - Ok(value) - } - - fn validate_non_empty(name: &str, value: String) -> Result { - if value.is_empty() { - return Err(( - ErrorType::InvalidValue, - format!("`{}` element in JWE value must not be empty.", name), - )); - } - - Ok(value) - } - - fn validate_max_size(name: &str, value: String) -> Result { - if value.len() > DEFAULT_MAX_CHARS_PER_VARIABLE_SIZE_ELEMENT { - return Err(( - ErrorType::InvalidOverflow, - format!( - "`{}` element in JWE value must not exceed {} characters.", - name, DEFAULT_MAX_CHARS_PER_VARIABLE_SIZE_ELEMENT - ), - )); - } - - Ok(value) - } - - fn validate_fixed_size_or_empty( - name: &str, - value: String, - size_in_bits: usize, - ) -> Result { - // Each Base64 digit represents exactly 6 bits of data. - // By dividing the size_in_bits by 6 and ceiling the result, - // we get the amount of characters the value should have. - let num_chars = (size_in_bits as f32 / 6f32).ceil() as usize; - if !value.is_empty() && value.len() != num_chars { - return Err(( - ErrorType::InvalidOverflow, - format!( - "`{}` element in JWE value must have exactly {}-bits or be empty.", - name, size_in_bits - ), - )); - } - - Ok(value) - } -} - -/// Trait implementation to convert a JWE [`compact representation`](https://tools.ietf.org/html/rfc7516#appendix-A.2.7) -/// string into a Jwe struct. -impl FromStr for Jwe { - type Err = (ErrorType, String); - - fn from_str(s: &str) -> Result { - let mut elements: Vec<&str> = s.split('.').collect(); - - if elements.len() != 5 { - return Err(( - ErrorType::InvalidValue, - "JWE value is not formatted as expected.".into(), - )); - } - - // Consume the vector extracting each part of the JWE from it. - // - // Safe unwraps, we already defined that the slice has five elements. - let auth_tag = elements.pop().unwrap(); - let cipher_text = elements.pop().unwrap(); - let init_vector = elements.pop().unwrap(); - let key = elements.pop().unwrap(); - let header = elements.pop().unwrap(); - - Self::new(header, key, init_vector, cipher_text, auth_tag) - } -} - -/// Trait implementation to print the Jwe struct as the proper JWE [`compact representation`](https://tools.ietf.org/html/rfc7516#appendix-A.2.7). -impl fmt::Display for Jwe { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{}.{}.{}.{}.{}", - self.header, self.key, self.init_vector, self.cipher_text, self.auth_tag - ) - } -} - -/// A JWE metric. -/// -/// This metric will be work as a "transport" for JWE encrypted data. -/// -/// The actual encrypti on is done somewhere else, -/// Glean must only make sure the data is valid JWE. -#[derive(Clone, Debug)] -pub struct JweMetric { - meta: CommonMetricData, -} - -impl MetricType for JweMetric { - fn meta(&self) -> &CommonMetricData { - &self.meta - } -} - -impl JweMetric { - /// Creates a new JWE metric. - pub fn new(meta: CommonMetricData) -> Self { - Self { meta } - } - - /// Sets to the specified JWE value. - /// - /// # Arguments - /// - /// * `glean` - the Glean instance this metric belongs to. - /// * `value` - the [`compact representation`](https://tools.ietf.org/html/rfc7516#appendix-A.2.7) of a JWE value. - pub fn set_with_compact_representation>(&self, glean: &Glean, value: S) { - if !self.should_record(glean) { - return; - } - - let value = value.into(); - match Jwe::from_str(&value) { - Ok(_) => glean - .storage() - .record(glean, &self.meta, &Metric::Jwe(value)), - Err((error_type, msg)) => record_error(glean, &self.meta, error_type, msg, None), - }; - } - - /// Builds a JWE value from its elements and set to it. - /// - /// # Arguments - /// - /// * `glean` - the Glean instance this metric belongs to. - /// * `header` - the JWE Protected Header element. - /// * `key` - the JWE Encrypted Key element. - /// * `init_vector` - the JWE Initialization Vector element. - /// * `cipher_text` - the JWE Ciphertext element. - /// * `auth_tag` - the JWE Authentication Tag element. - pub fn set>( - &self, - glean: &Glean, - header: S, - key: S, - init_vector: S, - cipher_text: S, - auth_tag: S, - ) { - if !self.should_record(glean) { - return; - } - - match Jwe::new(header, key, init_vector, cipher_text, auth_tag) { - Ok(jwe) => glean - .storage() - .record(glean, &self.meta, &Metric::Jwe(jwe.to_string())), - Err((error_type, msg)) => record_error(glean, &self.meta, error_type, msg, None), - }; - } - - /// **Test-only API (exported for FFI purposes).** - /// - /// Gets the currently stored value as a string. - /// - /// This doesn't clear the stored value. - pub fn test_get_value(&self, glean: &Glean, storage_name: &str) -> Option { - match StorageManager.snapshot_metric_for_test( - glean.storage(), - storage_name, - &self.meta.identifier(glean), - self.meta.lifetime, - ) { - Some(Metric::Jwe(b)) => Some(b), - _ => None, - } - } - - /// **Test-only API (exported for FFI purposes).** - /// - /// Gets the currently stored JWE as a JSON String of the serialized value. - /// - /// This doesn't clear the stored value. - pub fn test_get_value_as_json_string( - &self, - glean: &Glean, - storage_name: &str, - ) -> Option { - self.test_get_value(glean, storage_name).map(|snapshot| { - serde_json::to_string( - &Jwe::from_str(&snapshot).expect("Stored JWE metric should be valid JWE value."), - ) - .unwrap() - }) - } -} - -#[cfg(test)] -mod test { - use super::*; - - const HEADER: &str = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ"; - const KEY: &str = "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg"; - const INIT_VECTOR: &str = "48V1_ALb6US04U3b"; - const CIPHER_TEXT: &str = - "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A"; - const AUTH_TAG: &str = "XFBoMYUZodetZdvTiFvSkQ"; - const JWE: &str = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ"; - - #[test] - fn generates_jwe_from_correct_input() { - let jwe = Jwe::from_str(JWE).unwrap(); - assert_eq!(jwe.header, HEADER); - assert_eq!(jwe.key, KEY); - assert_eq!(jwe.init_vector, INIT_VECTOR); - assert_eq!(jwe.cipher_text, CIPHER_TEXT); - assert_eq!(jwe.auth_tag, AUTH_TAG); - - assert!(Jwe::new(HEADER, KEY, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG).is_ok()); - } - - #[test] - fn jwe_validates_header_value_correctly() { - // When header is empty, correct error is returned - match Jwe::new("", KEY, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidValue), - } - - // When header is bigger than max size, correct error is returned - let too_long = (0..1025).map(|_| "X").collect::(); - match Jwe::new( - too_long, - KEY.into(), - INIT_VECTOR.into(), - CIPHER_TEXT.into(), - AUTH_TAG.into(), - ) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidOverflow), - } - - // When header is not valid BASE64URL, correct error is returned - let not64 = "inv@alid value!"; - match Jwe::new(not64, KEY, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidValue), - } - } - - #[test] - fn jwe_validates_key_value_correctly() { - // When key is empty,JWE is created - assert!(Jwe::new(HEADER, "", INIT_VECTOR, CIPHER_TEXT, AUTH_TAG).is_ok()); - - // When key is bigger than max size, correct error is returned - let too_long = (0..1025).map(|_| "X").collect::(); - match Jwe::new(HEADER, &too_long, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidOverflow), - } - - // When key is not valid BASE64URL, correct error is returned - let not64 = "inv@alid value!"; - match Jwe::new(HEADER, not64, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidValue), - } - } - - #[test] - fn jwe_validates_init_vector_value_correctly() { - // When init_vector is empty, JWE is created - assert!(Jwe::new(HEADER, KEY, "", CIPHER_TEXT, AUTH_TAG).is_ok()); - - // When init_vector is not the correct size, correct error is returned - match Jwe::new(HEADER, KEY, "foo", CIPHER_TEXT, AUTH_TAG) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidOverflow), - } - - // When init_vector is not valid BASE64URL, correct error is returned - let not64 = "inv@alid value!!"; - match Jwe::new(HEADER, KEY, not64, CIPHER_TEXT, AUTH_TAG) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidValue), - } - } - - #[test] - fn jwe_validates_cipher_text_value_correctly() { - // When cipher_text is empty, correct error is returned - match Jwe::new(HEADER, KEY, INIT_VECTOR, "", AUTH_TAG) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidValue), - } - - // When cipher_text is bigger than max size, correct error is returned - let too_long = (0..1025).map(|_| "X").collect::(); - match Jwe::new(HEADER, KEY, INIT_VECTOR, &too_long, AUTH_TAG) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidOverflow), - } - - // When cipher_text is not valid BASE64URL, correct error is returned - let not64 = "inv@alid value!"; - match Jwe::new(HEADER, KEY, INIT_VECTOR, not64, AUTH_TAG) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidValue), - } - } - - #[test] - fn jwe_validates_auth_tag_value_correctly() { - // When auth_tag is empty, JWE is created - assert!(Jwe::new(HEADER, KEY, INIT_VECTOR, CIPHER_TEXT, "").is_ok()); - - // When auth_tag is not the correct size, correct error is returned - match Jwe::new(HEADER, KEY, INIT_VECTOR, CIPHER_TEXT, "foo") { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidOverflow), - } - - // When auth_tag is not valid BASE64URL, correct error is returned - let not64 = "inv@alid value!!!!!!!!"; - match Jwe::new(HEADER, KEY, INIT_VECTOR, CIPHER_TEXT, not64) { - Ok(_) => panic!("Should not have built JWE successfully."), - Err((error_type, _)) => assert_eq!(error_type, ErrorType::InvalidValue), - } - } - - #[test] - fn tranforms_jwe_struct_to_string_correctly() { - let jwe = Jwe::from_str(JWE).unwrap(); - assert_eq!(jwe.to_string(), JWE); - } - - #[test] - fn validates_base64url_correctly() { - assert!(validate_base64url_encoding( - "0987654321AaBbCcDdEeFfGgHhIiKkLlMmNnOoPpQqRrSsTtUuVvXxWwYyZz-_" - )); - assert!(validate_base64url_encoding("")); - assert!(!validate_base64url_encoding("aa aa")); - assert!(!validate_base64url_encoding("aa.aa")); - assert!(!validate_base64url_encoding("!nv@lid-val*e")); - } -} diff --git a/glean-core/src/metrics/mod.rs b/glean-core/src/metrics/mod.rs index 9fcc532ce..8b1ba86fd 100644 --- a/glean-core/src/metrics/mod.rs +++ b/glean-core/src/metrics/mod.rs @@ -17,7 +17,6 @@ mod datetime; mod denominator; mod event; mod experiment; -mod jwe; pub(crate) mod labeled; mod memory_distribution; mod memory_unit; @@ -47,7 +46,6 @@ pub use self::datetime::DatetimeMetric; pub use self::denominator::DenominatorMetric; pub use self::event::EventMetric; pub(crate) use self::experiment::ExperimentMetric; -pub use self::jwe::JweMetric; pub use self::labeled::{LabeledBoolean, LabeledCounter, LabeledMetric, LabeledString}; pub use self::memory_distribution::MemoryDistributionMetric; pub use self::memory_unit::MemoryUnit; @@ -117,7 +115,9 @@ pub enum Metric { TimingDistribution(Histogram), /// A memory distribution. See [`MemoryDistributionMetric`] for more information. MemoryDistribution(Histogram), - /// A JWE metric. See [`JweMetric`] for more information. + /// **DEPRECATED**: A JWE metric.. + /// Note: This variant MUST NOT be removed to avoid backwards-incompatible changes to the + /// serialization. This type has no underlying implementation anymore. Jwe(String), /// A rate metric. See [`RateMetric`] for more information. Rate(i32, i32), diff --git a/glean-core/src/traits/jwe.rs b/glean-core/src/traits/jwe.rs deleted file mode 100644 index a994f93ed..000000000 --- a/glean-core/src/traits/jwe.rs +++ /dev/null @@ -1,54 +0,0 @@ -// 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 https://mozilla.org/MPL/2.0/. - -/// A description for the [`JweMetric`](crate::metrics::JweMetric) type. -/// -/// When changing this trait, make sure all the operations are -/// implemented in the related type in `../metrics/`. -pub trait Jwe { - /// Sets to the specified JWE value. - /// - /// # Arguments - /// - /// * `value` - the [`compact representation`](https://tools.ietf.org/html/rfc7516#appendix-A.2.7) of a JWE value. - fn set_with_compact_representation>(&self, value: S); - - /// Builds a JWE value from its elements and set to it. - /// - /// # Arguments - /// - /// * `header` - the JWE Protected Header element. - /// * `key` - the JWE Encrypted Key element. - /// * `init_vector` - the JWE Initialization Vector element. - /// * `cipher_text` - the JWE Ciphertext element. - /// * `auth_tag` - the JWE Authentication Tag element. - fn set>(&self, header: S, key: S, init_vector: S, cipher_text: S, auth_tag: S); - - /// **Exported for test purposes.** - /// - /// Gets the currently stored value as a string. - /// - /// This doesn't clear the stored value. - /// - /// # Arguments - /// - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. - fn test_get_value<'a, S: Into>>(&self, ping_name: S) -> Option; - - /// **Exported for test purposes.** - /// - /// Gets the currently stored JWE as a JSON String of the serialized value. - /// - /// This doesn't clear the stored value. - /// - /// # Arguments - /// - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. - fn test_get_value_as_json_string<'a, S: Into>>( - &self, - ping_name: S, - ) -> Option; -} diff --git a/glean-core/src/traits/mod.rs b/glean-core/src/traits/mod.rs index 6a15c415d..182c0597b 100644 --- a/glean-core/src/traits/mod.rs +++ b/glean-core/src/traits/mod.rs @@ -12,7 +12,6 @@ mod counter; mod custom_distribution; mod datetime; mod event; -mod jwe; mod labeled; mod memory_distribution; mod numerator; @@ -34,7 +33,6 @@ pub use self::event::Event; pub use self::event::EventRecordingError; pub use self::event::ExtraKeys; pub use self::event::NoExtraKeys; -pub use self::jwe::Jwe; pub use self::labeled::Labeled; pub use self::memory_distribution::MemoryDistribution; pub use self::numerator::Numerator; diff --git a/glean-core/tests/jwe.rs b/glean-core/tests/jwe.rs deleted file mode 100644 index d6ddef487..000000000 --- a/glean-core/tests/jwe.rs +++ /dev/null @@ -1,113 +0,0 @@ -// 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 https://mozilla.org/MPL/2.0/. - -mod common; -use crate::common::*; - -use serde_json::json; - -use glean_core::metrics::*; -use glean_core::storage::StorageManager; -use glean_core::{CommonMetricData, Lifetime}; - -const HEADER: &str = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ"; -const KEY: &str = "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg"; -const INIT_VECTOR: &str = "48V1_ALb6US04U3b"; -const CIPHER_TEXT: &str = - "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A"; -const AUTH_TAG: &str = "XFBoMYUZodetZdvTiFvSkQ"; -const JWE: &str = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ"; - -#[test] -fn jwe_metric_is_generated_and_stored() { - let (glean, _t) = new_glean(None); - - let metric = JweMetric::new(CommonMetricData { - name: "jwe_metric".into(), - category: "local".into(), - send_in_pings: vec!["core".into()], - ..Default::default() - }); - - metric.set_with_compact_representation(&glean, JWE); - let snapshot = StorageManager - .snapshot_as_json(glean.storage(), "core", false) - .unwrap(); - - assert_eq!( - json!({"jwe": {"local.jwe_metric": metric.test_get_value(&glean, "core") }}), - snapshot - ); -} - -#[test] -fn set_properly_sets_the_value_in_all_stores() { - let (glean, _t) = new_glean(None); - let store_names: Vec = vec!["store1".into(), "store2".into()]; - - let metric = JweMetric::new(CommonMetricData { - name: "jwe_metric".into(), - category: "local".into(), - send_in_pings: store_names.clone(), - disabled: false, - lifetime: Lifetime::Ping, - ..Default::default() - }); - - metric.set_with_compact_representation(&glean, JWE); - - // Check that the data was correctly set in each store. - for store_name in store_names { - let snapshot = StorageManager - .snapshot_as_json(glean.storage(), &store_name, false) - .unwrap(); - - assert_eq!( - json!({"jwe": {"local.jwe_metric": metric.test_get_value(&glean, &store_name) }}), - snapshot - ); - } -} - -#[test] -fn get_test_value_returns_the_period_delimited_string() { - let (glean, _t) = new_glean(None); - - let metric = JweMetric::new(CommonMetricData { - name: "jwe_metric".into(), - category: "local".into(), - send_in_pings: vec!["core".into()], - disabled: false, - lifetime: Lifetime::Ping, - ..Default::default() - }); - - metric.set_with_compact_representation(&glean, JWE); - - assert_eq!(metric.test_get_value(&glean, "core").unwrap(), JWE); -} - -#[test] -fn get_test_value_as_json_string_returns_the_expected_repr() { - let (glean, _t) = new_glean(None); - - let metric = JweMetric::new(CommonMetricData { - name: "jwe_metric".into(), - category: "local".into(), - send_in_pings: vec!["core".into()], - disabled: false, - lifetime: Lifetime::Ping, - ..Default::default() - }); - - metric.set_with_compact_representation(&glean, JWE); - - let expected_json = format!("{{\"header\":\"{}\",\"key\":\"{}\",\"init_vector\":\"{}\",\"cipher_text\":\"{}\",\"auth_tag\":\"{}\"}}", HEADER, KEY, INIT_VECTOR, CIPHER_TEXT, AUTH_TAG); - assert_eq!( - metric - .test_get_value_as_json_string(&glean, "core") - .unwrap(), - expected_json - ); -}