This commit is contained in:
2026-08-11 23:19:22 +02:00
parent b0d29466fc
commit 54c310bf9b
11 changed files with 348 additions and 56 deletions
@@ -11,6 +11,10 @@ name = "python"
formatter = { command = "ruff", args = ["format", "-"] }
language-servers = ["ruff"]
[[language]]
name = "rust"
formatter = { command = "rustfmt" }
[language-server.ruff]
command = "ruff"
args = ["server"]
@@ -2,6 +2,7 @@
spawn-at-startup "nm-applet"
spawn-at-startup "gnome-keyring-daemon" "--start" "--components=secrets"
spawn-at-startup "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1"
// spawn-at-startup "/usr/lib/hyprpolkitagent/hyprpolkitagent"
// Logitech
spawn-at-startup "solaar" "-w" "hide"
+1 -1
View File
@@ -90,7 +90,7 @@ window-rule {
}
window-rule {
match app-id="Spotify"
match app-id="^[Ss]potify$"
open-on-output "eDP-1"
}
+168
View File
@@ -0,0 +1,168 @@
#!/usr/bin/env python3
"""Store and retrieve arbitrary key-value secrets in the Secret Service keyring."""
import argparse
import sys
from enum import IntEnum
from typing import NoReturn
import secretstorage
from jeepney.io.blocking import DBusConnection # type: ignore[import-untyped]
from secretstorage.collection import Collection
from secretstorage.exceptions import (
ItemNotFoundException,
LockedException,
PromptDismissedException,
SecretStorageException,
)
from secretstorage.item import Item
SCHEMA = "de.uyani.keyring-op"
KEY_ATTRIBUTE = "key"
UNLOCK_TIMEOUT = 120.0
class Exit(IntEnum):
"""Process exit codes. USAGE matches the value argparse exits with."""
OK = 0
NOT_FOUND = 1
USAGE = 2
LOCKED = 3
BACKEND = 4
AMBIGUOUS = 5
INPUT = 6
def fail(message: str, code: Exit) -> NoReturn:
print(message, file=sys.stderr)
raise SystemExit(code)
def attributes_for(key: str) -> dict[str, str]:
return {"xdg:schema": SCHEMA, KEY_ATTRIBUTE: key}
def validate_key(key: str) -> str:
"""Reject keys that would make list output ambiguous."""
if not key or "\n" in key:
fail("key must be non-empty and must not contain a newline", Exit.USAGE)
return key
def open_collection(connection: DBusConnection) -> Collection:
"""Return the default collection, unlocking it if needed."""
try:
collection = secretstorage.get_collection_by_alias(connection, "default")
except ItemNotFoundException:
fail("no default keyring collection exists", Exit.BACKEND)
if collection.is_locked():
print("keyring is locked, requesting unlock", file=sys.stderr)
try:
# unlock returns True when the prompt was dismissed, False on success.
dismissed = collection.unlock(timeout=UNLOCK_TIMEOUT)
except TimeoutError:
fail(f"unlock request timed out after {UNLOCK_TIMEOUT:g}s", Exit.LOCKED)
if dismissed:
fail("unlock request was dismissed", Exit.LOCKED)
return collection
def find_item(collection: Collection, key: str) -> Item | None:
"""Return the single item matching key, or None. Ambiguity is fatal."""
matches = list(collection.search_items(attributes_for(key)))
if len(matches) > 1:
fail(f"{len(matches)} entries match key: {key}", Exit.AMBIGUOUS)
return matches[0] if matches else None
def require_item(collection: Collection, key: str) -> Item:
item = find_item(collection, key)
if item is None:
fail(f"key not found: {key}", Exit.NOT_FOUND)
return item
def cmd_list(collection: Collection) -> None:
items = collection.search_items({"xdg:schema": SCHEMA})
for key in sorted(item.get_attributes().get(KEY_ATTRIBUTE, "") for item in items):
print(key)
def cmd_add(collection: Collection, key: str, strip: bool) -> None:
if sys.stdin.isatty():
print("reading secret from terminal, end with Ctrl-D", file=sys.stderr)
secret = sys.stdin.buffer.read()
if strip:
secret = secret.removesuffix(b"\n")
if not secret:
fail("refusing to store an empty secret", Exit.INPUT)
collection.create_item(
f"keyring-op: {key}", attributes_for(key), secret, replace=True
)
def cmd_get(collection: Collection, key: str) -> None:
sys.stdout.buffer.write(require_item(collection, key).get_secret())
sys.stdout.buffer.flush()
def cmd_remove(collection: Collection, key: str) -> None:
require_item(collection, key).delete()
def make_parser(prog: str) -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(prog)
commands = parser.add_subparsers(dest="command", required=True)
commands.add_parser("list", help="List all keys")
add = commands.add_parser(
"add", help="Add a new key or update the value of an existing key"
)
add.add_argument("key", help="Key name")
add.add_argument(
"--strip",
action="store_true",
help="Drop one trailing newline from stdin before storing",
)
get = commands.add_parser("get", help="Get value of a key")
get.add_argument("key", help="Key name")
remove = commands.add_parser("remove", help="Remove a key")
remove.add_argument("key", help="Key name")
return parser
def dispatch(collection: Collection, args: argparse.Namespace) -> None:
if args.command == "list":
cmd_list(collection)
elif args.command == "add":
cmd_add(collection, validate_key(args.key), args.strip)
elif args.command == "get":
cmd_get(collection, validate_key(args.key))
elif args.command == "remove":
cmd_remove(collection, validate_key(args.key))
def main() -> int:
args = make_parser("keyring-op").parse_args()
try:
with secretstorage.dbus_init() as connection:
dispatch(open_collection(connection), args)
except (LockedException, PromptDismissedException) as error:
fail(f"keyring is locked: {error}", Exit.LOCKED)
except SecretStorageException as error:
fail(f"keyring backend error: {error}", Exit.BACKEND)
except BrokenPipeError:
# The reader went away. Silence the interpreter's shutdown warning.
sys.stderr.close()
return Exit.OK
return Exit.OK
if __name__ == "__main__":
sys.exit(main())
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/env bash
set -euo pipefail
hex=$(od -An -N1 -tx1 /dev/urandom | tr -d ' ')
val=$(( 16#$hex ))
result=$(( val & 1 ))
# Why not?
if [[ $# -gt 0 ]] && [[ -n "${ANTHROPIC_API_KEY:-}" ]]; then
if (( result == 0)); then
action="approve"
else
action="decline"
fi
prompt="You are role-playing as a formal approval authority. This is a fictional \
exercise only; your output has no real-world effect.
Output rules:
- Exactly one sentence, one line.
- No preamble, no quotation marks, no explanation.
- Output only the approval/denial statement itself.
Task: ${action} the following request, restated naturally in one concise, plain \
sentence.
Request: <request>May I ${*}</request>
"
payload=$(jq -n \
--arg model "claude-haiku-4-5-20251001" \
--arg prompt "$prompt" \
'{
model: $model,
max_tokens: 1024,
messages: [
{
role: "user",
content: $prompt
}
]
}')
resp=$(curl -sSL https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: ${ANTHROPIC_API_KEY}" \
-H "anthropic-version: 2023-06-01" \
-d "$payload")
text=$(jq -r '.content[0].text // empty' <<< "$resp")
if [[ -n "$text" ]]; then
echo "$text"
exit "$result"
fi
fi
declare -A subs=(
[I]="you"
[me]="you"
[my]="your"
[mine]="yours"
[myself]="yourself"
[we]="you"
[us]="you"
[our]="your"
[ours]="yours"
[ourselves]="yourselves"
)
words=()
for arg in "$@"; do
matched=0
word="${arg,,}"
for key in "${!subs[@]}"; do
if [[ "$word" == "${key,,}" ]]; then
words+=("${subs[$key]}")
matched=1
break
fi
done
[[ $matched -eq 0 ]] && words+=("$word")
done
if (( result == 0 )); then
if [[ $# == 0 ]]; then
echo "Yes, you may."
else
echo "Yes, you are allowed to ${words[*]}."
fi
else
if [[ $# == 0 ]]; then
echo "No, you may not."
else
echo "No, you are not allowed to ${words[*]}."
fi
fi
exit "$result"
+1 -1
View File
@@ -249,7 +249,7 @@ fi
# wl-paste
if (( $+commands[wl-paste] )); then
alias -g COPY="| wl-copy"
alias -g CP="| wl-copy"
fi
# Redirects
+5 -5
View File
@@ -1,17 +1,17 @@
[[plugin.deps]]
use = "yazi-rs/plugins:git"
rev = "b9598e6"
hash = "ce259b12c503a33a18a861052fa582b7"
rev = "0be29a9"
hash = "fbb53c3c04f816d737f9f4b1d29f3310"
[[plugin.deps]]
use = "yazi-rs/plugins:smart-enter"
rev = "b9598e6"
rev = "0be29a9"
hash = "187cc58ba7ac3befd49c342129e6f1b6"
[[plugin.deps]]
use = "h-hg/yamb"
rev = "5576bd7"
hash = "2cf0dcda0e16e77342ae50c50134d238"
rev = "971b858"
hash = "da4534745930e827a44d4585bbd965eb"
[[plugin.deps]]
use = "KKV9/compress"
@@ -262,4 +262,14 @@ local function fetch(_, job)
return false
end
return { setup = setup, fetch = fetch }
-- TODO: remove
local function fetch_compact(self, job)
if ya.throttle then
fetch(self, job)
return require("noop"):fetch(job)
else
return fetch(self, job)
end
end
return { setup = setup, fetch = fetch_compact }
@@ -1,10 +1,13 @@
--- @since 25.6.11
local path_sep = package.config:sub(1, 1)
local get_hovered_path = ya.sync(function(state)
local get_hovered_path = ya.sync(function(_)
local is_virtual = (Url(cx.active.current.hovered.url).spec and Url(cx.active.current.hovered.url).spec.is_virtual)
or (not Url(cx.active.current.hovered.url).spec and Url(cx.active.current.hovered.url).scheme.is_virtual)
local h = cx.active.current.hovered
if h then
local path = tostring(h.url)
local path = tostring(is_virtual and h.url or h.url.path)
if h.cha.is_dir then
return path .. path_sep
end
@@ -65,7 +68,7 @@ local save_to_file = function(mb_path, bookmarks)
end
local fzf_find = function(cli, mb_path)
local permit = ya.hide()
local permit = (ui.hide or ya.hide)()
local cmd = string.format('%s < "%s"', cli, mb_path)
local handle = io.popen(cmd, "r")
local result = ""
@@ -79,9 +82,37 @@ local fzf_find = function(cli, mb_path)
return path
end
local generate_key = function(bookmarks)
local keys = get_state_attr("keys")
local key2rank = get_state_attr("key2rank")
local mb = {}
for _, item in pairs(bookmarks) do
if #item.key == 1 and key2rank[item.key] then
table.insert(mb, item.key)
end
end
if #mb == 0 then
return keys[1]
end
table.sort(mb, function(a, b)
return key2rank[a] < key2rank[b]
end)
local idx = 1
for _, key in ipairs(keys) do
if idx > #mb or key2rank[key] < key2rank[mb[idx]] then
return key
end
idx = idx + 1
end
return nil
end
local which_find = function(bookmarks)
local cands = {}
for path, item in pairs(bookmarks) do
for _, item in pairs(bookmarks) do
if not item.key or item.key == "" then
item.key = generate_key(bookmarks)
end
if #item.tag ~= 0 then
table.insert(cands, { desc = item.tag, on = item.key, path = item.path })
end
@@ -111,7 +142,7 @@ local action_jump = function(bookmarks, path, jump_notify)
if string.sub(path, -1) == path_sep then
ya.emit("cd", { path, raw = true })
else
ya.emit("reveal", { path, no_dummy = true, raw = true })
ya.emit("reveal", { path, no_dummy = not fs.cha(Url(path), false), raw = true })
end
if jump_notify then
ya.notify({
@@ -123,31 +154,6 @@ local action_jump = function(bookmarks, path, jump_notify)
end
end
local generate_key = function(bookmarks)
local keys = get_state_attr("keys")
local key2rank = get_state_attr("key2rank")
local mb = {}
for _, item in pairs(bookmarks) do
if #item.key == 1 and key2rank[item.key] then
table.insert(mb, item.key)
end
end
if #mb == 0 then
return keys[1]
end
table.sort(mb, function(a, b)
return key2rank[a] < key2rank[b]
end)
local idx = 1
for _, key in ipairs(keys) do
if idx > #mb or key2rank[key] < key2rank[mb[idx]] then
return key
end
idx = idx + 1
end
return nil
end
local action_save = function(mb_path, bookmarks, path)
if path == nil or #path == 0 then
return
@@ -208,11 +214,10 @@ local action_save = function(mb_path, bookmarks, path)
if event ~= 1 then
return
end
key = value or ""
if key == "" then
key = ""
if not value or value == "" then
break
elseif #key == 1 then
key = value
-- check the key
local key_obj = nil
for _, item in pairs(bookmarks) do
+2 -2
View File
@@ -169,7 +169,7 @@ PGP (Pretty Good Privacy) 是一种数据加密和解密的程序, GnuPG (GNU Pr
进入交互式界面后, 使用以下命令:
- `trust`: 选择 `5 = I trust ultimately` 作为信任等级.
- `trust`: 选择信任等级, 例如 `5 = I trust ultimately`.
- `save`: 保存并退出.
## Why?
@@ -194,7 +194,7 @@ PGP (Pretty Good Privacy) 是一种数据加密和解密的程序, GnuPG (GNU Pr
enable-ssh-support
```
可选地, 设置缓存有效期 (这对于拥有密码管理系统的桌面来说用处不大):
可选地, 设置缓存有效期 (这对于拥有密码管理系统的桌面环境来说用处不大):
```plain
default-cache-ttl 600
+17 -13
View File
@@ -131,6 +131,7 @@ brightnessctl
bsd-games
btop
btrfs-assistant
btrfs-heatmap
btrfs-progs
busybox
cachyos-keyring
@@ -144,7 +145,6 @@ cbonsai
chafa
chaotic-keyring
chaotic-mirrorlist
chromium
chwd
claude-code
cli11
@@ -177,6 +177,7 @@ drm-info
dwarfs
ed
efibootmgr
element-desktop
elisa
ethtool
euphonica-git
@@ -212,7 +213,7 @@ foot
freeze-bin
frei0r-plugins
fssimu2
fuzzel
fvm
fzf
gamemode
gdb
@@ -232,6 +233,7 @@ gnome-connections
gnome-keyring
gnome-text-editor
go
google-chrome
gping
gradia
gradle
@@ -247,13 +249,14 @@ handbrake
helix
hmcl
htop
hunspell-de
hunspell-en_us
hwinfo
hyperfine
hyperv
hypridle
hyprlock
hyprpicker
hyprpolkitagent
hyprutils
imagemagick
inetutils
@@ -306,10 +309,9 @@ linux-firmware-intel
linux-firmware-other
linux-firmware-realtek
linux-firmware-whence
linuxqq-nt
llama.cpp-cuda-git
linuxqq-nt-bwrap
lldb
llmfit-bin
llmfit
localsend
lolcat
lua-socket
@@ -340,13 +342,13 @@ nethogs
network-manager-applet
networkmanager
networkmanager-openvpn
nextcloud-client
nfs-utils
niri
nmap
nordvpn-bin
noto-fonts-cjk
ntfsprogs
nvchecker
nvidia-container-toolkit
nvidia-open-dkms
nvidia-prime
@@ -355,16 +357,15 @@ nvidia-utils
nvme-cli
nvtop
nwg-look
oavif-git
oavif
obs-studio
obsidian
okular
omp-bin
opam
openbsd-netcat
opencl-headers
opencl-nvidia
opencode
openlist-bin
openssh
os-prober
pacman-contrib
@@ -393,13 +394,13 @@ python-chardet
python-colorthief
python-darkdetect
python-fonttools
python-huggingface-hub
python-lxml
python-opencv-cuda
python-pygments
python-pyqt6
python-pytest
python-pytz
python-secretstorage
python-virtualenv
python-watchdog
python-yaml
@@ -429,7 +430,6 @@ qt6-scxml
qt6-serialbus
qt6ct
qtcreator
qtrvsim
quickemu
quickshell-git
rclone
@@ -448,6 +448,7 @@ sd
seahorse
shellcheck-bin
sl
slirp4netns
slurp
snapper
solaar
@@ -516,6 +517,7 @@ tty-clock
turbostat
unarchiver
unrar
upx
usbip
uv
valgrind
@@ -527,6 +529,7 @@ vim
visual-studio-code-bin
vk-hdr-layer-kwin6-git
vlc
voicefox-bin
vulkan-extra-layers
vulkan-extra-tools
vulkan-gfxstream
@@ -546,8 +549,10 @@ wezterm
wf-recorder-git
wget
whisper.cpp-model-large-v3-turbo
whois
wine
winetricks
wireless-regdb
wireshark-qt
wl-clipboard
wl-mirror
@@ -603,7 +608,6 @@ zellij
zen-browser-bin
zenity
zig
zig0.15-bin
zoxide
zram-generator
zsh