[prev in list] [next in list] [prev in thread] [next in thread]
List: subversion-dev
Subject: Re: A more permanent home for the add-a-password-to-a-cached-username script? (was: Re: using svn cl
From: Daniel Shahaf <d.s () daniel ! shahaf ! name>
Date: 2021-02-26 17:35:25
Message-ID: 20210226173525.GA24828 () tarpaulin ! shahaf ! local2
[Download RAW message or body]
Daniel Sahlberg wrote on Fri, Feb 26, 2021 at 13:49:25 +0100:
> +++ contrib/client-side/store-plaintext-password.py (working copy)
> @@ -0,0 +1,127 @@
> +def readHashFile(filename):
> + """Read a hashfile as written by svn_hash_write2() to a list of tuples (key, \
> value)""" + hash = {}
> + with open(authfileName, 'r', encoding='utf-8') as file:
> + while True:
> + # Expecting K [length] or END
> + line = file.readline()
> + if not line:
> + raise Exception('Parse failed, expected K [length] or END, got \
> EOF') + line = line.strip()
> + if line.strip() == 'END':
> + if file.readline():
> + raise Exception('Parse failed, unexpected data after END')
> + return hash
> + elif line[:1] != 'K':
> + raise Exception('Parse failed, expected K [length]')
> +
> + # Read keyname
> + key = file.readline()
> + if not line:
> + raise Exception('Parse failed, expected keyname')
> + key = key.strip()
> + if len(key.encode('utf-8')) != int(line[2:]):
> + raise Exception('Parse failed, invalid key length {} expected \
> {}'.format(len(key.encode('utf-8')), line[2:])) +
> + # Read V [length]
> + line = file.readline()
> + if not line:
> + raise Exception('Parse failed, expected V [length], got EOF')
> + line = line.strip()
> + if line[:1] != 'V':
> + raise Exception('Parse failed, expected V [length]')
> +
> + # Read value
> + value = file.readline()
> + if not value:
> + raise Exception('Parse failed, expected value')
> + value = value.strip()
> + if len(value.encode('utf-8')) != int(line[2:]):
> + raise Exception('Parse failed, invalid value length {} expected \
> {}'.format(len(value.encode('utf-8')), line[2:])) +
> + # Store
> + hash[key] = value
Couldn't resist. Attached is my take of this function. Preview:
[[[
% ./svn_hash_read.py ~/.subversion/auth/svn.simple/d3c8a345b14f6a1b42251aef8027ab57
{b'svn:realmstring': b'<https://svn.apache.org:443> ASF Committers',
b'username': b'danielsh'}
]]]
The script should support everything the serialized hash format allows,
including binary data in both keys and values (even though we generally
use «const char *» keys). I'm sure there are a few nits to pick, though.
The code is runnable as-is, despite the ellipses.
Cheers,
Daniel
[[[
#!/usr/bin/env python3
TERMINATOR = b"END\n"
def _read_one_datum(fd, letter):
"""\
Read a 'K <length>\\n<key>\\n' or 'V <length>\\n<value>\\n' block from
an svn_hash_write2()-format FD.
LETTER identifies the first letter, as a bytes object.
"""
assert letter in {b'K', b'V'}
# Read the letter and the space
if fd.read(1) != letter or fd.read(1) != b' ':
raise ...
# Read the length and the newline
line = fd.readline()
if line[-1:] != b'\n':
raise ...
expected_length = int(line[:-1])
# Read the datum and its newline
datum = fd.read(expected_length)
if len(datum) != expected_length:
raise ...
if fd.read(1) != b'\n':
raise ...
return datum
def svn_hash_read(fd):
"""\
Read an svn_hash_write2()-formatted dict from FD, terminated by "END".
Return a dict mapping bytes to bytes.
"""
assert 'b' in fd.mode
assert TERMINATOR[0] not in {b'K', b'V'}
ret = {}
while True:
if fd.peek(1)[0] == TERMINATOR[0]:
if fd.readline() != TERMINATOR:
raise ...
if fd.peek(1):
raise ...
return ret
key = _read_one_datum(fd, b'K')
value = _read_one_datum(fd, b'V')
ret[key] = value
def main():
import sys
parsed = svn_hash_read(open(sys.argv[1], 'rb'))
import pprint
pprint.pprint(parsed)
if __name__ == '__main__':
main()
]]]
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic