Added ENFORCE_BASEPATH option, fixes #68
This commit is contained in:
parent
ca4b91a094
commit
35ac89dcb1
5 changed files with 36 additions and 9 deletions
|
@ -43,6 +43,8 @@ The IP address the service is listening on. By default it is binding to `0.0.0.0
|
|||
The port the service is listening on. By default it is using 3218, but you can change this if you need to.
|
||||
#### BASEPATH (string)
|
||||
It is possible to place configurator.py somewhere else. Set the `BASEPATH` to something like `"/home/homeassistant/.homeassistant"`, and no matter where you are running the configurator from, it will start serving files from there. This is needed if you plan on running the configurator with systemd.
|
||||
#### ENFORCE_BASEPATH (bool)
|
||||
Set ENFORCE_BASEPATH to `True` to lock the configurator into the basepath and thereby prevent it from opening files outside of the BASEPATH
|
||||
#### SSL_CERTIFICATE / SSL_KEY (string)
|
||||
If you're using SSL, set the paths to your SSL files here. This is similar to the SSL setup you can do in HASS.
|
||||
#### HASS_API (string)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
Version 0.2.9 (2018-06-)
|
||||
- Material Icons and HASS-help now open in new tab instead of modal (Issues #85 and #34) @danielperna84
|
||||
- Open file by URL (Issue #95) @danielperna84
|
||||
- Added ENFORCE_BASEPATH option (Issue #68) @danielperna84
|
||||
|
||||
Version 0.2.8 (2018-04-23)
|
||||
- Updated CDN libraries @jmart518
|
||||
|
|
|
@ -30,6 +30,9 @@ LISTENPORT = 3218
|
|||
# Set BASEPATH to something like "/home/hass/.homeassistant/" if you're not
|
||||
# running the configurator from that path
|
||||
BASEPATH = None
|
||||
# Set ENFORCE_BASEPATH to True to lock the configurator into the basepath and
|
||||
# thereby prevent it from opening files outside of the BASEPATH
|
||||
ENFORCE_BASEPATH = False
|
||||
# Set the paths to a certificate and the key if you're using SSL,
|
||||
# e.g "/etc/ssl/certs/mycert.pem"
|
||||
SSL_CERTIFICATE = None
|
||||
|
@ -201,7 +204,7 @@ INDEX = Template(r"""<!DOCTYPE html>
|
|||
color: #616161 !important;
|
||||
font-weight: 400;
|
||||
display: inline-block;
|
||||
width: 185px;
|
||||
width: 182px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
|
@ -2387,7 +2390,10 @@ INDEX = Template(r"""<!DOCTYPE html>
|
|||
|
||||
function listdir(path) {
|
||||
$.get(encodeURI("api/listdir?path=" + path), function(data) {
|
||||
renderpath(data);
|
||||
if (!data.error) {
|
||||
renderpath(data);
|
||||
}
|
||||
console.log("Permission denied.");
|
||||
});
|
||||
document.getElementById("slide-out").scrollTop = 0;
|
||||
}
|
||||
|
@ -3314,7 +3320,7 @@ def signal_handler(sig, frame):
|
|||
def load_settings(settingsfile):
|
||||
global LISTENIP, LISTENPORT, BASEPATH, SSL_CERTIFICATE, SSL_KEY, HASS_API, \
|
||||
HASS_API_PASSWORD, CREDENTIALS, ALLOWED_NETWORKS, BANNED_IPS, BANLIMIT, \
|
||||
DEV, IGNORE_PATTERN, DIRSFIRST, SESAME, VERIFY_HOSTNAME
|
||||
DEV, IGNORE_PATTERN, DIRSFIRST, SESAME, VERIFY_HOSTNAME, ENFORCE_BASEPATH
|
||||
try:
|
||||
if os.path.isfile(settingsfile):
|
||||
with open(settingsfile) as fptr:
|
||||
|
@ -3322,6 +3328,7 @@ def load_settings(settingsfile):
|
|||
LISTENIP = settings.get("LISTENIP", LISTENIP)
|
||||
LISTENPORT = settings.get("LISTENPORT", LISTENPORT)
|
||||
BASEPATH = settings.get("BASEPATH", BASEPATH)
|
||||
ENFORCE_BASEPATH = settings.get("ENFORCE_BASEPATH", ENFORCE_BASEPATH)
|
||||
SSL_CERTIFICATE = settings.get("SSL_CERTIFICATE", SSL_CERTIFICATE)
|
||||
SSL_KEY = settings.get("SSL_KEY", SSL_KEY)
|
||||
HASS_API = settings.get("HASS_API", HASS_API)
|
||||
|
@ -3340,6 +3347,12 @@ def load_settings(settingsfile):
|
|||
LOG.warning("Not loading static settings")
|
||||
return False
|
||||
|
||||
def is_safe_path(basedir, path, follow_symlinks=True):
|
||||
if follow_symlinks:
|
||||
return os.path.realpath(path).startswith(basedir)
|
||||
|
||||
return os.path.abspath(path).startswith(basedir)
|
||||
|
||||
def get_dircontent(path, repo=None):
|
||||
dircontent = []
|
||||
if repo:
|
||||
|
@ -3476,6 +3489,8 @@ class RequestHandler(BaseHTTPRequestHandler):
|
|||
try:
|
||||
if filename:
|
||||
filename = unquote(filename[0]).encode('utf-8')
|
||||
if ENFORCE_BASEPATH and not is_safe_path(BASEPATH.encode('utf-8'), filename):
|
||||
raise OSError('Access denied.')
|
||||
if os.path.isfile(os.path.join(BASEDIR.encode('utf-8'), filename)):
|
||||
with open(os.path.join(BASEDIR.encode('utf-8'), filename)) as fptr:
|
||||
content += fptr.read()
|
||||
|
@ -3492,6 +3507,8 @@ class RequestHandler(BaseHTTPRequestHandler):
|
|||
try:
|
||||
if filename:
|
||||
filename = unquote(filename[0]).encode('utf-8')
|
||||
if ENFORCE_BASEPATH and not is_safe_path(BASEPATH.encode('utf-8'), filename):
|
||||
raise OSError('Access denied.')
|
||||
LOG.info(filename)
|
||||
if os.path.isfile(os.path.join(BASEDIR.encode('utf-8'), filename)):
|
||||
with open(os.path.join(BASEDIR.encode('utf-8'), filename), 'rb') as fptr:
|
||||
|
@ -3509,7 +3526,7 @@ class RequestHandler(BaseHTTPRequestHandler):
|
|||
self.wfile.write(bytes(content, "utf8"))
|
||||
return
|
||||
elif req.path.endswith('/api/listdir'):
|
||||
content = ""
|
||||
content = {'error': None}
|
||||
self.send_header('Content-type', 'text/json')
|
||||
self.end_headers()
|
||||
dirpath = query.get('path', None)
|
||||
|
@ -3517,6 +3534,8 @@ class RequestHandler(BaseHTTPRequestHandler):
|
|||
if dirpath:
|
||||
dirpath = unquote(dirpath[0]).encode('utf-8')
|
||||
if os.path.isdir(dirpath):
|
||||
if ENFORCE_BASEPATH and not is_safe_path(BASEPATH.encode('utf-8'), dirpath):
|
||||
raise OSError('Access denied.')
|
||||
repo = None
|
||||
activebranch = None
|
||||
dirty = False
|
||||
|
@ -3536,13 +3555,14 @@ class RequestHandler(BaseHTTPRequestHandler):
|
|||
'parent': os.path.dirname(os.path.abspath(dirpath)).decode('utf-8'),
|
||||
'branches': branches,
|
||||
'activebranch': activebranch,
|
||||
'dirty': dirty
|
||||
'dirty': dirty,
|
||||
'error': None
|
||||
}
|
||||
self.wfile.write(bytes(json.dumps(filedata), "utf8"))
|
||||
except Exception as err:
|
||||
LOG.warning(err)
|
||||
content = str(err)
|
||||
self.wfile.write(bytes(content, "utf8"))
|
||||
content['error'] = str(err)
|
||||
self.wfile.write(bytes(json.dumps(content), "utf8"))
|
||||
return
|
||||
elif req.path.endswith('/api/abspath'):
|
||||
content = ""
|
||||
|
|
7
dev.html
7
dev.html
|
@ -114,7 +114,7 @@
|
|||
color: #616161 !important;
|
||||
font-weight: 400;
|
||||
display: inline-block;
|
||||
width: 185px;
|
||||
width: 182px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
|
@ -2300,7 +2300,10 @@
|
|||
|
||||
function listdir(path) {
|
||||
$.get(encodeURI("api/listdir?path=" + path), function(data) {
|
||||
renderpath(data);
|
||||
if (!data.error) {
|
||||
renderpath(data);
|
||||
}
|
||||
console.log("Permission denied.");
|
||||
});
|
||||
document.getElementById("slide-out").scrollTop = 0;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"LISTENIP": "0.0.0.0",
|
||||
"LISTENPORT": 3218,
|
||||
"BASEPATH": null,
|
||||
"ENFORCE_BASEPATH": false,
|
||||
"SSL_CERTIFICATE": null,
|
||||
"SSL_KEY": null,
|
||||
"HASS_API": "http://127.0.0.1:8123/api/",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue