2
0

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:
Maarten Billemont 2015-04-18 14:48:27 -04:00
parent e126a55912
commit 8faf6b48dd
6 changed files with 53 additions and 15 deletions

View File

@ -58,8 +58,11 @@ public class MasterKeyV0 extends MasterKey {
logger.trc( "key scope: %s", mpKeyScope );
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
CharBuffer mpChars = CharBuffer.wrap( masterPassword );
byte[] mpBytes = MP_charset.encode( mpChars ).array();
ByteBuffer mpBytesBuf = MP_charset.encode( CharBuffer.wrap( masterPassword ) );
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
try {
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
}

View File

@ -4,6 +4,7 @@ import com.google.common.primitives.Bytes;
import com.lambdaworks.crypto.SCrypt;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.security.GeneralSecurityException;
import java.util.Arrays;
@ -42,8 +43,11 @@ public class MasterKeyV3 extends MasterKeyV2 {
logger.trc( "key scope: %s", mpKeyScope );
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
CharBuffer mpChars = CharBuffer.wrap( masterPassword );
byte[] mpBytes = MP_charset.encode( mpChars ).array();
ByteBuffer mpBytesBuf = MP_charset.encode( CharBuffer.wrap( masterPassword ) );
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
Arrays.fill( mpBytesBuf.array(), (byte)0 );
try {
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lyndir.masterpassword"
android:versionCode="1"
android:versionCode="2002"
android:versionName="2.2">
<uses-sdk

View File

@ -115,6 +115,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-android</artifactId>
<version>1.7.13-underscore</version>
</dependency>
<!-- clone https://github.com/mosabua/maven-android-sdk-deployer.git

View File

@ -85,7 +85,7 @@
android:layout_gravity="center"
android:orientation="vertical">
<TextView
<Button
android:id="@id/sitePasswordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -2,10 +2,11 @@ package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import android.app.Activity;
import android.app.*;
import android.content.*;
import android.content.ClipboardManager;
import android.graphics.Paint;
import android.os.Build;
import android.os.Bundle;
import android.text.*;
import android.text.method.PasswordTransformationMethod;
@ -18,7 +19,7 @@ import com.google.common.base.Throwables;
import com.google.common.util.concurrent.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import java.util.Arrays;
import java.util.*;
import java.util.concurrent.*;
import javax.annotation.Nullable;
@ -26,7 +27,9 @@ import javax.annotation.Nullable;
public class EmergencyActivity extends Activity {
@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 ValueChangedListener updateMasterKey = new ValueChangedListener() {
@ -66,7 +69,7 @@ public class EmergencyActivity extends Activity {
Spinner siteVersionField;
@InjectView(R.id.sitePasswordField)
TextView sitePasswordField;
Button sitePasswordField;
@InjectView(R.id.sitePasswordTip)
TextView sitePasswordTip;
@ -306,13 +309,40 @@ public class EmergencyActivity extends Activity {
}
public void copySitePassword(View view) {
if (TextUtils.isEmpty( sitePassword ))
final String currentSitePassword = this.sitePassword;
if (TextUtils.isEmpty( currentSitePassword ))
return;
ClipDescription description = new ClipDescription( strf( "Password for %s", siteNameField.getText() ),
new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } );
ClipData clipData = new ClipData( description, new ClipData.Item( sitePassword ) );
((ClipboardManager) getSystemService( CLIPBOARD_SERVICE )).setPrimaryClip( clipData );
final ClipboardManager clipboardManager = (ClipboardManager) getSystemService( CLIPBOARD_SERVICE );
final NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
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 );
startMain.addCategory( Intent.CATEGORY_HOME );