1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-10 05:40:51 +02:00

Compare commits

..

19 Commits

Author SHA1 Message Date
m2049r
028057a672 bump version (#519) 2019-01-14 12:52:28 +01:00
TheFuzzStone
909ff8ca5e Ukranian translation for Monerujo (#517)
* Ukranian translation

* Update for Russian language (fixed small typos)
2019-01-12 19:56:59 +01:00
m2049r
ffd61e4495 remove getErrorString method (#516) 2019-01-11 19:24:33 +01:00
m2049r
003dee382e Merge pull request #515 from m2049r/fix_license
SwipeableRecyclerView license
2019-01-11 19:23:56 +01:00
m2049r
be0498c67d SwipeableRecyclerView license 2019-01-11 19:23:25 +01:00
m2049r
06227a4a83 Merge pull request #514 from m2049r/feature_dismissTx
Allow swipe-to-dismiss transactions in street mode
2019-01-10 19:33:26 +01:00
m2049r
4409087bd0 update dependencies 2019-01-10 19:31:34 +01:00
m2049r
965e52d8a5 allow to dismiss tx in streetmode 2019-01-10 19:31:15 +01:00
m2049r
beba0f497b Fix bech32 (#513)
* fix bech32 recognition

* bump version
2019-01-09 20:54:14 +01:00
m2049r
9d1827ff0d show current node (#511)
& bump version
2019-01-08 22:13:25 +01:00
m2049r
c04b192753 keep node once found (#510) 2019-01-06 10:57:25 +01:00
m2049r
888b5edaec height for jan19 (#509) 2019-01-06 09:56:00 +01:00
netrik182
5ee5a81926 updated pt-BR translation help and node strings (#491)
* updated pt-BR translation for #440

* update help.xml after review

* update strings.xml after review

* update help.xml after further peer review
2019-01-05 13:42:49 +01:00
m2049r
c4e361a873 allow bech32 segwit btc addresses (#508) 2019-01-05 13:42:22 +01:00
m2049r
dba6cb057e add restore height for december (#502) 2018-12-23 08:29:21 +01:00
m2049r
9e1167c5b9 read unsigned types & read payload_data (top_version...) (#501) 2018-12-23 08:12:50 +01:00
Hans
12546a1ade [Estonian] Some additional translations (#497) 2018-12-23 07:48:20 +01:00
BlackLotus64
e9313bc235 ES Translation of strings and help v2 (#490) 2018-12-08 18:26:20 +01:00
m2049r
7e9bf84640 tweaks to barcode/tag reading (#494)
- deal with empty payment_id
- use btc message as description
- BarcodeData is final
2018-12-02 10:23:07 +01:00
31 changed files with 1319 additions and 342 deletions

View File

@@ -7,8 +7,8 @@ android {
applicationId "com.m2049r.xmrwallet" applicationId "com.m2049r.xmrwallet"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 28
versionCode 160 versionCode 164
versionName "1.10.10 'Node-O-matiC'" versionName "1.10.14 'Node-O-matiC'"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild { externalNativeBuild {
@@ -113,10 +113,12 @@ dependencies {
implementation 'dnsjava:dnsjava:2.1.8' implementation 'dnsjava:dnsjava:2.1.8'
implementation 'org.jitsi:dnssecjava:1.1.3' implementation 'org.jitsi:dnssecjava:1.1.3'
implementation 'org.slf4j:slf4j-nop:1.7.25' implementation 'org.slf4j:slf4j-nop:1.7.25'
implementation 'com.github.brnunes:swipeablerecyclerview:1.0.2'
testImplementation "junit:junit:$rootProject.ext.junitVersion" testImplementation "junit:junit:$rootProject.ext.junitVersion"
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion" testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion" testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
testImplementation 'org.json:json:20140107' testImplementation 'org.json:json:20180813'
testImplementation 'net.jodah:concurrentunit:0.4.2' testImplementation 'net.jodah:concurrentunit:0.4.4'
} }

View File

@@ -43,6 +43,9 @@ Copyright (c) 2014 Dushyanth Maguluru
<h3>AndroidLicensesPage (https://github.com/adamsp/AndroidLicensesPage)</h3> <h3>AndroidLicensesPage (https://github.com/adamsp/AndroidLicensesPage)</h3>
Copyright (c) 2013 Adam Speakman Copyright (c) 2013 Adam Speakman
<h3>SwipeableRecyclerView (https://github.com/brnunes/SwipeableRecyclerView)</h3>
Copyright (c) 2015 Bruno R. Nunes
<h3>Apache License, Version 2.0, January 2004</h3> <h3>Apache License, Version 2.0, January 2004</h3>
http://www.apache.org/licenses/<br/> http://www.apache.org/licenses/<br/>
<br/> <br/>

View File

@@ -442,12 +442,6 @@ Java_com_m2049r_xmrwallet_model_WalletManager_findWallets(JNIEnv *env, jobject i
return cpp2java(env, walletPaths); return cpp2java(env, walletPaths);
} }
JNIEXPORT jstring JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_getErrorString(JNIEnv *env, jobject instance) {
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
return env->NewStringUTF(wallet->errorString().c_str());
}
//TODO virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0; //TODO virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0;
JNIEXPORT void JNICALL JNIEXPORT void JNICALL

View File

@@ -18,7 +18,6 @@ package com.m2049r.levin.scanner;
import com.m2049r.xmrwallet.data.NodeInfo; import com.m2049r.xmrwallet.data.NodeInfo;
import java.net.InetSocketAddress;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
@@ -176,9 +175,9 @@ public class Dispatcher implements PeerRetriever.OnGetPeers {
} }
private void retrievePeers(PeerRetriever peer) { private void retrievePeers(PeerRetriever peer) {
for (InetSocketAddress socketAddress : peer.getPeers()) { for (LevinPeer levinPeer : peer.getPeers()) {
if (getMorePeers()) if (getMorePeers())
retrievePeer(new NodeInfo(socketAddress)); retrievePeer(new NodeInfo(levinPeer));
else else
break; break;
} }

View File

@@ -0,0 +1,23 @@
package com.m2049r.levin.scanner;
import java.net.InetAddress;
import java.net.InetSocketAddress;
public class LevinPeer {
final public InetSocketAddress socketAddress;
final public int version;
final public long height;
final public String top;
public InetSocketAddress getSocketAddress() {
return socketAddress;
}
LevinPeer(InetAddress address, int port, int version, long height, String top) {
this.socketAddress = new InetSocketAddress(address, port);
this.version = version;
this.height = height;
this.top = top;
}
}

View File

@@ -28,7 +28,6 @@ import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@@ -45,7 +44,7 @@ public class PeerRetriever implements Callable<PeerRetriever> {
static final private byte[] HANDSHAKE = handshakeRequest().asByteArray(); static final private byte[] HANDSHAKE = handshakeRequest().asByteArray();
static final private byte[] FLAGS_RESP = flagsResponse().asByteArray(); static final private byte[] FLAGS_RESP = flagsResponse().asByteArray();
final private List<InetSocketAddress> peers = new ArrayList<>(); final private List<LevinPeer> peers = new ArrayList<>();
private NodeInfo nodeInfo; private NodeInfo nodeInfo;
private OnGetPeers onGetPeersCallback; private OnGetPeers onGetPeersCallback;
@@ -67,7 +66,7 @@ public class PeerRetriever implements Callable<PeerRetriever> {
return !peers.isEmpty(); return !peers.isEmpty();
} }
public List<InetSocketAddress> getPeers() { public List<LevinPeer> getPeers() {
return peers; return peers;
} }
@@ -107,12 +106,18 @@ public class PeerRetriever implements Callable<PeerRetriever> {
} }
private void readAddressList(Section section) { private void readAddressList(Section section) {
Section data = (Section) section.get("payload_data");
int topVersion = (Integer) data.get("top_version");
long currentHeight = (Long) data.get("current_height");
String topId = HexHelper.bytesToHex((byte[]) data.get("top_id"));
Timber.d("PAYLOAD_DATA %d/%d/%s", topVersion, currentHeight, topId);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<Section> peerList = (List<Section>) section.get("local_peerlist_new"); List<Section> peerList = (List<Section>) section.get("local_peerlist_new");
if (peerList != null) { if (peerList != null) {
for (Section peer : peerList) { for (Section peer : peerList) {
Section adr = (Section) peer.get("adr"); Section adr = (Section) peer.get("adr");
Byte type = (Byte) adr.get("type"); Integer type = (Integer) adr.get("type");
if ((type == null) || (type != 1)) if ((type == null) || (type != 1))
continue; continue;
Section addr = (Section) adr.get("addr"); Section addr = (Section) adr.get("addr");
@@ -121,7 +126,7 @@ public class PeerRetriever implements Callable<PeerRetriever> {
Integer ip = (Integer) addr.get("m_ip"); Integer ip = (Integer) addr.get("m_ip");
if (ip == null) if (ip == null)
continue; continue;
Short sport = (Short) addr.get("m_port"); Integer sport = (Integer) addr.get("m_port");
if (sport == null) if (sport == null)
continue; continue;
int port = sport; int port = sport;
@@ -133,7 +138,7 @@ public class PeerRetriever implements Callable<PeerRetriever> {
&& !inet.isLoopbackAddress() && !inet.isLoopbackAddress()
&& !inet.isMulticastAddress() && !inet.isMulticastAddress()
&& !inet.isLinkLocalAddress()) { && !inet.isLinkLocalAddress()) {
peers.add(new InetSocketAddress(inet, port)); peers.add(new LevinPeer(inet, port, topVersion, currentHeight, topId));
} }
} }
} }

View File

@@ -83,9 +83,11 @@ public class LevinReader {
case Section.SERIALIZE_TYPE_INT32: case Section.SERIALIZE_TYPE_INT32:
return in.readInt(); return in.readInt();
case Section.SERIALIZE_TYPE_UINT16: case Section.SERIALIZE_TYPE_UINT16:
return in.readUnsignedShort();
case Section.SERIALIZE_TYPE_INT16: case Section.SERIALIZE_TYPE_INT16:
return in.readShort(); return in.readShort();
case Section.SERIALIZE_TYPE_UINT8: case Section.SERIALIZE_TYPE_UINT8:
return in.readUnsignedByte();
case Section.SERIALIZE_TYPE_INT8: case Section.SERIALIZE_TYPE_INT8:
return in.readByte(); return in.readByte();
case Section.SERIALIZE_TYPE_OBJECT: case Section.SERIALIZE_TYPE_OBJECT:

View File

@@ -92,6 +92,11 @@ public class LoginActivity extends BaseActivity
Set<NodeInfo> favouriteNodes = new HashSet<>(); Set<NodeInfo> favouriteNodes = new HashSet<>();
@Override
public NodeInfo getNode() {
return node;
}
@Override @Override
public void setNode(NodeInfo node) { public void setNode(NodeInfo node) {
if ((node != null) && (node.getNetworkType() != WalletManager.getInstance().getNetworkType())) if ((node != null) && (node.getNetworkType() != WalletManager.getInstance().getNetworkType()))

View File

@@ -99,6 +99,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
void setNode(NodeInfo node); void setNode(NodeInfo node);
NodeInfo getNode();
Set<NodeInfo> getFavouriteNodes(); Set<NodeInfo> getFavouriteNodes();
boolean hasLedger(); boolean hasLedger();
@@ -128,7 +130,11 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
activityCallback.setTitle(null); activityCallback.setTitle(null);
activityCallback.setToolbarButton(Toolbar.BUTTON_CREDITS); activityCallback.setToolbarButton(Toolbar.BUTTON_CREDITS);
activityCallback.showNet(); activityCallback.showNet();
findBestNode(); NodeInfo node = activityCallback.getNode();
if (node == null)
findBestNode();
else
showNode(node);
} }
@Override @Override
@@ -181,7 +187,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (activityCallback.getFavouriteNodes().isEmpty()) if (activityCallback.getFavouriteNodes().isEmpty())
activityCallback.onNodePrefs(); startNodePrefs();
else else
findBestNode(); findBestNode();
} }
@@ -191,8 +197,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
view.findViewById(R.id.ibOption).setOnClickListener(new View.OnClickListener() { view.findViewById(R.id.ibOption).setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (activityCallback != null) startNodePrefs();
activityCallback.onNodePrefs();
} }
}); });
@@ -476,4 +481,9 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
tvNodeAddress.setText(nodeInfo.getAddress()); tvNodeAddress.setText(nodeInfo.getAddress());
tvNodeAddress.setVisibility(View.VISIBLE); tvNodeAddress.setVisibility(View.VISIBLE);
} }
private void startNodePrefs() {
activityCallback.setNode(null);
activityCallback.onNodePrefs();
}
} }

View File

@@ -144,6 +144,9 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
} else { } else {
streetMode = 0; streetMode = 0;
} }
final WalletFragment walletFragment = (WalletFragment)
getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName());
if (walletFragment != null) walletFragment.resetDismissedTransactions();
updateAccountsBalance(); updateAccountsBalance();
forceUpdate(); forceUpdate();
} }
@@ -286,7 +289,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
showNet(); showNet();
} }
invalidateOptionsMenu(); invalidateOptionsMenu();
} }
private void onEnableStreetMode() { private void onEnableStreetMode() {

View File

@@ -38,6 +38,7 @@ import android.widget.ProgressBar;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import com.github.brnunes.swipeablerecyclerview.SwipeableRecyclerViewTouchListener;
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter; import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
import com.m2049r.xmrwallet.model.TransactionInfo; import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
@@ -73,6 +74,12 @@ public class WalletFragment extends Fragment
private Spinner sCurrency; private Spinner sCurrency;
private List<String> dismissedTransactions = new ArrayList<>();
public void resetDismissedTransactions() {
dismissedTransactions.clear();
}
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -116,9 +123,44 @@ public class WalletFragment extends Fragment
RecyclerView recyclerView = view.findViewById(R.id.list); RecyclerView recyclerView = view.findViewById(R.id.list);
this.adapter = new TransactionInfoAdapter(getActivity(), this); adapter = new TransactionInfoAdapter(getActivity(), this);
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
SwipeableRecyclerViewTouchListener swipeTouchListener =
new SwipeableRecyclerViewTouchListener(recyclerView,
new SwipeableRecyclerViewTouchListener.SwipeListener() {
@Override
public boolean canSwipeLeft(int position) {
return activityCallback.isStreetMode();
}
@Override
public boolean canSwipeRight(int position) {
return activityCallback.isStreetMode();
}
@Override
public void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
dismissedTransactions.add(adapter.getItem(position).hash);
adapter.removeItem(position);
}
adapter.notifyDataSetChanged();
}
@Override
public void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
dismissedTransactions.add(adapter.getItem(position).hash);
adapter.removeItem(position);
}
adapter.notifyDataSetChanged();
}
});
recyclerView.addOnItemTouchListener(swipeTouchListener);
bSend.setOnClickListener(new View.OnClickListener() { bSend.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@@ -294,7 +336,9 @@ public class WalletFragment extends Fragment
Timber.d("StreetHeight=%d", streetHeight); Timber.d("StreetHeight=%d", streetHeight);
for (TransactionInfo info : wallet.getHistory().getAll()) { for (TransactionInfo info : wallet.getHistory().getAll()) {
Timber.d("TxHeight=%d", info.blockheight); Timber.d("TxHeight=%d", info.blockheight);
if (info.isPending || (info.blockheight >= streetHeight)) list.add(info); if ((info.isPending || (info.blockheight >= streetHeight))
&& !dismissedTransactions.contains(info.hash))
list.add(info);
} }
adapter.setInfos(list); adapter.setInfos(list);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();

View File

@@ -38,6 +38,7 @@ public class BarcodeData {
public static final String OA_BTC_ASSET = "btc"; public static final String OA_BTC_ASSET = "btc";
static final String BTC_SCHEME = "bitcoin:"; static final String BTC_SCHEME = "bitcoin:";
static final String BTC_DESCRIPTION = "message";
static final String BTC_AMOUNT = "amount"; static final String BTC_AMOUNT = "amount";
public enum Asset { public enum Asset {
@@ -50,28 +51,32 @@ public class BarcodeData {
OA_DNSSEC OA_DNSSEC
} }
public Asset asset = null; final public Asset asset;
public String addressName = null; final public String address;
public String address = null; final public String addressName;
public String paymentId = null; final public String paymentId;
public String amount = null; final public String amount;
public String description = null; final public String description;
public Security security = Security.NORMAL; final public Security security;
public BarcodeData(String uri) {
this.asset = asset;
this.address = address;
}
public BarcodeData(Asset asset, String address) { public BarcodeData(Asset asset, String address) {
this.asset = asset; this.asset = asset;
this.address = address; this.address = address;
amount = null;
paymentId = null;
addressName = null;
description = null;
this.security = Security.NORMAL;
} }
public BarcodeData(Asset asset, String address, String amount) { public BarcodeData(Asset asset, String address, String amount) {
this.asset = asset; this.asset = asset;
this.address = address; this.address = address;
this.amount = amount; this.amount = amount;
paymentId = null;
addressName = null;
description = null;
this.security = Security.NORMAL;
} }
public BarcodeData(Asset asset, String address, String paymentId, String amount) { public BarcodeData(Asset asset, String address, String paymentId, String amount) {
@@ -79,6 +84,9 @@ public class BarcodeData {
this.address = address; this.address = address;
this.paymentId = paymentId; this.paymentId = paymentId;
this.amount = amount; this.amount = amount;
addressName = null;
description = null;
this.security = Security.NORMAL;
} }
public BarcodeData(Asset asset, String address, String paymentId, String description, String amount) { public BarcodeData(Asset asset, String address, String paymentId, String description, String amount) {
@@ -87,14 +95,18 @@ public class BarcodeData {
this.paymentId = paymentId; this.paymentId = paymentId;
this.description = description; this.description = description;
this.amount = amount; this.amount = amount;
addressName = null;
this.security = Security.NORMAL;
} }
public void setAddressName(String name) { public BarcodeData(Asset asset, String address, String addressName, String paymentId, String description, String amount, Security sec) {
addressName = name; this.asset = asset;
} this.address = address;
this.addressName = addressName;
public void setSecurity(Security security) { this.paymentId = paymentId;
this.security = security; this.description = description;
this.amount = amount;
this.security = sec;
} }
public Uri getUri() { public Uri getUri() {
@@ -140,7 +152,7 @@ public class BarcodeData {
} }
// check for OpenAlias // check for OpenAlias
if (bcData == null) { if (bcData == null) {
bcData = parseOpenAlias(qrCode); bcData = parseOpenAlias(qrCode, false);
} }
return bcData; return bcData;
} }
@@ -175,7 +187,11 @@ public class BarcodeData {
} }
} }
String address = monero.getPath(); String address = monero.getPath();
String paymentId = parms.get(XMR_PAYMENTID); String paymentId = parms.get(XMR_PAYMENTID);
// deal with empty payment_id created by non-spec-conforming apps
if ((paymentId != null) && paymentId.isEmpty()) paymentId = null;
String description = parms.get(XMR_DESCRIPTION); String description = parms.get(XMR_DESCRIPTION);
String amount = parms.get(XMR_AMOUNT); String amount = parms.get(XMR_AMOUNT);
if (amount != null) { if (amount != null) {
@@ -235,6 +251,7 @@ public class BarcodeData {
} }
} }
String address = bitcoin.getPath(); String address = bitcoin.getPath();
String description = parms.get(BTC_DESCRIPTION);
String amount = parms.get(BTC_AMOUNT); String amount = parms.get(BTC_AMOUNT);
if (amount != null) { if (amount != null) {
try { try {
@@ -248,7 +265,7 @@ public class BarcodeData {
Timber.d("address invalid"); Timber.d("address invalid");
return null; return null;
} }
return new BarcodeData(BarcodeData.Asset.BTC, address, amount); return new BarcodeData(BarcodeData.Asset.BTC, address, null, description, amount);
} }
static public BarcodeData parseBitcoinNaked(String address) { static public BarcodeData parseBitcoinNaked(String address) {
@@ -264,7 +281,7 @@ public class BarcodeData {
return new BarcodeData(BarcodeData.Asset.BTC, address); return new BarcodeData(BarcodeData.Asset.BTC, address);
} }
static public BarcodeData parseOpenAlias(String oaString) { static public BarcodeData parseOpenAlias(String oaString, boolean dnssec) {
Timber.d("parseOpenAlias=%s", oaString); Timber.d("parseOpenAlias=%s", oaString);
if (oaString == null) return null; if (oaString == null) return null;
@@ -316,8 +333,8 @@ public class BarcodeData {
return null; return null;
} }
BarcodeData bc = new BarcodeData(asset, address, paymentId, description, amount); Security sec = dnssec ? BarcodeData.Security.OA_DNSSEC : BarcodeData.Security.OA_NO_DNSSEC;
bc.setAddressName(addressName);
return bc; return new BarcodeData(asset, address, addressName, paymentId, description, amount, sec);
} }
} }

View File

@@ -22,6 +22,7 @@ import com.burgstaller.okhttp.digest.CachingAuthenticator;
import com.burgstaller.okhttp.digest.Credentials; import com.burgstaller.okhttp.digest.Credentials;
import com.burgstaller.okhttp.digest.DigestAuthenticator; import com.burgstaller.okhttp.digest.DigestAuthenticator;
import com.m2049r.levin.scanner.Dispatcher; import com.m2049r.levin.scanner.Dispatcher;
import com.m2049r.levin.scanner.LevinPeer;
import com.m2049r.xmrwallet.util.OkHttpHelper; import com.m2049r.xmrwallet.util.OkHttpHelper;
import org.json.JSONException; import org.json.JSONException;
@@ -99,21 +100,18 @@ public class NodeInfo extends Node {
super(nodeString); super(nodeString);
} }
public NodeInfo(InetSocketAddress socketAddress) { public NodeInfo(LevinPeer levinPeer) {
super(socketAddress); super(levinPeer.getSocketAddress());
}
public NodeInfo(InetSocketAddress address) {
super(address);
} }
public NodeInfo() { public NodeInfo() {
super(); super();
} }
public NodeInfo(InetSocketAddress peerAddress, long height, int majorVersion, double respTime) {
super(peerAddress);
this.height = height;
this.majorVersion = majorVersion;
this.responseTime = respTime;
}
public long getHeight() { public long getHeight() {
return height; return height;
} }

View File

@@ -296,11 +296,8 @@ public class SendAddressWizardFragment extends SendWizardFragment {
} }
private boolean isBitcoinAddress() { private boolean isBitcoinAddress() {
String address = etAddress.getEditText().getText().toString(); final String address = etAddress.getEditText().getText().toString();
if ((address.length() >= 27) && (address.length() <= 35)) return BitcoinAddressValidator.validate(address);
return BitcoinAddressValidator.validate(address);
else
return false;
} }
private boolean checkPaymentId() { private boolean checkPaymentId() {

View File

@@ -91,7 +91,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
public void setInfos(List<TransactionInfo> data) { public void setInfos(List<TransactionInfo> data) {
// TODO do stuff with data so we can really recycle elements (i.e. add only new tx) // TODO do stuff with data so we can really recycle elements (i.e. add only new tx)
// as the TransactionInfo items are always recreated, we cannot recycle // as the TransactionInfo items are always recreated, we cannot recycle
this.infoItems.clear(); infoItems.clear();
if (data != null) { if (data != null) {
Timber.d("setInfos %s", data.size()); Timber.d("setInfos %s", data.size());
infoItems.addAll(data); infoItems.addAll(data);
@@ -102,6 +102,15 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void removeItem(int position) {
infoItems.remove(position);
notifyItemRemoved(position);
}
public TransactionInfo getItem(int position) {
return infoItems.get(position);
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
final ImageView ivTxType; final ImageView ivTxType;
final TextView tvAmount; final TextView tvAmount;

View File

@@ -264,8 +264,6 @@ public class WalletManager {
return wallets; return wallets;
} }
public native String getErrorString();
//TODO virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0; //TODO virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0;
private String daemonAddress = null; private String daemonAddress = null;

View File

@@ -16,12 +16,13 @@
package com.m2049r.xmrwallet.util; package com.m2049r.xmrwallet.util;
// based on https://rosettacode.org/wiki/Bitcoin/address_validation#Java // mostly based on https://rosettacode.org/wiki/Bitcoin/address_validation#Java
import com.m2049r.xmrwallet.model.NetworkType; import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.model.WalletManager;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays; import java.util.Arrays;
@@ -31,8 +32,9 @@ public class BitcoinAddressValidator {
private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
public static boolean validate(String addrress) { public static boolean validate(String addrress) {
return validate(addrress, boolean testnet = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet;
WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet); if (validate(addrress, testnet)) return true;
return validateBech32Segwit(addrress, testnet);
} }
public static boolean validate(String addrress, boolean testnet) { public static boolean validate(String addrress, boolean testnet) {
@@ -85,4 +87,112 @@ public class BitcoinAddressValidator {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
} }
//
// validate Bech32 segwit
// see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki for spec
//
private static final String DATA_CHARS = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
public static boolean validateBech32Segwit(String bech32, boolean testnet) {
if (!bech32.equals(bech32.toLowerCase()) && !bech32.equals(bech32.toUpperCase())) {
return false; // mixing upper and lower case not allowed
}
bech32 = bech32.toLowerCase();
if (testnet && !bech32.startsWith("tb1")) return false;
if (!testnet && !bech32.startsWith("bc1")) return false;
if ((bech32.length() < 14) || (bech32.length() > 74)) return false;
int mod = bech32.length() % 8;
if ((mod == 0) || (mod == 3) || (mod == 5)) return false;
int sep = -1;
final byte[] bytes = bech32.getBytes(StandardCharsets.US_ASCII);
for (int i = 0; i < bytes.length; i++) {
if ((bytes[i] < 33) || (bytes[i] > 126)) {
return false;
}
if (bytes[i] == 49) sep = i; // 49 := '1' in ASCII
}
if (sep != 2) return false; // bech32 always has len(hrp)==2
if (sep > bytes.length - 7) {
return false; // min 6 bytes data
}
if (bytes.length < 8) { // hrp{min}=1 + sep=1 + data{min}=6 := 8
return false; // too short
}
if (bytes.length > 90) {
return false; // too long
}
final byte[] hrp = Arrays.copyOfRange(bytes, 0, sep);
final byte[] data = Arrays.copyOfRange(bytes, sep + 1, bytes.length);
for (int i = 0; i < data.length; i++) {
int b = DATA_CHARS.indexOf(data[i]);
if (b < 0) return false; // invalid character
data[i] = (byte) b;
}
if (!validateBech32Data(data)) return false;
return verifyChecksum(hrp, data);
}
private static int polymod(byte[] values) {
final int[] GEN = {0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3};
int chk = 1;
for (byte v : values) {
byte b = (byte) (chk >> 25);
chk = ((chk & 0x1ffffff) << 5) ^ v;
for (int i = 0; i < 5; i++) {
chk ^= ((b >> i) & 1) == 1 ? GEN[i] : 0;
}
}
return chk;
}
private static byte[] hrpExpand(byte[] hrp) {
final byte[] expanded = new byte[(2 * hrp.length) + 1];
int i = 0;
for (int j = 0; j < hrp.length; j++) {
expanded[i++] = (byte) (hrp[j] >> 5);
}
expanded[i++] = 0;
for (int j = 0; j < hrp.length; j++) {
expanded[i++] = (byte) (hrp[j] & 0x1f);
}
return expanded;
}
private static boolean verifyChecksum(byte[] hrp, byte[] data) {
final byte[] hrpExpanded = hrpExpand(hrp);
final byte[] values = new byte[hrpExpanded.length + data.length];
System.arraycopy(hrpExpanded, 0, values, 0, hrpExpanded.length);
System.arraycopy(data, 0, values, hrpExpanded.length, data.length);
return (polymod(values) == 1);
}
private static boolean validateBech32Data(final byte[] data) {
if ((data[0] < 0) || (data[0] > 16)) return false; // witness version
final int programLength = data.length - 1 - 6; // 1-byte version at beginning & 6-byte checksum at end
// since we are coming from our own decoder, we don't need to verify data is 5-bit bytes
final int convertedSize = programLength * 5 / 8;
final int remainderSize = programLength * 5 % 8;
if ((convertedSize < 2) || (convertedSize > 40)) return false;
if ((data[0] == 0) && (convertedSize != 20) && (convertedSize != 32)) return false;
if (remainderSize >= 5) return false;
// ignore checksum at end and get last byte of program
if ((data[data.length - 1 - 6] & ((1 << remainderSize) - 1)) != 0) return false;
return true;
}
} }

View File

@@ -140,9 +140,8 @@ public class OpenAliasHelper {
if (success) { if (success) {
Map<BarcodeData.Asset, BarcodeData> dataMap = new HashMap<>(); Map<BarcodeData.Asset, BarcodeData> dataMap = new HashMap<>();
for (String txt : txts) { for (String txt : txts) {
BarcodeData bc = BarcodeData.parseOpenAlias(txt); BarcodeData bc = BarcodeData.parseOpenAlias(txt, dnssec);
if (bc != null) { if (bc != null) {
bc.setSecurity(dnssec ? BarcodeData.Security.OA_DNSSEC : BarcodeData.Security.OA_NO_DNSSEC);
if (!dataMap.containsKey(bc.asset)) { if (!dataMap.containsKey(bc.asset)) {
dataMap.put(bc.asset, bc); dataMap.put(bc.asset, bc);
} }

View File

@@ -97,6 +97,8 @@ public class RestoreHeight {
blockheight.put("2018-09-01", 1651347L); blockheight.put("2018-09-01", 1651347L);
blockheight.put("2018-10-01", 1673031L); blockheight.put("2018-10-01", 1673031L);
blockheight.put("2018-11-01", 1695128L); blockheight.put("2018-11-01", 1695128L);
blockheight.put("2018-12-01", 1716687L);
blockheight.put("2019-01-01", 1738923L);
} }
public long getHeight(String date) { public long getHeight(String date) {

View File

@@ -222,24 +222,24 @@
]]></string> ]]></string>
<string name="help_create_ledger"><![CDATA[ <string name="help_create_ledger"><![CDATA[
<h1>Create Wallet - Ledger</h1> <h1>Crear Monedero - Ledger</h1>
<p>You want to recover your wallet from your Ledger Nano S device.</p> <p>Deseas recuperar tu monedero desde tu dispositivo Ledger Nano S.</p>
<p>Your secret keys never leave the Ledger device, so you need it plugged in every <p>Tus claves secretas nunca dejan el dispositivo Ledger, así que lo necesitas conectado cada
time you want to access your wallet.</p> vez que deseas acceder a tu monedero.</p>
<p>Enter a unique wallet name and password. The password is used for securing your wallet data on the Android <p>Ingresa un nombre de monedero y contraseña únicos. La contraseña es usada para asegurar tu información del monedero en el dispositivo
device. Use a strong password - even better use a passphrase.</p> Android. Usa una contraseña fuerte - o mejor aún, usa una frase de contraseña.</p>
<p>Enter the block number of the first transaction used for this address in the <p>Ingresa el número del bloque de la primera transacción usada para esta dirección en el
field \"Restore Height\". You can also use a date in the format YYYY-MM-DD. If you are not sure, campo \"Altura de restaurado\". También puedes usar una fecha en formato AAAA-MM-DD. Si no estás seguro,
enter an approximate date/blockheight <em>before</em> you first used this wallet address.</p> ingresa una fecha o altura del bloque aproximada <em>anterior</em> a la primera vez que usaste esta dirección del monedero.</p>
]]></string> ]]></string>
<string name="help_wallet"><![CDATA[ <string name="help_wallet"><![CDATA[
<h1>El monedero</h1> <h1>El monedero</h1>
<h2>Street Mode</h2> <h2>Modo Público</h2>
<p>Street mode can be enabled/disabled in the menu or Gunther\'s head icon. In this mode, your <p>El Modo Público puede ser habilitado/deshabilitado en el menú o en el icono de Gunther\'s. En este modo, tu
balance is not shown on any screen so you can safely use your wallet on the street, a pub or balance no se muestra en ninguna pantalla para que puedas usar de manera segura tu monedero en la calle, un pub u
other public place. Previous transactions are also hidden. New transactions will be shown, so otro lugar público. Transacciones anteriores también se ocultan. Nuevas transacciones serán mostradas, para
you can see that you have sent/received sweet Moneroj!</p> que puedas ver que has enviado/recibido Moneroj.</p>
<h2>Escaneado</h2> <h2>Escaneado</h2>
Como a Monero le gusta mantener las cosas privadas, cada vez que abres una cartera de Como a Monero le gusta mantener las cosas privadas, cada vez que abres una cartera de
Monerujo es necesario escanear la cadena de bloques para ver si nuevos moneroj han sido Monerujo es necesario escanear la cadena de bloques para ver si nuevos moneroj han sido
@@ -257,51 +257,51 @@
]]></string> ]]></string>
<string name="help_node"><![CDATA[ <string name="help_node"><![CDATA[
<h1>Nodes</h1> <h1>Nodos</h1>
<h2>TL;DR</h2> <h2>TL;DR</h2>
<p>Refresh the nodes list by pulling down &amp; bookmark 3&#8211;5 nodes to allow Monerujo <p>Refresca la lista de nodos al mostrar los marcadores de nodos para permitir a Monerujo
to choose the best one for you!</p> elegir el mejor para ti.</p>
<h2>What&apos;s a Node?</h2> <h2>¿Qué es un Nodo?h2>
<p>Monerujo uses a Remote Node (sometimes also called Daemon) to communicate with <p>Monerujo usa un Nodo Remoto (algunas veces también llamado Daemon) para comunicarse con
the Monero Network without having to download and store a copy of the la red de Monero sin tener que descargar y almacenar una copia de la
whole blockchain itself.<p> cadena de bloques completa.<p>
<h2>Node List</h2> <h2>Lista de Nodos</h2>
<p>If the list is empty, you can either add new nodes manually or let Monerujo <p>Si la lista está vacía, puedes agregar nuevos nodos manualmente o dejar que Monerujo
scan the network for you. Or both. Read on&#8230;</p> escanee la red por ti. O ambos.</p>
<p>The node list shows all currently known nodes. Additionally, the timestamp <p>La lista de nodos muestra todos los nodos actualmente conocidos. Adicionalmente, la marca de tiempo
of the latest block known to each node is shown under the node name. An icon del último bloque conocido para cada nodo se muestra bajo el nombre del nodo. Un icono
representing the node&apos;s response behaviour representando el comportamiento de respuesta del nodo
(which indicates the level of connectivity to be expected) (el cual indica el nivel de conectividad esperado)
is shown next to each node.</p> es mostrado seguido de cada nodo.</p>
<p>Any node in the list can be bookmarked for later use. <p>Cualquier nodo en la lista puede ser marcado para un posterior uso.
Nodes which are not bookmarked will be forgotten.<p> Nodos que no sean marcados serán olvidados.<p>
<p>Monerujo will choose the optimal bookmarked node each time you use it. <p>Monerujo elegirá el nodo marcado óptimo cada vez que lo uses.
It does this by checking the blockheight (how up-to-date Esto lo hace revisando la altura del bloque (¿qué tan al día
is the node?) as well as the response behaviour (how fast does the node respond to requests?).</p> está el nodo?) así como el comportamiento de respuesta (¿qué tan rápido responde el nodo a solicitudes?).</p>
<p>The list is sorted by these characteristics, so the top node would be the one Monerujo <p>La lista se ordena por estas características, por lo tanto el primer nodo en la lista sería el que Monerujo
would choose right now. The bottom of the list would show very slow or unavailable nodes.</p> elegiría en ese momento. El final de la lista mostraría nodos muy lentos o no disponibles.</p>
<h2>Add a Node</h2> <h2>Agregar un Nodo</h2>
<p>By touching the &quot;Add Node&quot; button at the bottom, you will be asked to <p>Presionando en el botón &quot;Agregar Nodo&quot; en la parte inferior, se te pedirá que
enter the node details in the following dialog. ingreses los detalles del nodo en el siguiente cuadro de diálogo.
The &quot;Address&quot; is the hostname or IP-address of the node - this is the only La &quot;Dirección&quot; es el nombre del host o dirección IP del nodo - esta es la única
mandatory entry. entrada obligatoria.
Enter the &quot;Port&quot; if the node runs on a non-default port (e.g. 18089). Ingresa el &quot;Puerto&quot; si el nodo se ejecuta en un puerto que no es por defecto (e.g. 18089).
You can also optionally name the node, so you can identify it easier later on. Puedes también nombrar el nodo opcionalmente, para que puedas identificarlo después fácilmente.
Some nodes require credentials to use them. Enter the provided username &amp; Algunos nodos requieren credenciales para usarlos. Ingresa el nombre de usuario provisto &amp;
password in the appropriate fields. Now you can &quot;Test&quot; these setting. contraseña en los campos apropiados. Ahora puedes &quot;Verificar&quot; estos ajustes.
The &quot;Test Results&quot; will display the blockheight, response time and actual IP used. Los &quot;Resultados de la Prueba&quot; mostrarán la altura del bloque, tiempo de respuesta y dirección IP real usados.
The result may also be an error - usually because the hostname provided is El resultado puede ser también un error - usualmente porque el nombre de host provisto no
not reachable in a sensible amount of time or the credentials are incorrect. es alcanzable en una sensible cantidad de tiempo o las credenciales son incorrectas.
Or the hostname/port combination does not point to an actual Monero Node! O la combinación nombre de host/puerto no indican a un nodo de Monero real.
Once the test passes (no error) - you&apos;re set to press &quot;OK&quot; to save &amp; Una vez que la prueba sea exitosa (sin error) - estás listo para presionar &quot;OK&quot; para guardar &amp;
bookmark this node.</p> como marcador este nodo.</p>
<h2>Scan for Nodes</h2> <h2>Escanear por Nodos</h2>
<p>Additionally, you can scan the network for nodes. Monerujo will start <p>Adicionalmente, puedes escanear la red por nodos. Monerujo empezará
scanning the network for Remote Nodes on port 18089. It begins by asking your escaneando la red por Nodos Remotos con puerto 18089. Comienza preguntando tus
bookmarked nodes for other peers in the Monero P2P network and then continues nodos marcados por otros compañeros en la red P2P de Monero y después continúa
by asking those for their peers, and so on. If you have no bookmarked nodes preguntando por nodos a ellos por sus compañeros, y así. Si no tienes nodos marcados
(or they don&apos;t tell us about their peers), (o no nos comunican sobre sus compañeros),
Monerujo will go straight to the Monero seed nodes hardcoded into Monero. The Monerujo irá directo a los nodos semilla de Monero codificados en Monero. El
scan stops when it finds 10 remote nodes in total.</p> escaneo parará cuando encuentre 10 nodos remotos en total.</p>
]]></string> ]]></string>
</resources> </resources>

View File

@@ -281,75 +281,75 @@
<string name="accounts_new">Nueva cuenta agregada #%1$d</string> <string name="accounts_new">Nueva cuenta agregada #%1$d</string>
<string name="tx_account"># de cuenta</string> <string name="tx_account"># de cuenta</string>
<string name="send_sweepall">Send all confirmed funds in this account!</string> <string name="send_sweepall">¡Enviar todos los fondos confirmados en esta cuenta!</string>
<string name="tx_subaddress">Subaddress #%1$d</string> <string name="tx_subaddress">Subdirecciones #%1$d</string>
<string name="generate_address_label_sub">Public Subaddress #%1$d</string> <string name="generate_address_label_sub">Subdirecciones Públicas #%1$d</string>
<string name="menu_language">Language</string> <string name="menu_language">Lenguaje</string>
<string name="language_system_default">Use System Language</string> <string name="language_system_default">Usar Idioma del Sistema</string>
<string name="fab_restore_ledger">Restore from Ledger Nano S</string> <string name="fab_restore_ledger">Restaurar desde Ledger Nano S</string>
<string name="progress_ledger_progress">Communicating with Ledger</string> <string name="progress_ledger_progress">Comunicándose con Ledger</string>
<string name="progress_ledger_confirm">Confirmation on Ledger required!</string> <string name="progress_ledger_confirm">¡Confirmación en Ledger requerida!</string>
<string name="progress_ledger_lookahead">Retrieving subaddresses</string> <string name="progress_ledger_lookahead">Recuperando subdirecciones</string>
<string name="progress_ledger_verify">Verifying keys</string> <string name="progress_ledger_verify">Verificando claves</string>
<string name="progress_ledger_opentx">Doing crazy maths</string> <string name="progress_ledger_opentx">Realizando cálculos alocados</string>
<string name="progress_ledger_mlsag">Hashing stuff</string> <string name="progress_ledger_mlsag">Cosas de hash</string>
<string name="open_wallet_ledger_missing">Please (re)connect Ledger device</string> <string name="open_wallet_ledger_missing">Por favor (re)conecta el dispositivo Ledger</string>
<string name="accounts_progress_new">Creating account</string> <string name="accounts_progress_new">Creando cuenta</string>
<string name="toast_ledger_attached">%1$s attached</string> <string name="toast_ledger_attached">%1$s adjunto</string>
<string name="toast_ledger_detached">%1$s detached</string> <string name="toast_ledger_detached">%1$s separado</string>
<string name="progress_nfc_write">Writing Tag</string> <string name="progress_nfc_write">Escribiento Etiqueta</string>
<string name="nfc_write_failed">Writing Tag failed!</string> <string name="nfc_write_failed">¡Escritura de Etiqueta fallida!</string>
<string name="nfc_write_successful">Writing Tag successful</string> <string name="nfc_write_successful">Escritura de Etiqueta exitosa</string>
<string name="nfc_tag_unsupported">Tag does not support NDEF!</string> <string name="nfc_tag_unsupported">¡Etiqueta no soporta NDEF!</string>
<string name="nfc_tag_size">Tag provides %1$d bytes, but we need %2$d!</string> <string name="nfc_tag_size">La etiqueta provee %1$d bytes, pero necesitamos %2$d!</string>
<string name="nfc_tag_read_undef">I don\'t understand the Tag!</string> <string name="nfc_tag_read_undef">¡No comprendo la etiqueta!</string>
<string name="nfc_tag_read_what">I don\'t know what you want!</string> <string name="nfc_tag_read_what">¡No sé lo que pides!</string>
<string name="nfc_tag_read_success">Reading Tag successful</string> <string name="nfc_tag_read_success">Lectura de Etiqueta exitosa</string>
<string name="nfc_tag_tap">NFC Available!</string> <string name="nfc_tag_tap">¡NFC disponible!</string>
<string name="receive_desc_hint">Description (optional)</string> <string name="receive_desc_hint">Descripción (opcional)</string>
<string name="send_address_not_openalias">OpenAlias address not available</string> <string name="send_address_not_openalias">Dirección OpenAlias no disponible</string>
<string name="send_address_openalias">OpenAlias secure &#x2714;</string> <string name="send_address_openalias">OpenAlias asegurado &#x2714;</string>
<string name="send_address_resolve_openalias">Resolving OpenAlias&#8230;</string> <string name="send_address_resolve_openalias">Resolviendo OpenAlias&#8230;</string>
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string> <string name="send_address_no_dnssec">OpenAlias sin DNSSEC - la drección puede ser falsificada</string>
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string> <string name="send_address_hint">Dirección XMR/BTC del receptor u OpenAlias</string>
<string name="status_wallet_connect_wrongversion">Node version incompatible - please upgrade!</string> <string name="status_wallet_connect_wrongversion">Versión de nodo incompatible - ¡por favor actualiza!</string>
<string name="menu_info">Detalles</string><!--Changed to: Show Secrets!--> <string name="menu_info">Detalles</string><!--Changed to: Show Secrets!-->
<string name="menu_streetmode">Street Mode</string> <string name="menu_streetmode">Modo Público</string>
<string name="info_nodes_enabled">Node-o-matiC enabled, tap for more info.</string> <string name="info_nodes_enabled">Nodo-o-matiC habilitado, toque para más información.</string>
<string name="node_height">Last block updated: %1$s</string> <string name="node_height">Último bloque actualizado: %1$s</string>
<string name="label_nodes">Nodes</string> <string name="label_nodes">Nodos</string>
<string name="node_name_hint">Node Name (Optional)</string> <string name="node_name_hint">Nombre del Nodo (Opcional)</string>
<string name="node_address_hint">Hostname</string> <string name="node_address_hint">Nombre del Host</string>
<string name="node_port_hint">Port</string> <string name="node_port_hint">Puerto</string>
<string name="node_user_hint">Username (Optional)</string> <string name="node_user_hint">Usuario (Opcional)</string>
<string name="node_pass_hint">Password (Optional)</string> <string name="node_pass_hint">Contraseña (Opcional)</string>
<string name="node_host_unresolved">Cannot resolve host</string> <string name="node_host_unresolved">No se puede resolver el host</string>
<string name="node_host_empty">We need this!</string> <string name="node_host_empty">¡Necesitamos esto!</string>
<string name="node_port_numeric">Must be numeric</string> <string name="node_port_numeric">Debe ser numérico</string>
<string name="node_port_range">Must be 1&#8211;65535</string> <string name="node_port_range">Debe ser 1&#8211;65535</string>
<string name="node_fab_add">Add Node</string> <string name="node_fab_add">Agregar Nodo</string>
<string name="node_refresh_hint">Touch to refresh!</string> <string name="node_refresh_hint">¡Toca para refrescar!</string>
<string name="node_test_error">CONNECTION ERROR %1$d</string> <string name="node_test_error">ERROR DE CONECCIÓN %1$d</string>
<string name="node_general_error">CONNECTION ERROR</string> <string name="node_general_error">ERROR DE CONECCIÓN</string>
<string name="node_auth_error">AUTHENTICATION FAILED</string> <string name="node_auth_error">AUTENTIFICACIÓN FALLIDA</string>
<string name="node_result_label">Test Result:</string> <string name="node_result_label">Resultados de la prueba:</string>
<string name="node_result">Height: %1$s (v%2$d), Ping: %3$.0fms, IP: %4$s</string> <string name="node_result">Altura: %1$s (v%2$d), Ping: %3$.0fms, IP: %4$s</string>
<string name="node_testing">Testing IP: %1$s &#8230;</string> <string name="node_testing">Probando el IP: %1$s &#8230;</string>
<string name="node_refresh_wait">Please wait for scan to finish</string> <string name="node_refresh_wait">Por favor espera a que termine el escaneo</string>
<string name="node_create_hint">Touch to select or add nodes</string> <string name="node_create_hint">Toca para seleccionar o agregar nodos</string>
<string name="node_pull_hint">Add nodes manually or pull down to scan</string> <string name="node_pull_hint">Agregar nodos manualmente o presiona para escanear</string>
<string name="node_scanning">Scanning network&#8230;</string> <string name="node_scanning">Escaneando la red&#8230;</string>
<string name="node_nobookmark">Automatically bookmarked best %1$d nodes</string> <string name="node_nobookmark">Mejores %1$d nodos marcados automáticamente</string>
<string name="label_test">Test</string><!--note: as in "Test a network connection"--> <string name="label_test">Probar</string><!--note: as in "Test a network connection"-->
</resources> </resources>

View File

@@ -8,54 +8,54 @@
<b>Autorid</b> <b>Autorid</b>
<br/> <br/>
m2049r, baltsar777, anhdres, keejef, m2049r, baltsar777, anhdres, keejef,
rehrar, EarlOfEgo, ErCiccione et al. rehrar, EarlOfEgo, ErCiccione jt
<br/><br/> <br/><br/>
<a href="https://monerujo.io/">monerujo.io</a> <a href="https://monerujo.io/">monerujo.io</a>
]]></string> ]]></string>
<string name="privacy_policy"><![CDATA[ <string name="privacy_policy"><![CDATA[
<h1>Privacy Policy</h1> <h1>Privaatsuspoliitika</h1>
<p>This page informs you of our policies regarding the collection, <p>See leht informeerib sind personaalsete andmete kogumise, kasutamise ja
use and disclosure of personal information we receive from users of our avaldamise osas, mida saame meie äpi (monerujo: Monero Wallet) kasutajatelt.
app (monerujo: Monero Wallet).
</p> </p>
<p>By using the app, you agree to the collection and use of information in <p>Äppi kasutades nõustute teabe kogumise ja kasutamisega vastavalt sellele
accordance with this policy. poliitikale.
</p> </p>
<h2>Data Collected</h2> <h2>Kogutud andmed</h2>
<p>Personal data is any kind of data that could identify an individual. <p>Isikuandmed on igasugused andmed, mis võivad isikut tuvastada.
</p> </p>
<p>Monero keys and public addresses are collected and processed by the app locally <p>Monero võtmeid ja avalikke aadresse kogutakse ja töödeldakse äpisiseselt
for the purpose of processing transactions and transmitted into the Monero Network tehingute töötlemiseks ja edastatakse Monero võrku krüptitud kujul.
in encrypted form.
</p> </p>
<p>Other personal data is not collected by the app.</p> <p>Rakendus ei kogu muid isikuandmeid.</p>
<p>If you use the exchange (optional) functionality, monerujo fetches the exchange <p>Kui kasutate vahetusfunktsiooni, kasutab monerujo selleks coinmarketcap.com\'i
rate through the public API of coinmarketcap.com. avaliku API funktsiooni. Vaadake nende privaatsuspoliitikat aadressil
See their privacy policy at https://coinmarketcap.com/privacy for https://coinmarketcap.com/privacy, et saada üksikasju, kuidas teie päringute kohta
details on how data in your requests is collected.</p> andmeid kogutakse.</p>
<p>If you use the app to pay to BTC addresses, you will be using the XMR.TO service. <p>Kui kasutate äppi BTC-aadressitele raha saatmiseks, siis kasutatakse selleks
See their privacy policy at https://xmr.to/ for details. Monerujo send them the BTC XMR.TO teenust. Lisateabe saamiseks vaadake nende privaatsuspoliitikat aadressil
destination address and amount. Your IP will also be collectable.</p> https://xmr.to/. Monerujo saadab neile BTC sihtkoha aadressi ja summa. Koguda
<h2>App Permissions</h2> võidakse ka teie IP aadressi.</p>
<h2>Äpi õigused</h2>
<ul> <ul>
<li>INTERNET : Connect to the Monero Network via a Monero Daemon Node</li> <li>INTERNET : Monero võrguga ühenduse loomine Monero Daemoni sõlmpunkti kaudu</li>
<li>READ_EXTERNAL_STORAGE : Read wallet files stored on the device</li> <li>READ_EXTERNAL_STORAGE : Seadmesse salvestatud rahakoti failide lugemiseks</li>
<li>WRITE_EXTERNAL_STORAGE : Write wallet files stored on the device</li> <li>WRITE_EXTERNAL_STORAGE : Rahakoti failide seadmesse salvestamiseks</li>
<li>WAKE_LOCK : Keep device awake while syncing</li> <li>WAKE_LOCK : Sünkroonimise ajal hoiab seadme ärkvel</li>
<li>CAMERA : Scan QR Codes for receiving Monero</li> <li>CAMERA : QR-koodi lugemine Monero saamiseks</li>
</ul> </ul>
<h2>Changes to this Privacy Policy</h2> <h2>Privaatsuspoliitika muudatused</h2>
<p>We may update this privacy policy from time to time. We will notify <p>Me võime aeg-ajalt seda privaatsuspoliitikat uuendada. Teatame teile kõigist
you of any changes by posting the new privacy policy in the app and on the muudatustest, avaldades uued privaatsuseeskirjad äpis ja veebis (www.monerujo.io)
website (www.monerujo.io) Soovitame teil seda privaatsuspoliitikat perioodiliselt üle vaadata juhuks,
You are advised to review this privacy policy periodically for any changes. kui vahepeal on toimunud muutusi.
<p>This Privacy Policy was last updated: 10th November, 2017.
</p> </p>
<h2>Contact Us</h2> <p>Seda privaatsuspoliitikat uuendati viimati: 10. november, 2017.
<p>If you have any questions about our privacy policy, </p>
or how your data is being collected and processed, <h2>Võta meiega ühendust</h2>
please e-mail privacy@monerujo.io. <p>Kui teil on mingeid küsimusi meie privaatsuseeskirjade kohta või kuidas teie
andmeid kogutakse ja töödeldakse, siis palume saata e-post aadressile
privacy@monerujo.io.
</p> </p>
]]></string> ]]></string>
</resources> </resources>

View File

@@ -167,14 +167,11 @@
<string name="generate_fingerprint_hint">Luba rahakoti avamine sõrmejäljega</string> <string name="generate_fingerprint_hint">Luba rahakoti avamine sõrmejäljega</string>
<string name="generate_fingerprint_warn"><![CDATA[ <string name="generate_fingerprint_warn"><![CDATA[
<strong>Sõrmejäljega avamine</strong> <strong>Sõrmejäljega avamine</strong>
<p>With fingerprint authentication enabled, you can view wallet balance and receive funds <p>Kui sõrmejäljega avamine on sisse lülitatud, saad kontoseisu vaadata ja raha vastu võtta ilma parooli sisestamata.</p>
without entering password.</p> <p>Kuid kõrgema turvalisuse nimel palutakse sul sisestada parool siis, kui vaatad rahakoti infot või saadad raha.</p>
<p>But for additional security, monerujo will still require you to enter password when
viewing wallet details or sending funds.</p>
<strong>Turvahoiatus</strong> <strong>Turvahoiatus</strong>
<p>Finally, monerujo wants to remind you that anyone who can get your fingerprint will be <p>Lõpetuseks, monerujo tahab sulle meelde tuletada, et igaüks, kes pääseb ligi sinu sõrmejäljele, saab vaadata su kontoseisu.</p>
able to peep into your wallet balance.</p> <p>Näiteks on võimalik pahatahtlikel inimestel nii avada su rahakott, kui sa magad.</p>
<p>For instance, a malicious user around you can open your wallet when you are asleep.</p>
<strong>Oled kindel, et soovid selle aktiveerida?</strong> <strong>Oled kindel, et soovid selle aktiveerida?</strong>
]]></string> ]]></string>
<string name="generate_bad_passwordB">Paroolid ei kattu</string> <string name="generate_bad_passwordB">Paroolid ei kattu</string>
@@ -336,32 +333,32 @@
<string name="menu_info">Näita salajast infot</string> <string name="menu_info">Näita salajast infot</string>
<string name="menu_streetmode">Avalik režiim</string> <string name="menu_streetmode">Avalik režiim</string>
<string name="info_nodes_enabled">Node-o-matiC enabled, tap for more info.</string> <string name="info_nodes_enabled">Node-o-matiC sisse lülitatud, puuduta lisainfo saamiseks.</string>
<string name="node_height">Last block updated: %1$s</string> <string name="node_height">Viimane uuendatud plokk: %1$s</string>
<string name="label_nodes">Nodes</string> <string name="label_nodes">Serverid</string>
<string name="node_name_hint">Node Name (Optional)</string> <string name="node_name_hint">Serveri nimi (valikuline)</string>
<string name="node_address_hint">Hostname</string> <string name="node_address_hint">Aadress</string>
<string name="node_port_hint">Port</string> <string name="node_port_hint">Port</string>
<string name="node_user_hint">Username (Optional)</string> <string name="node_user_hint">Kasutajanimi (valikuline)</string>
<string name="node_pass_hint">Password (Optional)</string> <string name="node_pass_hint">Parool (valikuline)</string>
<string name="node_host_unresolved">Cannot resolve host</string> <string name="node_host_unresolved">Aadressi lahendmine ebaõnnestus</string>
<string name="node_host_empty">We need this!</string> <string name="node_host_empty">Meil on seda vaja!</string>
<string name="node_port_numeric">Must be numeric</string> <string name="node_port_numeric">Peab olema arv</string>
<string name="node_port_range">Must be 1&#8211;65535</string> <string name="node_port_range">Peab olema 1&#8211;65535</string>
<string name="node_fab_add">Add Node</string> <string name="node_fab_add">Lisa server</string>
<string name="node_refresh_hint">Touch to refresh!</string> <string name="node_refresh_hint">Puuduta värskendamiseks!</string>
<string name="node_test_error">CONNECTION ERROR %1$d</string> <string name="node_test_error">ÜHENDUSE VIGA %1$d</string>
<string name="node_general_error">CONNECTION ERROR</string> <string name="node_general_error">ÜHENDUSE VIGA</string>
<string name="node_auth_error">AUTHENTICATION FAILED</string> <string name="node_auth_error">SISSE LOGIMINE EBAÕNNESTUS</string>
<string name="node_result_label">Test Result:</string> <string name="node_result_label">Testi tulemus:</string>
<string name="node_result">Height: %1$s (v%2$d), Ping: %3$.0fms, IP: %4$s</string> <string name="node_result">Kõrgus: %1$s (v%2$d), Ping: %3$.0fms, IP: %4$s</string>
<string name="node_testing">Testing IP: %1$s &#8230;</string> <string name="node_testing">Testimise IP: %1$s &#8230;</string>
<string name="node_refresh_wait">Please wait for scan to finish</string> <string name="node_refresh_wait">Palun oota otsimise lõpuni</string>
<string name="node_create_hint">Touch to select or add nodes</string> <string name="node_create_hint">Puuduta serverite valimiseks või lisamiseks</string>
<string name="node_pull_hint">Add nodes manually or pull down to scan</string> <string name="node_pull_hint">Lisa serverid käsitsi või pühi sõrmega alla, et otsida</string>
<string name="node_scanning">Scanning network&#8230;</string> <string name="node_scanning">Otsin võrgust&#8230;</string>
<string name="node_nobookmark">Automatically bookmarked best %1$d nodes</string> <string name="node_nobookmark">Automaatselt salvestati parimad %1$d serverit</string>
<string name="label_test">Test</string><!--note: as in "Test a network connection"--> <string name="label_test">Testi</string><!--note: as in "Test a network connection"-->
<string name="backup_success">Backup successful</string> <string name="backup_success">Tagavarakoopia õnnestus</string>
</resources> </resources>

View File

@@ -213,11 +213,11 @@
<string name="help_wallet"><![CDATA[ <string name="help_wallet"><![CDATA[
<h1>Carteira</h1> <h1>Carteira</h1>
<h2>Street Mode</h2> <h2>Modo Rua</h2>
<p>Street mode can be enabled/disabled in the menu or Gunther\'s head icon. In this mode, your <p>O modo rua pode ser ativado/desativado no menu ou no ícone da cabeça do Gunther. Neste modo, o seu
balance is not shown on any screen so you can safely use your wallet on the street, a pub or saldo não será exibido em nenhuma tela para que você possa usar sua carteira com segurança na rua, em um bar ou
other public place. Previous transactions are also hidden. New transactions will be shown, so outro lugar público. Transações anteriores também serão ocultas. Novas transações serão mostradas, então
you can see that you have sent/received sweet Moneroj!</p> você pode ver que você enviou/recebeu Moneroj!</p>
<h2>Escaneando</h2> <h2>Escaneando</h2>
Como o Monero sempre mantém tudo privado, sempre que você abrir sua carteira o Monerujo precisa escanear Como o Monero sempre mantém tudo privado, sempre que você abrir sua carteira o Monerujo precisa escanear
o blockchain para identificar se você recebeu algum novo Monero. Somente as informações que correspondem à sua o blockchain para identificar se você recebeu algum novo Monero. Somente as informações que correspondem à sua
@@ -234,51 +234,51 @@
]]></string> ]]></string>
<string name="help_node"><![CDATA[ <string name="help_node"><![CDATA[
<h1>Nodes</h1> <h1>Nós</h1>
<h2>TL;DR</h2> <h2>TL;DR</h2>
<p>Refresh the nodes list by pulling down &amp; bookmark 3&#8211;5 nodes to allow Monerujo <p>Atualize a lista de nós puxando para baixo &amp; favorite 3&#8211;5 nós para permitir que o Monerujo
to choose the best one for you!</p> escolha o melhor para você!</p>
<h2>What&apos;s a Node?</h2> <h2>O que é um Nó?</h2>
<p>Monerujo uses a Remote Node (sometimes also called Daemon) to communicate with <p>O Monerujo usa um nó remoto (às vezes também chamado de Daemon) para se comunicar com
the Monero Network without having to download and store a copy of the a Rede Monero sem ter que baixar e armazenar uma cópia do
whole blockchain itself.<p> blockchain inteiro.<p>
<h2>Node List</h2> <h2>Lista de Nós</h2>
<p>If the list is empty, you can either add new nodes manually or let Monerujo <p>Se a lista estiver vazia, você pode adicionar novos nós manualmente ou deixar que o Monerujo
scan the network for you. Or both. Read on&#8230;</p> escaneie a rede para você. Ou ambos. Leia mais&#8230;</p>
<p>The node list shows all currently known nodes. Additionally, the timestamp <p>A lista de nós mostra todos os nós conhecidos atualmente. Além disso, a data e hora
of the latest block known to each node is shown under the node name. An icon do último bloco sincronizado para cada nó é exibido abaixo de seu nome. Um ícone
representing the node&apos;s response behaviour representando o comportamento de resposta do nó
(which indicates the level of connectivity to be expected) (o que indica o nível de conectividade esperado)
is shown next to each node.</p> é exibido ao lado.</p>
<p>Any node in the list can be bookmarked for later use. <p>Qualquer nó na lista pode ser favoritado para uso posterior.
Nodes which are not bookmarked will be forgotten.<p> Os nós que não são marcados como favoritos serão esquecidos.<p>
<p>Monerujo will choose the optimal bookmarked node each time you use it. <p>O Monerujo sempre escolherá o nó ideal dentre os marcados.
It does this by checking the blockheight (how up-to-date Ele faz isso verificando a altura do bloco (quão sincronizado
is the node?) as well as the response behaviour (how fast does the node respond to requests?).</p> está o nó?) bem como o comportamento da resposta (com que rapidez o nó responde às solicitações?).</p>
<p>The list is sorted by these characteristics, so the top node would be the one Monerujo <p>A lista é classificada por essas características, portanto, o nó do topo seria o único que o Monerujo
would choose right now. The bottom of the list would show very slow or unavailable nodes.</p> escolheria nesse caso. A parte inferior da lista mostraria nós muito lentos ou indisponíveis.</p>
<h2>Add a Node</h2> <h2>Adicionar um Nó</h2>
<p>By touching the &quot;Add Node&quot; button at the bottom, you will be asked to <p>Ao tocar no botão &quot;Adicionar nó&quot; na parte inferior, você será solicitado a
enter the node details in the following dialog. inserir os detalhes do nó no diálogo seguinte.
The &quot;Address&quot; is the hostname or IP-address of the node - this is the only O &quot;Endereço do Host&quot; é o nome do host ou endereço IP do nó - esta é a única
mandatory entry. informação obrigatória.
Enter the &quot;Port&quot; if the node runs on a non-default port (e.g. 18089). Digite a &quot;Porta&quot; se o nó for executado em uma porta não padrão (por exemplo, 18089).
You can also optionally name the node, so you can identify it easier later on. Você também pode, opcionalmente, dar um nome ao nó para facilitar sua identificação mais tarde.
Some nodes require credentials to use them. Enter the provided username &amp; Alguns nós exigem credenciais para serem utilizados. Digite o nome de usuário e
password in the appropriate fields. Now you can &quot;Test&quot; these setting. senha nos campos apropriados. Agora você pode &quot;testar&quot; essas configurações.
The &quot;Test Results&quot; will display the blockheight, response time and actual IP used. Os &quot;Resultados dos Testes&quot; exibirão a altura do bloco, o tempo de resposta e o IP real usado.
The result may also be an error - usually because the hostname provided is O resultado também pode ser um erro - geralmente porque o nome do host fornecido
not reachable in a sensible amount of time or the credentials are incorrect. não pôde ser alcançado em um período de tempo razoável ou as credenciais estão incorretas.
Or the hostname/port combination does not point to an actual Monero Node! Ou a combinação Nome do Host/Porta não aponta para um Nó Monero válido!
Once the test passes (no error) - you&apos;re set to press &quot;OK&quot; to save &amp; Depois que o teste passar (sem erro), você poderá pressionar &quot;OK&quot; para salvar &amp;
bookmark this node.</p> marcar este nó como favorito.</p>
<h2>Scan for Nodes</h2> <h2>Escanear Nós</h2>
<p>Additionally, you can scan the network for nodes. Monerujo will start <p>Além disso, você pode verificar a rede em busca de nós. O Monerujo vai começar a
scanning the network for Remote Nodes on port 18089. It begins by asking your escanear a rede por nós remotos na porta 18089. Ele começa perguntando ao seus
bookmarked nodes for other peers in the Monero P2P network and then continues nós marcados como favoritos por outros pares na rede P2P do Monero e, em seguida, continua
by asking those for their peers, and so on. If you have no bookmarked nodes perguntando por seus pares, e assim por diante. Se você não tem nós marcados como favoritos
(or they don&apos;t tell us about their peers), (ou eles não nos dizem sobre seus pares),
Monerujo will go straight to the Monero seed nodes hardcoded into Monero. The o Monerujo irá direto para os nós codificados direto no Monero em si. O
scan stops when it finds 10 remote nodes in total.</p> escaneamento termina quando 10 nós remotos são encontrados no total.</p>
]]></string> ]]></string>
</resources> </resources>

View File

@@ -157,7 +157,7 @@
<string name="message_copy_viewkey">Chave de visualização copiada para a área de transferência!</string> <string name="message_copy_viewkey">Chave de visualização copiada para a área de transferência!</string>
<string name="message_copy_xmrtokey">Chave XMR.TO copiada para a área de transferência!</string> <string name="message_copy_xmrtokey">Chave XMR.TO copiada para a área de transferência!</string>
<string name="message_copy_address">Endereço da carteira copiado para a área de transferência!</string> <string name="message_copy_address">Endereço da carteira copiado para a área de transferência!</string>
<string name="message_copy_txid">ID da transacção copiado para a área de transferência!</string> <string name="message_copy_txid">ID da transação copiado para a área de transferência!</string>
<string name="message_nocopy">Copiar está desativado por razões de segurança!</string> <string name="message_nocopy">Copiar está desativado por razões de segurança!</string>
<string name="message_exchange_failed">Não foi possível obter a cotação!\nUse XMR/XMR ou tente novamente</string> <string name="message_exchange_failed">Não foi possível obter a cotação!\nUse XMR/XMR ou tente novamente</string>
@@ -325,35 +325,35 @@
<string name="nfc_tag_read_success">Sucesso na leitura da tag</string> <string name="nfc_tag_read_success">Sucesso na leitura da tag</string>
<string name="nfc_tag_tap">NFC disponível!</string> <string name="nfc_tag_tap">NFC disponível!</string>
<string name="menu_info">Detalhes</string><!--Changed to: Show Secrets!--> <string name="menu_info">Mostrar Segredos!</string>
<string name="menu_streetmode">Street Mode</string> <string name="menu_streetmode">Modo Rua</string>
<string name="info_nodes_enabled">Node-o-matiC enabled, tap for more info.</string> <string name="info_nodes_enabled">Nó-auto-mágiCo ativado, toque para mais informações.</string>
<string name="node_height">Last block updated: %1$s</string> <string name="node_height">Último bloco sincronizado em: %1$s</string>
<string name="label_nodes">Nodes</string> <string name="label_nodes">Nós</string>
<string name="node_name_hint">Node Name (Optional)</string> <string name="node_name_hint">Nome do Nó (Opcional)</string>
<string name="node_address_hint">Hostname</string> <string name="node_address_hint">Endereço do Host</string>
<string name="node_port_hint">Port</string> <string name="node_port_hint">Porta</string>
<string name="node_user_hint">Username (Optional)</string> <string name="node_user_hint">Usuário (Opcional)</string>
<string name="node_pass_hint">Password (Optional)</string> <string name="node_pass_hint">Senha (Opcional)</string>
<string name="node_host_unresolved">Cannot resolve host</string> <string name="node_host_unresolved">Host não encontrado</string>
<string name="node_host_empty">We need this!</string> <string name="node_host_empty">Nós precisamos disso!</string>
<string name="node_port_numeric">Must be numeric</string> <string name="node_port_numeric">Deve ser numérico</string>
<string name="node_port_range">Must be 1&#8211;65535</string> <string name="node_port_range">Deve ser entre 1&#8211;65535</string>
<string name="node_fab_add">Add Node</string> <string name="node_fab_add">Adicionar Nó</string>
<string name="node_refresh_hint">Touch to refresh!</string> <string name="node_refresh_hint">Toque para atualizar!</string>
<string name="node_test_error">CONNECTION ERROR %1$d</string> <string name="node_test_error">ERRO DE CONEXÃO %1$d</string>
<string name="node_general_error">CONNECTION ERROR</string> <string name="node_general_error">ERRO DE CONEXÃO</string>
<string name="node_auth_error">AUTHENTICATION FAILED</string> <string name="node_auth_error">FALHA NA AUTENTICAÇÃO</string>
<string name="node_result_label">Test Result:</string> <string name="node_result_label">Resultado do Teste:</string>
<string name="node_result">Height: %1$s (v%2$d), Ping: %3$.0fms, IP: %4$s</string> <string name="node_result">Altura: %1$s (v%2$d), Ping: %3$.0fms, IP: %4$s</string>
<string name="node_testing">Testing IP: %1$s &#8230;</string> <string name="node_testing">Testando IP: %1$s &#8230;</string>
<string name="node_refresh_wait">Please wait for scan to finish</string> <string name="node_refresh_wait">Por favor, aguarde o escaneamento terminar</string>
<string name="node_create_hint">Touch to select or add nodes</string> <string name="node_create_hint">Toque para selecionar ou adicionar nós</string>
<string name="node_pull_hint">Add nodes manually or pull down to scan</string> <string name="node_pull_hint">Adicione nós manualmente ou puxe para baixo para escanear</string>
<string name="node_scanning">Scanning network&#8230;</string> <string name="node_scanning">Escaneando rede&#8230;</string>
<string name="node_nobookmark">Automatically bookmarked best %1$d nodes</string> <string name="node_nobookmark">Melhores %1$d nós adicionados aos favoritos</string>
<string name="label_test">Test</string><!--note: as in "Test a network connection"--> <string name="label_test">Testar</string><!--note: as in "Test a network connection"-->
<string name="backup_success">Backup successful</string> <string name="backup_success">Backup feito com successo</string>
</resources> </resources>

View File

@@ -168,7 +168,7 @@
<h2>Заказ XMR.TO<h2> <h2>Заказ XMR.TO<h2>
<p>На экране \"Подтверждение\" можно увидеть фактический заказ XMR.TO. Этот заказ <p>На экране \"Подтверждение\" можно увидеть фактический заказ XMR.TO. Этот заказ
действителен в течение ограниченного времени. Обратный отсчёт можно увидеть на кнопке действителен в течение ограниченного времени. Обратный отсчёт можно увидеть на кнопке
траты \"Трата\". Курс обмена может отличаться от того, что был показан на предыдущих экранах..</p> траты \"Трата\". Курс обмена может отличаться от того, что был показан на предыдущих экранах.</p>
<h2>Секретный ключ XMR.TO<h2> <h2>Секретный ключ XMR.TO<h2>
<p>Так как Monerujo отвечает за ту часть транзакции, которая связана с Monero, для отслеживания <p>Так как Monerujo отвечает за ту часть транзакции, которая связана с Monero, для отслеживания
вашего заказа, которая связана с Bitcoin, можно использовать секретный ключ на домашней странице вашего заказа, которая связана с Bitcoin, можно использовать секретный ключ на домашней странице
@@ -197,7 +197,7 @@
<h2>Заказ XMR.TO<h2> <h2>Заказ XMR.TO<h2>
<p>На экране \"Подтверждение\" можно увидеть фактический заказ XMR.TO. Этот заказ <p>На экране \"Подтверждение\" можно увидеть фактический заказ XMR.TO. Этот заказ
действителен в течение ограниченного времени. Обратный отсчёт можно увидеть на кнопке \"Трата\". действителен в течение ограниченного времени. Обратный отсчёт можно увидеть на кнопке \"Трата\".
Курс обмена может отличаться от того, что был показан на предыдущих экранах..</p> Курс обмена может отличаться от того, что был показан на предыдущих экранах.</p>
<h2>Секретный ключ XMR.TO<h2> <h2>Секретный ключ XMR.TO<h2>
<p>Так как Monerujo отвечает за ту часть транзакции, которая связана с Monero, для отслеживания <p>Так как Monerujo отвечает за ту часть транзакции, которая связана с Monero, для отслеживания
вашего заказа, которая связана с Bitcoin, можно использовать секретный ключ на домашней странице вашего заказа, которая связана с Bitcoin, можно использовать секретный ключ на домашней странице

View File

@@ -51,7 +51,7 @@
<string name="info_send_xmrto_parms"><![CDATA[ <string name="info_send_xmrto_parms"><![CDATA[
<b>Вы можете отправить %1$s &#8212; %2$s BTC</b>.<br/> <b>Вы можете отправить %1$s &#8212; %2$s BTC</b>.<br/>
<i><b>XMR.TO</b> устанавливает курс обменна <b>%3$s BTC</b> <u>в данный момент</u></i>. <i><b>XMR.TO</b> устанавливает курс обмена <b>%3$s BTC</b> <u>в данный момент</u></i>.
]]></string> ]]></string>
<string name="info_send_xmrto_zeroconf"><![CDATA[ <string name="info_send_xmrto_zeroconf"><![CDATA[
<i>Сумма до <b>%1$s BTC</b> будет отправлена <u>немедленно</u>!</i> <i>Сумма до <b>%1$s BTC</b> будет отправлена <u>немедленно</u>!</i>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="about_close">Закрити</string>
<string name="about_whoami">Я monerujo</string>
<string name="about_version">Версія %1$s (%2$d)</string>
<string name="credits_text"><![CDATA[
<b>Інформація</b>
<br/>
m2049r, baltsar777, anhdres, keejef,
rehrar, EarlOfEgo et al.
<br/><br/>
<a href="https://monerujo.io/">monerujo.io</a>
]]></string>
<string name="privacy_policy"><![CDATA[
<h1>Політика конфіденційності</h1>
<p>Дана сторінка містить інформацію, що стосується нашої політики щодо збору,
використання і розкриття ваших особистих даних, які ми отримуємо
від користувачів додатку (monerujo: Monero Wallet).
</p>
<p>Використовуючи додаток, ви погоджуєтеся на збір і використання
інформації відповідно до даної політики.
</p>
<h2>Зібрані дані</h2>
<p>Особистими даними є будь-які дані, які дозволяють
ідентифікувати вас як особистість.</p>
<p>Додаток локально збирає і обробляє ключі і публічні адреси Monero
з метою обробки транзакцій і їх передачі в мережу Monero в зашифрованій формі.
</p>
<p>Додаток не збирає будь-яких інших особистих даних.</p>
<p>Якщо ви використовуєте функцію обміну (необовязково), monerujo отримує обмінний
курс через публічний API coinmarketcap.com.
Перейдіть за адресою https://coinmarketcap.com/privacy для отримання детальної
інформації про те, як збираються ваші персональні дані в запитах.</p>
<p>Якщо ви використовуєте додаток для оплати за адресами BTC,
ви будете використовувати сервіс XMR.TO. Їх політика конфіденційності детально
викладена на веб-сайті https://xmr.to/. Monerujo відправляє їм адресу
призначення BTC і суму. Ваш IP також вказується.</p>
<h2>Дозволи, необхідні додатку</h2>
<ul>
<li>INTERNET : Підключення до мережі Monero через демон-вузол.</li>
<li>READ_EXTERNAL_STORAGE : Зчитування файлів гаманця, які зберігаються на пристрої.</li>
<li>WRITE_EXTERNAL_STORAGE : Запис файлів гаманця, які зберігаються на пристрої.</li>
<li>WAKE_LOCK : Виведення пристрою з неактивного стану при синхронізації.</li>
<li>CAMERA : Сканування QR-кодів для отримання Monero.</li>
</ul>
<h2>Зміни в політиці конфіденційності</h2>
<p>У дані положення політики конфіденційності періодично можуть
вноситися зміни. У разі внесення таких змін, нові положення
будуть опубліковані в додатку і на вебсайті (www.monerujo.io).
Рекомендується періодично перевіряти положення політики
конфіденційності на предмет внесення змін.
<p>Дата останнього оновлення положень політики конфіденційності: 10.11.2017
</p>
<h2>Контактна інформація</h2>
<p>Якщо у вас виникли питання, що стосуються нашої політики конфіденційності
або того, як відбувається збір і обробка ваших даних,
напишіть нам за адресою 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

@@ -18,6 +18,7 @@ package com.m2049r.xmrwallet.util;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@@ -54,4 +55,38 @@ public class BitcoinAddressValidatorTest {
assertTrue(!BitcoinAddressValidator.validate("3NagLCvw8fLwtoUrK7s2mJPy9k6hoyWvTU ", false)); assertTrue(!BitcoinAddressValidator.validate("3NagLCvw8fLwtoUrK7s2mJPy9k6hoyWvTU ", false));
assertTrue(!BitcoinAddressValidator.validate(" 3NagLCvw8fLwtoUrK7s2mJPy9k6hoyWvTU ", false)); assertTrue(!BitcoinAddressValidator.validate(" 3NagLCvw8fLwtoUrK7s2mJPy9k6hoyWvTU ", false));
} }
@Test
public void validSegwit() {
// see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
assertTrue(BitcoinAddressValidator.validateBech32Segwit("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", false));
assertTrue(BitcoinAddressValidator.validateBech32Segwit("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx", true));
assertTrue(BitcoinAddressValidator.validateBech32Segwit("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", false));
assertTrue(BitcoinAddressValidator.validateBech32Segwit("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", true));
assertTrue(BitcoinAddressValidator.validateBech32Segwit("BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", false));
assertTrue(BitcoinAddressValidator.validateBech32Segwit("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", true));
assertTrue(BitcoinAddressValidator.validateBech32Segwit("bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx", false));
assertTrue(BitcoinAddressValidator.validateBech32Segwit("BC1SW50QA3JX3S", false));
assertTrue(BitcoinAddressValidator.validateBech32Segwit("bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", false));
assertTrue(BitcoinAddressValidator.validateBech32Segwit("tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", true));
assertTrue(BitcoinAddressValidator.validateBech32Segwit("bc1q76awjp3nmklgnf0yyu0qncsekktf4e3qj248t4", false)); // electrum blog
}
@Test
public void invalidSegwit() {
// see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
assertFalse(BitcoinAddressValidator.validateBech32Segwit("tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", true)); // Invalid human-readable part
assertFalse(BitcoinAddressValidator.validateBech32Segwit("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", true)); // Invalid checksum
assertFalse(BitcoinAddressValidator.validateBech32Segwit("BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", true)); // Invalid witness version
assertFalse(BitcoinAddressValidator.validateBech32Segwit("bc1rw5uspcuh", true)); // Invalid program length
assertFalse(BitcoinAddressValidator.validateBech32Segwit("bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", true)); // Invalid program length
assertFalse(BitcoinAddressValidator.validateBech32Segwit("BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", true)); // Invalid program length for witness version 0 (per BIP141)
assertFalse(BitcoinAddressValidator.validateBech32Segwit("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", true)); // Mixed case
assertFalse(BitcoinAddressValidator.validateBech32Segwit("bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", true)); // zero padding of more than 4 bits
assertFalse(BitcoinAddressValidator.validateBech32Segwit("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", true)); // Non-zero padding in 8-to-5 conversion
assertFalse(BitcoinAddressValidator.validateBech32Segwit("bc1gmk9yu", true)); // Empty data section
}
} }