mirror of
https://github.com/RoboSats/robosats.git
synced 2025-07-29 17:51:48 +00:00
Working
This commit is contained in:
@ -8,6 +8,7 @@ declare global {
|
||||
|
||||
interface AndroidAppRobosats {
|
||||
generateRoboname: (uuid: string, initialString: string) => void;
|
||||
generateRobohash: (uuid: string, initialString: string) => void;
|
||||
}
|
||||
|
||||
class AndroidRobosats {
|
||||
|
@ -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<string>((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 '';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
android:usesCleartextTraffic="true"
|
||||
android:theme="@style/Theme.Robosats">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name="com.robosats.MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -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)
|
@ -1,4 +1,4 @@
|
||||
package com.koalasat.robosats
|
||||
package com.robosats
|
||||
|
||||
import android.util.Log
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webView"
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.koalasat.robosats
|
||||
package com.robosats
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
|
Reference in New Issue
Block a user