Unverified Commit 56121d5b authored by Max Lv's avatar Max Lv Committed by GitHub

Merge pull request #2072 from shadowsocks/plugin-1.1.0

Plugin library 1.1.0
parents e6416253 9f037d2a
......@@ -149,7 +149,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
DataStore.plugin = pluginConfiguration.toString()
DataStore.dirty = true
true
} catch (exc: IllegalArgumentException) {
} catch (exc: RuntimeException) {
(activity as MainActivity).snackbar(exc.localizedMessage).show()
false
}
......
......@@ -84,6 +84,7 @@
android:key="plugin.configure"
android:icon="@drawable/ic_action_settings"
android:persistent="false"
android:singleLine="true"
app:pref_summaryHasText="%s"
android:title="@string/plugin_configure"/>
<Preference
......
* 1.1.0:
* Having control characters in plugin options is no longer allowed.
If this breaks your plugin, you are doing it wrong.
* New helper method: `PluginOptions.putWithDefault`.
* 1.0.0:
* BREAKING CHANGE: Plugins developed using this version and forward require shadowsocks-android 4.6.5 or higher.
* `PathProvider` now takes `Int` instead of `String` for file modes;
......
......@@ -10,8 +10,8 @@ android {
defaultConfig {
minSdkVersion rootProject.minSdkVersion
targetSdkVersion rootProject.sdkVersion
versionCode 7
versionName "1.0.0"
versionCode 8
versionName "1.1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
......
......@@ -38,6 +38,7 @@ class PluginOptions : HashMap<String, String?> {
@Suppress("NAME_SHADOWING")
var parseId = parseId
if (options.isNullOrEmpty()) return
check(options.all { !it.isISOControl() }) { "No control characters allowed." }
val tokenizer = StringTokenizer("$options;", "\\=;", true)
val current = StringBuilder()
var key: String? = null
......@@ -68,6 +69,14 @@ class PluginOptions : HashMap<String, String?> {
this.id = id
}
/**
* Put but if value is null or default, the entry is deleted.
*
* @return Old value before put.
*/
fun putWithDefault(key: String, value: String?, default: String? = null) =
if (value == null || value == default) remove(key) else put(key, value)
private fun append(result: StringBuilder, str: String) = (0 until str.length)
.map { str[it] }
.forEach {
......
......@@ -25,7 +25,7 @@ import org.junit.Test
class PluginOptionsTest {
@Test
fun equal() {
fun basic() {
val o1 = PluginOptions("obfs-local;obfs=http;obfs-host=localhost")
val o2 = PluginOptions("obfs-local", "obfs-host=localhost;obfs=http")
Assert.assertEquals(o1.hashCode(), o2.hashCode())
......@@ -35,4 +35,19 @@ class PluginOptionsTest {
val o4 = PluginOptions(o2.id, o2.toString())
Assert.assertEquals(true, o3 == o4)
}
@Test
fun escape() {
val options = PluginOptions("escapeTest")
options["subject"] = "value;semicolon"
Assert.assertEquals(true, options == PluginOptions(options.toString(false)))
options["key;semicolon"] = "object"
Assert.assertEquals(true, options == PluginOptions(options.toString(false)))
options["subject"] = "value=equals"
Assert.assertEquals(true, options == PluginOptions(options.toString(false)))
options["key=equals"] = "object"
Assert.assertEquals(true, options == PluginOptions(options.toString(false)))
options["advanced\\=;test"] = "in;=\\progress"
Assert.assertEquals(true, options == PluginOptions(options.toString(false)))
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment