Skip to content

Commit 985710b

Browse files
committed
Move things around and separate individual handlers
1 parent 9e00a71 commit 985710b

File tree

12 files changed

+259
-138
lines changed

12 files changed

+259
-138
lines changed

app/src/main/java/com/duckduckgo/app/browser/DuckDuckGoUrlDetector.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@ class DuckDuckGoUrlDetectorImpl @Inject constructor() : DuckDuckGoUrlDetector {
3838
return runCatching { AppUrl.Url.HOST == url.toHttpUrl().topPrivateDomain() }.getOrElse { false }
3939
}
4040

41-
override fun isDuckAiUrl(url: String): Boolean {
42-
return runCatching { AppUrl.Url.HOST_DUCKAI == url.toHttpUrl().topPrivateDomain() }.getOrElse { false }
43-
}
44-
4541
override fun isDuckDuckGoQueryUrl(uri: String): Boolean {
4642
return isDuckDuckGoUrl(uri) && hasQuery(uri)
4743
}

browser-api/src/main/java/com/duckduckgo/app/browser/DuckDuckGoUrlDetector.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@ interface DuckDuckGoUrlDetector {
3333
*/
3434
fun isDuckDuckGoUrl(url: String): Boolean
3535

36-
/**
37-
* This method takes a [url] and returns `true` or `false`.
38-
* @return `true` if the given [url] belongs to the duck.ai domain (apex or subdomain) and `false` otherwise.
39-
*/
40-
fun isDuckAiUrl(url: String): Boolean
41-
4236
/**
4337
* This method takes a [uri] and returns `true` or `false`.
4438
* @return `true` if the given [uri] is a DuckDuckGo query and `false`

common/common-utils/src/main/java/com/duckduckgo/common/utils/AppUrl.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ class AppUrl {
2020

2121
object Url {
2222
const val HOST = "duckduckgo.com"
23-
const val HOST_DUCKAI = "duck.ai"
2423
const val API = "https://$HOST"
2524
const val HOME = "https://$HOST"
2625
const val COOKIES = "https://$HOST"

content-scope-scripts/content-scope-scripts-impl/src/main/java/com/duckduckgo/contentscopescripts/impl/messaging/ContentScopeScriptsJsMessaging.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ class ContentScopeScriptsJsMessaging @Inject constructor(
6565
message: String,
6666
secret: String,
6767
) {
68+
logcat {
69+
"Marcos is $message"
70+
}
6871
try {
6972
val adapter = moshi.adapter(JsMessage::class.java)
7073
val jsMessage = adapter.fromJson(message)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) 2025 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.duckchat.impl
18+
19+
object DuckChatConstants {
20+
const val HOST_DUCK_AI = "duck.ai"
21+
22+
object StandaloneConstants {
23+
const val SERIALIZED_MIGRATION_FILE = "serializedMigrationFile"
24+
const val COUNT = "count"
25+
const val INDEX = "index"
26+
const val OK = "ok"
27+
const val REASON = "reason"
28+
}
29+
}

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/RealDuckChat.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import com.duckduckgo.di.scopes.AppScope
3434
import com.duckduckgo.duckchat.api.DuckAiFeatureState
3535
import com.duckduckgo.duckchat.api.DuckChat
3636
import com.duckduckgo.duckchat.api.DuckChatSettingsNoParams
37+
import com.duckduckgo.duckchat.impl.DuckChatConstants.HOST_DUCK_AI
3738
import com.duckduckgo.duckchat.impl.feature.AIChatImageUploadFeature
3839
import com.duckduckgo.duckchat.impl.feature.DuckChatFeature
3940
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarCallback
@@ -65,6 +66,7 @@ import kotlinx.coroutines.flow.asStateFlow
6566
import kotlinx.coroutines.launch
6667
import kotlinx.coroutines.withContext
6768
import logcat.logcat
69+
import okhttp3.HttpUrl.Companion.toHttpUrl
6870
import javax.inject.Inject
6971

7072
interface DuckChatInternal : DuckChat {
@@ -211,6 +213,12 @@ interface DuckChatInternal : DuckChat {
211213
*/
212214
fun isDuckChatFeatureEnabled(): Boolean
213215

216+
/**
217+
* This method takes a [url] and returns `true` or `false`.
218+
* @return `true` if the given [url] belongs to the duck.ai domain (apex or subdomain) or if it's the revoke url and `false` otherwise.
219+
*/
220+
fun isDuckAiUrl(url: String): Boolean
221+
214222
/**
215223
* Indicates whether Input Screen will present the input box at the bottom, if user has the omnibar also set to the bottom position.
216224
* Otherwise, the input box will be at the top.
@@ -429,6 +437,10 @@ class RealDuckChat @Inject constructor(
429437
}
430438
}
431439

440+
override fun isDuckAiUrl(url: String): Boolean {
441+
return runCatching { HOST_DUCK_AI == url.toHttpUrl().topPrivateDomain() || url == REVOKE_URL }.getOrElse { false }
442+
}
443+
432444
override fun isAddressBarEntryPointEnabled(): Boolean = isAddressBarEntryPointEnabled
433445
override fun isVoiceSearchEntryPointEnabled(): Boolean = isVoiceSearchEntryPointEnabled
434446

@@ -772,5 +784,6 @@ class RealDuckChat @Inject constructor(
772784
private const val BANG_QUERY_NAME = "bang"
773785
private const val BANG_QUERY_VALUE = "true"
774786
private const val DEFAULT_SESSION_ALIVE = 60
787+
private const val REVOKE_URL = "https://duckduckgo.com/revoke-duckai-access"
775788
}
776789
}

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/helper/DuckChatJSHelper.kt

Lines changed: 0 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.duckduckgo.duckchat.impl.helper
1818

19-
import com.duckduckgo.common.utils.DispatcherProvider
2019
import com.duckduckgo.di.scopes.AppScope
2120
import com.duckduckgo.duckchat.impl.ChatState
2221
import com.duckduckgo.duckchat.impl.ChatState.HIDE
@@ -29,7 +28,6 @@ import com.duckduckgo.duckchat.impl.store.DuckChatDataStore
2928
import com.duckduckgo.js.messaging.api.JsCallbackData
3029
import com.squareup.anvil.annotations.ContributesBinding
3130
import kotlinx.coroutines.runBlocking
32-
import kotlinx.coroutines.withContext
3331
import org.json.JSONObject
3432
import java.util.regex.Pattern
3533
import javax.inject.Inject
@@ -49,9 +47,7 @@ class RealDuckChatJSHelper @Inject constructor(
4947
private val duckChatPixels: DuckChatPixels,
5048
private val dataStore: DuckChatDataStore,
5149
private val duckAiMetricCollector: DuckAiMetricCollector,
52-
private val dispatchers: DispatcherProvider,
5350
) : DuckChatJSHelper {
54-
private val migrationItems = mutableListOf<String>()
5551
override suspend fun processJsCallbackMessage(
5652
featureName: String,
5753
method: String,
@@ -120,23 +116,6 @@ class RealDuckChatJSHelper @Inject constructor(
120116
}
121117
null
122118
}
123-
124-
METHOD_STORE_MIGRATION_DATA -> id?.let {
125-
getStoreMigrationDataResponse(featureName, method, it, data)
126-
}
127-
128-
METHOD_GET_MIGRATION_INFO -> id?.let {
129-
getMigrationInfoResponse(featureName, method, it)
130-
}
131-
132-
METHOD_GET_MIGRATION_DATA_BY_INDEX -> id?.let {
133-
getMigrationDataByIndexResponse(featureName, method, it, data)
134-
}
135-
136-
METHOD_CLEAR_MIGRATION_DATA -> id?.let {
137-
getClearMigrationDataResponse(featureName, method, it)
138-
}
139-
140119
else -> null
141120
}
142121

@@ -211,91 +190,6 @@ class RealDuckChatJSHelper @Inject constructor(
211190
}
212191
}
213192
}
214-
215-
/**
216-
* Accept incoming JSON payload { "serializedMigrationFile": "..." }
217-
* Store the string value in an ordered list for later retrieval
218-
*/
219-
private suspend fun getStoreMigrationDataResponse(
220-
featureName: String,
221-
method: String,
222-
id: String,
223-
data: JSONObject?,
224-
): JsCallbackData {
225-
return withContext(dispatchers.io()) {
226-
val item = data?.optString(SERIALIZED_MIGRATION_FILE)
227-
val jsonPayload = JSONObject()
228-
if (item != null && item != JSONObject.NULL) {
229-
migrationItems.add(item)
230-
jsonPayload.put(OK, true)
231-
} else {
232-
jsonPayload.put(OK, false)
233-
jsonPayload.put(REASON, "Missing or invalid serializedMigrationFile")
234-
}
235-
JsCallbackData(jsonPayload, featureName, method, id)
236-
}
237-
}
238-
239-
/**
240-
* Return the count of strings previously stored.
241-
* It's ok to return 0 if no items have been stored
242-
*/
243-
private suspend fun getMigrationInfoResponse(
244-
featureName: String,
245-
method: String,
246-
id: String,
247-
): JsCallbackData {
248-
return withContext(dispatchers.io()) {
249-
val count = migrationItems.size
250-
val jsonPayload = JSONObject().apply {
251-
put(OK, true)
252-
put(COUNT, count)
253-
}
254-
JsCallbackData(jsonPayload, featureName, method, id)
255-
}
256-
}
257-
258-
/**
259-
* Try to lookup a string by index
260-
* - when found, return { ok: true, serializedMigrationFile: '...' }
261-
* - when missing, return { ok: false, reason: '...' }
262-
*/
263-
private suspend fun getMigrationDataByIndexResponse(
264-
featureName: String,
265-
method: String,
266-
id: String,
267-
data: JSONObject?,
268-
): JsCallbackData {
269-
return withContext(dispatchers.io()) {
270-
val index = data?.optInt(INDEX, -1) ?: -1
271-
val value = migrationItems.getOrNull(index)
272-
val jsonPayload = JSONObject()
273-
if (value == null) {
274-
jsonPayload.put(OK, false)
275-
jsonPayload.put(REASON, "nothing at index: $index")
276-
} else {
277-
jsonPayload.put(OK, true)
278-
jsonPayload.put(SERIALIZED_MIGRATION_FILE, value)
279-
}
280-
JsCallbackData(jsonPayload, featureName, method, id)
281-
}
282-
}
283-
284-
/**
285-
* Clear migration data, returning { ok: true } when complete
286-
*/
287-
private suspend fun getClearMigrationDataResponse(
288-
featureName: String,
289-
method: String,
290-
id: String,
291-
): JsCallbackData {
292-
return withContext(dispatchers.io()) {
293-
migrationItems.clear()
294-
val jsonPayload = JSONObject().apply { put(OK, true) }
295-
JsCallbackData(jsonPayload, featureName, method, id)
296-
}
297-
}
298-
299193
companion object {
300194
const val DUCK_CHAT_FEATURE_NAME = "aiChat"
301195
private const val METHOD_GET_AI_CHAT_NATIVE_HANDOFF_DATA = "getAIChatNativeHandoffData"
@@ -323,17 +217,5 @@ class RealDuckChatJSHelper @Inject constructor(
323217
private const val DEFAULT_SELECTOR = "'user-prompt'"
324218
private const val SUCCESS = "success"
325219
private const val ERROR = "error"
326-
private const val OK = "ok"
327-
private const val REASON = "reason"
328-
329-
// Migration messaging constants
330-
private const val METHOD_STORE_MIGRATION_DATA = "storeMigrationData"
331-
private const val METHOD_GET_MIGRATION_INFO = "getMigrationInfo"
332-
private const val METHOD_GET_MIGRATION_DATA_BY_INDEX = "getMigrationDataByIndex"
333-
private const val METHOD_CLEAR_MIGRATION_DATA = "clearMigrationData"
334-
335-
private const val SERIALIZED_MIGRATION_FILE = "serializedMigrationFile"
336-
private const val COUNT = "count"
337-
private const val INDEX = "index"
338220
}
339221
}

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/messaging/DuckChatContentScopeJsMessageHandler.kt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.duckduckgo.duckchat.impl.messaging
1919
import com.duckduckgo.common.utils.AppUrl
2020
import com.duckduckgo.contentscopescripts.api.ContentScopeJsMessageHandlersPlugin
2121
import com.duckduckgo.di.scopes.AppScope
22+
import com.duckduckgo.duckchat.impl.DuckChatConstants.HOST_DUCK_AI
2223
import com.duckduckgo.js.messaging.api.JsMessage
2324
import com.duckduckgo.js.messaging.api.JsMessageCallback
2425
import com.duckduckgo.js.messaging.api.JsMessageHandler
@@ -41,7 +42,7 @@ class DuckChatContentScopeJsMessageHandler @Inject constructor() : ContentScopeJ
4142
override val allowedDomains: List<String> =
4243
listOf(
4344
AppUrl.Url.HOST,
44-
AppUrl.Url.HOST_DUCKAI,
45+
HOST_DUCK_AI,
4546
)
4647

4748
override val featureName: String = "aiChat"
@@ -57,12 +58,6 @@ class DuckChatContentScopeJsMessageHandler @Inject constructor() : ContentScopeJ
5758
"showChatInput",
5859
"reportMetric",
5960
"openKeyboard",
60-
61-
// migration handlers
62-
"storeMigrationData",
63-
"getMigrationInfo",
64-
"getMigrationDataByIndex",
65-
"clearMigrationData",
6661
)
6762
}
6863
}

0 commit comments

Comments
 (0)