From e44c5aee5b225ab97afdd8d0960d17aee659f985 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 10 Feb 2015 21:09:08 +0100 Subject: [PATCH] Add config options for geolocation/notifications. --- doc/help/settings.asciidoc | 26 +++++++++++ qutebrowser/browser/webpage.py | 71 +++++++++++++++++-------------- qutebrowser/config/configdata.py | 8 ++++ qutebrowser/config/configtypes.py | 46 +++++++++++++++----- 4 files changed, 109 insertions(+), 42 deletions(-) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 9a4abb113..bb0ef7986 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -121,6 +121,8 @@ |<>|Whether images are automatically loaded in web pages. |<>|Enables or disables the running of JavaScript programs. |<>|Enables or disables plugins in Web pages. +|<>|Allow websites to request geolocations. +|<>|Allow websites to show notifications. |<>|Whether JavaScript programs can open new windows. |<>|Whether JavaScript programs can close windows. |<>|Whether JavaScript programs can read or write to the clipboard. @@ -995,6 +997,30 @@ Valid values: Default: +pass:[false]+ +[[content-geolocation]] +=== geolocation +Allow websites to request geolocations. + +Valid values: + + * +true+ + * +false+ + * +ask+ + +Default: +pass:[ask]+ + +[[content-notifications]] +=== notifications +Allow websites to show notifications. + +Valid values: + + * +true+ + * +false+ + * +ask+ + +Default: +pass:[ask]+ + [[content-javascript-can-open-windows]] === javascript-can-open-windows Whether JavaScript programs can open new windows. diff --git a/qutebrowser/browser/webpage.py b/qutebrowser/browser/webpage.py index b8cddfbf8..3ecf243a9 100644 --- a/qutebrowser/browser/webpage.py +++ b/qutebrowser/browser/webpage.py @@ -285,39 +285,48 @@ class BrowserPage(QWebPage): @pyqtSlot('QWebFrame', 'QWebPage::Feature') def on_feature_permission_requested(self, frame, feature): """Ask the user for approval for geolocation/notifications.""" - bridge = objreg.get('message-bridge', scope='window', - window=self._win_id) - q = usertypes.Question(bridge) - q.mode = usertypes.PromptMode.yesno - - msgs = { - QWebPage.Notifications: 'show notifications', - QWebPage.Geolocation: 'access your location', + options = { + QWebPage.Notifications: ('content', 'notifications'), + QWebPage.Geolocation: ('content', 'geolocation'), } - host = frame.url().host() - if host: - q.text = "Allow the website at {} to {}?".format( - frame.url().host(), msgs[feature]) + if config.get(*options[feature]) == 'ask': + bridge = objreg.get('message-bridge', scope='window', + window=self._win_id) + q = usertypes.Question(bridge) + q.mode = usertypes.PromptMode.yesno + + msgs = { + QWebPage.Notifications: 'show notifications', + QWebPage.Geolocation: 'access your location', + } + + host = frame.url().host() + if host: + q.text = "Allow the website at {} to {}?".format( + frame.url().host(), msgs[feature]) + else: + q.text = "Allow the website to {}?".format(msgs[feature]) + + yes_action = functools.partial( + self.setFeaturePermission, frame, feature, + QWebPage.PermissionGrantedByUser) + q.answered_yes.connect(yes_action) + + no_action = functools.partial( + self.setFeaturePermission, frame, feature, + QWebPage.PermissionDeniedByUser) + q.answered_no.connect(no_action) + + q.completed.connect(q.deleteLater) + + self.featurePermissionRequestCanceled.connect(functools.partial( + self.on_feature_permission_cancelled, q, frame, feature)) + self.loadStarted.connect(q.abort) + + bridge.ask(q, blocking=False) else: - q.text = "Allow the website to {}?".format(msgs[feature]) - - yes_action = functools.partial( - self.setFeaturePermission, frame, feature, - QWebPage.PermissionGrantedByUser) - q.answered_yes.connect(yes_action) - - no_action = functools.partial( - self.setFeaturePermission, frame, feature, - QWebPage.PermissionDeniedByUser) - q.answered_no.connect(no_action) - - q.completed.connect(q.deleteLater) - - self.featurePermissionRequestCanceled.connect(functools.partial( - self.on_feature_permission_cancelled, q, frame, feature)) - self.loadStarted.connect(q.abort) - - bridge.ask(q, blocking=False) + self.setFeaturePermission(frame, feature, + QWebPage.PermissionDeniedByUser) def on_feature_permission_cancelled(self, question, frame, feature, cancelled_frame, cancelled_feature): diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 3bd724d8f..4d09ad527 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -498,6 +498,14 @@ DATA = collections.OrderedDict([ 'Qt plugins with a mimetype such as "application/x-qt-plugin" are ' "not affected by this setting."), + ('geolocation', + SettingValue(typ.NoAsk(), 'ask'), + "Allow websites to request geolocations."), + + ('notifications', + SettingValue(typ.NoAsk(), 'ask'), + "Allow websites to show notifications."), + #('allow-java', # SettingValue(typ.Bool(), 'true'), # "Enables or disables Java applets. Currently Java applets are " diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index 55606f45e..69f22f08f 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -38,6 +38,10 @@ from qutebrowser.config import configexc SYSTEM_PROXY = object() # Return value for Proxy type +# Taken from configparser +BOOLEAN_STATES = {'1': True, 'yes': True, 'true': True, 'on': True, + '0': False, 'no': False, 'false': False, 'off': False} + class ValidValues: @@ -221,25 +225,17 @@ class List(BaseType): class Bool(BaseType): - """Base class for a boolean setting. - - Class attributes: - _BOOLEAN_STATES: A dictionary of strings mapped to their bool meanings. - """ + """Base class for a boolean setting.""" typestr = 'bool' - # Taken from configparser - _BOOLEAN_STATES = {'1': True, 'yes': True, 'true': True, 'on': True, - '0': False, 'no': False, 'false': False, 'off': False} - valid_values = ValidValues('true', 'false') def transform(self, value): if not value: return None else: - return Bool._BOOLEAN_STATES[value.lower()] + return BOOLEAN_STATES[value.lower()] def validate(self, value): if not value: @@ -247,7 +243,7 @@ class Bool(BaseType): return else: raise configexc.ValidationError(value, "may not be empty!") - if value.lower() not in Bool._BOOLEAN_STATES: + if value.lower() not in BOOLEAN_STATES: raise configexc.ValidationError(value, "must be a boolean!") @@ -270,6 +266,34 @@ class BoolAsk(Bool): super().validate(value) +class NoAsk(BaseType): + + """A no/ask question.""" + + valid_values = ValidValues('false', 'ask') + + def transform(self, value): + if value.lower() == 'ask': + return 'ask' + else: + return BOOLEAN_STATES[value.lower()] + + def validate(self, value): + if not value: + if self._none_ok: + return + else: + raise configexc.ValidationError(value, "may not be empty!") + if value.lower() == 'ask': + return + try: + v = BOOLEAN_STATES[value.lower()] + if v: + raise configexc.ValidationError(value, "must be ask/false!") + except KeyError: + raise configexc.ValidationError(value, "must be ask/false!") + + class Int(BaseType): """Base class for an integer setting.