diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2018-04-05 18:24:48 +0200 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2018-04-21 11:23:29 +0200 |
commit | e91e498be862732d89392fa59c85045a92a584b0 (patch) | |
tree | 3db243e9348caf9674924645645274433ffcd867 | |
parent | c652eee8eca4ed5832f5befb67df0dd2332b607f (diff) |
Add --columns option
This option can be used to override the list of columns as found in the
first line of the CSV file or provide a mapping for values found in the
first line to PSKC properties.
-rw-r--r-- | docs/csv2pskc.rst | 19 | ||||
-rw-r--r-- | pskc/scripts/csv2pskc.py | 27 | ||||
-rw-r--r-- | tests/test_csv2pskc.doctest | 86 |
3 files changed, 127 insertions, 5 deletions
diff --git a/docs/csv2pskc.rst b/docs/csv2pskc.rst index 1c82a9f..06aabce 100644 --- a/docs/csv2pskc.rst +++ b/docs/csv2pskc.rst @@ -32,6 +32,25 @@ Options By default :program:`csv2pskc` writes a PSKC file to stdout. This option can be used to save to a file instead. +.. option:: -c COL,COL,.., --columns COL,COL,.. + + Specify the meaning of the columns in the CSV file. By default the first + row of the CSV file is expected to list the names of the columns. + + Any property of :class:`~pskc.key.Key` instances can be used as well as + :class:`~pskc.policy.Policy` properties via ``policy``. For example: + ``serial``, ``secret``, ``counter``, ``time_offset``, ``time_interval``, + ``interval``, ``time_drift``, ``issuer``, ``manufacturer``, + ``response_length``, ``policy.pin_min_length``. + + This option can either specify a list of columns or a COL:KEY mapping + where COL refers to the value found in the first line of the CSV file and + KEY refers to a property as described above. + + It is possible to map a single column in the CSV file to multiple PSKC + properties (e.g. use of ``id+serial`` sets both the ID and device serial + number to the value found in that column). + .. option:: -p PASS/FILE, --password PASS/FILE, --passwd PASS/FILE Encrypt the PSKC file with the specified password. If the argument refers diff --git a/pskc/scripts/csv2pskc.py b/pskc/scripts/csv2pskc.py index 814e756..a815755 100644 --- a/pskc/scripts/csv2pskc.py +++ b/pskc/scripts/csv2pskc.py @@ -53,6 +53,9 @@ parser.add_argument( '-o', '--output', metavar='FILE', help='write PSKC to file instead of stdout') parser.add_argument( + '-c', '--columns', metavar='COL|COL:LABEL,..', + help='list of columns or label to column mapping to import') +parser.add_argument( '-p', '--password', '--passwd', metavar='PASS/FILE', help='password to use for encrypting the PSKC file)') parser.add_argument( @@ -103,14 +106,28 @@ def main(): args = parser.parse_args() # open the CSV file csvfile = open_csvfile(open(args.input, 'r') if args.input else sys.stdin) - columns = next(csvfile) + # figure out the meaning of the columns + columns = [x.lower().replace(' ', '_') for x in next(csvfile)] + if args.columns: + if ':' in args.columns: + # --columns is a list of mappings + mapping = dict( + (label.lower().replace(' ', '_'), key.lower()) + for label, key in ( + column.split(':') + for column in args.columns.split(','))) + columns = [mapping.get(column, column) for column in columns] + else: + # --columns is a list of columns + columns = [x.lower() for x in args.columns.split(',')] # store rows in PSKC structure pskcfile = pskc.PSKC() for row in csvfile: - data = dict( - (key, from_column(key, value, args)) - for key, value in zip(columns, row) - if value and key not in ('', '-')) + data = {} + for column, value in zip(columns, row): + for key in column.split('+'): + if value and key not in ('', '-'): + data[key] = from_column(key, value, args) pskcfile.add_key(**data) # encrypt the file if needed if args.secret: diff --git a/tests/test_csv2pskc.doctest b/tests/test_csv2pskc.doctest index afa82e2..0c6e8d5 100644 --- a/tests/test_csv2pskc.doctest +++ b/tests/test_csv2pskc.doctest @@ -306,6 +306,92 @@ automatically pick up tab-separated files. </pskc:KeyContainer> +We can use the --columns option to override using the first row to specify +the key properties. + +>>> f = tempfile.NamedTemporaryFile('w+t') +>>> x = f.write(''' +... nr,key,start date,info +... 121232,6848464354638468468835346896846846846846,2017-04-01,something +... 213422,9843138168168196616849849634548496832446,2017-02-12,else +... '''.lstrip()) +>>> f.flush() +>>> sys.argv = ['csv2pskc', f.name, '--columns', 'id+serial,secret,start_date,-'] +>>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE +<?xml version="1.0" encoding="UTF-8"?> +<pskc:KeyContainer xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" Version="1.0"> + <pskc:KeyPackage> + <pskc:DeviceInfo> + <pskc:SerialNo>121232</pskc:SerialNo> + <pskc:StartDate>2017-04-01T00:00:00</pskc:StartDate> + </pskc:DeviceInfo> + <pskc:Key Id="121232"> + <pskc:Data> + <pskc:Secret> + <pskc:PlainValue>aEhGQ1RjhGhGiDU0aJaEaEaEaEY=</pskc:PlainValue> + </pskc:Secret> + </pskc:Data> + </pskc:Key> + </pskc:KeyPackage> + <pskc:KeyPackage> + <pskc:DeviceInfo> + <pskc:SerialNo>213422</pskc:SerialNo> + <pskc:StartDate>2017-02-12T00:00:00</pskc:StartDate> + </pskc:DeviceInfo> + <pskc:Key Id="213422"> + <pskc:Data> + <pskc:Secret> + <pskc:PlainValue>mEMTgWgWgZZhaEmEljRUhJaDJEY=</pskc:PlainValue> + </pskc:Secret> + </pskc:Data> + </pskc:Key> + </pskc:KeyPackage> +</pskc:KeyContainer> + + +Alternatively, we can provide a mapping for column names found in the CSV +file to key properties. + +>>> f = tempfile.NamedTemporaryFile('w+t') +>>> x = f.write(''' +... nr,key,start date,info +... 121232,6848464354638468468835346896846846846846,2017-04-01,something +... 213422,9843138168168196616849849634548496832446,2017-02-12,else +... '''.lstrip()) +>>> f.flush() +>>> sys.argv = ['csv2pskc', f.name, '--columns', 'key:secret,nr:id+serial,info:-'] +>>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE +<?xml version="1.0" encoding="UTF-8"?> +<pskc:KeyContainer xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" Version="1.0"> + <pskc:KeyPackage> + <pskc:DeviceInfo> + <pskc:SerialNo>121232</pskc:SerialNo> + <pskc:StartDate>2017-04-01T00:00:00</pskc:StartDate> + </pskc:DeviceInfo> + <pskc:Key Id="121232"> + <pskc:Data> + <pskc:Secret> + <pskc:PlainValue>aEhGQ1RjhGhGiDU0aJaEaEaEaEY=</pskc:PlainValue> + </pskc:Secret> + </pskc:Data> + </pskc:Key> + </pskc:KeyPackage> + <pskc:KeyPackage> + <pskc:DeviceInfo> + <pskc:SerialNo>213422</pskc:SerialNo> + <pskc:StartDate>2017-02-12T00:00:00</pskc:StartDate> + </pskc:DeviceInfo> + <pskc:Key Id="213422"> + <pskc:Data> + <pskc:Secret> + <pskc:PlainValue>mEMTgWgWgZZhaEmEljRUhJaDJEY=</pskc:PlainValue> + </pskc:Secret> + </pskc:Data> + </pskc:Key> + </pskc:KeyPackage> +</pskc:KeyContainer> + + We can encrypt the resulting PSKC file with a passphrase. >>> f = tempfile.NamedTemporaryFile('w+t') |