main.py 3.35 KB
Newer Older
jvoisin's avatar
jvoisin committed
1
#!/usr/bin/python3
2

jvoisin's avatar
jvoisin committed
3
import os
4
5
6
from typing import Tuple
import sys
import itertools
jvoisin's avatar
jvoisin committed
7
import mimetypes
jvoisin's avatar
jvoisin committed
8
import argparse
jvoisin's avatar
jvoisin committed
9
import multiprocessing
jvoisin's avatar
jvoisin committed
10

jvoisin's avatar
jvoisin committed
11
from src import parser_factory
jvoisin's avatar
jvoisin committed
12

jvoisin's avatar
jvoisin committed
13
__version__ = '0.1'
jvoisin's avatar
jvoisin committed
14

jvoisin's avatar
jvoisin committed
15
def __check_file(filename:str, mode:int = os.R_OK) -> bool:
jvoisin's avatar
jvoisin committed
16
17
18
19
20
21
22
    if not os.path.isfile(filename):
        print("[-] %s is not a regular file." % filename)
        return False
    elif not os.access(filename, mode):
        print("[-] %s is not readable and writeable." % filename)
        return False
    return True
jvoisin's avatar
jvoisin committed
23

24

jvoisin's avatar
jvoisin committed
25
26
27
def create_arg_parser():
    parser = argparse.ArgumentParser(description='Metadata anonymisation toolkit 2')
    parser.add_argument('files', nargs='*')
jvoisin's avatar
jvoisin committed
28
29
    parser.add_argument('-v', '--version', action='version',
            version='MAT2 %s' % __version__)
jvoisin's avatar
jvoisin committed
30
31
32
33
34
35
36
37

    info = parser.add_argument_group('Information')
    info.add_argument('-c', '--check', action='store_true',
                      help='check if a file is free of harmful metadatas')
    info.add_argument('-l', '--list', action='store_true',
                      help='list all supported fileformats')
    info.add_argument('-s', '--show', action='store_true',
                      help='list all the harmful metadata of a file without removing them')
jvoisin's avatar
jvoisin committed
38
39
    info.add_argument('-L', '--lightweight', action='store_true',
                      help='remove SOME metadata')
jvoisin's avatar
jvoisin committed
40
41
    return parser

42

jvoisin's avatar
jvoisin committed
43
def show_meta(filename:str):
jvoisin's avatar
jvoisin committed
44
45
46
    if not __check_file(filename):
        return

47
    p, mtype = parser_factory.get_parser(filename)
jvoisin's avatar
jvoisin committed
48
    if p is None:
jvoisin's avatar
jvoisin committed
49
        print("[-] %s's format (%s) is not supported" % (filename, mtype))
jvoisin's avatar
jvoisin committed
50
        return
jvoisin's avatar
jvoisin committed
51
    print("[+] Metadata for %s:" % filename)
jvoisin's avatar
jvoisin committed
52
    for k,v in p.get_meta().items():
jvoisin's avatar
jvoisin committed
53
54
55
56
        try:  # FIXME this is ugly.
            print("  %s: %s" % (k, v))
        except UnicodeEncodeError:
            print("  %s: harmful content" % k)
jvoisin's avatar
jvoisin committed
57

58

59
60
def clean_meta(params:Tuple[str, bool]) -> bool:
    filename, is_lightweigth = params
jvoisin's avatar
jvoisin committed
61
62
63
    if not __check_file(filename, os.R_OK|os.W_OK):
        return

jvoisin's avatar
jvoisin committed
64
    p, mtype = parser_factory.get_parser(filename)
jvoisin's avatar
jvoisin committed
65
66
    if p is None:
        print("[-] %s's format (%s) is not supported" % (filename, mtype))
67
        return False
jvoisin's avatar
jvoisin committed
68
    if is_lightweigth:
jvoisin's avatar
jvoisin committed
69
70
        return p.remove_all_lightweight()
    return p.remove_all()
jvoisin's avatar
jvoisin committed
71

72

73
74
75
76
77
78
79
def show_parsers():
    print('[+] Supported formats:')
    for parser in parser_factory._get_parsers():
        for mtype in parser.mimetypes:
            extensions = ', '.join(mimetypes.guess_all_extensions(mtype))
            print('  - %s (%s)' % (mtype, extensions))

80

81
82
83
84
85
86
87
88
89
def __get_files_recursively(files):
    for f in files:
        if os.path.isfile(f):
            yield f
        else:
            for path, _, _files in os.walk(f):
                for _f in _files:
                    yield os.path.join(path, _f)

jvoisin's avatar
jvoisin committed
90
def main():
jvoisin's avatar
jvoisin committed
91
92
    arg_parser = create_arg_parser()
    args = arg_parser.parse_args()
jvoisin's avatar
jvoisin committed
93

94
95
96
97
98
99
    if not args.files:
        if not args.list:
            return arg_parser.print_help()
        show_parsers()
        return

jvoisin's avatar
jvoisin committed
100
    elif args.show:
jvoisin's avatar
jvoisin committed
101
        for f in __get_files_recursively(args.files):
jvoisin's avatar
jvoisin committed
102
            show_meta(f)
jvoisin's avatar
jvoisin committed
103
104
        return

105
106
    else:
        p = multiprocessing.Pool()
jvoisin's avatar
jvoisin committed
107
        mode = (args.lightweight is True)
108
        l = zip(__get_files_recursively(args.files), itertools.repeat(mode))
jvoisin's avatar
jvoisin committed
109

110
111
        ret = list(p.imap_unordered(clean_meta, list(l)))
        return 0 if all(ret) else -1
jvoisin's avatar
jvoisin committed
112
113

if __name__ == '__main__':
114
    sys.exit(main())