diff options
author | Vincent Breitmoser <valodim@mugenguild.com> | 2015-09-28 18:27:29 +0200 |
---|---|---|
committer | Vincent Breitmoser <valodim@mugenguild.com> | 2015-09-28 18:27:29 +0200 |
commit | 0e613aff2e617ca12c1b2e1032b21334c2ca674a (patch) | |
tree | 4e16d6a086cbe12875454fba520241ac84e277c7 | |
parent | b65a23f2d46f905160b47e044de12cf9177dfd51 (diff) | |
parent | 3df9bea4554c0edddce57aa6a2e32cfe5250ed72 (diff) | |
download | open-keychain-0e613aff2e617ca12c1b2e1032b21334c2ca674a.tar.gz open-keychain-0e613aff2e617ca12c1b2e1032b21334c2ca674a.tar.bz2 open-keychain-0e613aff2e617ca12c1b2e1032b21334c2ca674a.zip |
Merge remote-tracking branch 'origin/master' into encrypted-export
71 files changed, 2100 insertions, 745 deletions
diff --git a/Graphics/get-material-icons.sh b/Graphics/get-material-icons.sh index b6a2515c9..999680751 100755 --- a/Graphics/get-material-icons.sh +++ b/Graphics/get-material-icons.sh @@ -4,6 +4,7 @@ python copy OpenKeychain action white search 24 python copy OpenKeychain navigation white arrow_back 24 python copy OpenKeychain navigation white close 24 python copy OpenKeychain navigation white check 24 +python copy OpenKeychain navigation black check 24 python copy OpenKeychain navigation black expand_less 24 python copy OpenKeychain navigation black expand_more 24 python copy OpenKeychain navigation white refresh 24 diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle index 9d29d0a98..39681fd05 100644 --- a/OpenKeychain/build.gradle +++ b/OpenKeychain/build.gradle @@ -57,7 +57,8 @@ dependencies { compile 'com.mikepenz.iconics:meteocons-typeface:1.1.1@aar' compile 'com.mikepenz.iconics:community-material-typeface:1.0.0@aar' compile 'com.nispok:snackbar:2.11.0' - compile 'com.squareup.okhttp:okhttp:2.4.0' + compile 'com.squareup.okhttp:okhttp:2.5.0' + compile 'com.squareup.okhttp:okhttp-urlconnection:2.5.0' compile 'org.apache.james:apache-mime4j-core:0.7.2' compile 'org.apache.james:apache-mime4j-dom:0.7.2' compile 'org.thoughtcrime.ssl.pinning:AndroidPinning:1.0.0' @@ -91,31 +92,38 @@ dependencyVerification { 'com.jpardogo.materialtabstrip:library:c6ef812fba4f74be7dc4a905faa4c2908cba261a94c13d4f96d5e67e4aad4aaa', 'com.getbase:floatingactionbutton:052aa2a94e49e5dccc97cb99f2add87e8698b84859f0e3ac181100c0bc7640ca', 'org.commonjava.googlecode.markdown4j:markdown4j:e952e825d29e1317d96f79f346bfb6786c7c5eef50bd26e54a80823704b62e13', + 'org.ocpsoft.prettytime:prettytime:a6bc2641b3ab7873df604b77b6680c75b86d98e78afefb367940972f925591b5', 'com.splitwise:tokenautocomplete:20bee71cc59b3828eb000b684d46ddf738efd56b8fee453a509cd16fda42c8cb', 'se.emilsjolander:stickylistheaders:8c05981ec5725be33f7cee5e68c13f3db49cd5c75f1aaeb04024920b1ef96ad4', + 'com.mikepenz:materialdrawer:70c3efb3842461db41df6a918ea93969a7da21e63c092be838b153e5a47a17bf', 'org.sufficientlysecure:html-textview:1d3bed31ef837437154de8d2362a0e6b0e59b6c3535d87ee48c2fab12c84f9bb', + 'com.mikepenz.iconics:octicons-typeface:67ed7d456a9ce5f5307b85f955797bfb3dd674e2f6defb31c6b8bbe2ede290be', 'com.mikepenz:iconics:c1a02203d8e0d638959463c00af3ab9096e0a7c1ad5928762eb10ef5ce8a63cd', - 'com.mikepenz:materialdrawer:70c3efb3842461db41df6a918ea93969a7da21e63c092be838b153e5a47a17bf', + 'com.mikepenz.iconics:community-material-typeface:f1c5afee5f0f10d66beb3ed0df977246a02a9c46de4e05d7c0264bcde53b6b7f', 'com.mikepenz.iconics:meteocons-typeface:39a8a9e70cd8287cdb119af57a672a41dd09240dba6697f5a0dbda1ccc33298b', - 'com.mikepenz.iconics:octicons-typeface:67ed7d456a9ce5f5307b85f955797bfb3dd674e2f6defb31c6b8bbe2ede290be', + 'com.squareup.okhttp:okhttp:1cc716e29539adcda677949508162796daffedb4794cbf947a6f65e696f0381c', 'com.nispok:snackbar:46b5eb9d630d329e13c2ce00ee9fb115ffb66c23c72cff32ee97eedd76824c6f', - 'com.mikepenz.iconics:community-material-typeface:f1c5afee5f0f10d66beb3ed0df977246a02a9c46de4e05d7c0264bcde53b6b7f', - 'com.squareup.okhttp:okhttp:bc0da7ac1f5441619faa2082811938acf7df97e4a8e08f0e043ff4937414d5ad', -// 'OpenKeychain.extern.openkeychain-api-lib:openkeychain-intents:111d7d53b9e920ad3405f8f3eb0ab7bd3aee66d577442452754b83c7c1c1d49a', -// 'OpenKeychain.extern.openpgp-api-lib:openpgp-api:544b7b2e20955556b83d1b72763543aa789836ebc1e77b332ed7cd83ef765c4a', -// 'com.madgag.spongycastle:core:97276487be598747ba78c063c90cea7fc3c7ad9bc7aeba03c0b9c98692052b8a', -// 'com.madgag.spongycastle:pkix:979aa4b2aaef94866e0f97b05b1922244eaf8b650f3691a3c44760ff0a41562b', -// 'com.madgag.spongycastle:pg:da319de706d946f178140959c74aec126f7803f1104dbad89bb1f55a53f6e1a9', -// 'OpenKeychain.extern:minidns:8274d50124d9584e95df0c5da7798269ac9caf0eab560df929c2c658ca624037', -// 'com.madgag.spongycastle:prov:902a484219bbf4e395a1c32da65b2453133e195bcc92336dc8c33b7c58edcd60', + 'org.apache.james:apache-mime4j-core:4d7434c68f94b81a253c12f28e6bbb4d6239c361d6086a46e22e594bb43ac660', + 'com.squareup.okhttp:okhttp-urlconnection:79ec6f4e79e683105e87fe83278a531c693e538d30e3b9237000ce7c94fcb2cf', + 'org.thoughtcrime.ssl.pinning:AndroidPinning:afa1d74e699257fa75cb109ff29bac50726ef269c6e306bdeffe8223cee06ef4', + 'org.apache.james:apache-mime4j-dom:7e6b06ee164a1c21b7e477249ea0b74a18fddce44764e5764085f58dd8c34633', +// 'OpenKeychain.extern.openpgp-api-lib:openpgp-api:a3f8b2ed40aaf12169e2a4e1f25e3764aa5ccb430683e1e7ca7867471eaf2bba', + 'com.cocosw:bottomsheet:871f5f4d6c10936569caf3528271efd77594a67aa5511765c96d7096c9b05f96', +// 'OpenKeychain.extern.spongycastle:core:6006a83fa427f4e5c8c93458176ab5e3b54d8dba7942171cb76cb134fc574c58', +// 'OpenKeychain.extern.openkeychain-api-lib:openkeychain-intents:8582442aa26e13c5a4bdf3588a22cb94b2fa5de6c79b84244fb575aa401fc330', +// 'OpenKeychain.extern.spongycastle:pg:0fd64a60311c5557f230bec9b2b162c9e6e690ccc83ac6b5af6a8d616309da98', +// 'OpenKeychain.extern.spongycastle:pkix:2348474aa27cb0461a368191d4d8fe7479a212b6365b177da131f4efa4c57f24', +// 'OpenKeychain.extern.spongycastle:prov:85c9ed6e24c5c7e5f7ff7c22d367bb553d020693350bd1c75555e6895311bb69', +// 'OpenKeychain.extern.safeslinger-exchange:safeslinger-exchange:274b71f8a1c383fb506342fd0f614b4a0cdb25517b5b2a1dfef9a4a2575477ed', 'com.android.support:support-annotations:beac5cae60bdb597df9af9c916f785c2f71f8c8ae4be9a32d4298dea85496a42', -// 'OpenKeychain.extern.KeybaseLib:Lib:d52e7888cea6de9e077501bb533270b2a86b52cb8af49e5f44ee8c4bb19ea017', -// 'OpenKeychain.extern.safeslinger-exchange:safeslinger-exchange:76e5da6b4f5f8835b12649e17569f0d0d8d89552815a61383c128545632689d1', - 'com.squareup.okio:okio:b53c1760864e1c39b5275d9023e2a6fbe8f3189e6e67b4c87877b8ec8f92e05a', +// 'OpenKeychain.extern:minidns:25e351fa4145e2a9b0a76658c48619b307f71432db7492e9e8a6b34aa2e9bdcf', +// 'OpenKeychain.extern.KeybaseLib:Lib:79c78c1054b58200028211e21f2c89012dc4a1eafdb00cc99a5ce1f61ad16937', + 'com.squareup.okio:okio:114bdc1f47338a68bcbc95abf2f5cdc72beeec91812f2fcd7b521c1937876266', ] } + android { compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index 1ef8b2eb3..11e86b28b 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -263,9 +263,7 @@ <action android:name="org.sufficientlysecure.keychain.action.DECRYPT_DATA" /> <category android:name="android.intent.category.DEFAULT" /> - - <data android:scheme="file" /> - <data android:scheme="content" /> + <data android:mimeType="*/*" /> </intent-filter> <!-- DECRYPT_TEXT --> diff --git a/OpenKeychain/src/main/assets/api.keybase.io.CA.cer b/OpenKeychain/src/main/assets/api.keybase.io.CA.cer new file mode 100644 index 000000000..c7da715c4 --- /dev/null +++ b/OpenKeychain/src/main/assets/api.keybase.io.CA.cer @@ -0,0 +1,38 @@ +-----BEGIN CERTIFICATE-----
+MIIGmzCCBIOgAwIBAgIJAPzhpcIBaOeNMA0GCSqGSIb3DQEBBQUAMIGPMQswCQYD
+VQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMRQwEgYDVQQK
+EwtLZXliYXNlIExMQzEXMBUGA1UECxMOQ2VydCBBdXRob3JpdHkxEzARBgNVBAMT
+CmtleWJhc2UuaW8xHDAaBgkqhkiG9w0BCQEWDWNhQGtleWJhc2UuaW8wHhcNMTQw
+MTAyMTY0MjMzWhcNMjMxMjMxMTY0MjMzWjCBjzELMAkGA1UEBhMCVVMxCzAJBgNV
+BAgTAk5ZMREwDwYDVQQHEwhOZXcgWW9yazEUMBIGA1UEChMLS2V5YmFzZSBMTEMx
+FzAVBgNVBAsTDkNlcnQgQXV0aG9yaXR5MRMwEQYDVQQDEwprZXliYXNlLmlvMRww
+GgYJKoZIhvcNAQkBFg1jYUBrZXliYXNlLmlvMIICIjANBgkqhkiG9w0BAQEFAAOC
+Ag8AMIICCgKCAgEA3sLA6ZG8uOvmlFvFLVIOURmcQrZyMFKbVu9/TeDiemls3w3/
+JzVTduD+7KiUi9R7QcCW/V1ZpReTfunm7rfACiJ1fpIkjSQrgsvKDLghIzxIS5FM
+I8utet5p6QtuJhaAwmmXn8xX05FvqWNbrcXRdpL4goFdigPsFK2xhTUiWatLMste
+oShI7+zmrgkx75LeLMD0bL2uOf87JjOzbY8x2sUIZLGwPoATyG8WS38ey6KkJxRj
+AhG3p+OTYEjYSrsAtQA6ImbeDpfSHKOB8HF3nVp//Eb4HEiEsWwBRbQXvAWh3DYL
+GukFW0wiO0HVCoWY+bHL/Mqa0NdRGOlLsbL4Z4pLrhqKgSDU8umX9YuNRRaB0P5n
+TkzyU6axHqzq990Gep/I62bjsBdYYp+DjSPK43mXRrfWJl2NTcl8xKAyfsOW+9hQ
+9vwK0tpSicNxfYuUZs0BhfjSZ/Tc6Z1ERdgUYRiXTtohl+SRA2IgZMloHCllVMNj
+EjXhguvHgLAOrcuyhVBupiUQGUHQvkMsr1Uz8VPNDFOJedwucRU2AaR881bknnSb
+ds9+zNLsvUFV+BK7Qdnt/WkFpYL78rGwY47msi9Ooddx6fPyeg3qkJGM6cwn/boy
+w9lQeleYDq8kyJdixIAxtAskNzRPJ4nDu2izTfByQoM8epwAWboc/gNFObMCAwEA
+AaOB9zCB9DAdBgNVHQ4EFgQURqpATOw1gVVrzlqqFKbkfaKXvwowgcQGA1UdIwSB
+vDCBuYAURqpATOw1gVVrzlqqFKbkfaKXvwqhgZWkgZIwgY8xCzAJBgNVBAYTAlVT
+MQswCQYDVQQIEwJOWTERMA8GA1UEBxMITmV3IFlvcmsxFDASBgNVBAoTC0tleWJh
+c2UgTExDMRcwFQYDVQQLEw5DZXJ0IEF1dGhvcml0eTETMBEGA1UEAxMKa2V5YmFz
+ZS5pbzEcMBoGCSqGSIb3DQEJARYNY2FAa2V5YmFzZS5pb4IJAPzhpcIBaOeNMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggIBAA3Z5FIhulYghMuHdcHYTYWc
+7xT5WD4hXQ0WALZs4p5Y+b2Af54o6v1wUE1Au97FORq5CsFXX/kGl/JzzTimeucn
+YJwGuXMpilrlHCBAL5/lSQjA7qbYIolQ3SB9ON+LYuF1jKB9k8SqNp7qzucxT3tO
+b8ZMDEPNsseC7NE2uwNtcW3yrTh6WZnSqg/jwswiWjHYDdG7U8FjMYlRol3wPux2
+PizGbSgiR+ztI2OthxtxNWMrT9XKxNQTpcxOXnLuhiSwqH8PoY17ecP8VPpaa0K6
+zym0zSkbroqydazaxcXRk3eSlc02Ktk7HzRzuqQQXhRMkxVnHbFHgGsz03L533pm
+mlIEgBMggZkHwNvs1LR7f3v2McdKulDH7Mv8yyfguuQ5Jxxt7RJhUuqSudbEhoaM
+6jAJwBkMFxsV2YnyFEd3eZ/qBYPf7TYHhyzmHW6WkSypGqSnXd4gYpJ8o7LxSf4F
+inLjxRD+H9Xn1UVXWLM0gaBB7zZcXd2zjMpRsWgezf5IR5vyakJsc7fxzgor3Qeq
+Ri6LvdEkhhFVl5rHMQBwNOPngySrq8cs/ikTLTfQVTYXXA4Ba1YyiMOlfaR1LhKw
+If1AkUV0tfCTNRZ01EotKSK77+o+k214n+BAu+7mO+9B5Kb7lMFQcuWCHXKYB2Md
+cT7Yh09F0QpFUd0ymEfv
+-----END CERTIFICATE-----
diff --git a/OpenKeychain/src/main/assets/sks-keyservers.netCA.cer b/OpenKeychain/src/main/assets/hkps.pool.sks-keyservers.net.CA.cer index 24a2ad2e8..24a2ad2e8 100644 --- a/OpenKeychain/src/main/assets/sks-keyservers.netCA.cer +++ b/OpenKeychain/src/main/assets/hkps.pool.sks-keyservers.net.CA.cer diff --git a/OpenKeychain/src/main/assets/pgp.mit.edu.cer b/OpenKeychain/src/main/assets/pgp.mit.edu.cer new file mode 100644 index 000000000..7249b3611 --- /dev/null +++ b/OpenKeychain/src/main/assets/pgp.mit.edu.cer @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE-----
+MIIFpzCCBI+gAwIBAgIQSCQjuTbnogvWCWWHeCDMbzANBgkqhkiG9w0BAQsFADB2
+MQswCQYDVQQGEwJVUzELMAkGA1UECBMCTUkxEjAQBgNVBAcTCUFubiBBcmJvcjES
+MBAGA1UEChMJSW50ZXJuZXQyMREwDwYDVQQLEwhJbkNvbW1vbjEfMB0GA1UEAxMW
+SW5Db21tb24gUlNBIFNlcnZlciBDQTAeFw0xNDEwMDkwMDAwMDBaFw0xNzEwMDgy
+MzU5NTlaMIHlMQswCQYDVQQGEwJVUzEOMAwGA1UEERMFMDIxMzkxCzAJBgNVBAgT
+Ak1hMRIwEAYDVQQHEwlDYW1icmlkZ2UxHTAbBgNVBAkTFDc3IE1hc3NhY2h1c2V0
+dHMgQXZlMS4wLAYDVQQKEyVNYXNzYWNodXNldHRzIEluc3RpdHV0ZSBvZiBUZWNo
+bm9sb2d5MSowKAYDVQQLFCFJbmZvcm1hdGlvbiBTZXJ2aWNlcyAmIFRlY2hub2xv
+Z3kxFDASBgNVBAsTC1BsYXRpbnVtU1NMMRQwEgYDVQQDEwtwZ3AubWl0LmVkdTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOXCQWXwK1O/saHfUEJjeE6w
+VvTMe8xgl5qmkU+9U2TS6HdyVItD9fHZ3sAwVHo7mYtLGXp0S8F2hiiyLgQeQo84
+F/owinPaPU8c+2Ogw464HbROmjU7Vc/iHQklA0kR+lZsFwZuWd+nYjmPrNfm87Ik
+k9Wenco7wwFUquoJ8XZW1RVTr9WRWWlyNKwPnil5aBUGtbG6CP1+IFN75xfJYjz5
+g+JcLHYsKyb6JhPYxT42ZdgTPKVRJNuIpyOMXMIPB/qFgUyU+2T/g7vxoa3THllq
+vkp/ds5lpDe+uu6H9mbtMYvX5w9TBqt7YPegWcTUhGERnytXxeNpncYkzGMMUN0C
+AwEAAaOCAb8wggG7MB8GA1UdIwQYMBaAFB4Fo3ePbJbiW4dLprSGrHEADOc4MB0G
+A1UdDgQWBBRISoMA6cVQE5089wT6LFO4aiNnzTAOBgNVHQ8BAf8EBAMCBaAwDAYD
+VR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwZwYDVR0g
+BGAwXjBSBgwrBgEEAa4jAQQDAQEwQjBABggrBgEFBQcCARY0aHR0cHM6Ly93d3cu
+aW5jb21tb24ub3JnL2NlcnQvcmVwb3NpdG9yeS9jcHNfc3NsLnBkZjAIBgZngQwB
+AgIwRAYDVR0fBD0wOzA5oDegNYYzaHR0cDovL2NybC5pbmNvbW1vbi1yc2Eub3Jn
+L0luQ29tbW9uUlNBU2VydmVyQ0EuY3JsMHUGCCsGAQUFBwEBBGkwZzA+BggrBgEF
+BQcwAoYyaHR0cDovL2NydC51c2VydHJ1c3QuY29tL0luQ29tbW9uUlNBU2VydmVy
+Q0FfMi5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w
+FgYDVR0RBA8wDYILcGdwLm1pdC5lZHUwDQYJKoZIhvcNAQELBQADggEBAHbQqv2o
+LrRD8rMzaHvPHVa92gfi6bpEsiRsVw3kpH4D4k+PL9LWkgtgTWpM+MvskiUvS9ay
+FbWdXiy/peOj421fwnL/re9gmWs1g7FtUrDgIpz2T2jonPqbnIJPMHxI+ICWZMYH
+V/dO844geRKAiGs/UZbG4Uf1Jo0PxtPtD5puaUk4l9Va8WHU2OLq0kzS9K+iu/sx
+z0XG+fAMneyiXm5jtfjYE2W8/h61RhZulSUmYBkiMLzKr5eqe2VIkMqyTfyZ5zms
+1LZ1GWaouMsTBN1+2TXssQ71L1tIZg/lXJVlfVRkwOIV5Mp3ohxLSBZT8qNSef1v
+mFNa+DGU1sdl6m4=
+-----END CERTIFICATE-----
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index 311ef2d3b..ebd48b9a5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -91,14 +91,16 @@ public class KeychainApplication extends Application { } brandGlowEffect(getApplicationContext(), - FormattingUtils.getColorFromAttr(getApplicationContext(), R.attr.colorPrimary)); + FormattingUtils.getColorFromAttr(getApplicationContext(), R.attr.colorPrimary)); setupAccountAsNeeded(this); // Update keyserver list as needed Preferences.getPreferences(this).upgradePreferences(this); - TlsHelper.addStaticCA("pool.sks-keyservers.net", getAssets(), "sks-keyservers.netCA.cer"); + TlsHelper.addPinnedCertificate("hkps.pool.sks-keyservers.net", getAssets(), "hkps.pool.sks-keyservers.net.CA.cer"); + TlsHelper.addPinnedCertificate("pgp.mit.edu", getAssets(), "pgp.mit.edu.cer"); + TlsHelper.addPinnedCertificate("api.keybase.io", getAssets(), "api.keybase.io.CA.cer"); TemporaryStorageProvider.cleanUp(this); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/BitInputStream.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/BitInputStream.java new file mode 100644 index 000000000..b6ec7234e --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/BitInputStream.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) Andreas Jakl + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.experimental; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +/** + * The BitInputStream allows reading individual bits from a + * general Java InputStream. + * Like the various Stream-classes from Java, the BitInputStream + * has to be created based on another Input stream. It provides + * a function to read the next bit from the sream, as well as to read multiple + * bits at once and write the resulting data into an integer value. + * <p/> + * source: http://developer.nokia.com/Community/Wiki/Bit_Input/Output_Stream_utility_classes_for_efficient_data_transfer + */ +public class BitInputStream { + /** + * The Java InputStream this class is working on. + */ + private InputStream iIs; + + /** + * The buffer containing the currently processed + * byte of the input stream. + */ + private int iBuffer; + + /** + * Next bit of the current byte value that the user will + * get. If it's 8, the next bit will be read from the + * next byte of the InputStream. + */ + private int iNextBit = 8; + + /** + * Create a new bit input stream based on an existing Java InputStream. + * + * @param aIs the input stream this class should read the bits from. + */ + public BitInputStream(InputStream aIs) { + iIs = aIs; + } + + /** + * Read a specified number of bits and return them combined as + * an integer value. The bits are written to the integer + * starting at the highest bit ( << aNumberOfBits ), going down + * to the lowest bit ( << 0 ) + * + * @param aNumberOfBits defines how many bits to read from the stream. + * @return integer value containing the bits read from the stream. + * @throws IOException + */ + synchronized public int readBits(final int aNumberOfBits) + throws IOException { + int value = 0; + for (int i = aNumberOfBits - 1; i >= 0; i--) { + value |= (readBit() << i); + } + return value; + } + + synchronized public int available() { + try { + return (8 - iNextBit) + iIs.available() * 8; // bytestream to bitstream available + } catch (Exception e) { + return 0; + } + } + + /** + * Read the next bit from the stream. + * + * @return 0 if the bit is 0, 1 if the bit is 1. + * @throws IOException + */ + synchronized public int readBit() throws IOException { + if (iIs == null) + throw new IOException("Already closed"); + + if (iNextBit == 8) { + iBuffer = iIs.read(); + + if (iBuffer == -1) + throw new EOFException(); + + iNextBit = 0; + } + + int bit = iBuffer & (1 << iNextBit); + iNextBit++; + + bit = (bit == 0) ? 0 : 1; + + return bit; + } + + /** + * Close the underlying input stream. + * + * @throws IOException + */ + public void close() throws IOException { + iIs.close(); + iIs = null; + } +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/SentenceConfirm.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/SentenceConfirm.java new file mode 100644 index 000000000..ead70b8f6 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/SentenceConfirm.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2014 Jake McGinty (Open Whisper Systems) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.experimental; + +import android.content.Context; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +/** + * From https://github.com/mcginty/TextSecure/tree/mnemonic-poem + */ +public class SentenceConfirm { + Context context; + List<String> n, vi, vt, adj, adv, p, art; + + public SentenceConfirm(Context context) { + this.context = context; + try { + n = readFile(R.raw.fp_sentence_nouns); + vi = readFile(R.raw.fp_sentence_verbs_i); + vt = readFile(R.raw.fp_sentence_verbs_t); + adj = readFile(R.raw.fp_sentence_adjectives); + adv = readFile(R.raw.fp_sentence_adverbs); + p = readFile(R.raw.fp_sentence_prepositions); + art = readFile(R.raw.fp_sentence_articles); + } catch (IOException e) { + Log.e(Constants.TAG, "Reading sentence files failed", e); + } + } + + List<String> readFile(int resId) throws IOException { + if (context.getApplicationContext() == null) { + throw new AssertionError("app context can't be null"); + } + + BufferedReader in = new BufferedReader(new InputStreamReader( + context.getApplicationContext() + .getResources() + .openRawResource(resId))); + List<String> words = new ArrayList<>(); + String word = in.readLine(); + while (word != null) { + words.add(word); + word = in.readLine(); + } + in.close(); + return words; + } + + public String fromBytes(final byte[] bytes, int desiredBytes) throws IOException { + BitInputStream bin = new BitInputStream(new ByteArrayInputStream(bytes)); + EntropyString fingerprint = new EntropyString(); + + while (fingerprint.getBits() < (desiredBytes * 8)) { + if (!fingerprint.isEmpty()) { + fingerprint.append("\n\n"); + } + try { + fingerprint.append(getSentence(bin)); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException when creating the sentence"); + throw e; + } + } + return fingerprint.toString(); + } + + /** + * Grab a word for a list of them using the necessary bits to choose from a BitInputStream + * + * @param words the list of words to select from + * @param bin the bit input stream to encode from + * @return A Pair of the word and the number of bits consumed from the stream + */ + private EntropyString getWord(List<String> words, BitInputStream bin) throws IOException { + final int neededBits = log(words.size(), 2); + Log.d(Constants.TAG, "need " + neededBits + " bits of entropy"); + int bits = bin.readBits(neededBits); + Log.d(Constants.TAG, "got word " + words.get(bits) + " with " + neededBits + " bits of entropy"); + return new EntropyString(words.get(bits), neededBits); + } + + private EntropyString getNounPhrase(BitInputStream bits) throws IOException { + final EntropyString phrase = new EntropyString(); + phrase.append(getWord(art, bits)).append(" "); + if (bits.readBit() != 0) { + phrase.append(getWord(adj, bits)).append(" "); + } + phrase.incBits(); + + phrase.append(getWord(n, bits)); + Log.d(Constants.TAG, "got phrase " + phrase + " with " + phrase.getBits() + " bits of entropy"); + return phrase; + } + + EntropyString getSentence(BitInputStream bits) throws IOException { + final EntropyString sentence = new EntropyString(); + sentence.append(getNounPhrase(bits)); // Subject + if (bits.readBit() != 0) { + sentence.append(" ").append(getWord(vt, bits)); // Transitive verb + sentence.append(" ").append(getNounPhrase(bits)); // Object of transitive verb + } else { + sentence.append(" ").append(getWord(vi, bits)); // Intransitive verb + } + sentence.incBits(); + + if (bits.readBit() != 0) { + sentence.append(" ").append(getWord(adv, bits)); // Adverb + } + + sentence.incBits(); + if (bits.readBit() != 0) { + sentence.append(" ").append(getWord(p, bits)); // Preposition + sentence.append(" ").append(getNounPhrase(bits)); // Object of preposition + } + sentence.incBits(); + Log.d(Constants.TAG, "got sentence " + sentence + " with " + sentence.getBits() + " bits of entropy"); + + // uppercase first character, end with dot (without increasing the bits) + sentence.getBuilder().replace(0, 1, + Character.toString(Character.toUpperCase(sentence.getBuilder().charAt(0)))); + sentence.getBuilder().append("."); + + return sentence; + } + + public static class EntropyString { + private StringBuilder builder; + private int bits; + + public EntropyString(String phrase, int bits) { + this.builder = new StringBuilder(phrase); + this.bits = bits; + } + + public EntropyString() { + this("", 0); + } + + public StringBuilder getBuilder() { + return builder; + } + + public boolean isEmpty() { + return builder.length() == 0; + } + + public EntropyString append(EntropyString phrase) { + builder.append(phrase); + bits += phrase.getBits(); + return this; + } + + public EntropyString append(String string) { + builder.append(string); + return this; + } + + public int getBits() { + return bits; + } + + public void setBits(int bits) { + this.bits = bits; + } + + public void incBits() { + bits += 1; + } + + @Override + public String toString() { + return builder.toString(); + } + } + + private static int log(int x, int base) { + return (int) (Math.log(x) / Math.log(base)); + } + +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ExperimentalWordConfirm.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/WordConfirm.java index 43ccac24f..daf63ea9e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ExperimentalWordConfirm.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/WordConfirm.java @@ -15,12 +15,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -package org.sufficientlysecure.keychain.ui.util; +package org.sufficientlysecure.keychain.experimental; import android.content.Context; import org.spongycastle.util.Arrays; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.Log; import java.io.BufferedReader; @@ -29,7 +30,7 @@ import java.io.InputStreamReader; import java.util.ArrayList; import java.util.BitSet; -public class ExperimentalWordConfirm { +public class WordConfirm { public static String getWords(Context context, byte[] fingerprintBlob) { ArrayList<String> words = new ArrayList<>(); @@ -37,7 +38,7 @@ public class ExperimentalWordConfirm { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader( - context.getAssets().open("word_confirm_list.txt"), + context.getResources().openRawResource(R.raw.fp_word_list), "UTF-8" )); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java index d91dd28bc..4e68e76c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java @@ -77,7 +77,7 @@ public class CloudSearch { // kill threads that haven't returned yet thread.interrupt(); } - } catch (InterruptedException e) { + } catch (InterruptedException ignored) { } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java index 558b8ce7d..7473705f3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java @@ -23,6 +23,7 @@ import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -196,19 +197,23 @@ public class HkpKeyserver extends Keyserver { /** * returns a client with pinned certificate if necessary * - * @param url url to be queried by client + * @param url url to be queried by client * @param proxy proxy to be used by client - * @return client with a pinned certificate if necesary + * @return client with a pinned certificate if necessary */ public static OkHttpClient getClient(URL url, Proxy proxy) throws IOException { OkHttpClient client = new OkHttpClient(); try { - TlsHelper.pinCertificateIfNecessary(client, url); + TlsHelper.usePinnedCertificateIfAvailable(client, url); } catch (TlsHelper.TlsHelperException e) { Log.w(Constants.TAG, e); } + // don't follow any redirects + client.setFollowRedirects(false); + client.setFollowSslRedirects(false); + if (proxy != null) { client.setProxy(proxy); client.setConnectTimeout(30000, TimeUnit.MILLISECONDS); @@ -228,7 +233,7 @@ public class HkpKeyserver extends Keyserver { OkHttpClient client = getClient(url, proxy); Response response = client.newCall(new Request.Builder().url(url).build()).execute(); - String responseBody = response.body().string();// contains body both in case of success or failure + String responseBody = response.body().string(); // contains body both in case of success or failure if (response.isSuccessful()) { return responseBody; @@ -238,17 +243,12 @@ public class HkpKeyserver extends Keyserver { } catch (IOException e) { Log.e(Constants.TAG, "IOException at HkpKeyserver", e); throw new QueryFailedException("Keyserver '" + mHost + "' is unavailable. Check your Internet connection!" + - proxy == null?"":" Using proxy " + proxy); + (proxy == null ? "" : " Using proxy " + proxy)); } } /** * Results are sorted by creation date of key! - * - * @param query - * @return - * @throws QueryFailedException - * @throws QueryNeedsRepairException */ @Override public ArrayList<ImportKeysListEntry> search(String query, Proxy proxy) throws QueryFailedException, @@ -299,30 +299,46 @@ public class HkpKeyserver extends Keyserver { entry.setQuery(query); entry.addOrigin(getUrlPrefix() + mHost + ":" + mPort); - int bitSize = Integer.parseInt(matcher.group(3)); - entry.setBitStrength(bitSize); - int algorithmId = Integer.decode(matcher.group(2)); - entry.setAlgorithm(KeyFormattingUtils.getAlgorithmInfo(algorithmId, bitSize, null)); - // group 1 contains the full fingerprint (v4) or the long key id if available // see https://bitbucket.org/skskeyserver/sks-keyserver/pull-request/12/fixes-for-machine-readable-indexes/diff String fingerprintOrKeyId = matcher.group(1).toLowerCase(Locale.ENGLISH); - if (fingerprintOrKeyId.length() > 16) { + if (fingerprintOrKeyId.length() == 40) { entry.setFingerprintHex(fingerprintOrKeyId); entry.setKeyIdHex("0x" + fingerprintOrKeyId.substring(fingerprintOrKeyId.length() - 16, fingerprintOrKeyId.length())); - } else { + } else if (fingerprintOrKeyId.length() == 16) { // set key id only entry.setKeyIdHex("0x" + fingerprintOrKeyId); + } else { + Log.e(Constants.TAG, "Wrong length for fingerprint/long key id."); + // skip this key + continue; } - final long creationDate = Long.parseLong(matcher.group(4)); - final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - tmpGreg.setTimeInMillis(creationDate * 1000); - entry.setDate(tmpGreg.getTime()); + try { + int bitSize = Integer.parseInt(matcher.group(3)); + entry.setBitStrength(bitSize); + int algorithmId = Integer.decode(matcher.group(2)); + entry.setAlgorithm(KeyFormattingUtils.getAlgorithmInfo(algorithmId, bitSize, null)); + + final long creationDate = Long.parseLong(matcher.group(4)); + final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + tmpGreg.setTimeInMillis(creationDate * 1000); + entry.setDate(tmpGreg.getTime()); + } catch (NumberFormatException e) { + Log.e(Constants.TAG, "Conversation for bit size, algorithm, or creation date failed.", e); + // skip this key + continue; + } - entry.setRevoked(matcher.group(6).contains("r")); - entry.setExpired(matcher.group(6).contains("e")); + try { + entry.setRevoked(matcher.group(6).contains("r")); + entry.setExpired(matcher.group(6).contains("e")); + } catch (NullPointerException e) { + Log.e(Constants.TAG, "Check for revocation or expiry failed.", e); + // skip this key + continue; + } ArrayList<String> userIds = new ArrayList<>(); final String uidLines = matcher.group(7); @@ -340,6 +356,10 @@ public class HkpKeyserver extends Keyserver { tmp = URLDecoder.decode(tmp, "UTF8"); } catch (UnsupportedEncodingException ignored) { // will never happen, because "UTF8" is supported + } catch (IllegalArgumentException e) { + Log.e(Constants.TAG, "User ID encoding broken", e); + // skip this user id + continue; } } userIds.add(tmp); @@ -363,11 +383,14 @@ public class HkpKeyserver extends Keyserver { Log.d(Constants.TAG, "Failed to get key at HkpKeyserver", httpError); throw new QueryFailedException("not found"); } + if (data == null) { + throw new QueryFailedException("data is null"); + } Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data); if (matcher.find()) { return matcher.group(1); } - return null; + throw new QueryFailedException("data is null"); } @Override @@ -418,7 +441,7 @@ public class HkpKeyserver extends Keyserver { * Tries to find a server responsible for a given domain * * @return A responsible Keyserver or null if not found. - * TODO: PHILIP Add proxy functionality + * TODO: Add proxy functionality */ public static HkpKeyserver resolve(String domain) { try { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java index c2865410e..486d658f6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java @@ -19,12 +19,13 @@ package org.sufficientlysecure.keychain.keyimport; import com.textuality.keybase.lib.KeybaseException; import com.textuality.keybase.lib.Match; -import com.textuality.keybase.lib.Search; +import com.textuality.keybase.lib.KeybaseQuery; import com.textuality.keybase.lib.User; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.OkHttpKeybaseClient; import java.net.Proxy; import java.util.ArrayList; @@ -49,7 +50,9 @@ public class KeybaseKeyserver extends Keyserver { mQuery = query; try { - Iterable<Match> matches = Search.search(query, proxy); + KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient()); + keybaseQuery.setProxy(proxy); + Iterable<Match> matches = keybaseQuery.search(query); for (Match match : matches) { results.add(makeEntry(match)); } @@ -101,7 +104,9 @@ public class KeybaseKeyserver extends Keyserver { @Override public String get(String id, Proxy proxy) throws QueryFailedException { try { - return User.keyForUsername(id, proxy); + KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient()); + keybaseQuery.setProxy(proxy); + return User.keyForUsername(keybaseQuery, id); } catch (KeybaseException e) { throw new QueryFailedException(e.getMessage()); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java index 640b39f44..15e0d94e9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java @@ -62,15 +62,15 @@ public abstract class Keyserver { * query too short _or_ too many responses */ public static class QueryTooShortOrTooManyResponsesException extends QueryNeedsRepairException { - private static final long serialVersionUID = 2703768928624654514L; + private static final long serialVersionUID = 2703768928624654518L; } public static class AddKeyException extends Exception { private static final long serialVersionUID = -507574859137295530L; } - public abstract List<ImportKeysListEntry> search(String query, Proxy proxy) throws QueryFailedException, - QueryNeedsRepairException; + public abstract List<ImportKeysListEntry> search(String query, Proxy proxy) + throws QueryFailedException, QueryNeedsRepairException; public abstract String get(String keyIdHex, Proxy proxy) throws QueryFailedException; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java index d9e48af8a..7ec33874f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import android.content.Context; import android.net.Uri; import android.support.annotation.NonNull; +import android.text.TextUtils; import org.apache.james.mime4j.MimeException; import org.apache.james.mime4j.codec.DecodeMonitor; @@ -86,6 +87,11 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> { DecryptVerifyResult decryptResult = null; PgpDecryptVerifyInputParcel decryptInput = input.getDecryptInput(); + + if (!input.getMimeDecode() && decryptInput == null) { + throw new AssertionError("no decryption or mime decoding, this is probably a bug"); + } + if (decryptInput != null) { log.add(LogType.MSG_DATA_OPENPGP, 1); @@ -109,16 +115,33 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> { return new InputDataResult(InputDataResult.RESULT_ERROR, log); } + // inform the storage provider about the mime type for this uri + if (decryptResult.getDecryptionMetadata() != null) { + TemporaryStorageProvider.setMimeType(mContext, currentInputUri, + decryptResult.getDecryptionMetadata().getMimeType()); + } + } else { currentInputUri = input.getInputUri(); } - // If we aren't supposed to attempt mime decode, we are done here - if (!input.getMimeDecode()) { - - if (decryptInput == null) { - throw new AssertionError("no decryption or mime decoding, this is probably a bug"); + // don't even attempt if we know the data isn't suitable for mime content, or if we have a filename + boolean skipMimeParsing = false; + if (decryptResult != null && decryptResult.getDecryptionMetadata() != null) { + OpenPgpMetadata metadata = decryptResult.getDecryptionMetadata(); + String fileName = metadata.getFilename(); + String contentType = metadata.getMimeType(); + if (!TextUtils.isEmpty(fileName) + || contentType != null + && !contentType.startsWith("multipart/") + && !contentType.startsWith("text/") + && !contentType.startsWith("application/")) { + skipMimeParsing = true; } + } + + // If we aren't supposed to attempt mime decode after decryption, we are done here + if (skipMimeParsing || !input.getMimeDecode()) { log.add(LogType.MSG_DATA_SKIP_MIME, 1); @@ -309,25 +332,32 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> { log.add(LogType.MSG_DATA_MIME, 1); - // open current uri for input - InputStream in = mContext.getContentResolver().openInputStream(currentInputUri); - parser.parse(in); + try { - if (mSignedDataUri != null) { + // open current uri for input + InputStream in = mContext.getContentResolver().openInputStream(currentInputUri); + parser.parse(in); - if (decryptResult != null) { - decryptResult.setSignatureResult(mSignedDataResult.getSignatureResult()); - } else { - decryptResult = mSignedDataResult; - } + if (mSignedDataUri != null) { - // the actual content is the signed data now (and will be passed verbatim, if parsing fails) - currentInputUri = mSignedDataUri; - in = mContext.getContentResolver().openInputStream(currentInputUri); - // reset signed data result, to indicate to the parser that it is in the inner part - mSignedDataResult = null; - parser.parse(in); + if (decryptResult != null) { + decryptResult.setSignatureResult(mSignedDataResult.getSignatureResult()); + } else { + decryptResult = mSignedDataResult; + } + // the actual content is the signed data now (and will be passed verbatim, if parsing fails) + currentInputUri = mSignedDataUri; + in = mContext.getContentResolver().openInputStream(currentInputUri); + // reset signed data result, to indicate to the parser that it is in the inner part + mSignedDataResult = null; + parser.parse(in); + + } + } catch (MimeException e) { + // a mime error likely means that this wasn't mime data, after all + e.printStackTrace(); + log.add(LogType.MSG_DATA_MIME_BAD, 2); } // if we found data, return success @@ -363,10 +393,6 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> { e.printStackTrace(); log.add(LogType.MSG_DATA_ERROR_IO, 2); return new InputDataResult(InputDataResult.RESULT_ERROR, log); - } catch (MimeException e) { - e.printStackTrace(); - log.add(LogType.MSG_DATA_MIME_ERROR, 2); - return new InputDataResult(InputDataResult.RESULT_ERROR, log); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java index 8f1abde83..aaff0a07c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java @@ -20,39 +20,43 @@ package org.sufficientlysecure.keychain.operations; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.net.Proxy; -import java.util.ArrayList; -import java.util.List; - import android.content.Context; import android.support.annotation.NonNull; +import com.textuality.keybase.lib.KeybaseQuery; import com.textuality.keybase.lib.Proof; import com.textuality.keybase.lib.prover.Prover; -import de.measite.minidns.Client; -import de.measite.minidns.DNSMessage; -import de.measite.minidns.Question; -import de.measite.minidns.Record; -import de.measite.minidns.record.Data; -import de.measite.minidns.record.TXT; + import org.json.JSONObject; import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.KeybaseVerificationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; +import org.sufficientlysecure.keychain.util.OkHttpKeybaseClient; import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.Proxy; +import java.util.ArrayList; +import java.util.List; + +import de.measite.minidns.Client; +import de.measite.minidns.DNSMessage; +import de.measite.minidns.Question; +import de.measite.minidns.Record; +import de.measite.minidns.record.Data; +import de.measite.minidns.record.TXT; + public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificationParcel> { public KeybaseVerificationOperation(Context context, ProviderHelper providerHelper, @@ -83,6 +87,9 @@ public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificat log.add(OperationResult.LogType.MSG_KEYBASE_VERIFICATION, 0, requiredFingerprint); try { + KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient()); + keybaseQuery.setProxy(proxy); + String keybaseProof = keybaseInput.mKeybaseProof; Proof proof = new Proof(new JSONObject(keybaseProof)); mProgressable.setProgress(R.string.keybase_message_fetching_data, 0, 100); @@ -95,7 +102,7 @@ public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificat return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log); } - if (!prover.fetchProofData(proxy)) { + if (!prover.fetchProofData(keybaseQuery)) { log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_FETCH_PROOF, 1); return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 6ac34faa2..fc72a9ac2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -474,6 +474,7 @@ public abstract class OperationResult implements Parcelable { MSG_KC_UID_BAD (LogLevel.WARN, R.string.msg_kc_uid_bad), MSG_KC_UID_CERT_DUP (LogLevel.DEBUG, R.string.msg_kc_uid_cert_dup), MSG_KC_UID_DUP (LogLevel.DEBUG, R.string.msg_kc_uid_dup), + MSG_KC_UID_TOO_MANY (LogLevel.DEBUG, R.string.msg_kc_uid_too_many), MSG_KC_UID_FOREIGN (LogLevel.DEBUG, R.string.msg_kc_uid_foreign), MSG_KC_UID_NO_CERT (LogLevel.DEBUG, R.string.msg_kc_uid_no_cert), MSG_KC_UID_REVOKE_DUP (LogLevel.DEBUG, R.string.msg_kc_uid_revoke_dup), @@ -832,7 +833,7 @@ public abstract class OperationResult implements Parcelable { MSG_DATA_DETACHED_NESTED(LogLevel.WARN, R.string.msg_data_detached_nested), MSG_DATA_DETACHED_TRAILING (LogLevel.WARN, R.string.msg_data_detached_trailing), MSG_DATA_DETACHED_UNSUPPORTED (LogLevel.WARN, R.string.msg_data_detached_unsupported), - MSG_DATA_MIME_ERROR (LogLevel.ERROR, R.string.msg_data_mime_error), + MSG_DATA_MIME_BAD(LogLevel.INFO, R.string.msg_data_mime_bad), MSG_DATA_MIME_FILENAME (LogLevel.DEBUG, R.string.msg_data_mime_filename), MSG_DATA_MIME_LENGTH (LogLevel.DEBUG, R.string.msg_data_mime_length), MSG_DATA_MIME (LogLevel.DEBUG, R.string.msg_data_mime), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java index 007f686e8..36b4f5e1e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java @@ -52,13 +52,13 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants.key; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.BaseOperation; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -512,8 +512,9 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp PGPLiteralData literalData = (PGPLiteralData) dataChunk; String originalFilename = literalData.getFileName(); + // reject filenames with slashes completely (path traversal issue) if (originalFilename.contains("/")) { - originalFilename = originalFilename.substring(originalFilename.lastIndexOf('/')); + originalFilename = ""; } String mimeType = null; if (literalData.getFormat() == PGPLiteralData.TEXT diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index 5acf6dd41..c8cdbd59d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -456,11 +456,15 @@ public class UncachedKeyRing { // check for duplicate user ids if (processedUserIds.contains(userId)) { - log.add(LogType.MSG_KC_UID_DUP, - indent, userId); + log.add(LogType.MSG_KC_UID_DUP, indent, userId); // strip out the first found user id with this name modified = PGPPublicKey.removeCertification(modified, rawUserId); } + if (processedUserIds.size() > 100) { + log.add(LogType.MSG_KC_UID_TOO_MANY, indent, userId); + // strip out the user id + modified = PGPPublicKey.removeCertification(modified, rawUserId); + } processedUserIds.add(userId); PGPSignature selfCert = null; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index d7fb738fc..0f90f8141 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -54,7 +54,7 @@ import java.io.IOException; */ public class KeychainDatabase extends SQLiteOpenHelper { private static final String DATABASE_NAME = "openkeychain.db"; - private static final int DATABASE_VERSION = 12; + private static final int DATABASE_VERSION = 13; static Boolean apgHack = false; private Context mContext; @@ -296,6 +296,8 @@ public class KeychainDatabase extends SQLiteOpenHelper { // the api_accounts fix and the new update keys table return; } + case 13: + // do nothing here, just consolidate } @@ -306,6 +308,13 @@ public class KeychainDatabase extends SQLiteOpenHelper { mContext.getApplicationContext().startActivity(consolidateIntent); } + @Override + public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + // NOTE: downgrading the database is explicitly not allowed to prevent + // someone from exploiting old bugs to export the database + throw new RuntimeException("Downgrading the database is not allowed!"); + } + /** This method tries to import data from a provided database. * * The sole assumptions made on this db are that there is a key_rings table diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java index 552fa34c0..2409523bc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java @@ -33,12 +33,14 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.experimental.SentenceConfirm; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.util.ExperimentalWordConfirm; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; +import java.io.IOException; + public class CertifyFingerprintFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks<Cursor> { @@ -46,24 +48,26 @@ public class CertifyFingerprintFragment extends LoaderFragment implements static final int REQUEST_CERTIFY = 1; public static final String ARG_DATA_URI = "uri"; - public static final String ARG_ENABLE_WORD_CONFIRM = "enable_word_confirm"; + public static final String ARG_ENABLE_PHRASES_CONFIRM = "enable_word_confirm"; + private TextView mActionYes; private TextView mFingerprint; private TextView mIntro; + private TextView mHeader; private static final int LOADER_ID_UNIFIED = 0; private Uri mDataUri; - private boolean mEnableWordConfirm; + private boolean mEnablePhrasesConfirm; /** * Creates new instance of this fragment */ - public static CertifyFingerprintFragment newInstance(Uri dataUri, boolean enableWordConfirm) { + public static CertifyFingerprintFragment newInstance(Uri dataUri, boolean enablePhrasesConfirm) { CertifyFingerprintFragment frag = new CertifyFingerprintFragment(); Bundle args = new Bundle(); args.putParcelable(ARG_DATA_URI, dataUri); - args.putBoolean(ARG_ENABLE_WORD_CONFIRM, enableWordConfirm); + args.putBoolean(ARG_ENABLE_PHRASES_CONFIRM, enablePhrasesConfirm); frag.setArguments(args); @@ -75,11 +79,12 @@ public class CertifyFingerprintFragment extends LoaderFragment implements View root = super.onCreateView(inflater, superContainer, savedInstanceState); View view = inflater.inflate(R.layout.certify_fingerprint_fragment, getContainer()); - View actionNo = view.findViewById(R.id.certify_fingerprint_button_no); - View actionYes = view.findViewById(R.id.certify_fingerprint_button_yes); + TextView actionNo = (TextView) view.findViewById(R.id.certify_fingerprint_button_no); + mActionYes = (TextView) view.findViewById(R.id.certify_fingerprint_button_yes); mFingerprint = (TextView) view.findViewById(R.id.certify_fingerprint_fingerprint); mIntro = (TextView) view.findViewById(R.id.certify_fingerprint_intro); + mHeader = (TextView) view.findViewById(R.id.certify_fingerprint_fingerprint_header); actionNo.setOnClickListener(new View.OnClickListener() { @Override @@ -87,7 +92,7 @@ public class CertifyFingerprintFragment extends LoaderFragment implements getActivity().finish(); } }); - actionYes.setOnClickListener(new View.OnClickListener() { + mActionYes.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { certify(mDataUri); @@ -107,10 +112,12 @@ public class CertifyFingerprintFragment extends LoaderFragment implements getActivity().finish(); return; } - mEnableWordConfirm = getArguments().getBoolean(ARG_ENABLE_WORD_CONFIRM); + mEnablePhrasesConfirm = getArguments().getBoolean(ARG_ENABLE_PHRASES_CONFIRM); - if (mEnableWordConfirm) { - mIntro.setText(R.string.certify_fingerprint_text_words); + if (mEnablePhrasesConfirm) { + mIntro.setText(R.string.certify_fingerprint_text_phrases); + mHeader.setText(R.string.section_phrases); + mActionYes.setText(R.string.btn_match_phrases); } loadData(dataUri); @@ -160,7 +167,7 @@ public class CertifyFingerprintFragment extends LoaderFragment implements if (data.moveToFirst()) { byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); - if (mEnableWordConfirm) { + if (mEnablePhrasesConfirm) { displayWordConfirm(fingerprintBlob); } else { displayHexConfirm(fingerprintBlob); @@ -180,9 +187,16 @@ public class CertifyFingerprintFragment extends LoaderFragment implements } private void displayWordConfirm(byte[] fingerprintBlob) { - String fingerprint = ExperimentalWordConfirm.getWords(getActivity(), fingerprintBlob); +// String fingerprint = ExperimentalWordConfirm.getWords(getActivity(), fingerprintBlob); + + String fingerprint; + try { + fingerprint = new SentenceConfirm(getActivity()).fromBytes(fingerprintBlob, 16); + } catch (IOException ioe) { + fingerprint = "-"; + } - mFingerprint.setTextSize(24); + mFingerprint.setTextSize(18); mFingerprint.setTypeface(Typeface.DEFAULT, Typeface.BOLD); mFingerprint.setText(fingerprint); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 5eb9963f5..4e9a6f17d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -168,7 +168,7 @@ public class DecryptActivity extends BaseActivity { return; } - uris.add(intent.getData()); + uris.add(uri); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java index dcba595e9..a0650f8b1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java @@ -257,7 +257,6 @@ public class DecryptListFragment } OpenPgpMetadata metadata = result.mMetadata.get(index); - Uri saveUri = Uri.fromFile(activity.getExternalFilesDir(metadata.getMimeType())); mCurrentSaveFileUri = result.getOutputUris().get(index); String filename = metadata.getFilename(); @@ -266,8 +265,8 @@ public class DecryptListFragment filename = "decrypted" + (ext != null ? "."+ext : ""); } - FileHelper.saveDocument(this, filename, saveUri, metadata.getMimeType(), - R.string.title_decrypt_to_file, R.string.specify_file_to_decrypt_to, REQUEST_CODE_OUTPUT); + FileHelper.saveDocument(this, filename, metadata.getMimeType(), + REQUEST_CODE_OUTPUT); } private void saveFile(Uri saveUri) { @@ -376,10 +375,12 @@ public class DecryptListFragment // noinspection deprecation, this should be called from Context, but not available in minSdk icon = getResources().getDrawable(R.drawable.ic_chat_black_24dp); } else if (ClipDescription.compareMimeTypes(type, "image/*")) { - int px = FormattingUtils.dpToPx(context, 48); + int px = FormattingUtils.dpToPx(context, 32); Bitmap bitmap = FileHelper.getThumbnail(context, outputUri, new Point(px, px)); icon = new BitmapDrawable(context.getResources(), bitmap); - } else { + } + + if (icon == null) { final Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(outputUri, type); @@ -445,6 +446,7 @@ public class DecryptListFragment displayWithViewIntent(result, index, true, true); break; case R.id.decrypt_save: + // only inside the menu xml for Android >= 4.4 saveFileDialog(result, index); break; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 8572a5712..0e357cfcd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -18,6 +18,7 @@ package org.sufficientlysecure.keychain.ui; +import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Date; @@ -224,9 +225,8 @@ public class EncryptFilesFragment String targetName = (mEncryptFilenames ? "1" : FileHelper.getFilename(getActivity(), model.inputUri)) + (mUseArmor ? Constants.FILE_EXTENSION_ASC : Constants.FILE_EXTENSION_PGP_MAIN); - Uri inputUri = model.inputUri; - FileHelper.saveDocument(this, targetName, inputUri, - R.string.title_encrypt_to_file, R.string.specify_file_to_encrypt_to, REQUEST_CODE_OUTPUT); + FileHelper.saveDocument(this, targetName, + REQUEST_CODE_OUTPUT); } public void addFile(Intent data) { @@ -308,6 +308,17 @@ public class EncryptFilesFragment return true; } + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + + // Show save only on Android >= 4.4 (Document Provider) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + MenuItem save = menu.findItem(R.id.encrypt_save); + save.setVisible(false); + } + } + public void toggleUseArmor(MenuItem item, final boolean useArmor) { mUseArmor = useArmor; @@ -441,9 +452,29 @@ public class EncryptFilesFragment } - // prepares mOutputUris, either directly and returns false, or indirectly - // which returns true and will call cryptoOperation after mOutputUris has - // been set at a later point. + /** + * Checks that the input uris are not linked to our own internal storage. + * This prevents the encryption of our own database (-> export of whole database) + */ + private void securityCheckInternalStorage() { + for (FilesAdapter.ViewModel model : mFilesAdapter.mDataset) { + File fileInput = new File(model.inputUri.getPath()); + try { + // the canonical path of the file must not start with /data/data/org.sufficientlysecure.keychain/ + if (fileInput.getCanonicalPath().startsWith(getActivity().getApplicationInfo().dataDir)) { + throw new RuntimeException("Encrypting OpenKeychain's private files is not allowed!"); + } + } catch (IOException e) { + Log.e(Constants.TAG, "Getting canonical path failed!", e); + } + } + } + + /** + * Prepares mOutputUris, either directly and returns false, or indirectly + * which returns true and will call cryptoOperation after mOutputUris has + * been set at a later point. + */ private boolean prepareOutputStreams() { switch (mAfterEncryptAction) { @@ -519,6 +550,8 @@ public class EncryptFilesFragment } + securityCheckInternalStorage(); + return actionsParcel; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java index d8edbe4f8..5a8ab36bc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java @@ -155,7 +155,7 @@ public class SettingsKeyserverFragment extends Fragment implements RecyclerItemC data.getBoolean(AddEditKeyserverDialogFragment.MESSAGE_VERIFIED); if (verified) { Notify.create(getActivity(), - R.string.add_keyserver_verified, Notify.Style.OK).show(); + R.string.add_keyserver_connection_verified, Notify.Style.OK).show(); } else { Notify.create(getActivity(), R.string.add_keyserver_without_verification, @@ -177,26 +177,6 @@ public class SettingsKeyserverFragment extends Fragment implements RecyclerItemC } break; } - case AddEditKeyserverDialogFragment.MESSAGE_VERIFICATION_FAILED: { - AddEditKeyserverDialogFragment.FailureReason failureReason = - (AddEditKeyserverDialogFragment.FailureReason) data.getSerializable( - AddEditKeyserverDialogFragment.MESSAGE_FAILURE_REASON); - switch (failureReason) { - case CONNECTION_FAILED: { - Notify.create(getActivity(), - R.string.add_keyserver_connection_failed, - Notify.Style.ERROR).show(); - break; - } - case INVALID_URL: { - Notify.create(getActivity(), - R.string.add_keyserver_invalid_url, - Notify.Style.ERROR).show(); - break; - } - } - break; - } } } }; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java index 4a46896bc..6331aa384 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -107,7 +107,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements View vFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); View vFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard); View vKeyShareButton = view.findViewById(R.id.view_key_action_key_share); - View vKeySafeButton = view.findViewById(R.id.view_key_action_key_export); + View vKeySaveButton = view.findViewById(R.id.view_key_action_key_export); View vKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc); View vKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard); ImageButton vKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger); @@ -133,7 +133,11 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements share(false, false); } }); - vKeySafeButton.setOnClickListener(new View.OnClickListener() { + // Show save only on Android >= 4.4 (Document Provider) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + vKeySaveButton.setVisibility(View.GONE); + } + vKeySaveButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { exportToFile(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeybaseFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeybaseFragment.java index 266633061..11c032517 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeybaseFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeybaseFragment.java @@ -40,6 +40,7 @@ import android.widget.TableRow; import android.widget.TextView; import com.textuality.keybase.lib.KeybaseException; +import com.textuality.keybase.lib.KeybaseQuery; import com.textuality.keybase.lib.Proof; import com.textuality.keybase.lib.User; @@ -51,6 +52,7 @@ import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.OkHttpKeybaseClient; import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; @@ -224,8 +226,9 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements } } - // look for evidence from keybase in the background, make tabular version of result - // + /** + * look for evidence from keybase in the background, make tabular version of result + */ private class DescribeKey extends AsyncTask<String, Void, ResultPage> { ParcelableProxy mParcelableProxy; @@ -240,7 +243,9 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements final ArrayList<CharSequence> proofList = new ArrayList<CharSequence>(); final Hashtable<Integer, ArrayList<Proof>> proofs = new Hashtable<Integer, ArrayList<Proof>>(); try { - User keybaseUser = User.findByFingerprint(fingerprint, mParcelableProxy.getProxy()); + KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient()); + keybaseQuery.setProxy(mParcelableProxy.getProxy()); + User keybaseUser = User.findByFingerprint(keybaseQuery, fingerprint); for (Proof proof : keybaseUser.getProofs()) { Integer proofType = proof.getType(); appendIfOK(proofs, proofType, proof); @@ -266,7 +271,12 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements } catch (KeybaseException ignored) { } - return new ResultPage(getString(R.string.key_trust_results_prefix), proofList); + String prefix = ""; + if (isAdded()) { + prefix = getString(R.string.key_trust_results_prefix); + } + + return new ResultPage(prefix, proofList); } private SpannableStringBuilder formatSpannableString(SpannableStringBuilder proofLinks, String proofType) { @@ -291,7 +301,10 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements if (haveProofFor(proof.getType())) { ssb.append("\u00a0["); startAt = ssb.length(); - String verify = getString(R.string.keybase_verify); + String verify = ""; + if (isAdded()) { + verify = getString(R.string.keybase_verify); + } ssb.append(verify); ClickableSpan clicker = new ClickableSpan() { @Override @@ -308,6 +321,11 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements @Override protected void onPostExecute(ResultPage result) { super.onPostExecute(result); + // stop if fragment is no longer added to an activity + if(!isAdded()) { + return; + } + if (result.mProofs.isEmpty()) { result.mHeader = getActivity().getString(R.string.key_trust_no_cloud_evidence); } @@ -356,7 +374,12 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements default: stringIndex = R.string.keybase_narrative_unknown; } - return getActivity().getString(stringIndex); + + if (isAdded()) { + return getString(stringIndex); + } else { + return ""; + } } private void appendIfOK(Hashtable<Integer, ArrayList<Proof>> table, Integer proofType, Proof proof) throws KeybaseException { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java index 47bc7dfda..3d96f3c6d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java @@ -24,6 +24,7 @@ import java.net.URI; import java.net.URISyntaxException; import android.app.Activity; +import android.support.design.widget.TextInputLayout; import android.support.v7.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; @@ -44,6 +45,7 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; @@ -54,6 +56,7 @@ import com.squareup.okhttp.Request; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; +import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.TlsHelper; @@ -68,11 +71,9 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On private static final String ARG_KEYSERVER = "arg_keyserver"; public static final int MESSAGE_OKAY = 1; - public static final int MESSAGE_VERIFICATION_FAILED = 2; public static final String MESSAGE_KEYSERVER = "new_keyserver"; public static final String MESSAGE_VERIFIED = "verified"; - public static final String MESSAGE_FAILURE_REASON = "failure_reason"; public static final String MESSAGE_KEYSERVER_DELETED = "keyserver_deleted"; public static final String MESSAGE_DIALOG_ACTION = "message_dialog_action"; public static final String MESSAGE_EDIT_POSITION = "keyserver_edited_position"; @@ -82,7 +83,9 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On private int mPosition; private EditText mKeyserverEditText; + private TextInputLayout mKeyserverEditTextLayout; private CheckBox mVerifyKeyserverCheckBox; + private CheckBox mOnlyTrustedKeyserverCheckBox; public enum DialogAction { ADD, @@ -91,7 +94,8 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On public enum FailureReason { INVALID_URL, - CONNECTION_FAILED + CONNECTION_FAILED, + NO_PINNED_CERTIFICATE } public static AddEditKeyserverDialogFragment newInstance(Messenger messenger, @@ -126,7 +130,15 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On alert.setView(view); mKeyserverEditText = (EditText) view.findViewById(R.id.keyserver_url_edit_text); - mVerifyKeyserverCheckBox = (CheckBox) view.findViewById(R.id.verify_keyserver_checkbox); + mKeyserverEditTextLayout = (TextInputLayout) view.findViewById(R.id.keyserver_url_edit_text_layout); + mVerifyKeyserverCheckBox = (CheckBox) view.findViewById(R.id.verify_connection_checkbox); + mOnlyTrustedKeyserverCheckBox = (CheckBox) view.findViewById(R.id.only_trusted_keyserver_checkbox); + mVerifyKeyserverCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mOnlyTrustedKeyserverCheckBox.setEnabled(isChecked); + } + }); switch (mDialogAction) { case ADD: { @@ -212,6 +224,8 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On positiveButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + mKeyserverEditTextLayout.setErrorEnabled(false); + // behaviour same for edit and add final String keyserverUrl = mKeyserverEditText.getText().toString(); if (mVerifyKeyserverCheckBox.isChecked()) { @@ -220,13 +234,20 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On OrbotHelper.DialogActions dialogActions = new OrbotHelper.DialogActions() { @Override public void onOrbotStarted() { - verifyConnection(keyserverUrl, - proxyPrefs.parcelableProxy.getProxy()); + verifyConnection( + keyserverUrl, + proxyPrefs.parcelableProxy.getProxy(), + mOnlyTrustedKeyserverCheckBox.isChecked() + ); } @Override public void onNeutralButton() { - verifyConnection(keyserverUrl, null); + verifyConnection( + keyserverUrl, + null, + mOnlyTrustedKeyserverCheckBox.isChecked() + ); } @Override @@ -236,7 +257,11 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On }; if (OrbotHelper.putOrbotInRequiredState(dialogActions, getActivity())) { - verifyConnection(keyserverUrl, proxyPrefs.parcelableProxy.getProxy()); + verifyConnection( + keyserverUrl, + proxyPrefs.parcelableProxy.getProxy(), + mOnlyTrustedKeyserverCheckBox.isChecked() + ); } } else { dismiss(); @@ -272,14 +297,28 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On sendMessageToHandler(MESSAGE_OKAY, data); } - public void verificationFailed(FailureReason reason) { - Bundle data = new Bundle(); - data.putSerializable(MESSAGE_FAILURE_REASON, reason); + public void verificationFailed(FailureReason failureReason) { + switch (failureReason) { + case CONNECTION_FAILED: { + mKeyserverEditTextLayout.setError( + getString(R.string.add_keyserver_connection_failed)); + break; + } + case INVALID_URL: { + mKeyserverEditTextLayout.setError( + getString(R.string.add_keyserver_invalid_url)); + break; + } + case NO_PINNED_CERTIFICATE: { + mKeyserverEditTextLayout.setError( + getString(R.string.add_keyserver_keyserver_not_trusted)); + break; + } + } - sendMessageToHandler(MESSAGE_VERIFICATION_FAILED, data); } - public void verifyConnection(String keyserver, final Proxy proxy) { + public void verifyConnection(String keyserver, final Proxy proxy, final boolean onlyTrustedKeyserver) { new AsyncTask<String, Void, FailureReason>() { ProgressDialog mProgressDialog; @@ -288,7 +327,7 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On @Override protected void onPreExecute() { mProgressDialog = new ProgressDialog(getActivity()); - mProgressDialog.setMessage(getString(R.string.progress_verifying_keyserver_url)); + mProgressDialog.setMessage(getString(R.string.progress_verifying_keyserver_connection)); mProgressDialog.setCancelable(false); mProgressDialog.show(); } @@ -316,7 +355,18 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On Log.d("Converted URL", newKeyserver.toString()); OkHttpClient client = HkpKeyserver.getClient(newKeyserver.toURL(), proxy); - TlsHelper.pinCertificateIfNecessary(client, newKeyserver.toURL()); + + // don't follow any redirects + client.setFollowRedirects(false); + client.setFollowSslRedirects(false); + + if (onlyTrustedKeyserver + && !TlsHelper.usePinnedCertificateIfAvailable(client, newKeyserver.toURL())) { + Log.w(Constants.TAG, "No pinned certificate for this host in OpenKeychain's assets."); + reason = FailureReason.NO_PINNED_CERTIFICATE; + return reason; + } + client.newCall(new Request.Builder().url(newKeyserver.toURL()).build()).execute(); } catch (TlsHelper.TlsHelperException e) { reason = FailureReason.CONNECTION_FAILED; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java deleted file mode 100644 index 84774ae5e..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.Activity; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.support.v4.app.DialogFragment; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.util.FileHelper; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.File; - -/** - * This is a file chooser dialog no longer used with KitKat - */ -public class FileDialogFragment extends DialogFragment { - private static final String ARG_MESSENGER = "messenger"; - private static final String ARG_TITLE = "title"; - private static final String ARG_MESSAGE = "message"; - private static final String ARG_DEFAULT_FILE = "default_file"; - private static final String ARG_CHECKBOX_TEXT = "checkbox_text"; - - public static final int MESSAGE_OKAY = 1; - - public static final String MESSAGE_DATA_FILE = "file"; - public static final String MESSAGE_DATA_CHECKED = "checked"; - - private Messenger mMessenger; - - private EditText mFilename; - private ImageButton mBrowse; - private CheckBox mCheckBox; - private TextView mMessageTextView; - - private File mFile; - - private static final int REQUEST_CODE = 0x00007004; - - /** - * Creates new instance of this file dialog fragment - */ - public static FileDialogFragment newInstance(Messenger messenger, String title, String message, - File defaultFile, String checkboxText) { - FileDialogFragment frag = new FileDialogFragment(); - Bundle args = new Bundle(); - args.putParcelable(ARG_MESSENGER, messenger); - - args.putString(ARG_TITLE, title); - args.putString(ARG_MESSAGE, message); - args.putString(ARG_DEFAULT_FILE, defaultFile.getAbsolutePath()); - args.putString(ARG_CHECKBOX_TEXT, checkboxText); - - frag.setArguments(args); - - return frag; - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Activity activity = getActivity(); - - mMessenger = getArguments().getParcelable(ARG_MESSENGER); - - String title = getArguments().getString(ARG_TITLE); - String message = getArguments().getString(ARG_MESSAGE); - mFile = new File(getArguments().getString(ARG_DEFAULT_FILE)); - if (!mFile.isAbsolute()) { - // We use OK dir by default - mFile = new File(Constants.Path.APP_DIR.getAbsolutePath(), mFile.getName()); - } - String checkboxText = getArguments().getString(ARG_CHECKBOX_TEXT); - - LayoutInflater inflater = (LayoutInflater) activity - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); - alert.setTitle(title); - - View view = inflater.inflate(R.layout.file_dialog, null); - - mMessageTextView = (TextView) view.findViewById(R.id.message); - mMessageTextView.setText(message); - - mFilename = (EditText) view.findViewById(R.id.input); - mFilename.setText(mFile.getName()); - mBrowse = (ImageButton) view.findViewById(R.id.btn_browse); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - mBrowse.setVisibility(View.GONE); - } else { - mBrowse.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - // only .asc or .gpg files - // setting it to text/plain prevents Cynaogenmod's file manager from selecting asc - // or gpg types! - FileHelper.saveDocumentKitKat( - FileDialogFragment.this, "*/*", mFile.getName(), REQUEST_CODE); - } - }); - } - - mCheckBox = (CheckBox) view.findViewById(R.id.checkbox); - if (checkboxText == null) { - mCheckBox.setEnabled(false); - mCheckBox.setVisibility(View.GONE); - } else { - mCheckBox.setEnabled(true); - mCheckBox.setVisibility(View.VISIBLE); - mCheckBox.setText(checkboxText); - mCheckBox.setChecked(true); - } - - alert.setView(view); - - alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - - String currentFilename = mFilename.getText().toString(); - if (currentFilename == null || currentFilename.isEmpty()) { - // No file is like pressing cancel, UI: maybe disable positive button in this case? - return; - } - - if (mFile == null || currentFilename.startsWith("/")) { - mFile = new File(currentFilename); - } else if (!mFile.getName().equals(currentFilename)) { - // We update our File object if user changed name! - mFile = new File(mFile.getParentFile(), currentFilename); - } - - boolean checked = mCheckBox.isEnabled() && mCheckBox.isChecked(); - - // return resulting data back to activity - Bundle data = new Bundle(); - data.putString(MESSAGE_DATA_FILE, mFile.getAbsolutePath()); - data.putBoolean(MESSAGE_DATA_CHECKED, checked); - - sendMessageToHandler(MESSAGE_OKAY, data); - } - }); - - alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - } - }); - return alert.show(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode & 0xFFFF) { - case REQUEST_CODE: { - if (resultCode == Activity.RESULT_OK && data != null) { - File file = new File(data.getData().getPath()); - if (file.getParentFile().exists()) { - mFile = file; - mFilename.setText(mFile.getName()); - } else { - Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR).show(); - } - } - - break; - } - - default: - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } - - /** - * Send message back to handler which is initialized in a activity - * - * @param what Message integer you want to send - */ - private void sendMessageToHandler(Integer what, Bundle data) { - Message msg = Message.obtain(); - msg.what = what; - if (data != null) { - msg.setData(data); - } - - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); - } catch (NullPointerException e) { - Log.w(Constants.TAG, "Messenger is null!", e); - } - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java index 22a201ba3..44323543f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java @@ -27,7 +27,6 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.EditText; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.linked.resources.GenericHttpsResource; @@ -35,7 +34,6 @@ import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.FileHelper; -import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.net.URI; @@ -134,9 +132,10 @@ public class LinkedIdCreateHttpsStep2Fragment extends LinkedIdCreateFinalFragmen String targetName = "pgpkey.txt"; + // TODO: not supported on Android < 4.4 FileHelper.saveDocument(this, - targetName, Uri.fromFile(new File(Constants.Path.APP_DIR, targetName)), - "text/plain", R.string.title_decrypt_to_file, R.string.specify_file_to_decrypt_to, + targetName, + "text/plain", REQUEST_CODE_OUTPUT); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java index d7491ab26..9a6d33260 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java @@ -103,8 +103,7 @@ public class EmailKeyHelper { } } } - } catch (Keyserver.QueryFailedException ignored) { - } catch (Keyserver.QueryNeedsRepairException ignored) { + } catch (Keyserver.CloudSearchFailureException ignored) { } return new ArrayList<>(keys); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java index 2e0b0af36..cc90c173f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java @@ -69,13 +69,14 @@ public class ExportHelper : R.string.specify_backup_dest_single); } - FileHelper.saveDocumentDialog(new FileHelper.FileDialogCallback() { - @Override - public void onFileSelected(File file, boolean checked) { - mExportFile = file; - exportKeys(masterKeyId == null ? null : new long[] { masterKeyId }, exportSecret); - } - }, mActivity.getSupportFragmentManager(), title, message, exportFile, null); + // TODO: for valodim +// FileHelper.saveDocumentDialog(new FileHelper.FileDialogCallback() { +// @Override +// public void onFileSelected(File file, boolean checked) { +// mExportFile = file; +// exportKeys(masterKeyId == null ? null : new long[] { masterKeyId }, exportSecret); +// } +// }, mActivity.getSupportFragmentManager(), title, message, exportFile, null); } // TODO: If ExportHelper requires pending data (see CryptoOPerationHelper), activities using diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java index 9fb362412..fea3e65b6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java @@ -18,7 +18,6 @@ package org.sufficientlysecure.keychain.util; import android.annotation.TargetApi; -import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.ContentResolver; import android.content.Context; @@ -30,20 +29,13 @@ import android.net.Uri; import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.Environment; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; import android.provider.DocumentsContract; import android.provider.OpenableColumns; import android.support.annotation.StringRes; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; import android.widget.Toast; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -82,52 +74,26 @@ import java.text.DecimalFormat; public class FileHelper { public static void openDocument(Fragment fragment, Uri last, String mimeType, boolean multiple, int requestCode) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - openDocumentPreKitKat(fragment, last, mimeType, multiple, requestCode); - } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { openDocumentKitKat(fragment, mimeType, multiple, requestCode); + } else { + openDocumentPreKitKat(fragment, last, mimeType, multiple, requestCode); } } - public static void saveDocument(Fragment fragment, String targetName, Uri inputUri, - @StringRes int title, @StringRes int message, int requestCode) { - saveDocument(fragment, targetName, inputUri, "*/*", title, message, requestCode); + public static void saveDocument(Fragment fragment, String targetName, int requestCode) { + saveDocument(fragment, targetName, "*/*", requestCode); } - public static void saveDocument(Fragment fragment, String targetName, Uri inputUri, String mimeType, - @StringRes int title, @StringRes int message, int requestCode) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - saveDocumentDialog(fragment, targetName, inputUri, title, message, requestCode); - } else { + public static void saveDocument(Fragment fragment, String targetName, String mimeType, + int requestCode) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { saveDocumentKitKat(fragment, mimeType, targetName, requestCode); + } else { + throw new RuntimeException("saveDocument does not support Android < 4.4!"); } } - public static void saveDocumentDialog(final Fragment fragment, String targetName, Uri inputUri, - @StringRes int title, @StringRes int message, final int requestCode) { - - saveDocumentDialog(fragment, targetName, inputUri, title, message, new FileDialogCallback() { - // is this a good idea? seems hacky... - @Override - public void onFileSelected(File file, boolean checked) { - Intent intent = new Intent(); - intent.setData(Uri.fromFile(file)); - fragment.onActivityResult(requestCode, Activity.RESULT_OK, intent); - } - }); - } - - public static void saveDocumentDialog(final Fragment fragment, String targetName, Uri inputUri, - @StringRes int title, @StringRes int message, FileDialogCallback callback) { - - File file = inputUri == null ? null : new File(inputUri.getPath()); - File parentDir = file != null && file.exists() ? file.getParentFile() : Constants.Path.APP_DIR; - File targetFile = new File(parentDir, targetName); - saveDocumentDialog(callback, fragment.getActivity().getSupportFragmentManager(), - fragment.getString(title), fragment.getString(message), targetFile, null); - - } - /** Opens the preferred installed file manager on Android and shows a toast * if no manager is installed. */ private static void openDocumentPreKitKat( @@ -172,36 +138,6 @@ public class FileHelper { fragment.startActivityForResult(intent, requestCode); } - public static void saveDocumentDialog( - final FileDialogCallback callback, final FragmentManager fragmentManager, - final String title, final String message, final File defaultFile, - final String checkMsg) { - // Message is received after file is selected - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == FileDialogFragment.MESSAGE_OKAY) { - callback.onFileSelected( - new File(message.getData().getString(FileDialogFragment.MESSAGE_DATA_FILE)), - message.getData().getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED)); - } - } - }; - - // Create a new Messenger for the communication back - final Messenger messenger = new Messenger(returnHandler); - - DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { - @Override - public void run() { - FileDialogFragment fileDialog = FileDialogFragment.newInstance(messenger, title, message, - defaultFile, checkMsg); - - fileDialog.show(fragmentManager, "fileDialog"); - } - }); - } - public static String getFilename(Context context, Uri uri) { String filename = null; try { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FilterCursorWrapper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FilterCursorWrapper.java index ab73f59b8..d06f2ab65 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FilterCursorWrapper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FilterCursorWrapper.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + package org.sufficientlysecure.keychain.util; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java index 2b47fd623..1040e683b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java @@ -141,6 +141,10 @@ public class NfcHelper { } protected void onPostExecute(Void unused) { + if (mActivity.isFinishing()) { + return; + } + // Register callback to set NDEF message mNfcAdapter.setNdefPushMessageCallback(mNdefCallback, mActivity); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/OkHttpKeybaseClient.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/OkHttpKeybaseClient.java new file mode 100644 index 000000000..32a5406e0 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/OkHttpKeybaseClient.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.util; + +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.OkUrlFactory; +import com.textuality.keybase.lib.KeybaseUrlConnectionClient; + +import org.sufficientlysecure.keychain.Constants; + +import java.io.IOException; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.util.concurrent.TimeUnit; + +/** + * Wrapper for Keybase Lib + */ +public class OkHttpKeybaseClient implements KeybaseUrlConnectionClient { + + private final OkUrlFactory factory; + + private static OkUrlFactory generateUrlFactory() { + OkHttpClient client = new OkHttpClient(); + return new OkUrlFactory(client); + } + + public OkHttpKeybaseClient() { + factory = generateUrlFactory(); + } + + @Override + public URLConnection openConnection(URL url) throws IOException { + return openConnection(url, null); + } + + @Override + public URLConnection openConnection(URL url, Proxy proxy) throws IOException { + if (proxy != null) { + factory.client().setProxy(proxy); + factory.client().setConnectTimeout(30000, TimeUnit.MILLISECONDS); + factory.client().setReadTimeout(40000, TimeUnit.MILLISECONDS); + } else { + factory.client().setConnectTimeout(5000, TimeUnit.MILLISECONDS); + factory.client().setReadTimeout(25000, TimeUnit.MILLISECONDS); + } + + factory.client().setFollowSslRedirects(false); + + // forced the usage of keybase.io pinned certificate + try { + if (!TlsHelper.usePinnedCertificateIfAvailable(factory.client(), url)) { + throw new IOException("no pinned certificate found for URL!"); + } + } catch (TlsHelper.TlsHelperException e) { + Log.e(Constants.TAG, "TlsHelper failed", e); + throw new IOException("TlsHelper failed"); + } + + return factory.open(url); + } + +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java index d1d1ada2a..1492abdeb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2013-2015 Dominik Schürmann <dominik@dominikschuermann.de> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.util; import android.content.res.AssetManager; import com.squareup.okhttp.OkHttpClient; + import org.sufficientlysecure.keychain.Constants; import java.io.ByteArrayInputStream; @@ -37,7 +38,6 @@ import java.security.cert.CertificateFactory; import java.util.HashMap; import java.util.Map; -import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; @@ -49,15 +49,14 @@ public class TlsHelper { } } - private static Map<String, byte[]> sStaticCA = new HashMap<>(); - - public static void addStaticCA(String domain, byte[] certificate) { - sStaticCA.put(domain, certificate); - } + private static Map<String, byte[]> sPinnedCertificates = new HashMap<>(); - public static void addStaticCA(String domain, AssetManager assetManager, String name) { + /** + * Add certificate from assets to pinned certificate map. + */ + public static void addPinnedCertificate(String host, AssetManager assetManager, String cerFilename) { try { - InputStream is = assetManager.open(name); + InputStream is = assetManager.open(cerFilename); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int reads = is.read(); @@ -68,27 +67,36 @@ public class TlsHelper { is.close(); - addStaticCA(domain, baos.toByteArray()); + sPinnedCertificates.put(host, baos.toByteArray()); } catch (IOException e) { Log.w(Constants.TAG, e); } } - public static void pinCertificateIfNecessary(OkHttpClient client, URL url) throws TlsHelperException, IOException { + /** + * Use pinned certificate for OkHttpClient if we have one. + * + * @return true, if certificate is available, false if not + * @throws TlsHelperException + * @throws IOException + */ + public static boolean usePinnedCertificateIfAvailable(OkHttpClient client, URL url) throws TlsHelperException, IOException { if (url.getProtocol().equals("https")) { - for (String domain : sStaticCA.keySet()) { - if (url.getHost().endsWith(domain)) { - pinCertificate(sStaticCA.get(domain), client); + // use certificate PIN from assets if we have one + for (String host : sPinnedCertificates.keySet()) { + if (url.getHost().endsWith(host)) { + pinCertificate(sPinnedCertificates.get(host), client); + return true; } } } + return false; } /** * Modifies the client to accept only requests with a given certificate. Applies to all URLs requested by the * client. * Therefore a client that is pinned this way should be used to only make requests to URLs with passed certificate. - * TODO: Refactor - More like SSH StrictHostKeyChecking than pinning? * * @param certificate certificate to pin * @param client OkHttpClient to enforce pinning on @@ -97,8 +105,10 @@ public class TlsHelper { */ private static void pinCertificate(byte[] certificate, OkHttpClient client) throws TlsHelperException, IOException { - // We don't use OkHttp's CertificatePinner since it depends on a TrustManager to verify it too. Refer to - // note at end of description: http://square.github.io/okhttp/javadoc/com/squareup/okhttp/CertificatePinner.html + // We don't use OkHttp's CertificatePinner since it can not be used to pin self-signed + // certificate if such certificate is not accepted by TrustManager. + // (Refer to note at end of description: + // http://square.github.io/okhttp/javadoc/com/squareup/okhttp/CertificatePinner.html ) // Creating our own TrustManager that trusts only our certificate eliminates the need for certificate pinning try { // Load CA @@ -126,42 +136,4 @@ public class TlsHelper { } } - /** - * Opens a Connection that will only accept certificates signed with a specific CA and skips common name check. - * This is required for some distributed Keyserver networks like sks-keyservers.net - * - * @param certificate The X.509 certificate used to sign the servers certificate - * @param url Connection target - */ - public static HttpsURLConnection openCAConnection(byte[] certificate, URL url) - throws TlsHelperException, IOException { - try { - // Load CA - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - Certificate ca = cf.generateCertificate(new ByteArrayInputStream(certificate)); - - // Create a KeyStore containing our trusted CAs - String keyStoreType = KeyStore.getDefaultType(); - KeyStore keyStore = KeyStore.getInstance(keyStoreType); - keyStore.load(null, null); - keyStore.setCertificateEntry("ca", ca); - - // Create a TrustManager that trusts the CAs in our KeyStore - String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); - tmf.init(keyStore); - - // Create an SSLContext that uses our TrustManager - SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, tmf.getTrustManagers(), null); - - // Tell the URLConnection to use a SocketFactory from our SSLContext - HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); - urlConnection.setSSLSocketFactory(context.getSocketFactory()); - - return urlConnection; - } catch (CertificateException | KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) { - throw new TlsHelperException(e); - } - } } diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_check_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_check_black_24dp.png Binary files differnew file mode 100644 index 000000000..e802d90ae --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_check_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_check_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_check_black_24dp.png Binary files differnew file mode 100644 index 000000000..1c14c9c44 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_check_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_black_24dp.png Binary files differnew file mode 100644 index 000000000..64a4944f7 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_black_24dp.png Binary files differnew file mode 100644 index 000000000..b26a2c05e --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_black_24dp.png Binary files differnew file mode 100644 index 000000000..2f6d6386d --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_black_24dp.png diff --git a/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml b/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml index 78e9247ea..b83681537 100644 --- a/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml +++ b/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml @@ -9,21 +9,37 @@ android:paddingRight="24dp" android:paddingTop="16dp"> - <EditText - android:id="@+id/keyserver_url_edit_text" + <android.support.design.widget.TextInputLayout + android:id="@+id/keyserver_url_edit_text_layout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginBottom="8dp" - android:ems="10" - android:hint="@string/label_enter_keyserver_url" - android:imeOptions="actionDone" /> + android:layout_marginBottom="8dp"> + + <EditText + android:id="@+id/keyserver_url_edit_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:ems="10" + android:hint="@string/label_enter_keyserver_url" + android:imeOptions="actionDone" + android:inputType="textUri" /> + + </android.support.design.widget.TextInputLayout> + + + <CheckBox + android:id="@+id/verify_connection_checkbox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:checked="true" + android:text="@string/label_verify_keyserver_connection" /> <CheckBox - android:id="@+id/verify_keyserver_checkbox" + android:id="@+id/only_trusted_keyserver_checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/label_verify_keyserver" - android:checked="true"/> + android:checked="true" + android:text="@string/label_only_trusted_keyserver" /> </LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml b/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml index 239cdcc95..7e2f78531 100644 --- a/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml +++ b/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml @@ -1,155 +1,107 @@ <?xml version="1.0" encoding="utf-8"?> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> - <ScrollView + <LinearLayout android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_above="@+id/certify_fingerprint_buttons_divider"> + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="16dp"> - <LinearLayout + <TextView + android:id="@+id/certify_fingerprint_intro" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="32dp" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:text="@string/certify_fingerprint_text" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <android.support.v7.widget.CardView + android:id="@+id/certify_fingerprint_card" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" - android:padding="16dp"> + android:layout_gravity="top" + app:cardBackgroundColor="?attr/colorCardViewBackground" + app:cardCornerRadius="4dp" + app:cardElevation="8dp" + app:cardUseCompatPadding="true"> - <TextView - android:id="@+id/certify_fingerprint_intro" + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" - android:textAppearance="?android:attr/textAppearanceMedium" - android:text="@string/certify_fingerprint_text" /> + android:orientation="vertical"> - <android.support.v7.widget.CardView - android:id="@+id/certify_fingerprint_card" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:cardBackgroundColor="?attr/colorCardViewBackground" - app:cardUseCompatPadding="true" - app:cardCornerRadius="4dp" - android:layout_gravity="top"> + <TextView + android:id="@+id/certify_fingerprint_fingerprint_header" + style="@style/CardViewHeader" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/label_fingerprint" /> - <LinearLayout + <TextView + android:id="@+id/certify_fingerprint_fingerprint" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical"> - - <TextView - style="@style/CardViewHeader" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/label_fingerprint" /> - - <TextView - android:id="@+id/certify_fingerprint_fingerprint" - android:paddingLeft="16dp" - android:paddingRight="16dp" - android:paddingTop="8dp" - android:paddingBottom="8dp" - android:textSize="20sp" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:typeface="monospace" - android:gravity="center_vertical" /> - </LinearLayout> - - </android.support.v7.widget.CardView> - - </LinearLayout> + android:gravity="center_vertical" + android:paddingBottom="24dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:paddingTop="16dp" + android:textSize="18sp" + android:typeface="monospace" /> + + <View + android:layout_width="match_parent" + android:layout_height="1dip" + android:background="?android:attr/listDivider" /> - </ScrollView> + <TextView + android:id="@+id/certify_fingerprint_button_no" + style="?android:attr/borderlessButtonStyle" + android:textColor="@color/android_red_dark" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:clickable="true" + android:drawableLeft="@drawable/ic_close_black_24dp" + android:drawablePadding="8dp" + android:gravity="left|center_vertical" + android:minHeight="48dp" + android:text="@string/btn_not_matching" + android:textAllCaps="true" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <View + android:layout_width="match_parent" + android:layout_height="1dip" + android:background="?android:attr/listDivider" /> + <TextView + android:id="@+id/certify_fingerprint_button_yes" + style="?android:attr/borderlessButtonStyle" + android:textColor="@color/android_green_dark" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:layout_weight="1" + android:clickable="true" + android:drawableLeft="@drawable/ic_check_black_24dp" + android:drawablePadding="8dp" + android:gravity="left|center_vertical" + android:minHeight="48dp" + android:text="@string/btn_match" + android:textAllCaps="true" + android:textAppearance="?android:attr/textAppearanceMedium" /> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:layout_alignParentBottom="true" - android:layout_alignParentLeft="true" - android:layout_alignParentStart="true" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" - android:id="@+id/certify_fingerprint_buttons"> + </LinearLayout> - <TextView - android:id="@+id/certify_fingerprint_button_no" - android:paddingLeft="8dp" - android:paddingRight="8dp" - android:textAppearance="?android:attr/textAppearanceMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@string/btn_no" - android:minHeight="?android:attr/listPreferredItemHeight" - android:gravity="center_vertical" - android:clickable="true" - style="?android:attr/borderlessButtonStyle" - android:layout_gravity="center_vertical" /> - <View - android:layout_width="1dp" - android:layout_height="match_parent" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" - android:background="?android:attr/listDivider" /> + </android.support.v7.widget.CardView> - <TextView - android:id="@+id/certify_fingerprint_button_yes" - android:paddingLeft="8dp" - android:paddingRight="8dp" - android:textAppearance="?android:attr/textAppearanceMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@string/btn_match" - android:minHeight="?android:attr/listPreferredItemHeight" - android:drawablePadding="8dp" - android:gravity="center_vertical" - android:clickable="true" - style="?android:attr/borderlessButtonStyle" - android:layout_gravity="center_vertical" /> </LinearLayout> - <View - android:id="@+id/certify_fingerprint_buttons_divider2" - android:layout_width="match_parent" - android:layout_height="1dip" - android:background="?android:attr/listDivider" - android:layout_alignBottom="@+id/certify_fingerprint_buttons_text" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" - android:layout_alignParentLeft="true" - android:layout_alignParentStart="true" /> - - <TextView - android:id="@+id/certify_fingerprint_buttons_text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="24dp" - android:layout_marginRight="24dp" - android:paddingTop="8dp" - android:paddingBottom="8dp" - android:textAppearance="?android:attr/textAppearanceMedium" - android:text="@string/certify_fingerprint_text2" - android:layout_above="@+id/certify_fingerprint_buttons" - android:layout_centerHorizontal="true" /> - - <View - android:id="@+id/certify_fingerprint_buttons_divider" - android:layout_width="match_parent" - android:layout_height="1dip" - android:background="?android:attr/listDivider" - android:layout_alignTop="@+id/certify_fingerprint_buttons_text" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" - android:layout_alignParentLeft="true" - android:layout_alignParentStart="true" /> - - - -</RelativeLayout> +</ScrollView> diff --git a/OpenKeychain/src/main/res/menu-v19/decrypt_bottom_sheet.xml b/OpenKeychain/src/main/res/menu-v19/decrypt_bottom_sheet.xml new file mode 100644 index 000000000..868bd605f --- /dev/null +++ b/OpenKeychain/src/main/res/menu-v19/decrypt_bottom_sheet.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:id="@+id/decrypt_open" + android:icon="@drawable/ic_apps_black_24dp" + android:title="@string/btn_open_with" /> + + <item + android:id="@+id/decrypt_share" + android:icon="@drawable/ic_share_black_24dp" + android:title="@string/btn_share_decrypted_text" /> + + <item + android:id="@+id/decrypt_save" + android:icon="@drawable/ic_save_black_24dp" + android:title="@string/btn_save" /> + +</menu> diff --git a/OpenKeychain/src/main/res/menu/decrypt_bottom_sheet.xml b/OpenKeychain/src/main/res/menu/decrypt_bottom_sheet.xml index 11b79bd5f..f3550278a 100644 --- a/OpenKeychain/src/main/res/menu/decrypt_bottom_sheet.xml +++ b/OpenKeychain/src/main/res/menu/decrypt_bottom_sheet.xml @@ -3,17 +3,12 @@ <item android:id="@+id/decrypt_open" - android:title="Open with…" - android:icon="@drawable/ic_apps_black_24dp" /> + android:icon="@drawable/ic_apps_black_24dp" + android:title="@string/btn_open_with" /> <item android:id="@+id/decrypt_share" - android:title="@string/btn_share_decrypted_text" - android:icon="@drawable/ic_share_black_24dp" /> + android:icon="@drawable/ic_share_black_24dp" + android:title="@string/btn_share_decrypted_text" /> - <item - android:id="@+id/decrypt_save" - android:title="@string/btn_save" - android:icon="@drawable/ic_save_black_24dp" /> - -</menu> +</menu>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/menu/key_view.xml b/OpenKeychain/src/main/res/menu/key_view.xml index 14ea099f4..1bda1463a 100644 --- a/OpenKeychain/src/main/res/menu/key_view.xml +++ b/OpenKeychain/src/main/res/menu/key_view.xml @@ -41,7 +41,7 @@ android:id="@+id/menu_key_view_certify_fingerprint_word" app:showAsAction="never" android:visible="false" - android:title="@string/menu_certify_fingerprint_word" /> + android:title="@string/menu_certify_fingerprint_phrases" /> <item android:id="@+id/menu_key_view_add_linked_identity" diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_adjectives b/OpenKeychain/src/main/res/raw/fp_sentence_adjectives new file mode 100644 index 000000000..cf8fa4674 --- /dev/null +++ b/OpenKeychain/src/main/res/raw/fp_sentence_adjectives @@ -0,0 +1,128 @@ +able +angry +bad +bent +bitter +black +blue +boiling +bright +broken +brown +certain +cheap +clean +clear +cold +common +complex +cruel +dark +dead +dear +deep +dirty +dry +early +elastic +equal +false +fat +feeble +female +fertile +first +fixed +flat +foolish +free +full +future +general +good +great +green +grey +hanging +happy +hard +healthy +high +hollow +kind +last +late +lazy +left +like +living +long +loose +loud +low +male +married +medical +mixed +narrow +natural +new +normal +old +open +past +poor +present +pretty +private +public +quick +quiet +ready +rare +red +regular +right +rough +round +sad +safe +same +second +secret +serious +sharp +short +shut +sick +simple +slow +small +smooth +soft +solid +sour +special +sticky +stiff +strange +strong +sudden +sweet +tall +thick +thin +tight +tired +true +unknown +violent +waiting +warm +wet +white +wide +wise +wrong +yellow +young diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_adverbs b/OpenKeychain/src/main/res/raw/fp_sentence_adverbs new file mode 100644 index 000000000..1d6002387 --- /dev/null +++ b/OpenKeychain/src/main/res/raw/fp_sentence_adverbs @@ -0,0 +1,64 @@ +ably +angrily +badly +bitterly +brightly +brokenly +cheaply +clearly +coldly +commonly +cruelly +darkly +dearly +deeply +drily +equally +falsely +feebly +fixedly +flatly +freely +fully +greatly +happily +hardly +kindly +lately +lazily +loosely +loudly +narrowly +newly +normally +openly +poorly +prettily +publicly +quickly +quietly +readily +rarely +roughly +sadly +safely +secretly +sharply +simply +slowly +smoothly +softly +solidly +sourly +stiffly +strongly +suddenly +sweetly +thickly +thinly +tightly +tiredly +truly +warmly +widely +wisely diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_articles b/OpenKeychain/src/main/res/raw/fp_sentence_articles new file mode 100644 index 000000000..0604b3d07 --- /dev/null +++ b/OpenKeychain/src/main/res/raw/fp_sentence_articles @@ -0,0 +1,8 @@ +her +his +my +our +that +the +this +your diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_nouns b/OpenKeychain/src/main/res/raw/fp_sentence_nouns new file mode 100644 index 000000000..ed4099c31 --- /dev/null +++ b/OpenKeychain/src/main/res/raw/fp_sentence_nouns @@ -0,0 +1,512 @@ +account +air +amount +angle +animal +answer +ant +apple +arch +arm +army +attack +attempt +baby +back +bag +ball +band +base +basin +basket +bath +bed +bee +belief +bell +berry +bird +birth +bite +blade +blood +blow +board +boat +body +bone +book +boot +bottle +box +boy +brain +brake +branch +bread +breath +brick +bridge +brother +brush +bucket +bulb +burn +butter +button +cake +camera +canvas +car +card +cat +cause +chain +chalk +chance +change +cheese +chest +chin +church +circle +clock +cloth +cloud +coal +coat +collar +colour +comb +comfort +company +control +cook +copper +copy +cord +cork +cotton +cough +country +cover +cow +crack +credit +crime +crush +cry +cup +current +curtain +curve +cushion +damage +danger +day +debt +degree +design +desire +detail +disease +disgust +dog +door +doubt +drain +drawer +dress +drink +drop +dust +ear +earth +edge +effect +egg +end +engine +error +event +example +expert +eye +face +fact +fall +family +farm +father +fear +feather +feeling +fiction +field +fight +finger +fire +fish +flag +flame +flight +floor +flower +fly +fold +food +foot +force +fork +form +fowl +frame +friend +front +fruit +garden +girl +glass +glove +goat +gold +grain +grass +grip +group +growth +guide +gun +hair +hammer +hand +harbour +harmony +hat +hate +head +heart +heat +history +hole +hook +hope +horn +horse +hour +house +humour +ice +idea +impulse +ink +insect +iron +island +jelly +jewel +join +journey +judge +jump +kettle +key +kick +kiss +knee +knife +knot +land +laugh +law +lead +leaf +leather +leg +letter +level +library +lift +light +limit +line +linen +lip +liquid +list +lock +look +loss +love +machine +man +manager +map +mark +market +mass +match +meal +measure +meat +meeting +memory +metal +middle +milk +mind +mine +minute +mist +money +monkey +month +moon +morning +mother +motion +mouth +move +muscle +music +nail +name +nation +neck +need +needle +nerve +net +news +night +noise +nose +note +number +nut +offer +office +oil +opinion +orange +order +oven +owner +page +pain +paint +paper +parcel +part +paste +payment +peace +pen +pencil +person +picture +pig +pin +pipe +place +plane +plant +plate +play +plough +pocket +point +poison +polish +porter +pot +potato +powder +power +price +print +prison +process +produce +profit +prose +protest +pull +pump +purpose +push +quality +rail +rain +range +rat +rate +ray +reason +receipt +record +regret +request +respect +rest +reward +rhythm +rice +ring +river +road +rod +roll +roof +room +root +rub +rule +run +sail +salt +sand +scale +school +science +screw +sea +seat +seed +self +sense +servant +sex +shade +shake +shame +sheep +shelf +ship +shirt +shock +shoe +side +sign +silk +silver +sister +size +skin +skirt +sky +sleep +slip +slope +smash +smell +smile +smoke +snake +sneeze +snow +soap +society +sock +son +song +sort +sound +soup +space +spade +sponge +spoon +spring +square +stage +stamp +star +start +station +steam +steel +stem +step +stick +stitch +stomach +stone +stop +store +story +street +stretch +sugar +summer +sun +support +swim +system +table +tail +talk +taste +tax +test +theory +thing +thought +thread +throat +thumb +thunder +ticket +time +tin +toe +tongue +tooth +top +touch +town +trade +train +tray +tree +trick +trouble +turn +twist +unit +value +verse +vessel +view +voice +walk +wall +war +wash +waste +watch +water +wave +wax +way +weather +week +weight +wheel +whip +whistle +wind +window +wine +wing +winter +wire +woman +wood +wool +word +work +worm +wound +writing +year diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_prepositions b/OpenKeychain/src/main/res/raw/fp_sentence_prepositions new file mode 100644 index 000000000..fb8206636 --- /dev/null +++ b/OpenKeychain/src/main/res/raw/fp_sentence_prepositions @@ -0,0 +1,32 @@ +above +across +after +against +along +among +around +at +before +behind +below +beneath +beside +between +beyond +by +from +in +inside +into +near +on +outside +over +past +round +through +to +towards +under +upon +with diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_verbs_i b/OpenKeychain/src/main/res/raw/fp_sentence_verbs_i new file mode 100644 index 000000000..57602bf17 --- /dev/null +++ b/OpenKeychain/src/main/res/raw/fp_sentence_verbs_i @@ -0,0 +1,128 @@ +agrees +allows +answers +arrives +asks +is +becomes +begins +believes +brings +burns +buys +calls +changes +chooses +cleans +closes +comes +compares +continues +cooks +costs +counts +cries +cuts +dances +decides +describes +destroys +dies +does +drinks +drives +eats +ends +explains +falls +feels +fights +fills +finds +finishes +forgets +forgives +gets +gives +goes +grows +hates +has +hears +helps +hides +holds +hurts +improves +jumps +keeps +kills +knows +laughs +learns +leaves +lets +lies +listens +lives +looks +loses +loves +makes +meets +moves +needs +occurs +offers +opens +pays +plays +prefers +prepares +presses +promises +pulls +pushes +puts +reads +receives +remembers +repeats +rests +returns +runs +sees +sells +sends +shouts +shows +sings +sits +sleeps +smiles +speaks +starts +stays +stops +studies +suggests +supports +takes +talks +teaches +tells +thinks +throws +touches +travels +treats +tries +turns +uses +visits +walks +wants +washes +wins +works +writes diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_verbs_t b/OpenKeychain/src/main/res/raw/fp_sentence_verbs_t new file mode 100644 index 000000000..36078bc78 --- /dev/null +++ b/OpenKeychain/src/main/res/raw/fp_sentence_verbs_t @@ -0,0 +1,128 @@ +agrees with +allows +answers +arrives at +asks +is +becomes +begins +believes +brings +burns +buys +calls +changes +chooses +cleans +closes +comes to +compares +continues +cooks +costs +counts +cries for +cuts +dances with +decides on +describes +destroys +dies for +does +drinks +drives +eats +ends +explains +falls on +feels +fights +fills +finds +finishes +forgets +forgives +gets +gives +goes to +grows +hates +has +hears +helps +hides +holds +hurts +improves +jumps over +keeps +kills +knows +laughs at +learns +leaves +lets +lies to +listens to +lives with +looks at +loses +loves +makes +meets +moves +needs +occurs to +offers +opens +pays +plays +prefers +prepares +presses +promises +pulls +pushes +puts +reads +receives +remembers +repeats +rests by +returns +runs to +sees +sells +sends +shouts at +shows +sings to +sits by +sleeps by +smiles at +speaks to +starts +stays with +stops +studies +suggests +supports +takes +talks to +teaches +tells +thinks of +throws +touches +travels to +treats +tries +turns +uses +visits +walks to +wants +washes +wins +works for +writes to diff --git a/OpenKeychain/src/main/assets/word_confirm_list.txt b/OpenKeychain/src/main/res/raw/fp_word_list index 080c7ce81..080c7ce81 100644 --- a/OpenKeychain/src/main/assets/word_confirm_list.txt +++ b/OpenKeychain/src/main/res/raw/fp_word_list diff --git a/OpenKeychain/src/main/res/values-cs/strings.xml b/OpenKeychain/src/main/res/values-cs/strings.xml index 6b6bc956b..79a5a276c 100644 --- a/OpenKeychain/src/main/res/values-cs/strings.xml +++ b/OpenKeychain/src/main/res/values-cs/strings.xml @@ -135,7 +135,7 @@ <string name="label_enable_compression">Zapnout kompresi</string> <string name="label_encrypt_filenames">Zašifrovat jména souborů</string> <string name="label_hidden_recipients">Skrýt příjemce</string> - <string name="label_verify_keyserver">Ověřit keyserver</string> + <string name="label_verify_keyserver_connection">Ověřit keyserver</string> <string name="label_enter_keyserver_url">Zadejte URL keyserveru</string> <string name="pref_keyserver">OpenPGP keyserver</string> <string name="pref_keyserver_summary">Vyhledat klíče na vybraném OpenPGP keyserveru (protokol HKP)</string> @@ -496,7 +496,7 @@ <string name="view_key_fragment_no_system_contact"><žádný></string> <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">Přidat keyserver</string> - <string name="add_keyserver_verified">Keyserver ověřen!</string> + <string name="add_keyserver_connection_verified">Keyserver ověřen!</string> <string name="add_keyserver_without_verification">Keyserver přidán bez verifikace.</string> <string name="add_keyserver_invalid_url">Neplatná URL!</string> <string name="add_keyserver_connection_failed">Nepodařilo se připojit ke key severu. Prosím ověřte URL a vaše připojení k internetu.</string> diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml index 291ebf238..0e4a43c6f 100644 --- a/OpenKeychain/src/main/res/values-de/strings.xml +++ b/OpenKeychain/src/main/res/values-de/strings.xml @@ -155,7 +155,7 @@ <string name="label_enable_compression">Komprimierung aktivieren</string> <string name="label_encrypt_filenames">Dateinamen verschlüsseln</string> <string name="label_hidden_recipients">Empfänger verbergen</string> - <string name="label_verify_keyserver">Schlüsselserver verifizieren</string> + <string name="label_verify_keyserver_connection">Schlüsselserver verifizieren</string> <string name="label_enter_keyserver_url">Schlüsselserver-URL eingeben</string> <string name="label_keyserver_dialog_delete">Schlüsselserver löschen</string> <string name="label_theme">Design</string> @@ -386,7 +386,7 @@ <string name="progress_deleting">Lösche Schlüssel…</string> <string name="progress_con_saving">Zusammenführung: Sichere in den Zwischenspeicher...</string> <string name="progress_con_reimport">Zusammenführung: Reimportiere...</string> - <string name="progress_verifying_keyserver_url">Schlüsselserver wird verifiziert…</string> + <string name="progress_verifying_keyserver_connection">Schlüsselserver wird verifiziert…</string> <string name="progress_starting_orbot">Orbot wird gestartet…</string> <!--action strings--> <string name="hint_cloud_search_hint">Via Name, E-Mail suchen...</string> @@ -691,7 +691,7 @@ <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">Schlüsselserver hinzufügen</string> <string name="edit_keyserver_dialog_title">Schlüsselserver bearbeiten</string> - <string name="add_keyserver_verified">Schlüsselserver verifiziert!</string> + <string name="add_keyserver_connection_verified">Schlüsselserver verifiziert!</string> <string name="add_keyserver_without_verification">Schlüsselserver ohne Verifikation hinzugefügt.</string> <string name="add_keyserver_invalid_url">Ungültige URL!</string> <string name="add_keyserver_connection_failed">Verbindung zum Schlüsselserver fehlgeschlagen. Bitte überprüfe die URL und deine Internetverbindung.</string> diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml index 043918c64..a6849c542 100644 --- a/OpenKeychain/src/main/res/values-es/strings.xml +++ b/OpenKeychain/src/main/res/values-es/strings.xml @@ -155,7 +155,7 @@ <string name="label_enable_compression">Habilitar compresión</string> <string name="label_encrypt_filenames">Cifrar nombres de ficheros</string> <string name="label_hidden_recipients">Ocultar receptores</string> - <string name="label_verify_keyserver">Verificar servidor de claves</string> + <string name="label_verify_keyserver_connection">Verificar servidor de claves</string> <string name="label_enter_keyserver_url">Introduzca URL de servidor de claves</string> <string name="label_keyserver_dialog_delete">Borrar servidor de claves</string> <string name="label_theme">Tema decorativo</string> @@ -386,7 +386,7 @@ <string name="progress_deleting">borrando claves...</string> <string name="progress_con_saving">consolidación: guardando en caché...</string> <string name="progress_con_reimport">consolidación: reimportando</string> - <string name="progress_verifying_keyserver_url">verificando servidor de claves...</string> + <string name="progress_verifying_keyserver_connection">verificando servidor de claves...</string> <string name="progress_starting_orbot">Iniciando Orbot...</string> <!--action strings--> <string name="hint_cloud_search_hint">Buscar mediante Nombre, Correo electrónico...</string> @@ -691,7 +691,7 @@ <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">Añadir servidor de claves</string> <string name="edit_keyserver_dialog_title">Editar servidor de claves</string> - <string name="add_keyserver_verified">¡Servidor de claves verificado!</string> + <string name="add_keyserver_connection_verified">¡Servidor de claves verificado!</string> <string name="add_keyserver_without_verification">Servidor de claves añadido sin verificación</string> <string name="add_keyserver_invalid_url">¡URL no válida!</string> <string name="add_keyserver_connection_failed">Fallo al conectar al servidor de claves. Por favor, compuebe la URL y su conexión a Internet.</string> diff --git a/OpenKeychain/src/main/res/values-eu/strings.xml b/OpenKeychain/src/main/res/values-eu/strings.xml index de4fb68d6..f57297498 100644 --- a/OpenKeychain/src/main/res/values-eu/strings.xml +++ b/OpenKeychain/src/main/res/values-eu/strings.xml @@ -154,7 +154,7 @@ <string name="label_enable_compression">Gaitu konpresioa</string> <string name="label_encrypt_filenames">Enkriptatu agirizenak</string> <string name="label_hidden_recipients">Ezkutatu jasotzaileak</string> - <string name="label_verify_keyserver">Egiaztatu giltza-zerbitzaria</string> + <string name="label_verify_keyserver_connection">Egiaztatu giltza-zerbitzaria</string> <string name="label_enter_keyserver_url">Sartu giltza-zerbitzariaren URL-a</string> <string name="label_keyserver_dialog_delete">Ezabatu giltza-zerbitzaria</string> <string name="label_theme">Azalgaia</string> @@ -376,7 +376,7 @@ <string name="progress_deleting">giltzak ezabatzen...</string> <string name="progress_con_saving">sendotu: katxean gordetzen...</string> <string name="progress_con_reimport">sendotu: berrinportatzen...</string> - <string name="progress_verifying_keyserver_url">giltza-zerbitzaria egiaztatzen...</string> + <string name="progress_verifying_keyserver_connection">giltza-zerbitzaria egiaztatzen...</string> <string name="progress_starting_orbot">Orbot Abiarazten...</string> <!--action strings--> <string name="hint_cloud_search_hint">Bilatu Izena, Post@... bidez</string> @@ -675,7 +675,7 @@ <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">Gehitu giltza-zerbitzaria</string> <string name="edit_keyserver_dialog_title">Editatu giltza-zerbitzaria</string> - <string name="add_keyserver_verified">Giltza-zerbitzaria egiaztatuta!</string> + <string name="add_keyserver_connection_verified">Giltza-zerbitzaria egiaztatuta!</string> <string name="add_keyserver_without_verification">Giltza-zerbitzaria gehituta egiaztapen gabe.</string> <string name="add_keyserver_invalid_url">URL baliogabea!</string> <string name="add_keyserver_connection_failed">Hutsegitea giltza-zerbitzariarekin elkartzerakoan. Mesedez egiaztatu URL-a eta zure internet elkarketa.</string> diff --git a/OpenKeychain/src/main/res/values-fa/strings.xml b/OpenKeychain/src/main/res/values-fa/strings.xml index 86d8ab5cd..790d5e90c 100644 --- a/OpenKeychain/src/main/res/values-fa/strings.xml +++ b/OpenKeychain/src/main/res/values-fa/strings.xml @@ -146,7 +146,7 @@ <string name="label_enable_compression">فشردهکردن</string> <string name="label_encrypt_filenames">رمزگذاری اسمِ فایلها</string> <string name="label_hidden_recipients">مخفیکردن گیرندهها</string> - <string name="label_verify_keyserver">بررسی سرورِ کلیدها</string> + <string name="label_verify_keyserver_connection">بررسی سرورِ کلیدها</string> <string name="label_enter_keyserver_url">آدرس URL سرورِ کلید را وارد کنید</string> <string name="label_keyserver_dialog_delete">حذف سرورهای کلید</string> <string name="label_theme">قالب</string> diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml index 4a6c2bbfe..b5e5f3d53 100644 --- a/OpenKeychain/src/main/res/values-fr/strings.xml +++ b/OpenKeychain/src/main/res/values-fr/strings.xml @@ -155,7 +155,7 @@ <string name="label_enable_compression">Activer la compression</string> <string name="label_encrypt_filenames">Chiffrer les nom de fichier</string> <string name="label_hidden_recipients">Cacher les destinataires</string> - <string name="label_verify_keyserver">Vérifier le serveur de clefs</string> + <string name="label_verify_keyserver_connection">Vérifier le serveur de clefs</string> <string name="label_enter_keyserver_url">Saisir l\'URL du serveur de clefs</string> <string name="label_keyserver_dialog_delete">Supprimer le serveur de clefs</string> <string name="label_theme">Thème</string> @@ -386,7 +386,7 @@ <string name="progress_deleting">suppression des clefs...</string> <string name="progress_con_saving">consolider : enregistrement dans le cache...</string> <string name="progress_con_reimport">consolider : réimportation...</string> - <string name="progress_verifying_keyserver_url">vérification du serveur de clefs...</string> + <string name="progress_verifying_keyserver_connection">vérification du serveur de clefs...</string> <string name="progress_starting_orbot">Démarrage d\'Orbot...</string> <!--action strings--> <string name="hint_cloud_search_hint">Chercher par nom, adresse courriel...</string> @@ -691,7 +691,7 @@ <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">Ajouter un serveur de clefs</string> <string name="edit_keyserver_dialog_title">Modifier le serveur de clefs</string> - <string name="add_keyserver_verified">Le serveur de clefs a été vérifié !</string> + <string name="add_keyserver_connection_verified">Le serveur de clefs a été vérifié !</string> <string name="add_keyserver_without_verification">Le serveur de clefs a été ajouté sans vérification.</string> <string name="add_keyserver_invalid_url">URL invalide !</string> <string name="add_keyserver_connection_failed">Échec de connexion au serveur de clefs. Veuillez vérifier l\'URL et votre connexion Internet.</string> diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml index 9f58dc3ba..5b87c6ced 100644 --- a/OpenKeychain/src/main/res/values-it/strings.xml +++ b/OpenKeychain/src/main/res/values-it/strings.xml @@ -149,7 +149,7 @@ <string name="label_enable_compression">Abilitare compressione</string> <string name="label_encrypt_filenames">Codifica nome dei file</string> <string name="label_hidden_recipients">Nascondi destinatari</string> - <string name="label_verify_keyserver">Verificare server chiavi</string> + <string name="label_verify_keyserver_connection">Verificare server chiavi</string> <string name="label_enter_keyserver_url">Inserisci URL server chiavi</string> <string name="label_keyserver_dialog_delete">Cancella server chiavi</string> <string name="pref_keyserver">Server chiavi OpenPGP</string> diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml index 6f735b35b..789a35e75 100644 --- a/OpenKeychain/src/main/res/values-ja/strings.xml +++ b/OpenKeychain/src/main/res/values-ja/strings.xml @@ -155,7 +155,7 @@ <string name="label_enable_compression">圧縮を有効</string> <string name="label_encrypt_filenames">暗号化するファイル名</string> <string name="label_hidden_recipients">受信者を隠す</string> - <string name="label_verify_keyserver">鍵サーバを検証</string> + <string name="label_verify_keyserver_connection">鍵サーバを検証</string> <string name="label_enter_keyserver_url">鍵サーバのURLを入力</string> <string name="label_keyserver_dialog_delete">鍵サーバの削除</string> <string name="label_theme">テーマ</string> @@ -382,7 +382,7 @@ <string name="progress_deleting">鍵の削除中...</string> <string name="progress_con_saving">統合: キャッシュへ保存…</string> <string name="progress_con_reimport">統合: 再インポート中…</string> - <string name="progress_verifying_keyserver_url">鍵サーバの検証...</string> + <string name="progress_verifying_keyserver_connection">鍵サーバの検証...</string> <string name="progress_starting_orbot">Orbotを始める...</string> <!--action strings--> <string name="hint_cloud_search_hint">名前、Email...で検索</string> @@ -674,7 +674,7 @@ <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">鍵サーバを追加</string> <string name="edit_keyserver_dialog_title">鍵サーバの編集</string> - <string name="add_keyserver_verified">鍵サーバを検証しました!</string> + <string name="add_keyserver_connection_verified">鍵サーバを検証しました!</string> <string name="add_keyserver_without_verification">鍵サーバを検証なしで追加した。</string> <string name="add_keyserver_invalid_url">無効なURLです!</string> <string name="add_keyserver_connection_failed">鍵サーバへの接続し失敗。URLとあなたのインターネット接続をチェックしてください。</string> diff --git a/OpenKeychain/src/main/res/values-nl/strings.xml b/OpenKeychain/src/main/res/values-nl/strings.xml index 1a02fdc07..812376026 100644 --- a/OpenKeychain/src/main/res/values-nl/strings.xml +++ b/OpenKeychain/src/main/res/values-nl/strings.xml @@ -151,7 +151,7 @@ <string name="label_enable_compression">Compressie aanzetten</string> <string name="label_encrypt_filenames">Versleutel bestandsnamen</string> <string name="label_hidden_recipients">Verberg ontvangers</string> - <string name="label_verify_keyserver">Sleutelserver verifiëren</string> + <string name="label_verify_keyserver_connection">Sleutelserver verifiëren</string> <string name="label_enter_keyserver_url">Voer sleutelserver-URL in</string> <string name="label_keyserver_dialog_delete">Sleutelserver verwijderen</string> <string name="label_theme">Thema</string> @@ -366,7 +366,7 @@ <string name="progress_deleting">bezig met verwijderen van sleutels…</string> <string name="progress_con_saving">consolidatie: bezig met opslaan naar cache…</string> <string name="progress_con_reimport">consolidatie: bezig met opnieuw importeren…</string> - <string name="progress_verifying_keyserver_url">bezig met verifiëren van sleutelserver…</string> + <string name="progress_verifying_keyserver_connection">bezig met verifiëren van sleutelserver…</string> <!--action strings--> <string name="hint_cloud_search_hint">Zoeken via naam, e-mail, ...</string> <!--key bit length selections--> @@ -648,7 +648,7 @@ <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">Sleutelserver toevoegen</string> <string name="edit_keyserver_dialog_title">Sleutelserver bewerken</string> - <string name="add_keyserver_verified">Sleutelserver geverifieerd!</string> + <string name="add_keyserver_connection_verified">Sleutelserver geverifieerd!</string> <string name="add_keyserver_without_verification">Sleutelserver toegevoegd zonder verificatie.</string> <string name="add_keyserver_invalid_url">Ongeldige URL!</string> <string name="add_keyserver_connection_failed">Kon niet verbinden met sleutelserver. Controleer de URL en je internetverbinding.</string> diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml index 55a5afa5e..6b73d367c 100644 --- a/OpenKeychain/src/main/res/values-ru/strings.xml +++ b/OpenKeychain/src/main/res/values-ru/strings.xml @@ -152,7 +152,7 @@ <string name="label_enable_compression">Использовать сжатие</string> <string name="label_encrypt_filenames">Шифровать имена файлов</string> <string name="label_hidden_recipients">Скрыть получателей</string> - <string name="label_verify_keyserver">Подтвердить сервер ключей</string> + <string name="label_verify_keyserver_connection">Подтвердить сервер ключей</string> <string name="label_enter_keyserver_url">Введите адрес сервера ключей</string> <string name="label_keyserver_dialog_delete">Удалить сервер ключей</string> <string name="label_theme">Тема</string> @@ -364,7 +364,7 @@ <string name="progress_deleting">удаление ключей...</string> <string name="progress_con_saving">объединение: сохранение в кэш...</string> <string name="progress_con_reimport">объединение: реимпорт...</string> - <string name="progress_verifying_keyserver_url">подтверждение сервера ключей...</string> + <string name="progress_verifying_keyserver_connection">подтверждение сервера ключей...</string> <!--action strings--> <string name="hint_cloud_search_hint">Искать через Имя, Email...</string> <!--key bit length selections--> @@ -568,7 +568,7 @@ <string name="view_key_fragment_no_system_contact"><нет></string> <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">Добавить сервер ключей</string> - <string name="add_keyserver_verified">Сервер ключей подтверждён!</string> + <string name="add_keyserver_connection_verified">Сервер ключей подтверждён!</string> <string name="add_keyserver_without_verification">Сервер ключей добавлен без подтверждения.</string> <string name="add_keyserver_invalid_url">Неправильный адрес!</string> <!--Navigation Drawer--> diff --git a/OpenKeychain/src/main/res/values-sr/strings.xml b/OpenKeychain/src/main/res/values-sr/strings.xml index 5c6d03950..ed7bce5f7 100644 --- a/OpenKeychain/src/main/res/values-sr/strings.xml +++ b/OpenKeychain/src/main/res/values-sr/strings.xml @@ -155,7 +155,7 @@ <string name="label_enable_compression">Омогући компресију</string> <string name="label_encrypt_filenames">Шифруј имена фајлова</string> <string name="label_hidden_recipients">Сакриј примаоце</string> - <string name="label_verify_keyserver">Овери сервер кључева</string> + <string name="label_verify_keyserver_connection">Овери сервер кључева</string> <string name="label_enter_keyserver_url">Унесите УРЛ сервера кључева</string> <string name="label_keyserver_dialog_delete">Обриши сервер кључева</string> <string name="label_theme">Тема</string> @@ -390,7 +390,7 @@ <string name="progress_deleting">бришем кључеве…</string> <string name="progress_con_saving">учвршћивање: уписујем у кеш…</string> <string name="progress_con_reimport">учвршћивање: поново увозим…</string> - <string name="progress_verifying_keyserver_url">оверавам сервер кључева…</string> + <string name="progress_verifying_keyserver_connection">оверавам сервер кључева…</string> <string name="progress_starting_orbot">Покрећем Орбот…</string> <!--action strings--> <string name="hint_cloud_search_hint">Тражи преко имена, е-адресе…</string> @@ -709,7 +709,7 @@ <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">Додај сервер кључева</string> <string name="edit_keyserver_dialog_title">Промени сервер кључева</string> - <string name="add_keyserver_verified">Сервер кључева оверен!</string> + <string name="add_keyserver_connection_verified">Сервер кључева оверен!</string> <string name="add_keyserver_without_verification">Сервер кључева додат без оверивања.</string> <string name="add_keyserver_invalid_url">Неисправан УРЛ!</string> <string name="add_keyserver_connection_failed">Неуспех повезивања са сервером кључева. Проверите УРЛ и вашу везу са интернетом.</string> diff --git a/OpenKeychain/src/main/res/values-sv/strings.xml b/OpenKeychain/src/main/res/values-sv/strings.xml index 1ccac9199..4a0a9d083 100644 --- a/OpenKeychain/src/main/res/values-sv/strings.xml +++ b/OpenKeychain/src/main/res/values-sv/strings.xml @@ -135,7 +135,7 @@ <string name="label_enable_compression">Aktivera kompression</string> <string name="label_encrypt_filenames">Kryptera filnamn</string> <string name="label_hidden_recipients">Dölj mottagare</string> - <string name="label_verify_keyserver">Verifiera nyckelserver</string> + <string name="label_verify_keyserver_connection">Verifiera nyckelserver</string> <string name="label_enter_keyserver_url">Ange nyckelserver-URL</string> <string name="pref_keyserver">OpenPGP nyckelservrar</string> <string name="pref_keyserver_summary">Sök nycklar på valda OpenPGP nyckelservrar (HKP-protokollet)</string> @@ -313,7 +313,7 @@ <string name="progress_deleting">raderar nycklar…</string> <string name="progress_con_saving">konsolidera: sparar till cache…</string> <string name="progress_con_reimport">konsolidera: återimporterar…</string> - <string name="progress_verifying_keyserver_url">verifierar nyckelserver...</string> + <string name="progress_verifying_keyserver_connection">verifierar nyckelserver...</string> <!--action strings--> <string name="hint_cloud_search_hint">Söker via Namn, E-post...</string> <!--key bit length selections--> @@ -565,7 +565,7 @@ <string name="view_key_fragment_no_system_contact"><ingen></string> <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">Lägg till nyckelserver</string> - <string name="add_keyserver_verified">Nyckelserver verifierad!</string> + <string name="add_keyserver_connection_verified">Nyckelserver verifierad!</string> <string name="add_keyserver_without_verification">Nyckelserver tillagd utan verifiering.</string> <string name="add_keyserver_invalid_url">Ogiltig URL!</string> <string name="add_keyserver_connection_failed">Misslyckades med att ansluta till nyckelserver. Kontrollera URL:en och din internetanslutning.</string> diff --git a/OpenKeychain/src/main/res/values-zh-rTW/strings.xml b/OpenKeychain/src/main/res/values-zh-rTW/strings.xml index 74d1cd781..87144422d 100644 --- a/OpenKeychain/src/main/res/values-zh-rTW/strings.xml +++ b/OpenKeychain/src/main/res/values-zh-rTW/strings.xml @@ -149,7 +149,7 @@ <string name="label_enable_compression">啓用壓縮</string> <string name="label_encrypt_filenames">加密檔名</string> <string name="label_hidden_recipients">隱藏收件人</string> - <string name="label_verify_keyserver">驗證金鑰伺服器</string> + <string name="label_verify_keyserver_connection">驗證金鑰伺服器</string> <string name="label_enter_keyserver_url">輸入金鑰伺服器網址</string> <string name="label_keyserver_dialog_delete">刪除金鑰伺服器</string> <string name="label_theme">主題</string> @@ -362,7 +362,7 @@ <string name="progress_verifying_integrity">正在驗證完整性…</string> <string name="progress_deleting_securely">正在安全地刪除 \'%s\'...</string> <string name="progress_deleting">正在刪除金鑰…</string> - <string name="progress_verifying_keyserver_url">正在驗證金鑰伺服器...</string> + <string name="progress_verifying_keyserver_connection">正在驗證金鑰伺服器...</string> <string name="progress_starting_orbot">正在啟動Orbot...</string> <!--action strings--> <string name="hint_cloud_search_hint">使用姓名,電子郵件尋找...</string> @@ -625,7 +625,7 @@ <!--Add/Edit keyserver--> <string name="add_keyserver_dialog_title">新增金鑰伺服器</string> <string name="edit_keyserver_dialog_title">編輯金鑰伺服器</string> - <string name="add_keyserver_verified">已驗證金鑰伺服器!</string> + <string name="add_keyserver_connection_verified">已驗證金鑰伺服器!</string> <string name="add_keyserver_without_verification">已新增金鑰伺服器但並未進行驗證。</string> <string name="add_keyserver_invalid_url">URL無效!</string> <string name="add_keyserver_connection_failed">連線到金鑰伺服器失敗。請確認金鑰伺服器網址及網路連線。</string> diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index aa25b2aa7..360ecb136 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -63,6 +63,7 @@ <string name="section_share_key">"Key"</string> <string name="section_key_server">"Keyserver"</string> <string name="section_fingerprint">"Fingerprint"</string> + <string name="section_phrases">"Phrases"</string> <string name="section_encrypt">"Encrypt"</string> <string name="section_decrypt">"Decrypt / Verify"</string> <string name="section_current_expiry">"Current expiry"</string> @@ -84,12 +85,14 @@ <string name="btn_back">"Back"</string> <string name="btn_no">"No"</string> <string name="btn_match">"Fingerprints match"</string> + <string name="btn_match_phrases">"Phrases match"</string> <string name="btn_share_encrypted_signed">"Encrypt/sign and share text"</string> <string name="btn_copy_encrypted_signed">"Encrypt/sign and copy text"</string> <string name="btn_view_cert_key">"View certification key"</string> <string name="btn_create_key">"Create key"</string> <string name="btn_add_files">"Add file(s)"</string> <string name="btn_share_decrypted_text">"Share"</string> + <string name="btn_open_with">"Open with…"</string> <string name="btn_copy_decrypted_text">"Copy decrypted text"</string> <string name="btn_decrypt_clipboard">"Read from clipboard"</string> <string name="btn_decrypt_files">"Select input file"</string> @@ -100,6 +103,7 @@ <string name="btn_add_keyserver">"Add"</string> <string name="btn_save_default">"Save as default"</string> <string name="btn_saved">"Saved!"</string> + <string name="btn_not_matching">"Doesn't match"</string> <!-- menu --> <string name="menu_preferences">"Settings"</string> @@ -116,7 +120,7 @@ <string name="menu_update_all_keys">"Update all keys"</string> <string name="menu_advanced">"Extended information"</string> <string name="menu_certify_fingerprint">"Confirm via fingerprint"</string> - <string name="menu_certify_fingerprint_word">"Confirm via words"</string> + <string name="menu_certify_fingerprint_phrases">"Confirm via phrases"</string> <string name="menu_share_log">"Share Log"</string> <string name="menu_keyserver_add">"Add"</string> @@ -173,8 +177,9 @@ <string name="label_encrypt_filenames">"Encrypt filenames"</string> <string name="label_hidden_recipients">"Hide recipients"</string> - <string name="label_verify_keyserver">"Verify keyserver"</string> - <string name="label_enter_keyserver_url">"Enter keyserver URL"</string> + <string name="label_verify_keyserver_connection">"Test connection"</string> + <string name="label_only_trusted_keyserver">"Only trusted keyserver"</string> + <string name="label_enter_keyserver_url">"URL"</string> <string name="label_keyserver_dialog_delete">"Delete keyserver"</string> <string name="label_theme">"Theme"</string> @@ -195,8 +200,8 @@ <string name="label_experimental_settings_desc_title">"Warning"</string> <string name="label_experimental_settings_desc_summary">"These features are not yet finished or results of user experience/security research. Thus, don't rely on their security and please don't report issues you encounter!"</string> - <string name="label_experimental_settings_word_confirm_title">"Word Confirm"</string> - <string name="label_experimental_settings_word_confirm_summary">"Confirm keys with words instead of hexadecimal fingerprints"</string> + <string name="label_experimental_settings_word_confirm_title">"Phrase Confirmation"</string> + <string name="label_experimental_settings_word_confirm_summary">"Confirm keys with phrases instead of hexadecimal fingerprints"</string> <string name="label_experimental_settings_linked_identities_title">"Linked Identities"</string> <string name="label_experimental_settings_linked_identities_summary">"Link keys to Twitter, GitHub, websites or DNS (similar to keybase.io but decentralized)"</string> <string name="label_experimental_settings_keybase_title">"Keybase.io Proofs"</string> @@ -446,7 +451,7 @@ <string name="progress_con_saving">"consolidate: saving to cache…"</string> <string name="progress_con_reimport">"consolidate: reimporting…"</string> - <string name="progress_verifying_keyserver_url">"verifying keyserver…"</string> + <string name="progress_verifying_keyserver_connection">"verifying connection…"</string> <string name="progress_starting_orbot">"Starting Orbot…"</string> @@ -779,9 +784,10 @@ <!-- Add/Edit keyserver --> <string name="add_keyserver_dialog_title">"Add keyserver"</string> <string name="edit_keyserver_dialog_title">"Edit keyserver"</string> - <string name="add_keyserver_verified">"Keyserver verified!"</string> + <string name="add_keyserver_connection_verified">"Connection verified!"</string> <string name="add_keyserver_without_verification">"Keyserver added without verification."</string> <string name="add_keyserver_invalid_url">"Invalid URL!"</string> + <string name="add_keyserver_keyserver_not_trusted">"Keyserver is not one of the trusted ones (no pinned certificate available)!"</string> <string name="add_keyserver_connection_failed">"Failed to connect to keyserver. Please check the URL and your Internet connection."</string> <string name="keyserver_preference_deleted">"%s deleted"</string> <string name="keyserver_preference_cannot_delete_last">"Cannot delete last keyserver. At least one is required!"</string> @@ -990,6 +996,7 @@ <string name="msg_kc_uid_no_cert">"No valid self-certificate found for user ID '%s', removing from ring"</string> <string name="msg_kc_uid_remove">"Removing invalid user ID '%s'"</string> <string name="msg_kc_uid_dup">"Removing duplicate user ID '%s'. The keyring contained two of them. This may result in missing certificates!"</string> + <string name="msg_kc_uid_too_many">"Removing user ID '%s'. More than 100 User IDs are not imported!"</string> <string name="msg_kc_uid_warn_encoding">"User ID does not verify as UTF-8!"</string> <string name="msg_kc_uat_jpeg">"Processing user attribute of type JPEG"</string> <string name="msg_kc_uat_unknown">"Processing user attribute of unknown type"</string> @@ -1362,7 +1369,7 @@ <string name="msg_data_detached_unsupported">"Unsupported type of detached signature!"</string> <string name="msg_data_error_io">"Error reading input data!"</string> <string name="msg_data_error_openpgp">"Error processing OpenPGP data!"</string> - <string name="msg_data_mime_error">"Error parsing MIME data!"</string> + <string name="msg_data_mime_bad">"Could not parse as MIME data"</string> <string name="msg_data_mime_filename">"Filename: '%s'"</string> <string name="msg_data_mime_length">"Content-Length: %s"</string> <string name="msg_data_mime">"Parsing MIME data structure"</string> @@ -1441,9 +1448,8 @@ <string name="certs_text">"Only validated self-certificates and validated certificates created with your keys are displayed here."</string> <string name="section_uids_to_certify">"Identities for "</string> <string name="certify_text">"The keys you are importing contain “identities”: names and email addresses. Select exactly those for confirmation which match what you expected."</string> - <string name="certify_fingerprint_text">"Compare the displayed fingerprint, character by character, with the one displayed on your partners device."</string> - <string name="certify_fingerprint_text_words">"Compare the displayed fingerprint, word by word, with the one displayed on your partners device."</string> - <string name="certify_fingerprint_text2">"Do the fingerprints match?"</string> + <string name="certify_fingerprint_text">"Compare the fingerprint, character by character, with the one displayed on your partner’s device."</string> + <string name="certify_fingerprint_text_phrases">"Compare these phrases with the ones displayed on your partner’s device."</string> <string name="label_revocation">"Revocation Reason"</string> <string name="label_cert_type">"Type"</string> <string name="error_key_not_found">"Key not found!"</string> @@ -46,7 +46,7 @@ Expand the Tools directory and select "Android SDK Build-tools (Version 21.1.2)" Expand the Extras directory and install "Android Support Repository" Select everything for the newest SDK Platform, API 22, and also API 21 5. Export ANDROID_HOME pointing to your Android SDK -6. Execute ``./gradlew build`` +6. Execute ``./gradlew assembleDebug`` 7. You can install the app with ``adb install -r OpenKeychain/build/outputs/apk/OpenKeychain-debug-unaligned.apk`` ### Run Tests diff --git a/extern/KeybaseLib b/extern/KeybaseLib -Subproject 0b0a60533c5f76b60e43895f3a0342bb0be6853 +Subproject b89648f50011445df59fa02f16a0691857aea68 |