Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃毟 Filename validator for new projects #298

Merged
merged 6 commits into from
Feb 18, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 51 additions & 5 deletions pros/conductor/conductor.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import errno
import os.path
import shutil
from enum import Enum
from pathlib import Path
import sys
from typing import *
import re

import click
from semantic_version import Spec, Version
Expand All @@ -27,6 +30,50 @@ class ReleaseChannel(Enum):
Beta = 'beta'
"""

def is_pathname_valid(pathname: str) -> bool:
'''
A more detailed check for path validity than regex.
https://stackoverflow.com/a/34102855/11177720
'''
try:
if not isinstance(pathname, str) or not pathname:
return False

_, pathname = os.path.splitdrive(pathname)

root_dirname = os.environ.get('HOMEDRIVE', 'C:') \
if sys.platform == 'win32' else os.path.sep
assert os.path.isdir(root_dirname)

root_dirname = root_dirname.rstrip(os.path.sep) + os.path.sep
for pathname_part in pathname.split(os.path.sep):
try:
os.lstat(root_dirname + pathname_part)
except OSError as exc:
if hasattr(exc, 'winerror'):
if exc.winerror == 123: # ERROR_INVALID_NAME, python doesn't have this constant
return False
elif exc.errno in {errno.ENAMETOOLONG, errno.ERANGE}:
return False

# Check for emojis
# https://stackoverflow.com/a/62898106/11177720
ranges = [
(ord(u'\U0001F300'), ord(u"\U0001FAF6")), # 127744, 129782
(126980, 127569),
(169, 174),
(8205, 12953)
]
for a_char in pathname:
char_code = ord(a_char)
for range_min, range_max in ranges:
if range_min <= char_code <= range_max:
return False
except TypeError as exc:
return False
else:
return True

class Conductor(Config):
"""
Provides entrances for all conductor-related tasks (fetching, applying, creating new projects)
Expand Down Expand Up @@ -312,13 +359,12 @@ def new_project(self, path: str, no_default_libs: bool = False, **kwargs) -> Pro
elif self.use_early_access:
ui.echo(f'Early access is enabled.')

if not is_pathname_valid(str(Path(path).absolute())):
raise dont_send(ValueError('Project path contains invalid characters.'))

if Path(path).exists() and Path(path).samefile(os.path.expanduser('~')):
raise dont_send(ValueError('Will not create a project in user home directory'))
for char in str(Path(path)):
if char in ['?', '<', '>', '*', '|', '^', '#', '%', '&', '$', '+', '!', '`', '\'', '=',
'@', '\'', '{', '}', '[', ']', '(', ')', '~'] or ord(char) > 127:
raise dont_send(ValueError(f'Invalid character found in directory name: \'{char}\''))


proj = Project(path=path, create=True)
if 'target' in kwargs:
proj.target = kwargs['target']
Expand Down
Loading