diff --git a/.gitignore b/.gitignore index a14101e6c..be193326d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,36 @@ -.gradle -/local.properties -/.idea/workspace.xml -/.idea/libraries +#built application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ + +# Local configuration file (sdk path, etc) +local.properties + +# Windows thumbnail db +Thumbs.db + +# OSX files .DS_Store -/build + +# Android Studio *.iml -/.idea/.name -/.idea/gradle.xml -/.idea/misc.xml -/.idea/modules.xml -/term/term-release.apk -/term/Term-nh.apk -release +.idea +#.idea/workspace.xml - remove # and delete .idea if it better suit your needs. +.gradle +build/ +.navigation +captures/ +output.json + +#NDK +obj/ +.externalNativeBuild diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 9a8b7e5c4..000000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml deleted file mode 100644 index e7bedf337..000000000 --- a/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 97626ba45..000000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index e503882fa..000000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 3b312839b..000000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml deleted file mode 100644 index 922003b84..000000000 --- a/.idea/scopes/scope_settings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/Android.mk b/Android.mk index 633ef4ec7..6fb4ff640 100644 --- a/Android.mk +++ b/Android.mk @@ -25,4 +25,4 @@ LOCAL_SRC_FILES := $(nhterm_dir)/$(nhterm_apk) LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) -include $(BUILD_PREBUILT) \ No newline at end of file +include $(BUILD_PREBUILT) diff --git a/README.md b/README.md index 50f7a58f8..cc8857810 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,23 @@ -#NetHunter Terminal Emulator +# NetHunter Terminal Emulator -This is a new fork of the Android Terminal Emulator so we can adapt it to our neeeds for Kali Linux Nethunter. +This is a new fork of the Android Terminal Emulator so we can adapt it to our neeeds for Kali NetHunter. Dependencies running the terminal: - Nedds a full instalation (included the chroot install) of Kali Nethunter + Needs a full installation of Kali NetHunter (including chroot) -Buiding from sources: +Building from sources: (Todo) see: https://github.com/jmingov/NetHunter-Terminal-Emulator/blob/master/docs/Building.md -Since the original proyect is "ended" we left here the credits an licenses: +Since the original project has "ended" we'll include the credits and licenses below: Original author: https://github.com/jackpal -Original proyect: https://github.com/jackpal/Android-Terminal-Emulator +Original project: https://github.com/jackpal/Android-Terminal-Emulator -License: The same as the original proyect. (Thouse files are [included](https://github.com/jmingov/NetHunter-Terminal-Emulator/blob/master/NOTICE) in this proyect too.) +License: The same as the original project. (Thouse files are [included](https://github.com/jmingov/NetHunter-Terminal-Emulator/blob/master/NOTICE) in this project too.) diff --git a/build.gradle b/build.gradle index 474fe2aa8..087f69faf 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,3 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. -task wrapper (type:Wrapper) { - gradleVersion = '4.1' - distributionUrl = 'https://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip' -} - buildscript { repositories { jcenter() @@ -13,12 +7,24 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:3.0.0-beta3' + classpath 'com.android.tools.build:gradle:3.2.0' } } + allprojects { repositories { jcenter() + google() } -} \ No newline at end of file +} + +ext { + compileSdkVersion=28 + minSdkVersion=14 + targetSdkVersion=28 + //version=YYYYMMVVRR (Either "VV" for stable version OR "RR" for pre-release candidate (e.g. 0001 for rc1) + versionCode=2019020002 + versionName="2019.2-rc2" +} + diff --git a/emulatorview/build.gradle b/emulatorview/build.gradle index f3ba04aef..cad5df3c5 100644 --- a/emulatorview/build.gradle +++ b/emulatorview/build.gradle @@ -1,12 +1,18 @@ apply plugin: 'com.android.library' +repositories { + jcenter() + google() +} + android { - compileSdkVersion 25 - buildToolsVersion "25" +<<<<<<< HEAD + compileSdkVersion 28 + buildToolsVersion "28.0.3" defaultConfig { - minSdkVersion 4 - targetSdkVersion 25 + minSdkVersion 14 + targetSdkVersion 27 } buildTypes { diff --git a/emulatorview/src/main/AndroidManifest.xml b/emulatorview/src/main/AndroidManifest.xml index 61513aa83..601d55941 100644 --- a/emulatorview/src/main/AndroidManifest.xml +++ b/emulatorview/src/main/AndroidManifest.xml @@ -3,5 +3,4 @@ package="com.offsec.nhterm.emulatorview" android:versionCode="43" android:versionName="1.0.42"> - diff --git a/emulatorview/src/main/java/com/offsec/nhterm/emulatorview/TermSession.java b/emulatorview/src/main/java/com/offsec/nhterm/emulatorview/TermSession.java index f98e4f5b2..2cfe4688e 100644 --- a/emulatorview/src/main/java/com/offsec/nhterm/emulatorview/TermSession.java +++ b/emulatorview/src/main/java/com/offsec/nhterm/emulatorview/TermSession.java @@ -112,11 +112,12 @@ public interface FinishCallback { private FinishCallback mFinishCallback; private boolean mIsRunning = false; - private final Handler mMsgHandler = new Handler() { + + private final Handler mMsgHandler = new Handler(new Handler.Callback() { @Override - public void handleMessage(Message msg) { + public boolean handleMessage(Message msg) { if (!mIsRunning) { - return; + return false; } if (msg.what == NEW_INPUT) { readFromProcess(); @@ -128,8 +129,9 @@ public void run() { } }); } + return true; } - }; + }); private UpdateCallback mTitleChangedListener; @@ -186,16 +188,17 @@ public void run() { Looper.prepare(); Log.d("TermSession.java: ", "new Handler"); - mWriterHandler = new Handler() { + mWriterHandler = new Handler(new Handler.Callback() { @Override - public void handleMessage(Message msg) { + public boolean handleMessage(Message msg) { if (msg.what == NEW_OUTPUT) { writeToOutput(); } else if (msg.what == FINISH) { Looper.myLooper().quit(); } + return true; } - }; + }); // Drain anything in the queue from before we started Log.d("TermSession.java: ", "writeToOutput()"); diff --git a/gradle.properties b/gradle.properties index e0b6a5fed..004c59039 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,3 +13,4 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Fri Sep 16 18:00:52 CDT 2016 + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0f83a6793..a0545d350 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Aug 31 21:08:59 CDT 2017 +#Thu Feb 14 02:14:00 CST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/libtermexec/build.gradle b/libtermexec/build.gradle index 34ed3dddb..e899b6c97 100644 --- a/libtermexec/build.gradle +++ b/libtermexec/build.gradle @@ -1,9 +1,10 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.android.tools.build:gradle:3.2.0' } } apply plugin: 'com.android.library' @@ -13,18 +14,18 @@ repositories { } android { - compileSdkVersion 25 - buildToolsVersion "26.0.1" + compileSdkVersion rootProject.ext.compileSdkVersion defaultConfig { - minSdkVersion 14 - targetSdkVersion 25 - versionCode 2 - versionName "2.0" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode rootProject.ext.versionCode + versionName rootProject.ext.versionName + ndk { moduleName 'libjackpal-termexec2' - abiFilters 'armeabi', 'arm64-v8a', 'armeabi-v7a', 'x86' + abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86' ldLibs 'log', 'c' } } @@ -63,5 +64,5 @@ android.libraryVariants.all { variant -> dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.android.support:support-annotations:26+' + implementation 'com.android.support:support-annotations:28.0.0' } \ No newline at end of file diff --git a/libtermexec/src/main/jni/Application.mk b/libtermexec/src/main/jni/Application.mk index 35ab62887..c29f1d41f 100644 --- a/libtermexec/src/main/jni/Application.mk +++ b/libtermexec/src/main/jni/Application.mk @@ -1,2 +1,2 @@ # Build for ARMv5TE, mips and x86 architectures. -APP_ABI := armeabi mips x86 arm64-v8a armeabi-v7a +APP_ABI := mips x86 arm64-v8a armeabi-v7a diff --git a/libtermexec/src/main/jni/process.cpp b/libtermexec/src/main/jni/process.cpp index 65c505e7f..2e4a8bcd6 100644 --- a/libtermexec/src/main/jni/process.cpp +++ b/libtermexec/src/main/jni/process.cpp @@ -26,8 +26,9 @@ #include #include #include +#include -typedef unsigned short char16_t; +typedef unsigned short uint_least16_t; class String8 { public: @@ -41,7 +42,7 @@ class String8 { } } - void set(const char16_t* o, size_t numChars) { + void set(const uint_least16_t* o, size_t numChars) { if (mString) { free(mString); } diff --git a/term/build.gradle b/term/build.gradle index e4ef9de1d..ec2f2c9d9 100644 --- a/term/build.gradle +++ b/term/build.gradle @@ -1,16 +1,18 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 26 - buildToolsVersion '26.0.1' + compileSdkVersion rootProject.ext.compileSdkVersion + defaultConfig { applicationId 'com.offsec.nhterm' - minSdkVersion 14 - targetSdkVersion 26 + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode rootProject.ext.versionCode + versionName rootProject.ext.versionName ndk { moduleName "libjackpal-androidterm5nhj1" - abiFilters 'armeabi', 'arm64-v8a', 'armeabi-v7a', 'x86' + abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86' ldLibs 'log', 'c' } } @@ -44,5 +46,5 @@ android { dependencies { implementation project(':emulatorview') implementation project(':libtermexec') - implementation "com.android.support:support-v4:+" + implementation 'com.android.support:support-v4:+' } diff --git a/term/src/main/AndroidManifest.xml b/term/src/main/AndroidManifest.xml index f03738761..ae0acd229 100644 --- a/term/src/main/AndroidManifest.xml +++ b/term/src/main/AndroidManifest.xml @@ -10,6 +10,8 @@ + + - + diff --git a/term/src/main/java/com/offsec/nhterm/ShellTermSession.java b/term/src/main/java/com/offsec/nhterm/ShellTermSession.java index d20fb7cd1..a0b4f7438 100644 --- a/term/src/main/java/com/offsec/nhterm/ShellTermSession.java +++ b/term/src/main/java/com/offsec/nhterm/ShellTermSession.java @@ -96,13 +96,29 @@ private void initializeSession(String mShell) throws IOException { if (settings.verifyPath()) { path = checkPath(path); } - String[] env = new String[3]; + String[] env = new String[4]; env[0] = "TERM=" + settings.getTermType(); - env[1] = "PATH=" + path + ":/data/data/com.offsec.nethunter/files/scripts/"; + env[1] = "PATH=" + path + ":/data/data/com.offsec.nethunter/files/scripts" + ":/sbin/.magisk/busybox"; env[2] = "HOME=" + settings.getHomePath(); + // Seems the $HOSTNAME is not defined in the file /system/etc/mkshrc on android 9, + // so the workaround is to set the $HOSTNAME manually by running getprop net.hostname, but shoud getprop be fine to use here? + env[3] = "HOSTNAME=" + getSystemProperty("ro.product.name"); // Log.d("Initialize Sess", settings.getShell()); mProcId = createSubprocess(mShell, env); } + // Copied from stack overflow..https://stackoverflow.com/questions/16944494/system-getpropertyparam-returns-wrong-value-android by @Muzikant + private String getSystemProperty(String propertyName) { + String propertyValue = "";// let's default empty + try { + Process getPropProcess = Runtime.getRuntime().exec("getprop " + propertyName); + BufferedReader osRes = new BufferedReader(new InputStreamReader(getPropProcess.getInputStream())); + propertyValue = osRes.readLine(); + osRes.close(); + } catch (Exception e) { + Log.d(": Get hostname: ", "Failed to get hostname by $(getprop net.hostname)"); + } + return propertyValue; + } private String checkPath(String path) { String[] dirs = path.split(":"); diff --git a/term/src/main/java/com/offsec/nhterm/ShellType.java b/term/src/main/java/com/offsec/nhterm/ShellType.java index 235e76686..51bcbf05b 100644 --- a/term/src/main/java/com/offsec/nhterm/ShellType.java +++ b/term/src/main/java/com/offsec/nhterm/ShellType.java @@ -11,9 +11,9 @@ class ShellType { static final String ANDROID_SHELL = whichCMD("sh") + " -"; - static final String ANDROID_SU_SHELL = whichCMD("su"); - static final String KALI_SHELL = whichCMD("su") + " -c /data/data/com.offsec.nethunter/files/scripts/bootkali"; - static final String KALI_LOGIN_SHELL = whichCMD("su") +" -c /data/data/com.offsec.nethunter/files/scripts/bootkali_login"; + static final String ANDROID_SU_SHELL = whichCMD("su") + " --mount-master"; + static final String KALI_SHELL = whichCMD("su") + " --mount-master -c /data/data/com.offsec.nethunter/files/scripts/bootkali"; + static final String KALI_LOGIN_SHELL = whichCMD("su") + " --mount-master -c /data/data/com.offsec.nethunter/files/scripts/bootkali_login"; private static String whichCMD(String theCmd){ String output = null; diff --git a/term/src/main/java/com/offsec/nhterm/Term.java b/term/src/main/java/com/offsec/nhterm/Term.java index fd47f8e8f..ec9589e10 100644 --- a/term/src/main/java/com/offsec/nhterm/Term.java +++ b/term/src/main/java/com/offsec/nhterm/Term.java @@ -15,7 +15,6 @@ */ package com.offsec.nhterm; - import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; @@ -35,6 +34,7 @@ import android.content.res.Resources; import android.net.Uri; import android.net.wifi.WifiManager; +import android.nfc.Tag; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -58,6 +58,7 @@ import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.Button; +import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; @@ -198,7 +199,7 @@ public View getView(int position, View convertView, ViewGroup parent) { Log.d("mPendingPathBroadcasts","Tamano = " + mTermService.getSessions().size()); Log.d("mPendingPathBroadcasts","Tamano = " + oldLength); TextView label = new TextView(Term.this); - @SuppressLint("StringFormatInvalid") String title = getSessionTitle(position, getString(R.string.window_title, position + 1)); + String title = getSessionTitle(position, getString(R.string.window_title, position + 1)); label.setText(title); if (AndroidCompat.SDK >= 13) { label.setTextAppearance(Term.this, TextAppearance_Holo_Widget_ActionBar_Title); @@ -376,7 +377,7 @@ public void onCreate(Bundle icicle) { Intent broadcast = new Intent(ACTION_PATH_BROADCAST); if (AndroidCompat.SDK >= 12) { - broadcast.addFlags(FLAG_INCLUDE_STOPPED_PACKAGES); + broadcast.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); } mPendingPathBroadcasts++; sendOrderedBroadcast(broadcast, PERMISSION_PATH_BROADCAST, mPathReceiver, null, RESULT_OK, null, null); @@ -388,7 +389,6 @@ public void onCreate(Bundle icicle) { TSIntent = new Intent(this, TermService.class); startService(TSIntent); - if (AndroidCompat.SDK >= 11) { int actionBarMode = mSettings.actionBarMode(); mActionBarMode = actionBarMode; @@ -411,7 +411,7 @@ public void onCreate(Bundle icicle) { setFunctionKeyListener(); PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TermDebug.LOG_TAG); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "com.offsec.nhterm:TermDebug.LOG_TAG"); WifiManager wm = (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE); int wifiLockMode = WifiManager.WIFI_MODE_FULL; if (AndroidCompat.SDK >= 12) { @@ -777,6 +777,8 @@ public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.menu_preferences) { doPreferences(); + } else if (id == R.id.menu_chroot_path) { + doConfigChrootPath(); } else if (id == R.id.menu_new_window) { doCreateNewWindow(); } else if (id == R.id.menu_close_window) { @@ -897,7 +899,7 @@ public void onClick(DialogInterface dialog, int id) { if(CheckRoot.isDeviceRooted()){ Log.d("isDeviceRooted","Device is rooted!"); - String chroot_dir = "/data/local/nhsystem/kali-armhf"; // Not sure if I can wildcard this + String chroot_dir = mSettings.getChrootDir(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (!dir_exists(chroot_dir)){ @@ -992,13 +994,13 @@ public boolean dir_exists(String dir_path) @TargetApi(Build.VERSION_CODES.KITKAT) private void NotFound(String text){ - String msg = ""; + String msg = "Please config a proper Chroot Container Path in Settings."; - if (Objects.equals(text, "/data/data/com.offsec.nethunter/files/scripts/bootkali")){ - msg = "Please run Nethunter Application to generate!"; - } else if (Objects.equals(text, "/data/local/nhsystem/kali-armhf")){ - msg = "Missing chroot. You need to install from Chroot Manager"; - } + //if (Objects.equals(text, "/data/data/com.offsec.nethunter/files/scripts/bootkali")){ + // msg = "Please run Nethunter Application to generate!"; + //} else if (Objects.equals(text, "/data/local/nhsystem/kali-armhf")){ + //msg = "Missing chroot. You need to install from Chroot Manager"; + //} /// Do something for not found text (alertDialog) alertDialogBuilder = new AlertDialog.Builder(this); //alertDialogBuilder.setView(promptsView); @@ -1080,6 +1082,30 @@ private void sendKeyStrings(String str, boolean esc) { } } + private void doConfigChrootPath(){ + final View promptView = getLayoutInflater().inflate(R.layout.menu_chroot_path, null); + final EditText chrootpathEditText = promptView.findViewById(R.id.menu_chroot_path_et); + chrootpathEditText.setText(mSettings.getChrootDir()); + final AlertDialog.Builder adbConfigChrootPath = new AlertDialog.Builder(this); + adbConfigChrootPath.setView(promptView); + adbConfigChrootPath.setCancelable(false); + adbConfigChrootPath.setPositiveButton("OK", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mSettings.setChrootDir(getApplicationContext(), chrootpathEditText.getText().toString()); + } + }); + adbConfigChrootPath.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + adbConfigChrootPath.create().show(); + + + + } private void doCreateNewWindow() { if (mTermSessions == null) { Log.w(TermDebug.LOG_TAG, "Couldn't create new window because mTermSessions == null"); diff --git a/term/src/main/java/com/offsec/nhterm/TermService.java b/term/src/main/java/com/offsec/nhterm/TermService.java index 42a968311..5129895d9 100644 --- a/term/src/main/java/com/offsec/nhterm/TermService.java +++ b/term/src/main/java/com/offsec/nhterm/TermService.java @@ -15,7 +15,7 @@ */ package com.offsec.nhterm; - +import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Context; @@ -31,14 +31,11 @@ import android.support.v4.app.TaskStackBuilder; import android.text.TextUtils; import android.util.Log; -import android.app.Notification; + import android.support.v4.app.NotificationCompat; import android.app.PendingIntent; - -import com.offsec.nhterm.R; import com.offsec.nhterm.emulatorview.TermSession; - import com.offsec.nhterm.compat.ServiceForegroundCompat; import com.offsec.nhterm.libtermexec.v1.*; import com.offsec.nhterm.util.SessionList; @@ -51,9 +48,9 @@ public class TermService extends Service implements TermSession.FinishCallback /* Parallels the value of START_STICKY on API Level >= 5 */ private static final int COMPAT_START_STICKY = 1; - private NotificationManager mNotificationManager; - private final int notifyID = 1; - + private NotificationManager notificationManager; + private static final int notifyID = 1; + private static final String NH_TERM_CHANNEL_ID = "NH_TERM_CHANNEL"; private static final int RUNNING_NOTIFICATION = 1; private ServiceForegroundCompat compat; @@ -102,14 +99,28 @@ public void onCreate() { //compat = new ServiceForegroundCompat(this); mTermSessions = new SessionList(); - mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // Create the NotificationChannel + CharSequence name = getString(R.string.nh_term_notification_channel); + String description = getString(R.string.nh_term_notification_channel); + int importance = NotificationManager.IMPORTANCE_LOW; + NotificationChannel mChannel = new NotificationChannel(NH_TERM_CHANNEL_ID, name, importance); + mChannel.setDescription(description); + // Register the channel with the system; you can't change the importance + // or other notification behaviors after this + notificationManager = (NotificationManager) getSystemService( + NOTIFICATION_SERVICE); + if (notificationManager != null) { + notificationManager.createNotificationChannel(mChannel); + } + } // Building the notification - NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, NH_TERM_CHANNEL_ID) .setSmallIcon(R.drawable.ic_stat_service_notification_icon) // notification icon .setContentTitle(getText(R.string.application_terminal)) // main title of the notification .setContentText(getText(R.string.service_notify_text)); // notification text - //.setContentIntent(pendingIntent); // notification intent + //.setContentIntent(pendingIntent); // notification intent Intent notifyIntent = new Intent(this, Term.class); @@ -133,16 +144,19 @@ public void onCreate() { mBuilder.setContentIntent(resultPendingIntent); // mId allows you to update the notification later on. - mNotificationManager.notify(notifyID, mBuilder.build()); + //notificationManager.notify(notifyID, mBuilder.build()); + startForeground(notifyID, mBuilder.build()); - //compat.startForeground(RUNNING_NOTIFICATION, notification); Log.d(TermDebug.LOG_TAG, "TermService started"); } @Override public void onDestroy() { + // invoking notificationManager.cancel on Android < 8 causes a null pointer exception so we should check first + if (notificationManager == null) + notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); // Remove notification - mNotificationManager.cancel(notifyID); + notificationManager.cancel(notifyID); for (TermSession session : mTermSessions) { /* Don't automatically remove from list of sessions -- we clear the diff --git a/term/src/main/java/com/offsec/nhterm/compat/ServiceForegroundCompat.java b/term/src/main/java/com/offsec/nhterm/compat/ServiceForegroundCompat.java index 28b4bd15f..af566a654 100644 --- a/term/src/main/java/com/offsec/nhterm/compat/ServiceForegroundCompat.java +++ b/term/src/main/java/com/offsec/nhterm/compat/ServiceForegroundCompat.java @@ -21,6 +21,7 @@ import java.lang.reflect.InvocationTargetException; import android.app.Service; import android.util.Log; + import android.app.Notification; import android.app.NotificationManager; import android.content.Context; diff --git a/term/src/main/java/com/offsec/nhterm/util/TermSettings.java b/term/src/main/java/com/offsec/nhterm/util/TermSettings.java index cbc7a1539..46173a2b0 100644 --- a/term/src/main/java/com/offsec/nhterm/util/TermSettings.java +++ b/term/src/main/java/com/offsec/nhterm/util/TermSettings.java @@ -18,8 +18,10 @@ import com.offsec.nhterm.R; +import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; +import android.preference.PreferenceManager; import android.view.KeyEvent; /** @@ -28,6 +30,7 @@ public class TermSettings { private SharedPreferences mPrefs; + private String mChrootPath; private int mStatusBar; private boolean mFunctionBar; private int mActionBarMode; @@ -71,6 +74,7 @@ public class TermSettings { private boolean mUseKeyboardShortcuts; + private static final String CHROOT_DIR = "chroot_dir"; private static final String STATUSBAR_KEY = "statusbar"; private static final String FUNCTIONBAR_KEY = "functionbar"; private static final String ACTIONBAR_KEY = "actionbar"; @@ -183,6 +187,8 @@ public TermSettings(Resources res, SharedPreferences prefs) { } private void readDefaultPrefs(Resources res) { + + mChrootPath = res.getString(R.string.chroot_dir); mStatusBar = Integer.parseInt(res.getString(R.string.pref_statusbar_default)); mFunctionBar = res.getBoolean(R.bool.pref_functionbar_default); mActionBarMode = res.getInteger(R.integer.pref_actionbar_default); @@ -223,6 +229,8 @@ private void readDefaultPrefs(Resources res) { public void readPrefs(SharedPreferences prefs) { mPrefs = prefs; + + mChrootPath = readStringPref(CHROOT_DIR, mChrootPath); mStatusBar = readIntPref(STATUSBAR_KEY, mStatusBar, 1); mFunctionBar = readBooleanPref(FUNCTIONBAR_KEY, mFunctionBar); mActionBarMode = readIntPref(ACTIONBAR_KEY, mActionBarMode, ACTION_BAR_MODE_MAX); @@ -284,6 +292,13 @@ private boolean readBooleanPref(String key, boolean defaultValue) { return mPrefs.getBoolean(key, defaultValue); } + public String getChrootDir() { return mChrootPath; } + + public void setChrootDir(Context context, String chrootDir) { + mPrefs = PreferenceManager.getDefaultSharedPreferences(context); + mPrefs.edit().putString(CHROOT_DIR, chrootDir).apply(); + mPrefs = null; + } public boolean showStatusBar() { return true; } diff --git a/term/src/main/jni/Application.mk b/term/src/main/jni/Application.mk index 35ab62887..c29f1d41f 100644 --- a/term/src/main/jni/Application.mk +++ b/term/src/main/jni/Application.mk @@ -1,2 +1,2 @@ # Build for ARMv5TE, mips and x86 architectures. -APP_ABI := armeabi mips x86 arm64-v8a armeabi-v7a +APP_ABI := mips x86 arm64-v8a armeabi-v7a diff --git a/term/src/main/res/layout/menu_chroot_path.xml b/term/src/main/res/layout/menu_chroot_path.xml new file mode 100644 index 000000000..b99aa8dab --- /dev/null +++ b/term/src/main/res/layout/menu_chroot_path.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/term/src/main/res/menu/main.xml b/term/src/main/res/menu/main.xml index 166245a9e..29dc8be1a 100644 --- a/term/src/main/res/menu/main.xml +++ b/term/src/main/res/menu/main.xml @@ -16,6 +16,8 @@ --> + diff --git a/term/src/main/res/values-ro/strings.xml b/term/src/main/res/values-ro/strings.xml index 3c7ea069f..3795fa050 100644 --- a/term/src/main/res/values-ro/strings.xml +++ b/term/src/main/res/values-ro/strings.xml @@ -34,7 +34,7 @@ "Trimiteţi tasta Control" "Trimiteţi tasta Fn" - "Fereastră" + "Fereastră %1$d" "Sesiune de terminal se execută" diff --git a/term/src/main/res/values/strings.xml b/term/src/main/res/values/strings.xml index 0b1aa7ab3..44264a514 100644 --- a/term/src/main/res/values/strings.xml +++ b/term/src/main/res/values/strings.xml @@ -41,13 +41,17 @@ Send control key Send fn key - %1$d) + Window %1$d Terminal session is running Terminal session finished - + + nh_term + Notification for nh_term + + /data/local/nhsystem/kali-arm64 Screen Status bar