Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
com.ccwangluo.accelerator
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
sheteng
com.ccwangluo.accelerator
Commits
be6cf63d
Commit
be6cf63d
authored
Feb 23, 2019
by
Mygod
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into preference-1.1
parents
f4171711
dca0da09
Changes
39
Show whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
942 additions
and
478 deletions
+942
-478
build.gradle
build.gradle
+3
-5
core/build.gradle
core/build.gradle
+9
-1
core/src/main/assets/acl/gfwlist.acl
core/src/main/assets/acl/gfwlist.acl
+372
-18
core/src/main/java/com/github/shadowsocks/acl/Acl.kt
core/src/main/java/com/github/shadowsocks/acl/Acl.kt
+3
-2
core/src/main/java/com/github/shadowsocks/aidl/ShadowsocksConnection.kt
...java/com/github/shadowsocks/aidl/ShadowsocksConnection.kt
+10
-6
core/src/main/java/com/github/shadowsocks/bg/BaseService.kt
core/src/main/java/com/github/shadowsocks/bg/BaseService.kt
+35
-29
core/src/main/java/com/github/shadowsocks/bg/Executable.kt
core/src/main/java/com/github/shadowsocks/bg/Executable.kt
+3
-4
core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
.../src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
+4
-2
core/src/main/java/com/github/shadowsocks/bg/ServiceNotification.kt
...ain/java/com/github/shadowsocks/bg/ServiceNotification.kt
+1
-1
core/src/main/java/com/github/shadowsocks/database/Profile.kt
.../src/main/java/com/github/shadowsocks/database/Profile.kt
+27
-24
core/src/main/java/com/github/shadowsocks/database/ProfileManager.kt
...in/java/com/github/shadowsocks/database/ProfileManager.kt
+35
-0
core/src/main/java/com/github/shadowsocks/net/ChannelMonitor.kt
...rc/main/java/com/github/shadowsocks/net/ChannelMonitor.kt
+12
-3
core/src/main/java/com/github/shadowsocks/net/LocalDnsServer.kt
...rc/main/java/com/github/shadowsocks/net/LocalDnsServer.kt
+11
-11
core/src/main/java/com/github/shadowsocks/net/LocalSocketListener.kt
...in/java/com/github/shadowsocks/net/LocalSocketListener.kt
+1
-1
core/src/main/java/com/github/shadowsocks/net/TcpFastOpen.kt
core/src/main/java/com/github/shadowsocks/net/TcpFastOpen.kt
+2
-1
core/src/main/java/com/github/shadowsocks/utils/DeviceStorageApp.kt
...ain/java/com/github/shadowsocks/utils/DeviceStorageApp.kt
+1
-1
core/src/main/java/com/github/shadowsocks/utils/Utils.kt
core/src/main/java/com/github/shadowsocks/utils/Utils.kt
+2
-0
core/src/main/jni/shadowsocks-libev
core/src/main/jni/shadowsocks-libev
+1
-1
core/src/main/res/values/strings.xml
core/src/main/res/values/strings.xml
+1
-0
mobile/build.gradle
mobile/build.gradle
+5
-0
mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
...om/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
+2
-2
mobile/src/main/java/com/github/shadowsocks/MainActivity.kt
mobile/src/main/java/com/github/shadowsocks/MainActivity.kt
+29
-22
mobile/src/main/java/com/github/shadowsocks/ProfileConfigActivity.kt
...main/java/com/github/shadowsocks/ProfileConfigActivity.kt
+14
-7
mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt
...main/java/com/github/shadowsocks/ProfileConfigFragment.kt
+36
-23
mobile/src/main/java/com/github/shadowsocks/ProfilesFragment.kt
.../src/main/java/com/github/shadowsocks/ProfilesFragment.kt
+45
-36
mobile/src/main/java/com/github/shadowsocks/QuickToggleShortcut.kt
...c/main/java/com/github/shadowsocks/QuickToggleShortcut.kt
+5
-4
mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt
...in/java/com/github/shadowsocks/acl/CustomRulesFragment.kt
+80
-66
mobile/src/main/java/com/github/shadowsocks/bg/TileService.kt
...le/src/main/java/com/github/shadowsocks/bg/TileService.kt
+18
-11
mobile/src/main/java/com/github/shadowsocks/widget/ServiceButton.kt
.../main/java/com/github/shadowsocks/widget/ServiceButton.kt
+6
-6
mobile/src/main/java/com/github/shadowsocks/widget/StatsBar.kt
...e/src/main/java/com/github/shadowsocks/widget/StatsBar.kt
+5
-5
mobile/src/main/res/menu/profile_manager_menu.xml
mobile/src/main/res/menu/profile_manager_menu.xml
+5
-0
plugin/CHANGES.md
plugin/CHANGES.md
+3
-0
plugin/build.gradle
plugin/build.gradle
+29
-4
plugin/gradle-mvn-push.gradle
plugin/gradle-mvn-push.gradle
+0
-133
plugin/gradle.properties
plugin/gradle.properties
+22
-0
plugin/src/main/java/com/github/shadowsocks/plugin/AlertDialogFragment.kt
...java/com/github/shadowsocks/plugin/AlertDialogFragment.kt
+70
-0
tv/src/main/java/com/github/shadowsocks/tv/MainFragment.kt
tv/src/main/java/com/github/shadowsocks/tv/MainFragment.kt
+1
-1
tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt
.../java/com/github/shadowsocks/tv/MainPreferenceFragment.kt
+33
-47
tv/src/main/res/xml/pref_main.xml
tv/src/main/res/xml/pref_main.xml
+1
-1
No files found.
build.gradle
View file @
be6cf63d
...
@@ -9,14 +9,11 @@ buildscript {
...
@@ -9,14 +9,11 @@ buildscript {
sdkVersion
=
28
sdkVersion
=
28
compileSdkVersion
=
28
compileSdkVersion
=
28
buildToolsVersion
=
'28.0.3'
buildToolsVersion
=
'28.0.3'
lifecycleVersion
=
'2.0.0'
roomVersion
=
'2.0.0'
workVersion
=
'1.0.0-beta05'
junitVersion
=
'4.12'
junitVersion
=
'4.12'
androidTestVersion
=
'1.1.1'
androidTestVersion
=
'1.1.1'
androidEspressoVersion
=
'3.1.1'
androidEspressoVersion
=
'3.1.1'
versionCode
=
4070
0
50
versionCode
=
4070
1
50
versionName
=
'4.7.
0
-nightly'
versionName
=
'4.7.
1
-nightly'
}
}
repositories
{
repositories
{
...
@@ -28,6 +25,7 @@ buildscript {
...
@@ -28,6 +25,7 @@ buildscript {
}
}
dependencies
{
dependencies
{
classpath
'com.vanniktech:gradle-maven-publish-plugin:0.8.0'
classpath
'com.android.tools.build:gradle:3.3.1'
classpath
'com.android.tools.build:gradle:3.3.1'
classpath
'com.github.ben-manes:gradle-versions-plugin:0.20.0'
classpath
'com.github.ben-manes:gradle-versions-plugin:0.20.0'
classpath
'com.google.gms:google-services:4.2.0'
classpath
'com.google.gms:google-services:4.2.0'
...
...
core/build.gradle
View file @
be6cf63d
apply
plugin:
'com.android.library'
apply
plugin:
'com.android.library'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android-extensions'
apply
plugin:
'kotlin-kapt'
apply
plugin:
'kotlin-kapt'
android
{
android
{
...
@@ -38,6 +39,13 @@ android {
...
@@ -38,6 +39,13 @@ android {
}
}
}
}
androidExtensions
{
experimental
=
true
}
def
lifecycleVersion
=
'2.0.0'
def
roomVersion
=
'2.0.0'
def
workVersion
=
'1.0.0-rc02'
dependencies
{
dependencies
{
api
project
(
':plugin'
)
api
project
(
':plugin'
)
api
"android.arch.work:work-runtime-ktx:$workVersion"
api
"android.arch.work:work-runtime-ktx:$workVersion"
...
@@ -46,7 +54,7 @@ dependencies {
...
@@ -46,7 +54,7 @@ dependencies {
api
'androidx.preference:preference:1.1.0-alpha03'
api
'androidx.preference:preference:1.1.0-alpha03'
api
"androidx.room:room-runtime:$roomVersion"
api
"androidx.room:room-runtime:$roomVersion"
api
'com.crashlytics.sdk.android:crashlytics:2.9.9'
api
'com.crashlytics.sdk.android:crashlytics:2.9.9'
api
'com.google.firebase:firebase-config:16.
3.0
'
api
'com.google.firebase:firebase-config:16.
1.3
'
api
'com.google.firebase:firebase-core:16.0.7'
api
'com.google.firebase:firebase-core:16.0.7'
api
'dnsjava:dnsjava:2.1.8'
api
'dnsjava:dnsjava:2.1.8'
api
'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'
api
'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'
...
...
core/src/main/assets/acl/gfwlist.acl
View file @
be6cf63d
#
#
# GFW list from https://github.com/gfwlist/gfwlist/blob/master/gfwlist.txt
# GFW list from https://github.com/gfwlist/gfwlist/blob/master/gfwlist.txt
# updated on 201
8-03-30
# updated on 201
9-02-21
#
#
[bypass_all]
[bypass_all]
...
@@ -14,6 +14,8 @@
...
@@ -14,6 +14,8 @@
91.108.56.0/22
91.108.56.0/22
109.239.140.0/24
109.239.140.0/24
149.154.160.0/20
149.154.160.0/20
1.1.1.1
14.102.250.18
14.102.250.18
14.102.250.19
14.102.250.19
174.142.105.153
174.142.105.153
...
@@ -36,6 +38,7 @@
...
@@ -36,6 +38,7 @@
(^|\.)12bet\.com$
(^|\.)12bet\.com$
(^|\.)12vpn\.com$
(^|\.)12vpn\.com$
(^|\.)12vpn\.net$
(^|\.)12vpn\.net$
(^|\.)138\.com$
(^|\.)141hongkong\.com$
(^|\.)141hongkong\.com$
(^|\.)141jj\.com$
(^|\.)141jj\.com$
(^|\.)141tube\.com$
(^|\.)141tube\.com$
...
@@ -72,7 +75,6 @@
...
@@ -72,7 +75,6 @@
(^|\.)24hrs\.ca$
(^|\.)24hrs\.ca$
(^|\.)24smile\.org$
(^|\.)24smile\.org$
(^|\.)25u\.com$
(^|\.)25u\.com$
(^|\.)2dbook\.com$
(^|\.)2lipstube\.com$
(^|\.)2lipstube\.com$
(^|\.)2shared\.com$
(^|\.)2shared\.com$
(^|\.)2waky\.com$
(^|\.)2waky\.com$
...
@@ -88,6 +90,7 @@
...
@@ -88,6 +90,7 @@
(^|\.)3proxy\.ru$
(^|\.)3proxy\.ru$
(^|\.)3ren\.ca$
(^|\.)3ren\.ca$
(^|\.)3tui\.net$
(^|\.)3tui\.net$
(^|\.)43110\.cf$
(^|\.)466453\.com$
(^|\.)466453\.com$
(^|\.)4bluestones\.biz$
(^|\.)4bluestones\.biz$
(^|\.)4chan\.com$
(^|\.)4chan\.com$
...
@@ -98,11 +101,11 @@
...
@@ -98,11 +101,11 @@
(^|\.)4pu\.com$
(^|\.)4pu\.com$
(^|\.)4rbtv\.com$
(^|\.)4rbtv\.com$
(^|\.)4shared\.com$
(^|\.)4shared\.com$
(^|\.)4tern\.com$
(^|\.)51\.ca$
(^|\.)51\.ca$
(^|\.)51jav\.org$
(^|\.)51jav\.org$
(^|\.)51luoben\.com$
(^|\.)51luoben\.com$
(^|\.)5278\.cc$
(^|\.)5278\.cc$
(^|\.)5299\.tv$
(^|\.)56cun04\.jigsy\.com$
(^|\.)56cun04\.jigsy\.com$
(^|\.)5aimiku\.com$
(^|\.)5aimiku\.com$
(^|\.)5i01\.com$
(^|\.)5i01\.com$
...
@@ -145,10 +148,13 @@
...
@@ -145,10 +148,13 @@
(^|\.)a5\.com\.ru$
(^|\.)a5\.com\.ru$
(^|\.)aamacau\.com$
(^|\.)aamacau\.com$
(^|\.)abc\.com$
(^|\.)abc\.com$
(^|\.)abc\.net\.au$
(^|\.)abc\.pp\.ru$
(^|\.)abc\.pp\.ru$
(^|\.)abc\.xyz$
(^|\.)abc\.xyz$
(^|\.)abchinese\.com$
(^|\.)abchinese\.com$
(^|\.)abclite\.net$
(^|\.)abclite\.net$
(^|\.)abebooks\.com$
(^|\.)abematv\.akamaized\.net$
(^|\.)abitno\.linpie\.com$
(^|\.)abitno\.linpie\.com$
(^|\.)ablwang\.com$
(^|\.)ablwang\.com$
(^|\.)aboluowang\.com$
(^|\.)aboluowang\.com$
...
@@ -167,10 +173,11 @@
...
@@ -167,10 +173,11 @@
(^|\.)actimes\.com\.au$
(^|\.)actimes\.com\.au$
(^|\.)activpn\.com$
(^|\.)activpn\.com$
(^|\.)aculo\.us$
(^|\.)aculo\.us$
(^|\.)adcex\.com$
(^|\.)addictedtocoffee\.de$
(^|\.)addictedtocoffee\.de$
(^|\.)adelaidebbs\.com$
(^|\.)adelaidebbs\.com$
(^|\.)admin\.recaptcha\.net$
(^|\.)admob\.com$
(^|\.)admob\.com$
(^|\.)adorama\.com$
(^|\.)adpl\.org\.hk$
(^|\.)adpl\.org\.hk$
(^|\.)ads-twitter\.com$
(^|\.)ads-twitter\.com$
(^|\.)adsense\.com$
(^|\.)adsense\.com$
...
@@ -183,6 +190,7 @@
...
@@ -183,6 +190,7 @@
(^|\.)ae\.hao123\.com$
(^|\.)ae\.hao123\.com$
(^|\.)ae\.org$
(^|\.)ae\.org$
(^|\.)aenhancers\.com$
(^|\.)aenhancers\.com$
(^|\.)aex\.com$
(^|\.)af\.mil$
(^|\.)af\.mil$
(^|\.)afantibbs\.com$
(^|\.)afantibbs\.com$
(^|\.)agnesb\.fr$
(^|\.)agnesb\.fr$
...
@@ -192,6 +200,7 @@
...
@@ -192,6 +200,7 @@
(^|\.)ai-kan\.net$
(^|\.)ai-kan\.net$
(^|\.)ai-wen\.net$
(^|\.)ai-wen\.net$
(^|\.)ai\.binwang\.me$
(^|\.)ai\.binwang\.me$
(^|\.)ai\.google$
(^|\.)aiph\.net$
(^|\.)aiph\.net$
(^|\.)airasia\.com$
(^|\.)airasia\.com$
(^|\.)airconsole\.com$
(^|\.)airconsole\.com$
...
@@ -203,6 +212,7 @@
...
@@ -203,6 +212,7 @@
(^|\.)akademiye\.org$
(^|\.)akademiye\.org$
(^|\.)akiba-online\.com$
(^|\.)akiba-online\.com$
(^|\.)akiba-web\.com$
(^|\.)akiba-web\.com$
(^|\.)akow\.org$
(^|\.)al-islam\.com$
(^|\.)al-islam\.com$
(^|\.)al-qimmah\.net$
(^|\.)al-qimmah\.net$
(^|\.)alabout\.com$
(^|\.)alabout\.com$
...
@@ -213,9 +223,9 @@
...
@@ -213,9 +223,9 @@
(^|\.)alforattv\.net$
(^|\.)alforattv\.net$
(^|\.)alhayat\.com$
(^|\.)alhayat\.com$
(^|\.)alicejapan\.co\.jp$
(^|\.)alicejapan\.co\.jp$
(^|\.)alien-ufos\.com$
(^|\.)aliengu\.com$
(^|\.)aliengu\.com$
(^|\.)alkasir\.com$
(^|\.)alkasir\.com$
(^|\.)allcoin\.com$
(^|\.)allconnected\.co$
(^|\.)allconnected\.co$
(^|\.)alldrawnsex\.com$
(^|\.)alldrawnsex\.com$
(^|\.)allervpn\.com$
(^|\.)allervpn\.com$
...
@@ -239,6 +249,7 @@
...
@@ -239,6 +249,7 @@
(^|\.)alwaysdata\.net$
(^|\.)alwaysdata\.net$
(^|\.)alwaysvpn\.com$
(^|\.)alwaysvpn\.com$
(^|\.)am730\.com\.hk$
(^|\.)am730\.com\.hk$
(^|\.)amazon\.co\.jp$
(^|\.)amazon\.com$
(^|\.)amazon\.com$
(^|\.)ameblo\.jp$
(^|\.)ameblo\.jp$
(^|\.)americangreencard\.com$
(^|\.)americangreencard\.com$
...
@@ -261,8 +272,11 @@
...
@@ -261,8 +272,11 @@
(^|\.)android\.com$
(^|\.)android\.com$
(^|\.)androidify\.com$
(^|\.)androidify\.com$
(^|\.)androidplus\.co$
(^|\.)androidplus\.co$
(^|\.)androidtv\.com$
(^|\.)andygod\.com$
(^|\.)andygod\.com$
(^|\.)angela-merkel\.de$
(^|\.)angelfire\.com$
(^|\.)angelfire\.com$
(^|\.)angola\.org$
(^|\.)angularjs\.org$
(^|\.)angularjs\.org$
(^|\.)animecrazy\.net$
(^|\.)animecrazy\.net$
(^|\.)animeshippuuden\.com$
(^|\.)animeshippuuden\.com$
...
@@ -287,6 +301,8 @@
...
@@ -287,6 +301,8 @@
(^|\.)aojiao\.org$
(^|\.)aojiao\.org$
(^|\.)aolchannels\.aol\.com$
(^|\.)aolchannels\.aol\.com$
(^|\.)aomiwang\.com$
(^|\.)aomiwang\.com$
(^|\.)apartmentratings\.com$
(^|\.)apartments\.com$
(^|\.)apetube\.com$
(^|\.)apetube\.com$
(^|\.)api-secure\.recaptcha\.net$
(^|\.)api-secure\.recaptcha\.net$
(^|\.)api-verify\.recaptcha\.net$
(^|\.)api-verify\.recaptcha\.net$
...
@@ -294,6 +310,7 @@
...
@@ -294,6 +310,7 @@
(^|\.)api\.dropboxapi\.com$
(^|\.)api\.dropboxapi\.com$
(^|\.)api\.linksalpha\.com$
(^|\.)api\.linksalpha\.com$
(^|\.)api\.proxlet\.com$
(^|\.)api\.proxlet\.com$
(^|\.)api\.pureapk\.com$
(^|\.)api\.recaptcha\.net$
(^|\.)api\.recaptcha\.net$
(^|\.)apiary\.io$
(^|\.)apiary\.io$
(^|\.)apidocs\.linksalpha\.com$
(^|\.)apidocs\.linksalpha\.com$
...
@@ -307,17 +324,23 @@
...
@@ -307,17 +324,23 @@
(^|\.)aplusvpn\.com$
(^|\.)aplusvpn\.com$
(^|\.)app\.box\.com$
(^|\.)app\.box\.com$
(^|\.)app\.heywire\.com$
(^|\.)app\.heywire\.com$
(^|\.)app\.smartmailcloud\.com$
(^|\.)app\.tutanota\.com$
(^|\.)app\.tutanota\.com$
(^|\.)appdownloader\.net$
(^|\.)appdownloader\.net$
(^|\.)appledaily\.com$
(^|\.)appledaily\.com$
(^|\.)appledaily\.com\.hk$
(^|\.)appledaily\.com\.tw$
(^|\.)appshopper\.com$
(^|\.)appshopper\.com$
(^|\.)appsocks\.net$
(^|\.)appsocks\.net$
(^|\.)appspot\.com$
(^|\.)appspot\.com$
(^|\.)appsto\.re$
(^|\.)appsto\.re$
(^|\.)aptoide\.com$
(^|\.)ar\.hao123\.com$
(^|\.)ar\.hao123\.com$
(^|\.)archive\.fo$
(^|\.)archive\.fo$
(^|\.)archive\.is$
(^|\.)archive\.is$
(^|\.)archive\.li$
(^|\.)archive\.org$
(^|\.)archive\.org$
(^|\.)archive\.today$
(^|\.)archives\.gov$
(^|\.)archives\.gov$
(^|\.)archives\.gov\.tw$
(^|\.)archives\.gov\.tw$
(^|\.)arctosia\.com$
(^|\.)arctosia\.com$
...
@@ -327,10 +350,10 @@
...
@@ -327,10 +350,10 @@
(^|\.)arlingtoncemetery\.mil$
(^|\.)arlingtoncemetery\.mil$
(^|\.)army\.mil$
(^|\.)army\.mil$
(^|\.)art4tibet1998\.org$
(^|\.)art4tibet1998\.org$
(^|\.)arte\.tv$
(^|\.)artofpeacefoundation\.org$
(^|\.)artofpeacefoundation\.org$
(^|\.)artsy\.net$
(^|\.)artsy\.net$
(^|\.)asacp\.org$
(^|\.)asacp\.org$
(^|\.)asahichinese\.com$
(^|\.)asdfg\.jp$
(^|\.)asdfg\.jp$
(^|\.)asg\.to$
(^|\.)asg\.to$
(^|\.)asia-gaming\.com$
(^|\.)asia-gaming\.com$
...
@@ -344,6 +367,7 @@
...
@@ -344,6 +367,7 @@
(^|\.)askstudent\.com$
(^|\.)askstudent\.com$
(^|\.)askynz\.net$
(^|\.)askynz\.net$
(^|\.)assembla\.com$
(^|\.)assembla\.com$
(^|\.)assets\.bwbx\.io$
(^|\.)assimp\.org$
(^|\.)assimp\.org$
(^|\.)astrill\.com$
(^|\.)astrill\.com$
(^|\.)atc\.org\.au$
(^|\.)atc\.org\.au$
...
@@ -358,6 +382,7 @@
...
@@ -358,6 +382,7 @@
(^|\.)authorizeddns\.org$
(^|\.)authorizeddns\.org$
(^|\.)authorizeddns\.us$
(^|\.)authorizeddns\.us$
(^|\.)autodraw\.com$
(^|\.)autodraw\.com$
(^|\.)av-e-body\.com$
(^|\.)av\.com$
(^|\.)av\.com$
(^|\.)av\.movie$
(^|\.)av\.movie$
(^|\.)av\.nightlife141\.com$
(^|\.)av\.nightlife141\.com$
...
@@ -368,6 +393,7 @@
...
@@ -368,6 +393,7 @@
(^|\.)avdb\.in$
(^|\.)avdb\.in$
(^|\.)avdb\.tv$
(^|\.)avdb\.tv$
(^|\.)avfantasy\.com$
(^|\.)avfantasy\.com$
(^|\.)avgle\.com$
(^|\.)avidemux\.org$
(^|\.)avidemux\.org$
(^|\.)avmo\.pw$
(^|\.)avmo\.pw$
(^|\.)avmoo\.com$
(^|\.)avmoo\.com$
...
@@ -384,17 +410,22 @@
...
@@ -384,17 +410,22 @@
(^|\.)backchina\.com$
(^|\.)backchina\.com$
(^|\.)backpackers\.com\.tw$
(^|\.)backpackers\.com\.tw$
(^|\.)backtotiananmen\.com$
(^|\.)backtotiananmen\.com$
(^|\.)badiucao\.com$
(^|\.)badjojo\.com$
(^|\.)badjojo\.com$
(^|\.)badoo\.com$
(^|\.)badoo\.com$
(^|\.)baidu\.jp$
(^|\.)baidu\.jp$
(^|\.)baijie\.org$
(^|\.)bailandaily\.com$
(^|\.)bailandaily\.com$
(^|\.)baixing\.me$
(^|\.)baixing\.me$
(^|\.)bakgeekhome\.tk$
(^|\.)bakgeekhome\.tk$
(^|\.)banana-vpn\.com$
(^|\.)banana-vpn\.com$
(^|\.)band\.us$
(^|\.)bandwagonhost\.com$
(^|\.)bandwagonhost\.com$
(^|\.)bangbrosnetwork\.com$
(^|\.)bangbrosnetwork\.com$
(^|\.)bangchen\.net$
(^|\.)bangchen\.net$
(^|\.)bangdream\.space$
(^|\.)bangyoulater\.com$
(^|\.)bangyoulater\.com$
(^|\.)bankmobilevibe\.com$
(^|\.)bannedbook\.org$
(^|\.)bannedbook\.org$
(^|\.)bannednews\.org$
(^|\.)bannednews\.org$
(^|\.)banorte\.com$
(^|\.)banorte\.com$
...
@@ -409,10 +440,10 @@
...
@@ -409,10 +440,10 @@
(^|\.)bb\.ttv\.com\.tw$
(^|\.)bb\.ttv\.com\.tw$
(^|\.)bbc\.co\.uk$
(^|\.)bbc\.co\.uk$
(^|\.)bbc\.com$
(^|\.)bbc\.com$
(^|\.)bbc\.com%2fzhongwen$
(^|\.)bbc\.in$
(^|\.)bbc\.in$
(^|\.)bbcchinese\.com$
(^|\.)bbcchinese\.com$
(^|\.)bbchat\.tv$
(^|\.)bbchat\.tv$
(^|\.)bbci\.co\.uk$
(^|\.)bbg\.gov$
(^|\.)bbg\.gov$
(^|\.)bbkz\.com$
(^|\.)bbkz\.com$
(^|\.)bbnradio\.org$
(^|\.)bbnradio\.org$
...
@@ -425,6 +456,7 @@
...
@@ -425,6 +456,7 @@
(^|\.)bbs\.huasing\.org$
(^|\.)bbs\.huasing\.org$
(^|\.)bbs\.junglobal\.net$
(^|\.)bbs\.junglobal\.net$
(^|\.)bbs\.kimy\.com\.tw$
(^|\.)bbs\.kimy\.com\.tw$
(^|\.)bbs\.mikocon\.com$
(^|\.)bbs\.morbell\.com$
(^|\.)bbs\.morbell\.com$
(^|\.)bbs\.mychat\.to$
(^|\.)bbs\.mychat\.to$
(^|\.)bbs\.netbig\.com$
(^|\.)bbs\.netbig\.com$
...
@@ -444,12 +476,14 @@
...
@@ -444,12 +476,14 @@
(^|\.)bcast\.co\.nz$
(^|\.)bcast\.co\.nz$
(^|\.)bcc\.com\.tw$
(^|\.)bcc\.com\.tw$
(^|\.)bcchinese\.net$
(^|\.)bcchinese\.net$
(^|\.)bcex\.ca$
(^|\.)bcmorning\.com$
(^|\.)bcmorning\.com$
(^|\.)bdsmvideos\.net$
(^|\.)bdsmvideos\.net$
(^|\.)beaconevents\.com$
(^|\.)beaconevents\.com$
(^|\.)bebo\.com$
(^|\.)bebo\.com$
(^|\.)beeg\.com$
(^|\.)beeg\.com$
(^|\.)beevpn\.com$
(^|\.)beevpn\.com$
(^|\.)behance\.net$
(^|\.)behindkink\.com$
(^|\.)behindkink\.com$
(^|\.)beijing1989\.com$
(^|\.)beijing1989\.com$
(^|\.)beijingspring\.com$
(^|\.)beijingspring\.com$
...
@@ -469,7 +503,6 @@
...
@@ -469,7 +503,6 @@
(^|\.)bestvpnservice\.com$
(^|\.)bestvpnservice\.com$
(^|\.)bestvpnusa\.com$
(^|\.)bestvpnusa\.com$
(^|\.)bet365\.com$
(^|\.)bet365\.com$
(^|\.)beta\.usejump\.com$
(^|\.)betfair\.com$
(^|\.)betfair\.com$
(^|\.)betternet\.co$
(^|\.)betternet\.co$
(^|\.)bettervpn\.com$
(^|\.)bettervpn\.com$
...
@@ -484,7 +517,9 @@
...
@@ -484,7 +517,9 @@
(^|\.)biantailajiao\.com$
(^|\.)biantailajiao\.com$
(^|\.)biantailajiao\.in$
(^|\.)biantailajiao\.in$
(^|\.)biblesforamerica\.org$
(^|\.)biblesforamerica\.org$
(^|\.)bibox\.com$
(^|\.)bic2011\.org$
(^|\.)bic2011\.org$
(^|\.)big\.one$
(^|\.)bigfools\.com$
(^|\.)bigfools\.com$
(^|\.)bigjapanesesex\.com$
(^|\.)bigjapanesesex\.com$
(^|\.)bigmoney\.biz$
(^|\.)bigmoney\.biz$
...
@@ -492,12 +527,19 @@
...
@@ -492,12 +527,19 @@
(^|\.)bigsound\.org$
(^|\.)bigsound\.org$
(^|\.)biliworld\.com$
(^|\.)biliworld\.com$
(^|\.)billypan\.com$
(^|\.)billypan\.com$
(^|\.)binance\.com$
(^|\.)binux\.me$
(^|\.)binux\.me$
(^|\.)bipic\.net$
(^|\.)bipic\.net$
(^|\.)bird\.so$
(^|\.)bit-z\.com$
(^|\.)bit\.do$
(^|\.)bit\.do$
(^|\.)bit\.ly$
(^|\.)bit\.ly$
(^|\.)bitc\.bme\.emory\.edu$
(^|\.)bitc\.bme\.emory\.edu$
(^|\.)bitcointalk\.org$
(^|\.)bitcointalk\.org$
(^|\.)bitcoinworld\.com$
(^|\.)bitfinex\.com$
(^|\.)bithumb\.com$
(^|\.)bitinka\.com\.ar$
(^|\.)bitmex\.com$
(^|\.)bitmex\.com$
(^|\.)bitshare\.com$
(^|\.)bitshare\.com$
(^|\.)bitsnoop\.com$
(^|\.)bitsnoop\.com$
...
@@ -560,7 +602,10 @@
...
@@ -560,7 +602,10 @@
(^|\.)blogs\.libraryinformationtechnology\.com$
(^|\.)blogs\.libraryinformationtechnology\.com$
(^|\.)blogs\.tampabay\.com$
(^|\.)blogs\.tampabay\.com$
(^|\.)blogs\.yahoo\.co\.jp$
(^|\.)blogs\.yahoo\.co\.jp$
(^|\.)blogspot(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?){1,2}$
(^|\.)blogspot\.com$
(^|\.)blogspot\.hk$
(^|\.)blogspot\.jp$
(^|\.)blogspot\.tw$
(^|\.)blogtd\.net$
(^|\.)blogtd\.net$
(^|\.)blogtd\.org$
(^|\.)blogtd\.org$
(^|\.)bloodshed\.net$
(^|\.)bloodshed\.net$
...
@@ -572,6 +617,7 @@
...
@@ -572,6 +617,7 @@
(^|\.)blueangellive\.com$
(^|\.)blueangellive\.com$
(^|\.)bmfinn\.com$
(^|\.)bmfinn\.com$
(^|\.)bnews\.co$
(^|\.)bnews\.co$
(^|\.)bnn\.co$
(^|\.)bnrmetal\.com$
(^|\.)bnrmetal\.com$
(^|\.)boardreader\.com$
(^|\.)boardreader\.com$
(^|\.)bod\.asia$
(^|\.)bod\.asia$
...
@@ -587,6 +633,7 @@
...
@@ -587,6 +633,7 @@
(^|\.)book\.zi5\.me$
(^|\.)book\.zi5\.me$
(^|\.)bookepub\.com$
(^|\.)bookepub\.com$
(^|\.)books\.com\.tw$
(^|\.)books\.com\.tw$
(^|\.)booktopia\.com\.au$
(^|\.)boomssr\.com$
(^|\.)boomssr\.com$
(^|\.)bot\.nu$
(^|\.)bot\.nu$
(^|\.)botanwang\.com$
(^|\.)botanwang\.com$
...
@@ -625,10 +672,14 @@
...
@@ -625,10 +672,14 @@
(^|\.)bt95\.com$
(^|\.)bt95\.com$
(^|\.)btaia\.com$
(^|\.)btaia\.com$
(^|\.)btbtav\.com$
(^|\.)btbtav\.com$
(^|\.)btc98\.com$
(^|\.)btcbank\.bank$
(^|\.)btctrade\.im$
(^|\.)btdigg\.org$
(^|\.)btdigg\.org$
(^|\.)btku\.me$
(^|\.)btku\.me$
(^|\.)btku\.org$
(^|\.)btku\.org$
(^|\.)btspread\.com$
(^|\.)btspread\.com$
(^|\.)btsynckeys\.com$
(^|\.)budaedu\.org$
(^|\.)budaedu\.org$
(^|\.)buddhanet\.com\.tw$
(^|\.)buddhanet\.com\.tw$
(^|\.)buddhistchannel\.tv$
(^|\.)buddhistchannel\.tv$
...
@@ -647,13 +698,17 @@
...
@@ -647,13 +698,17 @@
(^|\.)buzzhand\.net$
(^|\.)buzzhand\.net$
(^|\.)buzzorange\.com$
(^|\.)buzzorange\.com$
(^|\.)bvpn\.com$
(^|\.)bvpn\.com$
(^|\.)bwgyhw\.com$
(^|\.)bwh1\.net$
(^|\.)bwsj\.hk$
(^|\.)bwsj\.hk$
(^|\.)bx\.in\.th$
(^|\.)bx\.tl$
(^|\.)bx\.tl$
(^|\.)bynet\.co\.il$
(^|\.)bynet\.co\.il$
(^|\.)c-est-simple\.com$
(^|\.)c-est-simple\.com$
(^|\.)c-spanvideo\.org$
(^|\.)c-spanvideo\.org$
(^|\.)c100tibet\.org$
(^|\.)c100tibet\.org$
(^|\.)c1522\.mooo\.com$
(^|\.)c1522\.mooo\.com$
(^|\.)c2cx\.com$
(^|\.)cablegatesearch\.net$
(^|\.)cablegatesearch\.net$
(^|\.)cachinese\.com$
(^|\.)cachinese\.com$
(^|\.)cacnw\.com$
(^|\.)cacnw\.com$
...
@@ -693,6 +748,7 @@
...
@@ -693,6 +748,7 @@
(^|\.)casinoriva\.com$
(^|\.)casinoriva\.com$
(^|\.)castbox\.fm$
(^|\.)castbox\.fm$
(^|\.)catch22\.net$
(^|\.)catch22\.net$
(^|\.)catchgod\.com$
(^|\.)catfightpayperview\.xxx$
(^|\.)catfightpayperview\.xxx$
(^|\.)catholic\.org\.hk$
(^|\.)catholic\.org\.hk$
(^|\.)catholic\.org\.tw$
(^|\.)catholic\.org\.tw$
...
@@ -711,6 +767,7 @@
...
@@ -711,6 +767,7 @@
(^|\.)cclife\.org$
(^|\.)cclife\.org$
(^|\.)cclifefl\.org$
(^|\.)cclifefl\.org$
(^|\.)ccthere\.com$
(^|\.)ccthere\.com$
(^|\.)ccthere\.net$
(^|\.)cctmweb\.net$
(^|\.)cctmweb\.net$
(^|\.)cctongbao\.com$
(^|\.)cctongbao\.com$
(^|\.)ccue\.ca$
(^|\.)ccue\.ca$
...
@@ -728,6 +785,7 @@
...
@@ -728,6 +785,7 @@
(^|\.)cdn\.assets\.lfpcontent\.com$
(^|\.)cdn\.assets\.lfpcontent\.com$
(^|\.)cdn\.helixstudios\.net$
(^|\.)cdn\.helixstudios\.net$
(^|\.)cdn\.printfriendly\.com$
(^|\.)cdn\.printfriendly\.com$
(^|\.)cdn\.seatguru\.com$
(^|\.)cdn\.softlayer\.net$
(^|\.)cdn\.softlayer\.net$
(^|\.)cdn1\.lp\.saboom\.com$
(^|\.)cdn1\.lp\.saboom\.com$
(^|\.)cdnews\.com\.tw$
(^|\.)cdnews\.com\.tw$
...
@@ -751,6 +809,7 @@
...
@@ -751,6 +809,7 @@
(^|\.)certificate-transparency\.org$
(^|\.)certificate-transparency\.org$
(^|\.)certificate\.revocationcheck\.com$
(^|\.)certificate\.revocationcheck\.com$
(^|\.)cfhks\.org\.hk$
(^|\.)cfhks\.org\.hk$
(^|\.)cfos\.de$
(^|\.)cftfc\.com$
(^|\.)cftfc\.com$
(^|\.)cgdepot\.org$
(^|\.)cgdepot\.org$
(^|\.)cgst\.edu$
(^|\.)cgst\.edu$
...
@@ -762,6 +821,7 @@
...
@@ -762,6 +821,7 @@
(^|\.)changp\.com$
(^|\.)changp\.com$
(^|\.)changsa\.net$
(^|\.)changsa\.net$
(^|\.)channel8news\.sg$
(^|\.)channel8news\.sg$
(^|\.)chaoex\.com$
(^|\.)chapm25\.com$
(^|\.)chapm25\.com$
(^|\.)chatnook\.com$
(^|\.)chatnook\.com$
(^|\.)chaturbate\.com$
(^|\.)chaturbate\.com$
...
@@ -824,6 +884,7 @@
...
@@ -824,6 +884,7 @@
(^|\.)chinatopsex\.com$
(^|\.)chinatopsex\.com$
(^|\.)chinatown\.com\.au$
(^|\.)chinatown\.com\.au$
(^|\.)chinatweeps\.com$
(^|\.)chinatweeps\.com$
(^|\.)chinaview\.wordpress\.com$
(^|\.)chinaway\.org$
(^|\.)chinaway\.org$
(^|\.)chinaworker\.info$
(^|\.)chinaworker\.info$
(^|\.)chinaxchina\.com$
(^|\.)chinaxchina\.com$
...
@@ -841,6 +902,7 @@
...
@@ -841,6 +902,7 @@
(^|\.)chinesedemocracy\.com$
(^|\.)chinesedemocracy\.com$
(^|\.)chinesegay\.org$
(^|\.)chinesegay\.org$
(^|\.)chinesen\.de$
(^|\.)chinesen\.de$
(^|\.)chinesenews\.net\.au$
(^|\.)chinesepen\.org$
(^|\.)chinesepen\.org$
(^|\.)chinesetalks\.net$
(^|\.)chinesetalks\.net$
(^|\.)chineseupress\.com$
(^|\.)chineseupress\.com$
...
@@ -848,6 +910,7 @@
...
@@ -848,6 +910,7 @@
(^|\.)chinman\.net$
(^|\.)chinman\.net$
(^|\.)chithu\.org$
(^|\.)chithu\.org$
(^|\.)chn\.chosun\.com$
(^|\.)chn\.chosun\.com$
(^|\.)chobit\.cc$
(^|\.)chrdnet\.com$
(^|\.)chrdnet\.com$
(^|\.)christianfreedom\.org$
(^|\.)christianfreedom\.org$
(^|\.)christianstudy\.com$
(^|\.)christianstudy\.com$
...
@@ -870,6 +933,7 @@
...
@@ -870,6 +933,7 @@
(^|\.)cineastentreff\.de$
(^|\.)cineastentreff\.de$
(^|\.)cipfg\.org$
(^|\.)cipfg\.org$
(^|\.)circlethebayfortibet\.org$
(^|\.)circlethebayfortibet\.org$
(^|\.)cirosantilli\.com$
(^|\.)citizencn\.com$
(^|\.)citizencn\.com$
(^|\.)citizenlab\.org$
(^|\.)citizenlab\.org$
(^|\.)citizenscommission\.hk$
(^|\.)citizenscommission\.hk$
...
@@ -893,19 +957,24 @@
...
@@ -893,19 +957,24 @@
(^|\.)cleansite\.info$
(^|\.)cleansite\.info$
(^|\.)cleansite\.us$
(^|\.)cleansite\.us$
(^|\.)clearharmony\.net$
(^|\.)clearharmony\.net$
(^|\.)clearsurance\.com$
(^|\.)clearwisdom\.net$
(^|\.)clearwisdom\.net$
(^|\.)clementine-player\.org$
(^|\.)clementine-player\.org$
(^|\.)cling\.omy\.sg$
(^|\.)cling\.omy\.sg$
(^|\.)clinica-tibet\.ru$
(^|\.)clinica-tibet\.ru$
(^|\.)clipfish\.de$
(^|\.)clipfish\.de$
(^|\.)cloakpoint\.com$
(^|\.)cloakpoint\.com$
(^|\.)cloud\.feedly\.com$
(^|\.)cloud\.mail\.ru$
(^|\.)cloud\.mail\.ru$
(^|\.)club1069\.com$
(^|\.)club1069\.com$
(^|\.)clyp\.it$
(^|\.)cmcn\.org$
(^|\.)cmi\.org\.tw$
(^|\.)cmi\.org\.tw$
(^|\.)cmp\.hku\.hk$
(^|\.)cmp\.hku\.hk$
(^|\.)cms\.gov$
(^|\.)cms\.gov$
(^|\.)cmule\.com$
(^|\.)cmule\.com$
(^|\.)cmule\.org$
(^|\.)cmule\.org$
(^|\.)cmx\.im$
(^|\.)cn-proxy\.com$
(^|\.)cn-proxy\.com$
(^|\.)cn\.calameo\.com$
(^|\.)cn\.calameo\.com$
(^|\.)cn\.dayabook\.com$
(^|\.)cn\.dayabook\.com$
...
@@ -917,6 +986,7 @@
...
@@ -917,6 +986,7 @@
(^|\.)cn\.sandscotaicentral\.com$
(^|\.)cn\.sandscotaicentral\.com$
(^|\.)cn\.shafaqna\.com$
(^|\.)cn\.shafaqna\.com$
(^|\.)cn\.streetvoice\.com$
(^|\.)cn\.streetvoice\.com$
(^|\.)cn\.thegay\.com$
(^|\.)cn\.uncyclopedia\.wikia\.com$
(^|\.)cn\.uncyclopedia\.wikia\.com$
(^|\.)cn\.uptodown\.com$
(^|\.)cn\.uptodown\.com$
(^|\.)cn\.voa\.mobi$
(^|\.)cn\.voa\.mobi$
...
@@ -934,11 +1004,21 @@
...
@@ -934,11 +1004,21 @@
(^|\.)cnproxy\.com$
(^|\.)cnproxy\.com$
(^|\.)co\.ng\.mil$
(^|\.)co\.ng\.mil$
(^|\.)coat\.co\.jp$
(^|\.)coat\.co\.jp$
(^|\.)cobinhood\.com$
(^|\.)cochina\.co$
(^|\.)cochina\.co$
(^|\.)cochina\.org$
(^|\.)cochina\.org$
(^|\.)code1984\.com$
(^|\.)code1984\.com$
(^|\.)codeshare\.io$
(^|\.)codeshare\.io$
(^|\.)codeskulptor\.org$
(^|\.)codeskulptor\.org$
(^|\.)coin2co\.in$
(^|\.)coinbene\.com$
(^|\.)coinegg\.com$
(^|\.)coinex\.com$
(^|\.)coingi\.com$
(^|\.)coinrail\.co\.kr$
(^|\.)cointiger\.com$
(^|\.)cointobe\.com$
(^|\.)coinut\.com$
(^|\.)collateralmurder\.com$
(^|\.)collateralmurder\.com$
(^|\.)collateralmurder\.org$
(^|\.)collateralmurder\.org$
(^|\.)com\.google$
(^|\.)com\.google$
...
@@ -961,21 +1041,27 @@
...
@@ -961,21 +1041,27 @@
(^|\.)coolder\.com$
(^|\.)coolder\.com$
(^|\.)coolloud\.org\.tw$
(^|\.)coolloud\.org\.tw$
(^|\.)coolncute\.com$
(^|\.)coolncute\.com$
(^|\.)coolstuffinc\.com$
(^|\.)corumcollege\.com$
(^|\.)corumcollege\.com$
(^|\.)cos-moe\.com$
(^|\.)cos-moe\.com$
(^|\.)cosmic\.monar\.ch$
(^|\.)cosmic\.monar\.ch$
(^|\.)cosplayjav\.pl$
(^|\.)cosplayjav\.pl$
(^|\.)costco\.com$
(^|\.)cotweet\.com$
(^|\.)cotweet\.com$
(^|\.)counter\.social$
(^|\.)coursehero\.com$
(^|\.)coursehero\.com$
(^|\.)cpj\.org$
(^|\.)cpj\.org$
(^|\.)cq99\.us$
(^|\.)cq99\.us$
(^|\.)crackle\.com$
(^|\.)crackle\.com$
(^|\.)crazys\.cc$
(^|\.)crazys\.cc$
(^|\.)crazyshit\.com$
(^|\.)crbug\.com$
(^|\.)crchina\.org$
(^|\.)crchina\.org$
(^|\.)crd-net\.org$
(^|\.)crd-net\.org$
(^|\.)creaders\.net$
(^|\.)creaders\.net$
(^|\.)creadersnet\.com$
(^|\.)creadersnet\.com$
(^|\.)creativelab5\.com$
(^|\.)creativelab5\.com$
(^|\.)crisisresponse\.google$
(^|\.)cristyli\.com$
(^|\.)cristyli\.com$
(^|\.)crocotube\.com$
(^|\.)crocotube\.com$
(^|\.)crossfire\.co\.kr$
(^|\.)crossfire\.co\.kr$
...
@@ -1000,6 +1086,7 @@
...
@@ -1000,6 +1086,7 @@
(^|\.)cumlouder\.com$
(^|\.)cumlouder\.com$
(^|\.)curvefish\.com$
(^|\.)curvefish\.com$
(^|\.)cusu\.hk$
(^|\.)cusu\.hk$
(^|\.)cutscenes\.net$
(^|\.)cw\.com\.tw$
(^|\.)cw\.com\.tw$
(^|\.)cyberghost\.natado\.com$
(^|\.)cyberghost\.natado\.com$
(^|\.)cyberghostvpn\.com$
(^|\.)cyberghostvpn\.com$
...
@@ -1019,15 +1106,18 @@
...
@@ -1019,15 +1106,18 @@
(^|\.)dabr\.mobi$
(^|\.)dabr\.mobi$
(^|\.)dadazim\.com$
(^|\.)dadazim\.com$
(^|\.)dadi360\.com$
(^|\.)dadi360\.com$
(^|\.)dafabet\.com$
(^|\.)dafagood\.com$
(^|\.)dafagood\.com$
(^|\.)dafahao\.com$
(^|\.)dafahao\.com$
(^|\.)dafoh\.org$
(^|\.)dafoh\.org$
(^|\.)daftporn\.com$
(^|\.)dagelijksestandaard\.nl$
(^|\.)dagelijksestandaard\.nl$
(^|\.)daidostup\.ru$
(^|\.)daidostup\.ru$
(^|\.)dailidaili\.com$
(^|\.)dailidaili\.com$
(^|\.)dailymotion\.com$
(^|\.)dailymotion\.com$
(^|\.)dailynews\.sina\.com$
(^|\.)dailynews\.sina\.com$
(^|\.)dailynews\.sina\.com%2f$
(^|\.)dailynews\.sina\.com%2f$
(^|\.)dailyview\.tw$
(^|\.)daiphapinfo\.net$
(^|\.)daiphapinfo\.net$
(^|\.)dajiyuan\.com$
(^|\.)dajiyuan\.com$
(^|\.)dajiyuan\.de$
(^|\.)dajiyuan\.de$
...
@@ -1115,6 +1205,7 @@
...
@@ -1115,6 +1205,7 @@
(^|\.)dhcp\.biz$
(^|\.)dhcp\.biz$
(^|\.)diaoyuislands\.org$
(^|\.)diaoyuislands\.org$
(^|\.)dictionary\.goo\.ne\.jp$
(^|\.)dictionary\.goo\.ne\.jp$
(^|\.)difangwenge\.org$
(^|\.)digiland\.tw$
(^|\.)digiland\.tw$
(^|\.)digisfera\.com$
(^|\.)digisfera\.com$
(^|\.)digitalnomadsproject\.org$
(^|\.)digitalnomadsproject\.org$
...
@@ -1123,6 +1214,9 @@
...
@@ -1123,6 +1214,9 @@
(^|\.)dingchin\.com\.tw$
(^|\.)dingchin\.com\.tw$
(^|\.)dipity\.com$
(^|\.)dipity\.com$
(^|\.)directcreative\.com$
(^|\.)directcreative\.com$
(^|\.)discoins\.com$
(^|\.)discordapp\.com$
(^|\.)discordapp\.net$
(^|\.)discuss\.com\.hk$
(^|\.)discuss\.com\.hk$
(^|\.)discuss4u\.com$
(^|\.)discuss4u\.com$
(^|\.)dish\.com$
(^|\.)dish\.com$
...
@@ -1173,6 +1267,8 @@
...
@@ -1173,6 +1267,8 @@
(^|\.)dotsub\.com$
(^|\.)dotsub\.com$
(^|\.)dotvpn\.com$
(^|\.)dotvpn\.com$
(^|\.)doub\.io$
(^|\.)doub\.io$
(^|\.)doubibackup\.com$
(^|\.)doubmirror\.cf$
(^|\.)dougscripts\.com$
(^|\.)dougscripts\.com$
(^|\.)douhokanko\.net$
(^|\.)douhokanko\.net$
(^|\.)doujincafe\.com$
(^|\.)doujincafe\.com$
...
@@ -1183,6 +1279,7 @@
...
@@ -1183,6 +1279,7 @@
(^|\.)dphk\.org$
(^|\.)dphk\.org$
(^|\.)dpp\.org\.tw$
(^|\.)dpp\.org\.tw$
(^|\.)dpr\.info$
(^|\.)dpr\.info$
(^|\.)dragonex\.io$
(^|\.)dragonsprings\.org$
(^|\.)dragonsprings\.org$
(^|\.)dreamamateurs\.com$
(^|\.)dreamamateurs\.com$
(^|\.)drepung\.org$
(^|\.)drepung\.org$
...
@@ -1218,6 +1315,7 @@
...
@@ -1218,6 +1315,7 @@
(^|\.)dupola\.com$
(^|\.)dupola\.com$
(^|\.)dupola\.net$
(^|\.)dupola\.net$
(^|\.)dushi\.ca$
(^|\.)dushi\.ca$
(^|\.)dvdpac\.com$
(^|\.)dvorak\.org$
(^|\.)dvorak\.org$
(^|\.)dw-world\.com$
(^|\.)dw-world\.com$
(^|\.)dw-world\.de$
(^|\.)dw-world\.de$
...
@@ -1239,6 +1337,7 @@
...
@@ -1239,6 +1337,7 @@
(^|\.)dynu\.com$
(^|\.)dynu\.com$
(^|\.)dynu\.net$
(^|\.)dynu\.net$
(^|\.)dynupdate\.no-ip\.com$
(^|\.)dynupdate\.no-ip\.com$
(^|\.)dysfz\.cc$
(^|\.)dzze\.com$
(^|\.)dzze\.com$
(^|\.)e-classical\.com\.tw$
(^|\.)e-classical\.com\.tw$
(^|\.)e-gold\.com$
(^|\.)e-gold\.com$
...
@@ -1263,6 +1362,7 @@
...
@@ -1263,6 +1362,7 @@
(^|\.)ebook\.hyread\.com\.tw$
(^|\.)ebook\.hyread\.com\.tw$
(^|\.)ebookbrowse\.com$
(^|\.)ebookbrowse\.com$
(^|\.)ebookee\.com$
(^|\.)ebookee\.com$
(^|\.)ebtcbank\.com$
(^|\.)ecfa\.org\.tw$
(^|\.)ecfa\.org\.tw$
(^|\.)echofon\.com$
(^|\.)echofon\.com$
(^|\.)ecimg\.tw$
(^|\.)ecimg\.tw$
...
@@ -1290,6 +1390,7 @@
...
@@ -1290,6 +1390,7 @@
(^|\.)eksisozluk\.com$
(^|\.)eksisozluk\.com$
(^|\.)electionsmeter\.com$
(^|\.)electionsmeter\.com$
(^|\.)elgoog\.im$
(^|\.)elgoog\.im$
(^|\.)ellawine\.org$
(^|\.)elpais\.com$
(^|\.)elpais\.com$
(^|\.)eltondisney\.com$
(^|\.)eltondisney\.com$
(^|\.)emaga\.com$
(^|\.)emaga\.com$
...
@@ -1353,9 +1454,11 @@
...
@@ -1353,9 +1454,11 @@
(^|\.)eroticsaloon\.net$
(^|\.)eroticsaloon\.net$
(^|\.)eslite\.com$
(^|\.)eslite\.com$
(^|\.)esmtp\.biz$
(^|\.)esmtp\.biz$
(^|\.)esurance\.com$
(^|\.)etaa\.org\.au$
(^|\.)etaa\.org\.au$
(^|\.)etadult\.com$
(^|\.)etadult\.com$
(^|\.)etaiwannews\.com$
(^|\.)etaiwannews\.com$
(^|\.)etherdelta\.com$
(^|\.)etizer\.org$
(^|\.)etizer\.org$
(^|\.)etokki\.com$
(^|\.)etokki\.com$
(^|\.)etools\.ncol\.com$
(^|\.)etools\.ncol\.com$
...
@@ -1367,10 +1470,12 @@
...
@@ -1367,10 +1470,12 @@
(^|\.)eucasino\.com$
(^|\.)eucasino\.com$
(^|\.)eulam\.com$
(^|\.)eulam\.com$
(^|\.)eurekavpt\.com$
(^|\.)eurekavpt\.com$
(^|\.)euronews\.com$
(^|\.)evchk\.wikia\.com$
(^|\.)evchk\.wikia\.com$
(^|\.)evschool\.net$
(^|\.)evschool\.net$
(^|\.)exblog\.jp$
(^|\.)exblog\.jp$
(^|\.)exchristian\.hk$
(^|\.)exchristian\.hk$
(^|\.)exmo\.com$
(^|\.)exmormon\.org$
(^|\.)exmormon\.org$
(^|\.)expatshield\.com$
(^|\.)expatshield\.com$
(^|\.)expecthim\.com$
(^|\.)expecthim\.com$
...
@@ -1378,8 +1483,10 @@
...
@@ -1378,8 +1483,10 @@
(^|\.)experts-univers\.com$
(^|\.)experts-univers\.com$
(^|\.)exploader\.net$
(^|\.)exploader\.net$
(^|\.)expressvpn\.com$
(^|\.)expressvpn\.com$
(^|\.)exrates\.me$
(^|\.)extmatrix\.com$
(^|\.)extmatrix\.com$
(^|\.)extremetube\.com$
(^|\.)extremetube\.com$
(^|\.)exx\.com$
(^|\.)eyevio\.jp$
(^|\.)eyevio\.jp$
(^|\.)eyny\.com$
(^|\.)eyny\.com$
(^|\.)ezpc\.tk$
(^|\.)ezpc\.tk$
...
@@ -1393,6 +1500,7 @@
...
@@ -1393,6 +1500,7 @@
(^|\.)facebook\.in$
(^|\.)facebook\.in$
(^|\.)facebook\.nl$
(^|\.)facebook\.nl$
(^|\.)facebook\.se$
(^|\.)facebook\.se$
(^|\.)facebookmail\.com$
(^|\.)facebookquotes4u\.com$
(^|\.)facebookquotes4u\.com$
(^|\.)faceless\.me$
(^|\.)faceless\.me$
(^|\.)facesofnyfw\.com$
(^|\.)facesofnyfw\.com$
...
@@ -1453,13 +1561,16 @@
...
@@ -1453,13 +1561,16 @@
(^|\.)fastpic\.ru$
(^|\.)fastpic\.ru$
(^|\.)fastssh\.com$
(^|\.)fastssh\.com$
(^|\.)faststone\.org$
(^|\.)faststone\.org$
(^|\.)fatbtc\.com$
(^|\.)favstar\.fm$
(^|\.)favstar\.fm$
(^|\.)fawanghuihui\.org$
(^|\.)fawanghuihui\.org$
(^|\.)faydao\.com$
(^|\.)faydao\.com$
(^|\.)fb\.com$
(^|\.)fb\.com$
(^|\.)fb\.me$
(^|\.)fb\.me$
(^|\.)fbaddins\.com$
(^|\.)fbcdn\.net$
(^|\.)fbcdn\.net$
(^|\.)fbsbx\.com$
(^|\.)fbsbx\.com$
(^|\.)fbworkmail\.com$
(^|\.)fc2\.com$
(^|\.)fc2\.com$
(^|\.)fc2blog\.net$
(^|\.)fc2blog\.net$
(^|\.)fc2china\.com$
(^|\.)fc2china\.com$
...
@@ -1499,6 +1610,7 @@
...
@@ -1499,6 +1610,7 @@
(^|\.)finchvpn\.com$
(^|\.)finchvpn\.com$
(^|\.)findmespot\.com$
(^|\.)findmespot\.com$
(^|\.)findyoutube\.com$
(^|\.)findyoutube\.com$
(^|\.)findyoutube\.net$
(^|\.)fingerdaily\.com$
(^|\.)fingerdaily\.com$
(^|\.)finler\.net$
(^|\.)finler\.net$
(^|\.)firearmsworld\.net$
(^|\.)firearmsworld\.net$
...
@@ -1521,6 +1633,10 @@
...
@@ -1521,6 +1633,10 @@
(^|\.)flitto\.com$
(^|\.)flitto\.com$
(^|\.)flnet\.org$
(^|\.)flnet\.org$
(^|\.)flog\.tw$
(^|\.)flog\.tw$
(^|\.)flyvpn\.com$
(^|\.)flyzy2005\.com$
(^|\.)fnac\.be$
(^|\.)fnac\.com$
(^|\.)fochk\.org$
(^|\.)fochk\.org$
(^|\.)focustaiwan\.tw$
(^|\.)focustaiwan\.tw$
(^|\.)focusvpn\.com$
(^|\.)focusvpn\.com$
...
@@ -1529,6 +1645,7 @@
...
@@ -1529,6 +1645,7 @@
(^|\.)fofldfradio\.org$
(^|\.)fofldfradio\.org$
(^|\.)fooooo\.com$
(^|\.)fooooo\.com$
(^|\.)footwiball\.com$
(^|\.)footwiball\.com$
(^|\.)foreignpolicy\.com$
(^|\.)forum\.baby-kingdom\.com$
(^|\.)forum\.baby-kingdom\.com$
(^|\.)forum\.cyberctm\.com$
(^|\.)forum\.cyberctm\.com$
(^|\.)forum\.idsam\.com$
(^|\.)forum\.idsam\.com$
...
@@ -1561,6 +1678,7 @@
...
@@ -1561,6 +1678,7 @@
(^|\.)free-gate\.org$
(^|\.)free-gate\.org$
(^|\.)free-hada-now\.org$
(^|\.)free-hada-now\.org$
(^|\.)free-proxy\.cz$
(^|\.)free-proxy\.cz$
(^|\.)free-ss\.site$
(^|\.)free-ssh\.com$
(^|\.)free-ssh\.com$
(^|\.)free\.fr$
(^|\.)free\.fr$
(^|\.)free4u\.com\.ar$
(^|\.)free4u\.com\.ar$
...
@@ -1570,6 +1688,7 @@
...
@@ -1570,6 +1688,7 @@
(^|\.)freechina\.net$
(^|\.)freechina\.net$
(^|\.)freechina\.news$
(^|\.)freechina\.news$
(^|\.)freechinaforum\.org$
(^|\.)freechinaforum\.org$
(^|\.)freechinaweibo\.com$
(^|\.)freeddns\.com$
(^|\.)freeddns\.com$
(^|\.)freeddns\.org$
(^|\.)freeddns\.org$
(^|\.)freedomchina\.info$
(^|\.)freedomchina\.info$
...
@@ -1657,6 +1776,7 @@
...
@@ -1657,6 +1776,7 @@
(^|\.)g-area\.org$
(^|\.)g-area\.org$
(^|\.)g-queen\.com$
(^|\.)g-queen\.com$
(^|\.)g\.co$
(^|\.)g\.co$
(^|\.)g0v\.social$
(^|\.)g6hentai\.com$
(^|\.)g6hentai\.com$
(^|\.)gabocorp\.com$
(^|\.)gabocorp\.com$
(^|\.)gaeproxy\.com$
(^|\.)gaeproxy\.com$
...
@@ -1667,7 +1787,9 @@
...
@@ -1667,7 +1787,9 @@
(^|\.)game735\.com$
(^|\.)game735\.com$
(^|\.)gamebase\.com\.tw$
(^|\.)gamebase\.com\.tw$
(^|\.)gamejolt\.com$
(^|\.)gamejolt\.com$
(^|\.)gamer-cds\.cdn\.hinet\.net$
(^|\.)gamer\.com\.tw$
(^|\.)gamer\.com\.tw$
(^|\.)gamer2-cds\.cdn\.hinet\.net$
(^|\.)gamez\.com\.tw$
(^|\.)gamez\.com\.tw$
(^|\.)gamousa\.com$
(^|\.)gamousa\.com$
(^|\.)ganges\.com$
(^|\.)ganges\.com$
...
@@ -1679,6 +1801,8 @@
...
@@ -1679,6 +1801,8 @@
(^|\.)gardennetworks\.org$
(^|\.)gardennetworks\.org$
(^|\.)gartlive\.com$
(^|\.)gartlive\.com$
(^|\.)gate-project\.com$
(^|\.)gate-project\.com$
(^|\.)gate\.io$
(^|\.)gatecoin\.com$
(^|\.)gather\.com$
(^|\.)gather\.com$
(^|\.)gatherproxy\.com$
(^|\.)gatherproxy\.com$
(^|\.)gati\.org\.tw$
(^|\.)gati\.org\.tw$
...
@@ -1686,11 +1810,13 @@
...
@@ -1686,11 +1810,13 @@
(^|\.)gaycn\.net$
(^|\.)gaycn\.net$
(^|\.)gayhub\.com$
(^|\.)gayhub\.com$
(^|\.)gaymap\.cc$
(^|\.)gaymap\.cc$
(^|\.)gaymenring\.com$
(^|\.)gaytube\.com$
(^|\.)gaytube\.com$
(^|\.)gaywatch\.com$
(^|\.)gaywatch\.com$
(^|\.)gazotube\.com$
(^|\.)gazotube\.com$
(^|\.)gcc\.org\.hk$
(^|\.)gcc\.org\.hk$
(^|\.)gclooney\.com$
(^|\.)gclooney\.com$
(^|\.)gcmasia\.com$
(^|\.)gcpnews\.com$
(^|\.)gcpnews\.com$
(^|\.)gcr\.io$
(^|\.)gcr\.io$
(^|\.)gdbt\.net$
(^|\.)gdbt\.net$
...
@@ -1704,7 +1830,9 @@
...
@@ -1704,7 +1830,9 @@
(^|\.)geocities\.com$
(^|\.)geocities\.com$
(^|\.)geocities\.jp$
(^|\.)geocities\.jp$
(^|\.)gerefoundation\.org$
(^|\.)gerefoundation\.org$
(^|\.)get\.app$
(^|\.)get\.how$
(^|\.)get\.how$
(^|\.)get\.page$
(^|\.)getastrill\.com$
(^|\.)getastrill\.com$
(^|\.)getchu\.com$
(^|\.)getchu\.com$
(^|\.)getcloak\.com$
(^|\.)getcloak\.com$
...
@@ -1716,6 +1844,7 @@
...
@@ -1716,6 +1844,7 @@
(^|\.)getjetso\.com$
(^|\.)getjetso\.com$
(^|\.)getlantern\.org$
(^|\.)getlantern\.org$
(^|\.)getmdl\.io$
(^|\.)getmdl\.io$
(^|\.)getoutline\.org$
(^|\.)getsocialscope\.com$
(^|\.)getsocialscope\.com$
(^|\.)getsync\.com$
(^|\.)getsync\.com$
(^|\.)gettrials\.com$
(^|\.)gettrials\.com$
...
@@ -1728,7 +1857,6 @@
...
@@ -1728,7 +1857,6 @@
(^|\.)gfw\.press$
(^|\.)gfw\.press$
(^|\.)ggpht\.com$
(^|\.)ggpht\.com$
(^|\.)ggssl\.com$
(^|\.)ggssl\.com$
(^|\.)ghost\.org$
(^|\.)ghostpath\.com$
(^|\.)ghostpath\.com$
(^|\.)ghut\.org$
(^|\.)ghut\.org$
(^|\.)giantessnight\.com$
(^|\.)giantessnight\.com$
...
@@ -1737,6 +1865,7 @@
...
@@ -1737,6 +1865,7 @@
(^|\.)gigporno\.ru$
(^|\.)gigporno\.ru$
(^|\.)girlbanker\.com$
(^|\.)girlbanker\.com$
(^|\.)git\.io$
(^|\.)git\.io$
(^|\.)github\.com$
(^|\.)gizlen\.net$
(^|\.)gizlen\.net$
(^|\.)gjczz\.com$
(^|\.)gjczz\.com$
(^|\.)glass8\.eu$
(^|\.)glass8\.eu$
...
@@ -1799,8 +1928,61 @@
...
@@ -1799,8 +1928,61 @@
(^|\.)goodtv\.com\.tw$
(^|\.)goodtv\.com\.tw$
(^|\.)goodtv\.tv$
(^|\.)goodtv\.tv$
(^|\.)goofind\.com$
(^|\.)goofind\.com$
(^|\.)google(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?){1,2}$
(^|\.)google\.ae$
(^|\.)googleapis(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?){1,2}$
(^|\.)google\.am$
(^|\.)google\.as$
(^|\.)google\.at$
(^|\.)google\.az$
(^|\.)google\.ba$
(^|\.)google\.be$
(^|\.)google\.bg$
(^|\.)google\.ca$
(^|\.)google\.calstate\.edu$
(^|\.)google\.cd$
(^|\.)google\.ci$
(^|\.)google\.co\.id$
(^|\.)google\.co\.jp$
(^|\.)google\.co\.kr$
(^|\.)google\.co\.ma$
(^|\.)google\.co\.uk$
(^|\.)google\.com$
(^|\.)google\.de$
(^|\.)google\.dj$
(^|\.)google\.dk$
(^|\.)google\.es$
(^|\.)google\.fi$
(^|\.)google\.fm$
(^|\.)google\.fr$
(^|\.)google\.gg$
(^|\.)google\.gl$
(^|\.)google\.gr$
(^|\.)google\.ie$
(^|\.)google\.is$
(^|\.)google\.it$
(^|\.)google\.jo$
(^|\.)google\.kz$
(^|\.)google\.lv$
(^|\.)google\.mn$
(^|\.)google\.ms$
(^|\.)google\.nl$
(^|\.)google\.no$
(^|\.)google\.nu$
(^|\.)google\.ro$
(^|\.)google\.ru$
(^|\.)google\.rw$
(^|\.)google\.sc$
(^|\.)google\.sh$
(^|\.)google\.sk$
(^|\.)google\.sm$
(^|\.)google\.sn$
(^|\.)google\.tk$
(^|\.)google\.tm$
(^|\.)google\.to$
(^|\.)google\.tt$
(^|\.)google\.vu$
(^|\.)google\.ws$
(^|\.)googleapis\.cn$
(^|\.)googleapis\.com$
(^|\.)googleapps\.com$
(^|\.)googleapps\.com$
(^|\.)googlearth\.com$
(^|\.)googlearth\.com$
(^|\.)googleartproject\.com$
(^|\.)googleartproject\.com$
...
@@ -1831,6 +2013,7 @@
...
@@ -1831,6 +2013,7 @@
(^|\.)googlezip\.net$
(^|\.)googlezip\.net$
(^|\.)gopetition\.com$
(^|\.)gopetition\.com$
(^|\.)goproxing\.net$
(^|\.)goproxing\.net$
(^|\.)goregrish\.com$
(^|\.)gospelherald\.com$
(^|\.)gospelherald\.com$
(^|\.)got-game\.org$
(^|\.)got-game\.org$
(^|\.)gotdns\.ch$
(^|\.)gotdns\.ch$
...
@@ -1864,8 +2047,11 @@
...
@@ -1864,8 +2047,11 @@
(^|\.)greenreadings\.com$
(^|\.)greenreadings\.com$
(^|\.)greenvpn\.net$
(^|\.)greenvpn\.net$
(^|\.)greenvpn\.org$
(^|\.)greenvpn\.org$
(^|\.)grotty-monday\.com$
(^|\.)groups\.google\.cn$
(^|\.)groups\.google\.cn$
(^|\.)grow\.google$
(^|\.)gs-discuss\.com$
(^|\.)gs-discuss\.com$
(^|\.)gsp\.target\.com$
(^|\.)gstatic\.com$
(^|\.)gstatic\.com$
(^|\.)gtricks\.com$
(^|\.)gtricks\.com$
(^|\.)gts-vpn\.com$
(^|\.)gts-vpn\.com$
...
@@ -1873,6 +2059,7 @@
...
@@ -1873,6 +2059,7 @@
(^|\.)guaguass\.com$
(^|\.)guaguass\.com$
(^|\.)guaguass\.org$
(^|\.)guaguass\.org$
(^|\.)guancha\.org$
(^|\.)guancha\.org$
(^|\.)guaneryu\.com$
(^|\.)guangming\.com\.my$
(^|\.)guangming\.com\.my$
(^|\.)guardster\.com$
(^|\.)guardster\.com$
(^|\.)guishan\.org$
(^|\.)guishan\.org$
...
@@ -1907,6 +2094,7 @@
...
@@ -1907,6 +2094,7 @@
(^|\.)hacken\.cc$
(^|\.)hacken\.cc$
(^|\.)hacker\.org$
(^|\.)hacker\.org$
(^|\.)hackthatphone\.net$
(^|\.)hackthatphone\.net$
(^|\.)hahaxixi\.github\.io$
(^|\.)hahlo\.com$
(^|\.)hahlo\.com$
(^|\.)hakkatv\.org\.tw$
(^|\.)hakkatv\.org\.tw$
(^|\.)handcraftedsoftware\.org$
(^|\.)handcraftedsoftware\.org$
...
@@ -1920,12 +2108,15 @@
...
@@ -1920,12 +2108,15 @@
(^|\.)hautelook\.com$
(^|\.)hautelook\.com$
(^|\.)hautelookcdn\.com$
(^|\.)hautelookcdn\.com$
(^|\.)have8\.com$
(^|\.)have8\.com$
(^|\.)hbg\.com$
(^|\.)hbo\.com$
(^|\.)hclips\.com$
(^|\.)hclips\.com$
(^|\.)hd\.stheadline\.com$
(^|\.)hd\.stheadline\.com$
(^|\.)hdlt\.me$
(^|\.)hdlt\.me$
(^|\.)hdtvb\.net$
(^|\.)hdtvb\.net$
(^|\.)hdzog\.com$
(^|\.)hdzog\.com$
(^|\.)heartyit\.com$
(^|\.)heartyit\.com$
(^|\.)heavy-r\.com$
(^|\.)hec\.su$
(^|\.)hec\.su$
(^|\.)hecaitou\.net$
(^|\.)hecaitou\.net$
(^|\.)hechaji\.com$
(^|\.)hechaji\.com$
...
@@ -1977,6 +2168,7 @@
...
@@ -1977,6 +2168,7 @@
(^|\.)himalayanglacier\.com$
(^|\.)himalayanglacier\.com$
(^|\.)himemix\.com$
(^|\.)himemix\.com$
(^|\.)himemix\.net$
(^|\.)himemix\.net$
(^|\.)hitbtc\.com$
(^|\.)hitomi\.la$
(^|\.)hitomi\.la$
(^|\.)hiwifi\.com$
(^|\.)hiwifi\.com$
(^|\.)hizb-ut-tahrir\.info$
(^|\.)hizb-ut-tahrir\.info$
...
@@ -2020,6 +2212,7 @@
...
@@ -2020,6 +2212,7 @@
(^|\.)hkfaa\.com$
(^|\.)hkfaa\.com$
(^|\.)hkfreezone\.com$
(^|\.)hkfreezone\.com$
(^|\.)hkfront\.org$
(^|\.)hkfront\.org$
(^|\.)hkgalden\.com$
(^|\.)hkgolden\.com$
(^|\.)hkgolden\.com$
(^|\.)hkgreenradio\.org$
(^|\.)hkgreenradio\.org$
(^|\.)hkheadline\.com$
(^|\.)hkheadline\.com$
...
@@ -2040,6 +2233,7 @@
...
@@ -2040,6 +2233,7 @@
(^|\.)hkwcc\.org\.hk$
(^|\.)hkwcc\.org\.hk$
(^|\.)hkzone\.org$
(^|\.)hkzone\.org$
(^|\.)hmonghot\.com$
(^|\.)hmonghot\.com$
(^|\.)hmv\.co\.jp$
(^|\.)hmvdigital\.ca$
(^|\.)hmvdigital\.ca$
(^|\.)hmvdigital\.com$
(^|\.)hmvdigital\.com$
(^|\.)hnjhj\.com$
(^|\.)hnjhj\.com$
...
@@ -2073,6 +2267,7 @@
...
@@ -2073,6 +2267,7 @@
(^|\.)hotvpn\.com$
(^|\.)hotvpn\.com$
(^|\.)hougaige\.com$
(^|\.)hougaige\.com$
(^|\.)howtoforge\.com$
(^|\.)howtoforge\.com$
(^|\.)hoxx\.com$
(^|\.)hpa\.gov\.tw$
(^|\.)hpa\.gov\.tw$
(^|\.)hqcdp\.org$
(^|\.)hqcdp\.org$
(^|\.)hqjapanesesex\.com$
(^|\.)hqjapanesesex\.com$
...
@@ -2083,6 +2278,7 @@
...
@@ -2083,6 +2278,7 @@
(^|\.)hrcir\.com$
(^|\.)hrcir\.com$
(^|\.)hrea\.org$
(^|\.)hrea\.org$
(^|\.)hrichina\.org$
(^|\.)hrichina\.org$
(^|\.)hrtsea\.com$
(^|\.)hrw\.org$
(^|\.)hrw\.org$
(^|\.)hrweb\.org$
(^|\.)hrweb\.org$
(^|\.)hsjp\.net$
(^|\.)hsjp\.net$
...
@@ -2109,6 +2305,7 @@
...
@@ -2109,6 +2305,7 @@
(^|\.)huaxin\.ph$
(^|\.)huaxin\.ph$
(^|\.)huayuworld\.org$
(^|\.)huayuworld\.org$
(^|\.)hudatoriq\.web\.id$
(^|\.)hudatoriq\.web\.id$
(^|\.)hudson\.org$
(^|\.)huffingtonpost\.com$
(^|\.)huffingtonpost\.com$
(^|\.)hugoroy\.eu$
(^|\.)hugoroy\.eu$
(^|\.)huhaitai\.com$
(^|\.)huhaitai\.com$
...
@@ -2193,6 +2390,7 @@
...
@@ -2193,6 +2390,7 @@
(^|\.)ihakka\.net$
(^|\.)ihakka\.net$
(^|\.)ihao\.org$
(^|\.)ihao\.org$
(^|\.)iicns\.com$
(^|\.)iicns\.com$
(^|\.)iipdigital\.usembassy\.gov$
(^|\.)ikstar\.com$
(^|\.)ikstar\.com$
(^|\.)ikwb\.com$
(^|\.)ikwb\.com$
(^|\.)illusionfactory\.com$
(^|\.)illusionfactory\.com$
...
@@ -2240,16 +2438,19 @@
...
@@ -2240,16 +2438,19 @@
(^|\.)instagram\.com$
(^|\.)instagram\.com$
(^|\.)instanthq\.com$
(^|\.)instanthq\.com$
(^|\.)institut-tibetain\.org$
(^|\.)institut-tibetain\.org$
(^|\.)international-news\.newsmagazine\.asia$
(^|\.)internet\.org$
(^|\.)internet\.org$
(^|\.)internetdefenseleague\.org$
(^|\.)internetdefenseleague\.org$
(^|\.)internetfreedom\.org$
(^|\.)internetfreedom\.org$
(^|\.)internetpopculture\.com$
(^|\.)internetpopculture\.com$
(^|\.)inthenameofconfuciusmovie\.com$
(^|\.)investigating\.wordpress\.com$
(^|\.)investigating\.wordpress\.com$
(^|\.)inxian\.com$
(^|\.)inxian\.com$
(^|\.)iownyour\.biz$
(^|\.)iownyour\.biz$
(^|\.)iownyour\.org$
(^|\.)iownyour\.org$
(^|\.)ipalter\.com$
(^|\.)ipalter\.com$
(^|\.)ipfire\.org$
(^|\.)ipfire\.org$
(^|\.)ipfs\.io$
(^|\.)iphone4hongkong\.com$
(^|\.)iphone4hongkong\.com$
(^|\.)iphonehacks\.com$
(^|\.)iphonehacks\.com$
(^|\.)iphonetaiwan\.org$
(^|\.)iphonetaiwan\.org$
...
@@ -2272,6 +2473,7 @@
...
@@ -2272,6 +2473,7 @@
(^|\.)is\.gd$
(^|\.)is\.gd$
(^|\.)isaacmao\.com$
(^|\.)isaacmao\.com$
(^|\.)isasecret\.com$
(^|\.)isasecret\.com$
(^|\.)isc\.sans\.edu$
(^|\.)isgreat\.org$
(^|\.)isgreat\.org$
(^|\.)islahhaber\.net$
(^|\.)islahhaber\.net$
(^|\.)islam\.org\.hk$
(^|\.)islam\.org\.hk$
...
@@ -2322,6 +2524,7 @@
...
@@ -2322,6 +2524,7 @@
(^|\.)janwongphoto\.com$
(^|\.)janwongphoto\.com$
(^|\.)japan-whores\.com$
(^|\.)japan-whores\.com$
(^|\.)japanfirst\.asianfreeforum\.com$
(^|\.)japanfirst\.asianfreeforum\.com$
(^|\.)japantimes\.co\.jp$
(^|\.)jav\.com$
(^|\.)jav\.com$
(^|\.)jav101\.com$
(^|\.)jav101\.com$
(^|\.)jav2be\.com$
(^|\.)jav2be\.com$
...
@@ -2347,6 +2550,7 @@
...
@@ -2347,6 +2550,7 @@
(^|\.)jdwsy\.com$
(^|\.)jdwsy\.com$
(^|\.)jeanyim\.com$
(^|\.)jeanyim\.com$
(^|\.)jetos\.com$
(^|\.)jetos\.com$
(^|\.)jex\.com$
(^|\.)jfqu36\.club$
(^|\.)jfqu36\.club$
(^|\.)jfqu37\.xyz$
(^|\.)jfqu37\.xyz$
(^|\.)jgoodies\.com$
(^|\.)jgoodies\.com$
...
@@ -2365,6 +2569,8 @@
...
@@ -2365,6 +2569,8 @@
(^|\.)jingsim\.org$
(^|\.)jingsim\.org$
(^|\.)jinpianwang\.com$
(^|\.)jinpianwang\.com$
(^|\.)jinroukong\.com$
(^|\.)jinroukong\.com$
(^|\.)jintian\.net$
(^|\.)jinx\.com$
(^|\.)jitouch\.com$
(^|\.)jitouch\.com$
(^|\.)jizzthis\.com$
(^|\.)jizzthis\.com$
(^|\.)jjgirls\.com$
(^|\.)jjgirls\.com$
...
@@ -2376,6 +2582,7 @@
...
@@ -2376,6 +2582,7 @@
(^|\.)joachims\.org$
(^|\.)joachims\.org$
(^|\.)jobnewera\.wordpress\.com$
(^|\.)jobnewera\.wordpress\.com$
(^|\.)jobso\.tv$
(^|\.)jobso\.tv$
(^|\.)joinmastodon\.org$
(^|\.)journalchretien\.net$
(^|\.)journalchretien\.net$
(^|\.)journalofdemocracy\.org$
(^|\.)journalofdemocracy\.org$
(^|\.)joymiihub\.com$
(^|\.)joymiihub\.com$
...
@@ -2383,6 +2590,7 @@
...
@@ -2383,6 +2590,7 @@
(^|\.)jp\.hao123\.com$
(^|\.)jp\.hao123\.com$
(^|\.)jpl\.nasa\.gov$
(^|\.)jpl\.nasa\.gov$
(^|\.)jpopforum\.net$
(^|\.)jpopforum\.net$
(^|\.)jtvnw\.net$
(^|\.)jubushoushen\.com$
(^|\.)jubushoushen\.com$
(^|\.)juhuaren\.com$
(^|\.)juhuaren\.com$
(^|\.)jukujo-club\.com$
(^|\.)jukujo-club\.com$
...
@@ -2425,6 +2633,7 @@
...
@@ -2425,6 +2633,7 @@
(^|\.)karmapa-teachings\.org$
(^|\.)karmapa-teachings\.org$
(^|\.)karmapa\.org$
(^|\.)karmapa\.org$
(^|\.)kawaiikawaii\.jp$
(^|\.)kawaiikawaii\.jp$
(^|\.)kawase\.com$
(^|\.)kb\.monitorware\.com$
(^|\.)kb\.monitorware\.com$
(^|\.)kba-tx\.org$
(^|\.)kba-tx\.org$
(^|\.)kcoolonline\.com$
(^|\.)kcoolonline\.com$
...
@@ -2437,6 +2646,7 @@
...
@@ -2437,6 +2646,7 @@
(^|\.)kenengba\.com$
(^|\.)kenengba\.com$
(^|\.)keontech\.net$
(^|\.)keontech\.net$
(^|\.)kepard\.com$
(^|\.)kepard\.com$
(^|\.)kex\.com$
(^|\.)keycdn\.com$
(^|\.)keycdn\.com$
(^|\.)khabdha\.org$
(^|\.)khabdha\.org$
(^|\.)khatrimaza\.org$
(^|\.)khatrimaza\.org$
...
@@ -2472,7 +2682,9 @@
...
@@ -2472,7 +2682,9 @@
(^|\.)korenan2\.com$
(^|\.)korenan2\.com$
(^|\.)ksdl\.org$
(^|\.)ksdl\.org$
(^|\.)ksnews\.com\.tw$
(^|\.)ksnews\.com\.tw$
(^|\.)kspcoin\.com$
(^|\.)ktzhk\.com$
(^|\.)ktzhk\.com$
(^|\.)kucoin\.com$
(^|\.)kui\.name$
(^|\.)kui\.name$
(^|\.)kun\.im$
(^|\.)kun\.im$
(^|\.)kurashsultan\.com$
(^|\.)kurashsultan\.com$
...
@@ -2508,6 +2720,7 @@
...
@@ -2508,6 +2720,7 @@
(^|\.)lastfm\.es$
(^|\.)lastfm\.es$
(^|\.)latelinenews\.com$
(^|\.)latelinenews\.com$
(^|\.)latibet\.org$
(^|\.)latibet\.org$
(^|\.)lbank\.info$
(^|\.)ld\.hao123img\.com$
(^|\.)ld\.hao123img\.com$
(^|\.)le-vpn\.com$
(^|\.)le-vpn\.com$
(^|\.)leafyvpn\.net$
(^|\.)leafyvpn\.net$
...
@@ -2536,6 +2749,7 @@
...
@@ -2536,6 +2749,7 @@
(^|\.)lhakar\.org$
(^|\.)lhakar\.org$
(^|\.)lhasocialwork\.org$
(^|\.)lhasocialwork\.org$
(^|\.)liangyou\.net$
(^|\.)liangyou\.net$
(^|\.)liangzhichuanmei\.com$
(^|\.)lianyue\.net$
(^|\.)lianyue\.net$
(^|\.)liaowangxizang\.net$
(^|\.)liaowangxizang\.net$
(^|\.)liberal\.org\.hk$
(^|\.)liberal\.org\.hk$
...
@@ -2545,12 +2759,14 @@
...
@@ -2545,12 +2759,14 @@
(^|\.)lifemiles\.com$
(^|\.)lifemiles\.com$
(^|\.)lighten\.org\.tw$
(^|\.)lighten\.org\.tw$
(^|\.)lightnovel\.cn$
(^|\.)lightnovel\.cn$
(^|\.)lihkg\.com$
(^|\.)like\.com$
(^|\.)like\.com$
(^|\.)limiao\.net$
(^|\.)limiao\.net$
(^|\.)line-apps\.com$
(^|\.)line-apps\.com$
(^|\.)line-scdn\.net$
(^|\.)line-scdn\.net$
(^|\.)line\.me$
(^|\.)line\.me$
(^|\.)line\.naver\.jp$
(^|\.)line\.naver\.jp$
(^|\.)linear-abematv\.akamaized\.net$
(^|\.)linglingfa\.com$
(^|\.)linglingfa\.com$
(^|\.)lingvodics\.com$
(^|\.)lingvodics\.com$
(^|\.)link-o-rama\.com$
(^|\.)link-o-rama\.com$
...
@@ -2564,11 +2780,13 @@
...
@@ -2564,11 +2780,13 @@
(^|\.)listentoyoutube\.com$
(^|\.)listentoyoutube\.com$
(^|\.)listorious\.com$
(^|\.)listorious\.com$
(^|\.)lists\.w3\.org$
(^|\.)lists\.w3\.org$
(^|\.)liu-xiaobo\.org$
(^|\.)liudejun\.com$
(^|\.)liudejun\.com$
(^|\.)liuhanyu\.com$
(^|\.)liuhanyu\.com$
(^|\.)liujianshu\.com$
(^|\.)liujianshu\.com$
(^|\.)liuxiaobo\.net$
(^|\.)liuxiaobo\.net$
(^|\.)liuxiaotong\.com$
(^|\.)liuxiaotong\.com$
(^|\.)livecoin\.net$
(^|\.)livedoor\.jp$
(^|\.)livedoor\.jp$
(^|\.)liveleak\.com$
(^|\.)liveleak\.com$
(^|\.)livestation\.com$
(^|\.)livestation\.com$
...
@@ -2582,10 +2800,12 @@
...
@@ -2582,10 +2800,12 @@
(^|\.)llss\.me$
(^|\.)llss\.me$
(^|\.)load\.to$
(^|\.)load\.to$
(^|\.)lobsangwangyal\.com$
(^|\.)lobsangwangyal\.com$
(^|\.)localbitcoins\.com$
(^|\.)localdomain\.ws$
(^|\.)localdomain\.ws$
(^|\.)localpresshk\.com$
(^|\.)localpresshk\.com$
(^|\.)lockestek\.com$
(^|\.)lockestek\.com$
(^|\.)logbot\.net$
(^|\.)logbot\.net$
(^|\.)login\.target\.com$
(^|\.)logiqx\.com$
(^|\.)logiqx\.com$
(^|\.)londonchinese\.ca$
(^|\.)londonchinese\.ca$
(^|\.)longhair\.hk$
(^|\.)longhair\.hk$
...
@@ -2630,6 +2850,7 @@
...
@@ -2630,6 +2850,7 @@
(^|\.)mad-ar\.ch$
(^|\.)mad-ar\.ch$
(^|\.)madewithcode\.com$
(^|\.)madewithcode\.com$
(^|\.)madonna-av\.com$
(^|\.)madonna-av\.com$
(^|\.)madrau\.com$
(^|\.)madthumbs\.com$
(^|\.)madthumbs\.com$
(^|\.)magazines\.sina\.com\.tw$
(^|\.)magazines\.sina\.com\.tw$
(^|\.)magic-net\.info$
(^|\.)magic-net\.info$
...
@@ -2664,6 +2885,9 @@
...
@@ -2664,6 +2885,9 @@
(^|\.)marxists\.org$
(^|\.)marxists\.org$
(^|\.)mash\.to$
(^|\.)mash\.to$
(^|\.)maskedip\.com$
(^|\.)maskedip\.com$
(^|\.)mastodon\.cloud$
(^|\.)mastodon\.host$
(^|\.)mastodon\.social$
(^|\.)matainja\.com$
(^|\.)matainja\.com$
(^|\.)material\.io$
(^|\.)material\.io$
(^|\.)mathable\.io$
(^|\.)mathable\.io$
...
@@ -2671,6 +2895,7 @@
...
@@ -2671,6 +2895,7 @@
(^|\.)matome-plus\.com$
(^|\.)matome-plus\.com$
(^|\.)matome-plus\.net$
(^|\.)matome-plus\.net$
(^|\.)matsushimakaede\.com$
(^|\.)matsushimakaede\.com$
(^|\.)matters\.news$
(^|\.)mattwilcox\.net$
(^|\.)mattwilcox\.net$
(^|\.)maturejp\.com$
(^|\.)maturejp\.com$
(^|\.)maxing\.jp$
(^|\.)maxing\.jp$
...
@@ -2680,6 +2905,7 @@
...
@@ -2680,6 +2905,7 @@
(^|\.)mcfog\.com$
(^|\.)mcfog\.com$
(^|\.)mcreasite\.com$
(^|\.)mcreasite\.com$
(^|\.)md-t\.org$
(^|\.)md-t\.org$
(^|\.)me\.me$
(^|\.)me\.youthwant\.com\.tw$
(^|\.)me\.youthwant\.com\.tw$
(^|\.)meansys\.com$
(^|\.)meansys\.com$
(^|\.)media\.nu\.nl$
(^|\.)media\.nu\.nl$
...
@@ -2698,14 +2924,15 @@
...
@@ -2698,14 +2924,15 @@
(^|\.)megavideo\.com$
(^|\.)megavideo\.com$
(^|\.)megurineluka\.com$
(^|\.)megurineluka\.com$
(^|\.)meirixiaochao\.com$
(^|\.)meirixiaochao\.com$
(^|\.)melon-peach\.com$
(^|\.)meltoday\.com$
(^|\.)meltoday\.com$
(^|\.)meme\.yahoo\.com$
(^|\.)meme\.yahoo\.com$
(^|\.)memehk\.com$
(^|\.)memehk\.com$
(^|\.)memorybbs\.com$
(^|\.)memorybbs\.com$
(^|\.)memri\.org$
(^|\.)memri\.org$
(^|\.)memrijttm\.org$
(^|\.)memrijttm\.org$
(^|\.)mercatox\.com$
(^|\.)mercyprophet\.org$
(^|\.)mercyprophet\.org$
(^|\.)mergersandinquisitions\.org$
(^|\.)meridian-trust\.org$
(^|\.)meridian-trust\.org$
(^|\.)meripet\.biz$
(^|\.)meripet\.biz$
(^|\.)meripet\.com$
(^|\.)meripet\.com$
...
@@ -2714,6 +2941,7 @@
...
@@ -2714,6 +2941,7 @@
(^|\.)mesotw\.com$
(^|\.)mesotw\.com$
(^|\.)messenger\.com$
(^|\.)messenger\.com$
(^|\.)metacafe\.com$
(^|\.)metacafe\.com$
(^|\.)metart\.com$
(^|\.)metarthunter\.com$
(^|\.)metarthunter\.com$
(^|\.)meteorshowersonline\.com$
(^|\.)meteorshowersonline\.com$
(^|\.)metrohk\.com\.hk$
(^|\.)metrohk\.com\.hk$
...
@@ -2779,6 +3007,7 @@
...
@@ -2779,6 +3007,7 @@
(^|\.)mjlsh\.usc\.cuhk\.edu\.hk$
(^|\.)mjlsh\.usc\.cuhk\.edu\.hk$
(^|\.)mk5000\.com$
(^|\.)mk5000\.com$
(^|\.)mlcool\.com$
(^|\.)mlcool\.com$
(^|\.)mlzs\.work$
(^|\.)mm-cg\.com$
(^|\.)mm-cg\.com$
(^|\.)mmaaxx\.com$
(^|\.)mmaaxx\.com$
(^|\.)mmmca\.com$
(^|\.)mmmca\.com$
...
@@ -2791,9 +3020,13 @@
...
@@ -2791,9 +3020,13 @@
(^|\.)mobypicture\.com$
(^|\.)mobypicture\.com$
(^|\.)moeaic\.gov\.tw$
(^|\.)moeaic\.gov\.tw$
(^|\.)moeerolibrary\.com$
(^|\.)moeerolibrary\.com$
(^|\.)mofa\.gov\.tw$
(^|\.)mofaxiehui\.com$
(^|\.)mofaxiehui\.com$
(^|\.)mofos\.com$
(^|\.)mofos\.com$
(^|\.)mog\.com$
(^|\.)mog\.com$
(^|\.)mohu\.club$
(^|\.)mohu\.ml$
(^|\.)mojim\.com$
(^|\.)mol\.gov\.tw$
(^|\.)mol\.gov\.tw$
(^|\.)molihua\.org$
(^|\.)molihua\.org$
(^|\.)mondex\.org$
(^|\.)mondex\.org$
...
@@ -2803,10 +3036,12 @@
...
@@ -2803,10 +3036,12 @@
(^|\.)monster\.com$
(^|\.)monster\.com$
(^|\.)moodyz\.com$
(^|\.)moodyz\.com$
(^|\.)moonbbs\.com$
(^|\.)moonbbs\.com$
(^|\.)moonbingo\.com$
(^|\.)morningsun\.org$
(^|\.)morningsun\.org$
(^|\.)moroneta\.com$
(^|\.)moroneta\.com$
(^|\.)mos\.ru$
(^|\.)mos\.ru$
(^|\.)motherless\.com$
(^|\.)motherless\.com$
(^|\.)motiyun\.com$
(^|\.)motor4ik\.ru$
(^|\.)motor4ik\.ru$
(^|\.)mousebreaker\.com$
(^|\.)mousebreaker\.com$
(^|\.)movements\.org$
(^|\.)movements\.org$
...
@@ -2823,6 +3058,7 @@
...
@@ -2823,6 +3058,7 @@
(^|\.)mrface\.com$
(^|\.)mrface\.com$
(^|\.)mrslove\.com$
(^|\.)mrslove\.com$
(^|\.)mrtweet\.com$
(^|\.)mrtweet\.com$
(^|\.)msa-it\.org$
(^|\.)msguancha\.com$
(^|\.)msguancha\.com$
(^|\.)msha\.gov$
(^|\.)msha\.gov$
(^|\.)mswe1\.org$
(^|\.)mswe1\.org$
...
@@ -2957,7 +3193,6 @@
...
@@ -2957,7 +3193,6 @@
(^|\.)newipnow\.com$
(^|\.)newipnow\.com$
(^|\.)newlandmagazine\.com\.au$
(^|\.)newlandmagazine\.com\.au$
(^|\.)newnews\.ca$
(^|\.)newnews\.ca$
(^|\.)news\.bbc\.co\.uk$
(^|\.)news\.cnyes\.com$
(^|\.)news\.cnyes\.com$
(^|\.)news\.hk\.msn\.com$
(^|\.)news\.hk\.msn\.com$
(^|\.)news\.hkpeanut\.com$
(^|\.)news\.hkpeanut\.com$
...
@@ -2980,7 +3215,6 @@
...
@@ -2980,7 +3215,6 @@
(^|\.)newscn\.org$
(^|\.)newscn\.org$
(^|\.)newsdetox\.ca$
(^|\.)newsdetox\.ca$
(^|\.)newsdh\.com$
(^|\.)newsdh\.com$
(^|\.)newsforums\.bbc\.co\.uk$
(^|\.)newspeak\.cc$
(^|\.)newspeak\.cc$
(^|\.)newstamago\.com$
(^|\.)newstamago\.com$
(^|\.)newstapa\.org$
(^|\.)newstapa\.org$
...
@@ -3017,6 +3251,7 @@
...
@@ -3017,6 +3251,7 @@
(^|\.)ninjaproxy\.ninja$
(^|\.)ninjaproxy\.ninja$
(^|\.)nintendium\.com$
(^|\.)nintendium\.com$
(^|\.)ninth\.biz$
(^|\.)ninth\.biz$
(^|\.)niu\.moe$
(^|\.)niusnews\.com$
(^|\.)niusnews\.com$
(^|\.)njactb\.org$
(^|\.)njactb\.org$
(^|\.)njuice\.com$
(^|\.)njuice\.com$
...
@@ -3026,6 +3261,7 @@
...
@@ -3026,6 +3261,7 @@
(^|\.)nobel\.se$
(^|\.)nobel\.se$
(^|\.)nobelprize\.org$
(^|\.)nobelprize\.org$
(^|\.)nobodycanstop\.us$
(^|\.)nobodycanstop\.us$
(^|\.)nofile\.io$
(^|\.)nokogiri\.org$
(^|\.)nokogiri\.org$
(^|\.)nokola\.com$
(^|\.)nokola\.com$
(^|\.)noodlevpn\.com$
(^|\.)noodlevpn\.com$
...
@@ -3034,8 +3270,10 @@
...
@@ -3034,8 +3270,10 @@
(^|\.)nordstromimage\.com$
(^|\.)nordstromimage\.com$
(^|\.)nordstromrack\.com$
(^|\.)nordstromrack\.com$
(^|\.)nordvpn\.com$
(^|\.)nordvpn\.com$
(^|\.)notify\.dropboxapi\.com$
(^|\.)nottinghampost\.com$
(^|\.)nottinghampost\.com$
(^|\.)novelasia\.com$
(^|\.)novelasia\.com$
(^|\.)now\.com$
(^|\.)now\.im$
(^|\.)now\.im$
(^|\.)nownews\.com$
(^|\.)nownews\.com$
(^|\.)nowtorrents\.com$
(^|\.)nowtorrents\.com$
...
@@ -3044,6 +3282,7 @@
...
@@ -3044,6 +3282,7 @@
(^|\.)npa\.gov\.tw$
(^|\.)npa\.gov\.tw$
(^|\.)npnt\.me$
(^|\.)npnt\.me$
(^|\.)nps\.gov$
(^|\.)nps\.gov$
(^|\.)npsboost\.com$
(^|\.)nradio\.me$
(^|\.)nradio\.me$
(^|\.)nrk\.no$
(^|\.)nrk\.no$
(^|\.)ns01\.biz$
(^|\.)ns01\.biz$
...
@@ -3085,7 +3324,6 @@
...
@@ -3085,7 +3324,6 @@
(^|\.)ny\.stgloballink\.com$
(^|\.)ny\.stgloballink\.com$
(^|\.)ny\.visiontimes\.com$
(^|\.)ny\.visiontimes\.com$
(^|\.)nyaa\.eu$
(^|\.)nyaa\.eu$
(^|\.)nyaa\.si$
(^|\.)nydus\.ca$
(^|\.)nydus\.ca$
(^|\.)nylon-angel\.com$
(^|\.)nylon-angel\.com$
(^|\.)nylonstockingsonline\.com$
(^|\.)nylonstockingsonline\.com$
...
@@ -3110,6 +3348,7 @@
...
@@ -3110,6 +3348,7 @@
(^|\.)october-review\.org$
(^|\.)october-review\.org$
(^|\.)oculus\.com$
(^|\.)oculus\.com$
(^|\.)oculuscdn\.com$
(^|\.)oculuscdn\.com$
(^|\.)oex\.com$
(^|\.)offbeatchina\.com$
(^|\.)offbeatchina\.com$
(^|\.)officeoftibet\.com$
(^|\.)officeoftibet\.com$
(^|\.)ofile\.org$
(^|\.)ofile\.org$
...
@@ -3120,6 +3359,7 @@
...
@@ -3120,6 +3359,7 @@
(^|\.)oizoblog\.com$
(^|\.)oizoblog\.com$
(^|\.)ok\.ru$
(^|\.)ok\.ru$
(^|\.)okayfreedom\.com$
(^|\.)okayfreedom\.com$
(^|\.)okex\.com$
(^|\.)okk\.tw$
(^|\.)okk\.tw$
(^|\.)old-cat\.net$
(^|\.)old-cat\.net$
(^|\.)old\.honeynet\.org$
(^|\.)old\.honeynet\.org$
...
@@ -3135,6 +3375,7 @@
...
@@ -3135,6 +3375,7 @@
(^|\.)onapp\.com$
(^|\.)onapp\.com$
(^|\.)onedrive\.live\.com$
(^|\.)onedrive\.live\.com$
(^|\.)onedumb\.com$
(^|\.)onedumb\.com$
(^|\.)onejav\.com$
(^|\.)onion\.city$
(^|\.)onion\.city$
(^|\.)online\.recoveryversion\.org$
(^|\.)online\.recoveryversion\.org$
(^|\.)onlinecha\.com$
(^|\.)onlinecha\.com$
...
@@ -3158,9 +3399,11 @@
...
@@ -3158,9 +3399,11 @@
(^|\.)openid\.net$
(^|\.)openid\.net$
(^|\.)openleaks\.org$
(^|\.)openleaks\.org$
(^|\.)openvpn\.net$
(^|\.)openvpn\.net$
(^|\.)openvpn\.org$
(^|\.)openwebster\.com$
(^|\.)openwebster\.com$
(^|\.)openwrt\.org\.cn$
(^|\.)openwrt\.org\.cn$
(^|\.)opml\.radiotime\.com$
(^|\.)opml\.radiotime\.com$
(^|\.)opus-gaming\.com$
(^|\.)organcare\.org\.tw$
(^|\.)organcare\.org\.tw$
(^|\.)organharvestinvestigation\.net$
(^|\.)organharvestinvestigation\.net$
(^|\.)organiccrap\.com$
(^|\.)organiccrap\.com$
...
@@ -3171,6 +3414,7 @@
...
@@ -3171,6 +3414,7 @@
(^|\.)orn\.jp$
(^|\.)orn\.jp$
(^|\.)orzistic\.org$
(^|\.)orzistic\.org$
(^|\.)osfoora\.com$
(^|\.)osfoora\.com$
(^|\.)otcbtc\.com$
(^|\.)otnd\.org$
(^|\.)otnd\.org$
(^|\.)otto\.de$
(^|\.)otto\.de$
(^|\.)otzo\.com$
(^|\.)otzo\.com$
...
@@ -3203,14 +3447,12 @@
...
@@ -3203,14 +3447,12 @@
(^|\.)paldengyal\.com$
(^|\.)paldengyal\.com$
(^|\.)paljorpublications\.com$
(^|\.)paljorpublications\.com$
(^|\.)paltalk\.com$
(^|\.)paltalk\.com$
(^|\.)panacom\.co\.jp$
(^|\.)panamapapers\.sueddeutsche\.de$
(^|\.)panamapapers\.sueddeutsche\.de$
(^|\.)pandapow\.co$
(^|\.)pandapow\.co$
(^|\.)pandapow\.net$
(^|\.)pandapow\.net$
(^|\.)pandavpn-jp\.com$
(^|\.)pandavpn-jp\.com$
(^|\.)pandora\.com$
(^|\.)pandora\.com$
(^|\.)pandora\.tv$
(^|\.)pandora\.tv$
(^|\.)pangci\.net$
(^|\.)panluan\.net$
(^|\.)panluan\.net$
(^|\.)panoramio\.com$
(^|\.)panoramio\.com$
(^|\.)pao-pao\.net$
(^|\.)pao-pao\.net$
...
@@ -3223,6 +3465,7 @@
...
@@ -3223,6 +3465,7 @@
(^|\.)partypoker\.com$
(^|\.)partypoker\.com$
(^|\.)passion\.com$
(^|\.)passion\.com$
(^|\.)passiontimes\.hk$
(^|\.)passiontimes\.hk$
(^|\.)paste\.ee$
(^|\.)pastebin\.com$
(^|\.)pastebin\.com$
(^|\.)pastie\.org$
(^|\.)pastie\.org$
(^|\.)pbs\.org$
(^|\.)pbs\.org$
...
@@ -3283,6 +3526,7 @@
...
@@ -3283,6 +3526,7 @@
(^|\.)picturesocial\.com$
(^|\.)picturesocial\.com$
(^|\.)pin-cong\.com$
(^|\.)pin-cong\.com$
(^|\.)pin6\.com$
(^|\.)pin6\.com$
(^|\.)pincong\.rocks$
(^|\.)ping\.fm$
(^|\.)ping\.fm$
(^|\.)pinimg\.com$
(^|\.)pinimg\.com$
(^|\.)pinkrod\.com$
(^|\.)pinkrod\.com$
...
@@ -3306,6 +3550,7 @@
...
@@ -3306,6 +3550,7 @@
(^|\.)pixiv\.net$
(^|\.)pixiv\.net$
(^|\.)pixnet\.net$
(^|\.)pixnet\.net$
(^|\.)pk\.com$
(^|\.)pk\.com$
(^|\.)pki\.goog$
(^|\.)placemix\.com$
(^|\.)placemix\.com$
(^|\.)playboy\.com$
(^|\.)playboy\.com$
(^|\.)playboyplus\.com$
(^|\.)playboyplus\.com$
...
@@ -3315,6 +3560,7 @@
...
@@ -3315,6 +3560,7 @@
(^|\.)plays\.com\.tw$
(^|\.)plays\.com\.tw$
(^|\.)plm\.org\.hk$
(^|\.)plm\.org\.hk$
(^|\.)plunder\.com$
(^|\.)plunder\.com$
(^|\.)plurk\.com$
(^|\.)plus28\.com$
(^|\.)plus28\.com$
(^|\.)plusbb\.com$
(^|\.)plusbb\.com$
(^|\.)pmatehunter\.com$
(^|\.)pmatehunter\.com$
...
@@ -3322,9 +3568,11 @@
...
@@ -3322,9 +3568,11 @@
(^|\.)po2b\.com$
(^|\.)po2b\.com$
(^|\.)pobieramy\.top$
(^|\.)pobieramy\.top$
(^|\.)podictionary\.com$
(^|\.)podictionary\.com$
(^|\.)pokerstars\.com$
(^|\.)pokerstars\.net$
(^|\.)pokerstars\.net$
(^|\.)politicalchina\.org$
(^|\.)politicalchina\.org$
(^|\.)politicalconsultation\.org$
(^|\.)politicalconsultation\.org$
(^|\.)politiscales\.net$
(^|\.)poloniex\.com$
(^|\.)poloniex\.com$
(^|\.)polymer-project\.org$
(^|\.)polymer-project\.org$
(^|\.)polymerhk\.com$
(^|\.)polymerhk\.com$
...
@@ -3366,9 +3614,11 @@
...
@@ -3366,9 +3614,11 @@
(^|\.)powerphoto\.org$
(^|\.)powerphoto\.org$
(^|\.)prayforchina\.net$
(^|\.)prayforchina\.net$
(^|\.)premeforwindows7\.com$
(^|\.)premeforwindows7\.com$
(^|\.)premproxy\.com$
(^|\.)presentationzen\.com$
(^|\.)presentationzen\.com$
(^|\.)presidentlee\.tw$
(^|\.)presidentlee\.tw$
(^|\.)prestige-av\.com$
(^|\.)prestige-av\.com$
(^|\.)pride\.google$
(^|\.)prisoner-state-secret-journal-premier$
(^|\.)prisoner-state-secret-journal-premier$
(^|\.)prisoneralert\.com$
(^|\.)prisoneralert\.com$
(^|\.)pritunl\.com$
(^|\.)pritunl\.com$
...
@@ -3380,6 +3630,7 @@
...
@@ -3380,6 +3630,7 @@
(^|\.)privatevpn\.com$
(^|\.)privatevpn\.com$
(^|\.)procopytips\.com$
(^|\.)procopytips\.com$
(^|\.)prosiben\.de$
(^|\.)prosiben\.de$
(^|\.)protonvpn\.com$
(^|\.)provideocoalition\.com$
(^|\.)provideocoalition\.com$
(^|\.)provpnaccounts\.com$
(^|\.)provpnaccounts\.com$
(^|\.)proxfree\.com$
(^|\.)proxfree\.com$
...
@@ -3427,6 +3678,7 @@
...
@@ -3427,6 +3678,7 @@
(^|\.)python\.com$
(^|\.)python\.com$
(^|\.)python\.com\.tw$
(^|\.)python\.com\.tw$
(^|\.)pythonhackers\.com$
(^|\.)pythonhackers\.com$
(^|\.)pytorch\.org$
(^|\.)q%3dfreedom$
(^|\.)q%3dfreedom$
(^|\.)q%3dtriangle$
(^|\.)q%3dtriangle$
(^|\.)q=freedom$
(^|\.)q=freedom$
...
@@ -3454,6 +3706,7 @@
...
@@ -3454,6 +3706,7 @@
(^|\.)quitccp\.net$
(^|\.)quitccp\.net$
(^|\.)quitccp\.org$
(^|\.)quitccp\.org$
(^|\.)quora\.com$
(^|\.)quora\.com$
(^|\.)quoracdn\.net$
(^|\.)quran\.com$
(^|\.)quran\.com$
(^|\.)quranexplorer\.com$
(^|\.)quranexplorer\.com$
(^|\.)qusi8\.net$
(^|\.)qusi8\.net$
...
@@ -3488,6 +3741,7 @@
...
@@ -3488,6 +3741,7 @@
(^|\.)rawgit\.com$
(^|\.)rawgit\.com$
(^|\.)rawgithub\.com$
(^|\.)rawgithub\.com$
(^|\.)razyboard\.com$
(^|\.)razyboard\.com$
(^|\.)rcam\.target\.com$
(^|\.)rcinet\.ca$
(^|\.)rcinet\.ca$
(^|\.)rconversation\.blogs\.com$
(^|\.)rconversation\.blogs\.com$
(^|\.)rd\.com$
(^|\.)rd\.com$
...
@@ -3510,6 +3764,11 @@
...
@@ -3510,6 +3764,11 @@
(^|\.)redballoonsolidarity\.org$
(^|\.)redballoonsolidarity\.org$
(^|\.)redchinacn\.net$
(^|\.)redchinacn\.net$
(^|\.)redchinacn\.org$
(^|\.)redchinacn\.org$
(^|\.)redd\.it$
(^|\.)reddit\.com$
(^|\.)redditlist\.com$
(^|\.)redditmedia\.com$
(^|\.)redditstatic\.com$
(^|\.)redhotlabs\.com$
(^|\.)redhotlabs\.com$
(^|\.)redtube\.com$
(^|\.)redtube\.com$
(^|\.)referer\.us$
(^|\.)referer\.us$
...
@@ -3533,16 +3792,21 @@
...
@@ -3533,16 +3792,21 @@
(^|\.)revver\.com$
(^|\.)revver\.com$
(^|\.)rfa\.org$
(^|\.)rfa\.org$
(^|\.)rfachina\.com$
(^|\.)rfachina\.com$
(^|\.)rfalive1\.akacast\.akamaistream\.net$
(^|\.)rfamobile\.org$
(^|\.)rfamobile\.org$
(^|\.)rfaweb\.org$
(^|\.)rfaweb\.org$
(^|\.)rferl\.org$
(^|\.)rferl\.org$
(^|\.)rfi\.fr$
(^|\.)rfi\.fr$
(^|\.)rfi\.my$
(^|\.)rfi\.my$
(^|\.)rg3\.github\.io$
(^|\.)rightbtc\.com$
(^|\.)rigpa\.org$
(^|\.)rigpa\.org$
(^|\.)riku\.me$
(^|\.)riku\.me$
(^|\.)rileyguide\.com$
(^|\.)rileyguide\.com$
(^|\.)ritouki\.jp$
(^|\.)ritouki\.jp$
(^|\.)ritter\.vg$
(^|\.)ritter\.vg$
(^|\.)rixcloud\.com$
(^|\.)rixcloud\.us$
(^|\.)rlwlw\.com$
(^|\.)rlwlw\.com$
(^|\.)rmjdw\.com$
(^|\.)rmjdw\.com$
(^|\.)rmjdw132\.info$
(^|\.)rmjdw132\.info$
...
@@ -3557,6 +3821,7 @@
...
@@ -3557,6 +3821,7 @@
(^|\.)roodo\.com$
(^|\.)roodo\.com$
(^|\.)rosechina\.net$
(^|\.)rosechina\.net$
(^|\.)rotten\.com$
(^|\.)rotten\.com$
(^|\.)rsdlmonitor\.com$
(^|\.)rsf-chinese\.org$
(^|\.)rsf-chinese\.org$
(^|\.)rsf\.org$
(^|\.)rsf\.org$
(^|\.)rsgamen\.org$
(^|\.)rsgamen\.org$
...
@@ -3564,10 +3829,12 @@
...
@@ -3564,10 +3829,12 @@
(^|\.)rtalabel\.org$
(^|\.)rtalabel\.org$
(^|\.)rthk\.hk$
(^|\.)rthk\.hk$
(^|\.)rthk\.org\.hk$
(^|\.)rthk\.org\.hk$
(^|\.)rthklive2-lh\.akamaihd\.net$
(^|\.)rti\.org\.tw$
(^|\.)rti\.org\.tw$
(^|\.)rtycminnesota\.org$
(^|\.)rtycminnesota\.org$
(^|\.)ruanyifeng\.com$
(^|\.)ruanyifeng\.com$
(^|\.)rukor\.org$
(^|\.)rukor\.org$
(^|\.)runbtx\.com$
(^|\.)rushbee\.com$
(^|\.)rushbee\.com$
(^|\.)ruten\.com\.tw$
(^|\.)ruten\.com\.tw$
(^|\.)rutube\.ru$
(^|\.)rutube\.ru$
...
@@ -3587,6 +3854,7 @@
...
@@ -3587,6 +3854,7 @@
(^|\.)sadistic-v\.com$
(^|\.)sadistic-v\.com$
(^|\.)sadpanda\.us$
(^|\.)sadpanda\.us$
(^|\.)safervpn\.com$
(^|\.)safervpn\.com$
(^|\.)safety\.google$
(^|\.)saintyculture\.com$
(^|\.)saintyculture\.com$
(^|\.)saiq\.me$
(^|\.)saiq\.me$
(^|\.)sakuralive\.com$
(^|\.)sakuralive\.com$
...
@@ -3599,6 +3867,7 @@
...
@@ -3599,6 +3867,7 @@
(^|\.)saveliuxiaobo\.com$
(^|\.)saveliuxiaobo\.com$
(^|\.)savemedia\.com$
(^|\.)savemedia\.com$
(^|\.)savethedate\.foo$
(^|\.)savethedate\.foo$
(^|\.)savethesounds\.info$
(^|\.)savetibet\.de$
(^|\.)savetibet\.de$
(^|\.)savetibet\.fr$
(^|\.)savetibet\.fr$
(^|\.)savetibet\.nl$
(^|\.)savetibet\.nl$
...
@@ -3609,6 +3878,9 @@
...
@@ -3609,6 +3878,9 @@
(^|\.)say2\.info$
(^|\.)say2\.info$
(^|\.)sbme\.me$
(^|\.)sbme\.me$
(^|\.)sbs\.com\.au$
(^|\.)sbs\.com\.au$
(^|\.)scache\.vzw\.com$
(^|\.)scache1\.vzw\.com$
(^|\.)scache2\.vzw\.com$
(^|\.)scasino\.com$
(^|\.)scasino\.com$
(^|\.)schema\.org$
(^|\.)schema\.org$
(^|\.)sciencenets\.com$
(^|\.)sciencenets\.com$
...
@@ -3622,6 +3894,7 @@
...
@@ -3622,6 +3894,7 @@
(^|\.)search$
(^|\.)search$
(^|\.)search\.aol\.com$
(^|\.)search\.aol\.com$
(^|\.)search\.yahoo\.co\.jp$
(^|\.)search\.yahoo\.co\.jp$
(^|\.)search\.yahoo\.com$
(^|\.)searchtruth\.com$
(^|\.)searchtruth\.com$
(^|\.)secretchina\.com$
(^|\.)secretchina\.com$
(^|\.)secretgarden\.no$
(^|\.)secretgarden\.no$
...
@@ -3630,6 +3903,7 @@
...
@@ -3630,6 +3903,7 @@
(^|\.)secure\.logmein\.com$
(^|\.)secure\.logmein\.com$
(^|\.)secure\.raxcdn\.com$
(^|\.)secure\.raxcdn\.com$
(^|\.)securetunnel\.com$
(^|\.)securetunnel\.com$
(^|\.)securityinabox\.org$
(^|\.)securitykiss\.com$
(^|\.)securitykiss\.com$
(^|\.)seed4\.me$
(^|\.)seed4\.me$
(^|\.)seesmic\.com$
(^|\.)seesmic\.com$
...
@@ -3669,6 +3943,7 @@
...
@@ -3669,6 +3943,7 @@
(^|\.)shadowsky\.xyz$
(^|\.)shadowsky\.xyz$
(^|\.)shadowsocks-r\.com$
(^|\.)shadowsocks-r\.com$
(^|\.)shadowsocks\.asia$
(^|\.)shadowsocks\.asia$
(^|\.)shadowsocks\.be$
(^|\.)shadowsocks\.com$
(^|\.)shadowsocks\.com$
(^|\.)shadowsocks\.com\.hk$
(^|\.)shadowsocks\.com\.hk$
(^|\.)shadowsocks\.org$
(^|\.)shadowsocks\.org$
...
@@ -3720,6 +3995,7 @@
...
@@ -3720,6 +3995,7 @@
(^|\.)sierrafriendsoftibet\.org$
(^|\.)sierrafriendsoftibet\.org$
(^|\.)sijihuisuo\.club$
(^|\.)sijihuisuo\.club$
(^|\.)sijihuisuo\.com$
(^|\.)sijihuisuo\.com$
(^|\.)sikaozhe1997\.github\.io$
(^|\.)silkbook\.com$
(^|\.)silkbook\.com$
(^|\.)simbolostwitter\.com$
(^|\.)simbolostwitter\.com$
(^|\.)simplecd\.org$
(^|\.)simplecd\.org$
...
@@ -3742,11 +4018,13 @@
...
@@ -3742,11 +4018,13 @@
(^|\.)sis\.xxx$
(^|\.)sis\.xxx$
(^|\.)sis001\.com$
(^|\.)sis001\.com$
(^|\.)sis001\.us$
(^|\.)sis001\.us$
(^|\.)site2unblock\.com$
(^|\.)site90\.net$
(^|\.)site90\.net$
(^|\.)sitebro\.tw$
(^|\.)sitebro\.tw$
(^|\.)sitekreator\.com$
(^|\.)sitekreator\.com$
(^|\.)siteks\.uk\.to$
(^|\.)siteks\.uk\.to$
(^|\.)sitemaps\.org$
(^|\.)sitemaps\.org$
(^|\.)six-degrees\.io$
(^|\.)sixth\.biz$
(^|\.)sixth\.biz$
(^|\.)sjrt\.org$
(^|\.)sjrt\.org$
(^|\.)sjum\.cn$
(^|\.)sjum\.cn$
...
@@ -3783,6 +4061,7 @@
...
@@ -3783,6 +4061,7 @@
(^|\.)sobees\.com$
(^|\.)sobees\.com$
(^|\.)soc\.mil$
(^|\.)soc\.mil$
(^|\.)socialwhale\.com$
(^|\.)socialwhale\.com$
(^|\.)socks-proxy\.net$
(^|\.)sockscap64\.com$
(^|\.)sockscap64\.com$
(^|\.)sockslist\.net$
(^|\.)sockslist\.net$
(^|\.)socrec\.org$
(^|\.)socrec\.org$
...
@@ -3791,6 +4070,7 @@
...
@@ -3791,6 +4070,7 @@
(^|\.)softether-download\.com$
(^|\.)softether-download\.com$
(^|\.)softether\.co\.jp$
(^|\.)softether\.co\.jp$
(^|\.)softether\.org$
(^|\.)softether\.org$
(^|\.)softsmirror\.cf$
(^|\.)softwarebychuck\.com$
(^|\.)softwarebychuck\.com$
(^|\.)softwaredownload\.gitbooks\.io$
(^|\.)softwaredownload\.gitbooks\.io$
(^|\.)sogclub\.com$
(^|\.)sogclub\.com$
...
@@ -3827,6 +4107,8 @@
...
@@ -3827,6 +4107,8 @@
(^|\.)sourcewadio\.com$
(^|\.)sourcewadio\.com$
(^|\.)southnews\.com\.tw$
(^|\.)southnews\.com\.tw$
(^|\.)sowers\.org\.hk$
(^|\.)sowers\.org\.hk$
(^|\.)soylentnews\.org$
(^|\.)spaces\.hightail\.com$
(^|\.)spankbang\.com$
(^|\.)spankbang\.com$
(^|\.)spankingtube\.com$
(^|\.)spankingtube\.com$
(^|\.)spankwire\.com$
(^|\.)spankwire\.com$
...
@@ -3836,6 +4118,7 @@
...
@@ -3836,6 +4118,7 @@
(^|\.)speedify\.com$
(^|\.)speedify\.com$
(^|\.)spem\.at$
(^|\.)spem\.at$
(^|\.)spencertipping\.com$
(^|\.)spencertipping\.com$
(^|\.)spendee\.com$
(^|\.)spicevpn\.com$
(^|\.)spicevpn\.com$
(^|\.)spideroak\.com$
(^|\.)spideroak\.com$
(^|\.)spike\.com$
(^|\.)spike\.com$
...
@@ -3854,12 +4137,17 @@
...
@@ -3854,12 +4137,17 @@
(^|\.)ss-link\.com$
(^|\.)ss-link\.com$
(^|\.)ss\.carryzhou\.com$
(^|\.)ss\.carryzhou\.com$
(^|\.)ss\.levyhsu\.com$
(^|\.)ss\.levyhsu\.com$
(^|\.)ss\.pythonic\.life$
(^|\.)ss7\.vzw\.com$
(^|\.)ssglobal\.co$
(^|\.)ssglobal\.co$
(^|\.)ssglobal\.me$
(^|\.)ssglobal\.me$
(^|\.)ssh91\.com$
(^|\.)ssh91\.com$
(^|\.)ssl\.webpack\.de$
(^|\.)ssl\.webpack\.de$
(^|\.)ssl443\.org$
(^|\.)ssl443\.org$
(^|\.)sspanel\.net$
(^|\.)sspro\.ml$
(^|\.)sspro\.ml$
(^|\.)ssr\.tools$
(^|\.)ssrshare\.com$
(^|\.)sss\.camp$
(^|\.)sss\.camp$
(^|\.)sstmlt\.moe$
(^|\.)sstmlt\.moe$
(^|\.)sstmlt\.net$
(^|\.)sstmlt\.net$
...
@@ -3874,6 +4162,7 @@
...
@@ -3874,6 +4162,7 @@
(^|\.)stat\.gov\.tw$
(^|\.)stat\.gov\.tw$
(^|\.)static-economist\.com$
(^|\.)static-economist\.com$
(^|\.)static\.comico\.tw$
(^|\.)static\.comico\.tw$
(^|\.)static\.shemalez\.com$
(^|\.)static01\.nyt\.com$
(^|\.)static01\.nyt\.com$
(^|\.)staticflickr\.com$
(^|\.)staticflickr\.com$
(^|\.)statueofdemocracy\.org$
(^|\.)statueofdemocracy\.org$
...
@@ -3916,6 +4205,7 @@
...
@@ -3916,6 +4205,7 @@
(^|\.)sugumiru18\.com$
(^|\.)sugumiru18\.com$
(^|\.)suissl\.com$
(^|\.)suissl\.com$
(^|\.)sujiatun\.wordpress\.com$
(^|\.)sujiatun\.wordpress\.com$
(^|\.)sukebei\.nyaa\.si$
(^|\.)sulian\.me$
(^|\.)sulian\.me$
(^|\.)summify\.com$
(^|\.)summify\.com$
(^|\.)sumrando\.com$
(^|\.)sumrando\.com$
...
@@ -3927,19 +4217,23 @@
...
@@ -3927,19 +4217,23 @@
(^|\.)sunvpn\.net$
(^|\.)sunvpn\.net$
(^|\.)sunwinism\.joinbbs\.net$
(^|\.)sunwinism\.joinbbs\.net$
(^|\.)suoluo\.org$
(^|\.)suoluo\.org$
(^|\.)supchina\.com$
(^|\.)superfreevpn\.com$
(^|\.)superfreevpn\.com$
(^|\.)superokayama\.com$
(^|\.)superokayama\.com$
(^|\.)superpages\.com$
(^|\.)superpages\.com$
(^|\.)supervpn\.net$
(^|\.)supervpn\.net$
(^|\.)superzooi\.com$
(^|\.)suppig\.net$
(^|\.)suppig\.net$
(^|\.)suprememastertv\.com$
(^|\.)suprememastertv\.com$
(^|\.)surfeasy\.com$
(^|\.)surfeasy\.com$
(^|\.)surfeasy\.com\.au$
(^|\.)surfeasy\.com\.au$
(^|\.)suroot\.com$
(^|\.)suroot\.com$
(^|\.)surrenderat20\.net$
(^|\.)surrenderat20\.net$
(^|\.)sustainability\.google$
(^|\.)suyangg\.com$
(^|\.)suyangg\.com$
(^|\.)svsfx\.com$
(^|\.)svsfx\.com$
(^|\.)swagbucks\.com$
(^|\.)swagbucks\.com$
(^|\.)swissinfo\.ch$
(^|\.)swissvpn\.net$
(^|\.)swissvpn\.net$
(^|\.)switch1\.jp$
(^|\.)switch1\.jp$
(^|\.)switchvpn\.net$
(^|\.)switchvpn\.net$
...
@@ -3977,6 +4271,7 @@
...
@@ -3977,6 +4271,7 @@
(^|\.)taiwandc\.org$
(^|\.)taiwandc\.org$
(^|\.)taiwanjobs\.gov\.tw$
(^|\.)taiwanjobs\.gov\.tw$
(^|\.)taiwanjustice\.com$
(^|\.)taiwanjustice\.com$
(^|\.)taiwanjustice\.net$
(^|\.)taiwankiss\.com$
(^|\.)taiwankiss\.com$
(^|\.)taiwannation\.50webs\.com$
(^|\.)taiwannation\.50webs\.com$
(^|\.)taiwannation\.com$
(^|\.)taiwannation\.com$
...
@@ -3990,6 +4285,7 @@
...
@@ -3990,6 +4285,7 @@
(^|\.)taiwanyes\.ning\.com$
(^|\.)taiwanyes\.ning\.com$
(^|\.)talk853\.com$
(^|\.)talk853\.com$
(^|\.)talkboxapp\.com$
(^|\.)talkboxapp\.com$
(^|\.)talkcc\.com$
(^|\.)talkonly\.net$
(^|\.)talkonly\.net$
(^|\.)tamiaode\.tk$
(^|\.)tamiaode\.tk$
(^|\.)tanc\.org$
(^|\.)tanc\.org$
...
@@ -4027,10 +4323,15 @@
...
@@ -4027,10 +4323,15 @@
(^|\.)tcpspeed\.com$
(^|\.)tcpspeed\.com$
(^|\.)tcsofbc\.org$
(^|\.)tcsofbc\.org$
(^|\.)tcsovi\.org$
(^|\.)tcsovi\.org$
(^|\.)tdm\.com\.mo$
(^|\.)teachparentstech\.org$
(^|\.)teachparentstech\.org$
(^|\.)teamamericany\.com$
(^|\.)teamamericany\.com$
(^|\.)tech2\.in\.com$
(^|\.)tech2\.in\.com$
(^|\.)techviz\.net$
(^|\.)teck\.in$
(^|\.)teck\.in$
(^|\.)teco-hk\.org$
(^|\.)teco-mo\.org$
(^|\.)teddysun\.com$
(^|\.)teeniefuck\.net$
(^|\.)teeniefuck\.net$
(^|\.)teensinasia\.com$
(^|\.)teensinasia\.com$
(^|\.)telecomspace\.com$
(^|\.)telecomspace\.com$
...
@@ -4044,7 +4345,9 @@
...
@@ -4044,7 +4345,9 @@
(^|\.)tenacy\.com$
(^|\.)tenacy\.com$
(^|\.)tensorflow\.org$
(^|\.)tensorflow\.org$
(^|\.)tenzinpalmo\.com$
(^|\.)tenzinpalmo\.com$
(^|\.)terminus2049\.github\.io$
(^|\.)tew\.org$
(^|\.)tew\.org$
(^|\.)textnow\.me$
(^|\.)th\.hao123\.com$
(^|\.)th\.hao123\.com$
(^|\.)thaicn\.com$
(^|\.)thaicn\.com$
(^|\.)thb\.gov\.tw$
(^|\.)thb\.gov\.tw$
...
@@ -4067,6 +4370,7 @@
...
@@ -4067,6 +4370,7 @@
(^|\.)theinitium\.com$
(^|\.)theinitium\.com$
(^|\.)thenewslens\.com$
(^|\.)thenewslens\.com$
(^|\.)thepiratebay\.org$
(^|\.)thepiratebay\.org$
(^|\.)theporndude\.com$
(^|\.)theportalwiki\.com$
(^|\.)theportalwiki\.com$
(^|\.)thereallove\.kr$
(^|\.)thereallove\.kr$
(^|\.)therock\.net\.nz$
(^|\.)therock\.net\.nz$
...
@@ -4080,6 +4384,8 @@
...
@@ -4080,6 +4384,8 @@
(^|\.)thetrotskymovie\.com$
(^|\.)thetrotskymovie\.com$
(^|\.)thevivekspot\.com$
(^|\.)thevivekspot\.com$
(^|\.)thewgo\.org$
(^|\.)thewgo\.org$
(^|\.)theync\.com$
(^|\.)thinkgeek\.com$
(^|\.)thinkingtaiwan\.com$
(^|\.)thinkingtaiwan\.com$
(^|\.)thinkwithgoogle\.com$
(^|\.)thinkwithgoogle\.com$
(^|\.)thisav\.com$
(^|\.)thisav\.com$
...
@@ -4190,6 +4496,8 @@
...
@@ -4190,6 +4496,8 @@
(^|\.)times\.hinet\.net$
(^|\.)times\.hinet\.net$
(^|\.)timesofindia\.indiatimes\.com$
(^|\.)timesofindia\.indiatimes\.com$
(^|\.)timsah\.com$
(^|\.)timsah\.com$
(^|\.)tinc-vpn\.org$
(^|\.)tineye\.com$
(^|\.)tintuc101\.com$
(^|\.)tintuc101\.com$
(^|\.)tiny\.cc$
(^|\.)tiny\.cc$
(^|\.)tinychat\.com$
(^|\.)tinychat\.com$
...
@@ -4203,6 +4511,9 @@
...
@@ -4203,6 +4511,9 @@
(^|\.)tmdfish\.com$
(^|\.)tmdfish\.com$
(^|\.)tmi\.me$
(^|\.)tmi\.me$
(^|\.)tmpp\.org$
(^|\.)tmpp\.org$
(^|\.)tn1\.shemalez\.com$
(^|\.)tn2\.shemalez\.com$
(^|\.)tn3\.shemalez\.com$
(^|\.)tnaflix\.com$
(^|\.)tnaflix\.com$
(^|\.)tngrnow\.com$
(^|\.)tngrnow\.com$
(^|\.)tngrnow\.net$
(^|\.)tngrnow\.net$
...
@@ -4220,7 +4531,9 @@
...
@@ -4220,7 +4531,9 @@
(^|\.)toodoc\.com$
(^|\.)toodoc\.com$
(^|\.)toonel\.net$
(^|\.)toonel\.net$
(^|\.)top\.tv$
(^|\.)top\.tv$
(^|\.)top10vpn\.com$
(^|\.)top81\.ws$
(^|\.)top81\.ws$
(^|\.)topbtc\.com$
(^|\.)topic\.youthwant\.com\.tw$
(^|\.)topic\.youthwant\.com\.tw$
(^|\.)topnews\.in$
(^|\.)topnews\.in$
(^|\.)toppornsites\.com$
(^|\.)toppornsites\.com$
...
@@ -4242,6 +4555,7 @@
...
@@ -4242,6 +4555,7 @@
(^|\.)tosh\.comedycentral\.com$
(^|\.)tosh\.comedycentral\.com$
(^|\.)totalvpn\.com$
(^|\.)totalvpn\.com$
(^|\.)toutiaoabc\.com$
(^|\.)toutiaoabc\.com$
(^|\.)toutyrater\.github\.io$
(^|\.)towngain\.com$
(^|\.)towngain\.com$
(^|\.)toypark\.in$
(^|\.)toypark\.in$
(^|\.)toythieves\.com$
(^|\.)toythieves\.com$
...
@@ -4276,6 +4590,7 @@
...
@@ -4276,6 +4590,7 @@
(^|\.)tt-rss\.org$
(^|\.)tt-rss\.org$
(^|\.)tt1069\.com$
(^|\.)tt1069\.com$
(^|\.)tttan\.com$
(^|\.)tttan\.com$
(^|\.)ttvnw\.net$
(^|\.)tu8964\.com$
(^|\.)tu8964\.com$
(^|\.)tubaholic\.com$
(^|\.)tubaholic\.com$
(^|\.)tube\.com$
(^|\.)tube\.com$
...
@@ -4284,6 +4599,7 @@
...
@@ -4284,6 +4599,7 @@
(^|\.)tubecup\.com$
(^|\.)tubecup\.com$
(^|\.)tubegals\.com$
(^|\.)tubegals\.com$
(^|\.)tubeislam\.com$
(^|\.)tubeislam\.com$
(^|\.)tubepornclassic\.com$
(^|\.)tubestack\.com$
(^|\.)tubestack\.com$
(^|\.)tubewolf\.com$
(^|\.)tubewolf\.com$
(^|\.)tui\.orzdream\.com$
(^|\.)tui\.orzdream\.com$
...
@@ -4330,6 +4646,7 @@
...
@@ -4330,6 +4646,7 @@
(^|\.)tw\.bid\.yahoo\.com$
(^|\.)tw\.bid\.yahoo\.com$
(^|\.)tw\.gigacircle\.com$
(^|\.)tw\.gigacircle\.com$
(^|\.)tw\.hao123\.com$
(^|\.)tw\.hao123\.com$
(^|\.)tw\.iqiyi\.com$
(^|\.)tw\.jiepang\.com$
(^|\.)tw\.jiepang\.com$
(^|\.)tw\.knowledge\.yahoo\.com$
(^|\.)tw\.knowledge\.yahoo\.com$
(^|\.)tw\.mall\.yahoo\.com$
(^|\.)tw\.mall\.yahoo\.com$
...
@@ -4377,6 +4694,7 @@
...
@@ -4377,6 +4694,7 @@
(^|\.)twibble\.de$
(^|\.)twibble\.de$
(^|\.)twibbon\.com$
(^|\.)twibbon\.com$
(^|\.)twibs\.com$
(^|\.)twibs\.com$
(^|\.)twicountry\.org$
(^|\.)twicsy\.com$
(^|\.)twicsy\.com$
(^|\.)twiends\.com$
(^|\.)twiends\.com$
(^|\.)twifan\.com$
(^|\.)twifan\.com$
...
@@ -4398,6 +4716,8 @@
...
@@ -4398,6 +4716,8 @@
(^|\.)twit2d\.com$
(^|\.)twit2d\.com$
(^|\.)twitbrowser\.net$
(^|\.)twitbrowser\.net$
(^|\.)twitcause\.com$
(^|\.)twitcause\.com$
(^|\.)twitch\.tv$
(^|\.)twitchcdn\.net$
(^|\.)twitgether\.com$
(^|\.)twitgether\.com$
(^|\.)twitgoo\.com$
(^|\.)twitgoo\.com$
(^|\.)twitiq\.com$
(^|\.)twitiq\.com$
...
@@ -4449,6 +4769,7 @@
...
@@ -4449,6 +4769,7 @@
(^|\.)udnbkk\.com$
(^|\.)udnbkk\.com$
(^|\.)uforadio\.com\.tw$
(^|\.)uforadio\.com\.tw$
(^|\.)ufreevpn\.com$
(^|\.)ufreevpn\.com$
(^|\.)ug\.m\.wikipedia\.org$
(^|\.)ugo\.com$
(^|\.)ugo\.com$
(^|\.)uhdwallpapers\.org$
(^|\.)uhdwallpapers\.org$
(^|\.)uhrp\.org$
(^|\.)uhrp\.org$
...
@@ -4457,6 +4778,7 @@
...
@@ -4457,6 +4778,7 @@
(^|\.)uighurbiz\.net$
(^|\.)uighurbiz\.net$
(^|\.)ukcdp\.co\.uk$
(^|\.)ukcdp\.co\.uk$
(^|\.)ukliferadio\.co\.uk$
(^|\.)ukliferadio\.co\.uk$
(^|\.)uku\.im$
(^|\.)ulike\.net$
(^|\.)ulike\.net$
(^|\.)ulop\.net$
(^|\.)ulop\.net$
(^|\.)ultrareach$
(^|\.)ultrareach$
...
@@ -4477,6 +4799,7 @@
...
@@ -4477,6 +4799,7 @@
(^|\.)uni\.cc$
(^|\.)uni\.cc$
(^|\.)unification\.net$
(^|\.)unification\.net$
(^|\.)unification\.org\.tw$
(^|\.)unification\.org\.tw$
(^|\.)unirule\.cloud$
(^|\.)unitedsocialpress\.com$
(^|\.)unitedsocialpress\.com$
(^|\.)unix100\.com$
(^|\.)unix100\.com$
(^|\.)unknownspace\.org$
(^|\.)unknownspace\.org$
...
@@ -4497,6 +4820,7 @@
...
@@ -4497,6 +4820,7 @@
(^|\.)uproxy\.org$
(^|\.)uproxy\.org$
(^|\.)upwill\.org$
(^|\.)upwill\.org$
(^|\.)ur7s\.com$
(^|\.)ur7s\.com$
(^|\.)uraban\.me$
(^|\.)urbansurvival\.com$
(^|\.)urbansurvival\.com$
(^|\.)urchin\.com$
(^|\.)urchin\.com$
(^|\.)urlborg\.com$
(^|\.)urlborg\.com$
...
@@ -4519,6 +4843,7 @@
...
@@ -4519,6 +4843,7 @@
(^|\.)usus\.cc$
(^|\.)usus\.cc$
(^|\.)utopianpal\.com$
(^|\.)utopianpal\.com$
(^|\.)uu-gg\.com$
(^|\.)uu-gg\.com$
(^|\.)uukanshu\.com$
(^|\.)uvwxyz\.xyz$
(^|\.)uvwxyz\.xyz$
(^|\.)uwants\.com$
(^|\.)uwants\.com$
(^|\.)uwants\.net$
(^|\.)uwants\.net$
...
@@ -4542,6 +4867,7 @@
...
@@ -4542,6 +4867,7 @@
(^|\.)vanilla-jp\.com$
(^|\.)vanilla-jp\.com$
(^|\.)vanpeople\.com$
(^|\.)vanpeople\.com$
(^|\.)vansky\.com$
(^|\.)vansky\.com$
(^|\.)vaticannews\.va$
(^|\.)vatn\.org$
(^|\.)vatn\.org$
(^|\.)vcf-online\.org$
(^|\.)vcf-online\.org$
(^|\.)vcfbuilder\.org$
(^|\.)vcfbuilder\.org$
...
@@ -4587,6 +4913,7 @@
...
@@ -4587,6 +4913,7 @@
(^|\.)vine\.co$
(^|\.)vine\.co$
(^|\.)vinniev\.com$
(^|\.)vinniev\.com$
(^|\.)vip-enterprise\.com$
(^|\.)vip-enterprise\.com$
(^|\.)virtualrealporn\.com$
(^|\.)visibletweets\.com$
(^|\.)visibletweets\.com$
(^|\.)vital247\.org$
(^|\.)vital247\.org$
(^|\.)viu\.com$
(^|\.)viu\.com$
...
@@ -4595,10 +4922,12 @@
...
@@ -4595,10 +4922,12 @@
(^|\.)vivatube\.com$
(^|\.)vivatube\.com$
(^|\.)vivthomas\.com$
(^|\.)vivthomas\.com$
(^|\.)vizvaz\.com$
(^|\.)vizvaz\.com$
(^|\.)vjav\.com$
(^|\.)vjmedia\.com\.hk$
(^|\.)vjmedia\.com\.hk$
(^|\.)vllcs\.org$
(^|\.)vllcs\.org$
(^|\.)vlog\.xuite\.net$
(^|\.)vlog\.xuite\.net$
(^|\.)vmixcore\.com$
(^|\.)vmixcore\.com$
(^|\.)vmpsoft\.com$
(^|\.)vn\.hao123\.com$
(^|\.)vn\.hao123\.com$
(^|\.)vnet\.link$
(^|\.)vnet\.link$
(^|\.)voa-11\.akacast\.akamaistream\.net$
(^|\.)voa-11\.akacast\.akamaistream\.net$
...
@@ -4611,6 +4940,7 @@
...
@@ -4611,6 +4940,7 @@
(^|\.)voatibetanenglish\.com$
(^|\.)voatibetanenglish\.com$
(^|\.)vocativ\.com$
(^|\.)vocativ\.com$
(^|\.)vocn\.tv$
(^|\.)vocn\.tv$
(^|\.)vod-abematv\.akamaized\.net$
(^|\.)vod\.wwe\.com$
(^|\.)vod\.wwe\.com$
(^|\.)vot\.org$
(^|\.)vot\.org$
(^|\.)vovo2000\.com$
(^|\.)vovo2000\.com$
...
@@ -4630,6 +4960,7 @@
...
@@ -4630,6 +4960,7 @@
(^|\.)vpndada\.com$
(^|\.)vpndada\.com$
(^|\.)vpnfan\.com$
(^|\.)vpnfan\.com$
(^|\.)vpnfire\.com$
(^|\.)vpnfire\.com$
(^|\.)vpnfires\.biz$
(^|\.)vpnforgame\.net$
(^|\.)vpnforgame\.net$
(^|\.)vpngate\.jp$
(^|\.)vpngate\.jp$
(^|\.)vpngate\.net$
(^|\.)vpngate\.net$
...
@@ -4660,8 +4991,10 @@
...
@@ -4660,8 +4991,10 @@
(^|\.)vpser\.net$
(^|\.)vpser\.net$
(^|\.)vraiesagesse\.net$
(^|\.)vraiesagesse\.net$
(^|\.)vrmtr\.com$
(^|\.)vrmtr\.com$
(^|\.)vrsmash\.com$
(^|\.)vtunnel\.com$
(^|\.)vtunnel\.com$
(^|\.)vuku\.cc$
(^|\.)vuku\.cc$
(^|\.)vultryhw\.com$
(^|\.)w\.idaiwan\.com$
(^|\.)w\.idaiwan\.com$
(^|\.)w3schools\.com$
(^|\.)w3schools\.com$
(^|\.)waffle1999\.com$
(^|\.)waffle1999\.com$
...
@@ -4699,6 +5032,7 @@
...
@@ -4699,6 +5032,7 @@
(^|\.)wdf5\.com$
(^|\.)wdf5\.com$
(^|\.)wearehairy\.com$
(^|\.)wearehairy\.com$
(^|\.)wearn\.com$
(^|\.)wearn\.com$
(^|\.)web\.dev$
(^|\.)web2project\.net$
(^|\.)web2project\.net$
(^|\.)webbang\.net$
(^|\.)webbang\.net$
(^|\.)webevader\.org$
(^|\.)webevader\.org$
...
@@ -4716,6 +5050,7 @@
...
@@ -4716,6 +5050,7 @@
(^|\.)weekmag\.info$
(^|\.)weekmag\.info$
(^|\.)wefightcensorship\.org$
(^|\.)wefightcensorship\.org$
(^|\.)wefong\.com$
(^|\.)wefong\.com$
(^|\.)wego\.here\.com$
(^|\.)weiboleak\.com$
(^|\.)weiboleak\.com$
(^|\.)weiboscope\.jmsc\.hku\.hk$
(^|\.)weiboscope\.jmsc\.hku\.hk$
(^|\.)weihuo\.org$
(^|\.)weihuo\.org$
...
@@ -4730,6 +5065,7 @@
...
@@ -4730,6 +5065,7 @@
(^|\.)wenhui\.ch$
(^|\.)wenhui\.ch$
(^|\.)wenxuecity\.com$
(^|\.)wenxuecity\.com$
(^|\.)wenyunchao\.com$
(^|\.)wenyunchao\.com$
(^|\.)wenzhao\.ca$
(^|\.)westca\.com$
(^|\.)westca\.com$
(^|\.)westernshugdensociety\.org$
(^|\.)westernshugdensociety\.org$
(^|\.)westernwolves\.com$
(^|\.)westernwolves\.com$
...
@@ -4744,7 +5080,9 @@
...
@@ -4744,7 +5080,9 @@
(^|\.)wha\.la$
(^|\.)wha\.la$
(^|\.)whatblocked\.com$
(^|\.)whatblocked\.com$
(^|\.)whatbrowser\.org$
(^|\.)whatbrowser\.org$
(^|\.)whatsapp\.com$
(^|\.)whatsapp\.net$
(^|\.)whatsapp\.net$
(^|\.)whatsonweibo\.com$
(^|\.)wheatseeds\.org$
(^|\.)wheatseeds\.org$
(^|\.)wheelockslatin\.com$
(^|\.)wheelockslatin\.com$
(^|\.)whereiswerner\.com$
(^|\.)whereiswerner\.com$
...
@@ -4778,6 +5116,7 @@
...
@@ -4778,6 +5116,7 @@
(^|\.)wikimapia\.org$
(^|\.)wikimapia\.org$
(^|\.)wikiwiki\.jp$
(^|\.)wikiwiki\.jp$
(^|\.)wildammo\.com$
(^|\.)wildammo\.com$
(^|\.)williamhill\.com$
(^|\.)willw\.net$
(^|\.)willw\.net$
(^|\.)windowsphoneme\.com$
(^|\.)windowsphoneme\.com$
(^|\.)windscribe\.com$
(^|\.)windscribe\.com$
...
@@ -4813,6 +5152,7 @@
...
@@ -4813,6 +5152,7 @@
(^|\.)wordpress\.com$
(^|\.)wordpress\.com$
(^|\.)workatruna\.com$
(^|\.)workatruna\.com$
(^|\.)workerdemo\.org\.hk$
(^|\.)workerdemo\.org\.hk$
(^|\.)workerempowerment\.org$
(^|\.)workersthebig\.net$
(^|\.)workersthebig\.net$
(^|\.)worldcat\.org$
(^|\.)worldcat\.org$
(^|\.)worldjournal\.com$
(^|\.)worldjournal\.com$
...
@@ -4910,6 +5250,7 @@
...
@@ -4910,6 +5250,7 @@
(^|\.)xanga\.com$
(^|\.)xanga\.com$
(^|\.)xbabe\.com$
(^|\.)xbabe\.com$
(^|\.)xbookcn\.com$
(^|\.)xbookcn\.com$
(^|\.)xbtce\.com$
(^|\.)xcafe\.in$
(^|\.)xcafe\.in$
(^|\.)xcity\.jp$
(^|\.)xcity\.jp$
(^|\.)xcritic\.com$
(^|\.)xcritic\.com$
...
@@ -4918,6 +5259,7 @@
...
@@ -4918,6 +5259,7 @@
(^|\.)xfm\.pp\.ru$
(^|\.)xfm\.pp\.ru$
(^|\.)xgmyd\.com$
(^|\.)xgmyd\.com$
(^|\.)xhamster\.com$
(^|\.)xhamster\.com$
(^|\.)xianba\.net$
(^|\.)xianchawang\.net$
(^|\.)xianchawang\.net$
(^|\.)xianjian\.tw$
(^|\.)xianjian\.tw$
(^|\.)xianqiao\.net$
(^|\.)xianqiao\.net$
...
@@ -4929,6 +5271,7 @@
...
@@ -4929,6 +5271,7 @@
(^|\.)xiaoma\.org$
(^|\.)xiaoma\.org$
(^|\.)xiezhua\.com$
(^|\.)xiezhua\.com$
(^|\.)xihua\.es$
(^|\.)xihua\.es$
(^|\.)xijie\.wordpress\.com$
(^|\.)xing\.com$
(^|\.)xing\.com$
(^|\.)xinhuanet\.org$
(^|\.)xinhuanet\.org$
(^|\.)xinmiao\.com\.hk$
(^|\.)xinmiao\.com\.hk$
...
@@ -4951,6 +5294,7 @@
...
@@ -4951,6 +5294,7 @@
(^|\.)xn--czq75pvv1aj5c\.org$
(^|\.)xn--czq75pvv1aj5c\.org$
(^|\.)xn--i2ru8q2qg\.com$
(^|\.)xn--i2ru8q2qg\.com$
(^|\.)xn--ngstr-lra8j\.com$
(^|\.)xn--ngstr-lra8j\.com$
(^|\.)xn--oiq\.cc$
(^|\.)xn--p8j9a0d9c9a\.xn--q9jyb4c$
(^|\.)xn--p8j9a0d9c9a\.xn--q9jyb4c$
(^|\.)xnxx\.com$
(^|\.)xnxx\.com$
(^|\.)xpdo\.net$
(^|\.)xpdo\.net$
...
@@ -5012,11 +5356,15 @@
...
@@ -5012,11 +5356,15 @@
(^|\.)yinlei\.org$
(^|\.)yinlei\.org$
(^|\.)yipub\.com$
(^|\.)yipub\.com$
(^|\.)yizhihongxing\.com$
(^|\.)yizhihongxing\.com$
(^|\.)yobit\.net$
(^|\.)yobt\.com$
(^|\.)yobt\.com$
(^|\.)yobt\.tv$
(^|\.)yobt\.tv$
(^|\.)yogichen\.org$
(^|\.)yogichen\.org$
(^|\.)yolasite\.com$
(^|\.)yomiuri\.co\.jp$
(^|\.)yong\.hu$
(^|\.)yong\.hu$
(^|\.)yorkbbs\.ca$
(^|\.)yorkbbs\.ca$
(^|\.)you-get\.org$
(^|\.)youdontcare\.com$
(^|\.)youdontcare\.com$
(^|\.)youjizz\.com$
(^|\.)youjizz\.com$
(^|\.)youmaker\.com$
(^|\.)youmaker\.com$
...
@@ -5041,6 +5389,7 @@
...
@@ -5041,6 +5389,7 @@
(^|\.)youtubeeducation\.com$
(^|\.)youtubeeducation\.com$
(^|\.)youtubegaming\.com$
(^|\.)youtubegaming\.com$
(^|\.)youversion\.com$
(^|\.)youversion\.com$
(^|\.)youwin\.com$
(^|\.)youxu\.info$
(^|\.)youxu\.info$
(^|\.)yt\.be$
(^|\.)yt\.be$
(^|\.)ytht\.net$
(^|\.)ytht\.net$
...
@@ -5060,10 +5409,12 @@
...
@@ -5060,10 +5409,12 @@
(^|\.)zacebook\.com$
(^|\.)zacebook\.com$
(^|\.)zalmos\.com$
(^|\.)zalmos\.com$
(^|\.)zannel\.com$
(^|\.)zannel\.com$
(^|\.)zaobao\.com$
(^|\.)zaobao\.com\.sg$
(^|\.)zaobao\.com\.sg$
(^|\.)zaozon\.com$
(^|\.)zaozon\.com$
(^|\.)zapto\.org$
(^|\.)zapto\.org$
(^|\.)zattoo\.com$
(^|\.)zattoo\.com$
(^|\.)zb\.com$
(^|\.)zdnet\.com\.tw$
(^|\.)zdnet\.com\.tw$
(^|\.)zello\.com$
(^|\.)zello\.com$
(^|\.)zengjinyan\.org$
(^|\.)zengjinyan\.org$
...
@@ -5075,9 +5426,11 @@
...
@@ -5075,9 +5426,11 @@
(^|\.)zgsddh\.com$
(^|\.)zgsddh\.com$
(^|\.)zgzcjj\.net$
(^|\.)zgzcjj\.net$
(^|\.)zh-yue\.wikipedia\.org$
(^|\.)zh-yue\.wikipedia\.org$
(^|\.)zh\.bitterwinter\.org$
(^|\.)zh\.ecdm\.wikia\.com$
(^|\.)zh\.ecdm\.wikia\.com$
(^|\.)zh\.m\.wikipedia\.org$
(^|\.)zh\.m\.wikipedia\.org$
(^|\.)zh\.pokerstrategy\.com$
(^|\.)zh\.pokerstrategy\.com$
(^|\.)zh\.pttpedia\.wikia\.com$
(^|\.)zh\.uncyclopedia\.wikia\.com$
(^|\.)zh\.uncyclopedia\.wikia\.com$
(^|\.)zh\.wikinews\.org$
(^|\.)zh\.wikinews\.org$
(^|\.)zh\.wikipedia\.org$
(^|\.)zh\.wikipedia\.org$
...
@@ -5135,4 +5488,5 @@
...
@@ -5135,4 +5488,5 @@
(^|\.)zyns\.com$
(^|\.)zyns\.com$
(^|\.)zyzc9\.com$
(^|\.)zyzc9\.com$
(^|\.)zzcartoon\.com$
(^|\.)zzcartoon\.com$
(^|\.)zzcloud\.me$
(^|\.)zzux\.com$
(^|\.)zzux\.com$
core/src/main/java/com/github/shadowsocks/acl/Acl.kt
View file @
be6cf63d
...
@@ -32,6 +32,7 @@ import java.io.File
...
@@ -32,6 +32,7 @@ import java.io.File
import
java.io.IOException
import
java.io.IOException
import
java.io.Reader
import
java.io.Reader
import
java.net.URL
import
java.net.URL
import
java.net.URLConnection
class
Acl
{
class
Acl
{
companion
object
{
companion
object
{
...
@@ -151,11 +152,11 @@ class Acl {
...
@@ -151,11 +152,11 @@ class Acl {
fromReader
(
getFile
(
id
).
bufferedReader
())
fromReader
(
getFile
(
id
).
bufferedReader
())
}
catch
(
_
:
IOException
)
{
this
}
}
catch
(
_
:
IOException
)
{
this
}
fun
flatten
(
depth
:
Int
):
Acl
{
suspend
fun
flatten
(
depth
:
Int
,
connect
:
suspend
(
URL
)
->
URLConnection
):
Acl
{
if
(
depth
>
0
)
for
(
url
in
urls
.
asIterable
())
{
if
(
depth
>
0
)
for
(
url
in
urls
.
asIterable
())
{
val
child
=
Acl
()
val
child
=
Acl
()
try
{
try
{
child
.
fromReader
(
url
.
openStream
().
bufferedReader
(),
bypass
).
flatten
(
depth
-
1
)
child
.
fromReader
(
connect
(
url
).
getInputStream
().
bufferedReader
(),
bypass
).
flatten
(
depth
-
1
,
connect
)
}
catch
(
e
:
IOException
)
{
}
catch
(
e
:
IOException
)
{
e
.
printStackTrace
()
e
.
printStackTrace
()
continue
continue
...
...
core/src/main/java/com/github/shadowsocks/aidl/ShadowsocksConnection.kt
View file @
be6cf63d
...
@@ -28,6 +28,7 @@ import android.os.DeadObjectException
...
@@ -28,6 +28,7 @@ import android.os.DeadObjectException
import
android.os.Handler
import
android.os.Handler
import
android.os.IBinder
import
android.os.IBinder
import
android.os.RemoteException
import
android.os.RemoteException
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.bg.ProxyService
import
com.github.shadowsocks.bg.ProxyService
import
com.github.shadowsocks.bg.TransproxyService
import
com.github.shadowsocks.bg.TransproxyService
import
com.github.shadowsocks.bg.VpnService
import
com.github.shadowsocks.bg.VpnService
...
@@ -51,7 +52,7 @@ class ShadowsocksConnection(private val handler: Handler = Handler(),
...
@@ -51,7 +52,7 @@ class ShadowsocksConnection(private val handler: Handler = Handler(),
}
}
interface
Callback
{
interface
Callback
{
fun
stateChanged
(
state
:
Int
,
profileName
:
String
?,
msg
:
String
?)
fun
stateChanged
(
state
:
BaseService
.
State
,
profileName
:
String
?,
msg
:
String
?)
fun
trafficUpdated
(
profileId
:
Long
,
stats
:
TrafficStats
)
{
}
fun
trafficUpdated
(
profileId
:
Long
,
stats
:
TrafficStats
)
{
}
fun
trafficPersisted
(
profileId
:
Long
)
{
}
fun
trafficPersisted
(
profileId
:
Long
)
{
}
...
@@ -68,13 +69,16 @@ class ShadowsocksConnection(private val handler: Handler = Handler(),
...
@@ -68,13 +69,16 @@ class ShadowsocksConnection(private val handler: Handler = Handler(),
private
var
callback
:
Callback
?
=
null
private
var
callback
:
Callback
?
=
null
private
val
serviceCallback
=
object
:
IShadowsocksServiceCallback
.
Stub
()
{
private
val
serviceCallback
=
object
:
IShadowsocksServiceCallback
.
Stub
()
{
override
fun
stateChanged
(
state
:
Int
,
profileName
:
String
?,
msg
:
String
?)
{
override
fun
stateChanged
(
state
:
Int
,
profileName
:
String
?,
msg
:
String
?)
{
handler
.
post
{
callback
!!
.
stateChanged
(
state
,
profileName
,
msg
)
}
val
callback
=
callback
?:
return
handler
.
post
{
callback
.
stateChanged
(
BaseService
.
State
.
values
()[
state
],
profileName
,
msg
)
}
}
}
override
fun
trafficUpdated
(
profileId
:
Long
,
stats
:
TrafficStats
)
{
override
fun
trafficUpdated
(
profileId
:
Long
,
stats
:
TrafficStats
)
{
handler
.
post
{
callback
!!
.
trafficUpdated
(
profileId
,
stats
)
}
val
callback
=
callback
?:
return
handler
.
post
{
callback
.
trafficUpdated
(
profileId
,
stats
)
}
}
}
override
fun
trafficPersisted
(
profileId
:
Long
)
{
override
fun
trafficPersisted
(
profileId
:
Long
)
{
handler
.
post
{
callback
!!
.
trafficPersisted
(
profileId
)
}
val
callback
=
callback
?:
return
handler
.
post
{
callback
.
trafficPersisted
(
profileId
)
}
}
}
}
}
private
var
binder
:
IBinder
?
=
null
private
var
binder
:
IBinder
?
=
null
...
@@ -105,14 +109,14 @@ class ShadowsocksConnection(private val handler: Handler = Handler(),
...
@@ -105,14 +109,14 @@ class ShadowsocksConnection(private val handler: Handler = Handler(),
override
fun
onServiceDisconnected
(
name
:
ComponentName
?)
{
override
fun
onServiceDisconnected
(
name
:
ComponentName
?)
{
unregisterCallback
()
unregisterCallback
()
callback
!!
.
onServiceDisconnected
()
callback
?
.
onServiceDisconnected
()
service
=
null
service
=
null
binder
=
null
binder
=
null
}
}
override
fun
binderDied
()
{
override
fun
binderDied
()
{
service
=
null
service
=
null
handler
.
post
(
callback
!!::
onBinderDied
)
callback
?.
also
{
handler
.
post
(
it
::
onBinderDied
)
}
}
}
private
fun
unregisterCallback
()
{
private
fun
unregisterCallback
()
{
...
...
core/src/main/java/com/github/shadowsocks/bg/BaseService.kt
View file @
be6cf63d
...
@@ -39,9 +39,11 @@ import com.github.shadowsocks.plugin.PluginManager
...
@@ -39,9 +39,11 @@ import com.github.shadowsocks.plugin.PluginManager
import
com.github.shadowsocks.utils.Action
import
com.github.shadowsocks.utils.Action
import
com.github.shadowsocks.utils.broadcastReceiver
import
com.github.shadowsocks.utils.broadcastReceiver
import
com.github.shadowsocks.utils.printLog
import
com.github.shadowsocks.utils.printLog
import
com.github.shadowsocks.utils.readableMessage
import
com.google.firebase.analytics.FirebaseAnalytics
import
com.google.firebase.analytics.FirebaseAnalytics
import
kotlinx.coroutines.*
import
kotlinx.coroutines.*
import
java.io.File
import
java.io.File
import
java.net.BindException
import
java.net.InetAddress
import
java.net.InetAddress
import
java.net.URL
import
java.net.URL
import
java.net.UnknownHostException
import
java.net.UnknownHostException
...
@@ -51,20 +53,22 @@ import java.util.*
...
@@ -51,20 +53,22 @@ import java.util.*
* This object uses WeakMap to simulate the effects of multi-inheritance.
* This object uses WeakMap to simulate the effects of multi-inheritance.
*/
*/
object
BaseService
{
object
BaseService
{
enum
class
State
(
val
canStop
:
Boolean
=
false
)
{
/**
/**
* IDLE
state is only used by UI and will never be returned by BaseService.
* Idle
state is only used by UI and will never be returned by BaseService.
*/
*/
const
val
IDLE
=
0
Idle
,
const
val
CONNECTING
=
1
Connecting
(
true
),
const
val
CONNECTED
=
2
Connected
(
true
),
const
val
STOPPING
=
3
Stopping
,
const
val
STOPPED
=
4
Stopped
,
}
const
val
CONFIG_FILE
=
"shadowsocks.conf"
const
val
CONFIG_FILE
=
"shadowsocks.conf"
const
val
CONFIG_FILE_UDP
=
"shadowsocks-udp.conf"
const
val
CONFIG_FILE_UDP
=
"shadowsocks-udp.conf"
class
Data
internal
constructor
(
private
val
service
:
Interface
)
{
class
Data
internal
constructor
(
private
val
service
:
Interface
)
{
var
state
=
S
TOPPED
var
state
=
S
tate
.
Stopped
var
processes
:
GuardedProcessPool
?
=
null
var
processes
:
GuardedProcessPool
?
=
null
var
proxy
:
ProxyInstance
?
=
null
var
proxy
:
ProxyInstance
?
=
null
var
udpFallback
:
ProxyInstance
?
=
null
var
udpFallback
:
ProxyInstance
?
=
null
...
@@ -81,7 +85,7 @@ object BaseService {
...
@@ -81,7 +85,7 @@ object BaseService {
val
binder
=
Binder
(
this
)
val
binder
=
Binder
(
this
)
var
connectingJob
:
Job
?
=
null
var
connectingJob
:
Job
?
=
null
fun
changeState
(
s
:
Int
,
msg
:
String
?
=
null
)
{
fun
changeState
(
s
:
State
,
msg
:
String
?
=
null
)
{
if
(
state
==
s
&&
msg
==
null
)
return
if
(
state
==
s
&&
msg
==
null
)
return
binder
.
stateChanged
(
s
,
msg
)
binder
.
stateChanged
(
s
,
msg
)
state
=
s
state
=
s
...
@@ -102,7 +106,7 @@ object BaseService {
...
@@ -102,7 +106,7 @@ object BaseService {
private
val
bandwidthListeners
=
mutableMapOf
<
IBinder
,
Long
>()
// the binder is the real identifier
private
val
bandwidthListeners
=
mutableMapOf
<
IBinder
,
Long
>()
// the binder is the real identifier
private
val
handler
=
Handler
()
private
val
handler
=
Handler
()
override
fun
getState
():
Int
=
data
!!
.
state
override
fun
getState
():
Int
=
data
!!
.
state
.
ordinal
override
fun
getProfileName
():
String
=
data
!!
.
proxy
?.
profile
?.
name
?:
"Idle"
override
fun
getProfileName
():
String
=
data
!!
.
proxy
?.
profile
?.
name
?:
"Idle"
override
fun
registerCallback
(
cb
:
IShadowsocksServiceCallback
)
{
override
fun
registerCallback
(
cb
:
IShadowsocksServiceCallback
)
{
...
@@ -124,12 +128,12 @@ object BaseService {
...
@@ -124,12 +128,12 @@ object BaseService {
handler
.
postDelayed
(
this
::
onTimeout
,
bandwidthListeners
.
values
.
min
()
?:
return
)
handler
.
postDelayed
(
this
::
onTimeout
,
bandwidthListeners
.
values
.
min
()
?:
return
)
}
}
private
fun
onTimeout
()
{
private
fun
onTimeout
()
{
val
proxies
=
listOfNotNull
(
data
!!
.
proxy
,
data
!!
.
udpFallback
)
val
proxies
=
listOfNotNull
(
data
?.
proxy
,
data
?
.
udpFallback
)
val
stats
=
proxies
val
stats
=
proxies
.
map
{
Pair
(
it
.
profile
.
id
,
it
.
trafficMonitor
?.
requestUpdate
())
}
.
map
{
Pair
(
it
.
profile
.
id
,
it
.
trafficMonitor
?.
requestUpdate
())
}
.
filter
{
it
.
second
!=
null
}
.
filter
{
it
.
second
!=
null
}
.
map
{
Triple
(
it
.
first
,
it
.
second
!!
.
first
,
it
.
second
!!
.
second
)
}
.
map
{
Triple
(
it
.
first
,
it
.
second
!!
.
first
,
it
.
second
!!
.
second
)
}
if
(
stats
.
any
{
it
.
third
}
&&
state
==
CONNECTED
&&
bandwidthListeners
.
isNotEmpty
())
{
if
(
stats
.
any
{
it
.
third
}
&&
data
!!
.
state
==
State
.
Connected
&&
bandwidthListeners
.
isNotEmpty
())
{
val
sum
=
stats
.
fold
(
TrafficStats
())
{
a
,
b
->
a
+
b
.
second
}
val
sum
=
stats
.
fold
(
TrafficStats
())
{
a
,
b
->
a
+
b
.
second
}
broadcast
{
item
->
broadcast
{
item
->
if
(
bandwidthListeners
.
contains
(
item
.
asBinder
()))
{
if
(
bandwidthListeners
.
contains
(
item
.
asBinder
()))
{
...
@@ -145,7 +149,7 @@ object BaseService {
...
@@ -145,7 +149,7 @@ object BaseService {
val
wasEmpty
=
bandwidthListeners
.
isEmpty
()
val
wasEmpty
=
bandwidthListeners
.
isEmpty
()
if
(
bandwidthListeners
.
put
(
cb
.
asBinder
(),
timeout
)
==
null
)
{
if
(
bandwidthListeners
.
put
(
cb
.
asBinder
(),
timeout
)
==
null
)
{
if
(
wasEmpty
)
registerTimeout
()
if
(
wasEmpty
)
registerTimeout
()
if
(
state
!=
CONNECTED
)
return
if
(
data
!!
.
state
!=
State
.
Connected
)
return
var
sum
=
TrafficStats
()
var
sum
=
TrafficStats
()
val
proxy
=
data
!!
.
proxy
?:
return
val
proxy
=
data
!!
.
proxy
?:
return
proxy
.
trafficMonitor
?.
out
.
also
{
stats
->
proxy
.
trafficMonitor
?.
out
.
also
{
stats
->
...
@@ -177,9 +181,9 @@ object BaseService {
...
@@ -177,9 +181,9 @@ object BaseService {
callbacks
.
unregister
(
cb
)
callbacks
.
unregister
(
cb
)
}
}
fun
stateChanged
(
s
:
Int
,
msg
:
String
?)
{
fun
stateChanged
(
s
:
State
,
msg
:
String
?)
{
val
profileName
=
profileName
val
profileName
=
profileName
broadcast
{
it
.
stateChanged
(
s
,
profileName
,
msg
)
}
broadcast
{
it
.
stateChanged
(
s
.
ordinal
,
profileName
,
msg
)
}
}
}
fun
trafficPersisted
(
ids
:
List
<
Long
>)
{
fun
trafficPersisted
(
ids
:
List
<
Long
>)
{
...
@@ -211,9 +215,9 @@ object BaseService {
...
@@ -211,9 +215,9 @@ object BaseService {
return
return
}
}
val
s
=
data
.
state
val
s
=
data
.
state
when
(
s
)
{
when
{
STOPPED
->
startRunner
()
s
==
State
.
Stopped
->
startRunner
()
CONNECTED
->
stopRunner
(
true
)
s
.
canStop
->
stopRunner
(
true
)
else
->
Crashlytics
.
log
(
Log
.
WARN
,
tag
,
"Illegal state when invoking use: $s"
)
else
->
Crashlytics
.
log
(
Log
.
WARN
,
tag
,
"Illegal state when invoking use: $s"
)
}
}
}
}
...
@@ -249,11 +253,12 @@ object BaseService {
...
@@ -249,11 +253,12 @@ object BaseService {
}
}
fun
stopRunner
(
restart
:
Boolean
=
false
,
msg
:
String
?
=
null
)
{
fun
stopRunner
(
restart
:
Boolean
=
false
,
msg
:
String
?
=
null
)
{
if
(
data
.
state
==
S
TOPPING
)
return
if
(
data
.
state
==
S
tate
.
Stopping
)
return
// channge the state
// channge the state
data
.
changeState
(
S
TOPPING
)
data
.
changeState
(
S
tate
.
Stopping
)
GlobalScope
.
launch
(
Dispatchers
.
Main
,
CoroutineStart
.
UNDISPATCHED
)
{
GlobalScope
.
launch
(
Dispatchers
.
Main
,
CoroutineStart
.
UNDISPATCHED
)
{
Core
.
analytics
.
logEvent
(
"stop"
,
bundleOf
(
Pair
(
FirebaseAnalytics
.
Param
.
METHOD
,
tag
)))
Core
.
analytics
.
logEvent
(
"stop"
,
bundleOf
(
Pair
(
FirebaseAnalytics
.
Param
.
METHOD
,
tag
)))
data
.
connectingJob
?.
cancelAndJoin
()
// ensure stop connecting first
this
@Interface
as
Service
this
@Interface
as
Service
// we use a coroutineScope here to allow clean-up in parallel
// we use a coroutineScope here to allow clean-up in parallel
coroutineScope
{
coroutineScope
{
...
@@ -278,7 +283,7 @@ object BaseService {
...
@@ -278,7 +283,7 @@ object BaseService {
}
}
// change the state
// change the state
data
.
changeState
(
S
TOPPED
,
msg
)
data
.
changeState
(
S
tate
.
Stopped
,
msg
)
// stop the service if nothing has bound to it
// stop the service if nothing has bound to it
if
(
restart
)
startRunner
()
else
stopSelf
()
if
(
restart
)
startRunner
()
else
stopSelf
()
...
@@ -291,7 +296,7 @@ object BaseService {
...
@@ -291,7 +296,7 @@ object BaseService {
fun
onStartCommand
(
intent
:
Intent
?,
flags
:
Int
,
startId
:
Int
):
Int
{
fun
onStartCommand
(
intent
:
Intent
?,
flags
:
Int
,
startId
:
Int
):
Int
{
val
data
=
data
val
data
=
data
if
(
data
.
state
!=
S
TOPPED
)
return
Service
.
START_NOT_STICKY
if
(
data
.
state
!=
S
tate
.
Stopped
)
return
Service
.
START_NOT_STICKY
val
profilePair
=
Core
.
currentProfile
val
profilePair
=
Core
.
currentProfile
this
as
Context
this
as
Context
if
(
profilePair
==
null
)
{
if
(
profilePair
==
null
)
{
...
@@ -318,7 +323,7 @@ object BaseService {
...
@@ -318,7 +323,7 @@ object BaseService {
data
.
notification
=
createNotification
(
profile
.
formattedName
)
data
.
notification
=
createNotification
(
profile
.
formattedName
)
Core
.
analytics
.
logEvent
(
"start"
,
bundleOf
(
Pair
(
FirebaseAnalytics
.
Param
.
METHOD
,
tag
)))
Core
.
analytics
.
logEvent
(
"start"
,
bundleOf
(
Pair
(
FirebaseAnalytics
.
Param
.
METHOD
,
tag
)))
data
.
changeState
(
CONNECTING
)
data
.
changeState
(
State
.
Connecting
)
data
.
connectingJob
=
GlobalScope
.
launch
(
Dispatchers
.
Main
)
{
data
.
connectingJob
=
GlobalScope
.
launch
(
Dispatchers
.
Main
)
{
try
{
try
{
Executable
.
killAll
()
// clean up old processes
Executable
.
killAll
()
// clean up old processes
...
@@ -328,8 +333,7 @@ object BaseService {
...
@@ -328,8 +333,7 @@ object BaseService {
data
.
processes
=
GuardedProcessPool
{
data
.
processes
=
GuardedProcessPool
{
printLog
(
it
)
printLog
(
it
)
data
.
connectingJob
?.
cancelAndJoin
()
stopRunner
(
false
,
it
.
readableMessage
)
stopRunner
(
false
,
it
.
localizedMessage
)
}
}
startProcesses
()
startProcesses
()
...
@@ -337,16 +341,18 @@ object BaseService {
...
@@ -337,16 +341,18 @@ object BaseService {
data
.
udpFallback
?.
scheduleUpdate
()
data
.
udpFallback
?.
scheduleUpdate
()
RemoteConfig
.
fetch
()
RemoteConfig
.
fetch
()
data
.
changeState
(
CONNECTED
)
data
.
changeState
(
State
.
Connected
)
}
catch
(
_
:
CancellationException
)
{
}
catch
(
_
:
CancellationException
)
{
// if the job was cancelled, it is canceller's responsibility to call stopRunner
// if the job was cancelled, it is canceller's responsibility to call stopRunner
}
catch
(
_
:
UnknownHostException
)
{
}
catch
(
_
:
UnknownHostException
)
{
stopRunner
(
false
,
getString
(
R
.
string
.
invalid_server
))
stopRunner
(
false
,
getString
(
R
.
string
.
invalid_server
))
}
catch
(
exc
:
Throwable
)
{
}
catch
(
exc
:
Throwable
)
{
if
(
exc
!
is
PluginManager
.
PluginNotFoundException
&&
exc
!
is
VpnService
.
NullConnectionException
)
{
if
(
exc
!
is
PluginManager
.
PluginNotFoundException
&&
exc
!
is
BindException
&&
exc
!
is
VpnService
.
NullConnectionException
)
{
printLog
(
exc
)
printLog
(
exc
)
}
}
stopRunner
(
false
,
"${getString(R.string.service_failed)}: ${exc.
localized
Message}"
)
stopRunner
(
false
,
"${getString(R.string.service_failed)}: ${exc.
readable
Message}"
)
}
finally
{
}
finally
{
data
.
connectingJob
=
null
data
.
connectingJob
=
null
}
}
...
...
core/src/main/java/com/github/shadowsocks/bg/Executable.kt
View file @
be6cf63d
...
@@ -26,7 +26,6 @@ import android.system.OsConstants
...
@@ -26,7 +26,6 @@ import android.system.OsConstants
import
android.text.TextUtils
import
android.text.TextUtils
import
android.util.Log
import
android.util.Log
import
com.crashlytics.android.Crashlytics
import
com.crashlytics.android.Crashlytics
import
com.github.shadowsocks.Core.app
import
java.io.File
import
java.io.File
import
java.io.FileNotFoundException
import
java.io.FileNotFoundException
...
@@ -40,11 +39,11 @@ object Executable {
...
@@ -40,11 +39,11 @@ object Executable {
fun
killAll
()
{
fun
killAll
()
{
for
(
process
in
File
(
"/proc"
).
listFiles
{
_
,
name
->
TextUtils
.
isDigitsOnly
(
name
)
})
{
for
(
process
in
File
(
"/proc"
).
listFiles
{
_
,
name
->
TextUtils
.
isDigitsOnly
(
name
)
})
{
val
exe
=
File
(
try
{
val
exe
=
File
(
try
{
File
(
process
,
"cmdline"
).
readText
()
File
(
process
,
"cmdline"
).
inputStream
().
bufferedReader
().
readText
()
}
catch
(
ignore
:
FileNotFoundException
)
{
}
catch
(
_
:
FileNotFoundException
)
{
continue
continue
}.
split
(
Character
.
MIN_VALUE
,
limit
=
2
).
first
())
}.
split
(
Character
.
MIN_VALUE
,
limit
=
2
).
first
())
if
(
exe
.
parent
==
app
.
applicationInfo
.
nativeLibraryDir
&&
EXECUTABLES
.
contains
(
exe
.
name
))
try
{
if
(
EXECUTABLES
.
contains
(
exe
.
name
))
try
{
Os
.
kill
(
process
.
name
.
toInt
(),
OsConstants
.
SIGKILL
)
Os
.
kill
(
process
.
name
.
toInt
(),
OsConstants
.
SIGKILL
)
}
catch
(
e
:
ErrnoException
)
{
}
catch
(
e
:
ErrnoException
)
{
if
(
e
.
errno
!=
OsConstants
.
ESRCH
)
{
if
(
e
.
errno
!=
OsConstants
.
ESRCH
)
{
...
...
core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
View file @
be6cf63d
...
@@ -61,7 +61,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
...
@@ -61,7 +61,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
conn
.
doOutput
=
true
conn
.
doOutput
=
true
val
proxies
=
try
{
val
proxies
=
try
{
withTimeoutOrNull
(
3
0_000
)
{
withTimeoutOrNull
(
1
0_000
)
{
withContext
(
Dispatchers
.
IO
)
{
withContext
(
Dispatchers
.
IO
)
{
conn
.
outputStream
.
bufferedWriter
().
use
{
conn
.
outputStream
.
bufferedWriter
().
use
{
it
.
write
(
"sig="
+
Base64
.
encodeToString
(
mdg
.
digest
(),
Base64
.
DEFAULT
))
it
.
write
(
"sig="
+
Base64
.
encodeToString
(
mdg
.
digest
(),
Base64
.
DEFAULT
))
...
@@ -80,7 +80,9 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
...
@@ -80,7 +80,9 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
profile
.
method
=
proxy
[
3
].
trim
()
profile
.
method
=
proxy
[
3
].
trim
()
}
}
if
(
route
==
Acl
.
CUSTOM_RULES
)
Acl
.
save
(
Acl
.
CUSTOM_RULES
,
Acl
.
customRules
.
flatten
(
10
))
if
(
route
==
Acl
.
CUSTOM_RULES
)
withContext
(
Dispatchers
.
IO
)
{
Acl
.
save
(
Acl
.
CUSTOM_RULES
,
Acl
.
customRules
.
flatten
(
10
,
service
::
openConnection
))
}
// it's hard to resolve DNS on a specific interface so we'll do it here
// it's hard to resolve DNS on a specific interface so we'll do it here
if
(
profile
.
host
.
parseNumericAddress
()
==
null
)
profile
.
host
=
withTimeoutOrNull
(
10_000
)
{
if
(
profile
.
host
.
parseNumericAddress
()
==
null
)
profile
.
host
=
withTimeoutOrNull
(
10_000
)
{
...
...
core/src/main/java/com/github/shadowsocks/bg/ServiceNotification.kt
View file @
be6cf63d
...
@@ -94,7 +94,7 @@ class ServiceNotification(private val service: BaseService.Interface, profileNam
...
@@ -94,7 +94,7 @@ class ServiceNotification(private val service: BaseService.Interface, profileNam
}
}
private
fun
update
(
action
:
String
?,
forceShow
:
Boolean
=
false
)
{
private
fun
update
(
action
:
String
?,
forceShow
:
Boolean
=
false
)
{
if
(
forceShow
||
service
.
data
.
state
==
BaseService
.
CONNECTED
)
when
(
action
)
{
if
(
forceShow
||
service
.
data
.
state
==
BaseService
.
State
.
Connected
)
when
(
action
)
{
Intent
.
ACTION_SCREEN_OFF
->
{
Intent
.
ACTION_SCREEN_OFF
->
{
setVisible
(
false
,
forceShow
)
setVisible
(
false
,
forceShow
)
unregisterCallback
()
// unregister callback to save battery
unregisterCallback
()
// unregister callback to save battery
...
...
core/src/main/java/com/github/shadowsocks/database/Profile.kt
View file @
be6cf63d
...
@@ -21,6 +21,7 @@
...
@@ -21,6 +21,7 @@
package
com.github.shadowsocks.database
package
com.github.shadowsocks.database
import
android.net.Uri
import
android.net.Uri
import
android.os.Parcelable
import
android.util.Base64
import
android.util.Base64
import
android.util.Log
import
android.util.Log
import
android.util.LongSparseArray
import
android.util.LongSparseArray
...
@@ -32,6 +33,7 @@ import com.github.shadowsocks.preference.DataStore
...
@@ -32,6 +33,7 @@ import com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.asIterable
import
com.github.shadowsocks.utils.asIterable
import
com.github.shadowsocks.utils.parsePort
import
com.github.shadowsocks.utils.parsePort
import
kotlinx.android.parcel.Parcelize
import
org.json.JSONArray
import
org.json.JSONArray
import
org.json.JSONObject
import
org.json.JSONObject
import
org.json.JSONTokener
import
org.json.JSONTokener
...
@@ -41,7 +43,31 @@ import java.net.URISyntaxException
...
@@ -41,7 +43,31 @@ import java.net.URISyntaxException
import
java.util.*
import
java.util.*
@Entity
@Entity
class
Profile
:
Serializable
{
@Parcelize
data class
Profile
(
@PrimaryKey
(
autoGenerate
=
true
)
var
id
:
Long
=
0
,
var
name
:
String
?
=
""
,
var
host
:
String
=
"198.199.101.152"
,
var
remotePort
:
Int
=
8388
,
var
password
:
String
=
"u1rRWTssNv0p"
,
var
method
:
String
=
"aes-256-cfb"
,
var
route
:
String
=
"all"
,
var
remoteDns
:
String
=
"8.8.8.8"
,
var
proxyApps
:
Boolean
=
false
,
var
bypass
:
Boolean
=
false
,
var
udpdns
:
Boolean
=
false
,
var
ipv6
:
Boolean
=
true
,
var
individual
:
String
=
""
,
var
tx
:
Long
=
0
,
var
rx
:
Long
=
0
,
var
userOrder
:
Long
=
0
,
var
plugin
:
String
?
=
null
,
var
udpFallback
:
Long
?
=
null
,
@Ignore
// not persisted in db, only used by direct boot
var
dirty
:
Boolean
=
false
)
:
Parcelable
,
Serializable
{
companion
object
{
companion
object
{
private
const
val
TAG
=
"ShadowParser"
private
const
val
TAG
=
"ShadowParser"
private
const
val
serialVersionUID
=
0L
private
const
val
serialVersionUID
=
0L
...
@@ -200,29 +226,6 @@ class Profile : Serializable {
...
@@ -200,29 +226,6 @@ class Profile : Serializable {
fun
deleteAll
():
Int
fun
deleteAll
():
Int
}
}
@PrimaryKey
(
autoGenerate
=
true
)
var
id
:
Long
=
0
var
name
:
String
?
=
""
var
host
:
String
=
"198.199.101.152"
var
remotePort
:
Int
=
8388
var
password
:
String
=
"u1rRWTssNv0p"
var
method
:
String
=
"aes-256-cfb"
var
route
:
String
=
"all"
var
remoteDns
:
String
=
"8.8.8.8"
var
proxyApps
:
Boolean
=
false
var
bypass
:
Boolean
=
false
var
udpdns
:
Boolean
=
false
var
ipv6
:
Boolean
=
true
var
individual
:
String
=
""
var
tx
:
Long
=
0
var
rx
:
Long
=
0
var
userOrder
:
Long
=
0
var
plugin
:
String
?
=
null
var
udpFallback
:
Long
?
=
null
@Ignore
// not persisted in db, only used by direct boot
var
dirty
:
Boolean
=
false
val
formattedAddress
get
()
=
(
if
(
host
.
contains
(
":"
))
"[%s]:%d"
else
"%s:%d"
).
format
(
host
,
remotePort
)
val
formattedAddress
get
()
=
(
if
(
host
.
contains
(
":"
))
"[%s]:%d"
else
"%s:%d"
).
format
(
host
,
remotePort
)
val
formattedName
get
()
=
if
(
name
.
isNullOrEmpty
())
formattedAddress
else
name
!!
val
formattedName
get
()
=
if
(
name
.
isNullOrEmpty
())
formattedAddress
else
name
!!
...
...
core/src/main/java/com/github/shadowsocks/database/ProfileManager.kt
View file @
be6cf63d
...
@@ -21,11 +21,14 @@
...
@@ -21,11 +21,14 @@
package
com.github.shadowsocks.database
package
com.github.shadowsocks.database
import
android.database.sqlite.SQLiteCantOpenDatabaseException
import
android.database.sqlite.SQLiteCantOpenDatabaseException
import
android.util.LongSparseArray
import
com.github.shadowsocks.Core
import
com.github.shadowsocks.Core
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.printLog
import
com.github.shadowsocks.utils.printLog
import
org.json.JSONArray
import
java.io.IOException
import
java.io.IOException
import
java.io.InputStream
import
java.sql.SQLException
import
java.sql.SQLException
/**
/**
...
@@ -36,6 +39,7 @@ object ProfileManager {
...
@@ -36,6 +39,7 @@ object ProfileManager {
interface
Listener
{
interface
Listener
{
fun
onAdd
(
profile
:
Profile
)
fun
onAdd
(
profile
:
Profile
)
fun
onRemove
(
profileId
:
Long
)
fun
onRemove
(
profileId
:
Long
)
fun
onCleared
()
}
}
var
listener
:
Listener
?
=
null
var
listener
:
Listener
?
=
null
...
@@ -48,6 +52,36 @@ object ProfileManager {
...
@@ -48,6 +52,36 @@ object ProfileManager {
return
profile
return
profile
}
}
fun
createProfilesFromJson
(
jsons
:
Sequence
<
InputStream
>,
replace
:
Boolean
=
false
)
{
val
profiles
=
if
(
replace
)
getAllProfiles
()
?.
associateBy
{
it
.
formattedAddress
}
else
null
val
feature
=
if
(
replace
)
{
profiles
?.
values
?.
singleOrNull
{
it
.
id
==
DataStore
.
profileId
}
}
else
Core
.
currentProfile
?.
first
val
lazyClear
=
lazy
{
clear
()
}
var
result
:
Exception
?
=
null
for
(
json
in
jsons
)
try
{
Profile
.
parseJson
(
json
.
bufferedReader
().
readText
(),
feature
)
{
if
(
replace
)
{
lazyClear
.
value
// if two profiles has the same address, treat them as the same profile and copy stats over
profiles
?.
get
(
it
.
formattedAddress
)
?.
apply
{
it
.
tx
=
tx
it
.
rx
=
rx
}
}
createProfile
(
it
)
}
}
catch
(
e
:
Exception
)
{
if
(
result
==
null
)
result
=
e
else
result
.
addSuppressed
(
e
)
}
if
(
result
!=
null
)
throw
result
}
fun
serializeToJson
(
profiles
:
List
<
Profile
>?
=
getAllProfiles
()):
JSONArray
?
{
if
(
profiles
==
null
)
return
null
val
lookup
=
LongSparseArray
<
Profile
>(
profiles
.
size
).
apply
{
profiles
.
forEach
{
put
(
it
.
id
,
it
)
}
}
return
JSONArray
(
profiles
.
map
{
it
.
toJson
(
lookup
)
}.
toTypedArray
())
}
/**
/**
* Note: It's caller's responsibility to update DirectBoot profile if necessary.
* Note: It's caller's responsibility to update DirectBoot profile if necessary.
*/
*/
...
@@ -78,6 +112,7 @@ object ProfileManager {
...
@@ -78,6 +112,7 @@ object ProfileManager {
fun
clear
()
=
PrivateDatabase
.
profileDao
.
deleteAll
().
also
{
fun
clear
()
=
PrivateDatabase
.
profileDao
.
deleteAll
().
also
{
// listener is not called since this won't be used in mobile submodule
// listener is not called since this won't be used in mobile submodule
DirectBoot
.
clean
()
DirectBoot
.
clean
()
listener
?.
onCleared
()
}
}
@Throws
(
IOException
::
class
)
@Throws
(
IOException
::
class
)
...
...
core/src/main/java/com/github/shadowsocks/net/ChannelMonitor.kt
View file @
be6cf63d
...
@@ -20,6 +20,7 @@
...
@@ -20,6 +20,7 @@
package
com.github.shadowsocks.net
package
com.github.shadowsocks.net
import
android.os.Build
import
com.github.shadowsocks.utils.printLog
import
com.github.shadowsocks.utils.printLog
import
kotlinx.coroutines.*
import
kotlinx.coroutines.*
import
kotlinx.coroutines.channels.Channel
import
kotlinx.coroutines.channels.Channel
...
@@ -65,23 +66,31 @@ class ChannelMonitor : Thread("ChannelMonitor") {
...
@@ -65,23 +66,31 @@ class ChannelMonitor : Thread("ChannelMonitor") {
start
()
start
()
}
}
/**
* Prevent NetworkOnMainThreadException because people enable strict mode for no reasons.
*/
private
suspend
fun
WritableByteChannel
.
writeCompat
(
src
:
ByteBuffer
)
=
if
(
Build
.
VERSION
.
SDK_INT
<=
23
)
withContext
(
Dispatchers
.
Default
)
{
write
(
src
)
}
else
write
(
src
)
suspend
fun
register
(
channel
:
SelectableChannel
,
ops
:
Int
,
block
:
(
SelectionKey
)
->
Unit
):
SelectionKey
{
suspend
fun
register
(
channel
:
SelectableChannel
,
ops
:
Int
,
block
:
(
SelectionKey
)
->
Unit
):
SelectionKey
{
val
registration
=
Registration
(
channel
,
ops
,
block
)
val
registration
=
Registration
(
channel
,
ops
,
block
)
pendingRegistrations
.
send
(
registration
)
pendingRegistrations
.
send
(
registration
)
ByteBuffer
.
allocateDirect
(
1
).
also
{
junk
->
ByteBuffer
.
allocateDirect
(
1
).
also
{
junk
->
loop@
while
(
running
)
when
(
registrationPipe
.
sink
().
write
(
junk
))
{
loop@
while
(
running
)
when
(
registrationPipe
.
sink
().
write
Compat
(
junk
))
{
0
->
kotlinx
.
coroutines
.
yield
()
0
->
kotlinx
.
coroutines
.
yield
()
1
->
break
@loop
1
->
break
@loop
else
->
throw
IOException
(
"Failed to register in the channel"
)
else
->
throw
IOException
(
"Failed to register in the channel"
)
}
}
}
}
if
(!
running
)
throw
C
losedChannel
Exception
()
if
(!
running
)
throw
C
ancellation
Exception
()
return
registration
.
result
.
await
()
return
registration
.
result
.
await
()
}
}
suspend
fun
wait
(
channel
:
SelectableChannel
,
ops
:
Int
)
=
CompletableDeferred
<
SelectionKey
>().
run
{
suspend
fun
wait
(
channel
:
SelectableChannel
,
ops
:
Int
)
=
CompletableDeferred
<
SelectionKey
>().
run
{
register
(
channel
,
ops
)
{
register
(
channel
,
ops
)
{
if
(
it
.
isValid
)
it
.
interestOps
(
0
)
// stop listening
if
(
it
.
isValid
)
try
{
it
.
interestOps
(
0
)
// stop listening
}
catch
(
_
:
CancelledKeyException
)
{
}
complete
(
it
)
complete
(
it
)
}
}
await
()
await
()
...
...
core/src/main/java/com/github/shadowsocks/net/LocalDnsServer.kt
View file @
be6cf63d
...
@@ -68,7 +68,7 @@ class LocalDnsServer(private val localResolver: suspend (String) -> Array<InetAd
...
@@ -68,7 +68,7 @@ class LocalDnsServer(private val localResolver: suspend (String) -> Array<InetAd
private
fun
prepareDnsResponse
(
request
:
Message
)
=
Message
(
request
.
header
.
id
).
apply
{
private
fun
prepareDnsResponse
(
request
:
Message
)
=
Message
(
request
.
header
.
id
).
apply
{
header
.
setFlag
(
Flags
.
QR
.
toInt
())
// this is a response
header
.
setFlag
(
Flags
.
QR
.
toInt
())
// this is a response
if
(
request
.
header
.
getFlag
(
Flags
.
RD
.
toInt
()))
header
.
setFlag
(
Flags
.
RD
.
toInt
())
if
(
request
.
header
.
getFlag
(
Flags
.
RD
.
toInt
()))
header
.
setFlag
(
Flags
.
RD
.
toInt
())
addRecord
(
request
.
question
,
Section
.
QUESTION
)
request
.
question
?.
also
{
addRecord
(
it
,
Section
.
QUESTION
)
}
}
}
}
}
private
val
monitor
=
ChannelMonitor
()
private
val
monitor
=
ChannelMonitor
()
...
@@ -99,30 +99,30 @@ class LocalDnsServer(private val localResolver: suspend (String) -> Array<InetAd
...
@@ -99,30 +99,30 @@ class LocalDnsServer(private val localResolver: suspend (String) -> Array<InetAd
printLog
(
e
)
printLog
(
e
)
return
forward
(
packet
)
return
forward
(
packet
)
}
}
return
coroutine
Scope
{
return
super
visor
Scope
{
val
remote
=
async
{
withTimeout
(
TIMEOUT
)
{
forward
(
packet
)
}
}
val
remote
=
async
{
withTimeout
(
TIMEOUT
)
{
forward
(
packet
)
}
}
try
{
try
{
if
(
forwardOnly
||
request
.
header
.
opcode
!=
Opcode
.
QUERY
)
return
@
coroutine
Scope
remote
.
await
()
if
(
forwardOnly
||
request
.
header
.
opcode
!=
Opcode
.
QUERY
)
return
@
supervisor
Scope
remote
.
await
()
val
question
=
request
.
question
val
question
=
request
.
question
if
(
question
?.
type
!=
Type
.
A
)
return
@
coroutine
Scope
remote
.
await
()
if
(
question
?.
type
!=
Type
.
A
)
return
@
supervisor
Scope
remote
.
await
()
val
host
=
question
.
name
.
toString
(
true
)
val
host
=
question
.
name
.
toString
(
true
)
if
(
remoteDomainMatcher
?.
containsMatchIn
(
host
)
==
true
)
return
@
coroutine
Scope
remote
.
await
()
if
(
remoteDomainMatcher
?.
containsMatchIn
(
host
)
==
true
)
return
@
supervisor
Scope
remote
.
await
()
val
localResults
=
try
{
val
localResults
=
try
{
withTimeout
(
TIMEOUT
)
{
GlobalScope
.
async
(
Dispatchers
.
IO
)
{
localResolver
(
host
)
}.
await
()
}
withTimeout
(
TIMEOUT
)
{
GlobalScope
.
async
(
Dispatchers
.
IO
)
{
localResolver
(
host
)
}.
await
()
}
}
catch
(
_
:
TimeoutCancellationException
)
{
}
catch
(
_
:
TimeoutCancellationException
)
{
Crashlytics
.
log
(
Log
.
WARN
,
TAG
,
"Local resolving timed out, falling back to remote resolving"
)
Crashlytics
.
log
(
Log
.
WARN
,
TAG
,
"Local resolving timed out, falling back to remote resolving"
)
return
@
coroutine
Scope
remote
.
await
()
return
@
supervisor
Scope
remote
.
await
()
}
catch
(
_
:
UnknownHostException
)
{
}
catch
(
_
:
UnknownHostException
)
{
return
@
coroutine
Scope
remote
.
await
()
return
@
supervisor
Scope
remote
.
await
()
}
}
if
(
localResults
.
isEmpty
())
return
@
coroutine
Scope
remote
.
await
()
if
(
localResults
.
isEmpty
())
return
@
supervisor
Scope
remote
.
await
()
if
(
localIpMatcher
.
isEmpty
()
||
localIpMatcher
.
any
{
subnet
->
localResults
.
any
(
subnet
::
matches
)
})
{
if
(
localIpMatcher
.
isEmpty
()
||
localIpMatcher
.
any
{
subnet
->
localResults
.
any
(
subnet
::
matches
)
})
{
remote
.
cancel
()
remote
.
cancel
()
ByteBuffer
.
wrap
(
prepareDnsResponse
(
request
).
apply
{
ByteBuffer
.
wrap
(
prepareDnsResponse
(
request
).
apply
{
header
.
setFlag
(
Flags
.
RA
.
toInt
())
// recursion available
header
.
setFlag
(
Flags
.
RA
.
toInt
())
// recursion available
for
(
address
in
localResults
)
addRecord
(
when
(
address
)
{
for
(
address
in
localResults
)
addRecord
(
when
(
address
)
{
is
Inet4Address
->
ARecord
(
request
.
question
.
name
,
DClass
.
IN
,
TTL
,
address
)
is
Inet4Address
->
ARecord
(
question
.
name
,
DClass
.
IN
,
TTL
,
address
)
is
Inet6Address
->
AAAARecord
(
request
.
question
.
name
,
DClass
.
IN
,
TTL
,
address
)
is
Inet6Address
->
AAAARecord
(
question
.
name
,
DClass
.
IN
,
TTL
,
address
)
else
->
throw
IllegalStateException
(
"Unsupported address $address"
)
else
->
throw
IllegalStateException
(
"Unsupported address $address"
)
},
Section
.
ANSWER
)
},
Section
.
ANSWER
)
}.
toWire
())
}.
toWire
())
...
@@ -159,7 +159,7 @@ class LocalDnsServer(private val localResolver: suspend (String) -> Array<InetAd
...
@@ -159,7 +159,7 @@ class LocalDnsServer(private val localResolver: suspend (String) -> Array<InetAd
check
(
channel
.
send
(
remoteDns
.
udpWrap
(
packet
),
proxy
)
>
0
)
check
(
channel
.
send
(
remoteDns
.
udpWrap
(
packet
),
proxy
)
>
0
)
monitor
.
wait
(
channel
,
SelectionKey
.
OP_READ
)
monitor
.
wait
(
channel
,
SelectionKey
.
OP_READ
)
val
result
=
remoteDns
.
udpReceiveBuffer
(
UDP_PACKET_SIZE
)
val
result
=
remoteDns
.
udpReceiveBuffer
(
UDP_PACKET_SIZE
)
check
(
channel
.
receive
(
result
)
==
proxy
)
while
(
channel
.
receive
(
result
)
!=
proxy
)
result
.
clear
(
)
result
.
flip
()
result
.
flip
()
remoteDns
.
udpUnwrap
(
result
)
remoteDns
.
udpUnwrap
(
result
)
result
result
...
...
core/src/main/java/com/github/shadowsocks/net/LocalSocketListener.kt
View file @
be6cf63d
...
@@ -65,7 +65,7 @@ abstract class LocalSocketListener(name: String, socketFile: File) : Thread(name
...
@@ -65,7 +65,7 @@ abstract class LocalSocketListener(name: String, socketFile: File) : Thread(name
open
fun
shutdown
(
scope
:
CoroutineScope
)
{
open
fun
shutdown
(
scope
:
CoroutineScope
)
{
running
=
false
running
=
false
localSocket
.
fileDescriptor
.
apply
{
localSocket
.
fileDescriptor
?
.
apply
{
// see also: https://issuetracker.google.com/issues/36945762#comment15
// see also: https://issuetracker.google.com/issues/36945762#comment15
if
(
valid
())
try
{
if
(
valid
())
try
{
Os
.
shutdown
(
this
,
OsConstants
.
SHUT_RDWR
)
Os
.
shutdown
(
this
,
OsConstants
.
SHUT_RDWR
)
...
...
core/src/main/java/com/github/shadowsocks/net/TcpFastOpen.kt
View file @
be6cf63d
...
@@ -20,6 +20,7 @@
...
@@ -20,6 +20,7 @@
package
com.github.shadowsocks.net
package
com.github.shadowsocks.net
import
com.github.shadowsocks.utils.readableMessage
import
kotlinx.coroutines.runBlocking
import
kotlinx.coroutines.runBlocking
import
kotlinx.coroutines.withTimeoutOrNull
import
kotlinx.coroutines.withTimeoutOrNull
import
java.io.File
import
java.io.File
...
@@ -57,7 +58,7 @@ object TcpFastOpen {
...
@@ -57,7 +58,7 @@ object TcpFastOpen {
ProcessBuilder
(
"su"
,
"-c"
,
"echo 3 > $PATH"
).
redirectErrorStream
(
true
).
start
()
ProcessBuilder
(
"su"
,
"-c"
,
"echo 3 > $PATH"
).
redirectErrorStream
(
true
).
start
()
.
inputStream
.
bufferedReader
().
readText
()
.
inputStream
.
bufferedReader
().
readText
()
}
catch
(
e
:
IOException
)
{
}
catch
(
e
:
IOException
)
{
e
.
localized
Message
e
.
readable
Message
}
}
}
}
fun
enableTimeout
()
=
runBlocking
{
withTimeoutOrNull
(
1000
)
{
enable
()
}
}
fun
enableTimeout
()
=
runBlocking
{
withTimeoutOrNull
(
1000
)
{
enable
()
}
}
...
...
core/src/main/java/com/github/shadowsocks/utils/DeviceStorageApp.kt
View file @
be6cf63d
...
@@ -36,5 +36,5 @@ class DeviceStorageApp(context: Context) : Application() {
...
@@ -36,5 +36,5 @@ class DeviceStorageApp(context: Context) : Application() {
* Thou shalt not get the REAL underlying application context which would no longer be operating under device
* Thou shalt not get the REAL underlying application context which would no longer be operating under device
* protected storage.
* protected storage.
*/
*/
override
fun
getApplicationContext
()
:
Context
=
this
override
fun
getApplicationContext
()
=
this
}
}
core/src/main/java/com/github/shadowsocks/utils/Utils.kt
View file @
be6cf63d
...
@@ -42,6 +42,8 @@ import kotlinx.coroutines.launch
...
@@ -42,6 +42,8 @@ import kotlinx.coroutines.launch
import
java.net.HttpURLConnection
import
java.net.HttpURLConnection
import
java.net.InetAddress
import
java.net.InetAddress
val
Throwable
.
readableMessage
get
()
=
localizedMessage
?:
javaClass
.
name
private
val
parseNumericAddress
by
lazy
{
private
val
parseNumericAddress
by
lazy
{
InetAddress
::
class
.
java
.
getDeclaredMethod
(
"parseNumericAddress"
,
String
::
class
.
java
).
apply
{
InetAddress
::
class
.
java
.
getDeclaredMethod
(
"parseNumericAddress"
,
String
::
class
.
java
).
apply
{
isAccessible
=
true
isAccessible
=
true
...
...
shadowsocks-libev
@
b430124e
Subproject commit
7ad2df961505ecddb44984ce34ea86874cd2ecc
4
Subproject commit
b430124ed82973d4edf345dfadbe556f9337748
4
core/src/main/res/values/strings.xml
View file @
be6cf63d
...
@@ -97,6 +97,7 @@
...
@@ -97,6 +97,7 @@
<string
name=
"action_export"
>
Export to Clipboard
</string>
<string
name=
"action_export"
>
Export to Clipboard
</string>
<string
name=
"action_import"
>
Import from Clipboard
</string>
<string
name=
"action_import"
>
Import from Clipboard
</string>
<string
name=
"action_import_file"
>
Import from file…
</string>
<string
name=
"action_import_file"
>
Import from file…
</string>
<string
name=
"action_replace_file"
>
Replace from file…
</string>
<string
name=
"action_export_msg"
>
Successfully export!
</string>
<string
name=
"action_export_msg"
>
Successfully export!
</string>
<string
name=
"action_export_err"
>
Failed to export.
</string>
<string
name=
"action_export_err"
>
Failed to export.
</string>
<string
name=
"action_import_msg"
>
Successfully import!
</string>
<string
name=
"action_import_msg"
>
Successfully import!
</string>
...
...
mobile/build.gradle
View file @
be6cf63d
...
@@ -5,6 +5,7 @@ import java.util.regex.Pattern
...
@@ -5,6 +5,7 @@ import java.util.regex.Pattern
apply
plugin:
'com.android.application'
apply
plugin:
'com.android.application'
apply
plugin:
'io.fabric'
apply
plugin:
'io.fabric'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android-extensions'
def
getCurrentFlavor
()
{
def
getCurrentFlavor
()
{
String
task
=
getGradle
().
getStartParameter
().
getTaskRequests
().
toString
()
String
task
=
getGradle
().
getStartParameter
().
getTaskRequests
().
toString
()
...
@@ -49,6 +50,10 @@ android {
...
@@ -49,6 +50,10 @@ android {
new
File
(
project
(
':core'
).
buildDir
,
"intermediates/bundles/${getCurrentFlavor()}/jni"
)
new
File
(
project
(
':core'
).
buildDir
,
"intermediates/bundles/${getCurrentFlavor()}/jni"
)
}
}
androidExtensions
{
experimental
=
true
}
dependencies
{
dependencies
{
implementation
project
(
':core'
)
implementation
project
(
':core'
)
implementation
'androidx.browser:browser:1.0.0'
implementation
'androidx.browser:browser:1.0.0'
...
...
mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
View file @
be6cf63d
...
@@ -88,8 +88,8 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() {
...
@@ -88,8 +88,8 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() {
portTransproxy
.
isEnabled
=
enabledTransproxy
portTransproxy
.
isEnabled
=
enabledTransproxy
true
true
}
}
val
listener
:
(
Int
)
->
Unit
=
{
val
listener
:
(
BaseService
.
State
)
->
Unit
=
{
if
(
it
==
BaseService
.
S
TOPPED
)
{
if
(
it
==
BaseService
.
S
tate
.
Stopped
)
{
tfo
.
isEnabled
=
true
tfo
.
isEnabled
=
true
serviceMode
.
isEnabled
=
true
serviceMode
.
isEnabled
=
true
portProxy
.
isEnabled
=
true
portProxy
.
isEnabled
=
true
...
...
mobile/src/main/java/com/github/shadowsocks/MainActivity.kt
View file @
be6cf63d
...
@@ -23,6 +23,7 @@ package com.github.shadowsocks
...
@@ -23,6 +23,7 @@ package com.github.shadowsocks
import
android.app.Activity
import
android.app.Activity
import
android.app.backup.BackupManager
import
android.app.backup.BackupManager
import
android.content.ActivityNotFoundException
import
android.content.ActivityNotFoundException
import
android.content.DialogInterface
import
android.content.Intent
import
android.content.Intent
import
android.net.VpnService
import
android.net.VpnService
import
android.nfc.NdefMessage
import
android.nfc.NdefMessage
...
@@ -30,6 +31,7 @@ import android.nfc.NfcAdapter
...
@@ -30,6 +31,7 @@ import android.nfc.NfcAdapter
import
android.os.Bundle
import
android.os.Bundle
import
android.os.DeadObjectException
import
android.os.DeadObjectException
import
android.os.Handler
import
android.os.Handler
import
android.os.Parcelable
import
android.util.Log
import
android.util.Log
import
android.view.KeyCharacterMap
import
android.view.KeyCharacterMap
import
android.view.KeyEvent
import
android.view.KeyEvent
...
@@ -51,6 +53,8 @@ import com.github.shadowsocks.aidl.TrafficStats
...
@@ -51,6 +53,8 @@ import com.github.shadowsocks.aidl.TrafficStats
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.plugin.AlertDialogFragment
import
com.github.shadowsocks.plugin.Empty
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener
import
com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.Key
...
@@ -58,6 +62,7 @@ import com.github.shadowsocks.widget.ServiceButton
...
@@ -58,6 +62,7 @@ import com.github.shadowsocks.widget.ServiceButton
import
com.github.shadowsocks.widget.StatsBar
import
com.github.shadowsocks.widget.StatsBar
import
com.google.android.material.navigation.NavigationView
import
com.google.android.material.navigation.NavigationView
import
com.google.android.material.snackbar.Snackbar
import
com.google.android.material.snackbar.Snackbar
import
kotlinx.android.parcel.Parcelize
class
MainActivity
:
AppCompatActivity
(),
ShadowsocksConnection
.
Callback
,
OnPreferenceDataStoreChangeListener
,
class
MainActivity
:
AppCompatActivity
(),
ShadowsocksConnection
.
Callback
,
OnPreferenceDataStoreChangeListener
,
NavigationView
.
OnNavigationItemSelectedListener
{
NavigationView
.
OnNavigationItemSelectedListener
{
...
@@ -65,7 +70,18 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
...
@@ -65,7 +70,18 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
private
const
val
TAG
=
"ShadowsocksMainActivity"
private
const
val
TAG
=
"ShadowsocksMainActivity"
private
const
val
REQUEST_CONNECT
=
1
private
const
val
REQUEST_CONNECT
=
1
var
stateListener
:
((
Int
)
->
Unit
)?
=
null
var
stateListener
:
((
BaseService
.
State
)
->
Unit
)?
=
null
}
@Parcelize
data class
ProfilesArg
(
val
profiles
:
List
<
Profile
>)
:
Parcelable
class
ImportProfilesDialogFragment
:
AlertDialogFragment
<
ProfilesArg
,
Empty
>()
{
override
fun
AlertDialog
.
Builder
.
prepare
(
listener
:
DialogInterface
.
OnClickListener
)
{
setTitle
(
R
.
string
.
add_profile_dialog
)
setPositiveButton
(
R
.
string
.
yes
)
{
_
,
_
->
arg
.
profiles
.
forEach
{
ProfileManager
.
createProfile
(
it
)
}
}
setNegativeButton
(
R
.
string
.
no
,
null
)
setMessage
(
arg
.
profiles
.
joinToString
(
"\n"
))
}
}
}
// UI
// UI
...
@@ -91,12 +107,12 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
...
@@ -91,12 +107,12 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
}
}
// service
// service
var
state
=
BaseService
.
IDLE
var
state
=
BaseService
.
State
.
Idle
override
fun
stateChanged
(
state
:
Int
,
profileName
:
String
?,
msg
:
String
?)
=
changeState
(
state
,
msg
,
true
)
override
fun
stateChanged
(
state
:
BaseService
.
State
,
profileName
:
String
?,
msg
:
String
?)
=
changeState
(
state
,
msg
,
true
)
override
fun
trafficUpdated
(
profileId
:
Long
,
stats
:
TrafficStats
)
{
override
fun
trafficUpdated
(
profileId
:
Long
,
stats
:
TrafficStats
)
{
if
(
profileId
==
0L
)
this
@MainActivity
.
stats
.
updateTraffic
(
if
(
profileId
==
0L
)
this
@MainActivity
.
stats
.
updateTraffic
(
stats
.
txRate
,
stats
.
rxRate
,
stats
.
txTotal
,
stats
.
rxTotal
)
stats
.
txRate
,
stats
.
rxRate
,
stats
.
txTotal
,
stats
.
rxTotal
)
if
(
state
!=
BaseService
.
S
TOPPING
)
{
if
(
state
!=
BaseService
.
S
tate
.
Stopping
)
{
(
supportFragmentManager
.
findFragmentById
(
R
.
id
.
fragment_holder
)
as
?
ToolbarFragment
)
(
supportFragmentManager
.
findFragmentById
(
R
.
id
.
fragment_holder
)
as
?
ToolbarFragment
)
?.
onTrafficUpdated
(
profileId
,
stats
)
?.
onTrafficUpdated
(
profileId
,
stats
)
}
}
...
@@ -105,7 +121,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
...
@@ -105,7 +121,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
ProfilesFragment
.
instance
?.
onTrafficPersisted
(
profileId
)
ProfilesFragment
.
instance
?.
onTrafficPersisted
(
profileId
)
}
}
private
fun
changeState
(
state
:
Int
,
msg
:
String
?
=
null
,
animate
:
Boolean
=
false
)
{
private
fun
changeState
(
state
:
BaseService
.
State
,
msg
:
String
?
=
null
,
animate
:
Boolean
=
false
)
{
fab
.
changeState
(
state
,
animate
)
fab
.
changeState
(
state
,
animate
)
stats
.
changeState
(
state
)
stats
.
changeState
(
state
)
if
(
msg
!=
null
)
snackbar
(
getString
(
R
.
string
.
vpn_error
,
msg
)).
show
()
if
(
msg
!=
null
)
snackbar
(
getString
(
R
.
string
.
vpn_error
,
msg
)).
show
()
...
@@ -115,7 +131,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
...
@@ -115,7 +131,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
}
}
private
fun
toggle
()
=
when
{
private
fun
toggle
()
=
when
{
state
==
BaseService
.
CONNECTED
->
Core
.
stopService
()
state
.
canStop
->
Core
.
stopService
()
DataStore
.
serviceMode
==
Key
.
modeVpn
->
{
DataStore
.
serviceMode
==
Key
.
modeVpn
->
{
val
intent
=
VpnService
.
prepare
(
this
)
val
intent
=
VpnService
.
prepare
(
this
)
if
(
intent
!=
null
)
startActivityForResult
(
intent
,
REQUEST_CONNECT
)
if
(
intent
!=
null
)
startActivityForResult
(
intent
,
REQUEST_CONNECT
)
...
@@ -127,11 +143,11 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
...
@@ -127,11 +143,11 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
private
val
handler
=
Handler
()
private
val
handler
=
Handler
()
private
val
connection
=
ShadowsocksConnection
(
handler
,
true
)
private
val
connection
=
ShadowsocksConnection
(
handler
,
true
)
override
fun
onServiceConnected
(
service
:
IShadowsocksService
)
=
changeState
(
try
{
override
fun
onServiceConnected
(
service
:
IShadowsocksService
)
=
changeState
(
try
{
service
.
state
BaseService
.
State
.
values
()[
service
.
state
]
}
catch
(
_
:
DeadObjectException
)
{
}
catch
(
_
:
DeadObjectException
)
{
BaseService
.
IDLE
BaseService
.
State
.
Idle
})
})
override
fun
onServiceDisconnected
()
=
changeState
(
BaseService
.
IDLE
)
override
fun
onServiceDisconnected
()
=
changeState
(
BaseService
.
State
.
Idle
)
override
fun
onBinderDied
()
{
override
fun
onBinderDied
()
{
connection
.
disconnect
(
this
)
connection
.
disconnect
(
this
)
connection
.
connect
(
this
,
this
)
connection
.
connect
(
this
,
this
)
...
@@ -152,7 +168,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
...
@@ -152,7 +168,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
super
.
onCreate
(
savedInstanceState
)
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
layout_main
)
setContentView
(
R
.
layout
.
layout_main
)
stats
=
findViewById
(
R
.
id
.
stats
)
stats
=
findViewById
(
R
.
id
.
stats
)
stats
.
setOnClickListener
{
if
(
state
==
BaseService
.
CONNECTED
)
stats
.
testConnection
()
}
stats
.
setOnClickListener
{
if
(
state
==
BaseService
.
State
.
Connected
)
stats
.
testConnection
()
}
drawer
=
findViewById
(
R
.
id
.
drawer
)
drawer
=
findViewById
(
R
.
id
.
drawer
)
navigation
=
findViewById
(
R
.
id
.
navigation
)
navigation
=
findViewById
(
R
.
id
.
navigation
)
navigation
.
setNavigationItemSelectedListener
(
this
)
navigation
.
setNavigationItemSelectedListener
(
this
)
...
@@ -164,7 +180,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
...
@@ -164,7 +180,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
fab
=
findViewById
(
R
.
id
.
fab
)
fab
=
findViewById
(
R
.
id
.
fab
)
fab
.
setOnClickListener
{
toggle
()
}
fab
.
setOnClickListener
{
toggle
()
}
changeState
(
BaseService
.
IDLE
)
// reset everything to init state
changeState
(
BaseService
.
State
.
Idle
)
// reset everything to init state
connection
.
connect
(
this
,
this
)
connection
.
connect
(
this
,
this
)
DataStore
.
publicStore
.
registerChangeListener
(
this
)
DataStore
.
publicStore
.
registerChangeListener
(
this
)
...
@@ -188,17 +204,8 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
...
@@ -188,17 +204,8 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
}
}
if
(
sharedStr
.
isNullOrEmpty
())
return
if
(
sharedStr
.
isNullOrEmpty
())
return
val
profiles
=
Profile
.
findAllUrls
(
sharedStr
,
Core
.
currentProfile
?.
first
).
toList
()
val
profiles
=
Profile
.
findAllUrls
(
sharedStr
,
Core
.
currentProfile
?.
first
).
toList
()
if
(
profiles
.
isEmpty
())
{
if
(
profiles
.
isEmpty
())
snackbar
().
setText
(
R
.
string
.
profile_invalid_input
).
show
()
snackbar
().
setText
(
R
.
string
.
profile_invalid_input
).
show
()
else
ImportProfilesDialogFragment
().
withArg
(
ProfilesArg
(
profiles
)).
show
(
supportFragmentManager
,
null
)
return
}
AlertDialog
.
Builder
(
this
)
.
setTitle
(
R
.
string
.
add_profile_dialog
)
.
setPositiveButton
(
R
.
string
.
yes
)
{
_
,
_
->
profiles
.
forEach
{
ProfileManager
.
createProfile
(
it
)
}
}
.
setNegativeButton
(
R
.
string
.
no
,
null
)
.
setMessage
(
profiles
.
joinToString
(
"\n"
))
.
create
()
.
show
()
}
}
override
fun
onPreferenceDataStoreChanged
(
store
:
PreferenceDataStore
,
key
:
String
?)
{
override
fun
onPreferenceDataStoreChanged
(
store
:
PreferenceDataStore
,
key
:
String
?)
{
...
...
mobile/src/main/java/com/github/shadowsocks/ProfileConfigActivity.kt
View file @
be6cf63d
...
@@ -21,12 +21,15 @@
...
@@ -21,12 +21,15 @@
package
com.github.shadowsocks
package
com.github.shadowsocks
import
android.app.Activity
import
android.app.Activity
import
android.content.DialogInterface
import
android.content.Intent
import
android.content.Intent
import
android.os.Bundle
import
android.os.Bundle
import
android.view.Menu
import
android.view.Menu
import
android.view.MenuItem
import
android.view.MenuItem
import
androidx.appcompat.app.AlertDialog
import
androidx.appcompat.app.AlertDialog
import
androidx.appcompat.app.AppCompatActivity
import
androidx.appcompat.app.AppCompatActivity
import
com.github.shadowsocks.plugin.AlertDialogFragment
import
com.github.shadowsocks.plugin.Empty
import
com.github.shadowsocks.plugin.PluginContract
import
com.github.shadowsocks.plugin.PluginContract
import
com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.preference.DataStore
...
@@ -35,6 +38,15 @@ class ProfileConfigActivity : AppCompatActivity() {
...
@@ -35,6 +38,15 @@ class ProfileConfigActivity : AppCompatActivity() {
const
val
REQUEST_CODE_PLUGIN_HELP
=
1
const
val
REQUEST_CODE_PLUGIN_HELP
=
1
}
}
class
UnsavedChangesDialogFragment
:
AlertDialogFragment
<
Empty
,
Empty
>()
{
override
fun
AlertDialog
.
Builder
.
prepare
(
listener
:
DialogInterface
.
OnClickListener
)
{
setTitle
(
R
.
string
.
unsaved_changes_prompt
)
setPositiveButton
(
R
.
string
.
yes
,
listener
)
setNegativeButton
(
R
.
string
.
no
,
listener
)
setNeutralButton
(
android
.
R
.
string
.
cancel
,
null
)
}
}
private
val
child
by
lazy
{
supportFragmentManager
.
findFragmentById
(
R
.
id
.
content
)
as
ProfileConfigFragment
}
private
val
child
by
lazy
{
supportFragmentManager
.
findFragmentById
(
R
.
id
.
content
)
as
ProfileConfigFragment
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
...
@@ -59,13 +71,8 @@ class ProfileConfigActivity : AppCompatActivity() {
...
@@ -59,13 +71,8 @@ class ProfileConfigActivity : AppCompatActivity() {
override
fun
onOptionsItemSelected
(
item
:
MenuItem
)
=
child
.
onOptionsItemSelected
(
item
)
override
fun
onOptionsItemSelected
(
item
:
MenuItem
)
=
child
.
onOptionsItemSelected
(
item
)
override
fun
onBackPressed
()
{
override
fun
onBackPressed
()
{
if
(
DataStore
.
dirty
)
AlertDialog
.
Builder
(
this
)
if
(
DataStore
.
dirty
)
UnsavedChangesDialogFragment
().
show
(
child
,
ProfileConfigFragment
.
REQUEST_UNSAVED_CHANGES
)
.
setTitle
(
R
.
string
.
unsaved_changes_prompt
)
else
super
.
onBackPressed
()
.
setPositiveButton
(
R
.
string
.
yes
)
{
_
,
_
->
child
.
saveAndExit
()
}
.
setNegativeButton
(
R
.
string
.
no
)
{
_
,
_
->
finish
()
}
.
setNeutralButton
(
android
.
R
.
string
.
cancel
,
null
)
.
create
()
.
show
()
else
super
.
onBackPressed
()
}
}
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
?)
{
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
?)
{
...
...
mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt
View file @
be6cf63d
...
@@ -22,23 +22,24 @@ package com.github.shadowsocks
...
@@ -22,23 +22,24 @@ package com.github.shadowsocks
import
android.app.Activity
import
android.app.Activity
import
android.content.BroadcastReceiver
import
android.content.BroadcastReceiver
import
android.content.DialogInterface
import
android.content.Intent
import
android.content.Intent
import
android.os.Bundle
import
android.os.Bundle
import
android.os.Parcelable
import
android.view.MenuItem
import
android.view.MenuItem
import
androidx.appcompat.app.AlertDialog
import
androidx.appcompat.app.AlertDialog
import
androidx.preference.*
import
androidx.preference.*
import
com.github.shadowsocks.Core.app
import
com.github.shadowsocks.Core.app
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.plugin.PluginConfiguration
import
com.github.shadowsocks.plugin.*
import
com.github.shadowsocks.plugin.PluginContract
import
com.github.shadowsocks.plugin.PluginManager
import
com.github.shadowsocks.plugin.PluginOptions
import
com.github.shadowsocks.preference.*
import
com.github.shadowsocks.preference.*
import
com.github.shadowsocks.utils.Action
import
com.github.shadowsocks.utils.Action
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.DirectBoot
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.readableMessage
import
com.google.android.material.snackbar.Snackbar
import
com.google.android.material.snackbar.Snackbar
import
kotlinx.android.parcel.Parcelize
class
ProfileConfigFragment
:
PreferenceFragmentCompat
(),
class
ProfileConfigFragment
:
PreferenceFragmentCompat
(),
Preference
.
OnPreferenceChangeListener
,
OnPreferenceDataStoreChangeListener
{
Preference
.
OnPreferenceChangeListener
,
OnPreferenceDataStoreChangeListener
{
...
@@ -46,6 +47,20 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
...
@@ -46,6 +47,20 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
override
fun
provideSummary
(
preference
:
EditTextPreference
?)
=
"\u2022"
.
repeat
(
preference
?.
text
?.
length
?:
0
)
override
fun
provideSummary
(
preference
:
EditTextPreference
?)
=
"\u2022"
.
repeat
(
preference
?.
text
?.
length
?:
0
)
private
const
val
REQUEST_CODE_PLUGIN_CONFIGURE
=
1
private
const
val
REQUEST_CODE_PLUGIN_CONFIGURE
=
1
const
val
REQUEST_UNSAVED_CHANGES
=
2
}
@Parcelize
data class
ProfileIdArg
(
val
profileId
:
Long
)
:
Parcelable
class
DeleteConfirmationDialogFragment
:
AlertDialogFragment
<
ProfileIdArg
,
Empty
>()
{
override
fun
AlertDialog
.
Builder
.
prepare
(
listener
:
DialogInterface
.
OnClickListener
)
{
setTitle
(
R
.
string
.
delete_confirm_prompt
)
setPositiveButton
(
R
.
string
.
yes
)
{
_
,
_
->
ProfileManager
.
delProfile
(
arg
.
profileId
)
requireActivity
().
finish
()
}
setNegativeButton
(
R
.
string
.
no
,
null
)
}
}
}
private
var
profileId
=
-
1L
private
var
profileId
=
-
1L
...
@@ -114,7 +129,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
...
@@ -114,7 +129,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
}.
show
(
fragmentManager
?:
return
,
Key
.
pluginConfigure
)
}.
show
(
fragmentManager
?:
return
,
Key
.
pluginConfigure
)
}
}
fun
saveAndExit
()
{
private
fun
saveAndExit
()
{
val
profile
=
ProfileManager
.
getProfile
(
profileId
)
?:
Profile
()
val
profile
=
ProfileManager
.
getProfile
(
profileId
)
?:
Profile
()
profile
.
id
=
profileId
profile
.
id
=
profileId
profile
.
deserialize
()
profile
.
deserialize
()
...
@@ -140,7 +155,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
...
@@ -140,7 +155,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
DataStore
.
dirty
=
true
DataStore
.
dirty
=
true
true
true
}
catch
(
exc
:
RuntimeException
)
{
}
catch
(
exc
:
RuntimeException
)
{
Snackbar
.
make
(
view
!!
,
exc
.
localized
Message
,
Snackbar
.
LENGTH_LONG
).
show
()
Snackbar
.
make
(
view
!!
,
exc
.
readable
Message
,
Snackbar
.
LENGTH_LONG
).
show
()
false
false
}
}
...
@@ -167,28 +182,26 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
...
@@ -167,28 +182,26 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
}
}
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
?)
{
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
?)
{
if
(
requestCode
==
REQUEST_CODE_PLUGIN_CONFIGURE
)
when
(
resultCode
)
{
when
(
requestCode
)
{
REQUEST_CODE_PLUGIN_CONFIGURE
->
when
(
resultCode
)
{
Activity
.
RESULT_OK
->
{
Activity
.
RESULT_OK
->
{
val
options
=
data
?.
getStringExtra
(
PluginContract
.
EXTRA_OPTIONS
)
val
options
=
data
?.
getStringExtra
(
PluginContract
.
EXTRA_OPTIONS
)
pluginConfigure
.
text
=
options
pluginConfigure
.
text
=
options
onPreferenceChange
(
null
,
options
)
onPreferenceChange
(
null
,
options
)
}
}
PluginContract
.
RESULT_FALLBACK
->
showPluginEditor
()
PluginContract
.
RESULT_FALLBACK
->
showPluginEditor
()
}
else
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
}
REQUEST_UNSAVED_CHANGES
->
when
(
resultCode
)
{
DialogInterface
.
BUTTON_POSITIVE
->
saveAndExit
()
DialogInterface
.
BUTTON_NEGATIVE
->
requireActivity
().
finish
()
}
else
->
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
}
}
}
override
fun
onOptionsItemSelected
(
item
:
MenuItem
)
=
when
(
item
.
itemId
)
{
override
fun
onOptionsItemSelected
(
item
:
MenuItem
)
=
when
(
item
.
itemId
)
{
R
.
id
.
action_delete
->
{
R
.
id
.
action_delete
->
{
val
activity
=
requireActivity
()
DeleteConfirmationDialogFragment
().
withArg
(
ProfileIdArg
(
profileId
)).
show
(
this
)
AlertDialog
.
Builder
(
activity
)
.
setTitle
(
R
.
string
.
delete_confirm_prompt
)
.
setPositiveButton
(
R
.
string
.
yes
)
{
_
,
_
->
ProfileManager
.
delProfile
(
profileId
)
activity
.
finish
()
}
.
setNegativeButton
(
R
.
string
.
no
,
null
)
.
create
()
.
show
()
true
true
}
}
R
.
id
.
action_apply
->
{
R
.
id
.
action_apply
->
{
...
...
mobile/src/main/java/com/github/shadowsocks/ProfilesFragment.kt
View file @
be6cf63d
...
@@ -49,12 +49,12 @@ import com.github.shadowsocks.preference.DataStore
...
@@ -49,12 +49,12 @@ import com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.Action
import
com.github.shadowsocks.utils.Action
import
com.github.shadowsocks.utils.datas
import
com.github.shadowsocks.utils.datas
import
com.github.shadowsocks.utils.printLog
import
com.github.shadowsocks.utils.printLog
import
com.github.shadowsocks.utils.readableMessage
import
com.github.shadowsocks.widget.UndoSnackbarManager
import
com.github.shadowsocks.widget.UndoSnackbarManager
import
com.google.android.gms.ads.AdRequest
import
com.google.android.gms.ads.AdRequest
import
com.google.android.gms.ads.AdSize
import
com.google.android.gms.ads.AdSize
import
com.google.android.gms.ads.AdView
import
com.google.android.gms.ads.AdView
import
net.glxn.qrgen.android.QRCode
import
net.glxn.qrgen.android.QRCode
import
org.json.JSONArray
class
ProfilesFragment
:
ToolbarFragment
(),
Toolbar
.
OnMenuItemClickListener
{
class
ProfilesFragment
:
ToolbarFragment
(),
Toolbar
.
OnMenuItemClickListener
{
companion
object
{
companion
object
{
...
@@ -65,21 +65,16 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
...
@@ -65,21 +65,16 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
private
const
val
KEY_URL
=
"com.github.shadowsocks.QRCodeDialog.KEY_URL"
private
const
val
KEY_URL
=
"com.github.shadowsocks.QRCodeDialog.KEY_URL"
private
const
val
REQUEST_IMPORT_PROFILES
=
1
private
const
val
REQUEST_IMPORT_PROFILES
=
1
private
const
val
REQUEST_REPLACE_PROFILES
=
3
private
const
val
REQUEST_EXPORT_PROFILES
=
2
private
const
val
REQUEST_EXPORT_PROFILES
=
2
}
}
/**
/**
* Is ProfilesFragment editable at all.
* Is ProfilesFragment editable at all.
*/
*/
private
val
isEnabled
get
()
=
when
((
activity
as
MainActivity
).
state
)
{
private
val
isEnabled
get
()
=
(
activity
as
MainActivity
).
state
.
let
{
it
.
canStop
||
it
==
BaseService
.
State
.
Stopped
}
BaseService
.
CONNECTED
,
BaseService
.
STOPPED
->
true
private
fun
isProfileEditable
(
id
:
Long
)
=
else
->
false
(
activity
as
MainActivity
).
state
==
BaseService
.
State
.
Stopped
||
id
!
in
Core
.
activeProfileIds
}
private
fun
isProfileEditable
(
id
:
Long
)
=
when
((
activity
as
MainActivity
).
state
)
{
BaseService
.
CONNECTED
->
id
!
in
Core
.
activeProfileIds
BaseService
.
STOPPED
->
true
else
->
false
}
@SuppressLint
(
"ValidFragment"
)
@SuppressLint
(
"ValidFragment"
)
class
QRCodeDialog
()
:
DialogFragment
()
{
class
QRCodeDialog
()
:
DialogFragment
()
{
...
@@ -175,21 +170,20 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
...
@@ -175,21 +170,20 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
var
adView
=
adView
var
adView
=
adView
if
(
item
.
host
==
"198.199.101.152"
)
{
if
(
item
.
host
==
"198.199.101.152"
)
{
if
(
adView
==
null
)
{
if
(
adView
==
null
)
{
val
params
=
LinearLayout
.
LayoutParams
(
ViewGroup
.
LayoutParams
.
WRAP_CONT
ENT
,
val
params
=
LinearLayout
.
LayoutParams
(
ViewGroup
.
LayoutParams
.
MATCH_PAR
ENT
,
ViewGroup
.
LayoutParams
.
WRAP_CONTENT
)
AdSize
.
SMART_BANNER
.
getHeightInPixels
(
context
)
)
params
.
gravity
=
Gravity
.
CENTER_HORIZONTAL
params
.
gravity
=
Gravity
.
CENTER_HORIZONTAL
adView
=
AdView
(
context
)
adView
=
AdView
(
context
)
adView
.
layoutParams
=
params
adView
.
layoutParams
=
params
adView
.
adUnitId
=
"ca-app-pub-9097031975646651/7760346322"
adView
.
adUnitId
=
"ca-app-pub-9097031975646651/7760346322"
adView
.
adSize
=
AdSize
.
FLUID
adView
.
adSize
=
AdSize
.
SMART_BANNER
val
padding
=
context
.
resources
.
getDimensionPixelOffset
(
R
.
dimen
.
profile_padding
)
adView
.
setPadding
(
padding
,
0
,
0
,
padding
)
itemView
.
findViewById
<
LinearLayout
>(
R
.
id
.
content
).
addView
(
adView
)
itemView
.
findViewById
<
LinearLayout
>(
R
.
id
.
content
).
addView
(
adView
)
// Load Ad
// Load Ad
val
adBuilder
=
AdRequest
.
Builder
()
val
adBuilder
=
AdRequest
.
Builder
()
adBuilder
.
addTestDevice
(
"B08FC1764A7B250E91EA9D0D5EBEB208"
)
adBuilder
.
addTestDevice
(
"B08FC1764A7B250E91EA9D0D5EBEB208"
)
adBuilder
.
addTestDevice
(
"7509D18EB8AF82F915874FEF53877A64"
)
adView
.
loadAd
(
adBuilder
.
build
())
adView
.
loadAd
(
adBuilder
.
build
())
this
.
adView
=
adView
this
.
adView
=
adView
}
else
adView
.
visibility
=
View
.
VISIBLE
}
else
adView
.
visibility
=
View
.
VISIBLE
...
@@ -203,7 +197,7 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
...
@@ -203,7 +197,7 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
Core
.
switchProfile
(
item
.
id
)
Core
.
switchProfile
(
item
.
id
)
profilesAdapter
.
refreshId
(
old
)
profilesAdapter
.
refreshId
(
old
)
itemView
.
isSelected
=
true
itemView
.
isSelected
=
true
if
(
activity
.
state
==
BaseService
.
CONNECTED
)
Core
.
reloadService
()
if
(
activity
.
state
.
canStop
)
Core
.
reloadService
()
}
}
}
}
...
@@ -296,6 +290,11 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
...
@@ -296,6 +290,11 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
notifyItemRemoved
(
index
)
notifyItemRemoved
(
index
)
if
(
profileId
==
DataStore
.
profileId
)
DataStore
.
profileId
=
0
// switch to null profile
if
(
profileId
==
DataStore
.
profileId
)
DataStore
.
profileId
=
0
// switch to null profile
}
}
override
fun
onCleared
()
{
profiles
.
clear
()
notifyDataSetChanged
()
}
}
}
private
var
selectedItem
:
ProfileViewHolder
?
=
null
private
var
selectedItem
:
ProfileViewHolder
?
=
null
...
@@ -383,12 +382,20 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
...
@@ -383,12 +382,20 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
}
}
R
.
id
.
action_import_file
->
{
R
.
id
.
action_import_file
->
{
startFilesForResult
(
Intent
(
Intent
.
ACTION_GET_CONTENT
).
apply
{
startFilesForResult
(
Intent
(
Intent
.
ACTION_GET_CONTENT
).
apply
{
addCategory
(
Intent
.
CATEGORY_OPENABLE
)
type
=
"application/*"
type
=
"application/json"
putExtra
(
Intent
.
EXTRA_ALLOW_MULTIPLE
,
true
)
putExtra
(
Intent
.
EXTRA_ALLOW_MULTIPLE
,
true
)
putExtra
(
Intent
.
EXTRA_MIME_TYPES
,
arrayOf
(
"application/*"
,
"text/*"
))
},
REQUEST_IMPORT_PROFILES
)
},
REQUEST_IMPORT_PROFILES
)
true
true
}
}
R
.
id
.
action_replace_file
->
{
startFilesForResult
(
Intent
(
Intent
.
ACTION_GET_CONTENT
).
apply
{
type
=
"application/*"
putExtra
(
Intent
.
EXTRA_ALLOW_MULTIPLE
,
true
)
putExtra
(
Intent
.
EXTRA_MIME_TYPES
,
arrayOf
(
"application/*"
,
"text/*"
))
},
REQUEST_REPLACE_PROFILES
)
true
}
R
.
id
.
action_manual_settings
->
{
R
.
id
.
action_manual_settings
->
{
startConfig
(
ProfileManager
.
createProfile
(
startConfig
(
ProfileManager
.
createProfile
(
Profile
().
also
{
Core
.
currentProfile
?.
first
?.
copyFeatureSettingsTo
(
it
)
}))
Profile
().
also
{
Core
.
currentProfile
?.
first
?.
copyFeatureSettingsTo
(
it
)
}))
...
@@ -404,7 +411,6 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
...
@@ -404,7 +411,6 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
}
}
R
.
id
.
action_export_file
->
{
R
.
id
.
action_export_file
->
{
startFilesForResult
(
Intent
(
Intent
.
ACTION_CREATE_DOCUMENT
).
apply
{
startFilesForResult
(
Intent
(
Intent
.
ACTION_CREATE_DOCUMENT
).
apply
{
addCategory
(
Intent
.
CATEGORY_OPENABLE
)
type
=
"application/json"
type
=
"application/json"
putExtra
(
Intent
.
EXTRA_TITLE
,
"profiles.json"
)
// optional title that can be edited
putExtra
(
Intent
.
EXTRA_TITLE
,
"profiles.json"
)
// optional title that can be edited
},
REQUEST_EXPORT_PROFILES
)
},
REQUEST_EXPORT_PROFILES
)
...
@@ -414,9 +420,9 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
...
@@ -414,9 +420,9 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
}
}
}
}
private
fun
startFilesForResult
(
intent
:
Intent
?
,
requestCode
:
Int
)
{
private
fun
startFilesForResult
(
intent
:
Intent
,
requestCode
:
Int
)
{
try
{
try
{
startActivityForResult
(
intent
,
requestCode
)
startActivityForResult
(
intent
.
addCategory
(
Intent
.
CATEGORY_OPENABLE
)
,
requestCode
)
return
return
}
catch
(
_
:
ActivityNotFoundException
)
{
}
catch
(
_
:
SecurityException
)
{
}
}
catch
(
_
:
ActivityNotFoundException
)
{
}
catch
(
_
:
SecurityException
)
{
}
(
activity
as
MainActivity
).
snackbar
(
getString
(
R
.
string
.
file_manager_missing
)).
show
()
(
activity
as
MainActivity
).
snackbar
(
getString
(
R
.
string
.
file_manager_missing
)).
show
()
...
@@ -426,31 +432,34 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
...
@@ -426,31 +432,34 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
if
(
resultCode
!=
Activity
.
RESULT_OK
)
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
if
(
resultCode
!=
Activity
.
RESULT_OK
)
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
else
when
(
requestCode
)
{
else
when
(
requestCode
)
{
REQUEST_IMPORT_PROFILES
->
{
REQUEST_IMPORT_PROFILES
->
{
val
feature
=
Core
.
currentProfile
?.
first
var
success
=
false
val
activity
=
activity
as
MainActivity
val
activity
=
activity
as
MainActivity
for
(
uri
in
data
!!
.
datas
)
try
{
try
{
Profile
.
parseJson
(
activity
.
contentResolver
.
openInputStream
(
uri
)
!!
.
bufferedReader
().
readText
(),
ProfileManager
.
createProfilesFromJson
(
data
!!
.
datas
.
asSequence
().
map
{
feature
)
{
activity
.
contentResolver
.
openInputStream
(
it
)
ProfileManager
.
createProfile
(
it
)
})
success
=
true
}
catch
(
e
:
Exception
)
{
activity
.
snackbar
(
e
.
readableMessage
).
show
()
}
}
}
REQUEST_REPLACE_PROFILES
->
{
val
activity
=
activity
as
MainActivity
try
{
ProfileManager
.
createProfilesFromJson
(
data
!!
.
datas
.
asSequence
().
map
{
activity
.
contentResolver
.
openInputStream
(
it
)
},
true
)
}
catch
(
e
:
Exception
)
{
}
catch
(
e
:
Exception
)
{
printLog
(
e
)
activity
.
snackbar
(
e
.
readableMessage
).
show
(
)
}
}
activity
.
snackbar
().
setText
(
if
(
success
)
R
.
string
.
action_import_msg
else
R
.
string
.
action_import_err
)
.
show
()
}
}
REQUEST_EXPORT_PROFILES
->
{
REQUEST_EXPORT_PROFILES
->
{
val
profiles
=
ProfileManager
.
getAllProfiles
()
val
profiles
=
ProfileManager
.
serializeToJson
()
if
(
profiles
!=
null
)
try
{
if
(
profiles
!=
null
)
try
{
val
lookup
=
LongSparseArray
<
Profile
>(
profiles
.
size
).
apply
{
profiles
.
forEach
{
put
(
it
.
id
,
it
)
}
}
requireContext
().
contentResolver
.
openOutputStream
(
data
?.
data
!!
)
!!
.
bufferedWriter
().
use
{
requireContext
().
contentResolver
.
openOutputStream
(
data
?.
data
!!
)
!!
.
bufferedWriter
().
use
{
it
.
write
(
JSONArray
(
profiles
.
map
{
it
.
toJson
(
lookup
)
}.
toTypedArray
())
.
toString
(
2
))
it
.
write
(
profiles
.
toString
(
2
))
}
}
}
catch
(
e
:
Exception
)
{
}
catch
(
e
:
Exception
)
{
printLog
(
e
)
printLog
(
e
)
(
activity
as
MainActivity
).
snackbar
(
e
.
localized
Message
).
show
()
(
activity
as
MainActivity
).
snackbar
(
e
.
readable
Message
).
show
()
}
}
}
}
else
->
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
else
->
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
...
...
mobile/src/main/java/com/github/shadowsocks/QuickToggleShortcut.kt
View file @
be6cf63d
...
@@ -55,14 +55,15 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Callback {
...
@@ -55,14 +55,15 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Callback {
}
}
override
fun
onServiceConnected
(
service
:
IShadowsocksService
)
{
override
fun
onServiceConnected
(
service
:
IShadowsocksService
)
{
when
(
service
.
state
)
{
val
state
=
BaseService
.
State
.
values
()[
service
.
state
]
BaseService
.
STOPPED
->
Core
.
startService
()
when
{
BaseService
.
CONNECTED
->
Core
.
stopService
()
state
.
canStop
->
Core
.
stopService
()
state
==
BaseService
.
State
.
Stopped
->
Core
.
startService
()
}
}
finish
()
finish
()
}
}
override
fun
stateChanged
(
state
:
Int
,
profileName
:
String
?,
msg
:
String
?)
{
}
override
fun
stateChanged
(
state
:
BaseService
.
State
,
profileName
:
String
?,
msg
:
String
?)
{
}
override
fun
onDestroy
()
{
override
fun
onDestroy
()
{
connection
.
disconnect
(
this
)
connection
.
disconnect
(
this
)
...
...
mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt
View file @
be6cf63d
...
@@ -22,9 +22,12 @@ package com.github.shadowsocks.acl
...
@@ -22,9 +22,12 @@ package com.github.shadowsocks.acl
import
android.content.ClipData
import
android.content.ClipData
import
android.content.ClipboardManager
import
android.content.ClipboardManager
import
android.content.DialogInterface
import
android.content.Intent
import
android.content.res.Configuration
import
android.content.res.Configuration
import
android.os.Build
import
android.os.Build
import
android.os.Bundle
import
android.os.Bundle
import
android.os.Parcelable
import
android.text.Editable
import
android.text.Editable
import
android.text.TextWatcher
import
android.text.TextWatcher
import
android.view.*
import
android.view.*
...
@@ -43,10 +46,13 @@ import com.github.shadowsocks.R
...
@@ -43,10 +46,13 @@ import com.github.shadowsocks.R
import
com.github.shadowsocks.ToolbarFragment
import
com.github.shadowsocks.ToolbarFragment
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.net.Subnet
import
com.github.shadowsocks.net.Subnet
import
com.github.shadowsocks.plugin.AlertDialogFragment
import
com.github.shadowsocks.utils.asIterable
import
com.github.shadowsocks.utils.asIterable
import
com.github.shadowsocks.utils.readableMessage
import
com.github.shadowsocks.utils.resolveResourceId
import
com.github.shadowsocks.utils.resolveResourceId
import
com.github.shadowsocks.widget.UndoSnackbarManager
import
com.github.shadowsocks.widget.UndoSnackbarManager
import
com.google.android.material.textfield.TextInputLayout
import
com.google.android.material.textfield.TextInputLayout
import
kotlinx.android.parcel.Parcelize
import
java.net.IDN
import
java.net.IDN
import
java.net.MalformedURLException
import
java.net.MalformedURLException
import
java.net.URL
import
java.net.URL
...
@@ -55,6 +61,8 @@ import java.util.regex.PatternSyntaxException
...
@@ -55,6 +61,8 @@ import java.util.regex.PatternSyntaxException
class
CustomRulesFragment
:
ToolbarFragment
(),
Toolbar
.
OnMenuItemClickListener
,
ActionMode
.
Callback
{
class
CustomRulesFragment
:
ToolbarFragment
(),
Toolbar
.
OnMenuItemClickListener
,
ActionMode
.
Callback
{
companion
object
{
companion
object
{
private
const
val
REQUEST_CODE_ADD
=
1
private
const
val
REQUEST_CODE_EDIT
=
2
private
const
val
TEMPLATE_REGEX_DOMAIN
=
"(^|\\.)%s$"
private
const
val
TEMPLATE_REGEX_DOMAIN
=
"(^|\\.)%s$"
private
const
val
SELECTED_SUBNETS
=
"com.github.shadowsocks.acl.CustomRulesFragment.SELECTED_SUBNETS"
private
const
val
SELECTED_SUBNETS
=
"com.github.shadowsocks.acl.CustomRulesFragment.SELECTED_SUBNETS"
...
@@ -63,6 +71,14 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
...
@@ -63,6 +71,14 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
// unescaped: (?<=^(\(\^\|\\\.\)|\^\(\.\*\\\.\)\?)).*(?=\$$)
// unescaped: (?<=^(\(\^\|\\\.\)|\^\(\.\*\\\.\)\?)).*(?=\$$)
private
val
domainPattern
=
"(?<=^(\\(\\^\\|\\\\\\.\\)|\\^\\(\\.\\*\\\\\\.\\)\\?)).*(?=\\\$\$)"
.
toRegex
()
private
val
domainPattern
=
"(?<=^(\\(\\^\\|\\\\\\.\\)|\\^\\(\\.\\*\\\\\\.\\)\\?)).*(?=\\\$\$)"
.
toRegex
()
@Suppress
(
"FunctionName"
)
private
fun
AclItem
(
item
:
Any
)
=
when
(
item
)
{
is
String
->
AclItem
(
item
,
false
)
is
Subnet
->
AclItem
(
item
.
toString
(),
false
)
is
URL
->
AclItem
(
item
.
toString
(),
true
)
else
->
throw
IllegalArgumentException
(
"item"
)
}
}
}
private
enum
class
Template
{
private
enum
class
Template
{
...
@@ -70,53 +86,50 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
...
@@ -70,53 +86,50 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
Domain
,
Domain
,
Url
;
Url
;
}
}
private
inner
class
AclRuleDialog
(
item
:
Any
=
""
)
:
TextWatcher
,
AdapterView
.
OnItemSelectedListener
{
@Parcelize
val
builder
:
AlertDialog
.
Builder
data class
AclItem
(
val
item
:
String
=
""
,
val
isUrl
:
Boolean
=
false
)
:
Parcelable
{
val
templateSelector
:
Spinner
fun
toAny
()
=
if
(
isUrl
)
URL
(
item
)
else
Subnet
.
fromString
(
item
)
?:
item
val
editText
:
EditText
}
private
val
inputLayout
:
TextInputLayout
@Parcelize
private
lateinit
var
dialog
:
AlertDialog
data class
AclEditResult
(
val
edited
:
AclItem
,
val
replacing
:
AclItem
)
:
Parcelable
class
AclRuleDialogFragment
:
AlertDialogFragment
<
AclItem
,
AclEditResult
>(),
TextWatcher
,
AdapterView
.
OnItemSelectedListener
{
private
lateinit
var
templateSelector
:
Spinner
private
lateinit
var
editText
:
EditText
private
lateinit
var
inputLayout
:
TextInputLayout
private
lateinit
var
positive
:
Button
private
lateinit
var
positive
:
Button
init
{
override
fun
AlertDialog
.
Builder
.
prepare
(
listener
:
DialogInterface
.
OnClickListener
)
{
val
activity
=
requireActivity
()
val
activity
=
requireActivity
()
val
view
=
activity
.
layoutInflater
.
inflate
(
R
.
layout
.
dialog_acl_rule
,
null
)
val
view
=
activity
.
layoutInflater
.
inflate
(
R
.
layout
.
dialog_acl_rule
,
null
)
templateSelector
=
view
.
findViewById
(
R
.
id
.
template_selector
)
templateSelector
=
view
.
findViewById
(
R
.
id
.
template_selector
)
editText
=
view
.
findViewById
(
R
.
id
.
content
)
editText
=
view
.
findViewById
(
R
.
id
.
content
)
inputLayout
=
view
.
findViewById
(
R
.
id
.
content_layout
)
inputLayout
=
view
.
findViewById
(
R
.
id
.
content_layout
)
when
(
item
)
{
templateSelector
.
setSelection
(
Template
.
Generic
.
ordinal
)
is
String
->
{
editText
.
setText
(
arg
.
item
)
val
match
=
domainPattern
.
find
(
item
)
when
{
arg
.
isUrl
->
templateSelector
.
setSelection
(
Template
.
Url
.
ordinal
)
Subnet
.
fromString
(
arg
.
item
)
==
null
->
{
val
match
=
domainPattern
.
find
(
arg
.
item
)
if
(
match
!=
null
)
{
if
(
match
!=
null
)
{
templateSelector
.
setSelection
(
Template
.
Domain
.
ordinal
)
templateSelector
.
setSelection
(
Template
.
Domain
.
ordinal
)
editText
.
setText
(
IDN
.
toUnicode
(
match
.
value
.
replace
(
"\\."
,
"."
),
editText
.
setText
(
IDN
.
toUnicode
(
match
.
value
.
replace
(
"\\."
,
"."
),
IDN
.
ALLOW_UNASSIGNED
or
IDN
.
USE_STD3_ASCII_RULES
))
IDN
.
ALLOW_UNASSIGNED
or
IDN
.
USE_STD3_ASCII_RULES
))
}
else
{
templateSelector
.
setSelection
(
Template
.
Generic
.
ordinal
)
editText
.
setText
(
item
)
}
}
}
}
is
URL
->
{
templateSelector
.
setSelection
(
Template
.
Url
.
ordinal
)
editText
.
setText
(
item
.
toString
())
}
else
->
{
templateSelector
.
setSelection
(
Template
.
Generic
.
ordinal
)
editText
.
setText
(
item
.
toString
())
}
}
}
templateSelector
.
onItemSelectedListener
=
this
templateSelector
.
onItemSelectedListener
=
this
@AclRuleDialogFragment
editText
.
addTextChangedListener
(
this
)
editText
.
addTextChangedListener
(
this
@AclRuleDialogFragment
)
builder
=
AlertDialog
.
Builder
(
activity
)
setTitle
(
R
.
string
.
edit_rule
)
.
setTitle
(
R
.
string
.
edit_rule
)
setPositiveButton
(
android
.
R
.
string
.
ok
,
listener
)
.
setNegativeButton
(
android
.
R
.
string
.
cancel
,
null
)
setNegativeButton
(
android
.
R
.
string
.
cancel
,
null
)
.
setView
(
view
)
if
(
arg
.
item
.
isNotEmpty
())
setNeutralButton
(
R
.
string
.
delete
,
listener
)
setView
(
view
)
}
}
fun
show
()
{
override
fun
onStart
()
{
dialog
=
builder
.
create
()
super
.
onStart
()
dialog
.
show
()
positive
=
(
dialog
as
AlertDialog
).
getButton
(
AlertDialog
.
BUTTON_POSITIVE
)
positive
=
dialog
.
getButton
(
AlertDialog
.
BUTTON_POSITIVE
)
validate
()
validate
()
}
}
...
@@ -134,7 +147,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
...
@@ -134,7 +147,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
if
(
Subnet
.
fromString
(
this
)
==
null
)
toPattern
()
if
(
Subnet
.
fromString
(
this
)
==
null
)
toPattern
()
true
true
}
catch
(
e
:
PatternSyntaxException
)
{
}
catch
(
e
:
PatternSyntaxException
)
{
message
=
e
.
localized
Message
message
=
e
.
readable
Message
false
false
}
}
}
}
...
@@ -142,7 +155,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
...
@@ -142,7 +155,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
IDN
.
toASCII
(
value
.
toString
(),
IDN
.
ALLOW_UNASSIGNED
or
IDN
.
USE_STD3_ASCII_RULES
)
IDN
.
toASCII
(
value
.
toString
(),
IDN
.
ALLOW_UNASSIGNED
or
IDN
.
USE_STD3_ASCII_RULES
)
true
true
}
catch
(
e
:
IllegalArgumentException
)
{
}
catch
(
e
:
IllegalArgumentException
)
{
message
=
e
.
cause
?.
localizedMessage
?:
e
.
localized
Message
message
=
e
.
cause
?.
readableMessage
?:
e
.
readable
Message
false
false
}
}
Template
.
Url
->
try
{
Template
.
Url
->
try
{
...
@@ -150,22 +163,21 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
...
@@ -150,22 +163,21 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
if
(
"http"
.
equals
(
url
.
protocol
,
true
))
message
=
getString
(
R
.
string
.
cleartext_http_warning
)
if
(
"http"
.
equals
(
url
.
protocol
,
true
))
message
=
getString
(
R
.
string
.
cleartext_http_warning
)
true
true
}
catch
(
e
:
MalformedURLException
)
{
}
catch
(
e
:
MalformedURLException
)
{
message
=
e
.
localized
Message
message
=
e
.
readable
Message
false
false
}
}
}
}
inputLayout
.
error
=
message
inputLayout
.
error
=
message
}
}
fun
add
():
Int
?
{
override
val
ret
get
()
=
AclEditResult
(
editText
.
text
.
toString
().
let
{
text
->
val
text
=
editText
.
text
.
toString
()
when
(
Template
.
values
()[
templateSelector
.
selectedItemPosition
])
{
return
when
(
Template
.
values
()[
templateSelector
.
selectedItemPosition
])
{
Template
.
Generic
->
AclItem
(
text
)
Template
.
Generic
->
adapter
.
addToProxy
(
text
)
Template
.
Domain
->
AclItem
(
TEMPLATE_REGEX_DOMAIN
.
format
(
Locale
.
ENGLISH
,
IDN
.
toASCII
(
text
,
Template
.
Domain
->
adapter
.
addHostname
(
TEMPLATE_REGEX_DOMAIN
.
format
(
Locale
.
ENGLISH
,
IDN
.
toASCII
(
text
,
IDN
.
ALLOW_UNASSIGNED
or
IDN
.
USE_STD3_ASCII_RULES
).
replace
(
"."
,
"\\."
)))
IDN
.
ALLOW_UNASSIGNED
or
IDN
.
USE_STD3_ASCII_RULES
).
replace
(
"."
,
"\\."
)))
Template
.
Url
->
adapter
.
addURL
(
URL
(
text
))
Template
.
Url
->
AclItem
(
text
,
true
)
}
}
}
},
arg
)
}
}
private
inner
class
AclRuleViewHolder
(
view
:
View
)
:
RecyclerView
.
ViewHolder
(
view
),
private
inner
class
AclRuleViewHolder
(
view
:
View
)
:
RecyclerView
.
ViewHolder
(
view
),
...
@@ -197,22 +209,10 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
...
@@ -197,22 +209,10 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
}
}
override
fun
onClick
(
v
:
View
?)
{
override
fun
onClick
(
v
:
View
?)
{
if
(
selectedItems
.
isNotEmpty
())
onLongClick
(
v
)
else
{
if
(
selectedItems
.
isNotEmpty
())
onLongClick
(
v
)
val
dialog
=
AclRuleDialog
(
item
)
else
AclRuleDialogFragment
().
withArg
(
AclItem
(
item
)).
show
(
this
@CustomRulesFragment
,
REQUEST_CODE_EDIT
)
dialog
.
builder
.
setNeutralButton
(
R
.
string
.
delete
)
{
_
,
_
->
adapter
.
remove
(
item
)
undoManager
.
remove
(
Pair
(-
1
,
item
))
}
}
.
setPositiveButton
(
android
.
R
.
string
.
ok
)
{
_
,
_
->
override
fun
onLongClick
(
v
:
View
?):
Boolean
{
adapter
.
remove
(
item
)
val
index
=
dialog
.
add
()
?:
adapter
.
add
(
item
)
if
(
index
!=
null
)
list
.
post
{
list
.
scrollToPosition
(
index
)
}
}
dialog
.
show
()
}
}
override
fun
onLongClick
(
p0
:
View
?):
Boolean
{
if
(!
selectedItems
.
add
(
item
))
selectedItems
.
remove
(
item
)
// toggle
if
(!
selectedItems
.
add
(
item
))
selectedItems
.
remove
(
item
)
// toggle
onSelectedItemsUpdated
()
onSelectedItemsUpdated
()
itemView
.
isSelected
=
!
itemView
.
isSelected
itemView
.
isSelected
=
!
itemView
.
isSelected
...
@@ -346,11 +346,8 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
...
@@ -346,11 +346,8 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
}
}
}
}
private
val
isEnabled
get
()
=
when
((
activity
as
MainActivity
).
state
)
{
private
val
isEnabled
get
()
=
(
activity
as
MainActivity
).
state
==
BaseService
.
State
.
Stopped
||
BaseService
.
CONNECTED
->
Core
.
currentProfile
?.
first
?.
route
!=
Acl
.
CUSTOM_RULES
Core
.
currentProfile
?.
first
?.
route
!=
Acl
.
CUSTOM_RULES
BaseService
.
STOPPED
->
true
else
->
false
}
private
val
selectedItems
=
HashSet
<
Any
>()
private
val
selectedItems
=
HashSet
<
Any
>()
private
val
adapter
by
lazy
{
AclRulesAdapter
()
}
private
val
adapter
by
lazy
{
AclRulesAdapter
()
}
...
@@ -427,9 +424,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
...
@@ -427,9 +424,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
override
fun
onMenuItemClick
(
item
:
MenuItem
):
Boolean
=
when
(
item
.
itemId
)
{
override
fun
onMenuItemClick
(
item
:
MenuItem
):
Boolean
=
when
(
item
.
itemId
)
{
R
.
id
.
action_manual_settings
->
{
R
.
id
.
action_manual_settings
->
{
val
dialog
=
AclRuleDialog
()
AclRuleDialogFragment
().
withArg
(
AclItem
()).
show
(
this
,
REQUEST_CODE_ADD
)
dialog
.
builder
.
setPositiveButton
(
android
.
R
.
string
.
ok
)
{
_
,
_
->
dialog
.
add
()
}
dialog
.
show
()
true
true
}
}
R
.
id
.
action_import_clipboard
->
{
R
.
id
.
action_import_clipboard
->
{
...
@@ -451,6 +446,25 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
...
@@ -451,6 +446,25 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
else
->
false
else
->
false
}
}
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
?)
{
val
editing
=
when
(
requestCode
)
{
REQUEST_CODE_ADD
->
false
REQUEST_CODE_EDIT
->
true
else
->
return
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
}
val
ret
by
lazy
{
AlertDialogFragment
.
getRet
<
AclEditResult
>(
data
!!
)
}
when
(
resultCode
)
{
DialogInterface
.
BUTTON_POSITIVE
->
{
if
(
editing
)
adapter
.
remove
(
ret
.
replacing
.
toAny
())
adapter
.
add
(
ret
.
edited
.
toAny
())
?.
also
{
list
.
post
{
list
.
scrollToPosition
(
it
)
}
}
}
DialogInterface
.
BUTTON_NEUTRAL
->
ret
.
replacing
.
toAny
().
let
{
item
->
adapter
.
remove
(
item
)
undoManager
.
remove
(
Pair
(-
1
,
item
))
}
}
}
override
fun
onDetach
()
{
override
fun
onDetach
()
{
undoManager
.
flush
()
undoManager
.
flush
()
mode
?.
finish
()
mode
?.
finish
()
...
...
mobile/src/main/java/com/github/shadowsocks/bg/TileService.kt
View file @
be6cf63d
...
@@ -41,9 +41,9 @@ class TileService : BaseTileService(), ShadowsocksConnection.Callback {
...
@@ -41,9 +41,9 @@ class TileService : BaseTileService(), ShadowsocksConnection.Callback {
private
var
tapPending
=
false
private
var
tapPending
=
false
private
val
connection
=
ShadowsocksConnection
()
private
val
connection
=
ShadowsocksConnection
()
override
fun
stateChanged
(
state
:
Int
,
profileName
:
String
?,
msg
:
String
?)
=
updateTile
(
state
)
{
profileName
}
override
fun
stateChanged
(
state
:
BaseService
.
State
,
profileName
:
String
?,
msg
:
String
?)
=
updateTile
(
state
)
{
profileName
}
override
fun
onServiceConnected
(
service
:
IShadowsocksService
)
{
override
fun
onServiceConnected
(
service
:
IShadowsocksService
)
{
updateTile
(
service
.
state
)
{
service
.
profileName
}
updateTile
(
BaseService
.
State
.
values
()[
service
.
state
]
)
{
service
.
profileName
}
if
(
tapPending
)
{
if
(
tapPending
)
{
tapPending
=
false
tapPending
=
false
onClick
()
onClick
()
...
@@ -63,23 +63,28 @@ class TileService : BaseTileService(), ShadowsocksConnection.Callback {
...
@@ -63,23 +63,28 @@ class TileService : BaseTileService(), ShadowsocksConnection.Callback {
if
(
isLocked
&&
!
DataStore
.
canToggleLocked
)
unlockAndRun
(
this
::
toggle
)
else
toggle
()
if
(
isLocked
&&
!
DataStore
.
canToggleLocked
)
unlockAndRun
(
this
::
toggle
)
else
toggle
()
}
}
private
fun
updateTile
(
serviceState
:
Int
,
profileName
:
()
->
String
?)
{
private
fun
updateTile
(
serviceState
:
BaseService
.
State
,
profileName
:
()
->
String
?)
{
qsTile
?.
apply
{
qsTile
?.
apply
{
label
=
null
label
=
null
when
(
serviceState
)
{
when
(
serviceState
)
{
BaseService
.
STOPPED
->
{
BaseService
.
State
.
Idle
->
throw
IllegalStateException
(
"serviceState"
)
icon
=
iconIdle
BaseService
.
State
.
Connecting
->
{
state
=
Tile
.
STATE_INACTIVE
icon
=
iconBusy
state
=
Tile
.
STATE_ACTIVE
}
}
BaseService
.
CONNECTED
->
{
BaseService
.
State
.
Connected
->
{
icon
=
iconConnected
icon
=
iconConnected
if
(!
keyguard
.
isDeviceLocked
)
label
=
profileName
()
if
(!
keyguard
.
isDeviceLocked
)
label
=
profileName
()
state
=
Tile
.
STATE_ACTIVE
state
=
Tile
.
STATE_ACTIVE
}
}
else
->
{
BaseService
.
State
.
Stopping
->
{
icon
=
iconBusy
icon
=
iconBusy
state
=
Tile
.
STATE_UNAVAILABLE
state
=
Tile
.
STATE_UNAVAILABLE
}
}
BaseService
.
State
.
Stopped
->
{
icon
=
iconIdle
state
=
Tile
.
STATE_INACTIVE
}
}
}
label
=
label
?:
getString
(
R
.
string
.
app_name
)
label
=
label
?:
getString
(
R
.
string
.
app_name
)
updateTile
()
updateTile
()
...
@@ -88,9 +93,11 @@ class TileService : BaseTileService(), ShadowsocksConnection.Callback {
...
@@ -88,9 +93,11 @@ class TileService : BaseTileService(), ShadowsocksConnection.Callback {
private
fun
toggle
()
{
private
fun
toggle
()
{
val
service
=
connection
.
service
val
service
=
connection
.
service
if
(
service
==
null
)
tapPending
=
true
else
when
(
service
.
state
)
{
if
(
service
==
null
)
tapPending
=
true
else
BaseService
.
State
.
values
()[
service
.
state
].
let
{
state
->
BaseService
.
STOPPED
->
Core
.
startService
()
when
{
BaseService
.
CONNECTED
->
Core
.
stopService
()
state
.
canStop
->
Core
.
stopService
()
state
==
BaseService
.
State
.
Stopped
->
Core
.
startService
()
}
}
}
}
}
}
}
mobile/src/main/java/com/github/shadowsocks/widget/ServiceButton.kt
View file @
be6cf63d
...
@@ -68,14 +68,14 @@ class ServiceButton @JvmOverloads constructor(context: Context, attrs: Attribute
...
@@ -68,14 +68,14 @@ class ServiceButton @JvmOverloads constructor(context: Context, attrs: Attribute
return
drawableState
return
drawableState
}
}
fun
changeState
(
state
:
Int
,
animate
:
Boolean
)
{
fun
changeState
(
state
:
BaseService
.
State
,
animate
:
Boolean
)
{
when
(
state
)
{
when
(
state
)
{
BaseService
.
CONNECTING
->
changeState
(
iconConnecting
,
animate
)
BaseService
.
State
.
Connecting
->
changeState
(
iconConnecting
,
animate
)
BaseService
.
CONNECTED
->
changeState
(
iconConnected
,
animate
)
BaseService
.
State
.
Connected
->
changeState
(
iconConnected
,
animate
)
BaseService
.
S
TOPPING
->
changeState
(
iconStopping
,
animate
)
BaseService
.
S
tate
.
Stopping
->
changeState
(
iconStopping
,
animate
)
else
->
changeState
(
iconStopped
,
animate
)
else
->
changeState
(
iconStopped
,
animate
)
}
}
if
(
state
==
BaseService
.
CONNECTED
)
{
if
(
state
==
BaseService
.
State
.
Connected
)
{
checked
=
true
checked
=
true
TooltipCompat
.
setTooltipText
(
this
,
context
.
getString
(
R
.
string
.
stop
))
TooltipCompat
.
setTooltipText
(
this
,
context
.
getString
(
R
.
string
.
stop
))
}
else
{
}
else
{
...
@@ -83,7 +83,7 @@ class ServiceButton @JvmOverloads constructor(context: Context, attrs: Attribute
...
@@ -83,7 +83,7 @@ class ServiceButton @JvmOverloads constructor(context: Context, attrs: Attribute
TooltipCompat
.
setTooltipText
(
this
,
context
.
getString
(
R
.
string
.
connect
))
TooltipCompat
.
setTooltipText
(
this
,
context
.
getString
(
R
.
string
.
connect
))
}
}
refreshDrawableState
()
refreshDrawableState
()
isEnabled
=
state
==
BaseService
.
CONNECTED
||
state
==
BaseService
.
STOPPED
isEnabled
=
state
.
canStop
||
state
==
BaseService
.
State
.
Stopped
}
}
private
fun
counters
(
a
:
AnimatedVectorDrawableCompat
,
b
:
AnimatedVectorDrawableCompat
):
Boolean
=
private
fun
counters
(
a
:
AnimatedVectorDrawableCompat
,
b
:
AnimatedVectorDrawableCompat
):
Boolean
=
...
...
mobile/src/main/java/com/github/shadowsocks/widget/StatsBar.kt
View file @
be6cf63d
...
@@ -65,15 +65,15 @@ class StatsBar @JvmOverloads constructor(context: Context, attrs: AttributeSet?
...
@@ -65,15 +65,15 @@ class StatsBar @JvmOverloads constructor(context: Context, attrs: AttributeSet?
super
.
setOnClickListener
(
l
)
super
.
setOnClickListener
(
l
)
}
}
fun
changeState
(
state
:
Int
)
{
fun
changeState
(
state
:
BaseService
.
State
)
{
val
activity
=
context
as
MainActivity
val
activity
=
context
as
MainActivity
if
(
state
!=
BaseService
.
CONNECTED
)
{
if
(
state
!=
BaseService
.
State
.
Connected
)
{
updateTraffic
(
0
,
0
,
0
,
0
)
updateTraffic
(
0
,
0
,
0
,
0
)
tester
.
status
.
removeObservers
(
activity
)
tester
.
status
.
removeObservers
(
activity
)
if
(
state
!=
BaseService
.
IDLE
)
tester
.
invalidate
()
if
(
state
!=
BaseService
.
State
.
Idle
)
tester
.
invalidate
()
statusText
.
setText
(
when
(
state
)
{
statusText
.
setText
(
when
(
state
)
{
BaseService
.
CONNECTING
->
R
.
string
.
connecting
BaseService
.
State
.
Connecting
->
R
.
string
.
connecting
BaseService
.
S
TOPPING
->
R
.
string
.
stopping
BaseService
.
S
tate
.
Stopping
->
R
.
string
.
stopping
else
->
R
.
string
.
not_connected
else
->
R
.
string
.
not_connected
})
})
}
else
{
}
else
{
...
...
mobile/src/main/res/menu/profile_manager_menu.xml
View file @
be6cf63d
...
@@ -18,6 +18,11 @@
...
@@ -18,6 +18,11 @@
android:id=
"@+id/action_import_file"
android:id=
"@+id/action_import_file"
android:alphabeticShortcut=
"o"
android:alphabeticShortcut=
"o"
android:title=
"@string/action_import_file"
/>
android:title=
"@string/action_import_file"
/>
<item
android:id=
"@+id/action_replace_file"
android:alphabeticShortcut=
"o"
android:title=
"@string/action_replace_file"
app:alphabeticModifiers=
"CTRL|SHIFT"
/>
<item
<item
android:id=
"@+id/action_manual_settings"
android:id=
"@+id/action_manual_settings"
android:title=
"@string/add_profile_methods_manual_settings"
android:title=
"@string/add_profile_methods_manual_settings"
...
...
plugin/CHANGES.md
View file @
be6cf63d
*
1.2.0:
*
New helper class
`AlertDialogFragment`
for creating
`AlertDialog`
that persists through configuration changes;
*
Dependency update:
`com.google.android.material:material:1.1.0-alpha03`
.
*
1.1.0:
*
1.1.0:
*
Having control characters in plugin options is no longer allowed.
*
Having control characters in plugin options is no longer allowed.
If this breaks your plugin, you are doing it wrong.
If this breaks your plugin, you are doing it wrong.
...
...
plugin/build.gradle
View file @
be6cf63d
apply
plugin:
'com.android.library'
apply
plugin:
'com.android.library'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android-extensions'
apply
plugin:
'com.vanniktech.maven.publish'
apply
from:
'gradle-mvn-push.gradle'
@SuppressWarnings
(
"GroovyUnusedDeclaration"
)
def
getRepositoryUsername
()
{
return
hasProperty
(
'NEXUS_USERNAME'
)
?
NEXUS_USERNAME
:
""
}
@SuppressWarnings
(
"GroovyUnusedDeclaration"
)
def
getRepositoryPassword
()
{
return
hasProperty
(
'NEXUS_PASSWORD'
)
?
NEXUS_PASSWORD
:
""
}
android
{
android
{
buildToolsVersion
rootProject
.
buildToolsVersion
buildToolsVersion
rootProject
.
buildToolsVersion
...
@@ -10,10 +20,10 @@ android {
...
@@ -10,10 +20,10 @@ android {
defaultConfig
{
defaultConfig
{
minSdkVersion
rootProject
.
minSdkVersion
minSdkVersion
rootProject
.
minSdkVersion
targetSdkVersion
rootProject
.
sdkVersion
targetSdkVersion
rootProject
.
sdkVersion
versionCode
8
versionCode
Integer
.
parseInt
(
VERSION_CODE
)
versionName
"1.1.0"
versionName
VERSION_NAME
testInstrumentationRunner
"androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunner
"androidx.test
getRepositoryPassword()
.runner.AndroidJUnitRunner"
}
}
buildTypes
{
buildTypes
{
...
@@ -23,6 +33,21 @@ android {
...
@@ -23,6 +33,21 @@ android {
}
}
}
}
androidExtensions
{
experimental
=
true
}
mavenPublish
{
targets
{
uploadArchives
{
releaseRepositoryUrl
=
"https://oss.sonatype.org/service/local/staging/deploy/maven2/"
snapshotRepositoryUrl
=
"https://oss.sonatype.org/content/repositories/snapshots/"
repositoryUsername
=
getRepositoryUsername
()
repositoryPassword
=
getRepositoryPassword
()
}
}
}
dependencies
{
dependencies
{
api
'androidx.core:core-ktx:1.0.1'
api
'androidx.core:core-ktx:1.0.1'
api
'com.google.android.material:material:1.1.0-alpha03'
api
'com.google.android.material:material:1.1.0-alpha03'
...
...
plugin/gradle-mvn-push.gradle
deleted
100644 → 0
View file @
f4171711
/*
* Copyright 2013 Chris Banes
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
apply
plugin:
'maven'
apply
plugin:
'signing'
@SuppressWarnings
([
"GroovyUnusedDeclaration"
,
"GrMethodMayBeStatic"
])
def
isReleaseBuild
()
{
return
!
android
.
defaultConfig
.
versionName
.
contains
(
"SNAPSHOT"
)
}
@SuppressWarnings
(
"GroovyUnusedDeclaration"
)
def
getReleaseRepositoryUrl
()
{
return
hasProperty
(
'RELEASE_REPOSITORY_URL'
)
?
RELEASE_REPOSITORY_URL
:
"https://oss.sonatype.org/service/local/staging/deploy/maven2/"
}
@SuppressWarnings
(
"GroovyUnusedDeclaration"
)
def
getSnapshotRepositoryUrl
()
{
return
hasProperty
(
'SNAPSHOT_REPOSITORY_URL'
)
?
SNAPSHOT_REPOSITORY_URL
:
"https://oss.sonatype.org/content/repositories/snapshots/"
}
@SuppressWarnings
(
"GroovyUnusedDeclaration"
)
def
getRepositoryUsername
()
{
return
hasProperty
(
'NEXUS_USERNAME'
)
?
NEXUS_USERNAME
:
""
}
@SuppressWarnings
(
"GroovyUnusedDeclaration"
)
def
getRepositoryPassword
()
{
return
hasProperty
(
'NEXUS_PASSWORD'
)
?
NEXUS_PASSWORD
:
""
}
afterEvaluate
{
project
->
uploadArchives
{
repositories
{
mavenDeployer
{
beforeDeployment
{
MavenDeployment
deployment
->
signing
.
signPom
(
deployment
)
}
pom
.
groupId
=
'com.github.shadowsocks'
pom
.
artifactId
=
'plugin'
pom
.
version
=
android
.
defaultConfig
.
versionName
repository
(
url:
getReleaseRepositoryUrl
())
{
authentication
(
userName:
getRepositoryUsername
(),
password:
getRepositoryPassword
())
}
snapshotRepository
(
url:
getSnapshotRepositoryUrl
())
{
authentication
(
userName:
getRepositoryUsername
(),
password:
getRepositoryPassword
())
}
pom
.
project
{
name
'Shadowsocks Plugin'
packaging
'aar'
description
'Shadowsocks Plugin'
url
'https://github.com/shadowsocks/shadowsocks-android'
scm
{
url
'https://github.com/shadowsocks/shadowsocks-android.git'
connection
'scm:git:git://github.com/shadowsocks/shadowsocks-android.git'
developerConnection
'scm:git:git@github.com:shadowsocks/shadowsocks-android.git'
}
licenses
{
license
{
name
'GPLv3'
url
'https://www.gnu.org/licenses/gpl-3.0.html'
distribution
'repo'
}
}
developers
{
developer
{
id
'madeye'
name
'Max Lv'
url
'https://github.com/madeye'
}
developer
{
id
'Mygod'
name
'Mygod Studio'
url
'https://github.com/Mygod'
}
}
}
}
}
}
signing
{
required
{
isReleaseBuild
()
&&
gradle
.
taskGraph
.
hasTask
(
"uploadArchives"
)
}
sign
configurations
.
archives
}
android
.
libraryVariants
.
all
{
variant
->
def
javadocTask
=
task
(
"generate${variant.name.capitalize()}Javadoc"
,
type:
Javadoc
)
{
description
"Generates Javadoc for $variant.name."
source
=
android
.
sourceSets
.
main
.
java
.
srcDirs
classpath
+=
project
.
files
(
android
.
getBootClasspath
().
join
(
File
.
pathSeparator
))
exclude
'**/*.kt'
exclude
'**/BuildConfig.java'
exclude
'**/R.java'
}
def
jarJavadocTask
=
task
(
"jar${variant.name.capitalize()}Javadoc"
,
type:
Jar
)
{
description
"Generate Javadoc Jar for $variant.name"
classifier
=
'javadoc'
from
javadocTask
.
destinationDir
}
jarJavadocTask
.
dependsOn
javadocTask
artifacts
.
add
(
'archives'
,
jarJavadocTask
)
def
jarSourceTask
=
task
(
"jar${variant.name.capitalize()}Sources"
,
type:
Jar
)
{
description
"Generates Java Sources for $variant.name."
classifier
=
'sources'
from
android
.
sourceSets
.
main
.
java
.
srcDirs
}
artifacts
.
add
(
'archives'
,
jarSourceTask
)
}
}
plugin/gradle.properties
0 → 100644
View file @
be6cf63d
GROUP
=
com.github.shadowsocks
VERSION_NAME
=
1.2.0
VERSION_CODE
=
9
POM_ARTIFACT_ID
=
plugin
POM_NAME
=
Shadowsocks Plugin
POM_PACKAGING
=
aar
POM_DESCRIPTION
=
SIP003 plugin for Shadowsocks
POM_INCEPTION_YEAR
=
2018
POM_URL
=
https://github.com/shadowsocks/shadowsocks-android
POM_SCM_URL
=
https://github.com/shadowsocks/shadowsocks-android
POM_SCM_CONNECTION
=
scm:git:git://github.com/shadowsocks/shadowsocks-android.git
POM_SCM_DEV_CONNECTION
=
scm:git:ssh://git@github.com/shadowsocks/shadowsocks-android.git
POM_LICENCE_NAME
=
The GNU General Public License v3.0
POM_LICENCE_URL
=
https://www.gnu.org/licenses/gpl-3.0.html
POM_LICENCE_DIST
=
repo
POM_DEVELOPER_ID
=
Mygod
POM_DEVELOPER_NAME
=
Mygod Studio
plugin/src/main/java/com/github/shadowsocks/plugin/AlertDialogFragment.kt
0 → 100644
View file @
be6cf63d
/*******************************************************************************
* *
* Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* 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
com.github.shadowsocks.plugin
import
android.app.Activity
import
android.content.DialogInterface
import
android.content.Intent
import
android.os.Bundle
import
android.os.Parcelable
import
androidx.appcompat.app.AlertDialog
import
androidx.appcompat.app.AppCompatDialogFragment
import
androidx.fragment.app.Fragment
import
kotlinx.android.parcel.Parcelize
/**
* Based on: https://android.googlesource.com/platform/packages/apps/ExactCalculator/+/8c43f06/src/com/android/calculator2/AlertDialogFragment.java
*/
abstract
class
AlertDialogFragment
<
Arg
:
Parcelable
,
Ret
:
Parcelable
>
:
AppCompatDialogFragment
(),
DialogInterface
.
OnClickListener
{
companion
object
{
private
const
val
KEY_ARG
=
"arg"
private
const
val
KEY_RET
=
"ret"
fun
<
T
:
Parcelable
>
getRet
(
data
:
Intent
)
=
data
.
extras
!!
.
getParcelable
<
T
>(
KEY_RET
)
!!
}
protected
abstract
fun
AlertDialog
.
Builder
.
prepare
(
listener
:
DialogInterface
.
OnClickListener
)
protected
val
arg
by
lazy
{
arguments
!!
.
getParcelable
<
Arg
>(
KEY_ARG
)
!!
}
protected
open
val
ret
:
Ret
?
get
()
=
null
fun
withArg
(
arg
:
Arg
)
=
apply
{
arguments
=
Bundle
().
apply
{
putParcelable
(
KEY_ARG
,
arg
)
}
}
override
fun
onCreateDialog
(
savedInstanceState
:
Bundle
?):
AlertDialog
=
AlertDialog
.
Builder
(
requireContext
()).
also
{
it
.
prepare
(
this
)
}.
create
()
override
fun
onClick
(
dialog
:
DialogInterface
?,
which
:
Int
)
{
targetFragment
?.
onActivityResult
(
targetRequestCode
,
which
,
ret
?.
let
{
Intent
().
replaceExtras
(
Bundle
().
apply
{
putParcelable
(
KEY_RET
,
it
)
})
})
}
override
fun
onDismiss
(
dialog
:
DialogInterface
)
{
super
.
onDismiss
(
dialog
)
targetFragment
?.
onActivityResult
(
targetRequestCode
,
Activity
.
RESULT_CANCELED
,
null
)
}
fun
show
(
target
:
Fragment
,
requestCode
:
Int
=
0
,
tag
:
String
=
javaClass
.
simpleName
)
{
setTargetFragment
(
target
,
requestCode
)
show
(
target
.
fragmentManager
?:
return
,
tag
)
}
}
@Parcelize
class
Empty
:
Parcelable
tv/src/main/java/com/github/shadowsocks/tv/MainFragment.kt
View file @
be6cf63d
...
@@ -38,7 +38,7 @@ class MainFragment : LeanbackSettingsFragmentCompat() {
...
@@ -38,7 +38,7 @@ class MainFragment : LeanbackSettingsFragmentCompat() {
override
fun
onPreferenceDisplayDialog
(
caller
:
PreferenceFragmentCompat
,
pref
:
Preference
?):
Boolean
{
override
fun
onPreferenceDisplayDialog
(
caller
:
PreferenceFragmentCompat
,
pref
:
Preference
?):
Boolean
{
if
(
pref
?.
key
==
Key
.
id
)
{
if
(
pref
?.
key
==
Key
.
id
)
{
if
((
childFragmentManager
.
findFragmentById
(
R
.
id
.
settings_preference_fragment_container
)
if
((
childFragmentManager
.
findFragmentById
(
R
.
id
.
settings_preference_fragment_container
)
as
MainPreferenceFragment
).
state
==
BaseService
.
S
TOPPED
)
{
as
MainPreferenceFragment
).
state
==
BaseService
.
S
tate
.
Stopped
)
{
startPreferenceFragment
(
ProfilesDialogFragment
().
apply
{
startPreferenceFragment
(
ProfilesDialogFragment
().
apply
{
arguments
=
bundleOf
(
Pair
(
LeanbackPreferenceDialogFragmentCompat
.
ARG_KEY
,
Key
.
id
))
arguments
=
bundleOf
(
Pair
(
LeanbackPreferenceDialogFragmentCompat
.
ARG_KEY
,
Key
.
id
))
setTargetFragment
(
caller
,
0
)
setTargetFragment
(
caller
,
0
)
...
...
tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt
View file @
be6cf63d
...
@@ -30,7 +30,6 @@ import android.os.DeadObjectException
...
@@ -30,7 +30,6 @@ import android.os.DeadObjectException
import
android.os.Handler
import
android.os.Handler
import
android.text.format.Formatter
import
android.text.format.Formatter
import
android.util.Log
import
android.util.Log
import
android.util.LongSparseArray
import
android.widget.Toast
import
android.widget.Toast
import
androidx.leanback.preference.LeanbackPreferenceFragmentCompat
import
androidx.leanback.preference.LeanbackPreferenceFragmentCompat
import
androidx.lifecycle.Observer
import
androidx.lifecycle.Observer
...
@@ -44,7 +43,6 @@ import com.github.shadowsocks.aidl.IShadowsocksService
...
@@ -44,7 +43,6 @@ import com.github.shadowsocks.aidl.IShadowsocksService
import
com.github.shadowsocks.aidl.ShadowsocksConnection
import
com.github.shadowsocks.aidl.ShadowsocksConnection
import
com.github.shadowsocks.aidl.TrafficStats
import
com.github.shadowsocks.aidl.TrafficStats
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.bg.BaseService
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.database.ProfileManager
import
com.github.shadowsocks.net.HttpsTest
import
com.github.shadowsocks.net.HttpsTest
import
com.github.shadowsocks.net.TcpFastOpen
import
com.github.shadowsocks.net.TcpFastOpen
...
@@ -54,13 +52,13 @@ import com.github.shadowsocks.preference.PortPreferenceListener
...
@@ -54,13 +52,13 @@ import com.github.shadowsocks.preference.PortPreferenceListener
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.Key
import
com.github.shadowsocks.utils.datas
import
com.github.shadowsocks.utils.datas
import
com.github.shadowsocks.utils.printLog
import
com.github.shadowsocks.utils.printLog
import
org.json.JSONArray
import
com.github.shadowsocks.utils.readableMessage
class
MainPreferenceFragment
:
LeanbackPreferenceFragmentCompat
(),
ShadowsocksConnection
.
Callback
,
class
MainPreferenceFragment
:
LeanbackPreferenceFragmentCompat
(),
ShadowsocksConnection
.
Callback
,
OnPreferenceDataStoreChangeListener
{
OnPreferenceDataStoreChangeListener
{
companion
object
{
companion
object
{
private
const
val
REQUEST_CONNECT
=
1
private
const
val
REQUEST_CONNECT
=
1
private
const
val
REQUEST_
IMPORT
_PROFILES
=
2
private
const
val
REQUEST_
REPLACE
_PROFILES
=
2
private
const
val
REQUEST_EXPORT_PROFILES
=
3
private
const
val
REQUEST_EXPORT_PROFILES
=
3
private
const
val
TAG
=
"MainPreferenceFragment"
private
const
val
TAG
=
"MainPreferenceFragment"
}
}
...
@@ -88,9 +86,9 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
...
@@ -88,9 +86,9 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
private
lateinit
var
tester
:
HttpsTest
private
lateinit
var
tester
:
HttpsTest
// service
// service
var
state
=
BaseService
.
IDLE
var
state
=
BaseService
.
State
.
Idle
private
set
private
set
override
fun
stateChanged
(
state
:
Int
,
profileName
:
String
?,
msg
:
String
?)
=
changeState
(
state
,
msg
)
override
fun
stateChanged
(
state
:
BaseService
.
State
,
profileName
:
String
?,
msg
:
String
?)
=
changeState
(
state
,
msg
)
override
fun
trafficUpdated
(
profileId
:
Long
,
stats
:
TrafficStats
)
{
override
fun
trafficUpdated
(
profileId
:
Long
,
stats
:
TrafficStats
)
{
if
(
profileId
==
0L
)
requireContext
().
let
{
context
->
if
(
profileId
==
0L
)
requireContext
().
let
{
context
->
this
.
stats
.
summary
=
getString
(
R
.
string
.
stat_summary
,
this
.
stats
.
summary
=
getString
(
R
.
string
.
stat_summary
,
...
@@ -101,26 +99,26 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
...
@@ -101,26 +99,26 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
}
}
}
}
private
fun
changeState
(
state
:
Int
,
msg
:
String
?
=
null
)
{
private
fun
changeState
(
state
:
BaseService
.
State
,
msg
:
String
?
=
null
)
{
fab
.
isEnabled
=
state
==
BaseService
.
STOPPED
||
state
==
BaseService
.
CONNECTED
fab
.
isEnabled
=
state
.
canStop
||
state
==
BaseService
.
State
.
Stopped
fab
.
setTitle
(
when
(
state
)
{
fab
.
setTitle
(
when
(
state
)
{
BaseService
.
CONNECTING
->
R
.
string
.
connecting
BaseService
.
State
.
Connecting
->
R
.
string
.
connecting
BaseService
.
CONNECTED
->
R
.
string
.
stop
BaseService
.
State
.
Connected
->
R
.
string
.
stop
BaseService
.
S
TOPPING
->
R
.
string
.
stopping
BaseService
.
S
tate
.
Stopping
->
R
.
string
.
stopping
else
->
R
.
string
.
connect
else
->
R
.
string
.
connect
})
})
stats
.
setTitle
(
R
.
string
.
connection_test_pending
)
stats
.
setTitle
(
R
.
string
.
connection_test_pending
)
stats
.
isVisible
=
state
==
BaseService
.
CONNECTED
stats
.
isVisible
=
state
==
BaseService
.
State
.
Connected
if
(
state
!=
BaseService
.
CONNECTED
)
{
if
(
state
!=
BaseService
.
State
.
Connected
)
{
trafficUpdated
(
0
,
TrafficStats
())
trafficUpdated
(
0
,
TrafficStats
())
tester
.
status
.
removeObservers
(
this
)
tester
.
status
.
removeObservers
(
this
)
if
(
state
!=
BaseService
.
IDLE
)
tester
.
invalidate
()
if
(
state
!=
BaseService
.
State
.
Idle
)
tester
.
invalidate
()
}
else
tester
.
status
.
observe
(
this
,
Observer
{
}
else
tester
.
status
.
observe
(
this
,
Observer
{
it
.
retrieve
(
stats
::
setTitle
)
{
Toast
.
makeText
(
requireContext
(),
it
,
Toast
.
LENGTH_LONG
).
show
()
}
it
.
retrieve
(
stats
::
setTitle
)
{
Toast
.
makeText
(
requireContext
(),
it
,
Toast
.
LENGTH_LONG
).
show
()
}
})
})
if
(
msg
!=
null
)
Toast
.
makeText
(
requireContext
(),
getString
(
R
.
string
.
vpn_error
,
msg
),
Toast
.
LENGTH_SHORT
).
show
()
if
(
msg
!=
null
)
Toast
.
makeText
(
requireContext
(),
getString
(
R
.
string
.
vpn_error
,
msg
),
Toast
.
LENGTH_SHORT
).
show
()
this
.
state
=
state
this
.
state
=
state
if
(
state
==
BaseService
.
S
TOPPED
)
{
if
(
state
==
BaseService
.
S
tate
.
Stopped
)
{
controlImport
.
isEnabled
=
true
controlImport
.
isEnabled
=
true
tfo
.
isEnabled
=
true
tfo
.
isEnabled
=
true
serviceMode
.
isEnabled
=
true
serviceMode
.
isEnabled
=
true
...
@@ -141,11 +139,11 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
...
@@ -141,11 +139,11 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
private
val
handler
=
Handler
()
private
val
handler
=
Handler
()
private
val
connection
=
ShadowsocksConnection
(
handler
,
true
)
private
val
connection
=
ShadowsocksConnection
(
handler
,
true
)
override
fun
onServiceConnected
(
service
:
IShadowsocksService
)
=
changeState
(
try
{
override
fun
onServiceConnected
(
service
:
IShadowsocksService
)
=
changeState
(
try
{
service
.
state
BaseService
.
State
.
values
()[
service
.
state
]
}
catch
(
_
:
DeadObjectException
)
{
}
catch
(
_
:
DeadObjectException
)
{
BaseService
.
IDLE
BaseService
.
State
.
Idle
})
})
override
fun
onServiceDisconnected
()
=
changeState
(
BaseService
.
IDLE
)
override
fun
onServiceDisconnected
()
=
changeState
(
BaseService
.
State
.
Idle
)
override
fun
onBinderDied
()
{
override
fun
onBinderDied
()
{
connection
.
disconnect
(
requireContext
())
connection
.
disconnect
(
requireContext
())
connection
.
connect
(
requireContext
(),
this
)
connection
.
connect
(
requireContext
(),
this
)
...
@@ -203,7 +201,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
...
@@ -203,7 +201,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
}
}
tester
=
ViewModelProviders
.
of
(
this
).
get
()
tester
=
ViewModelProviders
.
of
(
this
).
get
()
changeState
(
BaseService
.
IDLE
)
// reset everything to init state
changeState
(
BaseService
.
State
.
Idle
)
// reset everything to init state
connection
.
connect
(
requireContext
(),
this
)
connection
.
connect
(
requireContext
(),
this
)
DataStore
.
publicStore
.
registerChangeListener
(
this
)
DataStore
.
publicStore
.
registerChangeListener
(
this
)
}
}
...
@@ -228,7 +226,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
...
@@ -228,7 +226,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
fun
startService
()
{
fun
startService
()
{
when
{
when
{
state
!=
BaseService
.
S
TOPPED
->
return
state
!=
BaseService
.
S
tate
.
Stopped
->
return
DataStore
.
serviceMode
==
Key
.
modeVpn
->
{
DataStore
.
serviceMode
==
Key
.
modeVpn
->
{
val
intent
=
VpnService
.
prepare
(
requireContext
())
val
intent
=
VpnService
.
prepare
(
requireContext
())
if
(
intent
!=
null
)
startActivityForResult
(
intent
,
REQUEST_CONNECT
)
if
(
intent
!=
null
)
startActivityForResult
(
intent
,
REQUEST_CONNECT
)
...
@@ -254,7 +252,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
...
@@ -254,7 +252,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
override
fun
onPreferenceTreeClick
(
preference
:
Preference
?)
=
when
(
preference
?.
key
)
{
override
fun
onPreferenceTreeClick
(
preference
:
Preference
?)
=
when
(
preference
?.
key
)
{
Key
.
id
->
{
Key
.
id
->
{
if
(
state
==
BaseService
.
CONNECTED
)
Core
.
stopService
()
if
(
state
==
BaseService
.
State
.
Connected
)
Core
.
stopService
()
true
true
}
}
Key
.
controlStats
->
{
Key
.
controlStats
->
{
...
@@ -263,15 +261,14 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
...
@@ -263,15 +261,14 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
}
}
Key
.
controlImport
->
{
Key
.
controlImport
->
{
startFilesForResult
(
Intent
(
Intent
.
ACTION_GET_CONTENT
).
apply
{
startFilesForResult
(
Intent
(
Intent
.
ACTION_GET_CONTENT
).
apply
{
addCategory
(
Intent
.
CATEGORY_OPENABLE
)
type
=
"application/*"
type
=
"application/json"
putExtra
(
Intent
.
EXTRA_ALLOW_MULTIPLE
,
true
)
putExtra
(
Intent
.
EXTRA_ALLOW_MULTIPLE
,
true
)
},
REQUEST_IMPORT_PROFILES
)
putExtra
(
Intent
.
EXTRA_MIME_TYPES
,
arrayOf
(
"application/*"
,
"text/*"
))
},
REQUEST_REPLACE_PROFILES
)
true
true
}
}
Key
.
controlExport
->
{
Key
.
controlExport
->
{
startFilesForResult
(
Intent
(
Intent
.
ACTION_CREATE_DOCUMENT
).
apply
{
startFilesForResult
(
Intent
(
Intent
.
ACTION_CREATE_DOCUMENT
).
apply
{
addCategory
(
Intent
.
CATEGORY_OPENABLE
)
type
=
"application/json"
type
=
"application/json"
putExtra
(
Intent
.
EXTRA_TITLE
,
"profiles.json"
)
// optional title that can be edited
putExtra
(
Intent
.
EXTRA_TITLE
,
"profiles.json"
)
// optional title that can be edited
},
REQUEST_EXPORT_PROFILES
)
},
REQUEST_EXPORT_PROFILES
)
...
@@ -280,9 +277,9 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
...
@@ -280,9 +277,9 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
else
->
super
.
onPreferenceTreeClick
(
preference
)
else
->
super
.
onPreferenceTreeClick
(
preference
)
}
}
private
fun
startFilesForResult
(
intent
:
Intent
?
,
requestCode
:
Int
)
{
private
fun
startFilesForResult
(
intent
:
Intent
,
requestCode
:
Int
)
{
try
{
try
{
startActivityForResult
(
intent
,
requestCode
)
startActivityForResult
(
intent
.
addCategory
(
Intent
.
CATEGORY_OPENABLE
)
,
requestCode
)
return
return
}
catch
(
_
:
ActivityNotFoundException
)
{
}
catch
(
_
:
SecurityException
)
{
}
}
catch
(
_
:
ActivityNotFoundException
)
{
}
catch
(
_
:
SecurityException
)
{
}
Toast
.
makeText
(
requireContext
(),
R
.
string
.
file_manager_missing
,
Toast
.
LENGTH_SHORT
).
show
()
Toast
.
makeText
(
requireContext
(),
R
.
string
.
file_manager_missing
,
Toast
.
LENGTH_SHORT
).
show
()
...
@@ -294,41 +291,30 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
...
@@ -294,41 +291,30 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
Toast
.
makeText
(
requireContext
(),
R
.
string
.
vpn_permission_denied
,
Toast
.
LENGTH_SHORT
).
show
()
Toast
.
makeText
(
requireContext
(),
R
.
string
.
vpn_permission_denied
,
Toast
.
LENGTH_SHORT
).
show
()
Crashlytics
.
log
(
Log
.
ERROR
,
TAG
,
"Failed to start VpnService from onActivityResult: $data"
)
Crashlytics
.
log
(
Log
.
ERROR
,
TAG
,
"Failed to start VpnService from onActivityResult: $data"
)
}
}
REQUEST_
IMPORT
_PROFILES
->
{
REQUEST_
REPLACE
_PROFILES
->
{
if
(
resultCode
!=
Activity
.
RESULT_OK
)
return
if
(
resultCode
!=
Activity
.
RESULT_OK
)
return
val
profiles
=
ProfileManager
.
getAllProfiles
()
?.
associateBy
{
it
.
formattedAddress
}
val
feature
=
profiles
?.
values
?.
singleOrNull
{
it
.
id
==
DataStore
.
profileId
}
val
lazyClear
=
lazy
{
ProfileManager
.
clear
()
}
val
context
=
requireContext
()
val
context
=
requireContext
()
for
(
uri
in
data
!!
.
datas
)
try
{
try
{
Profile
.
parseJson
(
context
.
contentResolver
.
openInputStream
(
uri
)
!!
.
bufferedReader
().
readText
(),
ProfileManager
.
createProfilesFromJson
(
data
!!
.
datas
.
asSequence
().
map
{
feature
)
{
context
.
contentResolver
.
openInputStream
(
it
)
lazyClear
.
value
},
true
)
// if two profiles has the same address, treat them as the same profile and copy stats over
profiles
?.
get
(
it
.
formattedAddress
)
?.
apply
{
it
.
tx
=
tx
it
.
rx
=
rx
}
ProfileManager
.
createProfile
(
it
)
}
}
catch
(
e
:
Exception
)
{
}
catch
(
e
:
Exception
)
{
printLog
(
e
)
printLog
(
e
)
Toast
.
makeText
(
context
,
e
.
localized
Message
,
Toast
.
LENGTH_SHORT
).
show
()
Toast
.
makeText
(
context
,
e
.
readable
Message
,
Toast
.
LENGTH_SHORT
).
show
()
}
}
populateProfiles
()
populateProfiles
()
}
}
REQUEST_EXPORT_PROFILES
->
{
REQUEST_EXPORT_PROFILES
->
{
if
(
resultCode
!=
Activity
.
RESULT_OK
)
return
if
(
resultCode
!=
Activity
.
RESULT_OK
)
return
val
profiles
=
ProfileManager
.
getAllProfiles
()
val
profiles
=
ProfileManager
.
serializeToJson
()
val
context
=
requireContext
()
val
context
=
requireContext
()
if
(
profiles
!=
null
)
try
{
if
(
profiles
!=
null
)
try
{
val
lookup
=
LongSparseArray
<
Profile
>(
profiles
.
size
).
apply
{
profiles
.
forEach
{
put
(
it
.
id
,
it
)
}
}
context
.
contentResolver
.
openOutputStream
(
data
?.
data
!!
)
!!
.
bufferedWriter
().
use
{
context
.
contentResolver
.
openOutputStream
(
data
?.
data
!!
)
!!
.
bufferedWriter
().
use
{
it
.
write
(
JSONArray
(
profiles
.
map
{
it
.
toJson
(
lookup
)
}.
toTypedArray
())
.
toString
(
2
))
it
.
write
(
profiles
.
toString
(
2
))
}
}
}
catch
(
e
:
Exception
)
{
}
catch
(
e
:
Exception
)
{
printLog
(
e
)
printLog
(
e
)
Toast
.
makeText
(
context
,
e
.
localized
Message
,
Toast
.
LENGTH_SHORT
).
show
()
Toast
.
makeText
(
context
,
e
.
readable
Message
,
Toast
.
LENGTH_SHORT
).
show
()
}
}
}
}
else
->
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
else
->
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
...
...
tv/src/main/res/xml/pref_main.xml
View file @
be6cf63d
...
@@ -13,7 +13,7 @@
...
@@ -13,7 +13,7 @@
app:summary=
"@string/stat_summary"
/>
app:summary=
"@string/stat_summary"
/>
<Preference
<Preference
app:key=
"control.import"
app:key=
"control.import"
app:title=
"@string/action_
import
_file"
/>
app:title=
"@string/action_
replace
_file"
/>
<Preference
<Preference
app:key=
"control.export"
app:key=
"control.export"
app:title=
"@string/action_export_file"
/>
app:title=
"@string/action_export_file"
/>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment