test_csv2pskc.doctest - tests for the csv2pskc script Copyright (C) 2018 Arthur de Jong This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA >>> from binascii import a2b_hex >>> import getpass >>> import shlex >>> import sys >>> import tempfile >>> from pskc import PSKC >>> from pskc.scripts.csv2pskc import main Sadly we cannot test --help and --version properly because argparse calls exit(0) which doctest does not like. >>> sys.argv = shlex.split('csv2pskc --help') >>> main() # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... SystemExit: 0 >>> sys.argv = shlex.split('csv2pskc --version') >>> main() # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... SystemExit: 0 We can output a PSKC file with some simple data from a CSV file. The columns in the CSV file refer to names of PSKC properties. >>> f = tempfile.NamedTemporaryFile('w+t') >>> x = f.write(''' ... serial,secret,algorithm,response_length,time_interval ... 987654321,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8, ... 987654321,31323334,urn:ietf:params:xml:ns:keyprov:pskc:pin,4, ... '''.lstrip()) >>> f.flush() >>> sys.argv = ['csv2pskc', f.name] >>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE 987654321 MTIzNDU2Nzg5MDEyMzQ1Njc4OTA= 987654321 MTIzNA== We can also save the output to a file. >>> f = tempfile.NamedTemporaryFile('w+t') >>> x = f.write(''' ... serial,secret,algorithm,response_length,time_interval ... 987654321,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8, ... 987654321,31323334,urn:ietf:params:xml:ns:keyprov:pskc:pin,4, ... '''.lstrip()) >>> f2 = tempfile.NamedTemporaryFile() >>> f.flush() >>> sys.argv = ['csv2pskc', f.name, '--output', f2.name] >>> main() >>> with open(f2.name, 'r') as r: ... x = sys.stdout.write(r.read()) #doctest: +ELLIPSIS +REPORT_UDIFF +NORMALIZE_WHITESPACE ... MTIzNDU2Nzg5MDEyMzQ1Njc4OTA= ... MTIzNA== A bigger example. >>> f = tempfile.NamedTemporaryFile('w+t') >>> x = f.write(''' ... serial,secret,algorithm,response_length,response_encoding,manufacturer,issuer,policy.start_date,policy.expiry_date,id,counter ... 654321,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8,DECIMAL,TokenVendorAcme,Issuer,2006-05-01 00:00:00+00:00,2006-05-31 00:00:00+00:00,1,2 ... 123456,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8,DECIMAL,TokenVendorAcme,Issuer,2006-05-01 00:00:00+00:00,2006-05-31 00:00:00+00:00,2,3 ... 9999999,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8,DECIMAL,TokenVendorAcme,Issuer,2006-03-01 00:00:00+00:00,2006-03-31 00:00:00+00:00,3,42 ... 9999999,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8,DECIMAL,TokenVendorAcme,Issuer,2006-04-01 00:00:00+00:00,2006-04-30 00:00:00+00:00,4,12 ... '''.lstrip()) >>> f.flush() >>> sys.argv = ['csv2pskc', f.name] >>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE TokenVendorAcme 654321 Issuer MTIzNDU2Nzg5MDEyMzQ1Njc4OTA= 2 2006-05-01T00:00:00Z 2006-05-31T00:00:00Z TokenVendorAcme 123456 Issuer MTIzNDU2Nzg5MDEyMzQ1Njc4OTA= 3 2006-05-01T00:00:00Z 2006-05-31T00:00:00Z TokenVendorAcme 9999999 Issuer MTIzNDU2Nzg5MDEyMzQ1Njc4OTA= 42 2006-03-01T00:00:00Z 2006-03-31T00:00:00Z TokenVendorAcme 9999999 Issuer MTIzNDU2Nzg5MDEyMzQ1Njc4OTA= 12 2006-04-01T00:00:00Z 2006-04-30T00:00:00Z As long as it is in a file (does not work on stdin) the script should also automatically pick up tab-separated files. >>> f = tempfile.NamedTemporaryFile('w+t') >>> x = f.write(''' ... id\tsecret\tcounter ... 654321\t3132333435363738393031323334353637383930\t2 ... 123456\t3132333435363738393031323334353637383930\t3 ... 9999999\t3132333435363738393031323334353637383930\t42 ... 9999999\t3132333435363738393031323334353637383930\t12 ... '''.lstrip()) >>> f.flush() >>> sys.argv = ['csv2pskc', f.name] >>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE MTIzNDU2Nzg5MDEyMzQ1Njc4OTA= 2 MTIzNDU2Nzg5MDEyMzQ1Njc4OTA= 3 MTIzNDU2Nzg5MDEyMzQ1Njc4OTA= 42 MTIzNDU2Nzg5MDEyMzQ1Njc4OTA= 12 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 121232 2017-04-01T00:00:00 aEhGQ1RjhGhGiDU0aJaEaEaEaEY= 213422 2017-02-12T00:00:00 mEMTgWgWgZZhaEmEljRUhJaDJEY= 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 121232 2017-04-01T00:00:00 aEhGQ1RjhGhGiDU0aJaEaEaEaEY= 213422 2017-02-12T00:00:00 mEMTgWgWgZZhaEmEljRUhJaDJEY= We can also set global key properties with the --set option to apply values to all keys in the PSKC file: >>> f = tempfile.NamedTemporaryFile('w+t') >>> x = f.write(''' ... id+serial,secret ... 987654321,7c613e9c2194ff7da7f4770ab2ed712111fcbe95 ... 987654322,4be618e3459e936137994854bc3d2ebe46f3cce2 ... '''.lstrip()) >>> f.flush() >>> sys.argv = [ ... 'csv2pskc', f.name, ... '--set', 'manufacturer=TokenVendor', '--set', 'issuer=TokenIssuer'] >>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE TokenVendor 987654321 TokenIssuer fGE+nCGU/32n9HcKsu1xIRH8vpU= TokenVendor 987654322 TokenIssuer S+YY40Wek2E3mUhUvD0uvkbzzOI= The --skip-rows option can be used to either not use the first row to denote the key properties that are set (in which case the --columns option is mandatory) or skip more rows at the beginning of the file. >>> f = tempfile.NamedTemporaryFile('w+t') >>> x = f.write(''' ... 987654321,7c613e9c2194ff7da7f4770ab2ed712111fcbe95 ... 987654322,4be618e3459e936137994854bc3d2ebe46f3cce2 ... '''.lstrip()) >>> f.flush() >>> sys.argv = ['csv2pskc', f.name, '--skip-rows=0', '--columns=id+serial,secret'] >>> main() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF ... ... fGE+nCGU/32n9HcKsu1xIRH8vpU= ... ... S+YY40Wek2E3mUhUvD0uvkbzzOI= ... >>> f = tempfile.NamedTemporaryFile('w+t') >>> x = f.write(''' ... id+serial,secret ... IGNORED LINE ... 987654321,7c613e9c2194ff7da7f4770ab2ed712111fcbe95 ... 987654322,4be618e3459e936137994854bc3d2ebe46f3cce2 ... '''.lstrip()) >>> f.flush() >>> sys.argv = ['csv2pskc', f.name, '--skip-rows=2'] >>> main() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF ... ... fGE+nCGU/32n9HcKsu1xIRH8vpU= ... ... S+YY40Wek2E3mUhUvD0uvkbzzOI= ... We can encrypt the resulting PSKC file with a passphrase. >>> f = tempfile.NamedTemporaryFile('w+t') >>> x = f.write(''' ... id,secret ... 987654321,7c613e9c2194ff7da7f4770ab2ed712111fcbe95 ... 987654322,4be618e3459e936137994854bc3d2ebe46f3cce2 ... '''.lstrip()) >>> f.flush() >>> sys.argv = ['csv2pskc', f.name, '--passwd', 'supersecure'] >>> main() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF ... ... 16 ... ... ... ... ... ... ... ... ... Alternatively we can switch from passphrase-based encryption to key-based encryption. >>> f = tempfile.NamedTemporaryFile('w+t') >>> x = f.write(''' ... id,secret ... 987654321,7c613e9c2194ff7da7f4770ab2ed712111fcbe95 ... 987654322,4be618e3459e936137994854bc3d2ebe46f3cce2 ... '''.lstrip()) >>> f.flush() >>> sys.argv = ['csv2pskc', f.name, '--secret', '12345678901234567890123456789012'] >>> main() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF ... ... ... ... ... ... ... ... ...