Commit 08d240a6 authored by Daniel Wolf's avatar Daniel Wolf
Browse files

Merge branch 'master' of https://git.frostnerd.com/PublicAndroidApps/smokescreen into translations

parents bc62cfc4 5a001f40
Pipeline #5076 passed with stages
in 1 minute and 5 seconds
...@@ -107,13 +107,15 @@ dependencies { ...@@ -107,13 +107,15 @@ dependencies {
implementation 'com.frostnerd.utilskt:preferences:1.5.14' // https://git.frostnerd.com/AndroidUtils/preferenceskt (Accessible after logging in [free of charge]) implementation 'com.frostnerd.utilskt:preferences:1.5.14' // https://git.frostnerd.com/AndroidUtils/preferenceskt (Accessible after logging in [free of charge])
implementation 'com.frostnerd.utilskt:navigationdraweractivity:1.3.19' // https://git.frostnerd.com/AndroidUtils/navigationdraweractivity (Accessible after logging in [free of charge]) implementation 'com.frostnerd.utilskt:navigationdraweractivity:1.3.19' // https://git.frostnerd.com/AndroidUtils/navigationdraweractivity (Accessible after logging in [free of charge])
implementation 'com.frostnerd.utilskt:encrypteddnstunnelproxy:1.5.135' // https://git.frostnerd.com/AndroidUtils/encrypteddnstunnelproxy implementation 'com.frostnerd.utilskt:encrypteddnstunnelproxy:1.5.136' // https://git.frostnerd.com/AndroidUtils/encrypteddnstunnelproxy
implementation 'com.frostnerd.utilskt:general:1.0.16' // https://git.frostnerd.com/AndroidUtils/generalkt (Accessible after logging in [free of charge]) implementation 'com.frostnerd.utilskt:general:1.0.16' // https://git.frostnerd.com/AndroidUtils/generalkt (Accessible after logging in [free of charge])
implementation 'com.frostnerd.utilskt:adapters:1.1.1' // https://git.frostnerd.com/AndroidUtils/Adapters (Accessible after logging in [free of charge]) implementation 'com.frostnerd.utilskt:adapters:1.1.1' // https://git.frostnerd.com/AndroidUtils/Adapters (Accessible after logging in [free of charge])
implementation 'androidx.work:work-runtime:2.2.0-rc01'
implementation 'androidx.appcompat:appcompat:1.1.0-rc01' implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation "androidx.preference:preference:1.1.0-rc01" implementation "androidx.preference:preference:1.1.0-rc01"
implementation "com.google.android.material:material:1.1.0-alpha08" implementation "com.google.android.material:material:1.1.0-alpha09"
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0-alpha01'
implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version" kapt "androidx.room:room-compiler:$room_version"
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 10, "version": 10,
"identityHash": "daac9efbbf9d89b9aa10f7ad54ac736a", "identityHash": "5d29ef2a948e6e550e83fcef5932253d",
"entities": [ "entities": [
{ {
"tableName": "CachedResponse", "tableName": "CachedResponse",
...@@ -194,7 +194,7 @@ ...@@ -194,7 +194,7 @@
}, },
{ {
"tableName": "HostSource", "tableName": "HostSource",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `enabled` INTEGER NOT NULL, `ruleCount` INTEGER, `name` TEXT NOT NULL, `source` TEXT NOT NULL, `whitelistSource` INTEGER NOT NULL)", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `enabled` INTEGER NOT NULL, `ruleCount` INTEGER, `checksum` TEXT, `name` TEXT NOT NULL, `source` TEXT NOT NULL, `whitelistSource` INTEGER NOT NULL)",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
...@@ -214,6 +214,12 @@ ...@@ -214,6 +214,12 @@
"affinity": "INTEGER", "affinity": "INTEGER",
"notNull": false "notNull": false
}, },
{
"fieldPath": "checksum",
"columnName": "checksum",
"affinity": "TEXT",
"notNull": false
},
{ {
"fieldPath": "name", "fieldPath": "name",
"columnName": "name", "columnName": "name",
...@@ -246,7 +252,7 @@ ...@@ -246,7 +252,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'daac9efbbf9d89b9aa10f7ad54ac736a')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5d29ef2a948e6e550e83fcef5932253d')"
] ]
} }
} }
\ No newline at end of file
...@@ -93,6 +93,7 @@ val MIGRATION_8_9 = migration(8, 9) { ...@@ -93,6 +93,7 @@ val MIGRATION_8_9 = migration(8, 9) {
val MIGRATION_9_10 = migration(9, 10) { val MIGRATION_9_10 = migration(9, 10) {
Logger.logIfOpen("DB_MIGRATION", "Migrating from 9 to 10") Logger.logIfOpen("DB_MIGRATION", "Migrating from 9 to 10")
it.execSQL("ALTER TABLE `DnsRule` ADD COLUMN `isWildcard` INTEGER NOT NULL DEFAULT 0") it.execSQL("ALTER TABLE `DnsRule` ADD COLUMN `isWildcard` INTEGER NOT NULL DEFAULT 0")
it.execSQL("ALTER TABLE `HostSource` ADD COLUMN `checksum` TEXT DEFAULT NULL")
Logger.logIfOpen("DB_MIGRATION", "Migration from 9 to 10 completed") Logger.logIfOpen("DB_MIGRATION", "Migration from 9 to 10 completed")
} }
......
...@@ -45,9 +45,12 @@ interface DnsRuleDao { ...@@ -45,9 +45,12 @@ interface DnsRuleDao {
@Query("DELETE FROM DnsRule WHERE importedFrom IS NULL") @Query("DELETE FROM DnsRule WHERE importedFrom IS NULL")
fun deleteAllUserRules() fun deleteAllUserRules()
@Query("UPDATE DnsRule SET stagingType=1 WHERE importedFrom IS NOT NULL") @Query("UPDATE DnsRule SET stagingType=1 WHERE importedFrom IS NOT NULL AND stagingType=0")
fun markNonUserRulesForDeletion() fun markNonUserRulesForDeletion()
@Query("UPDATE DnsRule SET stagingType=0 WHERE importedFrom=:hostSourceId AND stagingType=1")
fun unstageRulesOfSource(hostSourceId:Long)
@Query("DELETE FROM DnsRule WHERE stagingType=1") @Query("DELETE FROM DnsRule WHERE stagingType=1")
fun deleteMarkedRules() fun deleteMarkedRules()
......
...@@ -47,4 +47,7 @@ interface HostSourceDao { ...@@ -47,4 +47,7 @@ interface HostSourceDao {
@Query("SELECT COUNT(*) FROM HostSource WHERE enabled > 0") @Query("SELECT COUNT(*) FROM HostSource WHERE enabled > 0")
fun getEnabledCount(): Long fun getEnabledCount(): Long
@Query("UPDATE HostSource SET checksum=NULL WHERE checksum IS NOT NULL AND enabled<1")
fun removeChecksumForDisabled()
} }
\ No newline at end of file
...@@ -35,4 +35,7 @@ data class HostSource( ...@@ -35,4 +35,7 @@ data class HostSource(
var enabled: Boolean = true var enabled: Boolean = true
var ruleCount:Int? = null var ruleCount:Int? = null
// Content of the ETag header for supported rule sources
// Null if file-based or unknown (e.g. not requested yet)
var checksum:String? = null
} }
\ No newline at end of file
package com.frostnerd.smokescreen.dialog
import android.content.Context
import android.content.DialogInterface
import android.view.View
import android.widget.ArrayAdapter
import androidx.annotation.Keep
import androidx.appcompat.app.AlertDialog
import com.frostnerd.smokescreen.R
import com.frostnerd.smokescreen.getPreferences
import kotlinx.android.synthetic.main.dialog_host_source_refresh.view.*
/*
* Copyright (C) 2019 Daniel Wolf (Ch4t4r)
*
* 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/>.
*
* You can contact the developer at daniel.wolf@frostnerd.com.
*/
class HostSourceRefreshDialog(context:Context,
runRefresh:() -> Unit,
refreshConfigChanged:() -> Unit):AlertDialog(context, context.getPreferences().theme.dialogStyle) {
init {
setTitle(R.string.dialog_hostsourcerefresh_title)
val view = layoutInflater.inflate(R.layout.dialog_host_source_refresh, null, false)
setView(view)
view.refreshNow.setOnClickListener {
runRefresh()
}
val changeAutomaticRefreshStatus:(Boolean) -> Unit = { isChecked ->
view.refreshWifiOnly.isEnabled = isChecked
view.timeAmountTil.isEnabled = isChecked
view.timeUnit.isEnabled = isChecked
view.refreshTimeWrap.visibility = if(isChecked) View.VISIBLE else View.INVISIBLE
}
view.automaticRefresh.setOnCheckedChangeListener { _, isChecked ->
changeAutomaticRefreshStatus(isChecked)
}
changeAutomaticRefreshStatus(view.automaticRefresh.isChecked)
val adapter: ArrayAdapter<CharSequence> = ArrayAdapter.createFromResource(
context,
R.array.dialog_hostsourcerefresh_timeunits,
R.layout.item_tasker_action_spinner_item
)
adapter.setDropDownViewResource(R.layout.item_tasker_action_spinner_dropdown_item)
view.timeUnit.adapter = adapter
view.automaticRefresh.isChecked = context.getPreferences().automaticHostRefresh
view.refreshWifiOnly.isChecked = context.getPreferences().automaticHostRefreshWifiOnly
view.timeAmount.setText(context.getPreferences().automaticHostRefreshTimeAmount.toString())
view.timeUnit.setSelection(context.getPreferences().automaticHostRefreshTimeUnit.ordinal)
setButton(DialogInterface.BUTTON_NEUTRAL, context.getString(android.R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}
setButton(DialogInterface.BUTTON_POSITIVE, context.getString(android.R.string.ok)) { dialog, _ ->
dialog.dismiss()
context.getPreferences().automaticHostRefresh = view.automaticRefresh.isChecked
context.getPreferences().automaticHostRefreshWifiOnly = view.refreshWifiOnly.isChecked
context.getPreferences().automaticHostRefreshTimeAmount = view.timeAmount.text.toString().toIntOrNull() ?: 1
context.getPreferences().automaticHostRefreshTimeUnit = TimeUnit.values().find { it.ordinal == view.timeUnit.selectedItemPosition }!!
refreshConfigChanged()
}
}
@Keep
enum class TimeUnit {
MINUTES, HOURS, DAYS, WEEKS
}
}
\ No newline at end of file
...@@ -12,6 +12,10 @@ import androidx.appcompat.app.AppCompatActivity ...@@ -12,6 +12,10 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.work.Constraints
import androidx.work.NetworkType
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
import com.frostnerd.cacheadapter.ListDataSource import com.frostnerd.cacheadapter.ListDataSource
import com.frostnerd.cacheadapter.ModelAdapterBuilder import com.frostnerd.cacheadapter.ModelAdapterBuilder
import com.frostnerd.general.service.isServiceRunning import com.frostnerd.general.service.isServiceRunning
...@@ -23,12 +27,15 @@ import com.frostnerd.smokescreen.database.entities.HostSource ...@@ -23,12 +27,15 @@ import com.frostnerd.smokescreen.database.entities.HostSource
import com.frostnerd.smokescreen.database.getDatabase import com.frostnerd.smokescreen.database.getDatabase
import com.frostnerd.smokescreen.dialog.DnsRuleDialog import com.frostnerd.smokescreen.dialog.DnsRuleDialog
import com.frostnerd.smokescreen.dialog.ExportDnsRulesDialog import com.frostnerd.smokescreen.dialog.ExportDnsRulesDialog
import com.frostnerd.smokescreen.dialog.HostSourceRefreshDialog
import com.frostnerd.smokescreen.dialog.NewHostSourceDialog import com.frostnerd.smokescreen.dialog.NewHostSourceDialog
import com.frostnerd.smokescreen.service.RuleExportService import com.frostnerd.smokescreen.service.RuleExportService
import com.frostnerd.smokescreen.service.RuleImportService import com.frostnerd.smokescreen.service.RuleImportService
import com.frostnerd.smokescreen.util.SpaceItemDecorator import com.frostnerd.smokescreen.util.SpaceItemDecorator
import com.frostnerd.smokescreen.util.worker.RuleImportStartWorker
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_dns_rules.* import kotlinx.android.synthetic.main.activity_dns_rules.*
import kotlinx.android.synthetic.main.dialog_host_source_refresh.*
import kotlinx.android.synthetic.main.item_datasource.view.* import kotlinx.android.synthetic.main.item_datasource.view.*
import kotlinx.android.synthetic.main.item_datasource.view.cardContent import kotlinx.android.synthetic.main.item_datasource.view.cardContent
import kotlinx.android.synthetic.main.item_datasource.view.delete import kotlinx.android.synthetic.main.item_datasource.view.delete
...@@ -39,6 +46,8 @@ import kotlinx.android.synthetic.main.item_dnsrule_host.view.* ...@@ -39,6 +46,8 @@ import kotlinx.android.synthetic.main.item_dnsrule_host.view.*
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.Duration
import java.util.concurrent.TimeUnit
/* /*
* Copyright (C) 2019 Daniel Wolf (Ch4t4r) * Copyright (C) 2019 Daniel Wolf (Ch4t4r)
...@@ -118,13 +127,46 @@ class DnsRuleFragment : Fragment() { ...@@ -118,13 +127,46 @@ class DnsRuleFragment : Fragment() {
}).show() }).show()
} }
refresh.setOnClickListener { refresh.setOnClickListener {
if(context!!.isServiceRunning(RuleImportService::class.java)) { HostSourceRefreshDialog(context!!,runRefresh = {
context!!.startService(Intent(context!!, RuleImportService::class.java).putExtra("abort", true)) if(context!!.isServiceRunning(RuleImportService::class.java)) {
} else { context!!.startService(Intent(context!!, RuleImportService::class.java).putExtra("abort", true))
context!!.startService(Intent(context!!, RuleImportService::class.java)) } else {
refreshProgress.show() context!!.startService(Intent(context!!, RuleImportService::class.java))
refreshProgressShown = true refreshProgress.show()
} refreshProgressShown = true
}
}, refreshConfigChanged = {
getPreferences().apply {
val constraints = Constraints.Builder()
.setRequiresStorageNotLow(true)
.setRequiresBatteryNotLow(true)
.setRequiredNetworkType(if (this.automaticHostRefreshWifiOnly) NetworkType.UNMETERED else NetworkType.CONNECTED)
.build()
val mappedTimeAmount = automaticHostRefreshTimeAmount.let {
if (automaticHostRefreshTimeUnit == HostSourceRefreshDialog.TimeUnit.WEEKS) it * 7
else it
}.toLong()
val mappedTimeUnit = automaticHostRefreshTimeUnit.let {
when (it) {
HostSourceRefreshDialog.TimeUnit.WEEKS -> TimeUnit.DAYS
HostSourceRefreshDialog.TimeUnit.DAYS -> TimeUnit.DAYS
HostSourceRefreshDialog.TimeUnit.HOURS -> TimeUnit.HOURS
HostSourceRefreshDialog.TimeUnit.MINUTES -> TimeUnit.MINUTES
}
}
val workRequest = PeriodicWorkRequest.Builder(RuleImportStartWorker::class.java,
mappedTimeAmount,
mappedTimeUnit)
.setConstraints(constraints)
.setInitialDelay(mappedTimeAmount, mappedTimeUnit)
.addTag("hostSourceRefresh")
WorkManager.getInstance(context!!).apply {
cancelAllWorkByTag("hostSourceRefresh")
enqueue(workRequest.build())
}
}
}).show()
} }
export.setOnClickListener { export.setOnClickListener {
if (context!!.isServiceRunning(RuleExportService::class.java)) { if (context!!.isServiceRunning(RuleExportService::class.java)) {
......
...@@ -3,6 +3,7 @@ package com.frostnerd.smokescreen.service ...@@ -3,6 +3,7 @@ package com.frostnerd.smokescreen.service
import android.app.NotificationManager import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.app.Service import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
...@@ -94,6 +95,8 @@ class DnsVpnService : VpnService(), Runnable { ...@@ -94,6 +95,8 @@ class DnsVpnService : VpnService(), Runnable {
private var queryCountOffset: Long = 0 private var queryCountOffset: Long = 0
private var packageBypassAmount = 0 private var packageBypassAmount = 0
private var connectedToANetwork:Boolean? = null private var connectedToANetwork:Boolean? = null
private var lastScreenOff:Long? = null
private lateinit var screenStateReceiver:BroadcastReceiver
/* /*
URLs passed to the Service, which haven't been retrieved from the settings. URLs passed to the Service, which haven't been retrieved from the settings.
...@@ -185,6 +188,15 @@ class DnsVpnService : VpnService(), Runnable { ...@@ -185,6 +188,15 @@ class DnsVpnService : VpnService(), Runnable {
updateServiceTile() updateServiceTile()
subscribeToSettings() subscribeToSettings()
addNetworkChangeListener() addNetworkChangeListener()
screenStateReceiver = registerReceiver(listOf(Intent.ACTION_SCREEN_OFF, Intent.ACTION_SCREEN_ON)) {
if(it?.action == Intent.ACTION_SCREEN_OFF) {
lastScreenOff = System.currentTimeMillis()
} else {
if(lastScreenOff != null && System.currentTimeMillis() - lastScreenOff!! >= 60000) {
if(fileDescriptor != null) recreateVpn(false, null)
}
}
}
log("Service created.") log("Service created.")
} }
...@@ -513,9 +525,14 @@ class DnsVpnService : VpnService(), Runnable { ...@@ -513,9 +525,14 @@ class DnsVpnService : VpnService(), Runnable {
queryCountOffset += currentTrafficStats?.packetsReceivedFromDevice ?: 0 queryCountOffset += currentTrafficStats?.packetsReceivedFromDevice ?: 0
vpnProxy?.stop() vpnProxy?.stop()
fileDescriptor?.close() fileDescriptor?.close()
if(isStoppingCompletely && networkCallback != null) { if (isStoppingCompletely) {
(getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).unregisterNetworkCallback(networkCallback) if (networkCallback != null) {
networkCallback = null (getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).unregisterNetworkCallback(
networkCallback
)
networkCallback = null
}
unregisterReceiver(screenStateReceiver)
} }
vpnProxy = null vpnProxy = null
fileDescriptor = null fileDescriptor = null
......
...@@ -166,6 +166,7 @@ class RuleImportService : IntentService("RuleImportService") { ...@@ -166,6 +166,7 @@ class RuleImportService : IntentService("RuleImportService") {
dnsRuleDao.deleteStagedRules() dnsRuleDao.deleteStagedRules()
var count = 0 var count = 0
val maxCount = getDatabase().hostSourceDao().getEnabledCount() val maxCount = getDatabase().hostSourceDao().getEnabledCount()
val newChecksums = mutableMapOf<HostSource, String>()
getDatabase().hostSourceDao().getAllEnabled().forEach { getDatabase().hostSourceDao().getAllEnabled().forEach {
log("Importing HostSource $it") log("Importing HostSource $it")
if (!isAborted) { if (!isAborted) {
...@@ -189,15 +190,31 @@ class RuleImportService : IntentService("RuleImportService") { ...@@ -189,15 +190,31 @@ class RuleImportService : IntentService("RuleImportService") {
var response: Response? = null var response: Response? = null
try { try {
val request = Request.Builder().url(it.source) val request = Request.Builder().url(it.source)
if(it.checksum != null) request.header("If-None-Match", it.checksum!!)
response = httpClient.newCall(request.build()).execute() response = httpClient.newCall(request.build()).execute()
if (response.isSuccessful) { val localDataIsRecent = response.code == 304 || it.checksum!= null && response.headers.find {
processLines(it, response.body!!.byteStream()) it.first.equals("etag", true)
} else { }?.second == it.checksum
log("Downloading resource of $it failed.") when {
response.isSuccessful && !localDataIsRecent -> {
response.headers.find {
it.first.equals("etag", true)
}?.second?.apply {
newChecksums[it] = this
}
processLines(it, response.body!!.byteStream())
}
response.code == 304 || localDataIsRecent -> {
log("Host source ${it.name} hasn't changed, not updating.")
ruleCount += it.ruleCount ?: 0
dnsRuleDao.unstageRulesOfSource(it.id)
log("Unstaged rules for ${it.name}")
}
else -> log("Downloading resource of ${it.name} failed.")
} }
} catch (ex: java.lang.Exception) { } catch (ex: java.lang.Exception) {
ex.printStackTrace() ex.printStackTrace()
log("Downloading resource of $it failed ($ex)") log("Downloading resource of ${it.name} failed ($ex)")
} finally { } finally {
response?.body?.close() response?.body?.close()
} }
...@@ -217,6 +234,12 @@ class RuleImportService : IntentService("RuleImportService") { ...@@ -217,6 +234,12 @@ class RuleImportService : IntentService("RuleImportService") {
dnsRuleDao.deleteStagedRules() dnsRuleDao.deleteStagedRules()
log("Recreating database indices") log("Recreating database indices")
getDatabase().recreateDnsRuleIndizes() getDatabase().recreateDnsRuleIndizes()
log("Updating Etag values for sources")
newChecksums.forEach { (source, etag) ->
source.checksum = etag
getDatabase().hostSourceDao().update(source)
}
getDatabase().hostSourceDao().removeChecksumForDisabled()
log("Done.") log("Done.")
showSuccessNotification() showSuccessNotification()
} else { } else {
...@@ -302,11 +325,12 @@ class RuleImportService : IntentService("RuleImportService") { ...@@ -302,11 +325,12 @@ class RuleImportService : IntentService("RuleImportService") {
val defaultTargetV6 = if(isWhitelist) "" else "1" val defaultTargetV6 = if(isWhitelist) "" else "1"
when { when {
matcher.groupCount() == 1 -> { matcher.groupCount() == 1 -> {
val host = matcher.group(1).replace(wwwRegex, "") val host = if(matcher == dnsmasqBlockMatcher) "%%" + matcher.group(1)
else matcher.group(1).replace(wwwRegex, "")
return createRule(host, defaultTargetV4, defaultTargetV6, Record.TYPE.ANY, sourceId) return createRule(host, defaultTargetV4, defaultTargetV6, Record.TYPE.ANY, sourceId)
} }
matcher == dnsmasqMatcher -> { matcher == dnsmasqMatcher -> {
val host = matcher.group(1).replace(wwwRegex, "") val host = "%%" + matcher.group(1)
var target = matcher.group(2) var target = matcher.group(2)
val type = if (target.contains(":")) Record.TYPE.AAAA else Record.TYPE.A val type = if (target.contains(":")) Record.TYPE.AAAA else Record.TYPE.A
target = target.let { target = target.let {
......
...@@ -11,6 +11,7 @@ import com.frostnerd.preferenceskt.typedpreferences.cache.ExpirationCacheControl ...@@ -11,6 +11,7 @@ import com.frostnerd.preferenceskt.typedpreferences.cache.ExpirationCacheControl
import com.frostnerd.preferenceskt.typedpreferences.cache.buildCacheStrategy import com.frostnerd.preferenceskt.typedpreferences.cache.buildCacheStrategy
import com.frostnerd.preferenceskt.typedpreferences.types.* import com.frostnerd.preferenceskt.typedpreferences.types.*
import com.frostnerd.smokescreen.BuildConfig import com.frostnerd.smokescreen.BuildConfig
import com.frostnerd.smokescreen.dialog.HostSourceRefreshDialog
import java.util.* import java.util.*
/* /*
...@@ -229,7 +230,7 @@ class AppSettingsSharedPreferences(context: Context) : AppSettings, SimpleTypedP ...@@ -229,7 +230,7 @@ class AppSettingsSharedPreferences(context: Context) : AppSettings, SimpleTypedP
shouldContain(BuildConfig.APPLICATION_ID) shouldContain(BuildConfig.APPLICATION_ID)
}, cacheControl) }, cacheControl)
override var dnsServerConfig: DnsServerInformation<*> by cache(DnsServerInformationPreference("dns_server_config") { override var dnsServerConfig: DnsServerInformation<*> by cache(DnsServerInformationPreference("dns_server_config") {
AbstractTLSDnsHandle.waitUntilKnownServersArePopulated(500) { knownServers -> AbstractTLSDnsHandle.waitUntilKnownServersArePopulated(-1) { knownServers ->
knownServers.getValue(9) knownServers.getValue(9)
} }
}, cacheControl) }, cacheControl)
...@@ -243,6 +244,11 @@ class AppSettingsSharedPreferences(context: Context) : AppSettings, SimpleTypedP ...@@ -243,6 +244,11 @@ class AppSettingsSharedPreferences(context: Context) : AppSettings, SimpleTypedP
var vpnServiceState:VpnServiceState by enumPref("vpn_service_state", VpnServiceState.STOPPED) var vpnServiceState:VpnServiceState by enumPref("vpn_service_state", VpnServiceState.STOPPED)
var ignoreServiceKilled:Boolean by booleanPref("ignore_service_killed", false) var ignoreServiceKilled:Boolean by booleanPref("ignore_service_killed", false)
var automaticHostRefresh:Boolean by booleanPref("automatic_host_refresh", false)
var automaticHostRefreshWifiOnly:Boolean by booleanPref("automatic_host_refresh_wifi_only", true)
var automaticHostRefreshTimeUnit:HostSourceRefreshDialog.TimeUnit by enumPref("automatic_host_refresh_timeunit", HostSourceRefreshDialog.TimeUnit.HOURS)
var automaticHostRefreshTimeAmount:Int by intPref("automatic_host_refresh_timeamount", 12)
} }
fun AppSettings.Companion.fromSharedPreferences(context: Context): AppSettingsSharedPreferences { fun AppSettings.Companion.fromSharedPreferences(context: Context): AppSettingsSharedPreferences {
......
...@@ -54,7 +54,9 @@ class DnsServerInformationPreference(key: String, defaultValue: (String) -> DnsS ...@@ -54,7 +54,9 @@ class DnsServerInformationPreference(key: String, defaultValue: (String) -> DnsS
} }
} else { } else {
defaultValue(key) defaultValue(key).also {
setValue(thisRef, property, it)
}
} }
} }
......
...@@ -48,8 +48,10 @@ class ProxyTlsHandler( ...@@ -48,8 +48,10 @@ class ProxyTlsHandler(
) { ) {