perbaikan dari gemini
This commit is contained in:
@@ -33,7 +33,10 @@ android {
|
||||
}
|
||||
kotlinOptions { jvmTarget = "17" }
|
||||
packaging {
|
||||
resources.excludes += "META-INF/{AL2.0,LGPL2.1}"
|
||||
resources {
|
||||
excludes += "META-INF/{AL2.0,LGPL2.1}"
|
||||
excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
|
||||
}
|
||||
}
|
||||
lint { abortOnError = false }
|
||||
buildFeatures { viewBinding = true }
|
||||
@@ -50,6 +53,8 @@ dependencies {
|
||||
|
||||
// SSH
|
||||
implementation("com.hierynomus:sshj:0.38.0")
|
||||
implementation("org.bouncycastle:bcprov-jdk18on:1.78.1")
|
||||
implementation("org.bouncycastle:bcpkix-jdk18on:1.78.1")
|
||||
|
||||
// Secure credential storage (EncryptedSharedPreferences via Tink)
|
||||
implementation("androidx.security:security-crypto:1.1.0-alpha06")
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<application
|
||||
android:name=".KosSSHApplication"
|
||||
android:allowBackup="false"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.kosbarokah.sshclient
|
||||
|
||||
import android.app.Application
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import java.security.Security
|
||||
|
||||
class KosSSHApplication : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
setupBouncyCastle()
|
||||
}
|
||||
|
||||
private fun setupBouncyCastle() {
|
||||
// Remove the restricted system Bouncy Castle provider
|
||||
Security.removeProvider("BC")
|
||||
// Insert the full Bouncy Castle provider at the first position to ensure it's used
|
||||
Security.insertProviderAt(BouncyCastleProvider(), 1)
|
||||
}
|
||||
}
|
||||
@@ -143,22 +143,24 @@ class SshEngine(
|
||||
private fun newClient(): SSHClient {
|
||||
val config: Config = DefaultConfig()
|
||||
val c = SSHClient(config)
|
||||
c.useCompression()
|
||||
// Catatan: tidak memanggil loadKnownHosts() — di Android tidak ada file
|
||||
// known_hosts di path default JVM, jadi sshj hanya akan melempar peringatan
|
||||
// "could not load known_host". Host-key pinning (known_hosts) direncanakan
|
||||
// di backlog; untuk v1 kita terima host key (PromiscuousVerifier).
|
||||
// Validate host keys: in this v1 we accept any host key but warn.
|
||||
// TODO: real known-host pinning (store fingerprint per profile).
|
||||
// Disable compression for better stability on unstable mobile networks
|
||||
// c.useCompression()
|
||||
|
||||
c.addHostKeyVerifier(PromiscuousVerifier())
|
||||
val p = if (profile.port > 0) profile.port else 22
|
||||
|
||||
// Set connection timeout explicitly to 10 seconds
|
||||
c.connectTimeout = 10000
|
||||
c.connect(profile.host, p)
|
||||
c.timeout = 20000
|
||||
// Enable SSH keep-alive (client-side ping every 60s) so NAT/lazy routers
|
||||
// don't drop the session during idle.
|
||||
|
||||
// Set read timeout to 0 (infinite) for interactive shell stability
|
||||
c.timeout = 0
|
||||
|
||||
// Enable SSH keep-alive (client-side ping every 30s) to keep NAT sessions alive
|
||||
try {
|
||||
c.connection.keepAlive.setKeepAliveInterval(60)
|
||||
} catch (_: Exception) {
|
||||
c.connection.keepAlive.setKeepAliveInterval(30)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Gagal mengatur keep-alive: ${e.message}")
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user