From 9bb9799881e9a7a65552b8b78fa19d089838bc0e Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Wed, 21 Oct 2015 14:20:13 +0200 Subject: Display time left for certificates, fix profiles not be able to be edited. --- .../main/java/de/blinkt/openvpn/VpnProfile.java | 8 +++- .../java/de/blinkt/openvpn/core/X509Utils.java | 45 +++++++++++++++++++++- .../blinkt/openvpn/fragments/Settings_Basic.java | 3 +- .../de/blinkt/openvpn/views/FileSelectLayout.java | 3 +- main/src/main/res/values/strings.xml | 5 ++- 5 files changed, 58 insertions(+), 6 deletions(-) (limited to 'main/src') diff --git a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java index 01ee3d82..6b9576bd 100644 --- a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -69,7 +69,7 @@ public class VpnProfile implements Serializable, Cloneable { private static final long serialVersionUID = 7085688938959334563L; public static final int MAXLOGLEVEL = 4; - public static final int CURRENT_PROFILE_VERSION = 5; + public static final int CURRENT_PROFILE_VERSION = 6; public static final int DEFAULT_MSSFIX_SIZE = 1450; public static String DEFAULT_DNS1 = "8.8.8.8"; public static String DEFAULT_DNS2 = "8.8.4.4"; @@ -222,6 +222,12 @@ public class VpnProfile implements Serializable, Cloneable { if (mConnections ==null) mConnections = new Connection[0]; + if (mProfileVersion < 6) { + if (TextUtils.isEmpty(mProfileCreator)) + mUserEditable=true; + } + + mProfileVersion= CURRENT_PROFILE_VERSION; } diff --git a/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java b/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java index 671be297..9bc5ac97 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java +++ b/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java @@ -6,6 +6,7 @@ package de.blinkt.openvpn.core; import android.content.Context; +import android.content.res.Resources; import android.text.TextUtils; import de.blinkt.openvpn.R; @@ -20,8 +21,13 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.cert.Certificate; import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; import java.util.Hashtable; public class X509Utils { @@ -68,8 +74,9 @@ public class X509Utils { if(!TextUtils.isEmpty(filename)) { try { X509Certificate cert = (X509Certificate) getCertificateFromFile(filename); - - return getCertificateFriendlyName(cert); + String friendlycn = getCertificateFriendlyName(cert); + friendlycn = getCertificateValidityString(cert, c.getResources()) + friendlycn; + return friendlycn; } catch (Exception e) { VpnStatus.logError("Could not read certificate" + e.getLocalizedMessage()); @@ -78,6 +85,40 @@ public class X509Utils { return c.getString(R.string.cannotparsecert); } + public static String getCertificateValidityString(X509Certificate cert, Resources res) { + try { + cert.checkValidity(); + } catch (CertificateExpiredException ce) { + return "EXPIRED: "; + } catch (CertificateNotYetValidException cny) { + return "NOT YET VALID: "; + } + + Date certNotAfter = cert.getNotAfter(); + Date now = new Date(); + long timeLeft = certNotAfter.getTime() - now.getTime(); // Time left in ms + + // More than 72h left, display days + // More than 3 months display months + if (timeLeft > 90l* 24 * 3600 * 1000) { + long months = getMonthsDifference(now, certNotAfter); + return res.getString(R.string.months_left, months); + } else if (timeLeft > 72 * 3600 * 1000) { + long days = timeLeft / (24 * 3600 * 1000); + return res.getString(R.string.days_left, days); + } else { + long hours = timeLeft / (3600 * 1000); + + return res.getString(R.string.hours_left, hours); + } + } + + public static int getMonthsDifference(Date date1, Date date2) { + int m1 = date1.getYear() * 12 + date1.getMonth(); + int m2 = date2.getYear() * 12 + date2.getMonth(); + return m2 - m1 + 1; + } + public static String getCertificateFriendlyName(X509Certificate cert) { X500Principal principal = cert.getSubjectX500Principal(); byte[] encodedSubject = principal.getEncoded(); diff --git a/main/src/main/java/de/blinkt/openvpn/fragments/Settings_Basic.java b/main/src/main/java/de/blinkt/openvpn/fragments/Settings_Basic.java index 5f25b38b..38e4a4e2 100644 --- a/main/src/main/java/de/blinkt/openvpn/fragments/Settings_Basic.java +++ b/main/src/main/java/de/blinkt/openvpn/fragments/Settings_Basic.java @@ -89,8 +89,9 @@ public class Settings_Basic extends Settings_Fragment implements View.OnClickLis certstr+=getString(R.string.hwkeychain); } } - + certstr+=X509Utils.getCertificateValidityString(cert, getResources()); certstr+=X509Utils.getCertificateFriendlyName(cert); + } catch (Exception e) { certstr="Could not get certificate from Keystore: " +e.getLocalizedMessage(); } diff --git a/main/src/main/java/de/blinkt/openvpn/views/FileSelectLayout.java b/main/src/main/java/de/blinkt/openvpn/views/FileSelectLayout.java index 7629f85e..61a698ee 100644 --- a/main/src/main/java/de/blinkt/openvpn/views/FileSelectLayout.java +++ b/main/src/main/java/de/blinkt/openvpn/views/FileSelectLayout.java @@ -151,8 +151,9 @@ public class FileSelectLayout extends LinearLayout implements OnClickListener { mDataView.setText(R.string.inline_file_data); else mDataView.setText(data); - if (mIsCertificate) + if (mIsCertificate) { mDataDetails.setText(X509Utils.getCertificateFriendlyName(c, data)); + } // Show clear button if it should be shown mShowClearButton.setVisibility(mShowClear? VISIBLE : GONE); diff --git a/main/src/main/res/values/strings.xml b/main/src/main/res/values/strings.xml index 2697266b..487a6a62 100755 --- a/main/src/main/res/values/strings.xml +++ b/main/src/main/res/values/strings.xml @@ -178,7 +178,7 @@ No CA Certificate returned while reading from Android keystore. Authentication will probably fail. Shows the log window on connect. The log window can always be accessed from the notification status. Show log window - %10$s %9$s running on %3$s %1$s (%2$s), Android %6$s (%7$s) API %4$d, Build %7$s ABI %5$s, (%8$s) + %10$s %9$s running on %3$s %1$s (%2$s), Android %6$s (%7$s) API %4$d, ABI %5$s, (%8$s) Error signing with Android keystore key %1$s: %2$s The VPN connection warning telling you that this app can intercept all traffic is imposed by the system to prevent abuse of the VPNService API.\nThe VPN connection notification (The key symbol) is also imposed by the Android system to signal an ongoing VPN connection. On some images this notification plays a sound.\nAndroid introduced these system dialogs for your own safety and made sure that they cannot be circumvented. (On some images this unfortunately includes a notification sound) Connection warning and notification sound @@ -390,5 +390,8 @@ Protocol Enabled Preferred native ABI precedence of this device (%1$s) and ABI reported by native libraries (%2$s) mismatch + %d months left + %d days left + %d hours left -- cgit v1.2.3