Implement SIP002
https://github.com/shadowsocks/shadowsocks-org/issues/27
This commit is contained in:
@@ -20,13 +20,13 @@
|
||||
|
||||
package com.github.shadowsocks.database
|
||||
|
||||
import java.net.URLEncoder
|
||||
import java.util.Locale
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.os.Binder
|
||||
import android.text.TextUtils
|
||||
import android.util.Base64
|
||||
import com.github.shadowsocks.plugin.PluginConfiguration
|
||||
import com.github.shadowsocks.utils.Key
|
||||
import com.j256.ormlite.field.{DataType, DatabaseField}
|
||||
|
||||
@@ -93,11 +93,19 @@ class Profile {
|
||||
def nameIsEmpty: Boolean = name == null || name.isEmpty
|
||||
def getName: String = if (nameIsEmpty) formattedAddress else name
|
||||
|
||||
override def toString: String = "ss://" + Base64.encodeToString("%s:%s@%s:%d".formatLocal(Locale.ENGLISH,
|
||||
method, password, host, remotePort).getBytes, Base64.NO_PADDING | Base64.NO_WRAP) +
|
||||
(if (TextUtils.isEmpty(name)) "" else '#' + URLEncoder.encode(name, "utf-8"))
|
||||
|
||||
def isMethodUnsafe: Boolean = "table".equalsIgnoreCase(method) || "rc4".equalsIgnoreCase(method)
|
||||
def toUri: Uri = {
|
||||
val builder = new Uri.Builder()
|
||||
.scheme("ss")
|
||||
.authority("%s@%s:%d".formatLocal(Locale.ENGLISH,
|
||||
Base64.encodeToString("%s:%s".formatLocal(Locale.ENGLISH, method, password).getBytes,
|
||||
Base64.NO_PADDING | Base64.NO_WRAP | Base64.URL_SAFE), host, remotePort))
|
||||
val configuration = new PluginConfiguration(plugin)
|
||||
if (configuration.selected.nonEmpty)
|
||||
builder.appendQueryParameter(Key.plugin, configuration.selectedOptions.toString)
|
||||
if (!nameIsEmpty) builder.fragment(name)
|
||||
builder.build()
|
||||
}
|
||||
override def toString: String = toUri.toString
|
||||
|
||||
def serialize(editor: SharedPreferences.Editor): SharedPreferences.Editor = editor
|
||||
.putString(Key.name, name)
|
||||
|
||||
@@ -20,31 +20,46 @@
|
||||
|
||||
package com.github.shadowsocks.utils
|
||||
|
||||
import java.net.URLDecoder
|
||||
|
||||
import android.util.{Base64, Log}
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import com.github.shadowsocks.database.Profile
|
||||
|
||||
object Parser {
|
||||
val TAG = "ShadowParser"
|
||||
private val pattern = "(?i)ss://([A-Za-z0-9+-/=_]+)(#(.+))?".r
|
||||
private val decodedPattern = "(?i)^((.+?)(-auth)??:(.*)@(.+?):(\\d+?))$".r
|
||||
private val pattern = "(?i)^ss://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]$".r
|
||||
private val userInfoPattern = "^(.+?):(.*)$".r
|
||||
private val legacyPattern = "^((.+?):(.*)@(.+?):(\\d+?))$".r
|
||||
|
||||
def findAll(data: CharSequence): Iterator[Profile] =
|
||||
pattern.findAllMatchIn(if (data == null) "" else data).map(m => try
|
||||
decodedPattern.findFirstMatchIn(new String(Base64.decode(m.group(1), Base64.NO_PADDING), "UTF-8")) match {
|
||||
case Some(ss) =>
|
||||
pattern.findAllMatchIn(if (data == null) "" else data).map(m => {
|
||||
val uri = Uri.parse(m.matched)
|
||||
uri.getUserInfo match {
|
||||
case null => uri.getHost match {
|
||||
case legacyPattern(_, method, password, host, port) => // legacy uri
|
||||
val profile = new Profile
|
||||
profile.method = method.toLowerCase
|
||||
profile.password = password
|
||||
profile.host = host
|
||||
profile.remotePort = port.toInt
|
||||
profile.plugin = uri.getQueryParameter(Key.plugin)
|
||||
profile.name = uri.getFragment
|
||||
profile
|
||||
case _ =>
|
||||
Log.e(TAG, "Unrecognized URI: " + m.matched)
|
||||
null
|
||||
}
|
||||
case userInfoPattern(method, password) =>
|
||||
val profile = new Profile
|
||||
profile.method = ss.group(2).toLowerCase
|
||||
profile.password = ss.group(4)
|
||||
profile.host = ss.group(5)
|
||||
profile.remotePort = ss.group(6).toInt
|
||||
if (m.group(2) != null) profile.name = URLDecoder.decode(m.group(3), "utf-8")
|
||||
profile.method = method
|
||||
profile.password = password
|
||||
profile.host = uri.getHost
|
||||
profile.remotePort = uri.getPort
|
||||
profile.plugin = uri.getQueryParameter(Key.plugin)
|
||||
profile.name = uri.getFragment
|
||||
profile
|
||||
case _ => null
|
||||
} catch {
|
||||
case ex: Exception =>
|
||||
Log.e(TAG, "parser error: " + m.source, ex)// Ignore
|
||||
case _ =>
|
||||
Log.e(TAG, "Unknown user info: " + m.matched)
|
||||
null
|
||||
}).filter(_ != null)
|
||||
}
|
||||
}).filter(_ != null)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user