diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4dd1422..0355ee4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,6 +4,8 @@ stages:
- build
before_script:
+- apt update && apt -y install openjdk-17-jdk
+- JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
- export GRADLE_USER_HOME=$(pwd)/.gradle
- export PACKAGE=`egrep '^[[:blank:]]+package' ./nhterm/src/main/AndroidManifest.xml | awk -F'[=>]' '{print $2}' | sed s/\"//g`
- export VERSION_NAME=`egrep '^[[:blank:]]+versionName=' ./build.gradle | awk -F '"' '{print $2}'`
diff --git a/NeoLang/build.gradle b/NeoLang/build.gradle
index 574f81b..c459fc7 100644
--- a/NeoLang/build.gradle
+++ b/NeoLang/build.gradle
@@ -32,6 +32,6 @@ dependencies {
}
java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
diff --git a/NeoTermBridge/build.gradle b/NeoTermBridge/build.gradle
index d09a6f3..e8ca3cc 100644
--- a/NeoTermBridge/build.gradle
+++ b/NeoTermBridge/build.gradle
@@ -30,6 +30,6 @@ dependencies {
}
java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
diff --git a/Xorg/build.gradle b/Xorg/build.gradle
index ab1f764..7278189 100644
--- a/Xorg/build.gradle
+++ b/Xorg/build.gradle
@@ -35,6 +35,6 @@ dependencies {
}
java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
diff --git a/build.gradle b/build.gradle
index f58a7c1..100eb37 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,12 +1,12 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.5.30'
+ ext.kotlin_version = '1.6.10'
ext.android = [
- KOTLIN_VERSION : '1.5.30',
+ KOTLIN_VERSION : '1.6.10',
MIN_SDK_VERSION : 21,
COMPILE_SDK_VERSION: 31,
- TARGET_SDK_VERSION : 32,
+ TARGET_SDK_VERSION : 28,
JUNIT_VERSION : "4.12"
]
@@ -14,8 +14,8 @@ buildscript {
ext {
//version=YYYYMMVVRR (Either "VV" for stable version OR "RR" for pre-release candidate (e.g. 0001 for rc1))
//noinspection HighAppVersionCode
- versionCode=2023030200
- versionName="2023.3"
+ versionCode=2023040100
+ versionName="2023.4"
}
ext.deps = [
@@ -35,7 +35,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.3.1'
+ classpath 'com.android.tools.build:gradle:8.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath rootProject.ext.deps["kotlin-gradle-plugin"]
diff --git a/chrome-tabs/build.gradle b/chrome-tabs/build.gradle
index 4846b5a..4a6ec4a 100644
--- a/chrome-tabs/build.gradle
+++ b/chrome-tabs/build.gradle
@@ -25,6 +25,6 @@ dependencies {
}
java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
diff --git a/chrome-tabs/src/main/java/de/mrapp/android/tabswitcher/view/TabSwitcherButton.java b/chrome-tabs/src/main/java/de/mrapp/android/tabswitcher/view/TabSwitcherButton.java
index 2eb3239..7a9a539 100644
--- a/chrome-tabs/src/main/java/de/mrapp/android/tabswitcher/view/TabSwitcherButton.java
+++ b/chrome-tabs/src/main/java/de/mrapp/android/tabswitcher/view/TabSwitcherButton.java
@@ -41,13 +41,13 @@ public class TabSwitcherButton extends AppCompatImageButton implements TabSwitch
private TabSwitcherDrawable drawable;
/**
- * Initializes the view.
+ * Initializes the view. // selectableItemBackgroundBorderless
*/
private void initialize() {
drawable = new TabSwitcherDrawable(getContext());
setImageDrawable(drawable);
ViewUtil.setBackground(this,
- ThemeUtil.getDrawable(getContext(), R.attr.selectableItemBackgroundBorderless));
+ ThemeUtil.getDrawable(getContext(), androidx.appcompat.R.attr.selectableItemBackgroundBorderless));
setContentDescription(null);
setClickable(true);
setFocusable(true);
@@ -144,4 +144,4 @@ public class TabSwitcherButton extends AppCompatImageButton implements TabSwitch
drawable.onAllTabsRemoved(tabSwitcher, tabs, animation);
}
-}
\ No newline at end of file
+}
diff --git a/chrome-tabs/src/main/res/values/attrs.xml b/chrome-tabs/src/main/res/values/attrs.xml
index 220eb8e..c13a503 100644
--- a/chrome-tabs/src/main/res/values/attrs.xml
+++ b/chrome-tabs/src/main/res/values/attrs.xml
@@ -15,20 +15,63 @@ License.
-->
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle.properties b/gradle.properties
index 1eb1d68..a8d1527 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -14,3 +14,5 @@ org.gradle.jvmargs=-Xmx1536m
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
+
+ndkVersion=25.1.8937393
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ec7c7ff..9ec9d1f 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
diff --git a/gradlew b/gradlew
old mode 100755
new mode 100644
diff --git a/nhterm/build.gradle b/nhterm/build.gradle
index d841496..8963a4b 100644
--- a/nhterm/build.gradle
+++ b/nhterm/build.gradle
@@ -15,7 +15,7 @@ android {
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
- abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
+ abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64'
}
}
signingConfigs {
@@ -63,18 +63,26 @@ dependencies {
implementation rootProject.ext.deps["kotlin-stdlib"]
- implementation 'org.greenrobot:eventbus:3.0.0'
- implementation 'com.github.wrdlbrnft:modular-adapter:0.2.0.6'
- implementation 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.19'
+ implementation 'org.greenrobot:eventbus:3.3.1'
+ implementation 'com.github.wrdlbrnft:modular-adapter:0.3.0.22'
+ implementation 'com.github.wrdlbrnft:sorted-list-adapter:0.3.0.27'
implementation 'com.simplecityapps:recyclerview-fastscroll:1.0.16'
- implementation 'de.psdev.licensesdialog:licensesdialog:1.8.3'
+ implementation 'de.psdev.licensesdialog:licensesdialog:1.9.0'
implementation 'com.github.GrenderG:Color-O-Matic:1.1.5'
+ implementation 'com.github.topjohnwu.libsu:core:5.2.1'
- implementation 'androidx.annotation:annotation:1.2.0'
+ implementation 'androidx.annotation:annotation:1.3.0'
+ implementation "androidx.core:core:1.6.0"
implementation 'androidx.cardview:cardview:1.0.0'
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'androidx.appcompat:appcompat-resources:1.2.0'
- implementation 'androidx.preference:preference:1.0.0'
+ implementation 'androidx.appcompat:appcompat:1.3.0'
+ implementation 'androidx.appcompat:appcompat-resources:1.3.0'
+ implementation 'com.google.android.material:material:1.5.0'
+ implementation 'androidx.preference:preference:1.1.0'
+ implementation "androidx.compose.material:material:1.0.0"
+
+ // Backports for lower api levels
+ implementation 'com.llamalab.safs:safs-core:0.2.0'
+ implementation 'me.zhanghai.android.retrofile:library:1.1.1'
implementation project(':chrome-tabs')
implementation project(':NeoLang')
@@ -83,6 +91,6 @@ dependencies {
}
java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
diff --git a/nhterm/src/main/AndroidManifest.xml b/nhterm/src/main/AndroidManifest.xml
index a09d398..85f2b64 100644
--- a/nhterm/src/main/AndroidManifest.xml
+++ b/nhterm/src/main/AndroidManifest.xml
@@ -38,6 +38,8 @@
android:label="@string/app_name"
android:usesCleartextTraffic="true"
android:resizeableActivity="true"
+ android:hardwareAccelerated="true"
+ android:largeHeap="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="false"
tools:replace="android:supportsRtl"
@@ -46,7 +48,7 @@
android:name=".ui.term.NeoTermActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:launchMode="singleTask"
- android:theme="@style/AppTheme.NoActionBar.Dark"
+ android:theme="@style/AppTheme.NoActionBar"
android:windowSoftInputMode="adjustResize|stateHidden"
android:exported="true">
@@ -79,7 +81,7 @@
android:name=".ui.term.NeoTermRemoteInterface"
android:configChanges="orientation|keyboardHidden"
android:exported="true"
- android:theme="@style/AppTheme.Dark"
+ android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize|stateHidden">
@@ -141,12 +143,12 @@
android:name=".ui.other.AboutActivity"
android:exported="false"
android:label="@string/about"
- android:theme="@style/AppTheme.NoActionBar.Dark"/>
+ android:theme="@style/AppTheme.NoActionBar"/>
+ android:theme="@style/AppTheme.NoActionBar"/>
+ android:theme="@style/AppTheme.NoActionBar"/>
+ android:theme="@style/AppTheme.NoActionBar"/>
+ android:theme="@style/AppTheme.NoActionBar"/>
+ android:theme="@style/AppTheme.NoActionBar"/>
+ android:theme="@style/AppTheme"/>
+ android:theme="@style/AppTheme"/>
+ android:theme="@style/AppTheme"/>
Unit)?) {
- AlertDialog.Builder(context)
+ MaterialAlertDialogBuilder(context, R.style.DialogStyle)
.setTitle(R.string.error)
.setMessage(message)
.setNegativeButton(android.R.string.no, null)
diff --git a/nhterm/src/main/java/com/offsec/nhterm/backend/KeyHandler.java b/nhterm/src/main/java/com/offsec/nhterm/backend/KeyHandler.java
index 112c58d..e74e64c 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/backend/KeyHandler.java
+++ b/nhterm/src/main/java/com/offsec/nhterm/backend/KeyHandler.java
@@ -10,6 +10,7 @@ public final class KeyHandler {
public static final int KEYMOD_ALT = 0x80000000;
public static final int KEYMOD_CTRL = 0x40000000;
public static final int KEYMOD_SHIFT = 0x20000000;
+ public static final int KEYMOD_NUM_LOCK = 0x10000000;
private static final Map TERMCAP_TO_KEYCODE = new HashMap<>();
@@ -96,10 +97,16 @@ public final class KeyHandler {
keyMod |= KEYMOD_ALT;
keyCode &= ~KEYMOD_ALT;
}
+ if ((keyCode & KEYMOD_NUM_LOCK) != 0) {
+ keyMod |= KEYMOD_NUM_LOCK;
+ keyCode &= ~KEYMOD_NUM_LOCK;
+ }
return getCode(keyCode, keyMod, cursorKeysApplication, keypadApplication);
}
public static String getCode(int keyCode, int keyMode, boolean cursorApp, boolean keypadApplication) {
+ boolean numLockOn = (keyMode & KEYMOD_NUM_LOCK) != 0;
+ keyMode &= ~KEYMOD_NUM_LOCK;
switch (keyCode) {
case KEYCODE_DPAD_CENTER:
return "\015";
@@ -179,7 +186,11 @@ public final class KeyHandler {
// Just do what xterm and gnome-terminal does:
return prefix + (((keyMode & KEYMOD_CTRL) == 0) ? "\u007F" : "\u0008");
case KEYCODE_NUM_LOCK:
- return "\033OP";
+ if (keypadApplication) {
+ return "\033OP";
+ } else {
+ return null;
+ }
case KEYCODE_SPACE:
// If ctrl is not down, return null so that it goes through normal input processing (which may e.g. cause a
@@ -200,31 +211,81 @@ public final class KeyHandler {
case KEYCODE_NUMPAD_COMMA:
return ",";
case KEYCODE_NUMPAD_DOT:
- return keypadApplication ? "\033On" : ".";
+ if (numLockOn) {
+ return keypadApplication ? "\033On" : ".";
+ } else {
+ // DELETE
+ return transformForModifiers("\033[3", keyMode, '~');
+ }
case KEYCODE_NUMPAD_SUBTRACT:
return keypadApplication ? transformForModifiers("\033O", keyMode, 'm') : "-";
case KEYCODE_NUMPAD_DIVIDE:
return keypadApplication ? transformForModifiers("\033O", keyMode, 'o') : "/";
case KEYCODE_NUMPAD_0:
- return keypadApplication ? transformForModifiers("\033O", keyMode, 'p') : "0";
+ if (numLockOn) {
+ return keypadApplication ? transformForModifiers("\033O", keyMode, 'p') : "0";
+ } else {
+ // INSERT
+ return transformForModifiers("\033[2", keyMode, '~');
+ }
case KEYCODE_NUMPAD_1:
- return keypadApplication ? transformForModifiers("\033O", keyMode, 'q') : "1";
+ if (numLockOn) {
+ return keypadApplication ? transformForModifiers("\033O", keyMode, 'q') : "1";
+ } else {
+ // END
+ return (keyMode == 0) ? (cursorApp ? "\033OF" : "\033[F") : transformForModifiers("\033[1", keyMode, 'F');
+ }
case KEYCODE_NUMPAD_2:
- return keypadApplication ? transformForModifiers("\033O", keyMode, 'r') : "2";
+ if (numLockOn) {
+ return keypadApplication ? transformForModifiers("\033O", keyMode, 'r') : "2";
+ } else {
+ // DOWN
+ return (keyMode == 0) ? (cursorApp ? "\033OB" : "\033[B") : transformForModifiers("\033[1", keyMode, 'B');
+ }
case KEYCODE_NUMPAD_3:
- return keypadApplication ? transformForModifiers("\033O", keyMode, 's') : "3";
+ if (numLockOn) {
+ return keypadApplication ? transformForModifiers("\033O", keyMode, 's') : "3";
+ } else {
+ // PGDN
+ return "\033[6~";
+ }
case KEYCODE_NUMPAD_4:
- return keypadApplication ? transformForModifiers("\033O", keyMode, 't') : "4";
+ if (numLockOn) {
+ return keypadApplication ? transformForModifiers("\033O", keyMode, 't') : "4";
+ } else {
+ // LEFT
+ return (keyMode == 0) ? (cursorApp ? "\033OD" : "\033[D") : transformForModifiers("\033[1", keyMode, 'D');
+ }
case KEYCODE_NUMPAD_5:
return keypadApplication ? transformForModifiers("\033O", keyMode, 'u') : "5";
case KEYCODE_NUMPAD_6:
- return keypadApplication ? transformForModifiers("\033O", keyMode, 'v') : "6";
+ if (numLockOn) {
+ return keypadApplication ? transformForModifiers("\033O", keyMode, 'v') : "6";
+ } else {
+ // RIGHT
+ return (keyMode == 0) ? (cursorApp ? "\033OC" : "\033[C") : transformForModifiers("\033[1", keyMode, 'C');
+ }
case KEYCODE_NUMPAD_7:
- return keypadApplication ? transformForModifiers("\033O", keyMode, 'w') : "7";
+ if (numLockOn) {
+ return keypadApplication ? transformForModifiers("\033O", keyMode, 'w') : "7";
+ } else {
+ // HOME
+ return (keyMode == 0) ? (cursorApp ? "\033OH" : "\033[H") : transformForModifiers("\033[1", keyMode, 'H');
+ }
case KEYCODE_NUMPAD_8:
- return keypadApplication ? transformForModifiers("\033O", keyMode, 'x') : "8";
+ if (numLockOn) {
+ return keypadApplication ? transformForModifiers("\033O", keyMode, 'x') : "8";
+ } else {
+ // UP
+ return (keyMode == 0) ? (cursorApp ? "\033OA" : "\033[A") : transformForModifiers("\033[1", keyMode, 'A');
+ }
case KEYCODE_NUMPAD_9:
- return keypadApplication ? transformForModifiers("\033O", keyMode, 'y') : "9";
+ if (numLockOn) {
+ return keypadApplication ? transformForModifiers("\033O", keyMode, 'y') : "9";
+ } else {
+ // PGUP
+ return "\033[5~";
+ }
case KEYCODE_NUMPAD_EQUALS:
return keypadApplication ? transformForModifiers("\033O", keyMode, 'X') : "=";
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/colorscheme/comp.kt b/nhterm/src/main/java/com/offsec/nhterm/component/colorscheme/comp.kt
index a75b45b..1ecef8f 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/colorscheme/comp.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/colorscheme/comp.kt
@@ -1,6 +1,7 @@
package com.offsec.nhterm.component.colorscheme
import android.content.Context
+import android.os.Build
import io.neolang.frontend.ConfigVisitor
import com.offsec.nhterm.App
import com.offsec.nhterm.R
@@ -18,7 +19,7 @@ import java.nio.file.Files
class ColorSchemeComponent : ConfigFileBasedComponent(NeoTermPath.COLORS_PATH) {
companion object {
fun colorFile(colorName: String): File {
- return File("${NeoTermPath.COLORS_PATH}/$colorName.nl")
+ return File("${NeoTermPath.COLORS_PATH}/$colorName.nl")
}
}
@@ -49,18 +50,22 @@ class ColorSchemeComponent : ConfigFileBasedComponent(NeoTermPat
fun reloadColorSchemes(): Boolean {
colors.clear()
- File(baseDir)
- .listFiles(NEOLANG_FILTER)
- .mapNotNull { this.loadConfigure(it) }
- .forEach {
- colors.put(it.colorName, it)
- }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ File(baseDir)
+ .listFiles(NEOLANG_FILTER)
+ .mapNotNull { this.loadConfigure(it) }
+ .forEach {
+ colors.put(it.colorName, it)
+ }
- if (colors.containsKey(DefaultColorScheme.colorName)) {
- DEFAULT_COLOR = colors[DefaultColorScheme.colorName]!!
- return true
+ if (colors.containsKey(DefaultColorScheme.colorName)) {
+ DEFAULT_COLOR = colors[DefaultColorScheme.colorName]!!
+ return true
+ }
+ return false
+ } else {
+ return false
}
- return false
}
fun applyColorScheme(view: TerminalView?, extraKeysView: ExtraKeysView?, colorScheme: NeoColorScheme?) {
@@ -112,7 +117,11 @@ class ColorSchemeComponent : ConfigFileBasedComponent(NeoTermPat
val content = component.newGenerator(colorScheme).generateCode(colorScheme)
kotlin.runCatching {
- Files.write(colorFile.toPath(), content.toByteArray())
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ Files.write(colorFile.toPath(), content.toByteArray())
+ } else {
+ return
+ }
}.onFailure {
throw RuntimeException("Failed to save file ${colorFile.absolutePath}")
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/colorscheme/data.kt b/nhterm/src/main/java/com/offsec/nhterm/component/colorscheme/data.kt
index 113e660..fb20665 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/colorscheme/data.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/colorscheme/data.kt
@@ -1,5 +1,7 @@
package com.offsec.nhterm.component.colorscheme
+import android.os.Build
+import com.offsec.nhterm.R
import io.neolang.frontend.ConfigVisitor
import com.offsec.nhterm.backend.TerminalColorScheme
import com.offsec.nhterm.backend.TerminalColors
@@ -139,12 +141,16 @@ open class NeoColorScheme : CodeGenObject, ConfigFileBasedObject {
if (session != null && session.emulator != null) {
session.emulator.setColorScheme(scheme)
}
- view.setBackgroundColor(TerminalColors.parse(backgroundColor))
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ view.setBackgroundColor(TerminalColors.parse(backgroundColor))
+ }
}
if (extraKeysView != null) {
- extraKeysView.setBackgroundColor(TerminalColors.parse(backgroundColor))
- extraKeysView.setTextColor(TerminalColors.parse(foregroundColor))
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ extraKeysView.setBackgroundColor(TerminalColors.parse(backgroundColor))
+ extraKeysView.setTextColor(TerminalColors.parse(foregroundColor))
+ }
}
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/config/comp.kt b/nhterm/src/main/java/com/offsec/nhterm/component/config/comp.kt
index dc71483..fc96042 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/config/comp.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/config/comp.kt
@@ -2,6 +2,7 @@ package com.offsec.nhterm.component.config
import android.content.Context
import android.content.SharedPreferences
+import android.os.Build
import android.preference.PreferenceManager
import android.system.ErrnoException
import android.system.Os
@@ -49,14 +50,17 @@ open class NeoConfigureFile(val configureFile: File) {
fun getVisitor() = configVisitor ?: throw IllegalStateException("Configure file not loaded or parse failed.")
- open fun parseConfigure() = kotlin.runCatching {
- val programCode = String(Files.readAllBytes(configureFile.toPath()))
- configParser.setInputSource(programCode)
- val ast = configParser.parse()
- val astVisitor = ast.visit().getVisitor(ConfigVisitor::class.java) ?: return false
- astVisitor.start()
- configVisitor = astVisitor.getCallback()
+ open fun parseConfigure() = kotlin.runCatching {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val programCode = String(Files.readAllBytes(configureFile.toPath()))
+ configParser.setInputSource(programCode)
+
+ val ast = configParser.parse()
+ val astVisitor = ast.visit().getVisitor(ConfigVisitor::class.java) ?: return false
+ astVisitor.start()
+ configVisitor = astVisitor.getCallback()
+ }
}.isSuccess
}
@@ -85,14 +89,16 @@ object NeoPreference {
MIN_FONT_SIZE = (4f * dipInPixels).toInt()
MAX_FONT_SIZE = 256
- // load apt source
- val sourceFile = File(NeoTermPath.SOURCE_FILE)
- kotlin.runCatching {
- Files.readAllBytes(sourceFile.toPath())?.let {
- val source = String(it).trim().trimEnd()
- val array = source.split(" ")
- if (array.size >= 2 && array[0] == "deb") {
- store(R.string.key_package_source, array[1])
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ // load apt source
+ val sourceFile = File(NeoTermPath.SOURCE_FILE)
+ kotlin.runCatching {
+ Files.readAllBytes(sourceFile.toPath())?.let {
+ val source = String(it).trim().trimEnd()
+ val array = source.split(" ")
+ if (array.size >= 2 && array[0] == "deb") {
+ store(R.string.key_package_source, array[1])
+ }
}
}
}
@@ -226,13 +232,6 @@ object NeoPreference {
)
}
- fun isVibrateEnabled(): Boolean {
- return loadBoolean(
- R.string.key_general_vibrate,
- DefaultValues.enableVibrate
- )
- }
-
fun isExecveWrapperEnabled(): Boolean {
return loadBoolean(
R.string.key_general_use_execve_wrapper,
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/config/defaults.kt b/nhterm/src/main/java/com/offsec/nhterm/component/config/defaults.kt
index a3b1a9d..3037820 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/config/defaults.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/config/defaults.kt
@@ -3,10 +3,10 @@ package com.offsec.nhterm.component.config
import android.annotation.SuppressLint
object DefaultValues {
- const val fontSize = 30
+ const val fontSize = 18
const val enableBell = false
- const val enableVibrate = true
+ const val enableVibrate = false
const val enableExecveWrapper = true
const val enableAutoCompletion = false
const val enableFullScreen = false
@@ -27,6 +27,7 @@ object NeoTermPath {
@SuppressLint("SdCardPath")
const val ROOT_PATH = "/data/data/com.offsec.nhterm/files"
const val USR_PATH = "$ROOT_PATH/usr"
+ const val BIN_PATH = "$USR_PATH/bin"
const val HOME_PATH = "/"
const val APT_BIN_PATH = "$USR_PATH/bin/apt"
const val LIB_PATH = "$USR_PATH/lib"
@@ -43,7 +44,7 @@ object NeoTermPath {
const val SOURCE_FILE = "$USR_PATH/etc/apt/sources.list"
const val PACKAGE_LIST_DIR = "$USR_PATH/var/lib/apt/lists"
- private const val SOURCE = "https://example.com/nhterm"
+ private const val SOURCE = "http://http.kali.org/kali"
val DEFAULT_MAIN_PACKAGE_SOURCE: String
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/extrakey/comp.kt b/nhterm/src/main/java/com/offsec/nhterm/component/extrakey/comp.kt
index 6b49bc3..118938f 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/extrakey/comp.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/extrakey/comp.kt
@@ -1,6 +1,7 @@
package com.offsec.nhterm.component.extrakey
import android.content.Context
+import android.os.Build
import io.neolang.frontend.ConfigVisitor
import com.offsec.nhterm.App
import com.offsec.nhterm.component.ConfigFileBasedComponent
@@ -57,12 +58,14 @@ class ExtraKeyComponent : ConfigFileBasedComponent(NeoTermPath.EKS_
private fun reloadExtraKeyConfig() {
extraKeys.clear()
- File(baseDir)
- .listFiles(NEOLANG_FILTER)
- .filter { it.absolutePath != NeoTermPath.EKS_DEFAULT_FILE }
- .mapNotNull { this.loadConfigure(it) }
- .forEach {
- registerShortcutKeys(it)
- }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ File(baseDir)
+ .listFiles(NEOLANG_FILTER)
+ .filter { it.absolutePath != NeoTermPath.EKS_DEFAULT_FILE }
+ .mapNotNull { this.loadConfigure(it) }
+ .forEach {
+ registerShortcutKeys(it)
+ }
+ }
}
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/pm/NeoPackageParser.java b/nhterm/src/main/java/com/offsec/nhterm/component/pm/NeoPackageParser.java
index 92a0ffd..35bf086 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/pm/NeoPackageParser.java
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/pm/NeoPackageParser.java
@@ -4,6 +4,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.Objects;
/**
* @author kiva
@@ -38,7 +39,7 @@ public class NeoPackageParser {
KEY_HOMEPAGE = "Homepage",
KEY_DESC = "Description";
- private BufferedReader reader;
+ private final BufferedReader reader;
private ParseStateListener stateListener;
NeoPackageParser(InputStream inputStream) {
@@ -100,6 +101,9 @@ public class NeoPackageParser {
}
switch (key) {
+ case KEY_PACKAGE_NAME:
+ packageInfo.setPackageName(value);
+ break;
case KEY_ARCH:
packageInfo.setArchitecture(Architecture.Companion.parse(value));
break;
@@ -149,16 +153,14 @@ public class NeoPackageParser {
private String appendToLastValue(NeoPackageInfo packageInfo, String key, String value) {
// Currently, only descriptions can be multiline
- switch (key) {
- case KEY_DESC:
- return packageInfo.getDescription() + " " + value;
- default:
- return value;
+ if (KEY_DESC.equals(key)) {
+ return packageInfo.getDescription() + " " + value;
}
+ return value;
}
private boolean splitKeyAndValue(String line, String[] splits) {
- int valueIndex = line.indexOf(':');
+ int valueIndex = line.indexOf(": ");
if (valueIndex < 0) {
return false;
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/pm/PackageComponent.java b/nhterm/src/main/java/com/offsec/nhterm/component/pm/PackageComponent.java
index ffc55c4..7693eca 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/pm/PackageComponent.java
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/pm/PackageComponent.java
@@ -7,6 +7,7 @@ import com.offsec.nhterm.component.NeoComponent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.nio.file.Files;
import java.util.HashMap;
/**
@@ -56,7 +57,7 @@ public class PackageComponent implements NeoComponent {
}
private void tryParsePackages(File packageListFile, final boolean clearPrevious) throws IOException {
- NeoPackageParser packageParser = new NeoPackageParser(new FileInputStream(packageListFile));
+ NeoPackageParser packageParser = new NeoPackageParser(Files.newInputStream(packageListFile.toPath()));
packageParser.setStateListener(new NeoPackageParser.ParseStateListener() {
@Override
public void onStartState() {
@@ -88,6 +89,7 @@ public class PackageComponent implements NeoComponent {
neoPackages.put(packageInfo.getPackageName(), packageInfo);
}
});
+
packageParser.parse();
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/pm/data.kt b/nhterm/src/main/java/com/offsec/nhterm/component/pm/data.kt
index 241a7cd..51e10e2 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/pm/data.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/pm/data.kt
@@ -17,13 +17,13 @@ enum class Architecture {
}
class NeoPackageInfo {
- var packageName: String? = null
+ var packageName: String = "dummy"
var isEssential: Boolean = false
var version: String? = null
var architecture: Architecture = Architecture.ALL
var maintainer: String? = null
var installedSizeInBytes: Long = 0L
- var fileName: String? = null
+ var fileName: String = "null"
var dependenciesString: String? = null
var dependencies: Array? = null
var sizeInBytes: Long = 0L
@@ -31,5 +31,5 @@ class NeoPackageInfo {
var sha1: String? = null
var sha256: String? = null
var homePage: String? = null
- var description: String? = null
+ var description: String = "Dummy package"
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/pm/helper.kt b/nhterm/src/main/java/com/offsec/nhterm/component/pm/helper.kt
index 9f90435..b8c9aab 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/pm/helper.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/pm/helper.kt
@@ -1,11 +1,14 @@
package com.offsec.nhterm.component.pm
+import android.util.Log
import com.offsec.nhterm.App
import com.offsec.nhterm.R
import com.offsec.nhterm.component.ComponentManager
+import com.offsec.nhterm.component.config.NeoPreference
import com.offsec.nhterm.component.config.NeoTermPath
import com.offsec.nhterm.framework.NeoTermDatabase
import com.offsec.nhterm.utils.NLog
+import com.topjohnwu.superuser.Shell
import java.io.File
import java.net.URL
import java.nio.file.Files
@@ -19,7 +22,7 @@ object SourceHelper {
fun syncSource(sourceManager: SourceManager) {
val content = buildString {
- this.append("# Generated by NeoTerm-Preference\n")
+ this.append("# Generated by NetHunter TerminalPreference\n")
sourceManager.getEnabledSources()
.joinTo(this, "\n") { "deb [trusted=yes] ${it.url} ${it.repo}\n" }
}
@@ -29,6 +32,10 @@ object SourceHelper {
}
fun detectSourceFiles(): List {
+ // Workaround to get things running
+ // TODO: ( APT ) Make it prettier?
+ copySourceFromChroot()
+
val sourceManager = ComponentManager.getComponent().sourceManager
val sourceFiles = ArrayList()
try {
@@ -38,10 +45,9 @@ object SourceHelper {
File(NeoTermPath.PACKAGE_LIST_DIR)
.listFiles()
- .filterTo(sourceFiles) { file ->
- prefixes.filter { file.name.startsWith(it) }
- .count() > 0
- }
+ ?.filterTo(sourceFiles) { file ->
+ prefixes.count { file.name.startsWith(it) } > 0
+ }
} catch (e: Exception) {
sourceFiles.clear()
NLog.e("PM", "Failed to detect source files: ${e.localizedMessage}")
@@ -50,7 +56,7 @@ object SourceHelper {
return sourceFiles
}
- fun detectSourceFilePrefix(source: Source): String {
+ private fun detectSourceFilePrefix(source: Source): String {
try {
val url = URL(source.url)
val builder = StringBuilder(url.host)
@@ -65,12 +71,42 @@ object SourceHelper {
builder.append(fixedPath)
}
builder.append("_dists_${source.repo.replace(" ".toRegex(), "_")}_binary-")
+ Log.e("ERROR:", builder.toString())
return builder.toString()
} catch (e: Exception) {
NLog.e("PM", "Failed to detect source file prefix: ${e.localizedMessage}")
return ""
}
}
+
+ private fun copySourceFromChroot() {
+ val APP_MNT = NeoTermPath.USR_PATH
+ val MNT = "/data/local/nhsystem/kalifs"
+ val sources = "$MNT/etc/apt/sources.list"
+ val lists = "$MNT/var/lib/apt/lists"
+
+ // Make sure that nhterm has locally required apt dir's
+ Shell.cmd("mkdir -p $APP_MNT/etc/apt").exec()
+ Shell.cmd("mkdir -p $APP_MNT/var/lib/apt/lists").exec()
+
+ // Also we cant be sure that folders are empty from last use so lets remove stuff
+ Shell.cmd("rm -f $APP_MNT/etc/apt/*").exec()
+ Shell.cmd("rm -f $APP_MNT/var/lib/apt/lists/*").exec()
+
+ // Now lets copy chroot apt sources.list and lists data to app
+ // This allows us to read and show list of packages for user in manager
+ Shell.cmd("cp -f $sources $APP_MNT/etc/apt/sources.list").exec()
+ Shell.cmd("cp -f $lists/* $APP_MNT/var/lib/apt/lists/").exec()
+
+ // Now play with permissions so things are read/writable
+ Shell.cmd("chmod -R 775 $APP_MNT/etc/apt").exec()
+ Shell.cmd("chmod -R 775 $APP_MNT/var/lib/apt/lists").exec()
+ }
+
+ fun updateChrootSource() {
+ // TODO: ( APT ) Add option for user to edit and update sources.list in Package Manager option
+ return
+ }
}
class SourceManager internal constructor() {
@@ -84,7 +120,7 @@ class SourceManager internal constructor() {
database.saveBean(
Source(
it,
- "stable main",
+ "kali-rolling main",
true
)
)
@@ -122,7 +158,7 @@ class SourceManager internal constructor() {
fun getMainPackageSource(): String {
return getEnabledSources()
.map { it.repo }
- .singleOrNull { it.trim() == "stable main" }
+ .singleOrNull { it.trim() == "kali-rolling main" }
?: NeoTermPath.DEFAULT_MAIN_PACKAGE_SOURCE
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/session/shell.kt b/nhterm/src/main/java/com/offsec/nhterm/component/session/shell.kt
index 8b78d8b..4b63b45 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/session/shell.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/session/shell.kt
@@ -113,7 +113,6 @@ class ShellProfile : NeoProfile() {
var initialCommand = DefaultValues.initialCommand
var enableBell = DefaultValues.enableBell
- var enableVibrate = DefaultValues.enableVibrate
var enableExecveWrapper = DefaultValues.enableExecveWrapper
var enableSpecialVolumeKeys = DefaultValues.enableSpecialVolumeKeys
var enableAutoCompletion = DefaultValues.enableAutoCompletion
@@ -134,7 +133,6 @@ class ShellProfile : NeoProfile() {
loginShell = NeoPreference.getLoginShellPath()
initialCommand = NeoPreference.getInitialCommand()
enableBell = NeoPreference.isBellEnabled()
- enableVibrate = NeoPreference.isVibrateEnabled()
enableExecveWrapper = NeoPreference.isExecveWrapperEnabled()
enableSpecialVolumeKeys = NeoPreference.isSpecialVolumeKeysEnabled()
enableAutoCompletion = NeoPreference.isAutoCompletionEnabled()
@@ -148,7 +146,6 @@ class ShellProfile : NeoProfile() {
loginShell = configVisitor.getProfileString(LOGIN_SHELL, loginShell)
initialCommand = configVisitor.getProfileString(INITIAL_COMMAND, initialCommand)
enableBell = configVisitor.getProfileBoolean(BELL, enableBell)
- enableVibrate = configVisitor.getProfileBoolean(VIBRATE, enableVibrate)
enableExecveWrapper = configVisitor.getProfileBoolean(EXECVE_WRAPPER, enableExecveWrapper)
enableSpecialVolumeKeys = configVisitor.getProfileBoolean(SPECIAL_VOLUME_KEYS, enableSpecialVolumeKeys)
enableAutoCompletion = configVisitor.getProfileBoolean(AUTO_COMPLETION, enableAutoCompletion)
diff --git a/nhterm/src/main/java/com/offsec/nhterm/component/userscript/comp.kt b/nhterm/src/main/java/com/offsec/nhterm/component/userscript/comp.kt
index ba20b5f..874c4e1 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/component/userscript/comp.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/component/userscript/comp.kt
@@ -2,18 +2,22 @@ package com.offsec.nhterm.component.userscript
import android.content.Context
import android.system.Os
+import android.util.Log
import com.offsec.nhterm.App
import com.offsec.nhterm.component.NeoComponent
import com.offsec.nhterm.component.config.NeoTermPath
import com.offsec.nhterm.utils.NLog
import com.offsec.nhterm.utils.extractAssetsDir
+import com.topjohnwu.superuser.Shell
import java.io.File
class UserScript(val scriptFile: File)
class UserScriptComponent : NeoComponent {
var userScripts = listOf()
- private val scriptDir = File(NeoTermPath.USER_SCRIPT_PATH)
+ var binFiles = listOf()
+ val scriptDir = File(NeoTermPath.USER_SCRIPT_PATH)
+ val binDir = File(NeoTermPath.BIN_PATH)
override fun onServiceInit() = checkForFiles()
@@ -22,11 +26,23 @@ class UserScriptComponent : NeoComponent {
override fun onServiceObtained() = checkForFiles()
- private fun extractDefaultScript(context: Context) = kotlin.runCatching {
+ fun extractDefaultScript(context: Context) = kotlin.runCatching {
+ Shell.cmd("mkdir -p /data/data/com.offsec.nhterm/files/usr/").exec()
+ Shell.cmd("rm -rf /data/data/com.offsec.nhterm/files/usr/bin/*")
+
+ // Usual user script extraction
context.extractAssetsDir("scripts", NeoTermPath.USER_SCRIPT_PATH)
- scriptDir.listFiles().forEach {
+
+ scriptDir.listFiles()?.forEach {
Os.chmod(it.absolutePath, 448 /*Dec of 0700*/)
}
+
+ // Lets also extract the usual binaries too here
+ context.extractAssetsDir("bin", NeoTermPath.BIN_PATH)
+ binDir.listFiles()?.forEach {
+ Os.chmod(it.absolutePath, 448 /*Dec of 0700*/)
+ }
+
}.onFailure {
NLog.e("UserScript", "Failed to extract default user scripts: ${it.localizedMessage}")
}
@@ -41,5 +57,10 @@ class UserScriptComponent : NeoComponent {
.takeWhile { it.canExecute() }
.map { UserScript(it) }
.toList()
+
+ binFiles = binDir.listFiles()
+ .takeWhile { it.canExecute() }
+ .map { UserScript(it) }
+ .toList()
}
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/frontend/floating/dialog.kt b/nhterm/src/main/java/com/offsec/nhterm/frontend/floating/dialog.kt
index 36dc436..99e21a9 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/frontend/floating/dialog.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/frontend/floating/dialog.kt
@@ -6,8 +6,10 @@ import android.content.DialogInterface
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AlertDialog
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.offsec.nhterm.R
import com.offsec.nhterm.backend.TerminalSession
+import com.offsec.nhterm.component.config.DefaultValues.initialCommand
import com.offsec.nhterm.component.session.ShellParameter
import com.offsec.nhterm.component.session.ShellTermSession
import com.offsec.nhterm.frontend.session.terminal.BasicSessionCallback
@@ -36,12 +38,12 @@ class TerminalDialog(val context: Context) {
}
}
- fun execute(executablePath: String, arguments: Array?): TerminalDialog {
+ fun execute(executablePath: String, arguments: String, extraarg: String): TerminalDialog {
if (terminalSession != null) {
terminalSession?.finishIfRunning()
}
- dialog = AlertDialog.Builder(context)
+ dialog = MaterialAlertDialogBuilder(context, R.style.DialogStyle)
.setView(termWindowView.rootView)
.setOnCancelListener {
terminalSession?.finishIfRunning()
@@ -49,15 +51,19 @@ class TerminalDialog(val context: Context) {
}
.create()
+ val cmd = listOf(arguments + " " + extraarg + " && exit 0")
+
val parameter = ShellParameter()
.executablePath(executablePath)
- .arguments(arguments)
+ .initialCommand(cmd.joinToString())
.callback(terminalSessionCallback)
.systemShell(false)
+
terminalSession = Terminals.createSession(context, parameter)
if (terminalSession is ShellTermSession) {
(terminalSession as ShellTermSession).exitPrompt = context.getString(R.string.process_exit_prompt_press_back)
}
+
termWindowView.attachSession(terminalSession)
return this
}
@@ -107,7 +113,7 @@ class WindowTermView(val context: Context) {
Terminals.setupTerminalView(terminalView)
}
- fun setTerminalViewClient(terminalViewClient: com.offsec.nhterm.frontend.session.view.TerminalViewClient?) {
+ fun setTerminalViewClient(terminalViewClient: TerminalViewClient?) {
terminalView.setTerminalViewClient(terminalViewClient)
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/terminal/term-basic.kt b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/terminal/term-basic.kt
index 68850a5..431a984 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/terminal/term-basic.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/terminal/term-basic.kt
@@ -78,6 +78,14 @@ class BasicViewClient(val terminalView: TerminalView) :
return false
}
+ override fun readShiftKey(): Boolean {
+ return false
+ }
+
+ override fun readFnKey(): Boolean {
+ return false
+ }
+
override fun onCodePoint(codePoint: Int, ctrlDown: Boolean, session: TerminalSession?): Boolean {
return false
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/terminal/term-standard.kt b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/terminal/term-standard.kt
index 0605822..b27900b 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/terminal/term-standard.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/terminal/term-standard.kt
@@ -3,19 +3,13 @@ package com.offsec.nhterm.frontend.session.terminal
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
-import android.content.Context.VIBRATOR_SERVICE
import android.media.AudioManager
import android.media.SoundPool
-import android.os.VibrationEffect
-import android.os.Vibrator
-import android.util.Log
import android.view.InputDevice
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.InputMethodManager
-import androidx.core.content.ContextCompat.getSystemService
-import com.offsec.nhterm.BuildConfig
import com.offsec.nhterm.R
import com.offsec.nhterm.backend.KeyHandler
import com.offsec.nhterm.backend.TerminalSession
@@ -36,6 +30,7 @@ class TermViewClient(val context: Context) :
TerminalViewClient {
private var mVirtualControlKeyDown: Boolean = false
private var mVirtualFnKeyDown: Boolean = false
+ private var mVirtualShiftKeyDown: Boolean = false
private var lastTitle: String = ""
var termSessionData: TermSessionData? = null
@@ -69,11 +64,6 @@ class TermViewClient(val context: Context) :
return true
}
- if (NeoPreference.isVibrateEnabled()) {
- val vibrator = context.getSystemService(Vibrator::class.java)
- vibrator.vibrate(VibrationEffect.createOneShot(40, VibrationEffect.DEFAULT_AMPLITUDE))
- }
-
val termUI = termSessionData?.termUI
when (keyCode) {
@@ -140,6 +130,16 @@ class TermViewClient(val context: Context) :
return (extraKeysView != null && extraKeysView.readAltButton()) || mVirtualFnKeyDown
}
+ override fun readShiftKey(): Boolean {
+ val extraKeysView = termSessionData?.extraKeysView
+ return (extraKeysView != null && extraKeysView.readShiftButton()) || mVirtualShiftKeyDown
+ }
+
+ override fun readFnKey(): Boolean {
+ val extraKeysView = termSessionData?.extraKeysView
+ return (extraKeysView != null && extraKeysView.readFnButton()) || mVirtualFnKeyDown
+ }
+
override fun onCodePoint(codePoint: Int, ctrlDown: Boolean, session: TerminalSession?): Boolean {
if (mVirtualFnKeyDown) {
var resultingKeyCode: Int = -1
@@ -361,13 +361,6 @@ class BellController {
}
soundPool?.play(bellId, 1f, 1f, 0, 0, 1f)
}
-
- if (session.shellProfile.enableVibrate) {
- if (NeoPreference.isVibrateEnabled()) {
- val vibrator = context.getSystemService(Vibrator::class.java)
- vibrator.vibrate(VibrationEffect.createOneShot(40, VibrationEffect.DEFAULT_AMPLITUDE))
- }
- }
}
}
@@ -434,14 +427,6 @@ class TermCompleteListener(var terminalView: TerminalView?) : OnAutoCompleteList
}
}
- if (BuildConfig.DEBUG) {
- Log.e(
- "NeoTerm-AC",
- "currentEditing: $textNeedCompletion, " +
- "deleteLength: $deleteLength, completeString: $newText"
- )
- }
-
pushString(newText)
session.write(newText)
// Trigger next completion
diff --git a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/TerminalView.java b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/TerminalView.java
index a7bb0c0..d05b02e 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/TerminalView.java
+++ b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/TerminalView.java
@@ -104,6 +104,11 @@ public final class TerminalView extends View {
private boolean mAccessibilityEnabled;
+ public final static int KEY_EVENT_SOURCE_VIRTUAL_KEYBOARD = KeyCharacterMap.VIRTUAL_KEYBOARD; // -1
+
+ /** The {@link KeyEvent} is generated from a non-physical device, like if 0 value is returned by {@link KeyEvent#getDeviceId()}. */
+ public final static int KEY_EVENT_SOURCE_SOFT_KEYBOARD = 0;
+
public TerminalView(Context context) {
super(context);
commonInit(context);
@@ -334,11 +339,12 @@ public final class TerminalView extends View {
// https://github.com/termux/termux-app/issues/87.
// https://github.com/termux/termux-app/issues/126.
// https://github.com/termux/termux-app/issues/137 (japanese chars and TYPE_NULL).
+
if (mEnableWordBasedIme) {
// Workaround for Google Pinying cannot input Chinese
- outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
+ outAttrs.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
} else {
- outAttrs.inputType = InputType.TYPE_NULL;
+ outAttrs.inputType = InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD | InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL | InputType.TYPE_NULL;
}
// Note that IME_ACTION_NONE cannot be used as that makes it impossible to input newlines using the on-screen
@@ -432,7 +438,7 @@ public final class TerminalView extends View {
}
}
- inputCodePoint(codePoint, ctrlHeld, false);
+ inputCodePoint(KEY_EVENT_SOURCE_SOFT_KEYBOARD, codePoint, ctrlHeld, false);
}
}
@@ -744,14 +750,16 @@ public final class TerminalView extends View {
}
final int metaState = event.getMetaState();
- final boolean controlDownFromEvent = event.isCtrlPressed();
- final boolean leftAltDownFromEvent = (metaState & KeyEvent.META_ALT_LEFT_ON) != 0;
+ final boolean controlDown = event.isCtrlPressed() || mClient.readControlKey();
+ final boolean leftAltDown = (metaState & KeyEvent.META_ALT_LEFT_ON) != 0 || mClient.readAltKey();
+ final boolean shiftDown = event.isShiftPressed() || mClient.readShiftKey();
final boolean rightAltDownFromEvent = (metaState & KeyEvent.META_ALT_RIGHT_ON) != 0;
int keyMod = 0;
- if (controlDownFromEvent) keyMod |= KeyHandler.KEYMOD_CTRL;
- if (event.isAltPressed()) keyMod |= KeyHandler.KEYMOD_ALT;
- if (event.isShiftPressed()) keyMod |= KeyHandler.KEYMOD_SHIFT;
+ if (controlDown) keyMod |= KeyHandler.KEYMOD_CTRL;
+ if (event.isAltPressed() || leftAltDown) keyMod |= KeyHandler.KEYMOD_ALT;
+ if (shiftDown) keyMod |= KeyHandler.KEYMOD_SHIFT;
+ if (event.isNumLockOn()) keyMod |= KeyHandler.KEYMOD_NUM_LOCK;
if (!event.isFunctionPressed() && handleKeyCode(keyCode, keyMod)) {
if (LOG_KEY_EVENTS) Log.i(EmulatorDebug.LOG_TAG, "handleKeyCode() took key event");
return true;
@@ -778,7 +786,7 @@ public final class TerminalView extends View {
if ((result & KeyCharacterMap.COMBINING_ACCENT) != 0) {
// If entered combining accent previously, write it out:
if (mCombiningAccent != 0)
- inputCodePoint(mCombiningAccent, controlDownFromEvent, leftAltDownFromEvent);
+ inputCodePoint(event.getDeviceId(), mCombiningAccent, controlDown, leftAltDown);
mCombiningAccent = result & KeyCharacterMap.COMBINING_ACCENT_MASK;
} else {
if (mCombiningAccent != 0) {
@@ -786,7 +794,7 @@ public final class TerminalView extends View {
if (combinedChar > 0) result = combinedChar;
mCombiningAccent = 0;
}
- inputCodePoint(result, controlDownFromEvent, leftAltDownFromEvent);
+ inputCodePoint(event.getDeviceId(), result, controlDown, leftAltDown);
}
if (mCombiningAccent != oldCombiningAccent) invalidate();
@@ -804,7 +812,7 @@ public final class TerminalView extends View {
return true;
}
- void inputCodePoint(int codePoint, boolean controlDownFromEvent, boolean leftAltDownFromEvent) {
+ public void inputCodePoint(int eventSource, int codePoint, boolean controlDownFromEvent, boolean leftAltDownFromEvent) {
if (LOG_KEY_EVENTS) {
Log.i(EmulatorDebug.LOG_TAG, "inputCodePoint(codePoint=" + codePoint + ", controlDownFromEvent=" + controlDownFromEvent + ", leftAltDownFromEvent="
+ leftAltDownFromEvent + ")");
@@ -842,19 +850,22 @@ public final class TerminalView extends View {
}
if (codePoint > -1) {
- // Work around bluetooth keyboards sending funny unicode characters instead
- // of the more normal ones from ASCII that terminal programs expect - the
- // desire to input the original characters should be low.
- switch (codePoint) {
- case 0x02DC: // SMALL TILDE.
- codePoint = 0x007E; // TILDE (~).
- break;
- case 0x02CB: // MODIFIER LETTER GRAVE ACCENT.
- codePoint = 0x0060; // GRAVE ACCENT (`).
- break;
- case 0x02C6: // MODIFIER LETTER CIRCUMFLEX ACCENT.
- codePoint = 0x005E; // CIRCUMFLEX ACCENT (^).
- break;
+ // If not virtual or soft keyboard.
+ if (eventSource > KEY_EVENT_SOURCE_SOFT_KEYBOARD) {
+ // Work around bluetooth keyboards sending funny unicode characters instead
+ // of the more normal ones from ASCII that terminal programs expect - the
+ // desire to input the original characters should be low.
+ switch (codePoint) {
+ case 0x02DC: // SMALL TILDE.
+ codePoint = 0x007E; // TILDE (~).
+ break;
+ case 0x02CB: // MODIFIER LETTER GRAVE ACCENT.
+ codePoint = 0x0060; // GRAVE ACCENT (`).
+ break;
+ case 0x02C6: // MODIFIER LETTER CIRCUMFLEX ACCENT.
+ codePoint = 0x005E; // CIRCUMFLEX ACCENT (^).
+ break;
+ }
}
// If left alt, send escape before the code point to make e.g. Alt+B and Alt+F work in readline:
diff --git a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/TerminalViewClient.java b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/TerminalViewClient.java
index fa5ca64..04e0267 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/TerminalViewClient.java
+++ b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/TerminalViewClient.java
@@ -35,6 +35,10 @@ public interface TerminalViewClient {
boolean readAltKey();
+ boolean readShiftKey();
+
+ boolean readFnKey();
+
boolean onCodePoint(int codePoint, boolean ctrlDown, TerminalSession session);
boolean onLongPress(MotionEvent event);
diff --git a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/extrakey/ExtraKeysView.kt b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/extrakey/ExtraKeysView.kt
index f99bcd4..469528f 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/extrakey/ExtraKeysView.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/extrakey/ExtraKeysView.kt
@@ -2,6 +2,7 @@ package com.offsec.nhterm.frontend.session.view.extrakey
import android.content.Context
import android.graphics.Typeface
+import android.os.Build
import android.os.VibrationEffect
import android.os.Vibrator
import android.util.AttributeSet
@@ -29,6 +30,7 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
private val ARROW_DOWN = ArrowButton(IExtraButton.KEY_ARROW_DOWN)
private val ARROW_LEFT = ArrowButton(IExtraButton.KEY_ARROW_LEFT)
private val ARROW_RIGHT = ArrowButton(IExtraButton.KEY_ARROW_RIGHT)
+ private val SLASH = ControlButton(IExtraButton.KEY_SLASH)
private val TOGGLE_IME = object : ControlButton(KEY_TOGGLE_IME) {
override fun onClick(view: View) {
EventBus.getDefault().post(ToggleImeEvent())
@@ -51,8 +53,11 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
// For avoid memory and context leak.
private val CTRL = StatedControlButton(IExtraButton.KEY_CTRL)
private val ALT = StatedControlButton(IExtraButton.KEY_ALT)
+ private val FN = StatedControlButton(IExtraButton.KEY_FN)
+ private val SHIFT = StatedControlButton(IExtraButton.KEY_SHIFT)
private var buttonPanelExpanded = false
+
private val EXPAND_BUTTONS = object : ControlButton(IExtraButton.KEY_SHOW_ALL_BUTTONS) {
override fun onClick(view: View) {
expandButtonPanel()
@@ -103,6 +108,14 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
return ALT.readState()
}
+ fun readFnButton(): Boolean {
+ return FN.readState()
+ }
+
+ fun readShiftButton(): Boolean {
+ return SHIFT.readState()
+ }
+
fun addUserKey(button: IExtraButton) {
addKeyButton(userKeys, button)
}
@@ -208,11 +221,6 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
outerButton.isAllCaps = false
outerButton.setOnClickListener {
- if (NeoPreference.isVibrateEnabled()) {
- val vibrator = context.getSystemService(Vibrator::class.java)
- vibrator.vibrate(VibrationEffect.createOneShot(40, VibrationEffect.DEFAULT_AMPLITUDE))
- }
-
val root = rootView
extraButton.onClick(root)
}
@@ -236,7 +244,12 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
addBuiltinKey(HOME)
addBuiltinKey(ARROW_UP)
addBuiltinKey(END)
- addBuiltinKey(EXPAND_BUTTONS)
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ addBuiltinKey(EXPAND_BUTTONS)
+ } else {
+ addBuiltinKey(SLASH)
+ }
}
private fun calculateButtonWidth(): Int {
diff --git a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/extrakey/buttons.kt b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/extrakey/buttons.kt
index 5034dc1..edf8f17 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/extrakey/buttons.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/frontend/session/view/extrakey/buttons.kt
@@ -50,6 +50,7 @@ abstract class IExtraButton : View.OnClickListener {
const val KEY_ARROW_LEFT_TEXT = "Left"
const val KEY_ARROW_RIGHT_TEXT = "Right"
const val KEY_SHOW_ALL_BUTTONS = "···"
+ const val KEY_SLASH = "/"
const val KEY_TOGGLE_IME = "⌨"
const val KEY_ARROW_UP = "▲"
@@ -73,6 +74,7 @@ abstract class IExtraButton : View.OnClickListener {
const val KEY_F12 = "F12"
// Extra keys
+ const val KEY_SHIFT = "LShift"
const val KEY_DEL = "Del"
const val KEY_ENTER = "Enter"
@@ -97,6 +99,9 @@ abstract class IExtraButton : View.OnClickListener {
KEY_PAGE_DOWN -> keyCode = KeyEvent.KEYCODE_PAGE_DOWN
KEY_HOME -> keyCode = KeyEvent.KEYCODE_MOVE_HOME
KEY_END -> keyCode = KeyEvent.KEYCODE_MOVE_END
+ KEY_FN -> keyCode = KeyEvent.KEYCODE_FUNCTION
+ KEY_SHIFT -> keyCode = KeyEvent.KEYCODE_SHIFT_LEFT
+ KEY_SLASH -> keyCode = KeyEvent.KEYCODE_SLASH
"―" -> chars = "-"
// Function keys
diff --git a/nhterm/src/main/java/com/offsec/nhterm/setup/setup.kt b/nhterm/src/main/java/com/offsec/nhterm/setup/setup.kt
index 4ecafa7..bfca056 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/setup/setup.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/setup/setup.kt
@@ -5,6 +5,7 @@ import android.content.Context
import android.os.Build
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.offsec.nhterm.App
import com.offsec.nhterm.R
import com.offsec.nhterm.component.config.NeoTermPath
@@ -69,7 +70,7 @@ object SetupHelper {
}
fun makeErrorDialog(context: Context, message: String): AlertDialog {
- return AlertDialog.Builder(context)
+ return MaterialAlertDialogBuilder(context, R.style.DialogStyle)
.setTitle(R.string.error)
.setMessage(message)
.setPositiveButton(android.R.string.yes, null)
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/customize/ColorSchemeActivity.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/customize/ColorSchemeActivity.kt
index 952d3d0..7449045 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/customize/ColorSchemeActivity.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/customize/ColorSchemeActivity.kt
@@ -13,6 +13,7 @@ import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.wrdlbrnft.sortedlistadapter.SortedListAdapter
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import es.dmoral.coloromatic.ColorOMaticDialog
import es.dmoral.coloromatic.IndicatorMode
import es.dmoral.coloromatic.colormode.ColorMode
@@ -77,7 +78,7 @@ class ColorSchemeActivity : BaseCustomizeActivity() {
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (keyCode == KeyEvent.KEYCODE_BACK && event!!.action == KeyEvent.ACTION_DOWN && changed) {
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setMessage(getString(R.string.discard_changes))
.setPositiveButton(R.string.save) { _, _ ->
applyColorScheme(editingColorScheme, true)
@@ -129,7 +130,7 @@ class ColorSchemeActivity : BaseCustomizeActivity() {
changed = true
}
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setTitle(model.colorName)
.setView(view)
.setNegativeButton(android.R.string.no, null)
@@ -159,7 +160,7 @@ class ColorSchemeActivity : BaseCustomizeActivity() {
val edit = view.findViewById(R.id.dialog_edit_text_editor)
edit.setText(getString(R.string.save_color_scheme_name_template))
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setTitle(R.string.save_color)
.setView(view)
.setPositiveButton(android.R.string.yes) { _, _ ->
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/other/AboutActivity.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/other/AboutActivity.kt
index 3704080..8a250a4 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/other/AboutActivity.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/other/AboutActivity.kt
@@ -1,14 +1,17 @@
package com.offsec.nhterm.ui.other
+import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
+import android.system.Os
import android.view.MenuItem
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import de.psdev.licensesdialog.LicensesDialog
import de.psdev.licensesdialog.licenses.ApacheSoftwareLicense20
import de.psdev.licensesdialog.licenses.GnuGeneralPublicLicense30
@@ -17,9 +20,13 @@ import de.psdev.licensesdialog.model.Notice
import de.psdev.licensesdialog.model.Notices
import com.offsec.nhterm.App
import com.offsec.nhterm.R
+import com.offsec.nhterm.component.config.NeoTermPath
+import com.offsec.nhterm.frontend.floating.TerminalDialog
import com.offsec.nhterm.utils.extractAssetsDir
+import com.topjohnwu.superuser.Shell
import de.psdev.licensesdialog.licenses.SILOpenFontLicense11
import java.io.BufferedReader
+import java.io.File
import java.io.InputStreamReader
@@ -161,10 +168,10 @@ class AboutActivity : AppCompatActivity() {
}
findViewById(R.id.about_reset_app_view).setOnClickListener {
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setMessage(R.string.reset_app_warning)
- .setPositiveButton(R.string.yes) { _, _ ->
- resetApp()
+ .setPositiveButton("yes") { _, _ ->
+ resetApp(this)
resetisdone()
}
.setNegativeButton(android.R.string.no, null)
@@ -173,41 +180,29 @@ class AboutActivity : AppCompatActivity() {
}
private fun resetisdone() {
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setMessage(R.string.done)
- .setPositiveButton(R.string.ok) { _, _ ->
+ .setPositiveButton("Ok") { _, _ ->
return@setPositiveButton
}
.show()
}
- fun resetApp() {
- // Manual way of resetting required assets
- Runtime.getRuntime().exec("mkdir -p "+" "+"/data/data/com.offsec.nhterm/files/usr/").waitFor()
- Executer("/system/bin/rm -rf /data/data/com.offsec.nhterm/files/usr/bin")
- Thread.sleep(1200)
- extractAssetsDir("bin", "/data/data/com.offsec.nhterm/files/usr/bin/")
- Thread.sleep(800)
- Executer("/system/bin/chmod +x /data/data/com.offsec.nhterm/files/usr/bin/bash") // Static bash for arm ( works for *64 too )
- Executer("/system/bin/chmod +x /data/data/com.offsec.nhterm/files/usr/bin/kali") // Kali chroot scriptlet
- Executer("/system/bin/chmod +x /data/data/com.offsec.nhterm/files/usr/bin/android-su") // Android su scriptlet
- }
+ private fun resetApp(context: Context) {
+ val binDir = File(NeoTermPath.BIN_PATH)
+ ////
+ // As some roms act weird and cause issues like no assets are extracted on fresh run then we need to force
+ // assets extraction
+ ////
+ Shell.cmd("mkdir -p /data/data/com.offsec.nhterm/files/usr/").exec()
+ Shell.cmd("rm -rf /data/data/com.offsec.nhterm/files/usr/bin/*").exec()
- fun Executer(command: String?): String? {
- val output = StringBuilder()
- val p: Process
- try {
- p = Runtime.getRuntime().exec(command)
- p.waitFor()
- val reader = BufferedReader(InputStreamReader(p.inputStream))
- var line: String?
- while (reader.readLine().also { line = it } != null) {
- output.append(line).append('\n')
- }
- } catch (e: Exception) {
- e.printStackTrace()
- }
- return output.toString()
+ extractAssetsDir("bin", "/data/data/com.offsec.nhterm/files/usr/bin/")
+
+ context.extractAssetsDir("bin", NeoTermPath.BIN_PATH)
+ binDir.listFiles()?.forEach {
+ Os.chmod(it.absolutePath, 448 /*Dec of 0700*/)
+ }
}
private fun openUrl(url: String) {
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/other/SetupActivity.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/other/SetupActivity.kt
index b0ce87f..411aaa1 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/other/SetupActivity.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/other/SetupActivity.kt
@@ -9,6 +9,7 @@ import android.view.View
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.offsec.nhterm.App
import com.offsec.nhterm.R
import com.offsec.nhterm.component.config.NeoTermPath
@@ -142,7 +143,7 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
val edit = view.findViewById(R.id.dialog_edit_text_editor)
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setTitle(R.string.new_source)
.setView(view)
.setPositiveButton(android.R.string.yes) { _, _ ->
@@ -192,7 +193,7 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
val titleId = if (needSetup) R.string.setup_confirm else R.string.setup_reset_confirm
val messageId = if (needSetup) R.string.setup_confirm_text else R.string.setup_reset_confirm_text
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setTitle(titleId)
.setMessage(messageId)
.setPositiveButton(android.R.string.yes) { _, _ ->
@@ -213,7 +214,7 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
executeAptUpdate()
} else {
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setTitle(R.string.error)
.setMessage(error.toString())
.setNegativeButton(R.string.use_system_shell) { _, _ ->
@@ -228,11 +229,11 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
}
}
- private fun executeAptUpdate() = runApt("update") {
+ private fun executeAptUpdate() = runApt("apt","update", "") {
it.onSuccess { executeAptUpgrade() }
}
- private fun executeAptUpgrade() = runApt("upgrade", "-y") {
+ private fun executeAptUpgrade() = runApt("apt", "upgrade", "") {
it.onSuccess { finish() }
}
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/pm/PackageManagerActivity.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/pm/PackageManagerActivity.kt
index c44fa7b..9e5e97b 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/pm/PackageManagerActivity.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/pm/PackageManagerActivity.kt
@@ -15,12 +15,15 @@ import androidx.appcompat.widget.Toolbar
import androidx.core.view.MenuItemCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.wrdlbrnft.sortedlistadapter.SortedListAdapter
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.offsec.nhterm.R
import com.offsec.nhterm.component.ComponentManager
import com.offsec.nhterm.component.config.NeoPreference
import com.offsec.nhterm.component.pm.*
import com.offsec.nhterm.utils.StringDistance
import com.offsec.nhterm.utils.runApt
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
import java.util.*
/**
@@ -29,14 +32,14 @@ import java.util.*
class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListener, SortedListAdapter.Callback {
private val comparator = SortedListAdapter.ComparatorBuilder()
- .setOrderForModel(PackageModel::class.java) { a, b ->
+ .setOrderForModel(PackageModel::class.java) { a, b ->
a.packageInfo.packageName!!.compareTo(b.packageInfo.packageName!!)
}
.build()
- lateinit var recyclerView: androidx.recyclerview.widget.RecyclerView
- lateinit var adapter: PackageAdapter
- var models = listOf()
+ private lateinit var recyclerView: androidx.recyclerview.widget.RecyclerView
+ private lateinit var adapter: PackageAdapter
+ private var models = listOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -49,7 +52,7 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
recyclerView.setHasFixedSize(true)
adapter = PackageAdapter(this, comparator, object : PackageAdapter.Listener {
override fun onModelClicked(model: PackageModel) {
- AlertDialog.Builder(this@PackageManagerActivity)
+ MaterialAlertDialogBuilder(this@PackageManagerActivity, R.style.DialogStyle)
.setTitle(model.packageInfo.packageName)
.setMessage(model.getPackageDetails(this@PackageManagerActivity))
.setPositiveButton(R.string.install) { _, _ ->
@@ -63,11 +66,12 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
+
refreshPackageList()
}
- private fun installPackage(packageName: String?) = packageName?.let {
- runApt("install", "-y", it, autoClose = false) {
+ private fun installPackage(packageName: String?) = packageName?.let { it ->
+ runApt("apt install", "-y", it, autoClose = true) { it ->
it.onSuccess { it.setTitle(getString(R.string.done)) }
}
}
@@ -81,14 +85,14 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item?.itemId) {
+ when (item.itemId) {
android.R.id.home -> finish()
R.id.action_source -> changeSource()
R.id.action_update_and_refresh -> executeAptUpdate()
R.id.action_refresh -> refreshPackageList()
R.id.action_upgrade -> executeAptUpgrade()
}
- return item?.let { super.onOptionsItemSelected(it) }
+ return item.let { super.onOptionsItemSelected(it) }
}
private fun changeSource() {
@@ -97,7 +101,7 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
val items = sourceList.map { "${it.url} :: ${it.repo}" }.toTypedArray()
val selection = sourceList.map { it.enabled }.toBooleanArray()
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setTitle(R.string.pref_package_source)
.setMultiChoiceItems(items, selection) { _, which, isChecked ->
sourceList[which].enabled = isChecked
@@ -116,9 +120,9 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
val urlEditor = view.findViewById(R.id.dialog_edit_text_editor)
val repoEditor = view.findViewById(R.id.dialog_edit_text2_editor)
- repoEditor.setText("stable main")
+ repoEditor.setText("kali-rolling main")
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setTitle(R.string.pref_package_source)
.setView(view)
.setNegativeButton(android.R.string.no, null)
@@ -156,14 +160,16 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
executeAptUpdate()
}
- private fun executeAptUpdate() = runApt("update") {
+ private fun executeAptUpdate() = runApt("apt","update", "", autoClose = true) {
+ Toast.makeText(this, R.string.apt_update_ok, Toast.LENGTH_LONG).show()
+
it.onSuccess { refreshPackageList() }
}
- private fun executeAptUpgrade() = runApt("update") { update ->
+ private fun executeAptUpgrade() = runApt("apt", "update", "", autoClose = true) { update ->
update.onSuccess {
- runApt("upgrade", "-y") {
- it.onSuccess { Toast.makeText(this, R.string.apt_upgrade_ok, Toast.LENGTH_SHORT).show() }
+ runApt("apt", "upgrade", "-y", autoClose = true) {
+ it.onSuccess { Toast.makeText(this, R.string.apt_upgrade_ok, Toast.LENGTH_LONG).show() }
}
}
}
@@ -190,7 +196,7 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
): List> {
return models
.map {
- it to StringDistance.distance(mapper(it.packageInfo).toLowerCase(Locale.ROOT), query.toLowerCase(Locale.ROOT))
+ it to StringDistance.distance(mapper(it.packageInfo).lowercase(Locale.ENGLISH), query.lowercase(Locale.ENGLISH))
}
.sortedWith { l, r -> r.second.compareTo(l.second) }
.toList()
@@ -199,11 +205,9 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
private fun filter(models: List, query: String): List {
val prepared = models.filter {
it.packageInfo.packageName!!.contains(query, true)
- || it.packageInfo.description!!.contains(query, true)
}
return sortDistance(prepared, query) { it.packageName!! }
- .plus(sortDistance(prepared, query) { it.description!! })
.map { it.first }
.toList()
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/pm/model.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/pm/model.kt
index a849965..01f927f 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/pm/model.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/pm/model.kt
@@ -14,12 +14,12 @@ import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
class PackageAdapter(
context: Context,
comparator: Comparator,
- private val listener: PackageAdapter.Listener
+ private val listener: Listener
) : SortedListAdapter(context, PackageModel::class.java, comparator),
FastScrollRecyclerView.SectionedAdapter {
override fun getSectionName(position: Int): String {
- return getItem(position).packageInfo.packageName?.substring(0, 1) ?: "#"
+ return getItem(position).packageInfo.packageName!!.substring(0, 1) ?: "#"
}
interface Listener {
@@ -53,14 +53,14 @@ class PackageViewHolder(private val rootView: View, private val listener: Packag
*/
class PackageModel(val packageInfo: NeoPackageInfo) : SortedListAdapter.ViewModel {
- override fun isSameModelAs(t: T): Boolean {
+ override fun isSameModelAs(t: T): Boolean {
if (t is PackageModel) {
return t.packageInfo.packageName == packageInfo.packageName
}
return false
}
- override fun isContentTheSameAs(t: T): Boolean {
+ override fun isContentTheSameAs(t: T): Boolean {
return isSameModelAs(t)
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/pm/view/RecyclerTabLayout.java b/nhterm/src/main/java/com/offsec/nhterm/ui/pm/view/RecyclerTabLayout.java
index 145539b..987a10a 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/pm/view/RecyclerTabLayout.java
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/pm/view/RecyclerTabLayout.java
@@ -36,6 +36,8 @@ import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;
import com.offsec.nhterm.R;
+import java.util.Objects;
+
public class RecyclerTabLayout extends RecyclerView {
protected static final long DEFAULT_SCROLL_DURATION = 200;
@@ -397,6 +399,7 @@ public class RecyclerTabLayout extends RecyclerView {
int center = mRecyclerTabLayout.getWidth() / 2;
for (int position = first; position <= last; position++) {
View view = mLinearLayoutManager.findViewByPosition(position);
+ assert view != null;
if (view.getLeft() + view.getWidth() >= center) {
mRecyclerTabLayout.setCurrentItem(position, false);
break;
@@ -535,14 +538,14 @@ public class RecyclerTabLayout extends RecyclerView {
@Override
public void onBindViewHolder(DefaultAdapter.ViewHolder holder, int position) {
- CharSequence title = getViewPager().getAdapter().getPageTitle(position);
+ CharSequence title = Objects.requireNonNull(getViewPager().getAdapter()).getPageTitle(position);
holder.title.setText(title);
holder.title.setSelected(getCurrentIndicatorPosition() == position);
}
@Override
public int getItemCount() {
- return getViewPager().getAdapter().getCount();
+ return Objects.requireNonNull(getViewPager().getAdapter()).getCount();
}
public void setTabPadding(int tabPaddingStart, int tabPaddingTop, int tabPaddingEnd,
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/settings/BasePreferenceActivity.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/settings/BasePreferenceActivity.kt
index bfb6a82..899aa9b 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/settings/BasePreferenceActivity.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/settings/BasePreferenceActivity.kt
@@ -16,14 +16,20 @@
package com.offsec.nhterm.ui.settings
import android.content.res.Configuration
+import android.content.res.Resources.Theme
import android.os.Bundle
import android.preference.PreferenceActivity
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
+import androidx.annotation.StyleRes
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatDelegate
+import androidx.core.content.res.ResourcesCompat.ThemeCompat
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+import com.offsec.nhterm.R
/**
* A [android.preference.PreferenceActivity] which implements and proxies the necessary calls
@@ -39,6 +45,7 @@ abstract class BasePreferenceActivity : PreferenceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
delegate.installViewFactory()
delegate.onCreate(savedInstanceState)
+ delegate.setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/settings/GeneralSettingsActivity.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/settings/GeneralSettingsActivity.kt
index 01b3c1d..81ac909 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/settings/GeneralSettingsActivity.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/settings/GeneralSettingsActivity.kt
@@ -1,7 +1,9 @@
package com.offsec.nhterm.ui.settings
import android.os.Bundle
+import android.preference.PreferenceActivity
import android.view.MenuItem
+import androidx.preference.Preference
import com.offsec.nhterm.R
/**
@@ -16,7 +18,7 @@ class GeneralSettingsActivity : BasePreferenceActivity() {
addPreferencesFromResource(R.xml.setting_general)
}
- override fun onBuildHeaders(target: MutableList?) {
+ override fun onBuildHeaders(target: MutableList?) {
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/settings/SettingActivity.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/settings/SettingActivity.kt
index 299da40..f78c555 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/settings/SettingActivity.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/settings/SettingActivity.kt
@@ -1,5 +1,6 @@
package com.offsec.nhterm.ui.settings
+import android.os.Build
import android.os.Bundle
import android.view.MenuItem
import com.offsec.nhterm.R
@@ -13,7 +14,11 @@ class SettingActivity : BasePreferenceActivity() {
super.onCreate(savedInstanceState)
supportActionBar?.title = getString(R.string.settings)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
- addPreferencesFromResource(R.xml.settings_main)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ addPreferencesFromResource(R.xml.settings_main)
+ } else {
+ addPreferencesFromResource(R.xml.older_settings_main)
+ }
}
override fun onBuildHeaders(target: MutableList?) {
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/term/NeoTermActivity.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/term/NeoTermActivity.kt
index 6db1e04..0f64072 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/term/NeoTermActivity.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/term/NeoTermActivity.kt
@@ -9,6 +9,7 @@ import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
+import android.util.Log
import android.view.*
import android.view.inputmethod.InputMethodManager
import android.widget.ImageButton
@@ -21,8 +22,8 @@ import androidx.core.content.ContextCompat
import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.ViewCompat
import androidx.preference.PreferenceManager
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.offsec.nhterm.App
-import com.offsec.nhterm.BuildConfig
import com.offsec.nhterm.R
import com.offsec.nhterm.backend.TerminalSession
import com.offsec.nhterm.component.ComponentManager
@@ -34,14 +35,18 @@ import com.offsec.nhterm.component.session.XParameter
import com.offsec.nhterm.component.session.XSession
import com.offsec.nhterm.frontend.session.terminal.*
import com.offsec.nhterm.services.NeoTermService
+import com.offsec.nhterm.ui.pm.PackageManagerActivity
import com.offsec.nhterm.ui.settings.SettingActivity
import com.offsec.nhterm.utils.FullScreenHelper
import com.offsec.nhterm.utils.NeoPermission
import com.offsec.nhterm.utils.RangedInt
+import com.topjohnwu.superuser.Shell
import de.mrapp.android.tabswitcher.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
+import java.lang.System.`in`
+import java.lang.System.out
class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreferences.OnSharedPreferenceChangeListener {
@@ -60,8 +65,18 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ val SDCARD_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1
+
NeoPermission.initAppPermission(this, NeoPermission.REQUEST_APP_PERMISSION)
+ if (ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), SDCARD_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE)
+ }
+
val fullscreen = NeoPreference.isFullScreenEnabled()
if (fullscreen) {
window.setFlags(
@@ -70,19 +85,6 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
)
}
- val SDCARD_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1
- if (ContextCompat.checkSelfPermission(
- this,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- ) != PackageManager.PERMISSION_GRANTED
- ) {
- ActivityCompat.requestPermissions(
- this,
- arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
- SDCARD_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE,
- )
- }
-
setContentView(R.layout.ui_main)
toolbar = findViewById(R.id.terminal_toolbar)
@@ -142,7 +144,11 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
- menuInflater.inflate(R.menu.menu_main, menu)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ menuInflater.inflate(R.menu.menu_main, menu)
+ } else {
+ menuInflater.inflate(R.menu.older_menu_main, menu)
+ }
TabSwitcher.setupWithMenu(
tabSwitcher, toolbar.menu,
@@ -169,15 +175,23 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
true
}
R.id.menu_item_new_session -> {
- addNewNetHunterSession("KALI LINUX")
+ addNewNetHunterSession("Kali Shell")
true
}
- R.id.menu_item_new_system_session -> {
- addNewAndroidSession("Android")
+ R.id.menu_item_new_emergency_session -> {
+ addNewEmergencySession("Emergency Shell")
+ true
+ }
+ R.id.menu_item_new_bash_session -> {
+ addNewAndroidSession("Android Shell")
true
}
R.id.menu_item_new_root_session -> {
- addNewRootSession("Android SU")
+ addNewRootSession("Root Shell")
+ true
+ }
+ R.id.menu_item_package_settings -> {
+ startActivity(Intent(this, PackageManagerActivity::class.java))
true
}
else -> item?.let { super.onOptionsItemSelected(it) }
@@ -233,6 +247,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
}
},
)
+
val tab = tabSwitcher.selectedTab as NeoTab?
tab?.onResume()
}
@@ -241,7 +256,9 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
super.onStart()
EventBus.getDefault().register(this)
val tab = tabSwitcher.selectedTab as NeoTab?
- tab?.onStart()
+ if (tab != null) {
+ tab.onStart()
+ }
}
override fun onStop() {
@@ -303,7 +320,8 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
if (grantResults.isEmpty()
|| grantResults[0] != PackageManager.PERMISSION_GRANTED
) {
- AlertDialog.Builder(this).setMessage(R.string.permission_denied)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
+ .setMessage(R.string.permission_denied)
.setPositiveButton(
android.R.string.ok,
{ _: DialogInterface, _: Int ->
@@ -459,7 +477,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
val profilesShell = profiles.filterIsInstance()
if (profiles.isEmpty()) {
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setTitle(R.string.error)
.setMessage(R.string.no_profile_available)
.setPositiveButton(android.R.string.yes, null)
@@ -467,7 +485,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
return
}
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this, R.style.DialogStyle)
.setTitle(R.string.new_session_with_profile)
.setItems(
profiles.map { it.profileName }.toTypedArray(),
@@ -481,11 +499,11 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
}
private fun addNewSession() {
- addNewNetHunterSession("KALI LINUX")
+ addNewNetHunterSession("Kali Shell")
}
private fun addNewSession(sessionName: String?, systemShell: Boolean, animation: Animation) {
- addNewNetHunterSession("KALI LINUX")
+ addNewNetHunterSession("Kali Shell")
}
private fun addNewSessionWithProfile(profile: ShellProfile) {
@@ -511,7 +529,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
.profile(profile)
val session = termService!!.createTermSession(parameter)
- session.mSessionName = sessionName ?: generateSessionName("Kali Linux")
+ session.mSessionName = sessionName ?: generateSessionName("Kali Shell")
val tab = createTab(session.mSessionName) as TermTab
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
@@ -520,6 +538,27 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
switchToSession(tab)
}
+ @SuppressLint("SdCardPath")
+ private fun addNewEmergencySession(sessionName: String?) {
+ val sessionCallback = TermSessionCallback()
+ val viewClient = TermViewClient(this)
+
+ val parameter = ShellParameter()
+ .callback(sessionCallback)
+ .executablePath("/system/bin/sh")
+ .systemShell(true)
+
+ val session = termService!!.createTermSession(parameter)
+
+ session.mSessionName = sessionName ?: generateSessionName("Emergency Shell")
+
+ val tab = createTab(session.mSessionName) as TermTab
+ tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
+
+ addNewTab(tab, createRevealAnimation())
+ switchToSession(tab)
+ }
+
@SuppressLint("SdCardPath")
private fun addNewAndroidSession(sessionName: String?) {
val sessionCallback = TermSessionCallback()
@@ -532,7 +571,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
val session = termService!!.createTermSession(parameter)
- session.mSessionName = sessionName ?: generateSessionName("Android")
+ session.mSessionName = sessionName ?: generateSessionName("Android Shell")
val tab = createTab(session.mSessionName) as TermTab
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
@@ -550,7 +589,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
.executablePath("/data/data/com.offsec.nhterm/files/usr/bin/kali")
val session = termService!!.createTermSession(parameter)
- session.mSessionName = sessionName ?: generateSessionName("KALI LINUX")
+ session.mSessionName = sessionName ?: generateSessionName("Kali Shell")
val tab = createTab(session.mSessionName) as TermTab
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
@@ -572,7 +611,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
val session = termService!!.createTermSession(parameter)
generateSessionName("Android")
- session.mSessionName = sessionName ?: generateSessionName("ANDROID SU")
+ session.mSessionName = sessionName ?: generateSessionName("Root Shell")
val tab = createTab(session.mSessionName) as TermTab
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
@@ -605,15 +644,6 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
}
private fun addXSession() {
- if (!BuildConfig.DEBUG) {
- AlertDialog.Builder(this)
- .setTitle(R.string.error)
- .setMessage(R.string.sorry_for_development)
- .setPositiveButton(android.R.string.yes, null)
- .show()
- return
- }
-
if (!tabSwitcher.isSwitcherShown) {
toggleSwitcher(showSwitcher = true, easterEgg = false)
}
@@ -700,7 +730,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
}
private fun createXTab(tabTitle: String?): Tab {
- return postTabCreated(XSessionTab(tabTitle ?: "Kali Linux"))
+ return postTabCreated(XSessionTab(tabTitle ?: "Kali Shell"))
}
private fun postTabCreated(tab: T): T {
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/term/NeoTermRemoteInterface.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/term/NeoTermRemoteInterface.kt
index 291fb85..8411eb9 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/term/NeoTermRemoteInterface.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/term/NeoTermRemoteInterface.kt
@@ -10,6 +10,7 @@ import android.widget.ArrayAdapter
import android.widget.ListView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.offsec.nhterm.App
import com.offsec.nhterm.R
import com.offsec.nhterm.bridge.Bridge.*
@@ -161,7 +162,7 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
val filesAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, filesToHandle)
filesList.adapter = filesAdapter
filesList.setOnItemClickListener { _, _, position, _ ->
- AlertDialog.Builder(this@NeoTermRemoteInterface)
+ MaterialAlertDialogBuilder(this@NeoTermRemoteInterface, R.style.DialogStyle)
.setMessage(R.string.confirm_remove_file_from_list)
.setPositiveButton(android.R.string.yes) { _, _ ->
filesToHandle.removeAt(position)
diff --git a/nhterm/src/main/java/com/offsec/nhterm/ui/term/tabs.kt b/nhterm/src/main/java/com/offsec/nhterm/ui/term/tabs.kt
index 3572044..9883375 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/ui/term/tabs.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/ui/term/tabs.kt
@@ -3,6 +3,7 @@ package com.offsec.nhterm.ui.term
import android.content.Context
import android.content.res.Configuration
import android.graphics.Rect
+import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@@ -60,10 +61,12 @@ class NeoTabDecorator(val context: NeoTermActivity) : TabSwitcherDecorator() {
Terminals.setupExtraKeysView(extraKeysView)
val colorSchemeManager = ComponentManager.getComponent()
- colorSchemeManager.applyColorScheme(
- terminalView, extraKeysView,
- colorSchemeManager.getCurrentColorScheme()
- )
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ colorSchemeManager.applyColorScheme(
+ terminalView, extraKeysView,
+ colorSchemeManager.getCurrentColorScheme()
+ )
+ }
view
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/utils/NeoPermission.kt b/nhterm/src/main/java/com/offsec/nhterm/utils/NeoPermission.kt
index 0570e34..49cd8fb 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/utils/NeoPermission.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/utils/NeoPermission.kt
@@ -4,10 +4,13 @@ import android.Manifest
import android.content.ActivityNotFoundException
import android.content.DialogInterface
import android.content.pm.PackageManager
+import android.os.Build
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.offsec.nhterm.R
/**
* @author kiva
@@ -16,39 +19,35 @@ object NeoPermission {
const val REQUEST_APP_PERMISSION = 10086
fun initAppPermission(context: AppCompatActivity, requestCode: Int) {
- if (ContextCompat.checkSelfPermission(
- context,
- Manifest.permission.READ_EXTERNAL_STORAGE
- )
- != PackageManager.PERMISSION_GRANTED
- ) {
-
- if (ActivityCompat.shouldShowRequestPermissionRationale(
+ if (ContextCompat.checkSelfPermission(
context,
Manifest.permission.READ_EXTERNAL_STORAGE
)
- ) {
- AlertDialog.Builder(context).setMessage("需要存储权限来访问存储设备上的文件")
- .setPositiveButton(android.R.string.ok, { _: DialogInterface, _: Int ->
- doRequestPermission(context, requestCode)
- })
- .show()
+ != PackageManager.PERMISSION_GRANTED) {
- } else {
- doRequestPermission(context, requestCode)
+ if (ActivityCompat.shouldShowRequestPermissionRationale(
+ context,
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ )) {
+ MaterialAlertDialogBuilder(context, R.style.DialogStyle).setMessage("Please enable Storage permission")
+ .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
+ doRequestPermission(context, requestCode)
+ }.show()
+
+ } else {
+ doRequestPermission(context, requestCode)
+ }
}
}
}
private fun doRequestPermission(context: AppCompatActivity, requestCode: Int) {
try {
- ActivityCompat.requestPermissions(
- context,
- arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
- requestCode
- )
- } catch (ignore: ActivityNotFoundException) {
- // for MIUI, we ignore it.
- }
+ ActivityCompat.requestPermissions(
+ context,
+ arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
+ requestCode)
+ } catch (ignore: ActivityNotFoundException) {
+ // for MIUI, we ignore it.
}
}
diff --git a/nhterm/src/main/java/com/offsec/nhterm/utils/utils.kt b/nhterm/src/main/java/com/offsec/nhterm/utils/utils.kt
index bb8676d..ac087da 100644
--- a/nhterm/src/main/java/com/offsec/nhterm/utils/utils.kt
+++ b/nhterm/src/main/java/com/offsec/nhterm/utils/utils.kt
@@ -3,6 +3,7 @@ package com.offsec.nhterm.utils
import android.content.ContentUris
import android.content.Context
import android.net.Uri
+import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
@@ -37,25 +38,41 @@ fun Long.formatSizeInKB(): String {
}
fun Context.extractAssetsDir(assetDir: String, extractDir: String) = kotlin.runCatching {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val targetDir = Paths.get(extractDir)
- Files.createDirectories(targetDir)
- val assets = this.assets
- assets.list(assetDir)?.let {
- it.map { targetDir.resolve(it) }
- .takeWhile { !Files.exists(it) }
- .forEach { targetPath ->
- assets.open("$assetDir/${targetPath.fileName}").use {
- Files.copy(it, targetPath)
+ Paths.get(extractDir)
+ Files.createDirectories(targetDir)
+ val assets = this.assets
+ assets.list(assetDir)?.let {
+ it.map { targetDir.resolve(it) }
+ .takeWhile { !Files.exists(it) }
+ .forEach { targetPath ->
+ assets.open("$assetDir/${targetPath.fileName}").use {
+ Files.copy(it, targetPath)
+ }
}
- }
+ }
+ } else {
+ val targetDir = com.llamalab.safs.Paths.get(extractDir)
+ com.llamalab.safs.Files.createDirectories(targetDir)
+ val assets = this.assets
+ assets.list(assetDir)?.let {
+ it.map { targetDir.resolve(it) }
+ .takeWhile { !com.llamalab.safs.Files.exists(it) }
+ .forEach { targetPath ->
+ assets.open("$assetDir/${targetPath.fileName}").use {
+ com.llamalab.safs.Files.copy(it, targetPath)
+ }
+ }
+ }
}
}
fun Context.runApt(
- subCommand: String, vararg extraArgs: String,
+ command: String, subCommand: String, extraArgs: String,
autoClose: Boolean = true, block: (Result) -> Unit
) = TerminalDialog(this)
- .execute(NeoTermPath.APT_BIN_PATH, arrayOf(NeoTermPath.APT_BIN_PATH, subCommand, *extraArgs))
+ .execute(NeoTermPath.BIN_PATH + "/kali", command + " " + subCommand, extraArgs)
.imeEnabled(true)
.onFinish { dialog, session ->
val exit = session?.exitStatus ?: 1
diff --git a/nhterm/src/main/res/drawable/ic_launcher_background.xml b/nhterm/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..e009ebe
--- /dev/null
+++ b/nhterm/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nhterm/src/main/res/layout/item_package.xml b/nhterm/src/main/res/layout/item_package.xml
index b5fa57e..2bebfc3 100644
--- a/nhterm/src/main/res/layout/item_package.xml
+++ b/nhterm/src/main/res/layout/item_package.xml
@@ -9,7 +9,7 @@
android:orientation="vertical"
android:padding="@dimen/package_item_padding">
-
-
-
\ No newline at end of file
+
diff --git a/nhterm/src/main/res/layout/ui_main.xml b/nhterm/src/main/res/layout/ui_main.xml
index 11ceb02..a0ce6d5 100644
--- a/nhterm/src/main/res/layout/ui_main.xml
+++ b/nhterm/src/main/res/layout/ui_main.xml
@@ -6,15 +6,14 @@
android:background="@color/terminal_background"
android:orientation="vertical">
-
-
-
+ android:layout_below="@id/pm_tab_header">
+
diff --git a/nhterm/src/main/res/layout/ui_term_dialog.xml b/nhterm/src/main/res/layout/ui_term_dialog.xml
index 036582c..9d05a02 100644
--- a/nhterm/src/main/res/layout/ui_term_dialog.xml
+++ b/nhterm/src/main/res/layout/ui_term_dialog.xml
@@ -4,10 +4,13 @@
android:layout_height="match_parent">
\ No newline at end of file
+
diff --git a/nhterm/src/main/res/menu/older_menu_main.xml b/nhterm/src/main/res/menu/older_menu_main.xml
new file mode 100644
index 0000000..d3f2f10
--- /dev/null
+++ b/nhterm/src/main/res/menu/older_menu_main.xml
@@ -0,0 +1,41 @@
+
+
diff --git a/nhterm/src/main/res/mipmap-hdpi/ic_launcher.png b/nhterm/src/main/res/mipmap-hdpi/ic_launcher.png
index 9547f8a..d46bc0c 100644
Binary files a/nhterm/src/main/res/mipmap-hdpi/ic_launcher.png and b/nhterm/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/nhterm/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/nhterm/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
index 08598a3..3337c40 100644
Binary files a/nhterm/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and b/nhterm/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/nhterm/src/main/res/mipmap-hdpi/ic_launcher_round.png b/nhterm/src/main/res/mipmap-hdpi/ic_launcher_round.png
index aa68fe6..f3ea4ca 100644
Binary files a/nhterm/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/nhterm/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/nhterm/src/main/res/mipmap-mdpi/ic_launcher.png b/nhterm/src/main/res/mipmap-mdpi/ic_launcher.png
index 98719c0..1918731 100644
Binary files a/nhterm/src/main/res/mipmap-mdpi/ic_launcher.png and b/nhterm/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/nhterm/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/nhterm/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
index b3af75e..f4b7d0d 100644
Binary files a/nhterm/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and b/nhterm/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/nhterm/src/main/res/mipmap-mdpi/ic_launcher_round.png b/nhterm/src/main/res/mipmap-mdpi/ic_launcher_round.png
index 0ef5a4f..9d1c1ad 100644
Binary files a/nhterm/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/nhterm/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/nhterm/src/main/res/mipmap-xhdpi/ic_launcher.png b/nhterm/src/main/res/mipmap-xhdpi/ic_launcher.png
index 004a73b..93e9734 100644
Binary files a/nhterm/src/main/res/mipmap-xhdpi/ic_launcher.png and b/nhterm/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/nhterm/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/nhterm/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
index aee36dc..165ff61 100644
Binary files a/nhterm/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and b/nhterm/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/nhterm/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/nhterm/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index 55afe34..6ac8787 100644
Binary files a/nhterm/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/nhterm/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher.png b/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 1ab2299..0987e91 100644
Binary files a/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
index 01a91d8..e2e7a4c 100644
Binary files a/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and b/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index f62847d..c8b0600 100644
Binary files a/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/nhterm/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index 8a51ad8..8ae7b33 100644
Binary files a/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
index 7b7faa4..5b0745d 100644
Binary files a/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and b/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index 812c61d..e0d579a 100644
Binary files a/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/nhterm/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/nhterm/src/main/res/values/colors.xml b/nhterm/src/main/res/values/colors.xml
index 8702830..837b84e 100644
--- a/nhterm/src/main/res/values/colors.xml
+++ b/nhterm/src/main/res/values/colors.xml
@@ -10,4 +10,10 @@
#AE000000
#efefef
#363636
+
+ #202124
+ #131415
+ #A8D8D8D8
+
+ #A88B9FBA
diff --git a/nhterm/src/main/res/values/dimens.xml b/nhterm/src/main/res/values/dimens.xml
index 7122697..30b14d7 100644
--- a/nhterm/src/main/res/values/dimens.xml
+++ b/nhterm/src/main/res/values/dimens.xml
@@ -9,7 +9,7 @@
32dp
72dp
36dp
- 256dp
+ 350dp
48dp
36dp
36dp
diff --git a/nhterm/src/main/res/values/ic_launcher_background.xml b/nhterm/src/main/res/values/ic_launcher_background.xml
index 6feac1c..0c85e35 100644
--- a/nhterm/src/main/res/values/ic_launcher_background.xml
+++ b/nhterm/src/main/res/values/ic_launcher_background.xml
@@ -1,4 +1,4 @@
- #242424
+ #595959
\ No newline at end of file
diff --git a/nhterm/src/main/res/values/strings.xml b/nhterm/src/main/res/values/strings.xml
index 7a3043f..399d155 100644
--- a/nhterm/src/main/res/values/strings.xml
+++ b/nhterm/src/main/res/values/strings.xml
@@ -8,7 +8,8 @@
Toggle Tabs
New Session
New Session…
- New System Shell
+ New Emergency Shell
+ New Bash Shell
New Root Shell
%d session(s)
(Wake Locked)
@@ -47,6 +48,7 @@
Package Settings
Source, Updates, Upgrades
Font, ColorScheme
+ Disabled as of no required functions available by old android api
Customization
Toggle Keyboard
@@ -61,7 +63,7 @@
APT source changed, you may get it updated by executing: apt update
Done
Install
- Package: %s\nVersion: %s\nDepends: %s\nInstalled Size: %s\nDescription: %s\nHome
+ Package: %s\n\nVersion: %s\n\nDepends: %s\n\nInstalled Size: %s\n\nDescription: %s\n\nHome
Page: %s
Package list is empty, please check your source.
@@ -185,8 +187,7 @@
Danger Zone
This will delete and re-copy required files to boot kali chroot, confirm?
- https://example.com/nhterm
-
+ http://http.kali.org/kali
- sh
diff --git a/nhterm/src/main/res/values/styles.xml b/nhterm/src/main/res/values/styles.xml
index 4f637b8..cdf6d12 100644
--- a/nhterm/src/main/res/values/styles.xml
+++ b/nhterm/src/main/res/values/styles.xml
@@ -1,18 +1,17 @@
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nhterm/src/main/res/xml/older_settings_main.xml b/nhterm/src/main/res/xml/older_settings_main.xml
new file mode 100644
index 0000000..be2826f
--- /dev/null
+++ b/nhterm/src/main/res/xml/older_settings_main.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nhterm/src/main/res/xml/setting_general.xml b/nhterm/src/main/res/xml/setting_general.xml
index 53f03b2..5e2c073 100644
--- a/nhterm/src/main/res/xml/setting_general.xml
+++ b/nhterm/src/main/res/xml/setting_general.xml
@@ -5,12 +5,6 @@
android:summary="@string/pref_general_initial_command_desc"
android:title="@string/pref_general_initial_command"/>
-
-