PSKManagement.py
changeset 2340 decf52efb7f7
parent 2339 48b4eba13064
child 2428 e0f16317668e
equal deleted inserted replaced
2339:48b4eba13064 2340:decf52efb7f7
     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