Skip to content

Commit 8d8f136

Browse files
committed
Fix data handling
1 parent 73245d0 commit 8d8f136

4 files changed

Lines changed: 146 additions & 49 deletions

File tree

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/common/actions/ExecuteBrokerStepActionEventHandler.kt

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,11 @@ import com.duckduckgo.pir.impl.scripts.models.BrokerAction.GenerateEmail
5050
import com.duckduckgo.pir.impl.scripts.models.BrokerAction.GetCaptchaInfo
5151
import com.duckduckgo.pir.impl.scripts.models.BrokerAction.GetEmailData
5252
import com.duckduckgo.pir.impl.scripts.models.BrokerAction.SolveCaptcha
53+
import com.duckduckgo.pir.impl.scripts.models.DataSource.EMAIL_DATA
5354
import com.duckduckgo.pir.impl.scripts.models.DataSource.EXTRACTED_PROFILE
55+
import com.duckduckgo.pir.impl.scripts.models.DataSource.FETCHED_EMAIL
5456
import com.duckduckgo.pir.impl.scripts.models.ExtractedProfileParams
57+
import com.duckduckgo.pir.impl.scripts.models.FetchedEmail
5558
import com.duckduckgo.pir.impl.scripts.models.PirError
5659
import com.duckduckgo.pir.impl.scripts.models.PirScriptRequestData
5760
import com.duckduckgo.pir.impl.scripts.models.PirScriptRequestData.UserProfile
@@ -296,33 +299,32 @@ class ExecuteBrokerStepActionEventHandler @Inject constructor(
296299
state: State,
297300
requestData: PirScriptRequestData,
298301
): PirScriptRequestData {
299-
if (requestData !is UserProfile || requestData.extractedProfile != null) {
302+
if (requestData !is UserProfile) {
300303
return requestData
301304
}
302-
if (actionToExecute.dataSource != EXTRACTED_PROFILE) {
303-
return requestData
304-
}
305-
306-
val baseParams: ExtractedProfileParams = when (brokerStep) {
307-
is OptOutStep -> brokerStep.profileToOptOut.toParams(state.profileQuery.fullName)
308-
is EmailConfirmationStep -> brokerStep.profileToOptOut.toParams(state.profileQuery.fullName)
309-
is ScanStep -> if (state.generatedEmailData != null) ExtractedProfileParams() else return requestData
310-
}
311-
312-
val withEmail = state.generatedEmailData?.let {
313-
baseParams.copy(email = it.emailAddress)
314-
} ?: baseParams
315-
316-
val withEmailExtractedData = if (state.emailExtractedData.isNotEmpty()) {
317-
withEmail.copy(emailExtractedData = state.emailExtractedData)
318-
} else {
319-
withEmail
305+
return when (actionToExecute.dataSource) {
306+
FETCHED_EMAIL -> {
307+
val email = state.generatedEmailData?.emailAddress ?: return requestData
308+
requestData.copy(fetchedEmail = FetchedEmail(email = email))
309+
}
310+
EMAIL_DATA -> {
311+
if (state.emailExtractedData.isEmpty()) return requestData
312+
requestData.copy(emailData = state.emailExtractedData)
313+
}
314+
EXTRACTED_PROFILE -> {
315+
if (requestData.extractedProfile != null) return requestData
316+
val baseParams: ExtractedProfileParams = when (brokerStep) {
317+
is OptOutStep -> brokerStep.profileToOptOut.toParams(state.profileQuery.fullName)
318+
is EmailConfirmationStep -> brokerStep.profileToOptOut.toParams(state.profileQuery.fullName)
319+
is ScanStep -> if (state.generatedEmailData != null) ExtractedProfileParams() else return requestData
320+
}
321+
val withEmail = state.generatedEmailData?.let {
322+
baseParams.copy(email = it.emailAddress)
323+
} ?: baseParams
324+
requestData.copy(extractedProfile = withEmail)
325+
}
326+
else -> requestData
320327
}
321-
322-
return UserProfile(
323-
userProfile = requestData.userProfile,
324-
extractedProfile = withEmailExtractedData,
325-
)
326328
}
327329

328330
companion object {

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/scripts/models/BrokerAction.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,14 @@ enum class DataSource {
179179
// Uses the profile scraped via the extract action
180180
@Json(name = "extractedProfile")
181181
EXTRACTED_PROFILE,
182+
183+
// Uses the email address generated via the generateEmail action
184+
@Json(name = "fetchedEmail")
185+
FETCHED_EMAIL,
186+
187+
// Uses the data extracted from an email (e.g. verification code) via the getEmailData action
188+
@Json(name = "emailData")
189+
EMAIL_DATA,
182190
}
183191

184192
fun BrokerAction.asActionType(): String {

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/scripts/models/PirScriptRequestParams.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ sealed class PirScriptRequestData {
3535
data class UserProfile(
3636
val userProfile: ProfileQuery? = null,
3737
val extractedProfile: ExtractedProfileParams? = null,
38+
val fetchedEmail: FetchedEmail? = null,
39+
val emailData: Map<String, String>? = null,
3840
) : PirScriptRequestData()
3941
}
4042

@@ -44,5 +46,9 @@ data class ExtractedProfileParams(
4446
val profileUrl: String? = null,
4547
val email: String? = null,
4648
val fullName: String? = null,
47-
val emailExtractedData: Map<String, String>? = null,
49+
)
50+
51+
// Wraps the generated email as { "email": "..." } so C-S-S can resolve it via data[dataSource].email.
52+
data class FetchedEmail(
53+
val email: String,
4854
)

pir/pir-impl/src/test/kotlin/com/duckduckgo/pir/impl/common/actions/ExecuteBrokerStepActionEventHandlerTest.kt

Lines changed: 105 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import com.duckduckgo.pir.impl.pixels.PirStage
4949
import com.duckduckgo.pir.impl.scripts.models.BrokerAction
5050
import com.duckduckgo.pir.impl.scripts.models.DataSource
5151
import com.duckduckgo.pir.impl.scripts.models.ElementSelector
52+
import com.duckduckgo.pir.impl.scripts.models.FetchedEmail
5253
import com.duckduckgo.pir.impl.scripts.models.PirError
5354
import com.duckduckgo.pir.impl.scripts.models.PirScriptRequestData
5455
import com.duckduckgo.pir.impl.scripts.models.PirScriptRequestData.UserProfile
@@ -1102,7 +1103,6 @@ class ExecuteBrokerStepActionEventHandlerTest {
11021103
assertEquals(testProfileQuery, userData.userProfile)
11031104
assertEquals("scan-generated@example.com", userData.extractedProfile?.email)
11041105
assertNull(userData.extractedProfile?.name)
1105-
assertNull(userData.extractedProfile?.emailExtractedData)
11061106
}
11071107

11081108
@Test
@@ -1143,29 +1143,31 @@ class ExecuteBrokerStepActionEventHandlerTest {
11431143
}
11441144

11451145
@Test
1146-
fun whenOptOutFillFormWithEmailExtractedDataThenIncludesItInRequestData() = runTest {
1146+
fun whenFillFormDataSourceIsFetchedEmailThenIncludesFetchedEmailInRequestData() = runTest {
11471147
val action = BrokerAction.FillForm(
11481148
id = "action-fill",
11491149
elements = emptyList(),
11501150
selector = "form",
1151-
dataSource = DataSource.EXTRACTED_PROFILE,
1151+
dataSource = DataSource.FETCHED_EMAIL,
11521152
)
1153-
val optOutStep = OptOutStep(
1153+
val scanStep = ScanStep(
11541154
broker = testBroker,
1155-
step = OptOutStepActions(
1156-
stepType = "optout",
1155+
step = ScanStepActions(
1156+
stepType = "scan",
11571157
actions = listOf(action),
1158-
optOutType = "form",
1158+
scanType = "initial",
11591159
),
1160-
profileToOptOut = testExtractedProfile,
11611160
)
11621161
val state = State(
1163-
runType = RunType.OPTOUT,
1164-
brokerStepsToExecute = listOf(optOutStep),
1162+
runType = RunType.MANUAL,
1163+
brokerStepsToExecute = listOf(scanStep),
11651164
profileQuery = testProfileQuery,
11661165
currentBrokerStepIndex = 0,
11671166
currentActionIndex = 0,
1168-
emailExtractedData = mapOf("verificationCode" to "123456"),
1167+
generatedEmailData = GeneratedEmailData(
1168+
emailAddress = "scan-generated@example.com",
1169+
pattern = "pattern-123",
1170+
),
11691171
stageStatus = PirStageStatus(
11701172
currentStage = PirStage.OTHER,
11711173
stageStartMs = 0,
@@ -1177,17 +1179,19 @@ class ExecuteBrokerStepActionEventHandlerTest {
11771179

11781180
val sideEffect = result.sideEffect as PushJsAction
11791181
val userData = sideEffect.requestParamsData as UserProfile
1180-
assertEquals("John Doe", userData.extractedProfile?.name)
1181-
assertEquals(mapOf("verificationCode" to "123456"), userData.extractedProfile?.emailExtractedData)
1182+
assertEquals(testProfileQuery, userData.userProfile)
1183+
assertEquals(FetchedEmail(email = "scan-generated@example.com"), userData.fetchedEmail)
1184+
assertNull(userData.extractedProfile)
1185+
assertNull(userData.emailData)
11821186
}
11831187

11841188
@Test
1185-
fun whenScanStepFillFormWithGeneratedEmailAndEmailExtractedDataThenIncludesBoth() = runTest {
1189+
fun whenFillFormDataSourceIsFetchedEmailButNoGeneratedEmailThenFetchedEmailIsNull() = runTest {
11861190
val action = BrokerAction.FillForm(
11871191
id = "action-fill",
11881192
elements = emptyList(),
11891193
selector = "form",
1190-
dataSource = DataSource.EXTRACTED_PROFILE,
1194+
dataSource = DataSource.FETCHED_EMAIL,
11911195
)
11921196
val scanStep = ScanStep(
11931197
broker = testBroker,
@@ -1203,11 +1207,44 @@ class ExecuteBrokerStepActionEventHandlerTest {
12031207
profileQuery = testProfileQuery,
12041208
currentBrokerStepIndex = 0,
12051209
currentActionIndex = 0,
1206-
generatedEmailData = GeneratedEmailData(
1207-
emailAddress = "scan-generated@example.com",
1208-
pattern = "pattern-123",
1210+
generatedEmailData = null,
1211+
stageStatus = PirStageStatus(
1212+
currentStage = PirStage.OTHER,
1213+
stageStartMs = 0,
12091214
),
1210-
emailExtractedData = mapOf("verificationCode" to "654321"),
1215+
)
1216+
val event = ExecuteBrokerStepAction(UserProfile(userProfile = testProfileQuery))
1217+
1218+
val result = testee.invoke(state, event)
1219+
1220+
val sideEffect = result.sideEffect as PushJsAction
1221+
val userData = sideEffect.requestParamsData as UserProfile
1222+
assertNull(userData.fetchedEmail)
1223+
}
1224+
1225+
@Test
1226+
fun whenFillFormDataSourceIsEmailDataThenIncludesEmailDataInRequestData() = runTest {
1227+
val action = BrokerAction.FillForm(
1228+
id = "action-fill",
1229+
elements = emptyList(),
1230+
selector = "form",
1231+
dataSource = DataSource.EMAIL_DATA,
1232+
)
1233+
val scanStep = ScanStep(
1234+
broker = testBroker,
1235+
step = ScanStepActions(
1236+
stepType = "scan",
1237+
actions = listOf(action),
1238+
scanType = "initial",
1239+
),
1240+
)
1241+
val state = State(
1242+
runType = RunType.MANUAL,
1243+
brokerStepsToExecute = listOf(scanStep),
1244+
profileQuery = testProfileQuery,
1245+
currentBrokerStepIndex = 0,
1246+
currentActionIndex = 0,
1247+
emailExtractedData = mapOf("verificationCode" to "483921"),
12111248
stageStatus = PirStageStatus(
12121249
currentStage = PirStage.OTHER,
12131250
stageStartMs = 0,
@@ -1219,12 +1256,50 @@ class ExecuteBrokerStepActionEventHandlerTest {
12191256

12201257
val sideEffect = result.sideEffect as PushJsAction
12211258
val userData = sideEffect.requestParamsData as UserProfile
1222-
assertEquals("scan-generated@example.com", userData.extractedProfile?.email)
1223-
assertEquals(mapOf("verificationCode" to "654321"), userData.extractedProfile?.emailExtractedData)
1259+
assertEquals(mapOf("verificationCode" to "483921"), userData.emailData)
1260+
assertNull(userData.extractedProfile)
1261+
assertNull(userData.fetchedEmail)
1262+
}
1263+
1264+
@Test
1265+
fun whenFillFormDataSourceIsEmailDataButStateEmailExtractedDataIsEmptyThenEmailDataIsNull() = runTest {
1266+
val action = BrokerAction.FillForm(
1267+
id = "action-fill",
1268+
elements = emptyList(),
1269+
selector = "form",
1270+
dataSource = DataSource.EMAIL_DATA,
1271+
)
1272+
val scanStep = ScanStep(
1273+
broker = testBroker,
1274+
step = ScanStepActions(
1275+
stepType = "scan",
1276+
actions = listOf(action),
1277+
scanType = "initial",
1278+
),
1279+
)
1280+
val state = State(
1281+
runType = RunType.MANUAL,
1282+
brokerStepsToExecute = listOf(scanStep),
1283+
profileQuery = testProfileQuery,
1284+
currentBrokerStepIndex = 0,
1285+
currentActionIndex = 0,
1286+
emailExtractedData = emptyMap(),
1287+
stageStatus = PirStageStatus(
1288+
currentStage = PirStage.OTHER,
1289+
stageStartMs = 0,
1290+
),
1291+
)
1292+
val event = ExecuteBrokerStepAction(UserProfile(userProfile = testProfileQuery))
1293+
1294+
val result = testee.invoke(state, event)
1295+
1296+
val sideEffect = result.sideEffect as PushJsAction
1297+
val userData = sideEffect.requestParamsData as UserProfile
1298+
assertNull(userData.emailData)
12241299
}
12251300

12261301
@Test
1227-
fun whenEmailExtractedDataIsEmptyThenFieldIsNull() = runTest {
1302+
fun whenFillFormDataSourceIsExtractedProfileThenEmailDataAndFetchedEmailAreNotIncluded() = runTest {
12281303
val action = BrokerAction.FillForm(
12291304
id = "action-fill",
12301305
elements = emptyList(),
@@ -1246,7 +1321,11 @@ class ExecuteBrokerStepActionEventHandlerTest {
12461321
profileQuery = testProfileQuery,
12471322
currentBrokerStepIndex = 0,
12481323
currentActionIndex = 0,
1249-
emailExtractedData = emptyMap(),
1324+
generatedEmailData = GeneratedEmailData(
1325+
emailAddress = "should-not-leak@example.com",
1326+
pattern = "pattern-123",
1327+
),
1328+
emailExtractedData = mapOf("verificationCode" to "654321"),
12501329
stageStatus = PirStageStatus(
12511330
currentStage = PirStage.OTHER,
12521331
stageStartMs = 0,
@@ -1258,6 +1337,8 @@ class ExecuteBrokerStepActionEventHandlerTest {
12581337

12591338
val sideEffect = result.sideEffect as PushJsAction
12601339
val userData = sideEffect.requestParamsData as UserProfile
1261-
assertNull(userData.extractedProfile?.emailExtractedData)
1340+
assertEquals("John Doe", userData.extractedProfile?.name)
1341+
assertNull(userData.fetchedEmail)
1342+
assertNull(userData.emailData)
12621343
}
12631344
}

0 commit comments

Comments
 (0)