Second attempt to port our MOTP implementation to an up to date andOTP.

This has been lagging around due to several things.
I have also struggled to get my branch in sync with master, so I have
built patches and applied them directly to mater here.
Let's see if this time I can finally get this pushed and submit a pull request.
This commit is contained in:
Santiago Garcia Mantinan 2020-08-07 11:53:09 +02:00
parent fba943c675
commit 01feaa2ecc
37 changed files with 762 additions and 9 deletions

View file

@ -210,7 +210,7 @@ public class IntroScreenActivity extends IntroActivity {
}
});
selection.setSelection(selectionMapping.indexOfValue(Constants.EncryptionType.PASSWORD));
selection.setSelection(selectionMapping.indexOfValue(Constants.EncryptionType.KEYSTORE));
return root;
}
@ -466,7 +466,7 @@ public class IntroScreenActivity extends IntroActivity {
passwordInput.addTextChangedListener(textWatcher);
passwordConfirm.addTextChangedListener(textWatcher);
selection.setSelection(selectionMapping.indexOfValue(Constants.AuthMethod.PASSWORD));
selection.setSelection(selectionMapping.indexOfValue(Constants.AuthMethod.NONE));
return root;
}

View file

@ -40,11 +40,12 @@ import java.util.Objects;
public class Entry {
public enum OTPType {
TOTP, HOTP, STEAM
TOTP, HOTP, MOTP, STEAM
}
private static final OTPType DEFAULT_TYPE = OTPType.TOTP;
private static final int DEFAULT_PERIOD = 30;
private static final String MOTP_NO_PIN_CODE = "PINREQ";
private static final String JSON_SECRET = "secret";
private static final String JSON_ISSUER = "issuer";
@ -79,6 +80,7 @@ public class Entry {
public static final int COLOR_RED = 1;
private static final int EXPIRY_TIME = 8;
private int color = COLOR_DEFAULT;
private String pin = "";
public Entry(){}
@ -106,6 +108,16 @@ public class Entry {
setThumbnailFromIssuer(issuer);
}
public Entry(OTPType type, String secret, String issuer, String label, List<String> tags) {
this.type = type;
this.secret = secret.getBytes();
this.issuer = issuer;
this.label = label;
this.tags = tags;
this.period = TokenCalculator.TOTP_DEFAULT_PERIOD;
setThumbnailFromIssuer(issuer);
}
public Entry(String contents) throws Exception {
contents = contents.replaceFirst("otpauth", "http");
Uri uri = Uri.parse(contents);
@ -122,6 +134,9 @@ public class Entry {
case "hotp":
type = OTPType.HOTP;
break;
case "motp":
type = OTPType.MOTP;
break;
case "steam":
type = OTPType.STEAM;
break;
@ -155,7 +170,11 @@ public class Entry {
this.issuer = issuer;
this.label = label;
this.secret = new Base32().decode(secret.toUpperCase());
if(type == OTPType.MOTP) {
this.secret = secret.getBytes();
}else{
this.secret = new Base32().decode(secret.toUpperCase());
}
if (digits != null) {
this.digits = Integer.parseInt(digits);
@ -323,7 +342,7 @@ public class Entry {
}
public boolean isTimeBased() {
return type == OTPType.TOTP || type == OTPType.STEAM;
return type == OTPType.TOTP || type == OTPType.STEAM || type == OTPType.MOTP;
}
public boolean isCounterBased() { return type == OTPType.HOTP; }
@ -444,7 +463,19 @@ public class Entry {
return currentOTP;
}
public String getPin() {
return pin;
}
public void setPin(String pin) {
this.pin = pin;
}
public boolean updateOTP() {
return updateOTP(false);
}
public boolean updateOTP(boolean updateNow) {
if (type == OTPType.TOTP || type == OTPType.STEAM) {
long time = System.currentTimeMillis() / 1000;
long counter = time / this.getPeriod();
@ -465,6 +496,22 @@ public class Entry {
} else if (type == OTPType.HOTP) {
currentOTP = TokenCalculator.HOTP(secret, counter, digits, algorithm);
return true;
} else if (type == OTPType.MOTP) {
long time = System.currentTimeMillis() / 1000;
long counter = time / this.getPeriod();
if (counter > last_update || updateNow) {
String currentPin = this.getPin();
if (currentPin.isEmpty()) {
currentOTP = MOTP_NO_PIN_CODE;
} else {
currentOTP = TokenCalculator.MOTP(currentPin, new String(this.secret));
}
last_update = counter;
setColor(COLOR_DEFAULT);
return true;
} else {
return false;
}
} else {
return false;
}

View file

@ -81,6 +81,7 @@ public class ManualEntryDialog {
final LinearLayout periodLayout = inputView.findViewById(R.id.manual_layout_period);
final Spinner algorithmInput = inputView.findViewById(R.id.manual_algorithm);
final Button tagsInput = inputView.findViewById(R.id.manual_tags);
final Button expandButton = inputView.findViewById(R.id.dialog_expand_button);
final ArrayAdapter<TokenCalculator.HashAlgorithm> algorithmAdapter = new ArrayAdapter<>(callingActivity, android.R.layout.simple_expandable_list_item_1, TokenCalculator.HashAlgorithm.values());
final ArrayAdapter<Entry.OTPType> typeAdapter = new ArrayAdapter<>(callingActivity, android.R.layout.simple_expandable_list_item_1, Entry.OTPType.values());
@ -100,6 +101,7 @@ public class ManualEntryDialog {
if (type == Entry.OTPType.STEAM) {
counterLayout.setVisibility(View.GONE);
periodLayout.setVisibility(View.VISIBLE);
expandButton.setVisibility(View.VISIBLE);
digitsInput.setText(String.format(Locale.US, "%d", TokenCalculator.STEAM_DEFAULT_DIGITS));
periodInput.setText(String.format(Locale.US, "%d", TokenCalculator.TOTP_DEFAULT_PERIOD));
@ -111,6 +113,7 @@ public class ManualEntryDialog {
} else if (type == Entry.OTPType.TOTP) {
counterLayout.setVisibility(View.GONE);
periodLayout.setVisibility(View.VISIBLE);
expandButton.setVisibility(View.VISIBLE);
digitsInput.setText(String.format(Locale.US, "%d", TokenCalculator.TOTP_DEFAULT_DIGITS));
digitsInput.setEnabled(isNewEntry);
@ -119,11 +122,19 @@ public class ManualEntryDialog {
} else if (type == Entry.OTPType.HOTP) {
counterLayout.setVisibility(View.VISIBLE);
periodLayout.setVisibility(View.GONE);
expandButton.setVisibility(View.VISIBLE);
digitsInput.setText(String.format(Locale.US, "%d", TokenCalculator.TOTP_DEFAULT_DIGITS));
digitsInput.setEnabled(isNewEntry);
periodInput.setEnabled(isNewEntry);
algorithmInput.setEnabled(isNewEntry);
}else if (type == Entry.OTPType.MOTP) {
counterLayout.setVisibility(View.GONE);
periodLayout.setVisibility(View.VISIBLE);
digitsInput.setText(String.format(Locale.US, "%d", TokenCalculator.TOTP_DEFAULT_DIGITS));
expandButton.setVisibility(View.GONE);
algorithmInput.setEnabled(isNewEntry);
}
}
@ -163,8 +174,6 @@ public class ManualEntryDialog {
}
});
final Button expandButton = inputView.findViewById(R.id.dialog_expand_button);
// Dirty fix for the compound drawable to avoid crashes on KitKat
expandButton.setCompoundDrawablesWithIntrinsicBounds(null, null, callingActivity.getResources().getDrawable(R.drawable.ic_arrow_down_accent), null);

View file

@ -0,0 +1,515 @@
/*
* $Header: /u/users20/santtu/src/java/MD5/RCS/MD5.java,v 1.5 1996/12/12 10:47:02 santtu Exp $
*
* MD5 in Java JDK Beta-2
* written Santeri Paavolainen, Helsinki Finland 1996
* (c) Santeri Paavolainen, Helsinki Finland 1996
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* See http://www.cs.hut.fi/~santtu/java/ for more information on this
* class.
*
* This is rather straight re-implementation of the reference implementation
* given in RFC1321 by RSA.
*
* Passes MD5 test suite as defined in RFC1321.
*
*
* This Java class has been derived from the RSA Data Security, Inc. MD5
* Message-Digest Algorithm and its reference implementation.
*
*
* Revision 1.6 minor changes for j2me, 2003, Matthias Straub
*
* $Log: MD5.java,v $
* Revision 1.5 1996/12/12 10:47:02 santtu
* Changed GPL to LGPL
*
* Revision 1.4 1996/12/12 10:30:02 santtu
* Some typos, State -> MD5State etc.
*
* Revision 1.3 1996/04/15 07:28:09 santtu
* Added GPL statemets, and RSA derivate stametemetsnnts.
*
* Revision 1.2 1996/03/04 08:05:48 santtu
* Added offsets to Update method
*
* Revision 1.1 1996/01/07 20:51:59 santtu
* Initial revision
*
*/
/**
* Contains internal state of the MD5 class
*/
package org.shadowice.flocke.andotp.Utilities;
class MD5State {
/**
* 128-byte state
*/
int state[];
/**
* 64-bit character count (could be true Java long?)
*/
int count[];
/**
* 64-byte buffer (512 bits) for storing to-be-hashed characters
*/
byte buffer[];
public MD5State() {
buffer = new byte[64];
count = new int[2];
state = new int[4];
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
count[0] = count[1] = 0;
}
/** Create this State as a copy of another state */
public MD5State (MD5State from) {
this();
int i;
for (i = 0; i < buffer.length; i++)
this.buffer[i] = from.buffer[i];
for (i = 0; i < state.length; i++)
this.state[i] = from.state[i];
for (i = 0; i < count.length; i++)
this.count[i] = from.count[i];
}
};
/**
* Implementation of RSA's MD5 hash generator
*
* @version $Revision: 1.5 $
* @author Santeri Paavolainen <sjpaavol@cc.helsinki.fi>
*/
public class MD5 {
/**
* MD5 state
*/
MD5State state;
/**
* If Final() has been called, finals is set to the current finals
* state. Any Update() causes this to be set to null.
*/
MD5State finals;
/**
* Padding for Final()
*/
static byte padding[] = {
(byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/**
* Initialize MD5 internal state (object can be reused just by
* calling Init() after every Final()
*/
public synchronized void Init () {
state = new MD5State();
finals = null;
}
/**
* Class constructor
*/
public MD5 () {
this.Init();
}
/**
* Initialize class, and update hash with ob.toString()
*
* @param ob Object, ob.toString() is used to update hash
* after initialization
*/
public MD5 (Object ob) {
this();
Update(ob.toString());
}
private int rotate_left (int x, int n) {
return (x << n) | (x >>> (32 - n));
}
/* I wonder how many loops and hoops you'll have to go through to
get unsigned add for longs in java */
private int uadd (int a, int b) {
long aa, bb;
aa = ((long) a) & 0xffffffffL;
bb = ((long) b) & 0xffffffffL;
aa += bb;
return (int) (aa & 0xffffffffL);
}
private int uadd (int a, int b, int c) {
return uadd(uadd(a, b), c);
}
private int uadd (int a, int b, int c, int d) {
return uadd(uadd(a, b, c), d);
}
private int FF (int a, int b, int c, int d, int x, int s, int ac) {
a = uadd(a, ((b & c) | (~b & d)), x, ac);
return uadd(rotate_left(a, s), b);
}
private int GG (int a, int b, int c, int d, int x, int s, int ac) {
a = uadd(a, ((b & d) | (c & ~d)), x, ac);
return uadd(rotate_left(a, s), b);
}
private int HH (int a, int b, int c, int d, int x, int s, int ac) {
a = uadd(a, (b ^ c ^ d), x, ac);
return uadd(rotate_left(a, s) , b);
}
private int II (int a, int b, int c, int d, int x, int s, int ac) {
a = uadd(a, (c ^ (b | ~d)), x, ac);
return uadd(rotate_left(a, s), b);
}
private int[] Decode (byte buffer[], int len, int shift) {
int out[];
int i, j;
out = new int[16];
for (i = j = 0; j < len; i++, j += 4) {
out[i] = ((int) (buffer[j + shift] & 0xff)) |
(((int) (buffer[j + 1 + shift] & 0xff)) << 8) |
(((int) (buffer[j + 2 + shift] & 0xff)) << 16) |
(((int) (buffer[j + 3 + shift] & 0xff)) << 24);
/* System.out.println("out[" + i + "] = \t" +
((int) buffer[j + 0 + shift] & 0xff) + "\t|\t" +
((int) buffer[j + 1 + shift] & 0xff) + "\t|\t" +
((int) buffer[j + 2 + shift] & 0xff) + "\t|\t" +
((int) buffer[j + 3 + shift] & 0xff));*/
}
return out;
}
private void Transform (MD5State state, byte buffer[], int shift) {
int
a = state.state[0],
b = state.state[1],
c = state.state[2],
d = state.state[3],
x[];
x = Decode(buffer, 64, shift);
/* Round 1 */
a = FF (a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
d = FF (d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
c = FF (c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
b = FF (b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
a = FF (a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
d = FF (d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
c = FF (c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
b = FF (b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
a = FF (a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
d = FF (d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
c = FF (c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
b = FF (b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
a = FF (a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
d = FF (d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
c = FF (c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
b = FF (b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
/* Round 2 */
a = GG (a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
d = GG (d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
c = GG (c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
b = GG (b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
a = GG (a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
d = GG (d, a, b, c, x[10], 9, 0x2441453); /* 22 */
c = GG (c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
b = GG (b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
a = GG (a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
d = GG (d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
c = GG (c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
b = GG (b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
a = GG (a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
d = GG (d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
c = GG (c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
b = GG (b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
/* Round 3 */
a = HH (a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
d = HH (d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
c = HH (c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
b = HH (b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
a = HH (a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
d = HH (d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
c = HH (c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
b = HH (b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
a = HH (a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
d = HH (d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
c = HH (c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
b = HH (b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */
a = HH (a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
d = HH (d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
c = HH (c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
b = HH (b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
/* Round 4 */
a = II (a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
d = II (d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
c = II (c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
b = II (b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
a = II (a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
d = II (d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
c = II (c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
b = II (b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
a = II (a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
d = II (d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
c = II (c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
b = II (b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
a = II (a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
d = II (d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
c = II (c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
b = II (b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
state.state[0] += a;
state.state[1] += b;
state.state[2] += c;
state.state[3] += d;
}
/**
* Updates hash with the bytebuffer given (using at maximum length bytes from
* that buffer)
*
* @param stat Which state is updated
* @param buffer Array of bytes to be hashed
* @param offset Offset to buffer array
* @param length Use at maximum `length' bytes (absolute
* maximum is buffer.length)
*/
public void Update (MD5State stat, byte buffer[], int offset, int length) {
int index, partlen, i, start;
/* System.out.print("Offset = " + offset + "\tLength = " + length + "\t");
System.out.print("Buffer = ");
for (i = 0; i < buffer.length; i++)
System.out.print((int) (buffer[i] & 0xff) + " ");
System.out.print("\n");*/
finals = null;
/* Length can be told to be shorter, but not inter */
if ((length - offset)> buffer.length)
length = buffer.length - offset;
/* compute number of bytes mod 64 */
index = (int) (stat.count[0] >>> 3) & 0x3f;
if ((stat.count[0] += (length << 3)) <
(length << 3))
stat.count[1]++;
stat.count[1] += length >>> 29;
partlen = 64 - index;
if (length >= partlen) {
for (i = 0; i < partlen; i++)
stat.buffer[i + index] = buffer[i + offset];
Transform(stat, stat.buffer, 0);
for (i = partlen; (i + 63) < length; i+= 64)
Transform(stat, buffer, i);
index = 0;
} else
i = 0;
/* buffer remaining input */
if (i < length) {
start = i;
for (; i < length; i++)
stat.buffer[index + i - start] = buffer[i + offset];
}
}
/*
* Update()s for other datatypes than byte[] also. Update(byte[], int)
* is only the main driver.
*/
/**
* Plain update, updates this object
*/
public void Update (byte buffer[], int offset, int length) {
Update(this.state, buffer, offset, length);
}
public void Update (byte buffer[], int length) {
Update(this.state, buffer, 0, length);
}
/**
* Updates hash with given array of bytes
*
* @param buffer Array of bytes to use for updating the hash
*/
public void Update (byte buffer[]) {
Update(buffer, 0, buffer.length);
}
/**
* Updates hash with a single byte
*
* @param b Single byte to update the hash
*/
public void Update (byte b) {
byte buffer[] = new byte[1];
buffer[0] = b;
Update(buffer, 1);
}
/**
* Update buffer with given string.
*
* @param s String to be update to hash (is used as
* s.getBytes())
*/
public void Update (String s) {
byte chars[];
chars = new byte[s.length()];
chars=s.getBytes();
Update(chars, chars.length);
}
/**
* Update buffer with a single integer (only & 0xff part is used,
* as a byte)
*
* @param i Integer value, which is then converted to
* byte as i & 0xff
*/
public void Update (int i) {
Update((byte) (i & 0xff));
}
private byte[] Encode (int input[], int len) {
int i, j;
byte out[];
out = new byte[len];
for (i = j = 0; j < len; i++, j += 4) {
out[j] = (byte) (input[i] & 0xff);
out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
}
return out;
}
/**
* Returns array of bytes (16 bytes) representing hash as of the
* current state of this object. Note: getting a hash does not
* invalidate the hash object, it only creates a copy of the real
* state which is finalized.
*
* @return Array of 16 bytes, the hash of all updated bytes
*/
public synchronized byte[] Final () {
byte bits[];
int index, padlen;
MD5State fin;
if (finals == null) {
fin = new MD5State(state);
bits = Encode(fin.count, 8);
index = (int) ((fin.count[0] >>> 3) & 0x3f);
padlen = (index < 56) ? (56 - index) : (120 - index);
Update(fin, padding, 0, padlen);
/**/
Update(fin, bits, 0, 8);
/* Update() sets finalds to null */
finals = fin;
}
return Encode(finals.state, 16);
}
/**
* Turns array of bytes into string representing each byte as
* unsigned hex number.
*
* @param hash Array of bytes to convert to hex-string
* @return Generated hex string
*/
public static String asHex (byte hash[]) {
StringBuffer buf = new StringBuffer(hash.length * 2);
int i;
for (i = 0; i < hash.length; i++) {
if (((int) hash[i] & 0xff) < 0x10)
buf.append("0");
buf.append(Long.toString((int) hash[i] & 0xff, 16));
}
return buf.toString();
}
/**
* Returns 32-character hex representation of this objects hash
*
* @return String of this object's hash
*/
public String asHex () {
return asHex(this.Final());
}
}

View file

@ -26,6 +26,7 @@ package org.shadowice.flocke.andotp.Utilities;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
@ -115,4 +116,15 @@ public class TokenCalculator {
return r;
}
public static String MOTP(String PIN, String secret)
{
Date dateNow = new Date();
String epoch = "" + (dateNow.getTime());
epoch = epoch.substring(0, epoch.length() - 4);
String otp = epoch + secret + PIN;
MD5 hash = new MD5(otp);
otp = hash.asHex().substring(0, 6);
return otp;
}
}

View file

@ -48,10 +48,17 @@ public class UIHelper {
.show();
}
public static void showKeyboard(Context context, View view) {
public static void showKeyboard(Context context, View view){
showKeyboard(context,view,false);
}
public static void showKeyboard(Context context, View view, Boolean showForced) {
if (view != null) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(view, 0);
if(showForced)
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
else
imm.showSoftInput(view, 0);
}
}

View file

@ -36,11 +36,14 @@ import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.PasswordTransformationMethod;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
@ -66,6 +69,7 @@ import org.shadowice.flocke.andotp.Utilities.EncryptionHelper;
import org.shadowice.flocke.andotp.Utilities.EntryThumbnail;
import org.shadowice.flocke.andotp.Utilities.Settings;
import org.shadowice.flocke.andotp.Utilities.Tools;
import org.shadowice.flocke.andotp.Utilities.UIHelper;
import org.shadowice.flocke.andotp.View.ItemTouchHelper.ItemTouchHelperAdapter;
import java.text.Collator;
@ -97,6 +101,8 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
private TagsAdapter tagsFilterAdapter;
private Settings settings;
private static final int ESTABLISH_PIN_MENU_INDEX = 4;
public EntriesCardAdapter(Context context, TagsAdapter tagsFilterAdapter) {
this.context = context;
this.tagsFilterAdapter = tagsFilterAdapter;
@ -355,6 +361,14 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
public void onCounterLongPressed(int position) {
setCounter(position);
}
@Override
public void onItemClickListener(int position) {
final Entry entry = displayedEntries.get(position);
if(entry.getType() == Entry.OTPType.MOTP && entry.getPin().isEmpty()){
establishPIN(position);
}
}
});
return viewHolder;
@ -620,6 +634,52 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
alert.show();
}
public void establishPIN(final int pos) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
int marginSmall = context.getResources().getDimensionPixelSize(R.dimen.activity_margin_small);
int marginMedium = context.getResources().getDimensionPixelSize(R.dimen.activity_margin_medium);
final EditText input = new EditText(context);
input.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
input.setRawInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_CLASS_NUMBER);
input.setText(displayedEntries.get(pos).getPin());
input.setSingleLine();
input.requestFocus();
input.setTransformationMethod(new PasswordTransformationMethod());
UIHelper.showKeyboard(context,input,true);
FrameLayout container = new FrameLayout(context);
container.setPaddingRelative(marginMedium, marginSmall, marginMedium, 0);
container.addView(input);
builder.setTitle(R.string.dialog_title_pin)
.setCancelable(false)
.setView(container)
.setPositiveButton(R.string.button_accept, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
int realIndex = getRealIndex(pos);
String newPin = input.getEditableText().toString();
displayedEntries.get(pos).setPin(newPin);
Entry e = entries.get(realIndex);
e.setPin(newPin);
e.updateOTP(true);
notifyDataSetChanged();
UIHelper.hideKeyboard(context,input);
}
})
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
UIHelper.hideKeyboard(context,input);
}
})
.create()
.show();
}
public void removeItem(final int pos) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
@ -682,6 +742,11 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
MenuInflater inflate = popup.getMenuInflater();
inflate.inflate(R.menu.menu_popup, popup.getMenu());
if (displayedEntries.get(pos).getType() == Entry.OTPType.MOTP){
MenuItem item = popup.getMenu().getItem(ESTABLISH_PIN_MENU_INDEX);
item.setVisible(true);
}
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
@ -693,6 +758,9 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
} else if(id == R.id.menu_popup_changeImage) {
changeThumbnail(pos);
return true;
} else if (id == R.id.menu_popup_establishPin) {
establishPIN(pos);
return true;
} else if (id == R.id.menu_popup_remove) {
removeItem(pos);
return true;

View file

@ -154,6 +154,14 @@ public class EntryViewHolder extends RecyclerView.ViewHolder
}
});
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (callback != null)
callback.onItemClickListener(getAdapterPosition());
}
});
setTapToReveal(tapToReveal);
}
@ -328,6 +336,7 @@ public class EntryViewHolder extends RecyclerView.ViewHolder
void onCounterClicked(int position);
void onCounterLongPressed(int position);
void onItemClickListener(int position);
}
/**
* Updates the color of OTP to red (if expiring) or default color (if new OTP)

View file

@ -7,6 +7,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_margin_xxsmall"
android:layout_marginBottom="@dimen/activity_margin_xxsmall"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
app:contentPadding="0dp"
style="?attr/cardStyle">

View file

@ -7,6 +7,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_margin_xsmall"
android:layout_marginBottom="@dimen/activity_margin_xsmall"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
app:contentPadding="0dp"
style="?attr/cardStyle">

View file

@ -8,6 +8,8 @@
android:layout_marginTop="@dimen/activity_margin_xsmall"
android:layout_marginBottom="@dimen/activity_margin_xsmall"
app:contentPadding="0dp"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
style="?attr/cardStyle">
<LinearLayout

View file

@ -13,6 +13,11 @@
android:id="@+id/menu_popup_show_qr_code"
android:title="@string/menu_popup_show_qr_code" />
<item
android:id="@+id/menu_popup_establishPin"
android:title="@string/menu_popup_establish_pin"
android:visible="false"/>
<item
android:id="@+id/menu_popup_remove"
android:title="@string/menu_popup_remove" />

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">كافة العلامات</string>
<string name="button_no_tags">بدون علامات</string>
<string name="button_qr_from_image">رمز كيو آر مِن صورة</string>
<string name="button_accept">اقبل</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d ثا</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">تغيير الصورة</string>
<string name="menu_popup_remove">حذف</string>
<string name="menu_popup_show_qr_code">Show QR Code</string>
<string name="menu_popup_establish_pin">أدخل رمز PIN</string>
<!-- Toast messages -->
<string name="toast_auth_failed">أخفقت المصادقة، الرجاء إعادة المحاولة !</string>
<string name="toast_auth_failed_fatal">أخفقت عملية المصادقة، جارٍ إغلاق التطبيق!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_android21_depreaction">Deprecation notice</string>
<string name="dialog_title_enter_password">أدخل كلمة المرور</string>
<string name="dialog_title_pin">دبوس</string>
<string name="dialog_label_enter_password">أدخل كلمة المرور</string>
<string name="dialog_label_confirm_password">تأكيد كلمة المرور</string>
<string name="dialog_msg_auth">الرجاء إدخال بيانات الإعتماد الخاصة بجهازك لتشغيل التطبيق.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Всички маркери</string>
<string name="button_no_tags">Няма маркери</string>
<string name="button_qr_from_image">QR код от изображение</string>
<string name="button_accept">приемам</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d сек</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Промяна на изображението</string>
<string name="menu_popup_remove">Премахване</string>
<string name="menu_popup_show_qr_code">Показване на QR кода</string>
<string name="menu_popup_establish_pin">Въведете ПИН код</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Неуспешно удостоверяване. Моля, опитайте отново!</string>
<string name="toast_auth_failed_fatal">Неуспешно удостоверяване, затваряне на andOTP!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR код</string>
<string name="dialog_title_android21_depreaction">Остаряло известие</string>
<string name="dialog_title_enter_password">Въведете парола</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Въведете парола</string>
<string name="dialog_label_confirm_password">Потвърдете паролата</string>
<string name="dialog_msg_auth">Моля, въведете идентификационните данни на устройството си, за да стартирате andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Totes les etiquetes</string>
<string name="button_no_tags">Sense etiquetes</string>
<string name="button_qr_from_image">QR code from image</string>
<string name="button_accept">Acceptar</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Canvia la imatge</string>
<string name="menu_popup_remove">Suprimeix</string>
<string name="menu_popup_show_qr_code">Show QR Code</string>
<string name="menu_popup_establish_pin">Introduir PIN</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Error d\'autenticació. Torneu-ho a intentar!</string>
<string name="toast_auth_failed_fatal">L\'autenticació ha fallat, andOTP es tancarà!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_android21_depreaction">Deprecation notice</string>
<string name="dialog_title_enter_password">Introduïu la contrasenya</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Introduïu la contrasenya</string>
<string name="dialog_label_confirm_password">Confirmeu la contrasenya</string>
<string name="dialog_msg_auth">Per favor, introduïu les vostres credencials per a iniciar andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Všechny štítky</string>
<string name="button_no_tags">Bez štítku</string>
<string name="button_qr_from_image">QR kód z obrázku</string>
<string name="button_accept">Přijmout</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Změnit obrázek</string>
<string name="menu_popup_remove">Smazat</string>
<string name="menu_popup_show_qr_code">Ukaž QR kód</string>
<string name="menu_popup_establish_pin">Zadejte PIN</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Chyba ověření, zkuste to prosím znovu!</string>
<string name="toast_auth_failed_fatal">Ověření se nezdařilo, zavírám andOTP!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR kód</string>
<string name="dialog_title_android21_depreaction">Oznámení o ukončení podpory</string>
<string name="dialog_title_enter_password">Zadejte heslo</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Zadejte heslo</string>
<string name="dialog_label_confirm_password">Potvrďte heslo</string>
<string name="dialog_msg_auth">Prosím zadejte heslo zařízení ke spuštění andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Alle Marker</string>
<string name="button_no_tags">Keine Marker</string>
<string name="button_qr_from_image">QR-Code aus Bild</string>
<string name="button_accept">Akzeptiere</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Bild ändern</string>
<string name="menu_popup_remove">Entfernen</string>
<string name="menu_popup_show_qr_code">Zeige QR-Code</string>
<string name="menu_popup_establish_pin">PIN einstellen</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Authentifizierung fehlgeschlagen, bitte erneut versuchen!</string>
<string name="toast_auth_failed_fatal">Authentifizierung fehlgeschlagen, andOTP wird geschlossen!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR-Code</string>
<string name="dialog_title_android21_depreaction">Hinweis</string>
<string name="dialog_title_enter_password">Passwort eingeben</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Passwort eingeben</string>
<string name="dialog_label_confirm_password">Passwort bestätigen</string>
<string name="dialog_msg_auth">Bitte geben Sie die Anmeldeinformationen Ihres Geräts ein, um andOTP zu starten.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Όλες οι ετικέτες</string>
<string name="button_no_tags">Χωρίς ετικέτες</string>
<string name="button_qr_from_image">Κώδικας QR από εικόνα</string>
<string name="button_accept">Αποδοχή</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d\"</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Αλλαγή εικόνας</string>
<string name="menu_popup_remove">Διαγραφή</string>
<string name="menu_popup_show_qr_code">Show QR Code</string>
<string name="menu_popup_establish_pin">Ορίστε το PIN</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Η ταυτοποίηση απέτυχε. Παρακαλώ προσπάθησε ξανά!</string>
<string name="toast_auth_failed_fatal">Απέτυχε ο έλεγχος ταυτότητας, κλείνει το andOTP!</string>
@ -74,6 +76,7 @@
<string name="dialog_title_android21_depreaction">Deprecation notice</string>
<string name="dialog_title_enter_password">Εισάγετε κωδικό</string>
<string name="dialog_label_enter_password">Εισάγετε κωδικό</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_confirm_password">Επιβεβαίωση κωδικού</string>
<string name="dialog_msg_auth">Παρακαλούμε εισαγάγετε τα διαπιστευτήριά σας για να ανοίξετε το andOTP.</string>
<string name="dialog_msg_confirm_delete">Σίγουρα θέλετε να αφαιρέσετε το λογαριασμό \"%1$s\";</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Todas las etiquetas</string>
<string name="button_no_tags">Sin etiquetas</string>
<string name="button_qr_from_image">Imagen del código QR</string>
<string name="button_accept">Aceptar</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Cambiar imagen</string>
<string name="menu_popup_remove">Eliminar</string>
<string name="menu_popup_show_qr_code">Mostrar código QR</string>
<string name="menu_popup_establish_pin">Introducir pin</string>
<!-- Toast messages -->
<string name="toast_auth_failed">La autentificación ha fallado, por favor inténtelo otra vez!</string>
<string name="toast_auth_failed_fatal">La autenticación ha fallado, cerrando andOTP!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">Código QR</string>
<string name="dialog_title_android21_depreaction">Aviso de deprecación</string>
<string name="dialog_title_enter_password">Introduzca la contraseña</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Introduzca la contraseña</string>
<string name="dialog_label_confirm_password">Confirmar contraseña</string>
<string name="dialog_msg_auth">Por favor, introduce los credenciales del dispositivo para iniciar andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">همه تگ‌ها</string>
<string name="button_no_tags">بدون تگ</string>
<string name="button_qr_from_image">کد QR از تصویر</string>
<string name="button_accept">قبول کنید</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d ثانیه</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">تغییر تصویر</string>
<string name="menu_popup_remove">حذف</string>
<string name="menu_popup_show_qr_code">نمایش کد QR</string>
<string name="menu_popup_establish_pin">پین را تنظیم کنید</string>
<!-- Toast messages -->
<string name="toast_auth_failed">احراز هویت ناموفق بود، لطفا دوباره تلاش کنید!</string>
<string name="toast_auth_failed_fatal">احراز هویت ناموفق بود، در حال بستن andOTP!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">کد QR</string>
<string name="dialog_title_android21_depreaction">اخطار استهلاک</string>
<string name="dialog_title_enter_password">گذرواژه را وارد کنید</string>
<string name="dialog_title_pin">پین</string>
<string name="dialog_label_enter_password">گذرواژه را وارد کنید</string>
<string name="dialog_label_confirm_password">تایید گذرواژه</string>
<string name="dialog_msg_auth">برای شروع andOTP لطفا اعتبارنامه دستگاه خود را وارد کنید.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Tous les tags</string>
<string name="button_no_tags">Aucun tag</string>
<string name="button_qr_from_image">QR-code à partir d\'une image</string>
<string name="button_accept">Accepter</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Modifier l\'image</string>
<string name="menu_popup_remove">Supprimer</string>
<string name="menu_popup_show_qr_code">Montrer le QR Code</string>
<string name="menu_popup_establish_pin">Définir le code PIN</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Échec d\'authentification, veuillez réessayer !</string>
<string name="toast_auth_failed_fatal">Échec d\'authentification, fermeture d\'andOTP !</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_android21_depreaction">Avis d\'obsolescence</string>
<string name="dialog_title_enter_password">Saisir le mot de passe</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Saisir le mot de passe</string>
<string name="dialog_label_confirm_password">Confirmer le mot de passe</string>
<string name="dialog_msg_auth">Veuillez entrer les informations d\'identification du périphérique pour démarrer andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Todas as etiquetas</string>
<string name="button_no_tags">Sen etiquetas</string>
<string name="button_qr_from_image">Código QR desde imaxe</string>
<string name="button_accept">Aceptar</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Cambiar imaxe</string>
<string name="menu_popup_remove">Eliminar</string>
<string name="menu_popup_show_qr_code">Mostrar código QR</string>
<string name="menu_popup_establish_pin">Introducir o pin</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Fallou a autenticación, por favor inténtao de novo!</string>
<string name="toast_auth_failed_fatal">Fallou a autenticación, pechando andOTP!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">Código QR</string>
<string name="dialog_title_android21_depreaction">Aviso de abandono</string>
<string name="dialog_title_enter_password">Introducir contrasinal</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Introducir contrasinal</string>
<string name="dialog_label_confirm_password">Confirmar contrasinal</string>
<string name="dialog_msg_auth">Introduce as credenciais do dispositivo para iniciar andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">सभी टैग</string>
<string name="button_no_tags">कोई टैग नहीं</string>
<string name="button_qr_from_image">छवि से क्यूआर कोड</string>
<string name="button_accept">स्वीकार करना</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d सेकेंड</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">छवि बदलें</string>
<string name="menu_popup_remove">हटाएं</string>
<string name="menu_popup_show_qr_code">Show QR Code</string>
<string name="menu_popup_establish_pin">पिन सेट करें</string>
<!-- Toast messages -->
<string name="toast_auth_failed">प्रमाणीकरण असफल| कृपया पुन: प्रयास करें!</string>
<string name="toast_auth_failed_fatal">प्रमाणीकरण विफल, समापन andOTP!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_android21_depreaction">Deprecation notice</string>
<string name="dialog_title_enter_password">अपना पासवोर्ड डाले</string>
<string name="dialog_title_pin">पिन</string>
<string name="dialog_label_enter_password">अपना पासवोर्ड डाले</string>
<string name="dialog_label_confirm_password">पासवर्ड की पुष्टि करें</string>
<string name="dialog_msg_auth">AndOTP शुरू करने के लिए कृपया अपनी यंत्र साख दर्ज करें।</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Összes címke</string>
<string name="button_no_tags">Nincs címke</string>
<string name="button_qr_from_image">QR-kód képből</string>
<string name="button_accept">Elfogad</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d másodperc</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Kép módosítása</string>
<string name="menu_popup_remove">Eltávolítás</string>
<string name="menu_popup_show_qr_code">Show QR Code</string>
<string name="menu_popup_establish_pin">Állítsa be a PIN-kódot</string>
<!-- Toast messages -->
<string name="toast_auth_failed">A hitelesítés sikertelen, próbálja újra!</string>
<string name="toast_auth_failed_fatal">A hitelesítés sikertelen, az andOTP bezárul!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_android21_depreaction">Deprecation notice</string>
<string name="dialog_title_enter_password">Jelszó megadása</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Jelszó megadása</string>
<string name="dialog_label_confirm_password">Jelszó megerősítése</string>
<string name="dialog_msg_auth">Kérjük, adja meg a készülék hitelesítő adatait az andOTP indításához.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Tutti i tag</string>
<string name="button_no_tags">Nessun tag</string>
<string name="button_qr_from_image">QR code da immagine</string>
<string name="button_accept">Accettare</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Cambia Immagine</string>
<string name="menu_popup_remove">Rimuovi</string>
<string name="menu_popup_show_qr_code">Mostra codice QR</string>
<string name="menu_popup_establish_pin">Imposta PIN</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Autenticazione non riuscita, riprova!</string>
<string name="toast_auth_failed_fatal">Autenticazione non riuscita, andOTP verrà chiuso!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">Codice QR</string>
<string name="dialog_title_android21_depreaction">Avviso di deprecazione</string>
<string name="dialog_title_enter_password">Inserisci la password</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Inserisci la password</string>
<string name="dialog_label_confirm_password">Conferma la password</string>
<string name="dialog_msg_auth">Si prega di inserire le credenziali del dispositivo per avviare andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">すべてのタグ</string>
<string name="button_no_tags">タグなし</string>
<string name="button_qr_from_image">QR コードを画像からスキャン</string>
<string name="button_accept">受け入れる</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d 秒</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">画像を変更</string>
<string name="menu_popup_remove">削除</string>
<string name="menu_popup_show_qr_code">QR コードを表示</string>
<string name="menu_popup_establish_pin">PINを設定</string>
<!-- Toast messages -->
<string name="toast_auth_failed">認証に失敗しました、もう一度やり直してください!</string>
<string name="toast_auth_failed_fatal">認証に失敗しました、 andOTP を終了します!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR コード</string>
<string name="dialog_title_android21_depreaction">サポート廃止の通知</string>
<string name="dialog_title_enter_password">パスワードを入力</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">パスワードを入力</string>
<string name="dialog_label_confirm_password">パスワードの確認</string>
<string name="dialog_msg_auth">andOTP を起動するためにデバイス認証情報を入力してください。</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Alle labels</string>
<string name="button_no_tags">Geen labels</string>
<string name="button_qr_from_image">QR-code van afbeelding</string>
<string name="button_accept">Accepteren</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Afbeelding wijzigen</string>
<string name="menu_popup_remove">Verwijderen</string>
<string name="menu_popup_show_qr_code">Show QR Code</string>
<string name="menu_popup_establish_pin">PIN instellen</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Authenticatie mislukt. Probeer opnieuw!</string>
<string name="toast_auth_failed_fatal">Verificatie is mislukt, andOTP wordt afgesloten!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_android21_depreaction">Deprecation notice</string>
<string name="dialog_title_enter_password">Wachtwoord invoeren</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Wachtwoord invoeren</string>
<string name="dialog_label_confirm_password">Wachtwoord bevestigen</string>
<string name="dialog_msg_auth">Voer de referenties van uw apparaat in om te beginnen met andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Wszystkie znaczniki</string>
<string name="button_no_tags">Brak znaczników</string>
<string name="button_qr_from_image">Kod QR z obrazu</string>
<string name="button_accept">Zaakceptuj</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Zmień obraz</string>
<string name="menu_popup_remove">Usuń</string>
<string name="menu_popup_show_qr_code">Pokaż kod QR</string>
<string name="menu_popup_establish_pin">Ustaw PIN</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Uwierzytelnianie nie powiodło się, proszę spróbować ponownie</string>
<string name="toast_auth_failed_fatal">Uwierzytelnianie nie powiodło się, zamykanie andOTP</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">Kod QR</string>
<string name="dialog_title_android21_depreaction">Informacja o wycofaniu</string>
<string name="dialog_title_enter_password">Wprowadź hasło</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Wprowadź hasło</string>
<string name="dialog_label_confirm_password">Potwierdź hasło</string>
<string name="dialog_msg_auth">Podaj swoje dane uwierzytelniające, aby uruchomić andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Todos os marcadores</string>
<string name="button_no_tags">Sem marcadores</string>
<string name="button_qr_from_image">QR code from image</string>
<string name="button_accept">Aceitar</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Alterar imagem</string>
<string name="menu_popup_remove">Remover</string>
<string name="menu_popup_show_qr_code">Show QR Code</string>
<string name="menu_popup_establish_pin">Definir PIN</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Falha na autenticação. Por favor, tente novamente.</string>
<string name="toast_auth_failed_fatal">Falha na autenticação, fechando o aplicativo.</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_android21_depreaction">Deprecation notice</string>
<string name="dialog_title_enter_password">Digite a senha</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Digite a senha</string>
<string name="dialog_label_confirm_password">Confirme a senha</string>
<string name="dialog_msg_auth">Por favor, insira credenciais do dispositivo para iniciar andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Все теги</string>
<string name="button_no_tags">Нет тегов</string>
<string name="button_qr_from_image">QR код из изображения</string>
<string name="button_accept">принимать</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d сек.</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Изменить изображение</string>
<string name="menu_popup_remove">Убрать</string>
<string name="menu_popup_show_qr_code">Показать QR-код</string>
<string name="menu_popup_establish_pin">Установить PIN</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Ошибка аутентификации! Пожалуйста, попробуйте снова!</string>
<string name="toast_auth_failed_fatal">Ошибка аутентификации, andOTP закрывается!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR-код</string>
<string name="dialog_title_android21_depreaction">Уведомление об устаревании</string>
<string name="dialog_title_enter_password">Введите пароль</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Введите пароль</string>
<string name="dialog_label_confirm_password">Подтвердите пароль</string>
<string name="dialog_msg_auth">Пожалуйста, подтвердите учетные данные устройства для открытия andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Vse oznake</string>
<string name="button_no_tags">Ni oznak</string>
<string name="button_qr_from_image">QR code from image</string>
<string name="button_accept">Sprejmi</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Spremeni podobo</string>
<string name="menu_popup_remove">Odstrani</string>
<string name="menu_popup_show_qr_code">Show QR Code</string>
<string name="menu_popup_establish_pin">Nastavite kodo PIN</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Prišlo je do napake pri preverjanju vaše identitete. Prosimo, poskusite ponovno!</string>
<string name="toast_auth_failed_fatal">Preverjanje pristnosti ni uspelo, andOTP se zapira!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_android21_depreaction">Deprecation notice</string>
<string name="dialog_title_enter_password">Vnesite geslo</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Vnesite geslo</string>
<string name="dialog_label_confirm_password">Potrdite geslo</string>
<string name="dialog_msg_auth">Prosim, vnesite podatke o napravi za zagon andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Alla taggar</string>
<string name="button_no_tags">Inga taggar</string>
<string name="button_qr_from_image">QR-kod från bild</string>
<string name="button_accept">Acceptera</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Ändra bild</string>
<string name="menu_popup_remove">Ta bort</string>
<string name="menu_popup_show_qr_code">Visa QR-kod</string>
<string name="menu_popup_establish_pin">Ställ in PIN-kod</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Autentisering misslyckades, vänligen försök igen!</string>
<string name="toast_auth_failed_fatal">Autentisering misslyckades, stänger andOTP!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR-kod</string>
<string name="dialog_title_android21_depreaction">Avskrivningsnotis</string>
<string name="dialog_title_enter_password">Ange lösenord</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Ange lösenord</string>
<string name="dialog_label_confirm_password">Bekräfta lösenord</string>
<string name="dialog_msg_auth">Ange dina enhetsuppgifter för att starta andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Tüm etiketler</string>
<string name="button_no_tags">Etiket yok</string>
<string name="button_qr_from_image">Görüntüden QR kodu</string>
<string name="button_accept">Kabul etmek</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d lar(ler)</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Görseli değiştir</string>
<string name="menu_popup_remove">Kaldır</string>
<string name="menu_popup_show_qr_code">QR Kodunu Göster</string>
<string name="menu_popup_establish_pin">PIN ayarla</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Kimlik doğrulama başarısız oldu, lütfen tekrar deneyin!</string>
<string name="toast_auth_failed_fatal">Kimlik doğrulama başarısız oldu, andOTP kapatılıyor!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Kodu</string>
<string name="dialog_title_android21_depreaction">Destek sonlandırma bildirimi</string>
<string name="dialog_title_enter_password">Şifre girin</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_label_enter_password">Şifre Girin</string>
<string name="dialog_label_confirm_password">Şifreyi doğrula</string>
<string name="dialog_msg_auth">Lütfen andOTP\'yi başlatmak için cihaz kimlik bilgilerinizi girin.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">Усі мітки</string>
<string name="button_no_tags">Немає міток</string>
<string name="button_qr_from_image">QR code from image</string>
<string name="button_accept">Прийміть</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d с</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">Змінити зображення</string>
<string name="menu_popup_remove">Видалити</string>
<string name="menu_popup_show_qr_code">Show QR Code</string>
<string name="menu_popup_establish_pin">Встановити PIN-код</string>
<!-- Toast messages -->
<string name="toast_auth_failed">Аутентифікація не пройдена. Будь ласка, спробуйте ще раз!</string>
<string name="toast_auth_failed_fatal">Автентифікація не пройдена, закриття andOTP!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_android21_depreaction">Deprecation notice</string>
<string name="dialog_title_enter_password">Введіть пароль</string>
<string name="dialog_title_pin">PIN-код</string>
<string name="dialog_label_enter_password">Введіть пароль</string>
<string name="dialog_label_confirm_password">Підтвердіть пароль</string>
<string name="dialog_msg_auth">Будь ласка, підтвердіть дані вашого пристрою, щоб запустити andOTP.</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">所有标签</string>
<string name="button_no_tags">无标签</string>
<string name="button_qr_from_image">相册中选择二维码</string>
<string name="button_accept">接受</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d 秒</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">更改图像</string>
<string name="menu_popup_remove">移除</string>
<string name="menu_popup_show_qr_code">显示二维码</string>
<string name="menu_popup_establish_pin">设置密码</string>
<!-- Toast messages -->
<string name="toast_auth_failed">验证失败,请重试!</string>
<string name="toast_auth_failed_fatal">验证失败,正在关闭 andOTP</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">二维码</string>
<string name="dialog_title_android21_depreaction">禁用通知</string>
<string name="dialog_title_enter_password">输入密码</string>
<string name="dialog_title_pin">密码</string>
<string name="dialog_label_enter_password">输入密码</string>
<string name="dialog_label_confirm_password">确认密码</string>
<string name="dialog_msg_auth">请输入您的设备凭据以启动 andOTP。</string>

View file

@ -10,6 +10,7 @@
<string name="button_all_tags">所有標籤</string>
<string name="button_no_tags">無標籤</string>
<string name="button_qr_from_image">從圖片而來的 QR code</string>
<string name="button_accept">接受</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d 秒</string>
<!-- Hints -->
@ -45,6 +46,7 @@
<string name="menu_popup_change_image">變更影像</string>
<string name="menu_popup_remove">移除</string>
<string name="menu_popup_show_qr_code">顯示 QR Code</string>
<string name="menu_popup_establish_pin">設置密碼</string>
<!-- Toast messages -->
<string name="toast_auth_failed">認證失敗,請再試一次!</string>
<string name="toast_auth_failed_fatal">認證失敗andOTP 正在關閉!</string>
@ -73,6 +75,7 @@
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_android21_depreaction">棄用通知</string>
<string name="dialog_title_enter_password">請輸入密碼</string>
<string name="dialog_title_pin">密碼</string>
<string name="dialog_label_enter_password">輸入密碼</string>
<string name="dialog_label_confirm_password">確認密碼</string>
<string name="dialog_msg_auth">請鍵入設備憑證來開啟 andOTP。</string>

View file

@ -11,6 +11,7 @@
<string name="button_all_tags">All tags</string>
<string name="button_no_tags">No tags</string>
<string name="button_qr_from_image">QR code from image</string>
<string name="button_accept">Accept</string>
<!-- Custom formatting -->
<string name="format_custom_period">%d s</string>
@ -56,6 +57,7 @@
<string name="menu_popup_change_image">Change image</string>
<string name="menu_popup_remove">Remove</string>
<string name="menu_popup_show_qr_code">Show QR Code</string>
<string name="menu_popup_establish_pin">Enter pin</string>
<!-- Buttons -->
<string name="button_card_options">More options</string>
@ -93,6 +95,7 @@
<string name="dialog_title_used_tokens">Tokens usage</string>
<string name="dialog_title_keystore_error">KeyStore error</string>
<string name="dialog_title_qr_code">QR Code</string>
<string name="dialog_title_pin">PIN</string>
<string name="dialog_title_enter_password">Enter password</string>