Initial implementation
It should work, nobody tested it, there are TODO's which will likely never be implemented :-)master
commit
134cae1db3
@ -0,0 +1,63 @@
|
|||||||
|
from typing import IO
|
||||||
|
|
||||||
|
# Copied from sshd(8)
|
||||||
|
key_types = [
|
||||||
|
"sk-ecdsa-sha2-nistp256@openssh.com",
|
||||||
|
"ecdsa-sha2-nistp256",
|
||||||
|
"ecdsa-sha2-nistp384",
|
||||||
|
"ecdsa-sha2-nistp521",
|
||||||
|
"sk-ssh-ed25519@openssh.com",
|
||||||
|
"ssh-ed25519",
|
||||||
|
"ssh-dss",
|
||||||
|
"ssh-rsa",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorizedKey:
|
||||||
|
def __init__(self, line):
|
||||||
|
self.original = line
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith('#') or line == '':
|
||||||
|
raise ValueError('This is not a key, it is a comment or an empty line.')
|
||||||
|
if line.split(' ')[0] not in key_types:
|
||||||
|
# The hard case: there are options at the beginning.
|
||||||
|
# It is too simple to code the state machine myself, so no library :-)
|
||||||
|
in_quotes = False
|
||||||
|
backslash_preceding = False
|
||||||
|
for idx, char in enumerate(line):
|
||||||
|
if char == '\"' and not backslash_preceeding:
|
||||||
|
in_quotes = not in_quotes
|
||||||
|
elif char == ' ' and not in_quotes:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
backslash_preceeding = char == '\\'
|
||||||
|
else:
|
||||||
|
raise ValueError('Badly formatted options not followed by a key.')
|
||||||
|
|
||||||
|
if line[idx] != ' ':
|
||||||
|
raise ValueError('I am just broken.')
|
||||||
|
self.options = line[:idx]
|
||||||
|
line = line[idx+1:]
|
||||||
|
line = line.strip() # In case there are multiple spaces
|
||||||
|
else:
|
||||||
|
self.options = None
|
||||||
|
|
||||||
|
# Now only the key follows, so this is simple
|
||||||
|
self.options = None
|
||||||
|
split = line.split(' ', maxsplit=2)
|
||||||
|
self.type = split[0]
|
||||||
|
self.key_b64 = split[1]
|
||||||
|
self.coment = split[2] if len(split) >= 3 else None
|
||||||
|
|
||||||
|
def parse_file(f: IO[str]) -> list[AuthorizedKey | str]:
|
||||||
|
result = []
|
||||||
|
for line in f:
|
||||||
|
stripped = line.strip()
|
||||||
|
if stripped.startswith('#') or stripped == '':
|
||||||
|
# This is a comment / empty line, should be preserved
|
||||||
|
result.append(line)
|
||||||
|
else:
|
||||||
|
result.append(AuthorizedKey(line))
|
||||||
|
return result
|
||||||
|
|
||||||
|
# TODO: Implement option parsing, key validation and decoding to bytes.
|
Loading…
Reference in New Issue