diff --git a/build.sbt b/build.sbt index 62d5a5ee..2b292c2b 100644 --- a/build.sbt +++ b/build.sbt @@ -30,6 +30,8 @@ resolvers += Resolver.jcenterRepo useSupportVectors +googleServicesSettings + libraryDependencies ++= Seq( "com.android.support" % "design" % "24.2.1", "com.android.support" % "gridlayout-v7" % "24.2.1", @@ -39,6 +41,8 @@ libraryDependencies ++= Seq( "com.github.kevinsawicki" % "http-request" % "6.0", "com.google.android.gms" % "play-services-ads" % "9.6.1", "com.google.android.gms" % "play-services-analytics" % "9.6.1", + "com.google.firebase" % "firebase-core" % "9.6.1", + "com.google.firebase" % "firebase-storage" % "9.6.1", "com.j256.ormlite" % "ormlite-android" % "5.0", "com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2", "dnsjava" % "dnsjava" % "2.1.7", @@ -52,6 +56,7 @@ proguardVersion in Android := "5.3" proguardCache in Android := Seq() proguardOptions in Android ++= Seq( + "-keepattributes Signature", "-keep class com.github.shadowsocks.System { *; }", "-dontwarn com.google.android.gms.internal.**", "-dontwarn com.j256.ormlite.**", diff --git a/project/plugins.sbt b/project/plugins.sbt index f10c70aa..8131ffcc 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,7 @@ addSbtPlugin("org.scala-android" % "sbt-android" % "1.6.18") +addSbtPlugin("org.scala-android" % "sbt-android-gms" % "0.2") + addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.10") addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2") diff --git a/src/main/res/xml/pref_all.xml b/src/main/res/xml/pref_all.xml index 8af41fe1..d4df4e23 100644 --- a/src/main/res/xml/pref_all.xml +++ b/src/main/res/xml/pref_all.xml @@ -121,9 +121,6 @@ android:summary="@string/nat_summary"/> - diff --git a/src/main/scala/com/github/shadowsocks/BaseService.scala b/src/main/scala/com/github/shadowsocks/BaseService.scala index e3c620b6..15aacaf3 100644 --- a/src/main/scala/com/github/shadowsocks/BaseService.scala +++ b/src/main/scala/com/github/shadowsocks/BaseService.scala @@ -39,6 +39,7 @@ package com.github.shadowsocks +import java.io.File import java.io.IOException import java.util.{Timer, TimerTask} @@ -55,6 +56,10 @@ import com.github.shadowsocks.utils._ import com.github.shadowsocks.ShadowsocksApplication.app import com.github.shadowsocks.database.Profile +import com.google.firebase.FirebaseApp +import com.google.firebase.storage.FileDownloadTask +import com.google.firebase.storage.FirebaseStorage + trait BaseService extends Service { @volatile private var state = State.STOPPED @@ -276,6 +281,7 @@ trait BaseService extends Service { override def onCreate() { super.onCreate() + FirebaseApp.initializeApp(this) app.refreshContainerHolder } @@ -311,4 +317,28 @@ trait BaseService extends Service { case ex: Exception => "exclude = " + default + ";" } } + + def getAcl(route: String) { + val localAcl = route match { + case Route.BYPASS_LAN => "bypass_lan.acl" + case Route.BYPASS_CHN => "bypass_chn.acl" + case Route.BYPASS_LAN_CHN => "bypass_lan_chn.acl" + case Route.GFWLIST => "gfwlist.acl" + case Route.CHINALIST => "chinalist.acl" + } + val cloudAclFile = new File(getApplicationInfo.dataDir + "/" + localAcl) + if (!cloudAclFile.exists) cloudAclFile.createNewFile + val tempFile = File.createTempFile(localAcl, "acl") + val storage = FirebaseStorage.getInstance + val storageRef = storage.getReferenceFromUrl("gs://admob-app-id-3330146721.appspot.com/acl/") + val aclRef = storageRef.child(localAcl) + + val task = aclRef.getFile(tempFile) + task.addOnSuccessListener((_) => { + tempFile.renameTo(cloudAclFile) + return + }) + task.addOnFailureListener((_) => Log.e("shadowsocks", "Unable to download " + localAcl)) + tempFile.deleteOnExit() + } } diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index e82dbd98..43651183 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -545,15 +545,6 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext { } } - def flushDnsCache() { - val h = showProgress(R.string.flushing) - Utils.ThrowableFuture { - if (!Utils.toggleAirplaneMode(getBaseContext)) h.post(() => Snackbar.make(findViewById(android.R.id.content), - R.string.flush_dnscache_no_root, Snackbar.LENGTH_LONG).show) - h.sendEmptyMessage(0) - } - } - override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) = resultCode match { case Activity.RESULT_OK => serviceLoad() diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index a518dc24..187db537 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -96,6 +96,7 @@ class ShadowsocksNatService extends BaseService { if (profile.route != Route.ALL) { cmd += "--acl" + profile.route match { case Route.BYPASS_LAN => cmd += (getApplicationInfo.dataDir + "/bypass_lan.acl") case Route.BYPASS_CHN => cmd += (getApplicationInfo.dataDir + "/bypass_chn.acl") @@ -336,8 +337,10 @@ class ShadowsocksNatService extends BaseService { } handleConnection() - // Set DNS - su.addCommand(Utils.FLUSH_DNS) + + // lazily get ACL from cloud + getAcl(profile.route) + changeState(State.CONNECTED) notification = new ShadowsocksNotification(this, profile.name, true) } diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala index f1304f17..a52753e1 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala @@ -170,12 +170,6 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan true }) - findPreference("flush_dnscache").setOnPreferenceClickListener(_ => { - app.track(TAG, "flush_dnscache") - activity.flushDnsCache() - true - }) - findPreference("about").setOnPreferenceClickListener((preference: Preference) => { app.track(TAG, "about") val web = new WebView(activity) diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 0c174bd3..8a49bbba 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -162,6 +162,10 @@ class ShadowsocksVpnService extends VpnService with BaseService { handleConnection() changeState(State.CONNECTED) + + // lazily get ACL from cloud + getAcl(profile.route) + notification = new ShadowsocksNotification(this, profile.name) } @@ -257,6 +261,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (profile.route != Route.ALL) { cmd += "--acl" + profile.route match { case Route.BYPASS_LAN => cmd += (getApplicationInfo.dataDir + "/bypass_lan.acl") case Route.BYPASS_CHN => cmd += (getApplicationInfo.dataDir + "/bypass_chn.acl") diff --git a/src/main/scala/com/github/shadowsocks/utils/Utils.scala b/src/main/scala/com/github/shadowsocks/utils/Utils.scala index 4c417816..e6f32f02 100644 --- a/src/main/scala/com/github/shadowsocks/utils/Utils.scala +++ b/src/main/scala/com/github/shadowsocks/utils/Utils.scala @@ -169,19 +169,6 @@ object Utils { result } - // Because /sys/class/net/* isn't accessible since API level 24 - final val FLUSH_DNS = "for if in /sys/class/net/*; do " + - "if [ \"down\" != $(cat $if/operstate) ]; then " + // up or unknown - "ndc resolver flushif ${if##*/}; " + - "fi " + - "done; echo done" - - // Blocked > 3 seconds - def toggleAirplaneMode(context: Context) = { - val result = Shell.SU.run(FLUSH_DNS) - result != null && !result.isEmpty - } - def resolve(host: String, addrType: Int): Option[String] = { try { val lookup = new Lookup(host, addrType)