mirror of
				https://github.com/9001/copyparty.git
				synced 2025-10-31 12:03:32 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			140 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python3
 | |
| # coding: utf-8
 | |
| from __future__ import print_function, unicode_literals
 | |
| 
 | |
| import re
 | |
| import unittest
 | |
| 
 | |
| from xml.etree import ElementTree as ET
 | |
| from copyparty.dxml import parse_xml, BadXML, mkenod, mktnod
 | |
| 
 | |
| ET.register_namespace("D", "DAV:")
 | |
| 
 | |
| 
 | |
| def _parse(txt):
 | |
|     try:
 | |
|         parse_xml(txt)
 | |
|         raise Exception("unsafe")
 | |
|     except BadXML:
 | |
|         pass
 | |
| 
 | |
| 
 | |
| class TestDXML(unittest.TestCase):
 | |
|     def test1(self):
 | |
|         txt = r"""<!DOCTYPE qbe [
 | |
| <!ENTITY a "nice_bakuretsu">
 | |
| ]>
 | |
| <l>&a;&a;&a;&a;&a;&a;&a;&a;&a;</l>"""
 | |
|         _parse(txt)
 | |
|         ET.fromstring(txt)
 | |
| 
 | |
|     def test2(self):
 | |
|         txt = r"""<!DOCTYPE ext [
 | |
| <!ENTITY ee SYSTEM "file:///bin/bash">
 | |
| ]>
 | |
| <root>ⅇ</root>"""
 | |
|         _parse(txt)
 | |
|         try:
 | |
|             ET.fromstring(txt)
 | |
|             raise Exception("unsafe2")
 | |
|         except ET.ParseError:
 | |
|             pass
 | |
| 
 | |
|     def test3(self):
 | |
|         txt = r"""<?xml version="1.0" ?>
 | |
| <propfind xmlns="DAV:">
 | |
|     <prop>
 | |
|         <name/>
 | |
|         <href/>
 | |
|     </prop>
 | |
| </propfind>
 | |
| """
 | |
|         txt = txt.replace("\n", "\r\n")
 | |
|         ET.fromstring(txt)
 | |
|         el = parse_xml(txt)
 | |
|         self.assertListEqual(
 | |
|             [y.tag for y in el.findall(r"./{DAV:}prop/*")],
 | |
|             [r"{DAV:}name", r"{DAV:}href"],
 | |
|         )
 | |
| 
 | |
|     def test4(self):
 | |
|         txt = r"""<?xml version="1.0" encoding="utf-8" ?>
 | |
| <D:propertyupdate xmlns:D="DAV:" xmlns:Z="urn:schemas-microsoft-com:">
 | |
|     <D:set>
 | |
|         <D:prop>
 | |
|             <Z:Win32CreationTime>Thu, 20 Oct 2022 02:16:33 GMT</Z:Win32CreationTime>
 | |
|             <Z:Win32LastAccessTime>Thu, 20 Oct 2022 02:16:35 GMT</Z:Win32LastAccessTime>
 | |
|             <Z:Win32LastModifiedTime>Thu, 20 Oct 2022 02:16:33 GMT</Z:Win32LastModifiedTime>
 | |
|             <Z:Win32FileAttributes>00000000</Z:Win32FileAttributes>
 | |
|         </D:prop>
 | |
|     </D:set>
 | |
| </D:propertyupdate>"""
 | |
| 
 | |
|         ref = r"""<?xml version="1.0" encoding="UTF-8"?>
 | |
| <D:multistatus xmlns:D="DAV:">
 | |
|     <D:response>
 | |
|         <D:href>/d1/foo.txt</D:href>
 | |
|         <D:propstat>
 | |
|             <D:prop>
 | |
|                 <Win32CreationTime xmlns="urn:schemas-microsoft-com:"></Win32CreationTime>
 | |
|                 <Win32LastAccessTime xmlns="urn:schemas-microsoft-com:"></Win32LastAccessTime>
 | |
|                 <Win32LastModifiedTime xmlns="urn:schemas-microsoft-com:"></Win32LastModifiedTime>
 | |
|                 <Win32FileAttributes xmlns="urn:schemas-microsoft-com:"></Win32FileAttributes>
 | |
|             </D:prop>
 | |
|             <D:status>HTTP/1.1 403 Forbidden</D:status>
 | |
|         </D:propstat>
 | |
|     </D:response>
 | |
| </D:multistatus>"""
 | |
| 
 | |
|         txt = re.sub("\n +", "\n", txt)
 | |
|         root = mkenod("a")
 | |
|         root.insert(0, parse_xml(txt))
 | |
|         prop = root.find(r"./{DAV:}propertyupdate/{DAV:}set/{DAV:}prop")
 | |
|         assert prop
 | |
|         for el in prop:
 | |
|             el.clear()
 | |
| 
 | |
|         res = ET.tostring(prop).decode("utf-8")
 | |
|         want = """<D:prop xmlns:D="DAV:" xmlns:ns1="urn:schemas-microsoft-com:">
 | |
| <ns1:Win32CreationTime /><ns1:Win32LastAccessTime /><ns1:Win32LastModifiedTime /><ns1:Win32FileAttributes /></D:prop>
 | |
| """
 | |
|         self.assertEqual(res, want)
 | |
| 
 | |
|     def test5(self):
 | |
|         txt = r"""<?xml version="1.0" encoding="utf-8" ?>
 | |
| <D:lockinfo xmlns:D="DAV:">
 | |
|     <D:lockscope><D:exclusive/></D:lockscope>
 | |
|     <D:locktype><D:write/></D:locktype>
 | |
|     <D:owner><D:href>DESKTOP-FRS9AO2\ed</D:href></D:owner>
 | |
| </D:lockinfo>"""
 | |
| 
 | |
|         ref = r"""<?xml version="1.0" encoding="utf-8"?>
 | |
| <D:prop xmlns:D="DAV:"><D:lockdiscovery><D:activelock>
 | |
|     <D:locktype><D:write/></D:locktype>
 | |
|     <D:lockscope><D:exclusive/></D:lockscope>
 | |
|     <D:depth>infinity</D:depth>
 | |
|     <D:owner><D:href>DESKTOP-FRS9AO2\ed</D:href></D:owner>
 | |
|     <D:timeout>Second-3600</D:timeout>
 | |
|     <D:locktoken><D:href>1666199679</D:href></D:locktoken>
 | |
|     <D:lockroot><D:href>/d1/foo.txt</D:href></D:lockroot>
 | |
| </D:activelock></D:lockdiscovery></D:prop>"""
 | |
| 
 | |
|         txt = re.sub("\n +", "\n", txt)
 | |
|         ns = {"": "DAV:"}
 | |
|         lk = parse_xml(txt)
 | |
|         self.assertEqual(lk.tag, "{DAV:}lockinfo")
 | |
| 
 | |
|         if not lk.find(r"./{DAV:}depth"):
 | |
|             lk.append(mktnod("D:depth", "infinity"))
 | |
| 
 | |
|         lk.append(mkenod("D:timeout", mktnod("D:href", "Second-3600")))
 | |
|         lk.append(mkenod("D:locktoken", mktnod("D:href", "56709")))
 | |
|         lk.append(mkenod("D:lockroot", mktnod("D:href", "/foo/bar.txt")))
 | |
| 
 | |
|         lk2 = mkenod("D:activelock")
 | |
|         root = mkenod("D:prop", mkenod("D:lockdiscovery", lk2))
 | |
|         for a in lk:
 | |
|             lk2.append(a)
 | |
| 
 | |
|         print(ET.tostring(root).decode("utf-8"))
 |