comparison test/test_cgi.py @ 6190:15fd91fd3c4c

Quote all exported CSV data Quote all non-numeric data in csv export functions. Report that a title like '=a2+b3' could be interpreted as a function in Excel and executed. csv.writer now includes quoting=csv.QUOTE_NONNUMERIC to generate quoted values for all fields. This should make the string starting with = be interpreted as a string and not a formula.
author John Rouillard <rouilj@ieee.org>
date Mon, 08 Jun 2020 16:18:21 -0400
parents f74d078cfd9a
children bdcccd2b2141
comparison
equal deleted inserted replaced
6189:7458211ca6f3 6190:15fd91fd3c4c
1790 output = io.BytesIO() 1790 output = io.BytesIO()
1791 cl.request = MockNull() 1791 cl.request = MockNull()
1792 cl.request.wfile = output 1792 cl.request.wfile = output
1793 # call export version that outputs names 1793 # call export version that outputs names
1794 actions.ExportCSVAction(cl).handle() 1794 actions.ExportCSVAction(cl).handle()
1795 #print(output.getvalue()) 1795 should_be=(s2b('"id","title","status","keyword","assignedto","nosy"\r\n'
1796 should_be=(s2b('id,title,status,keyword,assignedto,nosy\r\n' 1796 '"1","foo1","deferred","","Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n'
1797 '1,foo1,deferred,,"Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n' 1797 '"2","bar2","unread","keyword1;keyword2","Bork, Chef","Bork, Chef"\r\n'
1798 '2,bar2,unread,keyword1;keyword2,"Bork, Chef","Bork, Chef"\r\n' 1798 '"3","baz32","need-eg","","",""\r\n'))
1799 '3,baz32,need-eg,,,\r\n'))
1800 #print(should_be) 1799 #print(should_be)
1801 #print(output.getvalue()) 1800 print(output.getvalue())
1802 self.assertEqual(output.getvalue(), should_be) 1801 self.assertEqual(output.getvalue(), should_be)
1803 output = io.BytesIO() 1802 output = io.BytesIO()
1804 cl.request = MockNull() 1803 cl.request = MockNull()
1805 cl.request.wfile = output 1804 cl.request.wfile = output
1806 # call export version that outputs id numbers 1805 # call export version that outputs id numbers
1807 actions.ExportCSVWithIdAction(cl).handle() 1806 actions.ExportCSVWithIdAction(cl).handle()
1807 should_be = s2b('"id","title","status","keyword","assignedto","nosy"\r\n'
1808 "\"1\",\"foo1\",\"2\",\"[]\",\"4\",\"['3', '4', '5']\"\r\n"
1809 "\"2\",\"bar2\",\"1\",\"['1', '2']\",\"3\",\"['3']\"\r\n"
1810 '\"3\","baz32",\"4\","[]","None","[]"\r\n')
1811 #print(should_be)
1808 print(output.getvalue()) 1812 print(output.getvalue())
1809 self.assertEqual(s2b('id,title,status,keyword,assignedto,nosy\r\n' 1813 self.assertEqual(output.getvalue(), should_be)
1810 "1,foo1,2,[],4,\"['3', '4', '5']\"\r\n"
1811 "2,bar2,1,\"['1', '2']\",3,['3']\r\n"
1812 '3,baz32,4,[],None,[]\r\n'),
1813 output.getvalue())
1814 1814
1815 def testCSVExportCharset(self): 1815 def testCSVExportCharset(self):
1816 cl = self._make_client( 1816 cl = self._make_client(
1817 {'@columns': 'id,title,status,keyword,assignedto,nosy'}, 1817 {'@columns': 'id,title,status,keyword,assignedto,nosy'},
1818 nodeid=None, userid='1') 1818 nodeid=None, userid='1')
1825 output = io.BytesIO() 1825 output = io.BytesIO()
1826 cl.request = MockNull() 1826 cl.request = MockNull()
1827 cl.request.wfile = output 1827 cl.request.wfile = output
1828 # call export version that outputs names 1828 # call export version that outputs names
1829 actions.ExportCSVAction(cl).handle() 1829 actions.ExportCSVAction(cl).handle()
1830 should_be=(b'id,title,status,keyword,assignedto,nosy\r\n' 1830 should_be=(b'"id","title","status","keyword","assignedto","nosy"\r\n'
1831 b'1,foo1\xc3\xa4,deferred,,"Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n') 1831 b'"1","foo1\xc3\xa4","deferred","","Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n')
1832 self.assertEqual(output.getvalue(), should_be) 1832 self.assertEqual(output.getvalue(), should_be)
1833 1833
1834 output = io.BytesIO() 1834 output = io.BytesIO()
1835 cl.request = MockNull() 1835 cl.request = MockNull()
1836 cl.request.wfile = output 1836 cl.request.wfile = output
1837 # call export version that outputs id numbers 1837 # call export version that outputs id numbers
1838 actions.ExportCSVWithIdAction(cl).handle() 1838 actions.ExportCSVWithIdAction(cl).handle()
1839 print(output.getvalue()) 1839 print(output.getvalue())
1840 self.assertEqual(b'id,title,status,keyword,assignedto,nosy\r\n' 1840 self.assertEqual(b'"id","title","status","keyword","assignedto","nosy"\r\n'
1841 b"1,foo1\xc3\xa4,2,[],4,\"['3', '4', '5']\"\r\n", 1841 b"\"1\",\"foo1\xc3\xa4\",\"2\",\"[]\",\"4\",\"['3', '4', '5']\"\r\n",
1842 output.getvalue()) 1842 output.getvalue())
1843 1843
1844 # again with ISO-8859-1 client charset 1844 # again with ISO-8859-1 client charset
1845 cl.charset = 'iso8859-1' 1845 cl.charset = 'iso8859-1'
1846 output = io.BytesIO() 1846 output = io.BytesIO()
1847 cl.request = MockNull() 1847 cl.request = MockNull()
1848 cl.request.wfile = output 1848 cl.request.wfile = output
1849 # call export version that outputs names 1849 # call export version that outputs names
1850 actions.ExportCSVAction(cl).handle() 1850 actions.ExportCSVAction(cl).handle()
1851 should_be=(b'id,title,status,keyword,assignedto,nosy\r\n' 1851 should_be=(b'"id","title","status","keyword","assignedto","nosy"\r\n'
1852 b'1,foo1\xe4,deferred,,"Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n') 1852 b'"1","foo1\xe4","deferred","","Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n')
1853 self.assertEqual(output.getvalue(), should_be) 1853 self.assertEqual(output.getvalue(), should_be)
1854 1854
1855 output = io.BytesIO() 1855 output = io.BytesIO()
1856 cl.request = MockNull() 1856 cl.request = MockNull()
1857 cl.request.wfile = output 1857 cl.request.wfile = output
1858 # call export version that outputs id numbers 1858 # call export version that outputs id numbers
1859 actions.ExportCSVWithIdAction(cl).handle() 1859 actions.ExportCSVWithIdAction(cl).handle()
1860 print(output.getvalue()) 1860 print(output.getvalue())
1861 self.assertEqual(b'id,title,status,keyword,assignedto,nosy\r\n' 1861 self.assertEqual(b'"id","title","status","keyword","assignedto","nosy"\r\n'
1862 b"1,foo1\xe4,2,[],4,\"['3', '4', '5']\"\r\n", 1862 b"\"1\",\"foo1\xe4\",\"2\",\"[]\",\"4\",\"['3', '4', '5']\"\r\n",
1863 output.getvalue()) 1863 output.getvalue())
1864 1864
1865 def testCSVExportBadColumnName(self): 1865 def testCSVExportBadColumnName(self):
1866 cl = self._make_client({'@columns': 'falseid,name'}, nodeid=None, 1866 cl = self._make_client({'@columns': 'falseid,name'}, nodeid=None,
1867 userid='1') 1867 userid='1')
1901 # used to be self.assertRaises(exceptions.Unauthorised, 1901 # used to be self.assertRaises(exceptions.Unauthorised,
1902 # but not acting like the column name is not found 1902 # but not acting like the column name is not found
1903 1903
1904 actions.ExportCSVAction(cl).handle() 1904 actions.ExportCSVAction(cl).handle()
1905 #print(output.getvalue()) 1905 #print(output.getvalue())
1906 self.assertEqual(s2b('id,username,address,password\r\n' 1906 self.assertEqual(s2b('"id","username","address","password"\r\n'
1907 '1,admin,[hidden],[hidden]\r\n' 1907 '"1","admin","[hidden]","[hidden]"\r\n'
1908 '2,anonymous,[hidden],[hidden]\r\n' 1908 '"2","anonymous","[hidden]","[hidden]"\r\n'
1909 '3,Chef,[hidden],[hidden]\r\n' 1909 '"3","Chef","[hidden]","[hidden]"\r\n'
1910 '4,mary,[hidden],[hidden]\r\n' 1910 '"4","mary","[hidden]","[hidden]"\r\n'
1911 '5,demo,demo@test.test,%s\r\n'%(passwd)), 1911 '"5","demo","demo@test.test","%s"\r\n'%(passwd)),
1912 output.getvalue()) 1912 output.getvalue())
1913 1913
1914 def testCSVExportWithId(self): 1914 def testCSVExportWithId(self):
1915 cl = self._make_client({'@columns': 'id,name'}, nodeid=None, 1915 cl = self._make_client({'@columns': 'id,name'}, nodeid=None,
1916 userid='1') 1916 userid='1')
1917 cl.classname = 'status' 1917 cl.classname = 'status'
1918 output = io.BytesIO() 1918 output = io.BytesIO()
1919 cl.request = MockNull() 1919 cl.request = MockNull()
1920 cl.request.wfile = output 1920 cl.request.wfile = output
1921 actions.ExportCSVWithIdAction(cl).handle() 1921 actions.ExportCSVWithIdAction(cl).handle()
1922 self.assertEqual(s2b('id,name\r\n1,unread\r\n2,deferred\r\n3,chatting\r\n' 1922 self.assertEqual(s2b('"id","name"\r\n"1","unread"\r\n"2","deferred"\r\n"3","chatting"\r\n'
1923 '4,need-eg\r\n5,in-progress\r\n6,testing\r\n7,done-cbb\r\n' 1923 '"4","need-eg"\r\n"5","in-progress"\r\n"6","testing"\r\n"7","done-cbb"\r\n'
1924 '8,resolved\r\n'), 1924 '"8","resolved"\r\n'),
1925 output.getvalue()) 1925 output.getvalue())
1926 1926
1927 def testCSVExportWithIdBadColumnName(self): 1927 def testCSVExportWithIdBadColumnName(self):
1928 cl = self._make_client({'@columns': 'falseid,name'}, nodeid=None, 1928 cl = self._make_client({'@columns': 'falseid,name'}, nodeid=None,
1929 userid='1') 1929 userid='1')

Roundup Issue Tracker: http://roundup-tracker.org/