diff --git a/filenuke/__init__.py b/filenuke/__init__.py old mode 100644 new mode 100755 index 93c6d7f..3eecc7c --- a/filenuke/__init__.py +++ b/filenuke/__init__.py @@ -1,8 +1,18 @@ #!/usr/bin/env python3 import sys +import os -from . import nuke +import nuke if __name__ == "__main__": - pass + try: + path_to_del = sys.argv[1] + except IndexError: + sys.exit(1) + if os.path.isfile(path_to_del): + nuke.clean(path_to_del) + else: + nuke.clean_tree(path_to_del) + print(f'Overwrote and deleted {path_to_del}') + diff --git a/filenuke/nuke.py b/filenuke/nuke.py index 73ea2b2..557f56b 100644 --- a/filenuke/nuke.py +++ b/filenuke/nuke.py @@ -1,11 +1,12 @@ import os -import sys +import shutil import secrets import string from typing import NewType NewPath = NewType('NewPath', str) + def _overwrite_file(file_path: str, passes: int, zeros=False): """overwrite a single file with secure random data passes times uses secrets library or zeros is zeros is set to true""" @@ -19,14 +20,14 @@ def _overwrite_file(file_path: str, passes: int, zeros=False): with open(file_path, 'wb') as top_secret_file: top_secret_file.write(new_data) + print('wrote to', file_path) -def _rename_inode(path: str, zeros=False) -> NewPath: +def _rename_inode(path_in: str, zeros=False) -> NewPath: """renames file randomly, or with zeros if zeros is true""" - name_len = len(os.path.basename(path)) + name_len = len(os.path.basename(path_in)) new_name = '' - path = os.path.abspath(path) - assert os.path.exists(path) + path = os.path.abspath(path_in) if zeros: new_name = '0' * name_len @@ -34,16 +35,33 @@ def _rename_inode(path: str, zeros=False) -> NewPath: for _ in range(name_len): new_name += secrets.choice(string.ascii_letters) - new_path = os.path.dirname(path) + '/' + new_name - os.rename(path, new_path) + os.rename(path, new_name) - return new_path + return new_name + + +def _nuke(path: str): + """properly delete inode""" + if os.path.isfile(path): + _overwrite_file(path, 1) + new_path = _rename_inode(path) + os.remove(new_path) + else: + new_path = _rename_inode(path) + shutil.rmtree(new_path) def clean_tree(directory: str): - for subdir, dirs, files in os.walk(directory): - for file in files: - print(os.path.join(subdir, file)) + """securely delete dir tree""" -def nuke(path: str): - os.remove(path) + for root, dirs, files in os.walk(directory, topdown=False): + for name in files: + _nuke(os.path.join(root, name)) + for name in dirs: + _nuke(os.path.join(root, name)) + _nuke(root) + + +def clean(path: str): + """securely delete path""" + _nuke(path) diff --git a/setup.py b/setup.py index 5854fab..039edb0 100644 --- a/setup.py +++ b/setup.py @@ -8,6 +8,7 @@ setup(name='filenuke', url='https://chaoswebs.net/', packages=find_packages(exclude=['contrib', 'docs', 'tests']), install_requires=[], + python_requires='>=3.6', classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", diff --git a/tests/test.py b/tests/test.py index 129c97e..89bfb59 100644 --- a/tests/test.py +++ b/tests/test.py @@ -2,6 +2,7 @@ import unittest import sys import os import uuid +import shutil sys.path.append(".") import filenuke from filenuke import nuke @@ -15,7 +16,7 @@ class TestErase(unittest.TestCase): f = get_file() with open(f, "w") as test_f: test_f.write('hello world') - filenuke.nuke.nuke(f) + filenuke.nuke._nuke(f) self.assertFalse(os.path.exists(f)) def test_overwrite_single(self): @@ -23,12 +24,39 @@ class TestErase(unittest.TestCase): with open(f, "w") as test_f: test_f.write('hello world') nuke._overwrite_file(f, 1) - - def test_rename(self): + with open(f, "rb") as test_f: + self.assertNotEqual(test_f.read(), b'hello world') + + def test_nuke_single(self): f = get_file() with open(f, "w") as test_f: test_f.write('hello world') - + nuke._nuke(f) + self.assertFalse(os.path.exists(f)) + + def test_nuke(self): + try: + os.mkdir('test') + except FileExistsError: pass + with open('test/test.txt', 'w') as f: + f.write('test') + try: + os.mkdir('test/test2/') + except FileExistsError: pass + try: + os.mkdir('test/test2/test3/') + except FileExistsError: pass + with open('test/test2/test-f.txt', 'w') as f: + f.write('test') + nuke._nuke('test') + self.assertFalse(os.path.exists('test/')) + + def test_rename(self): + f = os.path.basename(get_file()) + with open(f, "w") as test_f: + test_f.write('hello world') + with open(f, "r") as test_f: + self.assertEqual(test_f.read(), 'hello world') new_name = nuke._rename_inode(f) self.assertFalse(os.path.exists(f)) self.assertTrue(os.path.exists(new_name)) @@ -41,11 +69,12 @@ class TestErase(unittest.TestCase): self.assertEqual(len(os.path.basename(new_name)), len(f)) self.assertGreater(len(os.path.basename(new_name)), 0) + with open(new_name, "r") as test_f: self.assertEqual(test_f.read(), 'hello world') def test_rename_zeros(self): - f = get_file() + f = os.path.basename(get_file()) with open(f, "w") as test_f: test_f.write('hello world') @@ -63,4 +92,11 @@ class TestErase(unittest.TestCase): with open(new_name, "r") as test_f: self.assertEqual(test_f.read(), 'hello world') -unittest.main() \ No newline at end of file +try: + os.mkdir('testdata') +except FileExistsError: + pass +os.chdir('testdata') +unittest.main() +os.chdir('..') +shutil.rmtree('testdata')