1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-03 08:23:04 +02:00

Compare commits

...

119 Commits

Author SHA1 Message Date
m2049r
67f3c5f948 bump version 2019-02-04 19:41:28 +01:00
m2049r
cd67a7e2bf 2019-02 height 2019-02-04 19:41:28 +01:00
0140454
fa5fe313ea Update zh-rTW translation (#529) 2019-02-03 07:54:41 +01:00
jaro Lee
ed4957a3cc sk strings update (#523) 2019-01-29 22:33:09 +01:00
jaro Lee
3e0eeebd51 sk help.xml update (#527)
sk-translation - help_send update
2019-01-29 22:32:40 +01:00
m2049r
0d213a1eb4 hide sweep amount in street mode (#526) 2019-01-28 01:16:00 +01:00
m2049r
39d048fd5e Feature bitpay (#525)
* support bitcoin payment protocol (BIP70/72)

* prep translations
2019-01-27 21:32:06 +01:00
m2049r
1a5d2d0399 Update Android Studio v3.3 (#522)
* Update Android Studio v3.3

* also update circleci script to accept licenses
2019-01-21 17:38:59 +01:00
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
m2049r
94f87a5193 bump version 2018-11-28 22:03:24 +01:00
Lafudoci
8a8fc5ec9e Node-o-matiC translation in zh-tw (#488) 2018-11-28 19:47:29 +01:00
joshuamarques
036d4ebf6c Japanese translation added (#481) 2018-11-28 07:52:16 +01:00
m2049r
c6d4de8599 bump version 2018-11-26 23:39:01 +01:00
m2049r
2ef7f8571c adjust & tweak tx details layout (#489) 2018-11-26 23:08:32 +01:00
m2049r
d2612a26e5 show my tx (sub)address (#487) 2018-11-26 12:05:40 +01:00
m2049r
7e14572756 (optional) disable crazypass generation (#486)
* (optional) disable crazypass generation

* update FAQ about disabling crazypass
2018-11-26 12:05:25 +01:00
hrumag
6f840dcacf [IT-Translation] help.xml / strings.xml - First Issue (#480)
* [IT-Translation] help.xml / strings.xml

* [IT-Translation] Fixes from @erciccione and @serhack
2018-11-26 12:05:03 +01:00
m2049r
36b389cd0f USE_FINGERPRINT & bump version 2018-11-24 23:39:35 +01:00
m2049r
ed2b95ea37 Fix android9 permissions (#484)
* FOREGROUND_SERVICE for Android 9

* USE_BIOMETRIC for Android 9
2018-11-24 23:03:20 +01:00
m2049r
8d41d1d03e Stagenet build config (#483)
* combine gitignores

* stagenet build config
2018-11-24 22:28:33 +01:00
m2049r
e2e9da3437 bump version 2018-11-24 13:08:38 +01:00
m2049r
7cd07d1988 resurrect 'backup successful' message (#482) 2018-11-24 13:00:31 +01:00
Lafudoci
f5ae0525e3 Street mode translation in zh-tw (#465)
* Street mode translation in zh-tw

* Change street mode translation and minor fix

* Replace private mode translation to low profile mode
2018-11-24 11:32:12 +01:00
jaro Lee
b32ed8caf2 values-sk update (#479)
* Ledger and NFC support added
* minor typo fixes
* removed string  <string name="menu_language">
2018-11-24 11:29:48 +01:00
el00ruobuob
e0c2bfc4c4 French Nodes (#477) 2018-11-24 11:21:39 +01:00
m2049r
2986dfeaa7 nodes help (#476) 2018-11-20 21:10:25 +01:00
m2049r
acb7398dca Merge pull request #475 from m2049r/feature_nodes
- Feature node-o-matic
- allow fingerprint return from streetmode
2018-11-20 21:05:32 +01:00
m2049r
c8322f5a83 fingerprint return from streetmode 2018-11-20 20:06:56 +01:00
m2049r
973472e0ef Node-o-matiC 2018-11-20 19:20:51 +01:00
m2049r
2dad55e498 revert avoiding NPE 2018-11-13 22:51:43 +01:00
m2049r
8e82bd4cc8 fix typo (#472) 2018-11-13 22:35:01 +01:00
m2049r
38a825d580 avoid possible NPE (#471) 2018-11-13 22:32:31 +01:00
m2049r
be04185481 fix disappearing progressbar during sync (#470) 2018-11-13 21:58:32 +01:00
m2049r
5bfb920979 Direct Streetmode & credentials for disabling it (#469)
- Add wallet menu item to enter streetmode directly
- Add credentials check to leave streetmode (someone-snatches-your-phone-scenario)
- Recheck credentials for showing secrets after entering streetmode
2018-11-13 19:08:51 +01:00
m2049r
29583fa40d fix crash when no ledger connected (#463) 2018-11-05 18:47:11 +01:00
el00ruobuob
dc86f0469e Update FR for street mode (#464)
+ corrections after review
2018-11-05 18:28:34 +01:00
hrumag
9e48f2bdcb [i18n-IT] Aligned translation of new features (#461)
* [i18n-IT] Aligned translation of new features

* [i18n-IT] Translation change "menu_info"

Dettagli => Mostra i segreti!
2018-11-05 18:26:25 +01:00
Hans
b71c260323 Update to Estonian translations (#462) 2018-11-04 23:12:39 +01:00
m2049r
46dbc0659b vital fixes to translations (#460) 2018-11-03 17:24:11 +01:00
m2049r
85622b3958 bump version 2018-11-03 17:17:02 +01:00
m2049r
5a63481c09 correct static jni methods (#459) 2018-11-03 16:59:16 +01:00
m2049r
1cb558d78e streetmode hides all balances & previous transactions (#458) 2018-11-03 16:45:34 +01:00
Hans
942c80e38b Estonian translations (#447)
* Create about.xml

* Create help.xml

* Create strings.xml
2018-11-03 16:11:25 +01:00
m2049r
24ec848f0f 2018-11-01 height 2018-11-03 11:06:49 +01:00
m2049r
0d1b1da5f3 remove v9 notice (#457) 2018-11-03 09:45:39 +01:00
jaro Lee
0840d2f350 Update strings.xml (#445)
new strings translated , few old strings tuned
2018-10-31 12:25:01 +01:00
hrumag
c7d933ea9d [strings_it.xml] Correct some translations (#450)
"subaddress" => "sottoindirizzo"
"balance => "saldo"
Fix '/n' with '\n'
2018-10-31 12:24:42 +01:00
vp1111
c9b1800309 Translation to Brazilian Portuguese (pt-rBR). (#455)
* Translation to Brazilian Portuguese (pt-rBR).

* adopted some of shigutso's suggestions

* adopted some of netrik's suggestions
2018-10-31 12:24:12 +01:00
m2049r
e7b0b5999e remove help for ringsize & priority (#448) 2018-10-18 09:10:21 +02:00
m2049r
47e1871693 update buildToolsVersion 2018-10-17 22:23:43 +02:00
m2049r
900eab70c8 update gradle 2018-10-16 22:27:01 +02:00
m2049r
b11357f379 bump version 2018-10-13 10:05:52 +02:00
m2049r
eba0156a6d info/warn about v9 upgrade (#442) 2018-10-13 10:05:17 +02:00
m2049r
bf64d8bd89 add 2018-10-01 height (#441) 2018-10-13 10:04:30 +02:00
m2049r
2d74281b31 bump version 2018-10-12 23:05:14 +02:00
m2049r
668cefb357 explicit check pw (#439)
also, revert device type query changes
2018-10-12 23:03:53 +02:00
0140454
1f5061df38 Update zh-rTW translation for node version warning (#437) 2018-10-11 17:41:59 +02:00
m2049r
51445f5941 Fix build (#435) 2018-10-10 21:12:18 +02:00
m2049r
8c01ec36e8 deal with illegal values for device type (#434) 2018-10-10 21:11:59 +02:00
m2049r
3cf84c599d ignore build directories 2018-10-10 08:01:56 +02:00
m2049r
ead8564688 bump version 2018-10-09 19:38:06 +02:00
m2049r
b71b3badd8 remove settings & fix prio to default (#433) 2018-10-09 19:33:29 +02:00
ProkhorZ
5ad46e2f54 Add node version warning (#432)
for monero v0.13 upgrade.
2018-10-09 07:59:49 +02:00
m2049r
9d6895b60f adding missing resources 2018-10-08 23:10:25 +02:00
m2049r
a8755ee0da correct error message 2018-10-08 22:50:40 +02:00
m2049r
f186bc9d4f core wallet api 0.13 2018-10-08 22:50:16 +02:00
ProkhorZ
9cb961a368 Translate missing strings (#429)
As requested in #411
2018-10-08 22:34:00 +02:00
m2049r
aa78541b6f fix build 2018-10-08 20:58:26 +02:00
v1docq47
eba6a78004 Update for Russian translation #370 (#422)
* Update for Russian translation
- strings.xml
- help.xml
2018-10-08 19:44:56 +02:00
m2049r
8587eab41c whitespace & cleanup 2018-10-08 19:02:00 +02:00
m2049r
4271c743c7 update wallet balance on refresh 2018-10-08 19:02:00 +02:00
m2049r
5b60987692 remove beta flavor 2018-10-08 19:02:00 +02:00
m2049r
e1bd04c945 tweaks & new version 2018-10-08 19:02:00 +02:00
m2049r
ef29db62c4 change error message 2018-10-08 19:02:00 +02:00
m2049r
82ce12e27c increase mixin to 10 as per protocol v8 2018-10-08 19:02:00 +02:00
m2049r
4211687981 rework build process 2018-10-08 19:02:00 +02:00
m2049r
d398416a3d translation prep 2018-10-08 19:02:00 +02:00
m2049r
1844d84be8 whitespace 2018-10-08 19:02:00 +02:00
m2049r
5101b7da5e flavor alpha,beta 2018-10-08 19:02:00 +02:00
m2049r
3e90f2e22e new Ledger interface 2018-10-08 19:02:00 +02:00
m2049r
f01a8eac5d bump version 2018-10-08 19:02:00 +02:00
m2049r
0c13338dc0 link with libsodium 2018-10-08 19:02:00 +02:00
m2049r
78d6fef3e4 getDeviceType 2018-10-08 19:02:00 +02:00
m2049r
cbddcdc92d new api & queryWalletDevice 2018-10-08 19:02:00 +02:00
jaro Lee
4289aaac77 Update strings.xml (#428)
Minor translation misssteps. Bringing to context.
Regarding `send_settings_title` - NASTAVENIA string is too long (wrapping the text in a button). Changed to `Možnosti`  (options in english)
2018-10-08 19:00:55 +02:00
m2049r
fd15da9c84 cleaned old/irrelevant stuff 2018-10-08 18:59:36 +02:00
m2049r
c3357087d5 add missing strings 2018-10-08 13:35:10 +02:00
m2049r
47e0bc86fd fixed positional formatting 2018-10-08 13:35:10 +02:00
Wobole
dbd45ea4f5 Update german translation (#425) 2018-10-08 13:02:06 +02:00
ProkhorZ
90c3e6ef8b Add Dutch translation in values-nl (#411) 2018-10-08 13:00:17 +02:00
m2049r
bc6a816462 upgrade AndroidStudio 2018-09-25 22:39:07 +02:00
m2049r
274a1a25f1 correct cstdio files to patch 2018-09-25 21:27:05 +02:00
m2049r
9e3a2b102e correct sed syntax 2018-09-25 20:53:58 +02:00
Johan Lindqvist
647ae9a565 Patch 1 (#414)
* Added Swedish translations

* Fixed spelling error
2018-09-23 08:38:20 +02:00
m2049r
2bbd20855f deal correctly with escaped strings (#419) 2018-09-22 11:20:31 +02:00
erciccione
b8fc5f910a add 'ErCiccione' to the credits (#417) 2018-09-21 18:26:22 +02:00
erciccione
01700cf780 update values-it/strings.xml (#413) 2018-09-21 14:39:05 +02:00
Lafudoci
2fa6286b0e Update zh-rTW translation for OpenAlias (#415) 2018-09-21 14:37:24 +02:00
jar'o Lee
0ac1680e75 Update strings.xml (#416)
new strings translated , minor fix of weird-sounding old translation (restore height)
2018-09-21 14:37:06 +02:00
el00ruobuob
bd9a98e0d8 French translation OpenAlias & Language menu (#412) 2018-09-21 14:36:47 +02:00
jenniferberger
8a5121e792 enhance build description (#271)
Writing a script to build the artifacts in a reproducible environment
- PATH for openssl build was not set
- branch for m2049r/monero.git was not set
2018-09-21 09:52:07 +02:00
212 changed files with 12922 additions and 2627 deletions

View File

@@ -3,11 +3,13 @@ jobs:
build:
working_directory: ~/code
docker:
- image: bitriseio/android-ndk
- image: circleci/android:api-28-ndk
environment:
JVM_OPTS: -Xmx3200m
steps:
- checkout
- run: yes | sdkmanager --licenses || exit 0
- run: yes | sdkmanager --update || exit 0
- restore_cache:
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
- run:

7
.gitignore vendored
View File

@@ -6,4 +6,11 @@
/captures
.externalNativeBuild
.DS_Store
/app/build
/app/release
/app/alpha
/app/prod
/app/alphaMainnet
/app/prodMainnet
/app/alphaStagenet
/app/prodStagenet

3
.idea/.gitignore generated vendored
View File

@@ -1,3 +0,0 @@
workspace.xml
markdown-*
misc.xml

1
.idea/.name generated
View File

@@ -1 +0,0 @@
xmrwallet

22
.idea/compiler.xml generated
View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@@ -1,3 +0,0 @@
<component name="CopyrightManager">
<settings default="" />
</component>

18
.idea/gradle.xml generated
View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

9
.idea/modules.xml generated
View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/xmrwallet.iml" filepath="$PROJECT_DIR$/xmrwallet.iml" />
</modules>
</component>
</project>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -22,12 +22,8 @@ Help us translate Monerujo! You can find instructions [On Taiga](https://taiga.g
You may lose all your Moneroj if you use this App. Be cautious when spending on the mainnet.
### Random Notes
- Based off monero v0.11.1.0
- currently only android32 (runs on 64-bit as well)
- works on the testnet & mainnet
- sync is slow due to 32-bit architecture
- works on the mainnet & stagenet
- use your own daemon - it's easy
- screen stays on until first sync is complete
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/
### TODO
@@ -43,13 +39,8 @@ of the "real" testnet. After creating a new wallet, make a **new** one by recov
The official monero client shows the same behaviour.
### HOW TO BUILD
No need to build. Binaries are included:
- openssl-1.0.2l
- monero-v0.12
- boost_1_58_0
If you want to build them yourself (recommended) check out [the instructions](doc/BUILDING-external-libs.md)
See [the instructions](doc/BUILDING-external-libs.md)
Then, fire up Android Studio and build the APK.

3
app/.gitignore vendored
View File

@@ -1,3 +0,0 @@
.externalNativeBuild
build
app.iml

View File

@@ -7,13 +7,21 @@ add_library( monerujo
set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../external-libs)
############
# libsodium
############
add_library(sodium STATIC IMPORTED)
set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/libsodium/lib/${ANDROID_ABI}/libsodium.a)
############
# OpenSSL
############
add_library(crypto STATIC IMPORTED)
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.a)
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.a)
add_library(ssl STATIC IMPORTED)
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
@@ -184,5 +192,7 @@ target_link_libraries( monerujo
ssl
crypto
sodium
${log-lib}
)

View File

@@ -1,14 +1,15 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
buildToolsVersion '28.0.2'
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 27
versionCode 123
versionName "1.7.3 'OpenAlias'"
targetSdkVersion 28
versionCode 165
versionName "1.10.15 'Node-O-matiC'"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
@@ -18,6 +19,26 @@ android {
}
}
flavorDimensions 'type', 'net'
productFlavors {
mainnet {
dimension 'net'
}
stagenet {
dimension 'net'
applicationIdSuffix '.stage'
versionNameSuffix ' (stage)'
}
alpha {
dimension 'type'
applicationIdSuffix '.alpha'
versionNameSuffix ' (alpha)'
}
prod {
dimension 'type'
}
}
buildTypes {
release {
minifyEnabled false
@@ -27,6 +48,7 @@ android {
applicationIdSuffix ".debug"
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
@@ -61,9 +83,13 @@ android {
output ->
def abiName = output.getFilter(com.android.build.OutputFile.ABI)
output.versionCodeOverride = abiCodes.get(abiName, 0) + 10 * variant.versionCode
//def flavor = output.getFilter(flavor)
if (abiName == null) abiName = "universal"
def v = "${variant.versionName}".replaceFirst(" .*\$", "").replace(".", "x")
def v = "${variant.versionName}".replaceFirst(" '.*' ?", "")
.replace(".", "x")
.replace("(", "-")
.replace(")", "")
outputFileName = "$rootProject.ext.apkName-" + v + "_" + abiName + ".apk"
}
}
@@ -75,9 +101,11 @@ dependencies {
implementation "com.android.support:support-v4:$rootProject.ext.supportVersion"
implementation "com.android.support:recyclerview-v7:$rootProject.ext.supportVersion"
implementation "com.android.support:cardview-v7:$rootProject.ext.supportVersion"
implementation "com.android.support:swiperefreshlayout:$rootProject.ext.supportVersion"
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
implementation "com.squareup.okhttp3:okhttp:$rootProject.ext.okHttpVersion"
implementation "com.burgstaller:okhttp-digest:1.18"
implementation "com.jakewharton.timber:timber:$rootProject.ext.timberVersion"
implementation 'com.nulab-inc:zxcvbn:1.2.3'
@@ -85,10 +113,12 @@ dependencies {
implementation 'dnsjava:dnsjava:2.1.8'
implementation 'org.jitsi:dnssecjava:1.1.3'
implementation 'org.slf4j:slf4j-nop:1.7.25'
implementation 'com.github.brnunes:swipeablerecyclerview:1.0.2'
testImplementation "junit:junit:$rootProject.ext.junitVersion"
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
testImplementation 'org.json:json:20140107'
testImplementation 'net.jodah:concurrentunit:0.4.2'
testImplementation 'org.json:json:20180813'
testImplementation 'net.jodah:concurrentunit:0.4.4'
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">monerujo - Debug</string>
</resources>

View File

@@ -7,8 +7,10 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name=".XmrWalletApplication"
@@ -16,7 +18,8 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/MyMaterialTheme">
android:theme="@style/MyMaterialTheme"
android:usesCleartextTraffic="true">
<activity
android:name=".WalletActivity"
@@ -43,7 +46,7 @@
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />
</activity>
<service
android:name=".service.WalletService"
android:description="@string/service_description"

View File

@@ -43,6 +43,9 @@ Copyright (c) 2014 Dushyanth Maguluru
<h3>AndroidLicensesPage (https://github.com/adamsp/AndroidLicensesPage)</h3>
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>
http://www.apache.org/licenses/<br/>
<br/>

View File

@@ -0,0 +1,88 @@
// Copyright (c) 2017-2018, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if defined(HAVE_MONERUJO)
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief LedgerFind - find Ledger Device and return it's name
* @param buffer - buffer for name of found device
* @param len - length of buffer
* @return 0 - success
* -1 - no device connected / found
* -2 - JVM not found
*/
int LedgerFind(char *buffer, size_t len);
/**
* @brief LedgerExchange - exchange data with Ledger Device
* @param command - buffer for data to send
* @param cmd_len - length of send to send
* @param response - buffer for received data
* @param max_resp_len - size of receive buffer
*
* @return length of received data in response or -1 if error
*/
int LedgerExchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len);
#ifdef __cplusplus
}
#endif
#include "device_io.hpp"
#pragma once
namespace hw {
namespace io {
class device_io_monerujo: device_io {
public:
device_io_monerujo() {};
~device_io_monerujo() {};
void init() {};
void release() {};
void connect(void *params) {};
void disconnect() {};
bool connected() const {return true;}; // monerujo is always connected before it gets here
// returns number of bytes read or -1 on error
int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len) {
return LedgerExchange(command, cmd_len, response, max_resp_len);
}
};
};
};
#endif //#if defined(HAVE_MONERUJO)

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +0,0 @@
/**
* Copyright (c) 2018 m2049r
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef XMRWALLET_LEDGER_H
#define XMRWALLET_LEDGER_H
#ifdef __cplusplus
extern "C"
{
#endif
#define SCARD_S_SUCCESS ((LONG)0x00000000) /**< No error was encountered. */
#define SCARD_E_INSUFFICIENT_BUFFER ((LONG)0x80100008) /**< The data buffer to receive returned data is too small for the returned data. */
#define SCARD_E_NO_READERS_AVAILABLE ((LONG)0x8010002E) /**< Cannot find a smart card reader. */
typedef long LONG;
typedef unsigned long DWORD;
typedef DWORD *LPDWORD;
typedef unsigned char BYTE;
typedef BYTE *LPBYTE;
typedef const BYTE *LPCBYTE;
typedef char CHAR;
typedef CHAR *LPSTR;
int LedgerFind(char *buffer, size_t len);
LONG LedgerExchange(LPCBYTE pbSendBuffer, DWORD cbSendLength, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength);
#ifdef __cplusplus
}
#endif
#endif //XMRWALLET_LEDGER_H

View File

@@ -23,9 +23,9 @@ package com.btchip.comm;
import com.btchip.BTChipException;
public interface BTChipTransport {
public byte[] exchange(byte[] command);
byte[] exchange(byte[] command);
public void close();
void close();
public void setDebug(boolean debugFlag);
void setDebug(boolean debugFlag);
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2018 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.levin.data;
import com.m2049r.levin.util.HexHelper;
import com.m2049r.levin.util.LevinReader;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class Bucket {
// constants copied from monero p2p & epee
public final static int P2P_COMMANDS_POOL_BASE = 1000;
public final static int COMMAND_HANDSHAKE_ID = P2P_COMMANDS_POOL_BASE + 1;
public final static int COMMAND_TIMED_SYNC_ID = P2P_COMMANDS_POOL_BASE + 2;
public final static int COMMAND_PING_ID = P2P_COMMANDS_POOL_BASE + 3;
public final static int COMMAND_REQUEST_STAT_INFO_ID = P2P_COMMANDS_POOL_BASE + 4;
public final static int COMMAND_REQUEST_NETWORK_STATE_ID = P2P_COMMANDS_POOL_BASE + 5;
public final static int COMMAND_REQUEST_PEER_ID_ID = P2P_COMMANDS_POOL_BASE + 6;
public final static int COMMAND_REQUEST_SUPPORT_FLAGS_ID = P2P_COMMANDS_POOL_BASE + 7;
public final static long LEVIN_SIGNATURE = 0x0101010101012101L; // Bender's nightmare
public final static long LEVIN_DEFAULT_MAX_PACKET_SIZE = 100000000; // 100MB by default
public final static int LEVIN_PACKET_REQUEST = 0x00000001;
public final static int LEVIN_PACKET_RESPONSE = 0x00000002;
public final static int LEVIN_PROTOCOL_VER_0 = 0;
public final static int LEVIN_PROTOCOL_VER_1 = 1;
public final static int LEVIN_OK = 0;
public final static int LEVIN_ERROR_CONNECTION = -1;
public final static int LEVIN_ERROR_CONNECTION_NOT_FOUND = -2;
public final static int LEVIN_ERROR_CONNECTION_DESTROYED = -3;
public final static int LEVIN_ERROR_CONNECTION_TIMEDOUT = -4;
public final static int LEVIN_ERROR_CONNECTION_NO_DUPLEX_PROTOCOL = -5;
public final static int LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED = -6;
public final static int LEVIN_ERROR_FORMAT = -7;
public final static int P2P_SUPPORT_FLAG_FLUFFY_BLOCKS = 0x01;
public final static int P2P_SUPPORT_FLAGS = P2P_SUPPORT_FLAG_FLUFFY_BLOCKS;
final private long signature;
final private long cb;
final public boolean haveToReturnData;
final public int command;
final public int returnCode;
final private int flags;
final private int protcolVersion;
final byte[] payload;
final public Section payloadSection;
// create a request
public Bucket(int command, byte[] payload) throws IOException {
this.signature = LEVIN_SIGNATURE;
this.cb = payload.length;
this.haveToReturnData = true;
this.command = command;
this.returnCode = 0;
this.flags = LEVIN_PACKET_REQUEST;
this.protcolVersion = LEVIN_PROTOCOL_VER_1;
this.payload = payload;
payloadSection = LevinReader.readPayload(payload);
}
// create a response
public Bucket(int command, byte[] payload, int rc) throws IOException {
this.signature = LEVIN_SIGNATURE;
this.cb = payload.length;
this.haveToReturnData = false;
this.command = command;
this.returnCode = rc;
this.flags = LEVIN_PACKET_RESPONSE;
this.protcolVersion = LEVIN_PROTOCOL_VER_1;
this.payload = payload;
payloadSection = LevinReader.readPayload(payload);
}
public Bucket(DataInput in) throws IOException {
signature = in.readLong();
cb = in.readLong();
haveToReturnData = in.readBoolean();
command = in.readInt();
returnCode = in.readInt();
flags = in.readInt();
protcolVersion = in.readInt();
if (signature == Bucket.LEVIN_SIGNATURE) {
if (cb > Integer.MAX_VALUE)
throw new IllegalArgumentException();
payload = new byte[(int) cb];
in.readFully(payload);
} else
throw new IllegalStateException();
payloadSection = LevinReader.readPayload(payload);
}
public Section getPayloadSection() {
return payloadSection;
}
public void send(DataOutput out) throws IOException {
out.writeLong(signature);
out.writeLong(cb);
out.writeBoolean(haveToReturnData);
out.writeInt(command);
out.writeInt(returnCode);
out.writeInt(flags);
out.writeInt(protcolVersion);
out.write(payload);
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("sig: ").append(signature).append("\n");
sb.append("cb: ").append(cb).append("\n");
sb.append("call: ").append(haveToReturnData).append("\n");
sb.append("cmd: ").append(command).append("\n");
sb.append("rc: ").append(returnCode).append("\n");
sb.append("flags:").append(flags).append("\n");
sb.append("proto:").append(protcolVersion).append("\n");
sb.append(HexHelper.bytesToHex(payload)).append("\n");
sb.append(payloadSection.toString());
return sb.toString();
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright (c) 2018 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.levin.data;
import com.m2049r.levin.util.HexHelper;
import com.m2049r.levin.util.LevinReader;
import com.m2049r.levin.util.LevinWriter;
import com.m2049r.levin.util.LittleEndianDataOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Section {
// constants copied from monero p2p & epee
static final public int PORTABLE_STORAGE_SIGNATUREA = 0x01011101;
static final public int PORTABLE_STORAGE_SIGNATUREB = 0x01020101;
static final public byte PORTABLE_STORAGE_FORMAT_VER = 1;
static final public byte PORTABLE_RAW_SIZE_MARK_MASK = 0x03;
static final public byte PORTABLE_RAW_SIZE_MARK_BYTE = 0;
static final public byte PORTABLE_RAW_SIZE_MARK_WORD = 1;
static final public byte PORTABLE_RAW_SIZE_MARK_DWORD = 2;
static final public byte PORTABLE_RAW_SIZE_MARK_INT64 = 3;
static final long MAX_STRING_LEN_POSSIBLE = 2000000000; // do not let string be so big
// data types
static final public byte SERIALIZE_TYPE_INT64 = 1;
static final public byte SERIALIZE_TYPE_INT32 = 2;
static final public byte SERIALIZE_TYPE_INT16 = 3;
static final public byte SERIALIZE_TYPE_INT8 = 4;
static final public byte SERIALIZE_TYPE_UINT64 = 5;
static final public byte SERIALIZE_TYPE_UINT32 = 6;
static final public byte SERIALIZE_TYPE_UINT16 = 7;
static final public byte SERIALIZE_TYPE_UINT8 = 8;
static final public byte SERIALIZE_TYPE_DUOBLE = 9;
static final public byte SERIALIZE_TYPE_STRING = 10;
static final public byte SERIALIZE_TYPE_BOOL = 11;
static final public byte SERIALIZE_TYPE_OBJECT = 12;
static final public byte SERIALIZE_TYPE_ARRAY = 13;
static final public byte SERIALIZE_FLAG_ARRAY = (byte) 0x80;
private final Map<String, Object> entries = new HashMap<String, Object>();
public void add(String key, Object entry) {
entries.put(key, entry);
}
public int size() {
return entries.size();
}
public Set<Map.Entry<String, Object>> entrySet() {
return entries.entrySet();
}
public Object get(String key) {
return entries.get(key);
}
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("\n");
for (Map.Entry<String, Object> entry : entries.entrySet()) {
sb.append(entry.getKey()).append("=");
final Object value = entry.getValue();
if (value instanceof List) {
@SuppressWarnings("unchecked") final List<Object> list = (List<Object>) value;
for (Object listEntry : list) {
sb.append(listEntry.toString()).append("\n");
}
} else if (value instanceof String) {
sb.append("(").append(value).append(")\n");
} else if (value instanceof byte[]) {
sb.append(HexHelper.bytesToHex((byte[]) value)).append("\n");
} else {
sb.append(value.toString()).append("\n");
}
}
return sb.toString();
}
static public Section fromByteArray(byte[] buffer) {
try {
return LevinReader.readPayload(buffer);
} catch (IOException ex) {
throw new IllegalStateException();
}
}
public byte[] asByteArray() {
try {
ByteArrayOutputStream bas = new ByteArrayOutputStream();
DataOutput out = new LittleEndianDataOutputStream(bas);
LevinWriter writer = new LevinWriter(out);
writer.writePayload(this);
return bas.toByteArray();
} catch (IOException ex) {
throw new IllegalStateException();
}
}
}

View File

@@ -0,0 +1,196 @@
/*
* Copyright (c) 2018 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.levin.scanner;
import com.m2049r.xmrwallet.data.NodeInfo;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import timber.log.Timber;
public class Dispatcher implements PeerRetriever.OnGetPeers {
static final public int NUM_THREADS = 50;
static final public int MAX_PEERS = 1000;
static final public long MAX_TIME = 30000000000L; //30 seconds
private int peerCount = 0;
final private Set<NodeInfo> knownNodes = new HashSet<>(); // set of nodes to test
final private Set<NodeInfo> rpcNodes = new HashSet<>(); // set of RPC nodes we like
final private ExecutorService exeService = Executors.newFixedThreadPool(NUM_THREADS);
public interface Listener {
void onGet(NodeInfo nodeInfo);
}
private Listener listener;
public Dispatcher(Listener listener) {
this.listener = listener;
}
public Set<NodeInfo> getRpcNodes() {
return rpcNodes;
}
public int getPeerCount() {
return peerCount;
}
public boolean getMorePeers() {
return peerCount < MAX_PEERS;
}
public void awaitTermination(int nodesToFind) {
try {
final long t = System.nanoTime();
while (!jobs.isEmpty()) {
try {
Timber.d("Remaining jobs %d", jobs.size());
final PeerRetriever retrievedPeer = jobs.poll().get();
if (retrievedPeer.isGood() && getMorePeers())
retrievePeers(retrievedPeer);
final NodeInfo nodeInfo = retrievedPeer.getNodeInfo();
Timber.d("Retrieved %s", nodeInfo);
if ((nodeInfo.isValid() || nodeInfo.isFavourite())) {
nodeInfo.setName();
rpcNodes.add(nodeInfo);
Timber.d("RPC: %s", nodeInfo);
// the following is not totally correct but it works (otherwise we need to
// load much more before filtering - but we don't have time
if (listener != null) listener.onGet(nodeInfo);
if (rpcNodes.size() >= nodesToFind) {
Timber.d("are we done here?");
filterRpcNodes();
if (rpcNodes.size() >= nodesToFind) {
Timber.d("we're done here");
break;
}
}
}
if (System.nanoTime() - t > MAX_TIME) break; // watchdog
} catch (ExecutionException ex) {
Timber.d(ex); // tell us about it and continue
}
}
} catch (InterruptedException ex) {
Timber.d(ex);
} finally {
Timber.d("Shutting down!");
exeService.shutdownNow();
try {
exeService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
} catch (InterruptedException ex) {
Timber.d(ex);
}
}
filterRpcNodes();
}
static final public int HEIGHT_WINDOW = 1;
private boolean testHeight(long height, long consensus) {
return (height >= (consensus - HEIGHT_WINDOW))
&& (height <= (consensus + HEIGHT_WINDOW));
}
private long calcConsensusHeight() {
Timber.d("Calc Consensus height from %d nodes", rpcNodes.size());
final Map<Long, Integer> nodeHeights = new TreeMap<Long, Integer>();
for (NodeInfo info : rpcNodes) {
if (!info.isValid()) continue;
Integer h = nodeHeights.get(info.getHeight());
if (h == null)
h = 0;
nodeHeights.put(info.getHeight(), h + 1);
}
long consensusHeight = 0;
long consensusCount = 0;
for (Map.Entry<Long, Integer> entry : nodeHeights.entrySet()) {
final long entryHeight = entry.getKey();
int count = 0;
for (long i = entryHeight - HEIGHT_WINDOW; i <= entryHeight + HEIGHT_WINDOW; i++) {
Integer v = nodeHeights.get(i);
if (v == null)
v = 0;
count += v;
}
if (count >= consensusCount) {
consensusCount = count;
consensusHeight = entryHeight;
}
Timber.d("%d - %d/%d", entryHeight, count, entry.getValue());
}
return consensusHeight;
}
private void filterRpcNodes() {
long consensus = calcConsensusHeight();
Timber.d("Consensus Height = %d for %d nodes", consensus, rpcNodes.size());
for (Iterator<NodeInfo> iter = rpcNodes.iterator(); iter.hasNext(); ) {
NodeInfo info = iter.next();
// don't remove favourites
if (!info.isFavourite()) {
if (!testHeight(info.getHeight(), consensus)) {
iter.remove();
Timber.d("Removed %s", info);
}
}
}
}
// TODO: does this NEED to be a ConcurrentLinkedDeque?
private ConcurrentLinkedDeque<Future<PeerRetriever>> jobs = new ConcurrentLinkedDeque<>();
private void retrievePeer(NodeInfo nodeInfo) {
if (knownNodes.add(nodeInfo)) {
Timber.d("\t%d:%s", knownNodes.size(), nodeInfo);
jobs.add(exeService.submit(new PeerRetriever(nodeInfo, this)));
peerCount++; // jobs.size() does not perform well
}
}
private void retrievePeers(PeerRetriever peer) {
for (LevinPeer levinPeer : peer.getPeers()) {
if (getMorePeers())
retrievePeer(new NodeInfo(levinPeer));
else
break;
}
}
public void seedPeers(Collection<NodeInfo> seedNodes) {
for (NodeInfo node : seedNodes) {
node.clear();
if (node.isFavourite()) {
rpcNodes.add(node);
if (listener != null) listener.onGet(node);
}
retrievePeer(node);
}
}
}

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

@@ -0,0 +1,231 @@
/*
* Copyright (c) 2018 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.levin.scanner;
import com.m2049r.levin.data.Bucket;
import com.m2049r.levin.data.Section;
import com.m2049r.levin.util.HexHelper;
import com.m2049r.levin.util.LittleEndianDataInputStream;
import com.m2049r.levin.util.LittleEndianDataOutputStream;
import com.m2049r.xmrwallet.data.NodeInfo;
import com.m2049r.xmrwallet.util.Helper;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import timber.log.Timber;
public class PeerRetriever implements Callable<PeerRetriever> {
static final public int CONNECT_TIMEOUT = 500; //ms
static final public int SOCKET_TIMEOUT = 500; //ms
static final public long PEER_ID = new Random().nextLong();
static final private byte[] HANDSHAKE = handshakeRequest().asByteArray();
static final private byte[] FLAGS_RESP = flagsResponse().asByteArray();
final private List<LevinPeer> peers = new ArrayList<>();
private NodeInfo nodeInfo;
private OnGetPeers onGetPeersCallback;
public interface OnGetPeers {
boolean getMorePeers();
}
public PeerRetriever(NodeInfo nodeInfo, OnGetPeers onGetPeers) {
this.nodeInfo = nodeInfo;
this.onGetPeersCallback = onGetPeers;
}
public NodeInfo getNodeInfo() {
return nodeInfo;
}
public boolean isGood() {
return !peers.isEmpty();
}
public List<LevinPeer> getPeers() {
return peers;
}
public PeerRetriever call() {
if (isGood()) // we have already been called?
throw new IllegalStateException();
// first check for an rpc service
nodeInfo.findRpcService();
if (onGetPeersCallback.getMorePeers())
try {
Timber.d("%s CONN", nodeInfo.getLevinSocketAddress());
if (!connect())
return this;
Bucket handshakeBucket = new Bucket(Bucket.COMMAND_HANDSHAKE_ID, HANDSHAKE);
handshakeBucket.send(getDataOutput());
while (true) {// wait for response (which may never come)
Bucket recv = new Bucket(getDataInput()); // times out after SOCKET_TIMEOUT
if ((recv.command == Bucket.COMMAND_HANDSHAKE_ID)
&& (!recv.haveToReturnData)) {
readAddressList(recv.payloadSection);
return this;
} else if ((recv.command == Bucket.COMMAND_REQUEST_SUPPORT_FLAGS_ID)
&& (recv.haveToReturnData)) {
Bucket flagsBucket = new Bucket(Bucket.COMMAND_REQUEST_SUPPORT_FLAGS_ID, FLAGS_RESP, 1);
flagsBucket.send(getDataOutput());
} else {// and ignore others
Timber.d("Ignored LEVIN COMMAND %d", recv.command);
}
}
} catch (IOException ex) {
} finally {
disconnect(); // we have what we want - byebye
Timber.d("%s DISCONN", nodeInfo.getLevinSocketAddress());
}
return this;
}
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")
List<Section> peerList = (List<Section>) section.get("local_peerlist_new");
if (peerList != null) {
for (Section peer : peerList) {
Section adr = (Section) peer.get("adr");
Integer type = (Integer) adr.get("type");
if ((type == null) || (type != 1))
continue;
Section addr = (Section) adr.get("addr");
if (addr == null)
continue;
Integer ip = (Integer) addr.get("m_ip");
if (ip == null)
continue;
Integer sport = (Integer) addr.get("m_port");
if (sport == null)
continue;
int port = sport;
if (port < 0) // port is unsigned
port = port + 0x10000;
InetAddress inet = HexHelper.toInetAddress(ip);
// make sure this is an address we want to talk to (i.e. a remote address)
if (!inet.isSiteLocalAddress() && !inet.isAnyLocalAddress()
&& !inet.isLoopbackAddress()
&& !inet.isMulticastAddress()
&& !inet.isLinkLocalAddress()) {
peers.add(new LevinPeer(inet, port, topVersion, currentHeight, topId));
}
}
}
}
private Socket socket = null;
private boolean connect() {
if (socket != null) throw new IllegalStateException();
try {
socket = new Socket();
socket.connect(nodeInfo.getLevinSocketAddress(), CONNECT_TIMEOUT);
socket.setSoTimeout(SOCKET_TIMEOUT);
} catch (IOException ex) {
//Timber.d(ex);
return false;
}
return true;
}
private boolean isConnected() {
return socket.isConnected();
}
private void disconnect() {
try {
dataInput = null;
dataOutput = null;
if ((socket != null) && (!socket.isClosed())) {
socket.close();
}
} catch (IOException ex) {
Timber.d(ex);
} finally {
socket = null;
}
}
private DataOutput dataOutput = null;
private DataOutput getDataOutput() throws IOException {
if (dataOutput == null)
synchronized (this) {
if (dataOutput == null)
dataOutput = new LittleEndianDataOutputStream(
socket.getOutputStream());
}
return dataOutput;
}
private DataInput dataInput = null;
private DataInput getDataInput() throws IOException {
if (dataInput == null)
synchronized (this) {
if (dataInput == null)
dataInput = new LittleEndianDataInputStream(
socket.getInputStream());
}
return dataInput;
}
static private Section handshakeRequest() {
Section section = new Section(); // root object
Section nodeData = new Section();
nodeData.add("local_time", (new Date()).getTime());
nodeData.add("my_port", 0);
byte[] networkId = Helper.hexToBytes("1230f171610441611731008216a1a110"); // mainnet
nodeData.add("network_id", networkId);
nodeData.add("peer_id", PEER_ID);
section.add("node_data", nodeData);
Section payloadData = new Section();
payloadData.add("cumulative_difficulty", 1L);
payloadData.add("current_height", 1L);
byte[] genesisHash =
Helper.hexToBytes("418015bb9ae982a1975da7d79277c2705727a56894ba0fb246adaabb1f4632e3");
payloadData.add("top_id", genesisHash);
payloadData.add("top_version", (byte) 1);
section.add("payload_data", payloadData);
return section;
}
static private Section flagsResponse() {
Section section = new Section(); // root object
section.add("support_flags", Bucket.P2P_SUPPORT_FLAGS);
return section;
}
}

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