jblu

jblu / working_dedupe.py

Last active 6 months ago

Like 0
working_dedupe.py Raw
1#!/usr/bin/env python3
2
3# dedup.py
4# Removes duplicates from Bitwarden export .csv
5# 2019-02-09 5erif
6
7import sys
8import hashlib
9from urllib.parse import urlparse
10
11# Field ordinals in Bitwarden CSV
12FOLDER = 0
13FAVORITE = 1
14TYPE = 2
15NAME = 3
16NOTES = 4
17FIELDS = 5
18REPROMPT = 6
19URI = 7
20USERNAME = 8
21PASSWORD = 9
22TOTP = 10
23
24DEBUG = False
25def main(argv):
26
27 if len(argv) < 1:
28 print('Missing input file path')
29 sys.exit(1)
30
31 in_file_path = argv[0]
32 out_file_path = in_file_path[0:(len(in_file_path)-4)]+'_out.csv'
33 rem_file_path = in_file_path[0:(len(in_file_path)-4)]+'_rem.csv'
34 completed_lines_hash = set()
35 line_number = -1
36 write_count = 0
37 cache = ''
38
39 out_file = open(out_file_path, 'w', encoding = 'utf8')
40 rem_file = open(rem_file_path, 'w', encoding = 'utf8')
41 for line in open(in_file_path, 'r', encoding = 'utf8'):
42 line_number += 1
43 fields = line.split(',')
44 if len(fields) < 10:
45 # Add previous line if short
46 line = cache.strip('\n') + line
47 cache = line
48 fields = line.split(',')
49 if len(fields) > 9:
50 print(f'Recovered with line {line_number}:\n{line}')
51 cache = ''
52 else:
53 print(f'Missing fields in line {line_number}:\n{line}')
54 rem_file.write(line)
55 continue
56 else:
57 cache = ''
58 if line_number != 0:
59 domain = urlparse(fields[URI]).netloc
60 if DEBUG:
61 print(f'URI: {fields[URI]}')
62 if len(domain) > 0:
63 fields[URI] = domain
64 token = fields[URI] + fields[USERNAME] + fields[PASSWORD]
65 hashValue = hashlib.md5(token.rstrip().encode('utf-8')).hexdigest()
66 if hashValue not in completed_lines_hash:
67 out_file.write(line)
68 completed_lines_hash.add(hashValue)
69 write_count += 1
70 else:
71 rem_file.write(line)
72 # Uncomment for verbose mode
73 #print(f'Skipping duplicate on line {line_number}:\n{line}')
74 out_file.close()
75 rem_file.close()
76
77 dup_count = line_number - write_count
78 print(f'\nOutput file: {out_file_path}\n{write_count} unique entries saved')
79 print(f'\n{dup_count} duplicates saved to {rem_file_path}')
80
81if __name__ == "__main__":
82 main(sys.argv[1:])