public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "André Erdmann" <dywi@mailerd.de>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/ebuild/
Date: Thu, 25 Apr 2013 16:44:17 +0000 (UTC)	[thread overview]
Message-ID: <1363536390.fd838576df5db122a01f3e2001577842db3575a3.dywi@gentoo> (raw)

commit:     fd838576df5db122a01f3e2001577842db3575a3
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Sun Mar 17 14:02:15 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Sun Mar 17 16:06:30 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=fd838576

ebuild/evars: make value strings more robust

This commit adds the following actions in order to protect against
undesirable side-effects:
* eliminate character sequences starting with "$("
* fix the value string of ListValues on a per-item basis
  instead if editing the (final) ListValue string
* strip backslash chars at the end of value strings

---
 roverlay/ebuild/abstractcomponents.py |  165 ++++++++++++++++++++++++---------
 roverlay/ebuild/evars.py              |   27 +++--
 2 files changed, 136 insertions(+), 56 deletions(-)

diff --git a/roverlay/ebuild/abstractcomponents.py b/roverlay/ebuild/abstractcomponents.py
index 5b12260..b33189e 100644
--- a/roverlay/ebuild/abstractcomponents.py
+++ b/roverlay/ebuild/abstractcomponents.py
@@ -18,11 +18,68 @@ __all__ = [ 'ListValue', 'EbuildVar', ]
 
 import re
 
+import roverlay.strutil
+
 INDENT = '\t'
 
+# IGNORED_VALUE_CHARS
+#  chars not allowed in value strings
+#  Additionally, backslashes at the end of a string will be removed.
+IGNORED_VALUE_CHARS  = "\"'`;"
+
+def _value_char_allowed ( c ):
+	"""Returns True if the given char is allowed, else False (=char should
+	be ignored.
+
+	arguments:
+	* c --
+	"""
+	return c not in IGNORED_VALUE_CHARS
+# --- end of _value_char_allowed (...) ---
+
+## IGNORED_VALUE_CODE, catches:
+## * command substitution: $(<cmd>), $(< <file>)
+## * arithmetic expansion: $((<statement>))
+##
+#IGNORED_VALUE_CODE = re.compile (
+#	'[$][(]{1,2}[<]?(?P<text>.*?)[)]{1,2}\s*'
+#)
+
+# IGNORED_VALUE_CODE (strict), catches:
+# * any (sub)string beginning with '$(' which is either not allowed
+#   or it leads to syntax errors
+#
+# This will remove more text than the variant above, but we cannot trust
+# that code injection always uses correct syntax.
+#
+IGNORED_VALUE_CODE = re.compile ( '[$][(].*' )
+
+def get_value_str ( value, quote_char=None ):
+	"""Removes bad chars / substrings from vstr:
+	* non-ascii chars (this could be a no-op)
+	* IGNORED_VALUE_CHARS
+	* any substring starting with $(
+	* backslash characters at the end of the string
+
+	arguments:
+	* value --
+	"""
+	s = IGNORED_VALUE_CODE.sub (
+		"",
+		roverlay.strutil.ascii_filter (
+			str ( value ), additional_filter=_value_char_allowed
+		)
+	).rstrip ( "\\" )
+	if quote_char:
+		return quote_char + s + quote_char
+	else:
+		return s
+# --- end of get_value_str (...) ---
+
 def listlike ( ref ):
 	"""Returns True if ref is listlike (a non-str iterable)."""
 	return hasattr ( ref, '__iter__' ) and not isinstance ( ref, str )
+# --- end of listlike (...) ---
 
 
 class ListValue ( object ):
@@ -34,27 +91,27 @@ class ListValue ( object ):
 
 		arguments:
 		* value        --
-		* indent_level -- indention level ('\t') for extra value lines
+		* indent_level -- indention level ('\t') for value string lines
 		* empty_value  -- if set: a string value that is always part
-		                          of this ListValue's elements but ignored
-		                          by len().
-		                          Use cases are '${IUSE:-}' in the IUSE var etc.
+		                   of this ListValue's elements but ignored when
+		                   checking the number of stored items.
+		                   Use cases are '${IUSE:-}' in the IUSE var etc.
+		                   Defaults to None (which disables this feature).
+		* bash_array   -- whether this value is a bash array or a string
+		                   Defaults to False.
 		"""
-		self.set_level ( indent_level )
-
-		self.empty_value = empty_value
-
-
+		self.empty_value             = empty_value
 		self.single_line             = False
 		self.indent_lines            = True
-		# only used in multi line mode
-		self.append_indented_newline = True
-
 		self.is_bash_array           = bash_array
 		self.insert_leading_newline  = self.is_bash_array
 
-		self.val_join = ' '
+		# only used when dealing with multi-line non-bash array values:
+		#  append \n<var_indent> to the value string if True (useful for quoting
+		#  such strings)
+		self.append_indented_newline = True
 
+		self.set_level ( indent_level )
 		self.set_value ( value )
 	# --- end of __init__ (...) ---
 
@@ -71,13 +128,14 @@ class ListValue ( object ):
 	def __len__ ( self ):
 		l = len ( self.value )
 		return max ( 0, l if self.empty_value is None else l - 1 )
+	# --- end of __len__ (...) ---
 
 	def set_level ( self, level ):
 		"""Sets the indention level."""
-		self.level      = level
-		self.var_indent = (level - 1) * INDENT
-		self.val_indent = level * INDENT
-		self.line_join  = '\n' + self.val_indent
+		self.level         = level
+		self.var_indent    = (level - 1) * INDENT
+		self.val_indent    = level * INDENT
+		self.line_join_str = '\n' + self.val_indent
 	# --- end of set_level (...) ---
 
 	def set_value ( self, value ):
@@ -86,8 +144,7 @@ class ListValue ( object ):
 		if self.empty_value is not None:
 			self.value.append ( self.empty_value )
 
-		if self._accept_value ( value ):
-			self.add_value ( value )
+		self.add_value ( value )
 	# --- end of set_value (...) ---
 
 	def add ( self, value ):
@@ -105,54 +162,61 @@ class ListValue ( object ):
 	def to_str ( self ):
 		"""Returns a string representing this ListValue."""
 
+		def get_value_strings ( join_str, quoted=False ):
+			return join_str.join (
+				get_value_str (
+					v,
+					quote_char = "'" if quoted else None
+				) for v in self.value
+			)
+		# --- end of get_value_strings (...) ---
+
 		value_count = len ( self.value )
+
 		if self.is_bash_array:
 			if value_count == 0:
 				# empty value
 				ret = "()"
-			elif value_count == 1:
-				# one value
-				ret = "('" + str ( self.value [0] ) + "')"
-			elif self.single_line:
-				# several values in a single line
-				ret = self.val_join.join ( self.value )
+
+			elif self.single_line or value_count == 1:
+				# one value or several values in a single line
+				ret = "( " + get_value_strings ( ' ', True ) + " )"
+
 			else:
-				ret = "{intro}{values}{tail}{newline}".format (
-					intro   = '(\n' + self.val_indent \
-						if self.insert_leading_newline else '( ',
-					values  = self.line_join.join (
-						"'" + str ( x ) + "'" for x in self.value
+				ret = "{head}{values}{tail}".format (
+					head   = (
+						( '(\n' + self.val_indent )
+						if self.insert_leading_newline else '( '
 					),
-					tail    = '\n{indent})'.format ( indent=self.var_indent ),
-					newline = self.var_indent + '\n' \
-						if self.append_indented_newline else ''
+					values = get_value_strings ( self.line_join_str, True ),
+					tail   = '\n' + self.var_indent + ')\n'
 				)
 		else:
 			if value_count == 0:
 				ret = ""
-			elif value_count == 1:
-				ret = str ( self.value [0] )
+			elif self.single_line or value_count == 1:
+				ret = get_value_strings ( ' ' )
 			else:
 				if self.insert_leading_newline:
 					ret  = '\n' + self.val_indent
-					ret += self.line_join.join ( ( self.value ) )
+					ret += get_value_strings ( self.line_join_str )
 				else:
-					ret  = self.line_join.join ( ( self.value ) )
+					ret  = get_value_strings ( self.line_join_str )
 
 				if self.append_indented_newline:
-					ret += self.var_indent + '\n'
+					ret += '\n' + self.var_indent
 
 		return ret
 	# --- end of to_str (...) ---
 
 	__str__ = to_str
 
+# --- end of ListValue ---
+
 
 class EbuildVar ( object ):
 	"""An ebuild variable."""
 
-	IGNORED_VALUE_CHARS = re.compile ( "[\"'`¸]" )
-
 	def __init__ ( self, name, value, priority, param_expansion=True ):
 		"""Initializes an EbuildVar.
 
@@ -199,11 +263,20 @@ class EbuildVar ( object ):
 			return True
 	# --- end of active (...) ---
 
-	def _quote_value ( self ):
-		if hasattr ( self, '_get_value_str' ):
-			vstr = self._get_value_str()
+	def _get_value_str ( self ):
+		# hasattr ( ?? )
+		if isinstance ( self.value, ListValue ):
+			return self.value.to_str()
 		else:
-			vstr = str ( self.value )
+			return get_value_str ( self.value )
+	# --- end of _get_value_str (...) ---
+
+	def _quote_value ( self ):
+		vstr = self._get_value_str()
+
+		if hasattr ( self, '_transform_value_str' ):
+			vstr = self._transform_value_str ( vstr )
+		# -- end if
 
 		if self.use_param_expansion is None:
 			# value quoting / unquoting is disabled
@@ -217,7 +290,7 @@ class EbuildVar ( object ):
 			if len ( vstr ) == 0:
 				return 2 * q
 			else:
-				return q + EbuildVar.IGNORED_VALUE_CHARS.sub ( '', vstr ) + q
+				return q + vstr + q
 	# --- end of _quote_value (...) ---
 
 	def __str__ ( self ):
@@ -233,3 +306,5 @@ class EbuildVar ( object ):
 			# contain only quote chars
 			return self._empty_str() if hasattr ( self, '_empty_str' ) else ""
 	# --- end of __str__ (...) ---
+
+# --- end of EbuildVar ---

diff --git a/roverlay/ebuild/evars.py b/roverlay/ebuild/evars.py
index cb3ec17..cd8becb 100644
--- a/roverlay/ebuild/evars.py
+++ b/roverlay/ebuild/evars.py
@@ -17,39 +17,44 @@ __all__ = [ 'DEPEND', 'DESCRIPTION', 'IUSE', 'MISSINGDEPS',
 	'RDEPEND', 'R_SUGGESTS', 'SRC_URI', 'KEYWORDS',
 ]
 
-from roverlay import strutil
+import roverlay.strutil
 
 from roverlay.ebuild.abstractcomponents import ListValue, EbuildVar
 
 IUSE_SUGGESTS = 'R_suggests'
 RSUGGESTS_NAME = IUSE_SUGGESTS.upper()
 
-SEE_METADATA = '... (see metadata)'
-
-# ignoring case policies here (camel case,..)
+# ignoring style guide here (camel case, ...)
 
 class DESCRIPTION ( EbuildVar ):
 	"""A DESCRIPTION="..." statement."""
-	def __init__ ( self, description, maxlen=50 ):
+
+	SEE_METADATA = '... (see metadata)'
+
+	def __init__ ( self, description, maxlen=None ):
 		"""A DESCRIPTION="..." statement. Long values will be truncated.
 
 		arguments:
 		* description -- description text
-		* maxlen      -- maximum value length (defaults to 50 chars)
+		* maxlen      -- maximum value length (>0, defaults to 50 chars)
 		"""
+		assert maxlen is None or maxlen > 0
+
 		super ( DESCRIPTION, self ) . __init__ (
 			name='DESCRIPTION',
 			value=description,
 			priority=80, param_expansion=False
 		)
-		self.maxlen = 50 if maxlen is None else maxlen
+		self.maxlen = maxlen or 50
 	# --- end of __init__ (...) ---
 
-	def _get_value_str ( self ):
-		return strutil.shorten_str (
-			strutil.ascii_filter ( str ( self.value ) ), self.maxlen, SEE_METADATA
+	def _transform_value_str ( self, _str ):
+		return roverlay.strutil.shorten_str (
+			_str,
+			self.maxlen,
+			self.SEE_METADATA
 		)
-	# --- end of _get_value_str (...) ---
+	# --- end of _transform_value_str (...) ---
 
 
 class KEYWORDS ( EbuildVar ):


             reply	other threads:[~2013-04-25 16:44 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-25 16:44 André Erdmann [this message]
  -- strict thread matches above, loose matches on Subject: below --
2023-08-01  3:38 [gentoo-commits] proj/R_overlay:master commit in: roverlay/ebuild/ Benda XU
2019-08-17 16:41 Benda XU
2013-09-05 15:43 André Erdmann
2013-08-28  9:38 André Erdmann
2013-08-23 13:52 André Erdmann
2013-07-29  8:55 André Erdmann
2013-07-25 16:39 André Erdmann
2013-07-25 13:25 André Erdmann
2013-07-25  8:06 André Erdmann
2013-07-25  8:06 André Erdmann
2013-07-10 16:16 André Erdmann
2013-07-10  8:26 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-10 16:16 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-19 18:58 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-19 18:59 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-05 18:08 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-04-25 16:44 André Erdmann
2013-01-30 20:16 André Erdmann
2013-01-30 20:16 André Erdmann
2013-01-30 20:16 André Erdmann
2013-01-30 20:16 André Erdmann
2012-08-09  9:26 André Erdmann
2012-08-07  8:50 André Erdmann
2012-08-03 13:38 André Erdmann
2012-08-03 13:38 André Erdmann
2012-08-02 15:14 André Erdmann
2012-08-02 15:14 André Erdmann
2012-07-30  8:52 [gentoo-commits] proj/R_overlay:overlay_wip " André Erdmann
2012-07-30  8:52 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2012-07-16 16:15 André Erdmann
2012-07-16 16:15 André Erdmann
2012-07-12 18:04 André Erdmann
2012-07-06 22:19 André Erdmann
2012-06-29 22:48 André Erdmann
2012-06-29 22:48 André Erdmann
2012-06-29 22:48 André Erdmann
2012-06-29 22:48 André Erdmann
2012-06-28 15:55 André Erdmann
2012-06-28 13:29 André Erdmann
2012-06-26 15:42 André Erdmann
2012-06-21 16:55 André Erdmann
2012-06-20 19:03 André Erdmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1363536390.fd838576df5db122a01f3e2001577842db3575a3.dywi@gentoo \
    --to=dywi@mailerd.de \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox