Fixed UTF-8 issue, click on A4.4, add notification and expiry.
[FIXED] A Java UTF-8 encoding issue. [FIXED] Android 4.4 wasn't triggering onClick on TextViews. [ADDED] A notification when the password is copied. [ADDED] Expire the password from the clipboard after 20 seconds. [UPDATED] -underscore variant of slf4j-android to make tags settable with setprops
This commit is contained in:
parent
e126a55912
commit
8faf6b48dd
@ -58,8 +58,11 @@ public class MasterKeyV0 extends MasterKey {
|
|||||||
logger.trc( "key scope: %s", mpKeyScope );
|
logger.trc( "key scope: %s", mpKeyScope );
|
||||||
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
||||||
|
|
||||||
CharBuffer mpChars = CharBuffer.wrap( masterPassword );
|
ByteBuffer mpBytesBuf = MP_charset.encode( CharBuffer.wrap( masterPassword ) );
|
||||||
byte[] mpBytes = MP_charset.encode( mpChars ).array();
|
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
|
||||||
|
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
|
||||||
|
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import com.google.common.primitives.Bytes;
|
|||||||
import com.lambdaworks.crypto.SCrypt;
|
import com.lambdaworks.crypto.SCrypt;
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -42,8 +43,11 @@ public class MasterKeyV3 extends MasterKeyV2 {
|
|||||||
logger.trc( "key scope: %s", mpKeyScope );
|
logger.trc( "key scope: %s", mpKeyScope );
|
||||||
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
||||||
|
|
||||||
CharBuffer mpChars = CharBuffer.wrap( masterPassword );
|
ByteBuffer mpBytesBuf = MP_charset.encode( CharBuffer.wrap( masterPassword ) );
|
||||||
byte[] mpBytes = MP_charset.encode( mpChars ).array();
|
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
|
||||||
|
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
|
||||||
|
Arrays.fill( mpBytesBuf.array(), (byte)0 );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.lyndir.masterpassword"
|
package="com.lyndir.masterpassword"
|
||||||
android:versionCode="1"
|
android:versionCode="2002"
|
||||||
android:versionName="2.2">
|
android:versionName="2.2">
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
|
@ -115,6 +115,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-android</artifactId>
|
<artifactId>slf4j-android</artifactId>
|
||||||
|
<version>1.7.13-underscore</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- clone https://github.com/mosabua/maven-android-sdk-deployer.git
|
<!-- clone https://github.com/mosabua/maven-android-sdk-deployer.git
|
||||||
|
@ -85,7 +85,7 @@
|
|||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<Button
|
||||||
android:id="@id/sitePasswordField"
|
android:id="@id/sitePasswordField"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -2,10 +2,11 @@ package com.lyndir.masterpassword;
|
|||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.*;
|
||||||
import android.content.*;
|
import android.content.*;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.*;
|
import android.text.*;
|
||||||
import android.text.method.PasswordTransformationMethod;
|
import android.text.method.PasswordTransformationMethod;
|
||||||
@ -18,7 +19,7 @@ import com.google.common.base.Throwables;
|
|||||||
import com.google.common.util.concurrent.*;
|
import com.google.common.util.concurrent.*;
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -27,6 +28,8 @@ public class EmergencyActivity extends Activity {
|
|||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
private static final Logger logger = Logger.get( EmergencyActivity.class );
|
private static final Logger logger = Logger.get( EmergencyActivity.class );
|
||||||
|
private static final ClipData EMPTY_CLIP = new ClipData( new ClipDescription( "", new String[0] ), new ClipData.Item( "" ) );
|
||||||
|
private static final int PASSWORD_NOTIFICATION = 0;
|
||||||
|
|
||||||
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
||||||
private final ValueChangedListener updateMasterKey = new ValueChangedListener() {
|
private final ValueChangedListener updateMasterKey = new ValueChangedListener() {
|
||||||
@ -66,7 +69,7 @@ public class EmergencyActivity extends Activity {
|
|||||||
Spinner siteVersionField;
|
Spinner siteVersionField;
|
||||||
|
|
||||||
@InjectView(R.id.sitePasswordField)
|
@InjectView(R.id.sitePasswordField)
|
||||||
TextView sitePasswordField;
|
Button sitePasswordField;
|
||||||
|
|
||||||
@InjectView(R.id.sitePasswordTip)
|
@InjectView(R.id.sitePasswordTip)
|
||||||
TextView sitePasswordTip;
|
TextView sitePasswordTip;
|
||||||
@ -306,13 +309,40 @@ public class EmergencyActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void copySitePassword(View view) {
|
public void copySitePassword(View view) {
|
||||||
if (TextUtils.isEmpty( sitePassword ))
|
final String currentSitePassword = this.sitePassword;
|
||||||
|
if (TextUtils.isEmpty( currentSitePassword ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ClipDescription description = new ClipDescription( strf( "Password for %s", siteNameField.getText() ),
|
final ClipboardManager clipboardManager = (ClipboardManager) getSystemService( CLIPBOARD_SERVICE );
|
||||||
new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } );
|
final NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
|
||||||
ClipData clipData = new ClipData( description, new ClipData.Item( sitePassword ) );
|
|
||||||
((ClipboardManager) getSystemService( CLIPBOARD_SERVICE )).setPrimaryClip( clipData );
|
String title = strf( "Password for %s", siteNameField.getText() );
|
||||||
|
ClipDescription description = new ClipDescription( title, new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } );
|
||||||
|
clipboardManager.setPrimaryClip( new ClipData( description, new ClipData.Item( currentSitePassword ) ) );
|
||||||
|
|
||||||
|
Notification.Builder notificationBuilder = new Notification.Builder( this ).setContentTitle( title )
|
||||||
|
.setContentText( "Paste the password into your app." )
|
||||||
|
.setSmallIcon( R.drawable.icon )
|
||||||
|
.setAutoCancel( true );
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
notificationBuilder.setVisibility( Notification.VISIBILITY_SECRET )
|
||||||
|
.setCategory( Notification.CATEGORY_RECOMMENDATION )
|
||||||
|
.setLocalOnly( true );
|
||||||
|
notificationManager.notify( PASSWORD_NOTIFICATION, notificationBuilder.build() );
|
||||||
|
final Timer timer = new Timer();
|
||||||
|
timer.schedule( new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
ClipData clip = clipboardManager.getPrimaryClip();
|
||||||
|
for (int i = 0; i < clip.getItemCount(); ++i)
|
||||||
|
if (currentSitePassword.equals( clip.getItemAt( i ).coerceToText( EmergencyActivity.this ) )) {
|
||||||
|
clipboardManager.setPrimaryClip( EMPTY_CLIP );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
notificationManager.cancel( PASSWORD_NOTIFICATION );
|
||||||
|
timer.cancel();
|
||||||
|
}
|
||||||
|
}, 20000 );
|
||||||
|
|
||||||
Intent startMain = new Intent( Intent.ACTION_MAIN );
|
Intent startMain = new Intent( Intent.ACTION_MAIN );
|
||||||
startMain.addCategory( Intent.CATEGORY_HOME );
|
startMain.addCategory( Intent.CATEGORY_HOME );
|
||||||
|
Loading…
Reference in New Issue
Block a user