Commit 62a0bb59 authored by Max Lv's avatar Max Lv

Refine URL based ACL

parent 4eb77c88
...@@ -26,6 +26,27 @@ class Acl { ...@@ -26,6 +26,27 @@ class Acl {
@DatabaseField @DatabaseField
var bypass: Boolean = _ var bypass: Boolean = _
def isUrl(url: String): Boolean = url.startsWith("http://") || url.startsWith("https://")
def getBypassHostnamesString: String = bypassHostnames.mkString("\n")
def getProxyHostnamesString: String = proxyHostnames.mkString("\n")
def getSubnetsString: String = subnets.mkString("\n")
def setBypassHostnamesString(value: String) {
bypassHostnames.clear()
bypassHostnames ++= value.split("\n")
}
def setProxyHostnamesString(value: String) {
proxyHostnames.clear()
proxyHostnames ++= value.split("\n")
}
def setSubnetsString(value: String) {
subnets.clear()
subnets ++= value.split("\n").map(Subnet.fromString)
}
def setUrlRules(value: String) {
urls.clear()
urls ++= value.split("\n")
}
def fromAcl(other: Acl): Acl = { def fromAcl(other: Acl): Acl = {
bypassHostnames.clear() bypassHostnames.clear()
bypassHostnames ++= other.bypassHostnames bypassHostnames ++= other.bypassHostnames
...@@ -51,10 +72,17 @@ class Acl { ...@@ -51,10 +72,17 @@ class Acl {
var in_urls = false var in_urls = false
for (line <- value.getLines()) (line.indexOf('#') match { for (line <- value.getLines()) (line.indexOf('#') match {
case -1 => if (!in_urls) line else "" case -1 => if (!in_urls) line else ""
case index => case index => {
if (line.contains("URLS_BEGIN")) in_urls = true line.indexOf("NETWORK_ACL_BEGIN") match {
if (line.contains("URLS_END")) in_urls = false case -1 =>
line.substring(0, index) // trim comments case index => in_urls = true
}
line.indexOf("NETWORK_ACL_END") match {
case -1 =>
case index => in_urls = false
}
"" // ignore any comment lines
}
}).trim match { }).trim match {
case "[outbound_block_list]" => case "[outbound_block_list]" =>
hostnames = null hostnames = null
...@@ -68,8 +96,11 @@ class Acl { ...@@ -68,8 +96,11 @@ class Acl {
case "[reject_all]" | "[bypass_all]" => bypass = true case "[reject_all]" | "[bypass_all]" => bypass = true
case "[accept_all]" | "[proxy_all]" => bypass = false case "[accept_all]" | "[proxy_all]" => bypass = false
case input if subnets != null && input.nonEmpty => try subnets += Subnet.fromString(input) catch { case input if subnets != null && input.nonEmpty => try subnets += Subnet.fromString(input) catch {
case _: IllegalArgumentException => if (input.startsWith("http://") || input.startsWith("https://")) case _: IllegalArgumentException => if (isUrl(input)) {
urls += input else hostnames += input urls += input
} else {
hostnames += input
}
} }
case _ => case _ =>
} }
...@@ -81,17 +112,16 @@ class Acl { ...@@ -81,17 +112,16 @@ class Acl {
def getAclString(network: Boolean): String = { def getAclString(network: Boolean): String = {
val result = new StringBuilder() val result = new StringBuilder()
if (urls.nonEmpty) { if (urls.nonEmpty) {
result.append("#URLS_BEGIN\n")
result.append(urls.mkString("\n")) result.append(urls.mkString("\n"))
result.append("#NETWORK_ACL_BEGIN\n")
if (network) { if (network) {
try { try {
urls.foreach((url: String) => result.append(Source.fromURL(url).mkString)) urls.foreach((url: String) => result.append(Source.fromURL(url).mkString))
} catch { } catch {
case _: IOException => // ignore case e: IOException => // ignore
} }
} }
result.append("#URLS_END\n") result.append("#NETWORK_ACL_END\n")
} }
if (result.isEmpty) { if (result.isEmpty) {
result.append(if (bypass) "[bypass_all]\n" else "[proxy_all]\n") result.append(if (bypass) "[bypass_all]\n" else "[proxy_all]\n")
...@@ -112,7 +142,9 @@ class Acl { ...@@ -112,7 +142,9 @@ class Acl {
result.toString result.toString
} }
override def toString: String = getAclString(false) override def toString: String = {
getAclString(false)
}
def isValidCustomRules: Boolean = bypass && bypassHostnames.isEmpty def isValidCustomRules: Boolean = bypass && bypassHostnames.isEmpty
......
...@@ -125,22 +125,34 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi ...@@ -125,22 +125,34 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi
}) })
} }
def getItemCount: Int = acl.subnets.size + acl.proxyHostnames.size def getItemCount: Int = acl.subnets.size + acl.proxyHostnames.size + acl.urls.size
def onBindViewHolder(vh: AclRuleViewHolder, i: Int): Unit = { def onBindViewHolder(vh: AclRuleViewHolder, i: Int): Unit = {
val j = i - acl.subnets.size val j = i - acl.urls.size
if (j < 0) vh.bind(acl.subnets(i)) else vh.bind(acl.proxyHostnames(j)) val k = i - acl.subnets.size - acl.urls.size
if (j < 0)
vh.bind(acl.urls(i))
else if (k < 0)
vh.bind(acl.subnets(j))
else
vh.bind(acl.proxyHostnames(k))
} }
def onCreateViewHolder(vg: ViewGroup, i: Int) = new AclRuleViewHolder(LayoutInflater.from(vg.getContext) def onCreateViewHolder(vg: ViewGroup, i: Int) = new AclRuleViewHolder(LayoutInflater.from(vg.getContext)
.inflate(android.R.layout.simple_list_item_1, vg, false)) .inflate(android.R.layout.simple_list_item_1, vg, false))
def addUrl(url: String): Int = if (acl.urls.add(url)) {
val index = acl.urls.indexOf(url)
notifyItemInserted(index)
apply()
index
} else -1
def addSubnet(subnet: Subnet): Int = if (acl.subnets.add(subnet)) { def addSubnet(subnet: Subnet): Int = if (acl.subnets.add(subnet)) {
val index = acl.subnets.indexOf(subnet) val index = acl.subnets.indexOf(subnet) + acl.urls.size
notifyItemInserted(index) notifyItemInserted(index)
apply() apply()
index index
} else -1 } else -1
def addHostname(hostname: String): Int = if (acl.proxyHostnames.add(hostname)) { def addHostname(hostname: String): Int = if (acl.proxyHostnames.add(hostname)) {
val index = acl.proxyHostnames.indexOf(hostname) + acl.subnets.size val index = acl.proxyHostnames.indexOf(hostname) + acl.urls.size + acl.subnets.size
notifyItemInserted(index) notifyItemInserted(index)
apply() apply()
index index
...@@ -148,6 +160,7 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi ...@@ -148,6 +160,7 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi
def addToProxy(input: String): Int = { def addToProxy(input: String): Int = {
val acl = new Acl().fromSource(Source.fromString(input), defaultBypass = true) val acl = new Acl().fromSource(Source.fromString(input), defaultBypass = true)
var result = -1 var result = -1
for (url <- acl.urls) result = addUrl(url)
for (hostname <- acl.proxyHostnames) result = addHostname(hostname) for (hostname <- acl.proxyHostnames) result = addHostname(hostname)
if (acl.bypass) for (subnet <- acl.subnets) result = addSubnet(subnet) if (acl.bypass) for (subnet <- acl.subnets) result = addSubnet(subnet)
result result
...@@ -164,13 +177,17 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi ...@@ -164,13 +177,17 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi
} }
def remove(i: Int) { def remove(i: Int) {
val j = i - acl.subnets.size val j = i - acl.urls.size
val k = i - acl.urls.size - acl.subnets.size
if (j < 0) { if (j < 0) {
undoManager.remove((i, acl.subnets(i))) undoManager.remove((i, acl.urls(i)))
acl.subnets.remove(i) acl.urls.remove(i)
} else if (k < 0) {
undoManager.remove((j, acl.subnets(j)))
acl.subnets.remove(j)
} else { } else {
undoManager.remove((j, acl.proxyHostnames(j))) undoManager.remove((k, acl.proxyHostnames(k)))
acl.proxyHostnames.remove(j) acl.proxyHostnames.remove(k)
} }
notifyItemRemoved(i) notifyItemRemoved(i)
apply() apply()
...@@ -180,11 +197,16 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi ...@@ -180,11 +197,16 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi
notifyItemRemoved(acl.subnets.indexOf(subnet)) notifyItemRemoved(acl.subnets.indexOf(subnet))
acl.subnets.remove(subnet) acl.subnets.remove(subnet)
apply() apply()
case hostname: String => case hostname: String => if (acl.isUrl(hostname)) {
notifyItemRemoved(acl.urls.indexOf(hostname))
acl.urls.remove(hostname)
apply()
} else {
notifyItemRemoved(acl.proxyHostnames.indexOf(hostname)) notifyItemRemoved(acl.proxyHostnames.indexOf(hostname))
acl.proxyHostnames.remove(hostname) acl.proxyHostnames.remove(hostname)
apply() apply()
} }
}
def removeSelected() { def removeSelected() {
undoManager.remove(selectedItems.map((-1, _)).toSeq: _*) undoManager.remove(selectedItems.map((-1, _)).toSeq: _*)
selectedItems.foreach(remove) selectedItems.foreach(remove)
...@@ -192,12 +214,19 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi ...@@ -192,12 +214,19 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi
onSelectedItemsUpdated() onSelectedItemsUpdated()
} }
def undo(actions: Iterator[(Int, AnyRef)]): Unit = for ((_, item) <- actions) item match { def undo(actions: Iterator[(Int, AnyRef)]): Unit = for ((_, item) <- actions) item match {
case hostname: String => if (acl.proxyHostnames.insert(hostname)) { case hostname: String => if (acl.isUrl(hostname)) {
notifyItemInserted(acl.proxyHostnames.indexOf(hostname) + acl.subnets.size) if (acl.urls.insert(hostname)) {
notifyItemInserted(acl.urls.indexOf(hostname))
apply()
}
} else {
if (acl.proxyHostnames.insert(hostname)) {
notifyItemInserted(acl.proxyHostnames.indexOf(hostname) + acl.urls.size + acl.subnets.size)
apply() apply()
} }
}
case subnet: Subnet => if (acl.subnets.insert(subnet)) { case subnet: Subnet => if (acl.subnets.insert(subnet)) {
notifyItemInserted(acl.subnets.indexOf(subnet)) notifyItemInserted(acl.subnets.indexOf(subnet) + acl.urls.size)
apply() apply()
} }
} }
......
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