74 lines
2.5 KiB
Python
74 lines
2.5 KiB
Python
import os, tempfile, unittest
|
|
from path_sandbox import PathEscapeError, safe_join, safe_resolve, is_within, realpath_root
|
|
|
|
|
|
class TestPathSandbox(unittest.TestCase):
|
|
def setUp(self):
|
|
self.d = tempfile.mkdtemp()
|
|
self.root = os.path.join(self.d, "root")
|
|
os.makedirs(self.root)
|
|
self.rr = os.path.realpath(self.root)
|
|
# a file inside
|
|
with open(os.path.join(self.root, "a.txt"), "w") as f:
|
|
f.write("x")
|
|
# subdir
|
|
os.makedirs(os.path.join(self.root, "sub"))
|
|
# symlink escaping root
|
|
os.symlink("/etc", os.path.join(self.root, "escape"))
|
|
|
|
def test_basic_join(self):
|
|
self.assertEqual(safe_join(self.root, "a.txt"), os.path.join(self.rr, "a.txt"))
|
|
|
|
def test_nested(self):
|
|
self.assertEqual(safe_join(self.root, "sub", "b.txt"), os.path.join(self.rr, "sub", "b.txt"))
|
|
|
|
def test_traversal_rejected(self):
|
|
with self.assertRaises(PathEscapeError):
|
|
safe_join(self.root, "..", "etc", "passwd")
|
|
|
|
def test_absolute_rejected(self):
|
|
with self.assertRaises(PathEscapeError):
|
|
safe_join(self.root, "/etc/passwd")
|
|
|
|
def test_backslash_rejected(self):
|
|
with self.assertRaises(PathEscapeError):
|
|
safe_join(self.root, "a\\..\\..\\etc")
|
|
|
|
def test_nul_rejected(self):
|
|
with self.assertRaises(PathEscapeError):
|
|
safe_join(self.root, "a\x00b")
|
|
|
|
def test_symlink_escape_rejected(self):
|
|
with self.assertRaises(PathEscapeError):
|
|
safe_join(self.root, "escape", "passwd")
|
|
|
|
def test_empty_root_error(self):
|
|
with self.assertRaises(PathEscapeError):
|
|
realpath_root("")
|
|
|
|
def test_nonexistent_root_error(self):
|
|
with self.assertRaises(PathEscapeError):
|
|
realpath_root(os.path.join(self.d, "nope"))
|
|
|
|
def test_is_within_true(self):
|
|
self.assertTrue(is_within(self.root, os.path.join(self.root, "a.txt")))
|
|
|
|
def test_is_within_false(self):
|
|
self.assertFalse(is_within(self.root, "/etc/passwd"))
|
|
|
|
def test_safe_resolve_list(self):
|
|
self.assertEqual(safe_resolve(self.root, ["sub", "x"]), os.path.join(self.rr, "sub", "x"))
|
|
|
|
def test_dot_components_ok(self):
|
|
# single "." components collapse
|
|
p = safe_join(self.root, ".", "a.txt")
|
|
self.assertEqual(p, os.path.join(self.rr, "a.txt"))
|
|
|
|
def test_double_slash_ok(self):
|
|
p = safe_join(self.root, "sub//b.txt")
|
|
self.assertEqual(p, os.path.join(self.rr, "sub", "b.txt"))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|