mirror of
https://github.com/scito/extract_otp_secret_keys.git
synced 2025-12-06 23:05:06 +01:00
handle not encoded + in query params, fixes #15
- add debug level, by givein parameter -vv - if the base64 string is not urlencoded, then + will be replaced by a space, what cannot be decoded anymore --> replace spaces back to plus - add test
This commit is contained in:
parent
df8b99dce4
commit
cd2d3258d3
4 changed files with 74 additions and 5 deletions
|
|
@ -60,7 +60,7 @@ def sys_main():
|
|||
def main(sys_args):
|
||||
global verbose, quiet
|
||||
args = parse_args(sys_args)
|
||||
verbose = args.verbose
|
||||
verbose = args.verbose if args.verbose else 0
|
||||
quiet = args.quiet
|
||||
|
||||
otps = extract_otps(args)
|
||||
|
|
@ -70,7 +70,7 @@ def main(sys_args):
|
|||
|
||||
def parse_args(sys_args):
|
||||
arg_parser = argparse.ArgumentParser()
|
||||
arg_parser.add_argument('--verbose', '-v', help='verbose output', action='store_true')
|
||||
arg_parser.add_argument('--verbose', '-v', help='verbose output', action='count')
|
||||
arg_parser.add_argument('--quiet', '-q', help='no stdout output', action='store_true')
|
||||
arg_parser.add_argument('--saveqr', '-s', help='save QR code(s) as images to the "qr" subfolder', action='store_true')
|
||||
arg_parser.add_argument('--printqr', '-p', help='print QR code(s) as text to the terminal', action='store_true')
|
||||
|
|
@ -125,15 +125,21 @@ def extract_otps(args):
|
|||
|
||||
|
||||
def get_payload_from_line(line, i, args):
|
||||
global verbose
|
||||
if not line.startswith('otpauth-migration://'):
|
||||
print('\nWARN: line is not a otpauth-migration:// URL\ninput file: {}\nline "{}"\nProbably a wrong file was given'.format(args.infile, line))
|
||||
parsed_url = urlparse(line)
|
||||
params = parse_qs(parsed_url.query)
|
||||
if verbose > 1: print('\nDEBUG: parsed_url={}'.format(parsed_url))
|
||||
params = parse_qs(parsed_url.query, strict_parsing=True)
|
||||
if verbose > 1: print('\nDEBUG: querystring params={}'.format(params))
|
||||
if 'data' not in params:
|
||||
print('\nERROR: no data query parameter in input URL\ninput file: {}\nline "{}"\nProbably a wrong file was given'.format(args.infile, line))
|
||||
sys.exit(1)
|
||||
data_encoded = params['data'][0]
|
||||
data = base64.b64decode(data_encoded, validate=True)
|
||||
data_base64 = params['data'][0]
|
||||
if verbose > 1: print('\nDEBUG: data_base64={}'.format(data_base64))
|
||||
data_base64_fixed = data_base64.replace(' ', '+')
|
||||
if verbose > 1: print('\nDEBUG: data_base64_fixed={}'.format(data_base64))
|
||||
data = base64.b64decode(data_base64_fixed, validate=True)
|
||||
payload = protobuf_generated_python.google_auth_pb2.MigrationPayload()
|
||||
payload.ParseFromString(data)
|
||||
if verbose:
|
||||
|
|
|
|||
1
test/test_plus_problem_export.txt
Normal file
1
test/test_plus_problem_export.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
otpauth-migration://offline?data=ClEKFAciUeGF4aS6IDCvMv99ySZ1ekKsEiVTZXJlbml0eUxhYnM6dGVzdDFAc2VyZW5pdHlsYWJzLmNvLnVrGgxTZXJlbml0eUxhYnMgASgBMAIKUQoUkIY8/fbrHZWTb4CBln18lvqt0HcSJVNlcmVuaXR5TGFiczp0ZXN0MkBzZXJlbml0eWxhYnMuY28udWsaDFNlcmVuaXR5TGFicyABKAEwAgpRChScf+1/Ua4d4gCY0W/7fj9VBkM9PBIlU2VyZW5pdHlMYWJzOnRlc3QzQHNlcmVuaXR5bGFicy5jby51axoMU2VyZW5pdHlMYWJzIAEoATACClEKFG6Qu0ryTSFA/l5rmvTIXtNeb5LtEiVTZXJlbml0eUxhYnM6dGVzdDRAc2VyZW5pdHlsYWJzLmNvLnVrGgxTZXJlbml0eUxhYnMgASgBMAIQARgBIAAogtTa1vz/////AQ==
|
||||
|
|
@ -88,6 +88,39 @@ Type: OTP_TOTP
|
|||
assert captured.err == ''
|
||||
|
||||
|
||||
def test_extract_not_encoded_plus(capsys):
|
||||
# Act
|
||||
extract_otp_secret_keys.main(['test/test_plus_problem_export.txt'])
|
||||
|
||||
# Assert
|
||||
captured = capsys.readouterr()
|
||||
|
||||
expected_stdout = '''Name: SerenityLabs:test1@serenitylabs.co.uk
|
||||
Secret: A4RFDYMF4GSLUIBQV4ZP67OJEZ2XUQVM
|
||||
Issuer: SerenityLabs
|
||||
Type: OTP_TOTP
|
||||
|
||||
Name: SerenityLabs:test2@serenitylabs.co.uk
|
||||
Secret: SCDDZ7PW5MOZLE3PQCAZM7L4S35K3UDX
|
||||
Issuer: SerenityLabs
|
||||
Type: OTP_TOTP
|
||||
|
||||
Name: SerenityLabs:test3@serenitylabs.co.uk
|
||||
Secret: TR76272RVYO6EAEY2FX7W7R7KUDEGPJ4
|
||||
Issuer: SerenityLabs
|
||||
Type: OTP_TOTP
|
||||
|
||||
Name: SerenityLabs:test4@serenitylabs.co.uk
|
||||
Secret: N2ILWSXSJUQUB7S6NONPJSC62NPG7EXN
|
||||
Issuer: SerenityLabs
|
||||
Type: OTP_TOTP
|
||||
|
||||
'''
|
||||
|
||||
assert captured.out == expected_stdout
|
||||
assert captured.err == ''
|
||||
|
||||
|
||||
def test_extract_printqr(capsys):
|
||||
# Act
|
||||
extract_otp_secret_keys.main(['-p', 'example_export.txt'])
|
||||
|
|
|
|||
|
|
@ -95,6 +95,35 @@ Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
|||
Issuer: raspberrypi
|
||||
Type: OTP_TOTP
|
||||
|
||||
'''
|
||||
self.assertEqual(actual_output, expected_output)
|
||||
|
||||
def test_extract_not_encoded_plus(self):
|
||||
out = io.StringIO()
|
||||
with redirect_stdout(out):
|
||||
extract_otp_secret_keys.main(['test/test_plus_problem_export.txt'])
|
||||
actual_output = out.getvalue()
|
||||
|
||||
expected_output = '''Name: SerenityLabs:test1@serenitylabs.co.uk
|
||||
Secret: A4RFDYMF4GSLUIBQV4ZP67OJEZ2XUQVM
|
||||
Issuer: SerenityLabs
|
||||
Type: OTP_TOTP
|
||||
|
||||
Name: SerenityLabs:test2@serenitylabs.co.uk
|
||||
Secret: SCDDZ7PW5MOZLE3PQCAZM7L4S35K3UDX
|
||||
Issuer: SerenityLabs
|
||||
Type: OTP_TOTP
|
||||
|
||||
Name: SerenityLabs:test3@serenitylabs.co.uk
|
||||
Secret: TR76272RVYO6EAEY2FX7W7R7KUDEGPJ4
|
||||
Issuer: SerenityLabs
|
||||
Type: OTP_TOTP
|
||||
|
||||
Name: SerenityLabs:test4@serenitylabs.co.uk
|
||||
Secret: N2ILWSXSJUQUB7S6NONPJSC62NPG7EXN
|
||||
Issuer: SerenityLabs
|
||||
Type: OTP_TOTP
|
||||
|
||||
'''
|
||||
self.assertEqual(actual_output, expected_output)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue