Skip to content

Commit

Permalink
6/n filter default sensitive params
Browse files Browse the repository at this point in the history
Summary:
**Context**
In the future, we will have default sensitive parameters which are applied for all app events. We need to parse them and process separately.

More details in: https://fburl.com/gdoc/41wgxcd6

**Change in this diff**
- Parse default sensitive params
- Drop the default sensitive params if there is any

Reviewed By: KylinChang

Differential Revision: D53879033

fbshipit-source-id: e2c791e1a4c2f38c1eb54d13ffedcd624c1d934c
  • Loading branch information
Xinzhu Cai authored and facebook-github-bot committed Mar 20, 2024
1 parent 7164752 commit 92a1a7c
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,42 @@ import kotlin.collections.HashSet
@AutoHandleExceptions
object SensitiveParamsManager {
private var enabled = false

/* the parameters will be filtered out for all events */
private var defaultSensitiveParameters: HashSet<String> = HashSet()

/* the parameters will be filtered out based on the event name */
private var sensitiveParameters: MutableMap<String, HashSet<String>> = HashMap()
private const val SENSITIVE_PARAMS_KEY = "_filteredKey"

private const val DEFAULT_SENSITIVE_PARAMS_KEY = "_MTSDK_Default_"
private const val SENSITIVE_PARAMS_KEY = "_filteredKey" /* send back to Meta server */

@JvmStatic
fun enable() {
loadSensitiveParameters()
if (!sensitiveParameters.isNullOrEmpty()) {
enabled = true
if (defaultSensitiveParameters.isNullOrEmpty() && sensitiveParameters.isNullOrEmpty()) {
enabled = false
return
}

/* enable only when there is non empty default sensitive params or non empty specific
* sensitive params
*/
enabled = true
}

@JvmStatic
fun disable() {
enabled = false
sensitiveParameters = HashMap()
defaultSensitiveParameters = HashSet()
}

private fun loadSensitiveParameters() {
val settings = FetchedAppSettingsManager.queryAppSettings(FacebookSdk.getApplicationId(), false)
?: return
try {
defaultSensitiveParameters = HashSet()
sensitiveParameters = HashMap()
val sensitiveParamsFromServer = settings.sensitiveParams
if (sensitiveParamsFromServer != null && sensitiveParamsFromServer.length() != 0) {
Expand All @@ -47,12 +62,19 @@ object SensitiveParamsManager {
val hasEventName = jsonObject.has("key")
val hasSensitiveParams = jsonObject.has("value")
if (hasEventName && hasSensitiveParams) {
val eventName = jsonObject.getString("key")
/* This indicates that the sensitive params are from the specific event
* name or for all events which are the default sensitive params.
*/
val sensitiveParamsScope = jsonObject.getString("key")
val sensitiveParams = jsonObject.getJSONArray("value")
eventName?.let {
sensitiveParamsScope?.let {
sensitiveParams?.let {
convertJSONArrayToHashSet(sensitiveParams)?.let {
sensitiveParameters[eventName] = it
if (sensitiveParamsScope.equals(DEFAULT_SENSITIVE_PARAMS_KEY)) {
defaultSensitiveParameters = it
} else {
sensitiveParameters[sensitiveParamsScope] = it
}
}
}
}
Expand All @@ -69,7 +91,7 @@ object SensitiveParamsManager {
if (!enabled) {
return
}
if (!sensitiveParameters.containsKey(eventName)) {
if (defaultSensitiveParameters.isNullOrEmpty() && !sensitiveParameters.containsKey(eventName)) {
return
}

Expand All @@ -78,7 +100,7 @@ object SensitiveParamsManager {
val sensitiveParamsForEvent = sensitiveParameters.get(key = eventName)
val keys: List<String> = ArrayList(parameters.keys)
for (key in keys) {
if (!sensitiveParamsForEvent.isNullOrEmpty() && sensitiveParamsForEvent.contains(key)) {
if (shouldFilterOut(key, sensitiveParamsForEvent)) {
parameters.remove(key)
filteredParamsJSON.put(key)
}
Expand All @@ -91,4 +113,9 @@ object SensitiveParamsManager {
parameters[SENSITIVE_PARAMS_KEY] = filteredParamsJSON.toString()
}
}

private fun shouldFilterOut(parameterKey: String, sensitiveParamsForEvent: HashSet<String>?) : Boolean {
return defaultSensitiveParameters.contains(parameterKey)
|| (!sensitiveParamsForEvent.isNullOrEmpty() && sensitiveParamsForEvent.contains(parameterKey))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,27 +105,88 @@ class SensitiveParamsManagerTest : FacebookPowerMockTestCase() {
@Test
fun `test fetched sensitive params list is not null from the server and no params need to be filtered`() {
initMockFetchedAppSettings(mockSensitiveParamsFromServer)

var mockInputParamsWithoutSensitiveParams = HashMap<String, String?>()
mockInputParamsWithoutSensitiveParams[mockNonSensitiveParam] = mockNonSensitiveParamValue

enable()
processFilterSensitiveParams(mockInputParams, mockEventNameWithoutSensitiveParams)
processFilterSensitiveParams(mockInputParamsWithoutSensitiveParams, mockEventNameWithoutSensitiveParams)

Assertions.assertThat(mockInputParams.containsKey(filteredParamsKey)).isFalse
Assertions.assertThat(mockInputParams).isEqualTo(expectedFinalParamsWithoutChange)
var expectedFinalParamsWithoutChange = mockInputParamsWithoutSensitiveParams.toMap()

Assertions.assertThat(mockInputParamsWithoutSensitiveParams.containsKey(filteredParamsKey)).isFalse
Assertions.assertThat(mockInputParamsWithoutSensitiveParams).isEqualTo(expectedFinalParamsWithoutChange)
}

@Test
fun `test fetched sensitive params list has only default sensitive params from the server and need to filter the params`() {
initMockFetchedAppSettings(mockSensitiveParamsFromServerDefaultOnly)
enable()
processFilterSensitiveParams(mockInputParams, mockEventWithSensitiveParam)

var expectedParams = HashMap<String, String?>()
var filteredParams = JSONArray()
filteredParams.put(mockSensitiveParam3)
expectedParams[filteredParamsKey] = filteredParams.toString()
expectedParams[mockNonSensitiveParam] = mockNonSensitiveParamValue
expectedParams[mockSensitiveParam1] = null
expectedParams[mockSensitiveParam2] = null

Assertions.assertThat(mockInputParams.containsKey(filteredParamsKey)).isTrue
Assertions.assertThat(mockInputParams).isEqualTo(expectedParams)
}

@Test
fun `test fetched sensitive params list is not null from the server and filter the params`() {
initMockFetchedAppSettings(mockSensitiveParamsFromServer)
enable()
processFilterSensitiveParams(mockInputParams, mockEventWithSensitiveParam)

var expectedParams = HashMap<String, String?>()
var filteredParams = JSONArray()
filteredParams.put(mockSensitiveParam3) /* default sensitive param */
filteredParams.put(mockSensitiveParam1) /* specific sensitive params */
filteredParams.put(mockSensitiveParam2) /* specific sensitive params */
expectedParams[filteredParamsKey] = filteredParams.toString()
expectedParams[mockNonSensitiveParam] = mockNonSensitiveParamValue

Assertions.assertThat(mockInputParams.containsKey(filteredParamsKey)).isTrue
Assertions.assertThat(mockInputParams).isEqualTo(expectedParams)
}

@Test
fun `test fetched sensitive params list default only from the server and filter the params`() {
initMockFetchedAppSettings(mockSensitiveParamsFromServerDefaultOnly)
enable()
processFilterSensitiveParams(mockInputParams, mockEventWithSensitiveParam)

var expectedParams = HashMap<String, String?>()
var filteredParams = JSONArray()
filteredParams.put(mockSensitiveParam1)
filteredParams.put(mockSensitiveParam2)
filteredParams.put(mockSensitiveParam3) /* default sensitive param */
expectedParams[filteredParamsKey] = filteredParams.toString()
expectedParams[mockNonSensitiveParam] = mockNonSensitiveParamValue
expectedParams[mockSensitiveParam1] = null
expectedParams[mockSensitiveParam2] = null

Assertions.assertThat(mockInputParams.containsKey(filteredParamsKey)).isTrue
Assertions.assertThat(mockInputParams).isEqualTo(expectedParams)
}

@Test
fun `test fetched sensitive params list specific only from the server and filter the params`() {
initMockFetchedAppSettings(mockSensitiveParamsFromServerWithoutDefault)
enable()
processFilterSensitiveParams(mockInputParams, mockEventWithSensitiveParam)

var expectedParams = HashMap<String, String?>()
var filteredParams = JSONArray()
filteredParams.put(mockSensitiveParam1) /* specific sensitive params */
filteredParams.put(mockSensitiveParam2) /* specific sensitive params */

expectedParams[filteredParamsKey] = filteredParams.toString()
expectedParams[mockNonSensitiveParam] = mockNonSensitiveParamValue
expectedParams[mockSensitiveParam3] = null

Assertions.assertThat(mockInputParams.containsKey(filteredParamsKey)).isTrue
Assertions.assertThat(mockInputParams).isEqualTo(expectedParams)
}
Expand All @@ -135,22 +196,28 @@ class SensitiveParamsManagerTest : FacebookPowerMockTestCase() {

private const val configKey = "key"
private const val configValue = "value"

private const val filteredParamsKey = "_filteredKey"
private const val defaultSensitiveParametersKey = "_MTSDK_Default_"

private const val mockEventNameWithoutSensitiveParams = "install_app"
private const val mockEventWithSensitiveParam = "sensitive_event_1"
private const val mockSensitiveParam1 = "sensitive_param_1"
private const val mockSensitiveParam2 = "sensitive_param_2"
private const val mockSensitiveParam3 = "sensitive_param_3"
private const val mockNonSensitiveParam = "non_sensitive_param"
private const val mockNonSensitiveParamValue = "param_value"

private lateinit var emptyJSONArray: JSONArray

/* mock sensitive params with event name */
private lateinit var mockSpecificSensitiveParams: JSONObject
private lateinit var mockDefaultSensitiveParams: JSONObject /* default sensitive params */
private lateinit var mockSpecificSensitiveParams: JSONObject /* non default sensitive params */

/* mock config fetched from server */
private lateinit var mockSensitiveParamsFromServer: JSONArray
private lateinit var mockSensitiveParamsFromServerDefaultOnly: JSONArray /* default only */
private lateinit var mockSensitiveParamsFromServerWithoutDefault: JSONArray /* specific sensitive params only */
private lateinit var mockSensitiveParamsFromServer: JSONArray /* specific sensitive params and default */

private lateinit var mockInputParams: HashMap<String, String?>
private lateinit var expectedFinalParamsWithoutChange: Map<String, String?>
Expand All @@ -165,12 +232,26 @@ class SensitiveParamsManagerTest : FacebookPowerMockTestCase() {
put(configKey, mockEventWithSensitiveParam)
put(configValue, sensitiveParams)
}
mockSensitiveParamsFromServerWithoutDefault = JSONArray()
mockSensitiveParamsFromServerWithoutDefault.put(mockSpecificSensitiveParams)

sensitiveParams = JSONArray()
sensitiveParams.put(mockSensitiveParam3)
mockDefaultSensitiveParams = JSONObject().apply {
put("key", defaultSensitiveParametersKey)
put("value", sensitiveParams)
}
mockSensitiveParamsFromServerDefaultOnly = JSONArray()
mockSensitiveParamsFromServerDefaultOnly.put(mockDefaultSensitiveParams)

mockSensitiveParamsFromServer = JSONArray()
mockSensitiveParamsFromServer.put(mockSpecificSensitiveParams)
mockSensitiveParamsFromServer.put(mockDefaultSensitiveParams)

mockInputParams = HashMap()
mockInputParams[mockSensitiveParam1] = null
mockInputParams[mockSensitiveParam2] = null
mockInputParams[mockSensitiveParam3] = null
mockInputParams[mockNonSensitiveParam] = mockNonSensitiveParamValue

expectedFinalParamsWithoutChange = mockInputParams.toMap()
Expand Down

0 comments on commit 92a1a7c

Please sign in to comment.