diff --git a/frontend/src/services/Android/index.ts b/frontend/src/services/Android/index.ts index 973c1ff9..a8abb1af 100644 --- a/frontend/src/services/Android/index.ts +++ b/frontend/src/services/Android/index.ts @@ -8,6 +8,7 @@ declare global { interface AndroidAppRobosats { generateRoboname: (uuid: string, initialString: string) => void; + generateRobohash: (uuid: string, initialString: string) => void; } class AndroidRobosats { diff --git a/frontend/src/services/Roboidentities/RoboidentitiesAndroidClient/index.ts b/frontend/src/services/Roboidentities/RoboidentitiesAndroidClient/index.ts index 4fab857d..95584ecc 100644 --- a/frontend/src/services/Roboidentities/RoboidentitiesAndroidClient/index.ts +++ b/frontend/src/services/Roboidentities/RoboidentitiesAndroidClient/index.ts @@ -32,15 +32,20 @@ class RoboidentitiesAndroidClient implements RoboidentitiesClient { if (this.robohashes[key]) { return this.robohashes[key]; } else { - const response = await window.NativeRobosats?.postMessage({ - category: 'roboidentities', - type: 'robohash', - detail: key, - }); - const result: string = response ? Object.values(response)[0] : ''; - const image: string = `data:image/png;base64,${result}`; - this.robohashes[key] = image; - return image; + try { + const result = await new Promise((resolve, reject) => { + const uuid: string = uuidv4(); + window.AndroidAppRobosats?.generateRobohash(uuid, initialString); + window.AndroidRobosats?.storePromise(uuid, resolve, reject); + }); + + const image: string = `data:image/png;base64,${result}`; + this.robohashes[key] = image; + return image; + } catch (error) { + console.error('Error generating robohash:', error); + return ''; + } } }; } diff --git a/mobile_new/app/build.gradle.kts b/mobile_new/app/build.gradle.kts index 02f8fb5f..a6066824 100644 --- a/mobile_new/app/build.gradle.kts +++ b/mobile_new/app/build.gradle.kts @@ -6,11 +6,11 @@ plugins { } android { - namespace = "com.koalasat.robosats" + namespace = "com.robosats" compileSdk = 36 defaultConfig { - applicationId = "com.koalasat.robosats" + applicationId = "com.robosats" minSdk = 24 targetSdk = 36 versionCode = 1 diff --git a/mobile_new/app/src/androidTest/java/com/koalasat/robosats/ExampleInstrumentedTest.kt b/mobile_new/app/src/androidTest/java/com/koalasat/robosats/ExampleInstrumentedTest.kt index bc490e19..6e91a4d1 100644 --- a/mobile_new/app/src/androidTest/java/com/koalasat/robosats/ExampleInstrumentedTest.kt +++ b/mobile_new/app/src/androidTest/java/com/koalasat/robosats/ExampleInstrumentedTest.kt @@ -1,4 +1,4 @@ -package com.koalasat.robosats +package com.robosats import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -19,6 +19,6 @@ class ExampleInstrumentedTest { fun useAppContext() { // Context of the app under test. val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.koalasat.robosats", appContext.packageName) + assertEquals("com.robosats", appContext.packageName) } } diff --git a/mobile_new/app/src/main/AndroidManifest.xml b/mobile_new/app/src/main/AndroidManifest.xml index e887e5fb..c3fca3fe 100644 --- a/mobile_new/app/src/main/AndroidManifest.xml +++ b/mobile_new/app/src/main/AndroidManifest.xml @@ -17,7 +17,7 @@ android:usesCleartextTraffic="true" android:theme="@style/Theme.Robosats"> diff --git a/mobile_new/app/src/main/java/com/koalasat/robosats/MainActivity.kt b/mobile_new/app/src/main/java/com/robosats/MainActivity.kt similarity index 93% rename from mobile_new/app/src/main/java/com/koalasat/robosats/MainActivity.kt rename to mobile_new/app/src/main/java/com/robosats/MainActivity.kt index 1aefaf08..f042a8d1 100644 --- a/mobile_new/app/src/main/java/com/koalasat/robosats/MainActivity.kt +++ b/mobile_new/app/src/main/java/com/robosats/MainActivity.kt @@ -1,15 +1,21 @@ -package com.koalasat.robosats +package com.robosats import android.app.Application import android.content.Context +import android.graphics.Bitmap import android.os.Bundle import android.util.Log import android.webkit.* +import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import com.koalasat.robosats.WebAppInterface +import com.robosats.R import com.robosats.tor.TorKmp import com.robosats.tor.TorKmpManager +import java.io.ByteArrayInputStream +import java.net.HttpURLConnection import java.net.InetSocketAddress +import java.net.Proxy +import java.net.URL class MainActivity : AppCompatActivity() { private lateinit var webView: WebView @@ -50,10 +56,10 @@ class MainActivity : AppCompatActivity() { // Show a toast notification about the critical error runOnUiThread { - android.widget.Toast.makeText( + Toast.makeText( this, "Critical error: Tor initialization failed. App cannot proceed securely.", - android.widget.Toast.LENGTH_LONG + Toast.LENGTH_LONG ).show() } } @@ -66,10 +72,10 @@ class MainActivity : AppCompatActivity() { try { // Display connecting message runOnUiThread { - android.widget.Toast.makeText( + Toast.makeText( this, "Connecting to Tor network...", - android.widget.Toast.LENGTH_SHORT + Toast.LENGTH_SHORT ).show() } @@ -84,10 +90,10 @@ class MainActivity : AppCompatActivity() { // Update status on UI thread every few retries if (retries % 3 == 0) { runOnUiThread { - android.widget.Toast.makeText( + Toast.makeText( this, "Still connecting to Tor (attempt $retries/$maxRetries)...", - android.widget.Toast.LENGTH_SHORT + Toast.LENGTH_SHORT ).show() } } @@ -99,10 +105,10 @@ class MainActivity : AppCompatActivity() { // Show success message runOnUiThread { - android.widget.Toast.makeText( + Toast.makeText( this, "Tor connected successfully", - android.widget.Toast.LENGTH_SHORT + Toast.LENGTH_SHORT ).show() // Now that Tor is connected, set up the WebView @@ -113,10 +119,10 @@ class MainActivity : AppCompatActivity() { Log.e("TorInitialization", "Failed to connect to Tor after $maxRetries retries") runOnUiThread { - android.widget.Toast.makeText( + Toast.makeText( this, "Failed to connect to Tor after multiple attempts. App cannot proceed securely.", - android.widget.Toast.LENGTH_LONG + Toast.LENGTH_LONG ).show() } } @@ -124,10 +130,10 @@ class MainActivity : AppCompatActivity() { Log.e("TorInitialization", "Error during Tor connection: ${e.message}", e) runOnUiThread { - android.widget.Toast.makeText( + Toast.makeText( this, "Error connecting to Tor: ${e.message}", - android.widget.Toast.LENGTH_LONG + Toast.LENGTH_LONG ).show() } } @@ -190,10 +196,10 @@ class MainActivity : AppCompatActivity() { // Show message that we're setting up secure browsing runOnUiThread { - android.widget.Toast.makeText( + Toast.makeText( this, "Setting up secure Tor browsing...", - android.widget.Toast.LENGTH_SHORT + Toast.LENGTH_SHORT ).show() } @@ -225,10 +231,10 @@ class MainActivity : AppCompatActivity() { // Success - now configure WebViewClient and load URL on UI thread runOnUiThread { - android.widget.Toast.makeText( + Toast.makeText( this, "Secure connection established", - android.widget.Toast.LENGTH_SHORT + Toast.LENGTH_SHORT ).show() // Create a custom WebViewClient that forces all traffic through Tor @@ -249,14 +255,14 @@ class MainActivity : AppCompatActivity() { // For .onion domains, we must use SOCKS proxy type val proxyType = if (isOnionDomain) - java.net.Proxy.Type.SOCKS + Proxy.Type.SOCKS else - java.net.Proxy.Type.HTTP + Proxy.Type.HTTP // Create a proxy instance for Tor with the appropriate type - val torProxy = java.net.Proxy( + val torProxy = Proxy( proxyType, - java.net.InetSocketAddress(proxyHost, proxyPort) + InetSocketAddress(proxyHost, proxyPort) ) if (isOnionDomain) { @@ -264,14 +270,14 @@ class MainActivity : AppCompatActivity() { } // Create connection with proxy already configured - val url = java.net.URL(urlString) + val url = URL(urlString) val connection = url.openConnection(torProxy) // Configure basic connection properties connection.connectTimeout = 60000 // Longer timeout for onion domains connection.readTimeout = 60000 - if (connection is java.net.HttpURLConnection) { + if (connection is HttpURLConnection) { // Ensure no connection reuse to prevent proxy leaks connection.setRequestProperty("Connection", "close") @@ -305,7 +311,7 @@ class MainActivity : AppCompatActivity() { // Get the correct input stream based on response code val inputStream = if (responseCode >= 400) { - connection.errorStream ?: java.io.ByteArrayInputStream(byteArrayOf()) + connection.errorStream ?: ByteArrayInputStream(byteArrayOf()) } else { connection.inputStream } @@ -371,7 +377,7 @@ class MainActivity : AppCompatActivity() { super.onReceivedError(view, request, error) } - override fun onPageStarted(view: WebView, url: String, favicon: android.graphics.Bitmap?) { + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { // Verify Tor is connected when page starts loading if (!torKmp.isConnected()) { Log.e("SecurityError", "Tor disconnected as page started loading") @@ -409,10 +415,10 @@ class MainActivity : AppCompatActivity() { // Show error and exit - DO NOT LOAD WEBVIEW runOnUiThread { // Show toast with error - android.widget.Toast.makeText( + Toast.makeText( this, "SECURITY ERROR: Cannot set up secure browsing: ${e.message}", - android.widget.Toast.LENGTH_LONG + Toast.LENGTH_LONG ).show() } } @@ -478,7 +484,7 @@ class MainActivity : AppCompatActivity() { try { // Try to set global proxy through ConnectivityManager - val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) + val connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) val setDefaultProxyMethod = connectivityManager.javaClass.getDeclaredMethod("setDefaultProxy", proxyClass) setDefaultProxyMethod.isAccessible = true setDefaultProxyMethod.invoke(connectivityManager, proxyInfo) diff --git a/mobile_new/app/src/main/java/com/koalasat/robosats/RoboIdentities.kt b/mobile_new/app/src/main/java/com/robosats/RoboIdentities.kt similarity index 98% rename from mobile_new/app/src/main/java/com/koalasat/robosats/RoboIdentities.kt rename to mobile_new/app/src/main/java/com/robosats/RoboIdentities.kt index 578c8a0c..017d7941 100644 --- a/mobile_new/app/src/main/java/com/koalasat/robosats/RoboIdentities.kt +++ b/mobile_new/app/src/main/java/com/robosats/RoboIdentities.kt @@ -1,4 +1,4 @@ -package com.koalasat.robosats +package com.robosats import android.util.Log diff --git a/mobile_new/app/src/main/java/com/koalasat/robosats/WebAppInterface.kt b/mobile_new/app/src/main/java/com/robosats/WebAppInterface.kt similarity index 64% rename from mobile_new/app/src/main/java/com/koalasat/robosats/WebAppInterface.kt rename to mobile_new/app/src/main/java/com/robosats/WebAppInterface.kt index 160c5c56..ee913863 100644 --- a/mobile_new/app/src/main/java/com/koalasat/robosats/WebAppInterface.kt +++ b/mobile_new/app/src/main/java/com/robosats/WebAppInterface.kt @@ -1,4 +1,4 @@ -package com.koalasat.robosats +package com.robosats import android.content.Context import android.util.Log @@ -26,13 +26,11 @@ class WebAppInterface(private val context: Context, private val webView: WebView fun generateRoboname(uuid: String, message: String) { try { val roboname = roboIdentities.generateRoboname(message) - Log.d(TAG, "Generated roboname: $roboname for message: $message") - webView.post { webView.evaluateJavascript("javascript:window.AndroidRobosats.onResolvePromise('${uuid}', '${roboname}')", null) } } catch (e: Exception) { - Log.e(TAG, "Error in generateRoboname: ${e.message}", e) + Log.e(TAG, "Error in generateRoboname", e) // Handle error gracefully by returning a fallback value webView.post { @@ -43,4 +41,24 @@ class WebAppInterface(private val context: Context, private val webView: WebView } } } + + @JavascriptInterface + fun generateRobohash(uuid: String, message: String) { + try { + val roboname = roboIdentities.generateRobohash(message) + webView.post { + webView.evaluateJavascript("javascript:window.AndroidRobosats.onResolvePromise('${uuid}', '${roboname}')", null) + } + } catch (e: Exception) { + Log.e(TAG, "Error in generateRobohash", e) + + // Handle error gracefully by returning a fallback value + webView.post { + webView.evaluateJavascript( + "javascript:window.AndroidRobosats.onRejectPromise('${uuid}', 'Error generating robot hash')", + null + ) + } + } + } } diff --git a/mobile_new/app/src/main/java/com/koalasat/robosats/tor/EnumTorState.kt b/mobile_new/app/src/main/java/com/robosats/tor/EnumTorState.kt similarity index 100% rename from mobile_new/app/src/main/java/com/koalasat/robosats/tor/EnumTorState.kt rename to mobile_new/app/src/main/java/com/robosats/tor/EnumTorState.kt diff --git a/mobile_new/app/src/main/java/com/koalasat/robosats/tor/TorKmpManager.kt b/mobile_new/app/src/main/java/com/robosats/tor/TorKmpManager.kt similarity index 100% rename from mobile_new/app/src/main/java/com/koalasat/robosats/tor/TorKmpManager.kt rename to mobile_new/app/src/main/java/com/robosats/tor/TorKmpManager.kt diff --git a/mobile_new/app/src/main/java/com/koalasat/robosats/tor/TorState.kt b/mobile_new/app/src/main/java/com/robosats/tor/TorState.kt similarity index 100% rename from mobile_new/app/src/main/java/com/koalasat/robosats/tor/TorState.kt rename to mobile_new/app/src/main/java/com/robosats/tor/TorState.kt diff --git a/mobile_new/app/src/main/res/layout/activity_main.xml b/mobile_new/app/src/main/res/layout/activity_main.xml index 6dd3b647..c90ef138 100644 --- a/mobile_new/app/src/main/res/layout/activity_main.xml +++ b/mobile_new/app/src/main/res/layout/activity_main.xml @@ -6,7 +6,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" - tools:context=".MainActivity"> + tools:context="com.robosats.MainActivity">