From b475ec699d0c16c4ac7f4abb7680c7e6011428f4 Mon Sep 17 00:00:00 2001
From: Daniel Dickinson <openwrt@daniel.thecshore.com>
Date: Tue, 1 Dec 2015 23:02:38 -0500
Subject: [PATCH] luci-base: Make default for FileUpload 'safe'

Some files and pointers to files are not safe to remove without a replacement
file and config pointing to the file.  For instance for uhttpd application in
the works, removing the certificate or key config or files without having the
replacements in places renders the WeUI inaccessible.

The only other place where FileUpload is currently used is for wifi certificates
for which the 'safe' handling is also preferred.  Therefore make the default for
the FileUpload widget the safe handling and add a property self.unsafeupload that
allows for the old unsafe handling should it prove useful in some case.

Also allow to specify a file already on router instead of uploading a file.

Signed-off By: Daniel Dickinson <openwrt@daniel.thecshore.com>
---
 modules/luci-base/luasrc/cbi.lua             | 58 +++++++++++++++-----
 modules/luci-base/luasrc/view/cbi/upload.htm | 16 +++++-
 2 files changed, 57 insertions(+), 17 deletions(-)

diff --git a/modules/luci-base/luasrc/cbi.lua b/modules/luci-base/luasrc/cbi.lua
index 8fd0a337e..2c1bb4d22 100644
--- a/modules/luci-base/luasrc/cbi.lua
+++ b/modules/luci-base/luasrc/cbi.lua
@@ -1811,6 +1811,7 @@ function Button.__init__(self, ...)
 	self.template  = "cbi/button"
 	self.inputstyle = nil
 	self.rmempty = true
+        self.unsafeupload = false
 end
 
 
@@ -1827,9 +1828,15 @@ function FileUpload.__init__(self, ...)
 end
 
 function FileUpload.formcreated(self, section)
-	return AbstractValue.formcreated(self, section) or
-		self.map:formvalue("cbi.rlf."..section.."."..self.option) or
-		self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
+	if self.unsafeupload then
+		return AbstractValue.formcreated(self, section) or
+			self.map:formvalue("cbi.rlf."..section.."."..self.option) or
+			self.map:formvalue("cbi.rlf."..section.."."..self.option..".x") or
+			self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
+	else
+		return AbstractValue.formcreated(self, section) or
+			self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
+	end
 end
 
 function FileUpload.cfgvalue(self, section)
@@ -1840,27 +1847,50 @@ function FileUpload.cfgvalue(self, section)
 	return nil
 end
 
+-- If we have a new value, use it
+-- otherwise use old value
+-- deletion should be managed by a separate button object
+-- unless self.unsafeupload is set in which case if the user
+-- choose to remove the old file we do so.
+-- Also, allow to specify (via textbox) a file already on router
 function FileUpload.formvalue(self, section)
 	local val = AbstractValue.formvalue(self, section)
 	if val then
-		if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and
-		   not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
-		then
+		if self.unsafeupload then
+			if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and
+		   	    not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
+			then
+				return val
+			end
+			fs.unlink(val)
+			self.value = nil
+			return nil
+                elseif val ~= "" then
 			return val
-		end
-		fs.unlink(val)
-		self.value = nil
+                end
 	end
-	return nil
+	val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
+	if val == "" then
+		val = nil
+	end
+        if not self.unsafeupload then
+		if not val then
+			val = self.map:formvalue("cbi.rlf."..section.."."..self.option)
+		end
+        end
+	return val
 end
 
 function FileUpload.remove(self, section)
-	local val = AbstractValue.formvalue(self, section)
-	if val and fs.access(val) then fs.unlink(val) end
-	return AbstractValue.remove(self, section)
+	if self.unsafeupload then
+		local val = AbstractValue.formvalue(self, section)
+		if val and fs.access(val) then fs.unlink(val) end
+		return AbstractValue.remove(self, section)
+	else
+		return nil
+	end
 end
 
-
 FileBrowser = class(AbstractValue)
 
 function FileBrowser.__init__(self, ...)
diff --git a/modules/luci-base/luasrc/view/cbi/upload.htm b/modules/luci-base/luasrc/view/cbi/upload.htm
index 777093411..157f3b36f 100644
--- a/modules/luci-base/luasrc/view/cbi/upload.htm
+++ b/modules/luci-base/luasrc/view/cbi/upload.htm
@@ -6,9 +6,19 @@
 <%+cbi/valueheader%>
 	<% if s then %>
 		<%:Uploaded File%> (<%=t.byte_format(s.size)%>)
-		<input type="hidden"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> />
-		<input class="cbi-button cbi-input-image" type="image" value="<%:Replace entry%>" name="cbi.rlf.<%=section .. "." .. self.option%>" alt="<%:Replace entry%>" title="<%:Replace entry%>" src="<%=resource%>/cbi/reload.gif" />
-	<% else %>
+                <% if self.unsafeupload then %>
+		    <input type="hidden"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> />
+		    <input class="cbi-button cbi-input-image" type="image" value="<%:Replace entry%>" name="cbi.rlf.<%=section .. "." .. self.option%>" alt="<%:Replace entry%>" title="<%:Replace entry%>" src="<%=resource%>/cbi/reload.gif" />
+                <% end %>
+	<% end %>
+
+        <% if not self.unsafeupload then %>
+		<input type="hidden"<%= attr("value", v) .. attr("name", "cbi.rlf." .. section .. "." .. self.option) .. attr("id", "cbi.rlf." .. section .. "." .. self.option) %> />
+	<% end %>
+		
+	<% if (not s) or (s and not self.unsafeupload) then %>
 		<input class="cbi-input-file" type="file"<%= attr("name", cbid) .. attr("id", cbid) %> />
 	<% end %>
+	<input type="text" class="cbi-input-text" onchange="cbi_d_update(this.id)"<%=
+		attr("name", cbid .. ".textbox") .. attr("id", cbid .. ".textbox") .. attr("value", luci.cbi.AbstractValue.cfgvalue(self, section) or self.default) .. ifattr(self.size, "size") .. ifattr(self.placeholder, "placeholder") .. ifattr(self.readonly, "readonly") .. ifattr(self.maxlength, "maxlength") %> />
 <%+cbi/valuefooter%>
-- 
2.25.1