Support persisting clipboard prompt choices

All the promptable feature permissions so far have been of type BoolAsk.
The prompt uses a "yesno" mode prompt and only results in a bool. The
persistence logic only supports bools.

Previously I made the shared prompt support the String type clipboard
permission setting by treating non "ask" values as False (you only get
prompted if the global setting is "none" anyway), but saving the prompt
results with `:prompt-accept --save` didn't work because the persistence
code only supported bools.

What we want to do when saving is convert `False` to "none" and `True`
to "access-paste". This mirrors the new webengine logic. It does mean we
can't let users choose to persist either none/access/access-paste, but
webengine doesn't prompt us if the page is already allowed "access" but
is trying to paste anyway. If it did we would have to use a non-yesno
prompt for this (perhaps it could be driven directly by the ConfigType).

For now I've added a new concept to the ConfigTypes to allow them to be
casted to and from bools, so that we can plumb this String type from the
boolean yesno prompt.

TODO:
* try to make it an interface so we don't have to use `hasattr` (even if
  it means multiple inheritance)
* add test coverage to test_configtypes.py
This commit is contained in:
toofar 2024-10-28 14:58:09 +13:00
parent 4c3337f553
commit fbd148f983
5 changed files with 54 additions and 11 deletions

View File

@ -303,6 +303,7 @@ def feature_permission(url, option, msg, yes_action, no_action, abort_on,
None otherwise.
"""
config_val = config.instance.get(option, url=url)
opt = config.instance.get_opt(option)
if config_val == 'ask':
if url.isValid():
urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded)
@ -328,20 +329,21 @@ def feature_permission(url, option, msg, yes_action, no_action, abort_on,
cancel_action=no_action, abort_on=abort_on,
title='Permission request', text=text, url=urlstr,
option=option)
elif config_val is True:
if hasattr(opt.typ, "to_bool"):
config_val = opt.typ.to_bool(config_val)
if config_val is True:
yes_action()
return None
elif config_val is False:
no_action()
return None
else:
if option not in {
"content.javascript.clipboard" # String type option with 'ask' value
}:
log.misc.warning(
f"Unsupported value for permission prompt setting ({option}), expected boolean or "
f"'ask', got: {config_val} ({type(config_val)})"
)
log.misc.warning(
f"Unsupported value for permission prompt setting ({option}), expected boolean or "
f"'ask', got: {config_val} ({type(config_val)})"
)
no_action()
return None

View File

@ -925,7 +925,7 @@ content.javascript.alert:
content.javascript.clipboard:
default: ask
type:
name: String
name: JSClipboardPermission
valid_values:
- none: Disable access to clipboard.
- access: Allow reading from and writing to the clipboard.

View File

@ -2016,3 +2016,20 @@ class StatusbarWidget(String):
if value.startswith("text:") or value.startswith("clock:"):
return
super()._validate_valid_values(value)
class JSClipboardPermission(String):
"""Permission for page JS to access the system clipboard.
String + BoolAsk
"""
def to_bool(self, value: str) -> bool:
return value == "access-paste"
def from_bool(self, value: bool) -> str:
if value is True:
return "access-paste"
else:
return "none"

View File

@ -976,12 +976,23 @@ class YesNoPrompt(_BasePrompt):
raise Error("Invalid value {} - expected yes/no!".format(value))
if save:
value = self.question.answer
opt = config.instance.get_opt(self.question.option)
assert isinstance(opt.typ, configtypes.Bool)
if isinstance(opt.typ, configtypes.Bool):
pass
elif hasattr(opt.typ, "from_bool"):
value = opt.typ.from_bool(value)
else:
raise AssertionError(
"Cannot save prompt answer. Expected 'Bool' option or "
"option with 'from_bool()'. "
f"option={opt.name} type={type(opt.typ)}"
)
pattern = urlmatch.UrlPattern(self.question.url)
try:
config.instance.set_obj(opt.name, self.question.answer,
config.instance.set_obj(opt.name, value,
pattern=pattern, save_yaml=True)
except configexc.Error as e:
raise Error(str(e))

View File

@ -271,6 +271,19 @@ Feature: Prompts
Then the javascript message "Failed to read from clipboard." should be logged
And I run :config-unset -u localhost:* content.javascript.clipboard
@qt>=6.8
Scenario: Clipboard - ask allow persistent - paste
Given I may need a fresh instance
When I set content.javascript.clipboard to ask
And I open data/prompt/clipboard.html
And I run :click-element id paste
And I wait for a prompt
And I run :prompt-accept --save yes
And I wait for "*Text pasted: *" in the log
And I reload
And I run :click-element id paste
Then the javascript message "Text pasted: *" should be logged
# SSL
Scenario: SSL error with content.tls.certificate_errors = load-insecurely