Commit 018aa781 authored by Max Lv's avatar Max Lv

Merge branch 'develop' into beta

parents 3fa8a0c9 f7e2f869
...@@ -29,7 +29,8 @@ ...@@ -29,7 +29,8 @@
url = https://android.googlesource.com/platform/external/pcre url = https://android.googlesource.com/platform/external/pcre
[submodule "mobile/src/main/jni/libsodium"] [submodule "mobile/src/main/jni/libsodium"]
path = mobile/src/main/jni/libsodium path = mobile/src/main/jni/libsodium
url = https://github.com/shadowsocks/libsodium.git url = https://github.com/jedisct1/libsodium.git
branch = stable
[submodule "mobile/src/main/jni/libev"] [submodule "mobile/src/main/jni/libev"]
path = mobile/src/main/jni/libev path = mobile/src/main/jni/libev
url = https://github.com/shadowsocks/libev.git url = https://github.com/shadowsocks/libev.git
......
...@@ -18,7 +18,7 @@ lazy val commonSettings = Seq( ...@@ -18,7 +18,7 @@ lazy val commonSettings = Seq(
typedResources := false typedResources := false
) )
val supportLibsVersion = "25.1.0" val supportLibsVersion = "25.1.1"
lazy val root = Project(id = "shadowsocks-android", base = file(".")) lazy val root = Project(id = "shadowsocks-android", base = file("."))
.settings(commonSettings) .settings(commonSettings)
.aggregate(plugin, mobile) .aggregate(plugin, mobile)
......
...@@ -26,115 +26,32 @@ include $(CLEAR_VARS) ...@@ -26,115 +26,32 @@ include $(CLEAR_VARS)
SODIUM_SOURCE := \ SODIUM_SOURCE := \
crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c \ crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c \
crypto_auth/crypto_auth.c \
crypto_auth/hmacsha256/auth_hmacsha256_api.c \
crypto_auth/hmacsha256/cp/hmac_hmacsha256.c \
crypto_auth/hmacsha256/cp/verify_hmacsha256.c \
crypto_auth/hmacsha512/auth_hmacsha512_api.c \
crypto_auth/hmacsha512/cp/hmac_hmacsha512.c \
crypto_auth/hmacsha512/cp/verify_hmacsha512.c \
crypto_auth/hmacsha512256/auth_hmacsha512256_api.c \
crypto_auth/hmacsha512256/cp/hmac_hmacsha512256.c \
crypto_auth/hmacsha512256/cp/verify_hmacsha512256.c \
crypto_box/crypto_box.c \
crypto_box/crypto_box_easy.c \
crypto_box/crypto_box_seal.c \
crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305_api.c \
crypto_box/curve25519xsalsa20poly1305/ref/after_curve25519xsalsa20poly1305.c \
crypto_box/curve25519xsalsa20poly1305/ref/before_curve25519xsalsa20poly1305.c \
crypto_box/curve25519xsalsa20poly1305/ref/box_curve25519xsalsa20poly1305.c \
crypto_box/curve25519xsalsa20poly1305/ref/keypair_curve25519xsalsa20poly1305.c \
crypto_core/hsalsa20/ref2/core_hsalsa20.c \
crypto_core/hsalsa20/core_hsalsa20_api.c \
crypto_core/salsa20/ref/core_salsa20.c \ crypto_core/salsa20/ref/core_salsa20.c \
crypto_core/salsa20/core_salsa20_api.c \
crypto_generichash/crypto_generichash.c \
crypto_generichash/blake2/generichash_blake2_api.c \
crypto_generichash/blake2/ref/blake2-impl.h \
crypto_generichash/blake2/ref/blake2.h \
crypto_generichash/blake2/ref/blake2b-compress-ref.c \ crypto_generichash/blake2/ref/blake2b-compress-ref.c \
crypto_generichash/blake2/ref/blake2b-load-sse2.h \
crypto_generichash/blake2/ref/blake2b-load-sse41.h \
crypto_generichash/blake2/ref/blake2b-ref.c \ crypto_generichash/blake2/ref/blake2b-ref.c \
crypto_generichash/blake2/ref/blake2b-round.h \
crypto_generichash/blake2/ref/generichash_blake2b.c \ crypto_generichash/blake2/ref/generichash_blake2b.c \
crypto_hash/crypto_hash.c \
crypto_hash/sha256/hash_sha256_api.c \
crypto_hash/sha256/cp/hash_sha256.c \
crypto_hash/sha512/hash_sha512_api.c \
crypto_hash/sha512/cp/hash_sha512.c \
crypto_onetimeauth/crypto_onetimeauth.c \
crypto_onetimeauth/poly1305/onetimeauth_poly1305.c \ crypto_onetimeauth/poly1305/onetimeauth_poly1305.c \
crypto_onetimeauth/poly1305/onetimeauth_poly1305.h \
crypto_onetimeauth/poly1305/donna/poly1305_donna.h \
crypto_onetimeauth/poly1305/donna/poly1305_donna32.h \
crypto_onetimeauth/poly1305/donna/poly1305_donna64.h \
crypto_onetimeauth/poly1305/donna/poly1305_donna.c \ crypto_onetimeauth/poly1305/donna/poly1305_donna.c \
crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c \ crypto_pwhash/crypto_pwhash.c \
crypto_pwhash/scryptsalsa208sha256/crypto_scrypt.h \ crypto_pwhash/argon2/argon2-core.c \
crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c \ crypto_pwhash/argon2/argon2.c \
crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c \ crypto_pwhash/argon2/argon2-encoding.c \
crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.h \ crypto_pwhash/argon2/argon2-fill-block-ref.c \
crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c \ crypto_pwhash/argon2/blake2b-long.c \
crypto_pwhash/scryptsalsa208sha256/sysendian.h \ crypto_pwhash/argon2/pwhash_argon2i.c \
crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c \
crypto_scalarmult/crypto_scalarmult.c \
crypto_scalarmult/curve25519/scalarmult_curve25519.c \ crypto_scalarmult/curve25519/scalarmult_curve25519.c \
crypto_scalarmult/curve25519/scalarmult_curve25519.h \
crypto_secretbox/crypto_secretbox.c \
crypto_secretbox/crypto_secretbox_easy.c \
crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305_api.c \
crypto_shorthash/crypto_shorthash.c \
crypto_shorthash/siphash24/shorthash_siphash24_api.c \
crypto_shorthash/siphash24/ref/shorthash_siphash24.c \
crypto_sign/crypto_sign.c \
crypto_sign/ed25519/ref10/base.h \
crypto_sign/ed25519/ref10/base2.h \
crypto_sign/ed25519/sign_ed25519_api.c \
crypto_sign/ed25519/ref10/keypair.c \
crypto_sign/ed25519/ref10/open.c \
crypto_sign/ed25519/ref10/obsolete.c \
crypto_sign/ed25519/ref10/sign.c \
crypto_stream/crypto_stream.c \
crypto_stream/chacha20/stream_chacha20.c \ crypto_stream/chacha20/stream_chacha20.c \
crypto_stream/chacha20/stream_chacha20.h \
crypto_stream/chacha20/ref/stream_chacha20_ref.h \
crypto_stream/chacha20/ref/stream_chacha20_ref.c \ crypto_stream/chacha20/ref/stream_chacha20_ref.c \
crypto_stream/salsa20/stream_salsa20_api.c \ crypto_stream/salsa20/ref/stream_salsa20_ref.c \
crypto_stream/xsalsa20/stream_xsalsa20_api.c \ crypto_stream/salsa20/ref/xor_salsa20_ref.c \
crypto_stream/xsalsa20/ref/stream_xsalsa20.c \
crypto_stream/xsalsa20/ref/xor_xsalsa20.c \
crypto_verify/16/verify_16_api.c \
crypto_verify/16/ref/verify_16.c \ crypto_verify/16/ref/verify_16.c \
crypto_verify/32/verify_32_api.c \
crypto_verify/32/ref/verify_32.c \
crypto_verify/64/verify_64_api.c \
crypto_verify/64/ref/verify_64.c \
randombytes/randombytes.c \ randombytes/randombytes.c \
randombytes/sysrandom/randombytes_sysrandom.c \
sodium/core.c \ sodium/core.c \
sodium/runtime.c \ sodium/runtime.c \
sodium/utils.c \ sodium/utils.c \
sodium/version.c sodium/version.c
SODIUM_SOURCE += \
crypto_scalarmult/curve25519/ref10/x25519_ref10.c
SODIUM_SOURCE += \
crypto_pwhash/argon2/argon2-core.c \
crypto_pwhash/argon2/argon2.c \
crypto_pwhash/argon2/argon2-encoding.c \
crypto_pwhash/argon2/blake2b-long.c \
crypto_pwhash/argon2/argon2-fill-block-ref.c \
crypto_pwhash/argon2/pwhash_argon2i.c \
crypto_pwhash/argon2/argon2-fill-block-ssse3.c
SODIUM_SOURCE += \
crypto_stream/salsa20/ref/stream_salsa20_ref.c \
crypto_stream/salsa20/ref/xor_salsa20_ref.c
SODIUM_SOURCE += \
randombytes/sysrandom/randombytes_sysrandom.c
LOCAL_MODULE := sodium LOCAL_MODULE := sodium
LOCAL_CFLAGS += -O2 -I$(LOCAL_PATH)/libsodium/src/libsodium/include \ LOCAL_CFLAGS += -O2 -I$(LOCAL_PATH)/libsodium/src/libsodium/include \
-I$(LOCAL_PATH)/include \ -I$(LOCAL_PATH)/include \
...@@ -329,8 +246,10 @@ include $(BUILD_SHARED_EXECUTABLE) ...@@ -329,8 +246,10 @@ include $(BUILD_SHARED_EXECUTABLE)
include $(CLEAR_VARS) include $(CLEAR_VARS)
SHADOWSOCKS_SOURCES := local.c cache.c udprelay.c encrypt.c \ SHADOWSOCKS_SOURCES := local.c \
utils.c netutils.c json.c jconf.c acl.c http.c tls.c rule.c \ cache.c udprelay.c utils.c netutils.c json.c jconf.c \
acl.c http.c tls.c rule.c \
crypto.c aead.c stream.c base64.c \
plugin.c \ plugin.c \
android.c android.c
...@@ -364,7 +283,11 @@ include $(BUILD_SHARED_EXECUTABLE) ...@@ -364,7 +283,11 @@ include $(BUILD_SHARED_EXECUTABLE)
include $(CLEAR_VARS) include $(CLEAR_VARS)
SHADOWSOCKS_SOURCES := tunnel.c cache.c udprelay.c encrypt.c utils.c netutils.c json.c jconf.c android.c plugin.c SHADOWSOCKS_SOURCES := tunnel.c \
cache.c udprelay.c utils.c netutils.c json.c jconf.c \
crypto.c aead.c stream.c base64.c \
plugin.c \
android.c
LOCAL_MODULE := ss-tunnel LOCAL_MODULE := ss-tunnel
LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES)) LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES))
......
Subproject commit a81cea2366b9e814861a6f47e5bd460e06f19295 Subproject commit e160de24fd146ab84b4eb397c7cffbf34775aa02
Subproject commit 1c2b6170b9ec5443d4a3e211425bc0d5f8e18119 Subproject commit f4b1641636942bc44c96160afad9f023fb6dbf0e
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string-array name="enc_method_entry"> <string-array name="enc_method_entry">
<item>TABLE</item>
<item>RC4</item>
<item>RC4-MD5</item> <item>RC4-MD5</item>
<item>AES-128-CFB</item> <item>AES-128-CFB</item>
<item>AES-192-CFB</item> <item>AES-192-CFB</item>
...@@ -17,11 +15,14 @@ ...@@ -17,11 +15,14 @@
<item>SALSA20</item> <item>SALSA20</item>
<item>CHACHA20</item> <item>CHACHA20</item>
<item>CHACHA20-IETF</item> <item>CHACHA20-IETF</item>
<item>AES-128-GCM</item>
<item>AES-192-GCM</item>
<item>AES-256-GCM</item>
<item>CHACHA20-POLY1305</item>
<item>CHACHA20-IETF-POLY1305</item>
</string-array> </string-array>
<string-array name="enc_method_value"> <string-array name="enc_method_value">
<item>table</item>
<item>rc4</item>
<item>rc4-md5</item> <item>rc4-md5</item>
<item>aes-128-cfb</item> <item>aes-128-cfb</item>
<item>aes-192-cfb</item> <item>aes-192-cfb</item>
...@@ -36,6 +37,11 @@ ...@@ -36,6 +37,11 @@
<item>salsa20</item> <item>salsa20</item>
<item>chacha20</item> <item>chacha20</item>
<item>chacha20-ietf</item> <item>chacha20-ietf</item>
<item>aes-128-gcm</item>
<item>aes-192-gcm</item>
<item>aes-256-gcm</item>
<item>chacha20-poly1305</item>
<item>chacha20-ietf-poly1305</item>
</string-array> </string-array>
<string-array name="route_entry"> <string-array name="route_entry">
......
...@@ -36,8 +36,6 @@ ...@@ -36,8 +36,6 @@
<!-- feature category --> <!-- feature category -->
<string name="ipv6">IPv6 Route</string> <string name="ipv6">IPv6 Route</string>
<string name="ipv6_summary">Redirect IPv6 traffic to remote</string> <string name="ipv6_summary">Redirect IPv6 traffic to remote</string>
<string name="onetime_auth">One-time Authentication</string>
<string name="onetime_auth_summary">Enable one-time authentication</string>
<string name="route_list">Route</string> <string name="route_list">Route</string>
<string name="route_entry_all">All</string> <string name="route_entry_all">All</string>
<string name="route_entry_bypass_lan">Bypass LAN</string> <string name="route_entry_bypass_lan">Bypass LAN</string>
...@@ -62,7 +60,6 @@ ...@@ -62,7 +60,6 @@
<string name="forward_success">Shadowsocks started.</string> <string name="forward_success">Shadowsocks started.</string>
<string name="invalid_server">Invalid server name</string> <string name="invalid_server">Invalid server name</string>
<string name="service_failed">Failed to connect the remote server</string> <string name="service_failed">Failed to connect the remote server</string>
<string name="method_unsafe">WARNING: The current encryption method is unsafe</string>
<string name="nat_deprecated">WARNING: NAT mode has been deprecated since Android 5.0</string> <string name="nat_deprecated">WARNING: NAT mode has been deprecated since Android 5.0</string>
<string name="nat_no_root">NAT mode requires ROOT permission</string> <string name="nat_no_root">NAT mode requires ROOT permission</string>
<string name="switch_to_vpn">Switch to VPN mode</string> <string name="switch_to_vpn">Switch to VPN mode</string>
......
...@@ -37,10 +37,6 @@ ...@@ -37,10 +37,6 @@
android:entryValues="@array/enc_method_value" android:entryValues="@array/enc_method_value"
android:summary="%s" android:summary="%s"
android:title="@string/enc_method"/> android:title="@string/enc_method"/>
<SwitchPreference
android:key="isAuth"
android:summary="@string/onetime_auth_summary"
android:title="@string/onetime_auth"/>
</be.mygod.preference.PreferenceCategory> </be.mygod.preference.PreferenceCategory>
......
...@@ -183,9 +183,6 @@ trait BaseService extends Service { ...@@ -183,9 +183,6 @@ trait BaseService extends Service {
changeState(State.CONNECTING) changeState(State.CONNECTING)
if (profile.isMethodUnsafe)
handler.post(() => Toast.makeText(this, R.string.method_unsafe, Toast.LENGTH_LONG).show())
Utils.ThrowableFuture(try connect() catch { Utils.ThrowableFuture(try connect() catch {
case _: NameNotResolvedException => stopRunner(stopService = true, getString(R.string.invalid_server)) case _: NameNotResolvedException => stopRunner(stopService = true, getString(R.string.invalid_server))
case _: NullConnectionException => stopRunner(stopService = true, getString(R.string.reboot_required)) case _: NullConnectionException => stopRunner(stopService = true, getString(R.string.reboot_required))
...@@ -325,7 +322,6 @@ trait BaseService extends Service { ...@@ -325,7 +322,6 @@ trait BaseService extends Service {
.put("server_port", profile.remotePort) .put("server_port", profile.remotePort)
.put("password", profile.password) .put("password", profile.password)
.put("method", profile.method) .put("method", profile.method)
if (profile.auth) config.put("auth", true)
if (pluginPath != null) config if (pluginPath != null) config
.put("plugin", Commandline.toString(buildPluginCommandLine())) .put("plugin", Commandline.toString(buildPluginCommandLine()))
.put("plugin_opts", plugin.toString) .put("plugin_opts", plugin.toString)
......
...@@ -77,9 +77,6 @@ class DBHelper(val context: Context) ...@@ -77,9 +77,6 @@ class DBHelper(val context: Context)
} else if (oldVersion < 19) { } else if (oldVersion < 19) {
profileDao.executeRawNoArgs("UPDATE `profile` SET route = 'all' WHERE route IS NULL;") profileDao.executeRawNoArgs("UPDATE `profile` SET route = 'all' WHERE route IS NULL;")
} }
if (oldVersion < 10) {
profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN auth SMALLINT;")
}
if (oldVersion < 11) { if (oldVersion < 11) {
profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN ipv6 SMALLINT;") profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN ipv6 SMALLINT;")
} }
...@@ -89,9 +86,9 @@ class DBHelper(val context: Context) ...@@ -89,9 +86,9 @@ class DBHelper(val context: Context)
TableUtils.createTable(connectionSource, classOf[Profile]) TableUtils.createTable(connectionSource, classOf[Profile])
profileDao.executeRawNoArgs( profileDao.executeRawNoArgs(
"INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, proxyApps, bypass," + "INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, proxyApps, bypass," +
" udpdns, auth, ipv6, individual) " + " udpdns, ipv6, individual) " +
"SELECT id, name, host, localPort, remotePort, password, method, route, 1 - global, bypass, udpdns, auth," + "SELECT id, name, host, localPort, remotePort, password, method, route, 1 - global, bypass, udpdns, ipv6," +
" ipv6, individual FROM `tmp`;") " individual FROM `tmp`;")
profileDao.executeRawNoArgs("DROP TABLE `tmp`;") profileDao.executeRawNoArgs("DROP TABLE `tmp`;")
profileDao.executeRawNoArgs("COMMIT;") profileDao.executeRawNoArgs("COMMIT;")
} else if (oldVersion < 13) { } else if (oldVersion < 13) {
...@@ -127,10 +124,10 @@ class DBHelper(val context: Context) ...@@ -127,10 +124,10 @@ class DBHelper(val context: Context)
profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;") profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;")
TableUtils.createTable(connectionSource, classOf[Profile]) TableUtils.createTable(connectionSource, classOf[Profile])
profileDao.executeRawNoArgs( profileDao.executeRawNoArgs(
"INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, remoteDns, proxyApps," + "INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, remoteDns, " +
" bypass, udpdns, auth, ipv6, individual, tx, rx, date, userOrder, plugin) " + "proxyApps, bypass, udpdns, ipv6, individual, tx, rx, date, userOrder, plugin) " +
"SELECT id, name, host, localPort, CASE WHEN kcp = 1 THEN kcpPort ELSE remotePort END, password, method, " + "SELECT id, name, host, localPort, CASE WHEN kcp = 1 THEN kcpPort ELSE remotePort END, password, method, " +
"route, remoteDns, proxyApps, bypass, udpdns, auth, ipv6, individual, tx, rx, date, userOrder, " + "route, remoteDns, proxyApps, bypass, udpdns, ipv6, individual, tx, rx, date, userOrder, " +
"CASE WHEN kcp = 1 THEN 'kcptun ' || kcpcli ELSE NULL END FROM `tmp`;") "CASE WHEN kcp = 1 THEN 'kcptun ' || kcpcli ELSE NULL END FROM `tmp`;")
profileDao.executeRawNoArgs("DROP TABLE `tmp`;") profileDao.executeRawNoArgs("DROP TABLE `tmp`;")
profileDao.executeRawNoArgs("COMMIT;") profileDao.executeRawNoArgs("COMMIT;")
......
...@@ -20,13 +20,13 @@ ...@@ -20,13 +20,13 @@
package com.github.shadowsocks.database package com.github.shadowsocks.database
import java.net.URLEncoder
import java.util.Locale import java.util.Locale
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri
import android.os.Binder import android.os.Binder
import android.text.TextUtils
import android.util.Base64 import android.util.Base64
import com.github.shadowsocks.plugin.PluginConfiguration
import com.github.shadowsocks.utils.Key import com.github.shadowsocks.utils.Key
import com.j256.ormlite.field.{DataType, DatabaseField} import com.j256.ormlite.field.{DataType, DatabaseField}
...@@ -68,9 +68,6 @@ class Profile { ...@@ -68,9 +68,6 @@ class Profile {
@DatabaseField @DatabaseField
var udpdns: Boolean = _ var udpdns: Boolean = _
@DatabaseField
var auth: Boolean = _
@DatabaseField @DatabaseField
var ipv6: Boolean = _ var ipv6: Boolean = _
...@@ -96,11 +93,19 @@ class Profile { ...@@ -96,11 +93,19 @@ class Profile {
def nameIsEmpty: Boolean = name == null || name.isEmpty def nameIsEmpty: Boolean = name == null || name.isEmpty
def getName: String = if (nameIsEmpty) formattedAddress else name def getName: String = if (nameIsEmpty) formattedAddress else name
override def toString: String = "ss://" + Base64.encodeToString("%s%s:%s@%s:%d".formatLocal(Locale.ENGLISH, def toUri: Uri = {
method, if (auth) "-auth" else "", password, host, remotePort).getBytes, Base64.NO_PADDING | Base64.NO_WRAP) + val builder = new Uri.Builder()
(if (TextUtils.isEmpty(name)) "" else '#' + URLEncoder.encode(name, "utf-8")) .scheme("ss")
.encodedAuthority("%s@%s:%d".formatLocal(Locale.ENGLISH,
def isMethodUnsafe: Boolean = "table".equalsIgnoreCase(method) || "rc4".equalsIgnoreCase(method) Base64.encodeToString("%s:%s".formatLocal(Locale.ENGLISH, method, password).getBytes,
Base64.NO_PADDING | Base64.NO_WRAP | Base64.URL_SAFE), host, remotePort))
val configuration = new PluginConfiguration(plugin)
if (configuration.selected.nonEmpty)
builder.appendQueryParameter(Key.plugin, configuration.selectedOptions.toString(false))
if (!nameIsEmpty) builder.fragment(name)
builder.build()
}
override def toString: String = toUri.toString
def serialize(editor: SharedPreferences.Editor): SharedPreferences.Editor = editor def serialize(editor: SharedPreferences.Editor): SharedPreferences.Editor = editor
.putString(Key.name, name) .putString(Key.name, name)
...@@ -114,7 +119,6 @@ class Profile { ...@@ -114,7 +119,6 @@ class Profile {
.putBoolean(Key.proxyApps, proxyApps) .putBoolean(Key.proxyApps, proxyApps)
.putBoolean(Key.bypass, bypass) .putBoolean(Key.bypass, bypass)
.putBoolean(Key.udpdns, udpdns) .putBoolean(Key.udpdns, udpdns)
.putBoolean(Key.auth, auth)
.putBoolean(Key.ipv6, ipv6) .putBoolean(Key.ipv6, ipv6)
.putString(Key.individual, individual) .putString(Key.individual, individual)
.putString(Key.plugin, plugin) .putString(Key.plugin, plugin)
...@@ -132,7 +136,6 @@ class Profile { ...@@ -132,7 +136,6 @@ class Profile {
proxyApps = pref.getBoolean(Key.proxyApps, false) proxyApps = pref.getBoolean(Key.proxyApps, false)
bypass = pref.getBoolean(Key.bypass, false) bypass = pref.getBoolean(Key.bypass, false)
udpdns = pref.getBoolean(Key.udpdns, false) udpdns = pref.getBoolean(Key.udpdns, false)
auth = pref.getBoolean(Key.auth, false)
ipv6 = pref.getBoolean(Key.ipv6, false) ipv6 = pref.getBoolean(Key.ipv6, false)
individual = pref.getString(Key.individual, null) individual = pref.getString(Key.individual, null)
plugin = pref.getString(Key.plugin, null) plugin = pref.getString(Key.plugin, null)
......
...@@ -141,7 +141,6 @@ object Key { ...@@ -141,7 +141,6 @@ object Key {
val proxyApps = "isProxyApps" val proxyApps = "isProxyApps"
val bypass = "isBypassApps" val bypass = "isBypassApps"
val udpdns = "isUdpDns" val udpdns = "isUdpDns"
val auth = "isAuth"
val ipv6 = "isIpv6" val ipv6 = "isIpv6"
val host = "proxy" val host = "proxy"
......
...@@ -20,32 +20,49 @@ ...@@ -20,32 +20,49 @@
package com.github.shadowsocks.utils package com.github.shadowsocks.utils
import java.net.URLDecoder import android.net.Uri
import android.util.{Base64, Log} import android.util.{Base64, Log}
import com.github.shadowsocks.database.Profile import com.github.shadowsocks.database.Profile
object Parser { object Parser {
val TAG = "ShadowParser" val TAG = "ShadowParser"
private val pattern = "(?i)ss://([A-Za-z0-9+-/=_]+)(#(.+))?".r private val pattern = "(?i)^ss://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]$".r
private val decodedPattern = "(?i)^((.+?)(-auth)??:(.*)@(.+?):(\\d+?))$".r private val userInfoPattern = "^(.+?):(.*)$".r
private val legacyPattern = "^((.+?):(.*)@(.+?):(\\d+?))$".r
def findAll(data: CharSequence): Iterator[Profile] = def findAll(data: CharSequence): Iterator[Profile] =
pattern.findAllMatchIn(if (data == null) "" else data).map(m => try pattern.findAllMatchIn(if (data == null) "" else data).map(m => {
decodedPattern.findFirstMatchIn(new String(Base64.decode(m.group(1), Base64.NO_PADDING), "UTF-8")) match { val uri = Uri.parse(m.matched)
case Some(ss) => uri.getUserInfo match {
case null => uri.getHost match {
case legacyPattern(_, method, password, host, port) => // legacy uri
val profile = new Profile
profile.method = method.toLowerCase
profile.password = password
profile.host = host
profile.remotePort = port.toInt
profile.plugin = uri.getQueryParameter(Key.plugin)
profile.name = uri.getFragment
profile
case _ =>
Log.e(TAG, "Unrecognized URI: " + m.matched)
null
}
case userInfo =>
new String(Base64.decode(userInfo, Base64.NO_PADDING | Base64.NO_WRAP | Base64.URL_SAFE)) match {
case userInfoPattern(method, password) =>
val profile = new Profile val profile = new Profile
profile.method = ss.group(2).toLowerCase profile.method = method
if (ss.group(3) != null) profile.auth = true profile.password = password
profile.password = ss.group(4) profile.host = uri.getHost
profile.host = ss.group(5) profile.remotePort = uri.getPort
profile.remotePort = ss.group(6).toInt profile.plugin = uri.getQueryParameter(Key.plugin)
if (m.group(2) != null) profile.name = URLDecoder.decode(m.group(3), "utf-8") profile.name = uri.getFragment
profile profile
case _ => null case _ =>
} catch { Log.e(TAG, "Unknown user info: " + m.matched)
case ex: Exception =>
Log.e(TAG, "parser error: " + m.source, ex)// Ignore
null null
}
}
}).filter(_ != null) }).filter(_ != null)
} }
...@@ -88,7 +88,7 @@ Then add it to your manifest: ...@@ -88,7 +88,7 @@ Then add it to your manifest:
... ...
<provider android:name=".BinaryProvider" <provider android:name=".BinaryProvider"
android:exported="true" android:exported="true"
android:authorities="com.github.shadowsocks.plugin.$PLUGIN_ID"> android:authorities="$FULLY_QUALIFIED_NAME_OF_YOUR_CONTENTPROVIDER">
<intent-filter> <intent-filter>
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/> <action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
</intent-filter> </intent-filter>
......
...@@ -2,7 +2,7 @@ enablePlugins(AndroidLib) ...@@ -2,7 +2,7 @@ enablePlugins(AndroidLib)
android.useSupportVectors android.useSupportVectors
name := "plugin" name := "plugin"
version := "0.0.1" version := "0.0.2-SNAPSHOT"
pomExtra in Global := { pomExtra in Global := {
<url>https://github.com/shadowsocks/shadowsocks-android</url> <url>https://github.com/shadowsocks/shadowsocks-android</url>
......
...@@ -153,7 +153,7 @@ This corresponds to `com.github.shadowsocks.plugin.NativePluginProvider` in the ...@@ -153,7 +153,7 @@ This corresponds to `com.github.shadowsocks.plugin.NativePluginProvider` in the
... ...
<provider android:name=".BinaryProvider" <provider android:name=".BinaryProvider"
android:exported="true" android:exported="true"
android:authorities="com.github.shadowsocks.plugin.$PLUGIN_ID"> android:authorities="$FULLY_QUALIFIED_NAME_OF_YOUR_CONTENTPROVIDER">
<intent-filter> <intent-filter>
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/> <action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
</intent-filter> </intent-filter>
......
...@@ -24,6 +24,14 @@ public final class PluginOptions extends HashMap<String, String> { ...@@ -24,6 +24,14 @@ public final class PluginOptions extends HashMap<String, String> {
super(initialCapacity, loadFactor); super(initialCapacity, loadFactor);
} }
// TODO: this method is not needed since API 24
public String getOrDefault(Object key, String defaultValue) {
String v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
private PluginOptions(String options, boolean parseId) { private PluginOptions(String options, boolean parseId) {
this(); this();
if (TextUtils.isEmpty(options)) return; if (TextUtils.isEmpty(options)) return;
......
...@@ -15,7 +15,7 @@ import android.os.{Bundle, ParcelFileDescriptor} ...@@ -15,7 +15,7 @@ import android.os.{Bundle, ParcelFileDescriptor}
* &lt;application&gt; * &lt;application&gt;
* ... * ...
* &lt;provider android:name="com.github.shadowsocks.$PLUGIN_ID.BinaryProvider" * &lt;provider android:name="com.github.shadowsocks.$PLUGIN_ID.BinaryProvider"
* android:authorities="com.github.shadowsocks.plugin.$PLUGIN_ID"&gt; * android:authorities="com.github.shadowsocks.plugin.$PLUGIN_ID.BinaryProvider"&gt;
* &lt;intent-filter&gt; * &lt;intent-filter&gt;
* &lt;category android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN" /&gt; * &lt;category android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN" /&gt;
* &lt;/intent-filter&gt; * &lt;/intent-filter&gt;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment