diff --git a/src/octoprint/plugin/types.py b/src/octoprint/plugin/types.py index 6d98b661..2bcc9f3b 100644 --- a/src/octoprint/plugin/types.py +++ b/src/octoprint/plugin/types.py @@ -1367,11 +1367,48 @@ class SettingsPlugin(OctoPrintPlugin): and iterate yourself over all your settings, using the proper retriever methods on the settings manager to retrieve the data in the correct format. + The default implementation will also replace any paths that have been restricted by your plugin through + :func:`~octoprint.plugin.SettingsPlugin.get_settings_restricted_paths` with ``None`` values where necessary. + Make sure to do your own restriction if you decide to fully overload this method. + :return: the current settings of the plugin, as a dictionary """ + from flask.ext.login import current_user + data = self._settings.get_all_data() if self.config_version_key in data: del data[self.config_version_key] + + restricted_paths = self.get_settings_restricted_paths() + + def restrict_path_unless(data, path, condition): + if not path: + return + + if condition(): + return + + node = data + + if len(path) > 1: + for entry in path[:-1]: + if not entry in node: + return + node = node[entry] + + key = path[-1] + if key in node: + node[key] = None + + conditions = dict(user=lambda: current_user is not None and not current_user.is_anonymous(), + admin=lambda: current_user is not None and not current_user.is_anonymous() and current_user.is_admin(), + never=lambda: False) + + for level, condition in conditions.items(): + paths_for_level = restricted_paths.get(level, []) + for path in paths_for_level: + restrict_path_unless(data, path, condition) + return data def on_settings_save(self, data): @@ -1434,6 +1471,60 @@ class SettingsPlugin(OctoPrintPlugin): """ return dict() + def get_settings_restricted_paths(self): + """ + Retrieves the list of paths in the plugin's settings which be restricted on the REST API. + + Override this in your plugin's implementation to restrict whether a path should only be returned to logged in + users & admins, only to admins, or never on the REST API. + + Return a ``dict`` with the keys ``admin``, ``user``, ``never`` mapping to a list of paths (as tuples or lists of + the path elements) for which to restrict access via the REST API accordingly. Paths returned for the ``admin`` + key will only be available on the REST API when access with admin rights, ``user`` will only be available when accessed + as a logged in user. ``never`` will never be returned on the API. + + Example: + + .. code-block:: python + + def get_settings_defaults(self): + return dict(some=dict(admin_only=dict(path="path", foo="foo"), + user_only=dict(path="path", bar="bar")), + another=dict(admin_only=dict(path="path"), + field="field"), + path=dict(to=dict(never=dict(return="return")))) + + def get_settings_restricted_path(self): + return dict(admin=[["some", "admin_only", "path], ["another", "admin_only", "path"], + user=[["some", "user_only", "path"],], + never=[["path", "to", "never", "return"],]) + + # this will make the plugin return settings on the REST API like this for an anonymous user + # + # dict(some=dict(admin_only=dict(path=None, foo="foo"), + # user_only=dict(path=None, bar="bar")), + # another=dict(admin_only=dict(path=None), + # field="field"), + # path=dict(to=dict(never=dict(return=None)))) + # + # like this for a logged in user + # + # dict(some=dict(admin_only=dict(path=None, foo="foo"), + # user_only=dict(path="path", bar="bar")), + # another=dict(admin_only=dict(path=None), + # field="field"), + # path=dict(to=dict(never=dict(return=None)))) + # + # and like this for an admin user + # + # dict(some=dict(admin_only=dict(path="path", foo="foo"), + # user_only=dict(path="path", bar="bar")), + # another=dict(admin_only=dict(path="path"), + # field="field"), + # path=dict(to=dict(never=dict(return=None)))) + """ + return dict() + def get_settings_preprocessors(self): """ Retrieves the plugin's preprocessors to use for preprocessing returned or set values prior to returning/setting diff --git a/src/octoprint/server/util/flask.py b/src/octoprint/server/util/flask.py index 4c0f329f..3ff3f8f1 100644 --- a/src/octoprint/server/util/flask.py +++ b/src/octoprint/server/util/flask.py @@ -414,13 +414,6 @@ class OctoPrintFlaskResponse(flask.Response): # add request specific cookie suffix to name flask.Response.set_cookie(self, key + flask.request.cookie_suffix, *args, **kwargs) - def delete_cookie(self, key, *args, **kwargs): - # restrict cookie path to script root - kwargs["path"] = flask.request.script_root + kwargs.get("path", "/") - - # add request specific cookie suffix to name - flask.Response.delete_cookie(self, key + flask.request.cookie_suffix, *args, **kwargs) - #~~ passive login helper def passive_login(): diff --git a/src/octoprint/server/util/sockjs.py b/src/octoprint/server/util/sockjs.py index 9187a32a..cf14d778 100644 --- a/src/octoprint/server/util/sockjs.py +++ b/src/octoprint/server/util/sockjs.py @@ -207,4 +207,7 @@ class PrinterStateConnection(sockjs.tornado.SockJSConnection, octoprint.printer. try: self.send({type: payload}) except Exception as e: - self._logger.warn("Could not send message to client %s: %s" % (self._remoteAddress, str(e))) + if self._logger.isEnabledFor(logging.DEBUG): + self._logger.exception("Could not send message to client {}".format(self._remoteAddress)) + else: + self._logger.warn("Could not send message to client {}: {}".format(self._remoteAddress, e))