The SSH host key has changed on 8 April, 2022 to this one: SHA256:573uTBSeh74kvOo0HJXi5ijdzRm8me27suzNEDlGyrQ
Python implementation of [Earthstar](https://earthstar-project.org/)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
earthsnake/earthsnake/path.py

77 lines
2.1 KiB

"""Path handling"""
from .exc import ValidationError
from .identity import Identity
from .types import ALPHA_LOWER, ALPHA_UPPER, DIGIT
PATH_PUNCTUATION = "/'()-._~!$&+,:=@%"
PATH_CHARACTER = ALPHA_LOWER + ALPHA_UPPER + DIGIT + PATH_PUNCTUATION
class Path:
"""A document path"""
_SEGMENT_PATTERN = f'/[{PATH_CHARACTER}]+'
_PATTERN = f'^({_SEGMENT_PATTERN})+$'
def __init__(self, path: str) -> None:
self.validate(path, allow_ephemeral=True)
self.path = path
@staticmethod
def validate(path: str, allow_ephemeral: bool = False) -> None:
"""Validate a path"""
if not 2 <= len(path) <= 512:
raise ValidationError('Path length must be between 2 and 512')
if not path.startswith('/'):
raise ValidationError('Paths must start with a /')
if path.endswith('/'):
raise ValidationError('Paths must not end with a /')
if path.startswith('/@'):
raise ValidationError('Paths must not start with /@')
if '//' in path:
raise ValidationError('Paths must not contain //')
if path.count('!') > 1:
raise ValidationError('Only one ! is allowed in paths')
if '!' in path and not allow_ephemeral:
raise ValidationError('Only ephemeral paths may contain !')
@property
def is_shared(self) -> bool:
"""Check if the path is shared"""
return '~' not in self.path
@property
def is_ephemeral(self) -> bool:
"""Check if the path is ephemeral"""
return '!' in self.path
def can_write(self, author: Identity) -> bool:
"""Check if a specific author has write access over a document"""
if self.is_shared:
return True
segments = self.path.split('/')
for segment in segments:
for allowed_author in segment.split('~'):
if Identity.valid_address(allowed_author) and str(author) == allowed_author:
return True
return False
def __str__(self) -> str:
return self.path
def __repr__(self) -> str:
return f'<Path {self.path}>'