[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