summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2022-06-14 14:17:07 +0200
committerFlorian Bruhin <me@the-compiler.org>2022-06-14 14:17:07 +0200
commit7fc4a3da624e1b0a8c50843551d13505d8a72a8b (patch)
treec6aead0951961d9d75772a45e8dd3588d7b574d8
parent942effc635918f0a54dd735c43842aaf5f306c0b (diff)
parent9538cbe9e71ef5c36dd45de3abc97fe00da91249 (diff)
downloadqutebrowser-7fc4a3da624e1b0a8c50843551d13505d8a72a8b.tar.gz
qutebrowser-7fc4a3da624e1b0a8c50843551d13505d8a72a8b.zip
Merge remote-tracking branch 'origin/pr/6456'
-rw-r--r--misc/userscripts/README.md1
-rwxr-xr-xmisc/userscripts/qute-1pass124
2 files changed, 125 insertions, 0 deletions
diff --git a/misc/userscripts/README.md b/misc/userscripts/README.md
index 5a7a3d51d..12517e4f1 100644
--- a/misc/userscripts/README.md
+++ b/misc/userscripts/README.md
@@ -23,6 +23,7 @@ The following userscripts are included in the current directory.
dmenu-compatible application (e.g. dmenu, rofi -dmenu, ...).
- [qute-lastpass](./qute-lastpass): Similar to qute-pass, for Lastpass.
- [qute-bitwarden](./qute-bitwarden): Similar to qute-pass, for Bitwarden.
+- [qute-1pass](./qute-1pass): Insert login information using onepassword and rofi.
- [qutedmenu](./qutedmenu): Handle open -s && open -t with bemenu.
- [readability](./readability): Executes python-readability on current page and
opens the summary as new tab.
diff --git a/misc/userscripts/qute-1pass b/misc/userscripts/qute-1pass
new file mode 100755
index 000000000..091f841fc
--- /dev/null
+++ b/misc/userscripts/qute-1pass
@@ -0,0 +1,124 @@
+#!/usr/bin/env bash
+
+set +e
+
+# JS field injection code from https://github.com/qutebrowser/qutebrowser/blob/master/misc/userscripts/password_fill
+javascript_escape() {
+ # print the first argument in an escaped way, such that it can safely
+ # be used within javascripts double quotes
+ # shellcheck disable=SC2001
+ sed "s,[\\\\'\"\/],\\\\&,g" <<< "$1"
+}
+
+js() {
+cat <<EOF
+ function isVisible(elem) {
+ var style = elem.ownerDocument.defaultView.getComputedStyle(elem, null);
+ if (style.getPropertyValue("visibility") !== "visible" ||
+ style.getPropertyValue("display") === "none" ||
+ style.getPropertyValue("opacity") === "0") {
+ return false;
+ }
+ return elem.offsetWidth > 0 && elem.offsetHeight > 0;
+ };
+ function hasPasswordField(form) {
+ var inputs = form.getElementsByTagName("input");
+ for (var j = 0; j < inputs.length; j++) {
+ var input = inputs[j];
+ if (input.type == "password") {
+ return true;
+ }
+ }
+ return false;
+ };
+ function loadData2Form (form) {
+ var inputs = form.getElementsByTagName("input");
+ for (var j = 0; j < inputs.length; j++) {
+ var input = inputs[j];
+ if (isVisible(input) && (input.type == "text" || input.type == "email")) {
+ input.focus();
+ input.value = "$(javascript_escape "${USERNAME}")";
+ input.dispatchEvent(new Event('change'));
+ input.blur();
+ }
+ if (input.type == "password") {
+ input.focus();
+ input.value = "$(javascript_escape "${PASSWORD}")";
+ input.dispatchEvent(new Event('change'));
+ input.blur();
+ }
+ }
+ };
+ var forms = document.getElementsByTagName("form");
+ if("$(javascript_escape "${QUTE_URL}")" == window.location.href) {
+ for (i = 0; i < forms.length; i++) {
+ if (hasPasswordField(forms[i])) {
+ loadData2Form(forms[i]);
+ }
+ }
+ } else {
+ alert("Secrets will not be inserted.\nUrl of this page and the one where the user script was started differ.");
+ }
+EOF
+}
+
+URL=$(echo "$QUTE_URL" | awk -F/ '{print $3}' | sed 's/www.//g')
+TOKEN_TMPDIR="${TMPDIR:-/tmp}"
+TOKEN_CACHE="$TOKEN_TMPDIR/1pass.token"
+
+echo "message-info 'Looking for password for $URL...'" >> "$QUTE_FIFO"
+
+if [ -f "$TOKEN_CACHE" ]; then
+ TOKEN=$(cat "$TOKEN_CACHE")
+ if ! op signin --session="$TOKEN" --output=raw > /dev/null; then
+ TOKEN=$(rofi -dmenu -password -p "1password: "| op signin --output=raw) || TOKEN=""
+ echo "$TOKEN" > "$TOKEN_CACHE"
+ fi
+else
+ TOKEN=$(rofi -dmenu -password -p "1password: "| op signin --output=raw) || TOKEN=""
+ install -m 600 /dev/null "$TOKEN_CACHE"
+ echo "$TOKEN" > "$TOKEN_CACHE"
+fi
+
+
+if [ -n "$TOKEN" ]; then
+ UUID=$(op list items --cache --session="$TOKEN" | jq --arg url "$URL" -r '[.[] | {uuid, url: [.overview.URLs[]?.u, .overview.url][]?} | select(.uuid != null) | select(.url != null) | select(.url|test(".*\($url).*"))][.0].uuid') || UUID=""
+
+ if [ -z "$UUID" ] || [ "$UUID" == "null" ];then
+ echo "message-error 'No entry found for $URL'" >> "$QUTE_FIFO"
+ TITLE=$(op list items --cache --session="$TOKEN" | jq -r '.[].overview.title' | rofi -dmenu -i) || TITLE=""
+ if [ -n "$TITLE" ]; then
+ UUID=$(op list items --cache --session="$TOKEN" | jq --arg title "$TITLE" -r '[.[] | {uuid, title:.overview.title}|select(.title|test("\($title)"))][.0].uuid') || UUID=""
+ else
+ UUID=""
+ fi
+ fi
+
+ if [ -n "$UUID" ];then
+ ITEM=$(op get item --cache --session="$TOKEN" "$UUID")
+
+ PASSWORD=$(echo "$ITEM" | jq -r '.details.fields | .[] | select(.designation=="password") | .value')
+
+ if [ -n "$PASSWORD" ]; then
+ TITLE=$(echo "$ITEM" | jq -r '.overview.title')
+ USERNAME=$(echo "$ITEM" | jq -r '.details.fields | .[] | select(.designation=="username") | .value')
+
+ printjs() {
+ js | sed 's,//.*$,,' | tr '\n' ' '
+ }
+ echo "jseval -q $(printjs)" >> "$QUTE_FIFO"
+
+ TOTP=$(echo "$ITEM" | op get totp --cache --session="$TOKEN" "$UUID") || TOTP=""
+ if [ -n "$TOTP" ]; then
+ echo "$TOTP" | xclip -in -selection clipboard
+ echo "message-info 'Pasted one time password for $TITLE to clipboard'" >> "$QUTE_FIFO"
+ fi
+ else
+ echo "message-error 'No password found for $URL'" >> "$QUTE_FIFO"
+ fi
+ else
+ echo "message-error 'Entry not found for $UUID'" >> "$QUTE_FIFO"
+ fi
+else
+ echo "message-error 'Wrong master password'" >> "$QUTE_FIFO"
+fi