fix acceptinvalidcerts

This commit is contained in:
eskimo 2025-09-05 16:12:22 -04:00
parent eb3f3afa60
commit 8dee1c7ee5
2 changed files with 208 additions and 24 deletions

View File

@ -0,0 +1,146 @@
package software.eskimo.capacitor.sockets;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import androidx.core.app.NotificationCompat;
import com.getcapacitor.JSObject;
import android.util.Log;
public class SocketForegroundService extends Service {
private static final String TAG = "SocketForegroundService";
// Default values
private static final String DEFAULT_CHANNEL_ID = "socket_service_channel";
private static final String DEFAULT_CHANNEL_NAME = "Socket Connection";
private static final String DEFAULT_NOTIFICATION_TITLE = "Connected to Server";
private static final String DEFAULT_NOTIFICATION_TEXT = "Tap to open";
private static final int DEFAULT_NOTIFICATION_ID = 1001;
// Configurable values
private String channelId = DEFAULT_CHANNEL_ID;
private String channelName = DEFAULT_CHANNEL_NAME;
private String notificationTitle = DEFAULT_NOTIFICATION_TITLE;
private String notificationText = DEFAULT_NOTIFICATION_TEXT;
private int notificationId = DEFAULT_NOTIFICATION_ID;
private int notificationIcon = android.R.drawable.ic_dialog_info;
private boolean running = false;
private final IBinder binder = new LocalBinder();
public class LocalBinder extends Binder {
SocketForegroundService getService() {
return SocketForegroundService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
channelId = intent.getStringExtra("channelId") != null ?
intent.getStringExtra("channelId") : DEFAULT_CHANNEL_ID;
channelName = intent.getStringExtra("channelName") != null ?
intent.getStringExtra("channelName") : DEFAULT_CHANNEL_NAME;
notificationTitle = intent.getStringExtra("notificationTitle") != null ?
intent.getStringExtra("notificationTitle") : DEFAULT_NOTIFICATION_TITLE;
notificationText = intent.getStringExtra("notificationText") != null ?
intent.getStringExtra("notificationText") : DEFAULT_NOTIFICATION_TEXT;
notificationId = intent.getIntExtra("notificationId", DEFAULT_NOTIFICATION_ID);
notificationIcon = intent.getIntExtra("notificationIcon", notificationIcon);
Log.d(TAG, "Starting foreground service with: " +
"channelId=" + channelId +
", title=" + notificationTitle +
", text=" + notificationText);
startForeground();
} else {
Log.e(TAG, "Intent was null in onStartCommand");
}
return START_STICKY;
}
public void startForeground() {
if (running) {
Log.d(TAG, "Service already running, not starting again");
return;
}
try {
createNotificationChannel();
Intent notificationIntent = getPackageManager()
.getLaunchIntentForPackage(getPackageName());
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
Log.d(TAG, "Building notification with title: " + notificationTitle);
Notification notification = new NotificationCompat.Builder(this, channelId)
.setContentTitle(notificationTitle)
.setContentText(notificationText)
.setSmallIcon(notificationIcon)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(notificationId, notification);
running = true;
Log.d(TAG, "Foreground service started with notification ID: " + notificationId);
} catch (Exception e) {
Log.e(TAG, "Error in startForeground", e);
}
}
public void updateNotification(String title, String text) {
if (!running) return;
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(this, channelId)
.setContentTitle(title)
.setContentText(text)
.setSmallIcon(notificationIcon)
.setContentIntent(PendingIntent.getActivity(
this, 0,
getPackageManager().getLaunchIntentForPackage(getPackageName()),
PendingIntent.FLAG_IMMUTABLE))
.setOngoing(true)
.build();
notificationManager.notify(notificationId, notification);
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
channelId,
channelName,
NotificationManager.IMPORTANCE_LOW
);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
@Override
public void onDestroy() {
running = false;
Log.d(TAG, "Foreground service stopped");
super.onDestroy();
}
}

View File

@ -1,17 +1,23 @@
package software.eskimo.capacitor.sockets; package software.eskimo.capacitor.sockets;
import android.os.Build;
import android.util.Log; import android.util.Log;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.security.NoSuchAlgorithmException; import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
import java.io.IOException; import javax.net.ssl.SNIHostName;
import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate; import java.io.IOException;
import java.util.Collections;
public class SocketHandler { public class SocketHandler {
private String id; private String id;
@ -35,37 +41,56 @@ public class SocketHandler {
delegate.onStateChanged(id, "connecting"); delegate.onStateChanged(id, "connecting");
if (useTLS) { if (useTLS) {
SSLContext sslContext = SSLContext.getInstance("TLS"); SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
if (acceptInvalidCertificates) { if (acceptInvalidCertificates) {
sslContext.init(null, new TrustManager[]{new X509TrustManager() { sslContext.init(null, new TrustManager[]{new InsecureTrustAllManager()}, new java.security.SecureRandom());
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
@Override
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}}, new java.security.SecureRandom());
} else { } else {
sslContext.init(null, null, new java.security.SecureRandom()); sslContext.init(null, null, new java.security.SecureRandom());
} }
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
socket = socketFactory.createSocket(host, port); SSLSocketFactory factory = sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) factory.createSocket();
if (acceptInvalidCertificates) {
java.net.InetAddress addr = java.net.InetAddress.getByName(host);
sslSocket.connect(new java.net.InetSocketAddress(addr, port));
} else {
sslSocket.connect(new java.net.InetSocketAddress(host, port));
}
javax.net.ssl.SSLParameters params = sslSocket.getSSLParameters();
try {
if (android.os.Build.VERSION.SDK_INT >= 24) {
params.setServerNames(java.util.Collections.singletonList(new javax.net.ssl.SNIHostName(host)));
}
} catch (IllegalArgumentException ignored) {}
if (acceptInvalidCertificates) {
params.setEndpointIdentificationAlgorithm(null);
} else {
params.setEndpointIdentificationAlgorithm("HTTPS");
}
sslSocket.setSSLParameters(params);
sslSocket.startHandshake();
socket = sslSocket;
} else { } else {
socket = new Socket(host, port); socket = new java.net.Socket(host, port);
} }
delegate.onStateChanged(id, "connected"); delegate.onStateChanged(id, "connected");
outputStream = socket.getOutputStream(); outputStream = socket.getOutputStream();
inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); inputStream = new java.io.BufferedReader(new java.io.InputStreamReader(socket.getInputStream()));
receive(); receive();
} catch (Exception e) { } catch (Exception e) {
Log.e("SocketHandler", "Connection error: " + e.getMessage(), e); android.util.Log.e("SocketHandler", "Connection error: " + e.getMessage(), e);
delegate.onStateChanged(id, "disconnected"); delegate.onStateChanged(id, "disconnected");
closeQuietly();
} }
}).start(); }).start();
} }
public void send(String message) { public void send(String message) {
new Thread(() -> { new Thread(() -> {
try { try {
@ -76,6 +101,7 @@ public class SocketHandler {
} catch (IOException e) { } catch (IOException e) {
Log.e("SocketHandler", "Send error: " + e.getMessage(), e); Log.e("SocketHandler", "Send error: " + e.getMessage(), e);
delegate.onStateChanged(id, "disconnected"); delegate.onStateChanged(id, "disconnected");
closeQuietly();
} }
}).start(); }).start();
} }
@ -101,23 +127,35 @@ public class SocketHandler {
while ((numCharsRead = inputStream.read(buffer)) != -1) { while ((numCharsRead = inputStream.read(buffer)) != -1) {
messageBuilder.append(buffer, 0, numCharsRead); messageBuilder.append(buffer, 0, numCharsRead);
String message = messageBuilder.toString(); String message = messageBuilder.toString();
// Check if the message ends with \r\n (or \n, depending on protocol)
if (message.endsWith("\r\n")) { if (message.endsWith("\r\n")) {
Log.d("SocketHandler", "Message received: " + message); Log.d("SocketHandler", "Message received: " + message);
delegate.onMessageReceived(id, message); // Notify with full message including \r\n delegate.onMessageReceived(id, message);
messageBuilder.setLength(0); // Clear the buffer for the next message messageBuilder.setLength(0);
} }
} }
} catch (IOException e) { } catch (IOException e) {
Log.e("SocketHandler", "Receive error: " + e.getMessage(), e); Log.e("SocketHandler", "Receive error: " + e.getMessage(), e);
delegate.onStateChanged(id, "disconnected"); delegate.onStateChanged(id, "disconnected");
} finally {
closeQuietly();
} }
}).start(); }).start();
} }
private void closeQuietly() {
try {
if (socket != null) socket.close();
} catch (Throwable ignored) {}
}
public interface SocketDelegate { public interface SocketDelegate {
void onStateChanged(String socketId, String state); void onStateChanged(String socketId, String state);
void onMessageReceived(String socketId, String message); void onMessageReceived(String socketId, String message);
} }
private static class InsecureTrustAllManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}
} }