5 |
5 |
6 from __future__ import absolute_import |
6 from __future__ import absolute_import |
7 import os |
7 import os |
8 import time |
8 import time |
9 import json |
9 import json |
|
10 from zipfile import ZipFile |
10 |
11 |
|
12 # PSK Management Data model : |
|
13 # [[ID,Desc, LastKnownURI, LastConnect]] |
11 COL_ID,COL_URI,COL_DESC,COL_LAST = range(4) |
14 COL_ID,COL_URI,COL_DESC,COL_LAST = range(4) |
12 |
15 |
13 def _pskpath(project_path): |
16 def _pskpath(project_path): |
14 return os.path.join(project_path, 'psk') |
17 return os.path.join(project_path, 'psk') |
15 |
18 |
16 def _mgtpath(project_path): |
19 def _mgtpath(project_path): |
17 return os.path.join(_pskpath(project_path), 'management.json') |
20 return os.path.join(_pskpath(project_path), 'management.json') |
18 |
21 |
19 def _default(): |
22 def _default(ID): |
20 return ['', # default description |
23 return [ID, |
|
24 '', # default description |
21 None, # last known URI |
25 None, # last known URI |
22 None] # last connection date |
26 None] # last connection date |
23 |
27 |
|
28 def _dataByID(data): |
|
29 return {row[COL_ID]:row for row in data} |
|
30 |
24 def _LoadData(project_path): |
31 def _LoadData(project_path): |
|
32 """ load known keys metadata """ |
25 if os.path.isdir(_pskpath(project_path)): |
33 if os.path.isdir(_pskpath(project_path)): |
26 _path = _mgtpath(project_path) |
34 _path = _mgtpath(project_path) |
27 # load known keys metadata |
35 if os.path.exists(_path): |
28 # {ID:(Desc, LastKnownURI, LastConnect)} |
36 return json.loads(open(_path).read()) |
29 return json.loads(open(_path).read()) \ |
37 return [] |
30 if os.path.exists(_path) else {} |
|
31 return {} |
|
32 |
38 |
33 def GetData(project_path): |
39 def _filterData(psk_files, data_input): |
34 # [(ID, Desc, LastKnownURI, LastConnect) |
40 input_by_ID = _dataByID(data_input) |
35 data = [] |
41 output = [] |
36 loaded_data = _LoadData(project_path) |
|
37 # go through all secret files available an build data |
42 # go through all secret files available an build data |
38 # out of data recoverd from json and list of secret. |
43 # out of data recoverd from json and list of secret. |
39 # this implicitly filters IDs out of metadata who's |
44 # this implicitly filters IDs out of metadata who's |
40 # secret is missing |
45 # secret is missing |
41 psk_files = os.listdir(_pskpath(project_path)) |
|
42 for filename in psk_files: |
46 for filename in psk_files: |
43 if filename.endswith('.secret'): |
47 if filename.endswith('.secret'): |
44 ID = filename[:-7] # strip filename extension |
48 ID = filename[:-7] # strip filename extension |
45 meta = loaded_data.get(ID,_default()) |
49 output.append(input_by_ID.get(ID,_default(ID))) |
46 data.append([ID]+meta) |
50 return output |
47 return data |
|
48 |
51 |
|
52 def GetData(project_path): |
|
53 loaded_data = _LoadData(project_path) |
|
54 psk_files = os.listdir(_pskpath(project_path)) |
|
55 return _filterData(psk_files, loaded_data) |
49 |
56 |
50 def DeleteID(project_path, ID): |
57 def DeleteID(project_path, ID): |
51 secret_path = os.path.join(_pskpath(project_path), ID+'.secret') |
58 secret_path = os.path.join(_pskpath(project_path), ID+'.secret') |
52 os.remove(secret_path) |
59 os.remove(secret_path) |
53 |
60 |
54 def _StoreData(project_path, data): |
61 def SaveData(project_path, data): |
55 pskpath = _pskpath(project_path) |
62 pskpath = _pskpath(project_path) |
56 if not os.path.isdir(pskpath): |
63 if not os.path.isdir(pskpath): |
57 os.mkdir(pskpath) |
64 os.mkdir(pskpath) |
58 with open(_mgtpath(project_path), 'w') as f: |
65 with open(_mgtpath(project_path), 'w') as f: |
59 f.write(json.dumps(data)) |
66 f.write(json.dumps(data)) |
60 |
67 |
61 def SaveData(project_path, data): |
|
62 to_store = {row[0]:row[1:] for row in data} |
|
63 _StoreData(project_path, to_store) |
|
64 |
68 |
65 def UpdateID(project_path, ID, secret, URI): |
69 def UpdateID(project_path, ID, secret, URI): |
66 pskpath = _pskpath(project_path) |
70 pskpath = _pskpath(project_path) |
67 if not os.path.exists(pskpath): |
71 if not os.path.exists(pskpath): |
68 os.mkdir(pskpath) |
72 os.mkdir(pskpath) |
69 |
73 |
70 secpath = os.path.join(pskpath, ID+'.secret') |
74 secpath = os.path.join(pskpath, ID+'.secret') |
71 with open(secpath, 'w') as f: |
75 with open(secpath, 'w') as f: |
72 f.write(ID+":"+secret) |
76 f.write(ID+":"+secret) |
73 |
77 |
|
78 # here we directly use _LoadData, avoiding filtering that could be long |
74 data = _LoadData(project_path) |
79 data = _LoadData(project_path) |
75 dataForID = [ID] + (data.get(ID, _default()) if data else _default()) |
80 idata = _dataByID(data) |
|
81 dataForID = idata.get(ID, _default(ID)) if data else _default(ID) |
76 dataForID[COL_URI] = URI |
82 dataForID[COL_URI] = URI |
77 # FIXME : could store time instead os a string and use DVC model's cmp |
83 # FIXME : could store time instead os a string and use DVC model's cmp |
78 # then date display could be smarter, etc - sortable sting hack for now |
84 # then date display could be smarter, etc - sortable sting hack for now |
79 dataForID[COL_LAST] = time.strftime('%y/%M/%d-%H:%M:%S') |
85 dataForID[COL_LAST] = time.strftime('%y/%M/%d-%H:%M:%S') |
80 data[ID] = dataForID[1:] |
86 SaveData(project_path, data) |
81 _StoreData(project_path, data) |
87 |
|
88 def ExportIDs(project_path, export_zip): |
|
89 with ZipFile(export_zip, 'w') as zf: |
|
90 path = _pskpath(project_path) |
|
91 for nm in os.listdir(path): |
|
92 if nm.endswith('.secret') or nm == 'management.json': |
|
93 zf.write(os.path.join(path, nm), nm) |
|
94 |
|
95 def ImportIDs(project_path, import_zip, should_I_replace_callback): |
|
96 data = GetData(project_path) |
|
97 |
|
98 zip_loaded_data = json.loads(zf.open('management.json').read()) |
|
99 name_list = zf.namelist() |
|
100 zip_filtered_data = _filterData(name_list, loaded_data) |
|
101 |
|
102 idata = _dataByID(data) |
|
103 |
|
104 for imported_row in zip_filtered_data: |
|
105 ID = imported_row[COL_ID] |
|
106 existing_row = idata.get(ID, None) |
|
107 if existing_row is None: |
|
108 data.append(imported_row) |
|
109 else: |
|
110 # callback returns the selected list for merge or none if canceled |
|
111 result = should_I_replace_callback(existing_row, imported_row) |
|
112 if result is None: |
|
113 break |
|
114 |
|
115 if result: |
|
116 # replace with imported |
|
117 existing_row[:] = imported_row |
|
118 # copy the key of selected |
|
119 self.extract(ID+".secret", _pskpath(project_path)) |
|
120 |
|
121 SaveData(project_path, data) |
|
122 |
|
123 |