1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-04 00:53:36 +02:00

Compare commits

...

14 Commits

Author SHA1 Message Date
m2049r
d97b36aa44 v1.11 (#545) 2019-03-02 12:26:36 +01:00
m2049r
8fa06e5b37 2019-03 restore height (#544) 2019-03-02 09:44:40 +01:00
m2049r
8d95de828b prevent screenshots on dialogs (#543) 2019-03-02 09:31:06 +01:00
m2049r
93a7be0452 update slow_hash signature (#542) 2019-03-02 09:07:27 +01:00
m2049r
25c8ec1229 fix reading rest (#541) 2019-02-28 22:07:22 +01:00
m2049r
0bf0444dce seed is a password (#540) 2019-02-28 18:43:32 +01:00
m2049r
b74f9c6bd7 upgrade monero core (#539) 2019-02-28 18:33:16 +01:00
m2049r
f843bb1685 share: multiple send & save only when fired (#537) 2019-02-25 21:55:57 +01:00
m2049r
7d9d49c29e landscape mode on tablets (#535) 2019-02-18 19:05:45 +01:00
m2049r
4ca9328949 bump version (#534) 2019-02-17 20:23:00 +01:00
m2049r
08b5a87f19 get rid of keystore exception on first call (#533) 2019-02-14 23:45:01 +01:00
m2049r
445d8acc38 open on monero: & bitcoin: uri (#532) 2019-02-14 23:34:38 +01:00
m2049r
9385ac8c31 update gradle version 2019-02-11 18:50:43 +01:00
Keksoj
4c7ebd8402 translated 'help', 'strings' and 'about' to esperanto (#531) 2019-02-11 07:41:50 +01:00
46 changed files with 1287 additions and 98 deletions

View File

@@ -7,8 +7,8 @@ android {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 28
versionCode 165
versionName "1.10.15 'Node-O-matiC'"
versionCode 170
versionName "1.11.0 'Chernushka'"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {

View File

@@ -26,14 +26,14 @@
android:configChanges="orientation|keyboardHidden"
android:label="@string/wallet_activity_name"
android:launchMode="singleTask"
android:screenOrientation="portrait" />
android:screenOrientation="behind" />
<activity
android:name=".LoginActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name"
android:launchMode="singleTop"
android:screenOrientation="portrait">
android:screenOrientation="locked">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -42,6 +42,22 @@
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<data android:scheme="monero" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<data android:scheme="bitcoin" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />
@@ -52,5 +68,15 @@
android:description="@string/service_description"
android:exported="false"
android:label="Monero Wallet Service" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>
</manifest>

View File

@@ -60,14 +60,14 @@ enum {
HASH_DATA_AREA = 136
};
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed);
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, uint64_t height);
inline void slow_hash(const void *data, const size_t length, char *hash) {
cn_slow_hash(data, length, hash, 0 /* variant */, 0/*prehashed*/);
cn_slow_hash(data, length, hash, 0 /*variant*/, 0 /*prehashed*/, 0 /*height*/);
}
inline void slow_hash_broken(const void *data, char *hash, int variant) {
cn_slow_hash(data, 200 /*sizeof(union hash_state)*/, hash, variant, 1 /*prehashed*/);
cn_slow_hash(data, 200 /*sizeof(union hash_state)*/, hash, variant, 1 /*prehashed*/, 0 /*height*/);
}
#ifdef __cplusplus

View File

@@ -173,10 +173,10 @@ public class LevinReader {
// this should be in LittleEndianDataInputStream because it has little
// endian logic
private long readRest(int firstByte, int bytes) throws IOException {
private long readRest(final int firstByte, final int bytes) throws IOException {
long result = firstByte;
for (int i = 0; i < bytes; i++) {
result = result + (in.readUnsignedByte() << 8);
for (int i = 1; i < bytes + 1; i++) {
result = result + (((long) in.readUnsignedByte()) << (8 * i));
}
return result;
}

View File

@@ -95,7 +95,6 @@ public class GenerateFragment extends Fragment {
etWalletRestoreHeight = view.findViewById(R.id.etWalletRestoreHeight);
bGenerate = view.findViewById(R.id.bGenerate);
etWalletMnemonic.getEditText().setRawInputType(InputType.TYPE_CLASS_TEXT);
etWalletAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etWalletViewKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etWalletSpendKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);

View File

@@ -269,7 +269,11 @@ public class LoginActivity extends BaseActivity
} else {
Timber.i("Waiting for permissions");
}
processUsbIntent(getIntent());
// try intents
Intent intent = getIntent();
if (!processUsbIntent(intent))
processUriIntent(intent);
}
boolean checkServiceRunning() {
@@ -716,6 +720,10 @@ public class LoginActivity extends BaseActivity
intent.putExtra(WalletActivity.REQUEST_PW, walletPassword);
intent.putExtra(WalletActivity.REQUEST_FINGERPRINT_USED, fingerprintUsed);
intent.putExtra(WalletActivity.REQUEST_STREETMODE, streetmode);
if (uri != null) {
intent.putExtra(WalletActivity.REQUEST_URI, uri);
uri = null; // use only once
}
startActivity(intent);
}
@@ -1385,7 +1393,7 @@ public class LoginActivity extends BaseActivity
processUsbIntent(intent);
}
private void processUsbIntent(Intent intent) {
private boolean processUsbIntent(Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
synchronized (this) {
@@ -1398,6 +1406,21 @@ public class LoginActivity extends BaseActivity
}
}
}
return true;
}
return false;
}
private String uri = null;
private void processUriIntent(Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
synchronized (this) {
uri = intent.getDataString();
Timber.d("URI Intent %s", uri);
HelpFragment.display(getSupportFragmentManager(), R.string.help_uri);
}
}
}

View File

@@ -17,19 +17,28 @@
package com.m2049r.xmrwallet;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.nfc.NfcManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.Fragment;
import android.support.v4.content.FileProvider;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.ShareActionProvider;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.KeyEvent;
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.EditorInfo;
@@ -56,6 +65,9 @@ import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
import com.m2049r.xmrwallet.widget.ExchangeView;
import com.m2049r.xmrwallet.widget.Toolbar;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@@ -69,8 +81,8 @@ public class ReceiveFragment extends Fragment {
private TextInputLayout etNotes;
private ExchangeView evAmount;
private TextView tvQrCode;
private ImageView qrCode;
private ImageView qrCodeFull;
private ImageView ivQrCode;
private ImageView ivQrCodeFull;
private EditText etDummy;
private ImageButton bCopyAddress;
private Button bSubaddress;
@@ -97,9 +109,9 @@ public class ReceiveFragment extends Fragment {
tvAddress = view.findViewById(R.id.tvAddress);
etNotes = view.findViewById(R.id.etNotes);
evAmount = view.findViewById(R.id.evAmount);
qrCode = view.findViewById(R.id.qrCode);
ivQrCode = view.findViewById(R.id.qrCode);
tvQrCode = view.findViewById(R.id.tvQrCode);
qrCodeFull = view.findViewById(R.id.qrCodeFull);
ivQrCodeFull = view.findViewById(R.id.qrCodeFull);
etDummy = view.findViewById(R.id.etDummy);
bCopyAddress = view.findViewById(R.id.bCopyAddress);
bSubaddress = view.findViewById(R.id.bSubaddress);
@@ -178,25 +190,25 @@ public class ReceiveFragment extends Fragment {
}
});
qrCode.setOnClickListener(new View.OnClickListener() {
ivQrCode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.hideKeyboard(getActivity());
etDummy.requestFocus();
if (qrValid) {
qrCodeFull.setImageBitmap(((BitmapDrawable) qrCode.getDrawable()).getBitmap());
qrCodeFull.setVisibility(View.VISIBLE);
ivQrCodeFull.setImageBitmap(((BitmapDrawable) ivQrCode.getDrawable()).getBitmap());
ivQrCodeFull.setVisibility(View.VISIBLE);
} else {
evAmount.doExchange();
}
}
});
qrCodeFull.setOnClickListener(new View.OnClickListener() {
ivQrCodeFull.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
qrCodeFull.setImageBitmap(null);
qrCodeFull.setVisibility(View.GONE);
ivQrCodeFull.setImageBitmap(null);
ivQrCodeFull.setVisibility(View.GONE);
}
});
@@ -228,6 +240,81 @@ public class ReceiveFragment extends Fragment {
return view;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
private ShareActionProvider shareActionProvider;
@Override
public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.receive_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
// Locate MenuItem with ShareActionProvider
MenuItem item = menu.findItem(R.id.menu_item_share);
// Fetch and store ShareActionProvider
shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
shareActionProvider.setOnShareTargetSelectedListener(new ShareActionProvider.OnShareTargetSelectedListener() {
@Override
public boolean onShareTargetSelected(ShareActionProvider shareActionProvider, Intent intent) {
saveQrCode(); // save it only if we need it
return false;
}
});
}
private void setShareIntent() {
if (shareActionProvider != null) {
if (qrValid) {
shareActionProvider.setShareIntent(getShareIntent());
} else {
shareActionProvider.setShareIntent(null);
}
}
}
private void saveQrCode() {
if (!qrValid) throw new IllegalStateException("trying to save null qr code!");
File cachePath = new File(getActivity().getCacheDir(), "images");
if (!cachePath.exists())
if (!cachePath.mkdirs()) throw new IllegalStateException("cannot create images folder");
File png = new File(cachePath, "QR.png");
try {
FileOutputStream stream = new FileOutputStream(png);
Bitmap qrBitmap = ((BitmapDrawable) ivQrCode.getDrawable()).getBitmap();
qrBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
stream.close();
} catch (IOException ex) {
Timber.e(ex);
// make sure we don't share an old qr code
if (!png.delete()) throw new IllegalStateException("cannot delete old qr code");
// if we manage to delete it, the URI points to nothing and the user gets a toast with the error
}
}
private Intent getShareIntent() {
File imagePath = new File(getActivity().getCacheDir(), "images");
File png = new File(imagePath, "QR.png");
Uri contentUri = FileProvider.getUriForFile(getActivity(),
"com.m2049r.xmrwallet.fileprovider", png);
if (contentUri != null) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // temp permission for receiving app to read this file
shareIntent.setDataAndType(contentUri, getActivity().getContentResolver().getType(contentUri));
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
shareIntent.putExtra(Intent.EXTRA_TEXT, bcData.getUriString());
return shareIntent;
}
return null;
}
void enableSubaddressButton(boolean enable) {
bSubaddress.setEnabled(enable);
if (enable) {
@@ -242,23 +329,23 @@ public class ReceiveFragment extends Fragment {
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
}
boolean qrValid = true;
private boolean qrValid = false;
void clearQR() {
if (qrValid) {
qrCode.setImageBitmap(null);
ivQrCode.setImageBitmap(null);
qrValid = false;
setShareIntent();
if (isLoaded)
tvQrCode.setVisibility(View.VISIBLE);
}
}
void setQR(Bitmap qr) {
qrCode.setImageBitmap(qr);
ivQrCode.setImageBitmap(qr);
qrValid = true;
setShareIntent();
tvQrCode.setVisibility(View.GONE);
Helper.hideKeyboard(getActivity());
etDummy.requestFocus();
}
@Override
@@ -392,7 +479,7 @@ public class ReceiveFragment extends Fragment {
return;
}
bcData = new BarcodeData(BarcodeData.Asset.XMR, address, null, notes, xmrAmount);
int size = Math.min(qrCode.getHeight(), qrCode.getWidth());
int size = Math.max(ivQrCode.getWidth(), ivQrCode.getHeight());
Bitmap qr = generate(bcData.getUriString(), size, size);
if (qr != null) {
setQR(qr);
@@ -422,8 +509,8 @@ public class ReceiveFragment extends Fragment {
Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.RGB_565);
bitmap = addLogo(bitmap);
return bitmap;
} catch (WriterException e) {
e.printStackTrace();
} catch (WriterException ex) {
Timber.e(ex);
}
return null;
}

View File

@@ -31,7 +31,7 @@ public abstract class SecureActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
// set FLAG_SECURE to prevent screenshots in Release Mode
if (!BuildConfig.DEBUG && !BuildConfig.FLAVOR_type.equals("alpha")) {
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
}
}

View File

@@ -47,6 +47,7 @@ import android.widget.Toast;
import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.data.UserNotes;
import com.m2049r.xmrwallet.dialog.CreditsFragment;
import com.m2049r.xmrwallet.dialog.HelpFragment;
import com.m2049r.xmrwallet.fragment.send.SendAddressWizardFragment;
@@ -59,7 +60,6 @@ import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.WalletService;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
import com.m2049r.xmrwallet.data.UserNotes;
import com.m2049r.xmrwallet.widget.Toolbar;
import java.util.ArrayList;
@@ -81,6 +81,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
public static final String REQUEST_PW = "pw";
public static final String REQUEST_FINGERPRINT_USED = "fingerprint";
public static final String REQUEST_STREETMODE = "streetmode";
public static final String REQUEST_URI = "uri";
private NavigationView accountsView;
private DrawerLayout drawer;
@@ -92,6 +93,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
private String password;
private String uri = null;
private long streetMode = 0;
@Override
@@ -191,6 +194,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
// we can set the streetmode height AFTER opening the wallet
requestStreetMode = extras.getBoolean(REQUEST_STREETMODE);
password = extras.getString(REQUEST_PW);
uri = extras.getString(REQUEST_URI);
connectWalletService(walletId, password);
} else {
finish();
@@ -512,7 +516,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
@Override
public void onSendRequest() {
replaceFragment(new SendFragment(), null, null);
replaceFragment(SendFragment.newInstance(uri), null, null);
uri = null; // only use uri once
}
@Override

View File

@@ -67,7 +67,7 @@ public class HelpFragment extends DialogFragment {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view);
builder.setNegativeButton(R.string.about_close,
builder.setNegativeButton(R.string.help_ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {

View File

@@ -22,11 +22,11 @@ import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.view.WindowManager;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.R;
import java.util.Locale;
@@ -78,6 +78,11 @@ public class ProgressDialog extends AlertDialog {
}
super.onCreate(savedInstanceState);
// set FLAG_SECURE to prevent screenshots in Release Mode
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
}
public void setProgress(int value, int max) {

View File

@@ -38,15 +38,16 @@ import android.widget.EditText;
import com.m2049r.xmrwallet.OnBackPressedListener;
import com.m2049r.xmrwallet.OnUriScannedListener;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.WalletActivity;
import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.PendingTx;
import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.data.TxDataBtc;
import com.m2049r.xmrwallet.data.UserNotes;
import com.m2049r.xmrwallet.layout.SpendViewPager;
import com.m2049r.xmrwallet.model.PendingTransaction;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.Notice;
import com.m2049r.xmrwallet.data.UserNotes;
import com.m2049r.xmrwallet.widget.DotBar;
import com.m2049r.xmrwallet.widget.Toolbar;
@@ -104,6 +105,14 @@ public class SendFragment extends Fragment
static private int MAX_FALLBACK = Integer.MAX_VALUE;
public static SendFragment newInstance(String uri) {
SendFragment f = new SendFragment();
Bundle args = new Bundle();
args.putString(WalletActivity.REQUEST_URI, uri);
f.setArguments(args);
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@@ -187,6 +196,16 @@ public class SendFragment extends Fragment
etDummy.requestFocus();
Helper.hideKeyboard(getActivity());
Bundle args = getArguments();
if (args != null) {
String uri = args.getString(WalletActivity.REQUEST_URI);
Timber.d("URI: %s", uri);
if (uri != null) {
barcodeData = BarcodeData.fromQrCode(uri);
Timber.d("barcodeData: %s", barcodeData != null ? barcodeData.toString() : "null");
}
}
return view;
}

View File

@@ -6,7 +6,6 @@ import android.os.Looper;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.dialog.ProgressDialog;
import com.m2049r.xmrwallet.model.WalletManager;
import timber.log.Timber;

View File

@@ -587,6 +587,11 @@ public class Helper {
}
});
// set FLAG_SECURE to prevent screenshots in Release Mode
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
openDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
Helper.showKeyboard(openDialog);
openDialog.show();
}

View File

@@ -244,32 +244,48 @@ public class KeyStoreHelper {
Timber.d("M Keys created");
}
private static KeyStore.PrivateKeyEntry getPrivateKeyEntry(String alias) {
private static PrivateKey getPrivateKey(String alias) {
try {
KeyStore ks = KeyStore
.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
ks.load(null);
KeyStore.Entry entry = ks.getEntry(alias, null);
//KeyStore.Entry entry = ks.getEntry(alias, null);
PrivateKey privateKey = (PrivateKey) ks.getKey(alias, null);
if (entry == null) {
if (privateKey == null) {
Timber.w("No key found under alias: %s", alias);
return null;
}
if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
Timber.w("Not an instance of a PrivateKeyEntry");
return null;
}
return (KeyStore.PrivateKeyEntry) entry;
return privateKey;
} catch (IOException | NoSuchAlgorithmException | CertificateException
| UnrecoverableEntryException | KeyStoreException ex) {
throw new IllegalStateException(ex);
}
}
private static PublicKey getPublicKey(String alias) {
try {
KeyStore ks = KeyStore
.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
ks.load(null);
PublicKey publicKey = ks.getCertificate(alias).getPublicKey();
if (publicKey == null) {
Timber.w("No public key");
return null;
}
return publicKey;
} catch (IOException | NoSuchAlgorithmException | CertificateException
| KeyStoreException ex) {
throw new IllegalStateException(ex);
}
}
private static byte[] encrypt(String alias, byte[] data) {
try {
PublicKey publicKey = getPrivateKeyEntry(alias).getCertificate().getPublicKey();
PublicKey publicKey = getPublicKey(alias);
Cipher cipher = Cipher.getInstance(SecurityConstants.CIPHER_RSA_ECB_PKCS1);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
@@ -283,9 +299,8 @@ public class KeyStoreHelper {
private static byte[] decrypt(String alias, byte[] data) {
try {
KeyStore.PrivateKeyEntry pke = getPrivateKeyEntry(alias);
if (pke == null) return null;
PrivateKey privateKey = pke.getPrivateKey();
PrivateKey privateKey = getPrivateKey(alias);
if (privateKey == null) return null;
Cipher cipher = Cipher.getInstance(SecurityConstants.CIPHER_RSA_ECB_PKCS1);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
@@ -306,41 +321,14 @@ public class KeyStoreHelper {
*/
private static byte[] signData(String alias, byte[] data) throws NoSuchAlgorithmException,
InvalidKeyException, SignatureException {
KeyStore.PrivateKeyEntry pke = getPrivateKeyEntry(alias);
if (pke == null) return null;
PrivateKey privateKey = getPrivateKeyEntry(alias).getPrivateKey();
PrivateKey privateKey = getPrivateKey(alias);
if (privateKey == null) return null;
Signature s = Signature.getInstance(SecurityConstants.SIGNATURE_SHA256withRSA);
s.initSign(privateKey);
s.update(data);
return s.sign();
}
/**
* Given some data and a signature, uses the key pair stored in the Android
* Key Store to verify that the data was signed by this application, using
* that key pair.
*
* @param data The data to be verified.
* @param signature The signature provided for the data.
* @return A boolean value telling you whether the signature is valid or
* not.
*/
private static boolean verifyData(String alias, byte[] data, byte[] signature)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
// Make sure the signature string exists
if (signature == null) {
Timber.w("Invalid signature.");
return false;
}
KeyStore.PrivateKeyEntry keyEntry = getPrivateKeyEntry(alias);
Signature s = Signature.getInstance(SecurityConstants.SIGNATURE_SHA256withRSA);
s.initVerify(keyEntry.getCertificate());
s.update(data);
return s.verify(signature);
}
public interface SecurityConstants {
String KEYSTORE_PROVIDER_ANDROID_KEYSTORE = "AndroidKeyStore";
String TYPE_RSA = "RSA";

View File

@@ -100,6 +100,7 @@ public class RestoreHeight {
blockheight.put("2018-12-01", 1716687L);
blockheight.put("2019-01-01", 1738923L);
blockheight.put("2019-02-01", 1761435L);
blockheight.put("2019-03-01", 1781681L);
}
public long getHeight(String date) {

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp">
@@ -90,7 +89,7 @@
android:layout_height="wrap_content"
android:hint="@string/generate_mnemonic_hint"
android:imeOptions="actionNext"
android:inputType="textMultiLine"
android:inputType="textMultiLine|textVisiblePassword"
android:textAlignment="textStart" />
</android.support.design.widget.TextInputLayout>

View File

@@ -79,9 +79,9 @@
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:padding="12dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center"
android:padding="12dp"
android:src="@drawable/ic_search_orange_24dp" />
</RelativeLayout>
@@ -104,18 +104,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
<ImageView
android:id="@+id/ivGunther"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:fillViewport="true">
<ImageView
android:id="@+id/ivGunther"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:padding="48dp" />
</ScrollView>
android:adjustViewBounds="true"
android:layout_gravity="center"
android:padding="48dp" />
<android.support.v7.widget.RecyclerView xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list"

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_item_share"
android:title="Share"
app:actionProviderClass="android.support.v7.widget.ShareActionProvider"
app:showAsAction="ifRoom" />
</menu>

View File

@@ -289,4 +289,17 @@
]]></string>
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

View File

@@ -274,4 +274,17 @@
]]></string>
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="about_close">Fermi</string>
<string name="about_whoami">Mi estas monerujo</string>
<string name="about_version">Versio %1$s (%2$d)</string>
<string name="credits_text"><![CDATA[
<b>Agnoskoj</b>
<br/>
m2049r, baltsar777, anhdres, keejef,
rehrar, EarlOfEgo, ErCiccione kaj aliaj.
<br/><br/>
<a href="https://monerujo.io/">monerujo.io</a>
]]></string>
<string name="privacy_policy"><![CDATA[
<h1>Privateca politiko</h1>
<p>Tiu paĝo informas vin pri nia politiko rilate al la kolektado, uzado
kaj rivelado de personaj informoj kiujn ni ricevas de uzantoj de la
aplikaĵo. (monerujo: Monero Wallet).</p>
<p>Uzante la aplikaĵon, vi akceptas la kolektadon kaj uzon de informoj
kongrue al tiu politiko.</p>
<h2>Kolektitaj datumoj</h2>
<p>Persona datumo estas ĉiu ajn datumo kiu povas identigi personon.<p>
<p>Monero-ŝlosiloj kaj publikaj adresoj kolektiĝas kaj traktiĝas de la aplikaĵo
lokale, por la celo trakti transakciojn, kaj sendiĝas sur la Monero-reto je ĉifrita
formo.</p>
<p>Aliaj personaj datumoj ne kolektiĝas de la aplikaĵo.</p>
<p>Se vi uzas la opcian funkcionon, kiu permesas nombrumi vian pagon je alia valuto (ekz. dolaroj),
monerujo informpetos pri la kurzo per la publika interfaco de coinmarketcap.com.
Vidu ilian privatecan politikon je https://coinmarketcap.com/privacy por detaloj pri
kiel la datumo de viaj petoj kolektiĝos.</p>
<p>Se vi uzas la aplikaĵon por pagi al Bitmono-adresoj, vi uzos la XMR.TO-servon.
Vidu ilian privatecan politikon je https://xmr.to/ por detaloj. Monerujo sendos al ili la
BTC-ricevontadreson kaj kvanton. Via IP-adreso ankaŭ kolekteblos.</p>
<h2>Permesoj de la aplikaĵo</h2>
<ul>
<li>INTERRETO : Konekti kun la Monero-reto per noda demono</li>
<li>LEGI_EKSTERAJN_MEMORILOJN : Legi la monujdosierojn kiuj konserviĝas en la aparato</li>
<li>SKRIBI_EKSTERAJN_MEMORILOJN : Skribi la monujdosierojn kiuj konserviĝas en la aparato</li>
<li>LASI_VEKA : Lasi la aparaton veka dum la sinkronizado</li>
<li>FILMILO : Skani QR-kodojn por ricevi Monerojn</li>
</ul>
<h2>Ŝanĝoj de la privateca politiko</h2>
<p>Ni eble ĝisdatigos tiun privatecan politikon de temp\' al tempo. Ni
sciigos vin pri ĉiu ŝanĝo tiel : ni sendos la novan privatecan politikon en la
aplikaĵon kaj sur la retejo (www.monerujo.io)
Ni konsilas al vi, ke vi regule gvatu tiun dokumenton kaze de ŝanĝoj.
<p>Tiu privateca politiko ĝisdatiĝis lastfoje la 10an de novembro 2017.
</p>
<h2>Kontaktu nin</h2>
<p>Se vi havas ian demandon pri nia privateca politiko,
aŭ pri kiel viaj datumoj kolektiĝas kaj traktiĝas,
kontaktu retpoŝte privacy@monerujo.io.
</p>
]]></string>
</resources>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -314,4 +314,17 @@
]]></string>
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

View File

@@ -306,4 +306,17 @@
]]></string>
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

View File

@@ -311,4 +311,17 @@
]]></string>
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

View File

@@ -296,4 +296,17 @@
]]></string>
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

View File

@@ -293,4 +293,17 @@
]]></string>
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

View File

@@ -429,4 +429,17 @@
]]></string>
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

View File

@@ -294,4 +294,17 @@
]]></string>
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

View File

@@ -222,4 +222,17 @@
]]></string>
<!-- Note for translators: new/changed text also in help_send -->
<string name="help_uri"><![CDATA[
<h1>Using a payment link</h1>
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
<p>
1. Open the wallet you want to spend from<br>
2. Wait until the wallet is synced &amp; the "Give" button appears<br>
3. Touch the "Give" button
</p>
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
]]></string>
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
</resources>

Some files were not shown because too many files have changed in this diff Show More