mirror of
https://github.com/Matir/skel.git
synced 2026-07-24 21:26:57 -07:00
Compare commits
51 Commits
claude/deb
...
2814312d60
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2814312d60 | ||
|
|
a390d0a4d4 | ||
|
|
6caee04853 | ||
|
|
da1ee162c2 | ||
|
|
22b3f2e049 | ||
|
|
b81ca9703b | ||
|
|
be903aeb2c | ||
|
|
37816c7f72 | ||
|
|
63f8bb9364 | ||
|
|
691b2a7c6f | ||
|
|
8e42781710 | ||
|
|
de601c4a83 | ||
|
|
684f6c6e95 | ||
|
|
91972eed59 | ||
|
|
eca9a6bcb2 | ||
|
|
3214af0617 | ||
|
|
be3fdefd23 | ||
|
|
00eb8832c2 | ||
|
|
5852b8564f | ||
|
|
f56bcf4cdf | ||
|
|
ad135fac37 | ||
|
|
e4b9a7c16b | ||
|
|
75348c4413 | ||
|
|
2e0c11c044 | ||
|
|
68daa27893 | ||
|
|
398d55b8e4 | ||
|
|
c9918cf213 | ||
|
|
d1e3c8e43e | ||
|
|
f4bb5108ab | ||
|
|
5eac8826da | ||
|
|
b1d625d3c5 | ||
|
|
5a7d9cf060 | ||
|
|
9770514d6a | ||
|
|
e1724c77f3 | ||
|
|
ecbc25e5ac | ||
|
|
ea33840ef6 | ||
|
|
1048775da3 | ||
|
|
c9af80bc5d | ||
|
|
d8b4991419 | ||
|
|
158d9f6e4e | ||
|
|
b1d1c42a02 | ||
|
|
f8ec9cc338 | ||
|
|
6e3c3dd269 | ||
|
|
77b8374871 | ||
|
|
4645682b5c | ||
|
|
75bdebb497 | ||
|
|
4e72b9b18c | ||
|
|
bd2c2287cd | ||
|
|
db2c02bd2d | ||
|
|
fec16225e4 | ||
|
|
fa6a878487 |
47
Brewfile
47
Brewfile
@@ -1,5 +1,7 @@
|
||||
tap "dart-lang/dart"
|
||||
tap "sass/sass"
|
||||
tap "dart-lang/dart", trusted: true
|
||||
tap "espressif/eim"
|
||||
tap "holtwick/tap", trusted: true
|
||||
tap "sass/sass", trusted: true
|
||||
|
||||
brew "ack"
|
||||
brew "acme.sh"
|
||||
@@ -8,37 +10,51 @@ brew "autoconf"
|
||||
brew "automake"
|
||||
brew "b2-tools"
|
||||
brew "bat"
|
||||
brew "bazelisk"
|
||||
brew "binwalk"
|
||||
brew "cask"
|
||||
brew "ccache"
|
||||
brew "certbot"
|
||||
brew "cloudflared"
|
||||
brew "cmake"
|
||||
brew "colima"
|
||||
brew "devcontainer"
|
||||
brew "dfu-util"
|
||||
brew "difftastic"
|
||||
brew "direnv"
|
||||
brew "dua-cli"
|
||||
brew "duck"
|
||||
brew "dust"
|
||||
brew "earthly"
|
||||
brew "espressif/eim/eim", trusted: true
|
||||
brew "esptool"
|
||||
brew "fish"
|
||||
brew "fq"
|
||||
brew "gh"
|
||||
brew "ghidra", link: false
|
||||
brew "git"
|
||||
brew "git-delta"
|
||||
brew "git-lfs"
|
||||
brew "git-xet"
|
||||
brew "glib"
|
||||
brew "gnupg"
|
||||
brew "go"
|
||||
brew "gradle"
|
||||
brew "hashcat"
|
||||
brew "hf"
|
||||
brew "holtwick/tap/bx", trusted: true
|
||||
brew "htop"
|
||||
brew "httpie"
|
||||
brew "huggingface-cli"
|
||||
brew "hugo"
|
||||
brew "imagemagick"
|
||||
brew "john-jumbo"
|
||||
brew "jq"
|
||||
brew "kubeconform"
|
||||
brew "kubectx"
|
||||
brew "libgcrypt"
|
||||
brew "librsvg"
|
||||
brew "libslirp"
|
||||
brew "lima"
|
||||
brew "minikube"
|
||||
brew "mise"
|
||||
brew "mosh"
|
||||
brew "neovim"
|
||||
@@ -48,22 +64,27 @@ brew "ollama"
|
||||
brew "p7zip"
|
||||
brew "pipenv"
|
||||
brew "pipx"
|
||||
brew "pixman"
|
||||
brew "pkgconf"
|
||||
brew "protobuf"
|
||||
brew "pwgen"
|
||||
brew "pwntools"
|
||||
brew "python@3.13"
|
||||
brew "python@3.14"
|
||||
brew "qemu"
|
||||
brew "restic"
|
||||
brew "ripgrep"
|
||||
brew "ruby"
|
||||
brew "ruby", link: false
|
||||
brew "ruby@3.3"
|
||||
brew "rustup"
|
||||
brew "sass/sass/migrator"
|
||||
brew "sass/sass/sass"
|
||||
brew "sdl2-compat"
|
||||
brew "shellcheck"
|
||||
brew "smartmontools"
|
||||
brew "starship"
|
||||
brew "tmux"
|
||||
brew "todoist-cli"
|
||||
brew "uv"
|
||||
brew "virtualenvwrapper"
|
||||
brew "wget"
|
||||
@@ -92,7 +113,7 @@ cask "raycast"
|
||||
cask "rectangle"
|
||||
cask "scroll-reverser"
|
||||
cask "temurin"
|
||||
cask "veracrypt"
|
||||
cask "wezterm"
|
||||
cask "zulu@17"
|
||||
|
||||
def is_corp?
|
||||
@@ -100,13 +121,23 @@ def is_corp?
|
||||
`profiles status -type enrollment 2>/dev/null`.include?("Enrolled via DEP: Yes")
|
||||
end
|
||||
|
||||
if is_corp?
|
||||
brew "bazelisk", link: false
|
||||
end
|
||||
|
||||
# non-corp
|
||||
if !is_corp?
|
||||
brew "bazel"
|
||||
brew "bazelisk"
|
||||
brew "openssh"
|
||||
brew "virt-manager"
|
||||
|
||||
cask "claude-code"
|
||||
cask "codex"
|
||||
cask "cryptomator"
|
||||
cask "keepassxc"
|
||||
cask "gcloud-cli"
|
||||
cask "google-cloud-sdk"
|
||||
cask "keybase"
|
||||
cask "orbstack"
|
||||
cask "jordanbaird-ice@beta"
|
||||
cask "veracrypt"
|
||||
end
|
||||
|
||||
@@ -4,7 +4,12 @@ set -ueo pipefail
|
||||
shopt -s extglob
|
||||
|
||||
# get libraries
|
||||
. ${HOME}/.local/lib/bash/tui.sh
|
||||
if [[ -f "${HOME}/.local/lib/bash/tui.sh" ]]; then
|
||||
. "${HOME}/.local/lib/bash/tui.sh"
|
||||
else
|
||||
echo "Error: ${HOME}/.local/lib/bash/tui.sh not found!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
COMMANDS=(
|
||||
gctx
|
||||
@@ -43,7 +48,7 @@ _gctx_choose() {
|
||||
--format='value(is_active, name, format("{} (as {})", properties.core.project, properties.core.account))')
|
||||
local choice
|
||||
if choice=$(printf "%-${maxnamelen}s %s\n" "${lines[@]}" | select_entry "gcloud config" "$default") ; then
|
||||
_gctx_set "${choice}"
|
||||
_gctx_set "$(echo "${choice}" | awk '{print $1}')"
|
||||
else
|
||||
echo "No option selected, leaving unchanged."
|
||||
fi
|
||||
@@ -68,7 +73,7 @@ _gctx_clone() {
|
||||
local oldconfig=()
|
||||
local line
|
||||
while IFS= read -r line ; do
|
||||
old_config+=("$line")
|
||||
oldconfig+=("$line")
|
||||
done < <(gcloud config configurations describe "$(_gctx_name)" --format='multi(properties:format="flattened[separator=\" \"]")')
|
||||
|
||||
# create new
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
env > ${TMPDIR}/env-pre
|
||||
. ${HOME}/.shenv
|
||||
env > ${TMPDIR}/env-post
|
||||
for VAR in $(env | cut -d'=' -f1) ; do
|
||||
/bin/launchctl setenv "${VAR}" "$(eval echo \$${VAR})"
|
||||
done
|
||||
set -o nounset
|
||||
|
||||
TMP_DIR="${TMPDIR:-/tmp}"
|
||||
TMP_DIR="${TMP_DIR%/}"
|
||||
|
||||
env > "${TMP_DIR}/env-pre" 2>/dev/null || true
|
||||
if [ -f "${HOME}/.shenv" ]; then
|
||||
. "${HOME}/.shenv"
|
||||
fi
|
||||
env > "${TMP_DIR}/env-post" 2>/dev/null || true
|
||||
|
||||
if [ -x "/bin/launchctl" ]; then
|
||||
for VAR in $(env | awk -F= '/^[a-zA-Z_][a-zA-Z0-9_]*=/ {print $1}') ; do
|
||||
case "${VAR}" in
|
||||
_|""|*[!a-zA-Z0-9_]*|[0-9]*) continue ;;
|
||||
esac
|
||||
eval "val=\${${VAR}:-}"
|
||||
/bin/launchctl setenv "${VAR}" "${val}"
|
||||
done
|
||||
fi
|
||||
|
||||
@@ -12,8 +12,17 @@ fi
|
||||
|
||||
trap "test -f ${FILENAME} && rm -f ${FILENAME}" EXIT
|
||||
|
||||
IOENGINE="libaio"
|
||||
DIRECT=1
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
IOENGINE="posixaio"
|
||||
# macOS doesn't support O_DIRECT in the same way, but fio's direct=1
|
||||
# handles it via F_NOCACHE if supported.
|
||||
DIRECT=1
|
||||
fi
|
||||
|
||||
fio --loops=5 --size=${BENCHMARK_SIZE} --filename=${FILENAME} \
|
||||
--stonewall --ioengine=libaio --direct=1 \
|
||||
--stonewall --ioengine=${IOENGINE} --direct=${DIRECT} \
|
||||
--name=Seqread --bs=1m --rw=read \
|
||||
--name=Seqwrite --bs=1m --rw=write \
|
||||
--name=512Kread --bs=512k --rw=randread \
|
||||
|
||||
@@ -47,7 +47,7 @@ shift $((OPTIND - 1)) # Remove the parsed options
|
||||
|
||||
# --- Set target directory ---
|
||||
# Use the first remaining argument as the target directory.
|
||||
if [ -n "$1" ]; then
|
||||
if [ "$#" -gt 0 ]; then
|
||||
TARGET_DIR="$1"
|
||||
fi
|
||||
|
||||
@@ -75,7 +75,7 @@ find "${TARGET_DIR}" -type l ! -exec test -e {} \; -print0 | while IFS= read -r
|
||||
continue
|
||||
fi
|
||||
# Ask the user for confirmation.
|
||||
read -p "Remove broken symlink '${link}'? [y/N] " -n 1 -r
|
||||
read -p "Remove broken symlink '${link}'? [y/N] " -n 1 -r < /dev/tty
|
||||
echo # Move to a new line after input.
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
CHROME_BINS="google-chrome-beta google-chrome"
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
CHROME_BINS="${CHROME_BINS} /Applications/Google\ Chrome\ Beta.app/Contents/MacOS/Google\ Chrome\ Beta /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"
|
||||
fi
|
||||
|
||||
for bin in ${CHROME_BINS} ; do
|
||||
if command -v ${bin} >/dev/null 2>&1 ; then
|
||||
CHROME=$(command -v ${bin})
|
||||
@@ -18,4 +22,4 @@ export HOME=${HOME}/.chrome-pentest
|
||||
mkdir -p ${HOME}
|
||||
|
||||
# Launch chrome for burp
|
||||
exec ${CHROME} --user-data-dir=${HOME}/chrome-pentest --proxy-server=127.0.0.1:8080
|
||||
exec "${CHROME}" --user-data-dir=${HOME}/chrome-pentest --proxy-server=127.0.0.1:8080
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Installs Ansible, trying user-space methods first before falling back to sudo.
|
||||
# This script is designed to be idempotent and safe to run multiple times.
|
||||
|
||||
set -e # Exit immediately if a command exits with a non-zero status.
|
||||
set -euo pipefail # Exit immediately if a command exits with a non-zero status, undefined variable, or pipe failure.
|
||||
|
||||
# --- Helper Functions ---
|
||||
info() { echo "[INFO] $1"; }
|
||||
@@ -44,8 +44,8 @@ fi
|
||||
|
||||
# Try Python's venv module if pipx failed or wasn't present
|
||||
VENV_PATH="${HOME}/.local/share/ansible_venv"
|
||||
# Create a temp path to avoid clobbering a failed install
|
||||
VENV_TEST_PATH="/tmp/ansible_venv_test_$$"
|
||||
# Create a temp path securely to avoid clobbering a failed install
|
||||
VENV_TEST_PATH="$(mktemp -d "${TMPDIR:-/tmp}/ansible_venv_test.XXXXXX")"
|
||||
if python3 -m venv "${VENV_TEST_PATH}" >/dev/null 2>&1; then
|
||||
rm -rf "${VENV_TEST_PATH}" # Clean up test
|
||||
info "Python's venv module is available. Creating a virtual environment at ${VENV_PATH}..."
|
||||
@@ -55,7 +55,7 @@ if python3 -m venv "${VENV_TEST_PATH}" >/dev/null 2>&1; then
|
||||
info "Ansible installed successfully into a virtual environment."
|
||||
info "To use it, run: '${VENV_PATH}/bin/ansible'"
|
||||
info "To make it available everywhere, add its bin directory to your PATH:"
|
||||
info " echo 'export PATH="${VENV_PATH}/bin:$PATH"' >> ~/.profile"
|
||||
info " echo 'export PATH=\"${VENV_PATH}/bin:\$PATH\"' >> ~/.profile"
|
||||
info "(You may need to source ~/.profile or restart your shell)."
|
||||
exit 0
|
||||
else
|
||||
@@ -63,6 +63,7 @@ if python3 -m venv "${VENV_TEST_PATH}" >/dev/null 2>&1; then
|
||||
rm -rf "${VENV_PATH}" # Clean up failed attempt
|
||||
fi
|
||||
else
|
||||
rm -rf "${VENV_TEST_PATH}" # Clean up test after failure
|
||||
info "Python's venv module not available or failed to create a test environment."
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ue
|
||||
set -ueo pipefail
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
SYS_TMPDIR="${TMPDIR:-/tmp}"
|
||||
TMPDIR="$(mktemp -d "${SYS_TMPDIR%/}/install_tool.XXXXXX")"
|
||||
trap 'rm -rf -- "${TMPDIR}"' EXIT
|
||||
export -n TMPDIR 2>/dev/null || true
|
||||
|
||||
REINSTALL=0
|
||||
PACKAGES=1
|
||||
@@ -38,7 +40,7 @@ shift $((OPTIND-1))
|
||||
|
||||
function list_tools {
|
||||
echo "Options:" >/dev/stderr
|
||||
awk 'BEGIN {s=0;FS=")"};/main tool selection/{s=1};/^\s+\w+)$/{if(s==1){print $1}}' "$0" | sort | while read -r opt; do
|
||||
awk 'BEGIN {s=0;FS=")"};/main tool selection/{s=1};/^\s+[a-zA-Z0-9_.-]+)$/{if(s==1){print $1}}' "$0" | sort | while read -r opt; do
|
||||
echo -e "\\t${opt}" >/dev/stderr
|
||||
done
|
||||
}
|
||||
@@ -124,11 +126,13 @@ function get_latest_github_release_url {
|
||||
local repo="$1"
|
||||
local glob="$2"
|
||||
curl -s "https://api.github.com/repos/${repo}/releases/latest" | \
|
||||
jq -r ".assets[] | select(.name|test(\"${glob}\")) | .browser_download_url"
|
||||
jq -r --arg rx "${glob}" '.assets[] | select(.name | test($rx)) | .browser_download_url'
|
||||
}
|
||||
|
||||
function require_pipx {
|
||||
command -v pipx >/dev/null 2>&1 || die "Requires pipx"
|
||||
function require {
|
||||
local cmd="${1}"
|
||||
local msg="${2:-Requires ${cmd}}"
|
||||
command -v "${cmd}" >/dev/null 2>&1 || die "${msg}"
|
||||
}
|
||||
|
||||
# Begin main tool selection
|
||||
@@ -288,10 +292,7 @@ case ${TOOL} in
|
||||
git clone "${src}" "${DESTDIR}"
|
||||
;;
|
||||
pwndbg)
|
||||
if ! command -v gdb > /dev/null 2>&1 ; then
|
||||
echo 'No gdb available!' >/dev/stderr
|
||||
exit 1
|
||||
fi
|
||||
require gdb "No gdb available!"
|
||||
git clone --depth 1 -b stable https://github.com/pwndbg/pwndbg.git "${DESTDIR}"
|
||||
PY_PACKAGES=${DESTDIR}/vendor
|
||||
mkdir -p "${PY_PACKAGES}"
|
||||
@@ -311,10 +312,7 @@ case ${TOOL} in
|
||||
;;
|
||||
gef)
|
||||
makedest_or_die
|
||||
if ! command -v gdb > /dev/null 2>&1 ; then
|
||||
echo 'No gdb available!' >/dev/stderr
|
||||
exit 1
|
||||
fi
|
||||
require gdb "No gdb available!"
|
||||
download \
|
||||
https://github.com/hugsy/gef/raw/master/gef.py \
|
||||
"${DESTDIR}/gef.py"
|
||||
@@ -441,25 +439,19 @@ EOF
|
||||
add_bin_symlink docker-compose
|
||||
;;
|
||||
tldr)
|
||||
require_pipx
|
||||
require pipx
|
||||
pipx install tldr
|
||||
;;
|
||||
blint)
|
||||
require_pipx
|
||||
require pipx
|
||||
pipx install blint
|
||||
;;
|
||||
dust)
|
||||
if ! command -v cargo >/dev/null 2>&1 ; then
|
||||
echo "This needs cargo (for rust)!" >/dev/stderr
|
||||
exit 1
|
||||
fi
|
||||
require cargo "This needs cargo (for rust)!"
|
||||
cargo install du-dust
|
||||
;;
|
||||
bottom)
|
||||
if ! command -v cargo >/dev/null 2>&1 ; then
|
||||
echo "This needs cargo (for rust)!" >/dev/stderr
|
||||
exit 1
|
||||
fi
|
||||
require cargo "This needs cargo (for rust)!"
|
||||
cargo install bottom
|
||||
;;
|
||||
delta)
|
||||
@@ -476,7 +468,8 @@ EOF
|
||||
ropper)
|
||||
deb_only
|
||||
install_pkgs python3-z3
|
||||
pip3 install --user pyvex ropper
|
||||
require pipx
|
||||
pipx install ropper
|
||||
;;
|
||||
kubeconform)
|
||||
go install github.com/yannh/kubeconform/cmd/kubeconform@latest
|
||||
@@ -527,14 +520,11 @@ EOF
|
||||
sh "${rustup_init}" --no-modify-path -y
|
||||
;;
|
||||
igrep)
|
||||
if ! command -v cargo >/dev/null 2>&1 ; then
|
||||
echo "This needs cargo (for rust)!" >/dev/stderr
|
||||
exit 1
|
||||
fi
|
||||
require cargo "This needs cargo (for rust)!"
|
||||
cargo install igrep
|
||||
;;
|
||||
unblob)
|
||||
require_pipx
|
||||
require pipx
|
||||
pipx install unblob
|
||||
;;
|
||||
fq)
|
||||
@@ -555,6 +545,37 @@ EOF
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
speckit)
|
||||
require uv
|
||||
latest_version=$(curl -s "https://api.github.com/repos/github/spec-kit/releases/latest" | jq -r '.tag_name')
|
||||
if [ -z "${latest_version}" ] || [ "${latest_version}" = "null" ]; then
|
||||
die "Failed to determine latest release version for speckit."
|
||||
fi
|
||||
uv tool install specify-cli --from "git+https://github.com/github/spec-kit.git@${latest_version}"
|
||||
;;
|
||||
ssh-agent-mux)
|
||||
makedest_or_die
|
||||
os=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
case "$(uname -m)" in
|
||||
x86_64|amd64)
|
||||
arch="amd64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
arch="arm64"
|
||||
;;
|
||||
*)
|
||||
die "Unsupported architecture: $(uname -m)"
|
||||
;;
|
||||
esac
|
||||
tar_url=$(get_latest_github_release_url "overhacked/ssh-agent-mux" ".*${os}-${arch}\\.tar\\.gz$")
|
||||
if [ -z "${tar_url}" ]; then
|
||||
die "Could not find ssh-agent-mux release for ${os}-${arch}"
|
||||
fi
|
||||
download "${tar_url}" "${TMPDIR}/ssh-agent-mux.tar.gz"
|
||||
tar zxf "${TMPDIR}/ssh-agent-mux.tar.gz" --strip-components=1 -C "${DESTDIR}"
|
||||
chmod +x "${DESTDIR}/ssh-agent-mux"
|
||||
add_bin_symlink ssh-agent-mux
|
||||
;;
|
||||
*)
|
||||
echo "Unknown tool: ${TOOL}" >/dev/stderr
|
||||
list_tools
|
||||
|
||||
@@ -2,12 +2,20 @@
|
||||
|
||||
set -ue
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Error: This script must be run as root." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat >/usr/local/bin/x-resize <<"EOF"
|
||||
#!/bin/sh
|
||||
PATH=/usr/bin:/bin:/usr/local/bin
|
||||
desktopuser=$(/bin/ps -ef | /bin/grep -oP '^\w+ (?=.*vdagent( |$))') || exit 0
|
||||
desktopuser=$(/bin/ps -eo user,comm 2>/dev/null | awk '$2 ~ /vdagent/ {print $1; exit}')
|
||||
[ -z "$desktopuser" ] && exit 0
|
||||
desktophome=$(getent passwd "$desktopuser" | cut -d: -f6)
|
||||
[ -z "$desktophome" ] && exit 0
|
||||
export DISPLAY=:0
|
||||
export XAUTHORITY=$(eval echo "~$desktopuser")/.Xauthority
|
||||
export XAUTHORITY="${desktophome}/.Xauthority"
|
||||
/usr/bin/xrandr --output $(/usr/bin/xrandr | awk '/ connected/{print $1; exit; }') --auto
|
||||
EOF
|
||||
chmod 755 /usr/local/bin/x-resize
|
||||
@@ -251,7 +251,13 @@ def main(args):
|
||||
if last_type and e.pkg_type != last_type:
|
||||
output_lines.append("")
|
||||
last_type = e.pkg_type
|
||||
output_lines.extend(e.to_lines())
|
||||
|
||||
lines = e.to_lines()
|
||||
# If we just added a blank line, and the new lines start with one, skip the first new line
|
||||
if output_lines and output_lines[-1] == "" and lines and lines[0] == "":
|
||||
output_lines.extend(lines[1:])
|
||||
else:
|
||||
output_lines.extend(lines)
|
||||
|
||||
new_content = "\n".join(output_lines)
|
||||
if footer:
|
||||
|
||||
213
bin/newnote
Executable file
213
bin/newnote
Executable file
@@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Exit on error, undefined variables, and pipe failures
|
||||
set -euo pipefail
|
||||
|
||||
show_help() {
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") [options] <note_name_or_path>
|
||||
|
||||
Create a new note in your Obsidian vault.
|
||||
|
||||
Options:
|
||||
-v, --vault <dir> Specify the Obsidian vault directory.
|
||||
--overwrite Overwrite the file if it already exists.
|
||||
-h, --help Show this help message.
|
||||
EOF
|
||||
}
|
||||
|
||||
VAULT_DIR=""
|
||||
OVERWRITE="false"
|
||||
NOTE_PATH=""
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-v|--vault)
|
||||
if [[ -z "${2:-}" ]]; then
|
||||
echo "Error: --vault requires a directory path." >&2
|
||||
exit 1
|
||||
fi
|
||||
VAULT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
--overwrite)
|
||||
OVERWRITE="true"
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
echo "Error: Unknown option: $1" >&2
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [[ -n "$NOTE_PATH" ]]; then
|
||||
echo "Error: Multiple note paths provided: $NOTE_PATH and $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
NOTE_PATH="$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$NOTE_PATH" ]]; then
|
||||
echo "Error: Missing note path/name." >&2
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 1. Find the Obsidian vault.
|
||||
if [[ -n "$VAULT_DIR" ]]; then
|
||||
# -v/--vault was passed. Check that the directory exists and contains a .obsidian directory.
|
||||
if [[ ! -d "$VAULT_DIR" ]]; then
|
||||
echo "Error: Specified vault directory does not exist: $VAULT_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -d "$VAULT_DIR/.obsidian" ]]; then
|
||||
echo "Error: Specified directory is not an Obsidian vault (missing .obsidian): $VAULT_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
VAULT_DIR="$(cd "$VAULT_DIR" && pwd)"
|
||||
else
|
||||
# Search directories upward for a parent (or current) directory containing a .obsidian subdirectory.
|
||||
# Stop at the user's home directory or a filesystem boundary.
|
||||
CURRENT_DIR="$PWD"
|
||||
FOUND_VAULT=""
|
||||
|
||||
get_device_id() {
|
||||
local dir="$1"
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
stat -f '%d' "$dir" 2>/dev/null || echo ""
|
||||
else
|
||||
stat -c '%d' "$dir" 2>/dev/null || echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
CURRENT_DEV="$(get_device_id "$CURRENT_DIR")"
|
||||
|
||||
while [[ "$CURRENT_DIR" != "/" && "$CURRENT_DIR" != "$HOME" ]]; do
|
||||
if [[ -d "$CURRENT_DIR/.obsidian" ]]; then
|
||||
FOUND_VAULT="$CURRENT_DIR"
|
||||
break
|
||||
fi
|
||||
|
||||
PARENT_DIR="$(dirname "$CURRENT_DIR")"
|
||||
if [[ "$PARENT_DIR" == "$CURRENT_DIR" ]]; then
|
||||
break
|
||||
fi
|
||||
|
||||
# Check filesystem boundary
|
||||
PARENT_DEV="$(get_device_id "$PARENT_DIR")"
|
||||
if [[ -n "$CURRENT_DEV" && -n "$PARENT_DEV" && "$CURRENT_DEV" != "$PARENT_DEV" ]]; then
|
||||
break
|
||||
fi
|
||||
|
||||
CURRENT_DIR="$PARENT_DIR"
|
||||
CURRENT_DEV="$PARENT_DEV"
|
||||
done
|
||||
|
||||
# Check the last checked directory (could be HOME or /)
|
||||
if [[ -z "$FOUND_VAULT" && -d "$CURRENT_DIR/.obsidian" ]]; then
|
||||
FOUND_VAULT="$CURRENT_DIR"
|
||||
fi
|
||||
|
||||
if [[ -n "$FOUND_VAULT" ]]; then
|
||||
VAULT_DIR="$FOUND_VAULT"
|
||||
else
|
||||
# Fallback paths in order: ~/Notes, ~/Obsidian/Notes, ~/Personal/Notes, ~/Projects/Notes.
|
||||
FALLBACKS=(
|
||||
"$HOME/Notes"
|
||||
"$HOME/notes"
|
||||
"$HOME/Obsidian/Notes"
|
||||
"$HOME/Obsidian/notes"
|
||||
"$HOME/Personal/Notes"
|
||||
"$HOME/Personal/notes"
|
||||
"$HOME/Projects/Notes"
|
||||
"$HOME/Projects/notes"
|
||||
)
|
||||
for path in "${FALLBACKS[@]}"; do
|
||||
if [[ -d "$path" && -d "$path/.obsidian" ]]; then
|
||||
VAULT_DIR="$(cd "$path" && pwd)"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "$VAULT_DIR" ]]; then
|
||||
echo "Error: Could not find an Obsidian vault. Please specify one with -v/--vault." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Strip leading slash from NOTE_PATH to handle relative paths properly
|
||||
NOTE_PATH="${NOTE_PATH#/}"
|
||||
|
||||
# 2. Determine if current working directory is within the vault.
|
||||
# Resolve physical paths to handle symlinks cleanly.
|
||||
RESOLVED_PWD="$(pwd -P)"
|
||||
RESOLVED_VAULT="$(cd "$VAULT_DIR" && pwd -P)"
|
||||
|
||||
if [[ "$RESOLVED_PWD" == "$RESOLVED_VAULT" || "$RESOLVED_PWD" == "$RESOLVED_VAULT"/* ]]; then
|
||||
# Within the vault, treat relative to CWD
|
||||
TARGET_FILE="$PWD/$NOTE_PATH"
|
||||
else
|
||||
# Not within the vault, treat relative to vault root
|
||||
TARGET_FILE="$VAULT_DIR/$NOTE_PATH"
|
||||
fi
|
||||
|
||||
TARGET_DIR="$(dirname "$TARGET_FILE")"
|
||||
TARGET_BASE="$(basename "$TARGET_FILE")"
|
||||
|
||||
# If there's no file extension on the argument, add .md.
|
||||
if [[ "$TARGET_BASE" != *.* ]]; then
|
||||
TARGET_BASE="$TARGET_BASE.md"
|
||||
fi
|
||||
|
||||
TARGET_FILE="$TARGET_DIR/$TARGET_BASE"
|
||||
|
||||
# If the necessary directory components don't exist, create them.
|
||||
if [[ ! -d "$TARGET_DIR" ]]; then
|
||||
mkdir -p "$TARGET_DIR"
|
||||
fi
|
||||
|
||||
# 3. If the file exists and there's no --overwrite argument, throw an error.
|
||||
if [[ -f "$TARGET_FILE" && "$OVERWRITE" != "true" ]]; then
|
||||
echo "Error: File already exists: $TARGET_FILE (use --overwrite to replace it)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 4. If the path ends in .md (case-insensitive), generate appropriate YAML front matter and write it to the new file.
|
||||
if [[ "$TARGET_BASE" =~ \.[mM][dD]$ ]]; then
|
||||
NOTE_TITLE="${TARGET_BASE%.*}"
|
||||
NOTE_TITLE_ESCAPED="${NOTE_TITLE//\"/\\\"}"
|
||||
CURRENT_DATE="$(date +"%Y-%m-%d %H:%M")"
|
||||
|
||||
cat << EOF > "$TARGET_FILE"
|
||||
---
|
||||
title: "$NOTE_TITLE_ESCAPED"
|
||||
date: $CURRENT_DATE
|
||||
tags: []
|
||||
---
|
||||
|
||||
EOF
|
||||
else
|
||||
# Just touch the file to ensure it exists
|
||||
touch "$TARGET_FILE"
|
||||
fi
|
||||
|
||||
# 5. Open the user's $EDITOR (falling back to vim/vi if unset) pointing to the new file.
|
||||
EDITOR="${EDITOR:-}"
|
||||
if [[ -z "$EDITOR" ]]; then
|
||||
if command -v vim >/dev/null 2>&1; then
|
||||
EDITOR="vim"
|
||||
else
|
||||
EDITOR="vi"
|
||||
fi
|
||||
fi
|
||||
|
||||
exec "$EDITOR" "$TARGET_FILE"
|
||||
63
bin/quartz
Executable file
63
bin/quartz
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# QUARTZ_DIR search logic
|
||||
if [ -z "${QUARTZ_DIR:-}" ]; then
|
||||
if [ -f "quartz.config.ts" ]; then
|
||||
QUARTZ_DIR="$PWD"
|
||||
elif [ -d "$HOME/Personal/notes-quartz" ]; then
|
||||
QUARTZ_DIR="$HOME/Personal/notes-quartz"
|
||||
elif [ -d "$HOME/Projects/notes-quartz" ]; then
|
||||
QUARTZ_DIR="$HOME/Projects/notes-quartz"
|
||||
else
|
||||
echo "Error: QUARTZ_DIR could not be found." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -d "$QUARTZ_DIR" ]; then
|
||||
echo "Error: QUARTZ_DIR '$QUARTZ_DIR' is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# NOTES_DIR search logic
|
||||
PARSE_NOTES_DIR=""
|
||||
# Use a copy of args to find -d/--directory
|
||||
ARGS=("$@")
|
||||
for ((i=0; i<${#ARGS[@]}; i++)); do
|
||||
if [[ "${ARGS[i]}" == "-d" || "${ARGS[i]}" == "--directory" ]]; then
|
||||
if [[ $((i+1)) -lt ${#ARGS[@]} ]]; then
|
||||
PARSE_NOTES_DIR="${ARGS[i+1]}"
|
||||
fi
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$PARSE_NOTES_DIR" ]; then
|
||||
NOTES_DIR="$PARSE_NOTES_DIR"
|
||||
elif [ -z "${NOTES_DIR:-}" ]; then
|
||||
if [ -d "$HOME/Notes" ]; then
|
||||
NOTES_DIR="$HOME/Notes"
|
||||
elif [ -d "$HOME/Personal/notes" ]; then
|
||||
NOTES_DIR="$HOME/Personal/notes"
|
||||
elif [ -d "$HOME/Projects/notes" ]; then
|
||||
NOTES_DIR="$HOME/Projects/notes"
|
||||
else
|
||||
echo "Error: NOTES_DIR could not be found." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -d "$NOTES_DIR" ]; then
|
||||
echo "Error: NOTES_DIR '$NOTES_DIR' is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$QUARTZ_DIR"
|
||||
|
||||
# Run npx quartz
|
||||
# Following the prompt's structure but using NOTES_DIR for the flag
|
||||
# npx quartz ${argv[1]} --directory ${NOTES_DIR} "$@"
|
||||
# We use ${1:-} for argv[1] to handle cases with no arguments.
|
||||
npx quartz "${1:-}" --directory "$NOTES_DIR" "$@"
|
||||
@@ -18,7 +18,7 @@ HOST_SPECIFIC_SCRIPT="${RESTIC_SCRIPTS_DIR}/${HOSTNAME}"
|
||||
# Check if the script exists and is executable
|
||||
if [[ -f "${HOST_SPECIFIC_SCRIPT}" && -x "${HOST_SPECIFIC_SCRIPT}" ]]; then
|
||||
echo "Executing restic script for hostname: ${HOSTNAME}"
|
||||
"${HOST_SPECIFIC_SCRIPT}"
|
||||
"${HOST_SPECIFIC_SCRIPT}" "$@"
|
||||
else
|
||||
echo "Error: No executable restic script found for hostname '${HOSTNAME}' at '${HOST_SPECIFIC_SCRIPT}'." >&2
|
||||
echo "Please create an executable script at that path if you want to use this functionality." >&2
|
||||
|
||||
@@ -12,8 +12,8 @@ set -o pipefail
|
||||
# For this script, we assume the user's home directory.
|
||||
SOURCE_DIR="${HOME}"
|
||||
|
||||
# Exclude file location. We'll create a default one next to the script.
|
||||
EXCLUDE_FILE="$HOME/.restic_exclude.darwin"
|
||||
# Exclude file location.
|
||||
EXCLUDE_FILE="${HOME}/.restic_exclude.darwin"
|
||||
|
||||
# --- Functions ---
|
||||
usage() {
|
||||
@@ -34,7 +34,7 @@ EOF
|
||||
|
||||
# --- Main Script ---
|
||||
# Check if restic is installed
|
||||
if ! command -v restic &> /dev/null; then
|
||||
if ! command -v restic >/dev/null 2>&1; then
|
||||
echo "Error: restic command not found." >&2
|
||||
echo "Please install restic first: https://restic.net/" >&2
|
||||
exit 1
|
||||
@@ -57,7 +57,7 @@ while getopts ":l:bu:h" opt; do
|
||||
;;
|
||||
b)
|
||||
BACKUP_MODE="b2"
|
||||
if [[ ${OPTIND} -le $# && "${!OPTIND}" != -* ]]; then
|
||||
if [[ ${OPTIND} -le $# && "${!OPTIND:-}" != -* ]]; then
|
||||
REPO="b2:${!OPTIND}:"
|
||||
OPTIND=$((OPTIND + 1))
|
||||
fi
|
||||
@@ -91,18 +91,19 @@ fi
|
||||
|
||||
if [[ "${BACKUP_MODE}" == "b2" ]]; then
|
||||
if [[ -f "${HOME}/.resticb2" ]] ; then
|
||||
# shellcheck disable=SC1090
|
||||
. "${HOME}/.resticb2"
|
||||
fi
|
||||
export B2_ACCOUNT_ID
|
||||
export B2_ACCOUNT_KEY
|
||||
export B2_BUCKET_NAME
|
||||
if [[ -z "${B2_ACCOUNT_ID:-}" || -z "${B2_ACCOUNT_KEY:-}" ]]; then
|
||||
export B2_ACCOUNT_ID="${B2_ACCOUNT_ID:-}"
|
||||
export B2_ACCOUNT_KEY="${B2_ACCOUNT_KEY:-}"
|
||||
export B2_BUCKET_NAME="${B2_BUCKET_NAME:-}"
|
||||
if [[ -z "${B2_ACCOUNT_ID}" || -z "${B2_ACCOUNT_KEY}" ]]; then
|
||||
echo "Error: For Backblaze B2 backups, you must set the B2_ACCOUNT_ID and B2_ACCOUNT_KEY environment variables." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${REPO:-}" ]]; then
|
||||
if [[ -n "${B2_BUCKET_NAME:-}" ]]; then
|
||||
if [[ -z "${REPO}" ]]; then
|
||||
if [[ -n "${B2_BUCKET_NAME}" ]]; then
|
||||
REPO="b2:${B2_BUCKET_NAME}:"
|
||||
else
|
||||
echo "Error: Backup mode is B2 but no bucket name was provided and the B2_BUCKET_NAME environment variable is not set." >&2
|
||||
@@ -113,41 +114,56 @@ if [[ "${BACKUP_MODE}" == "b2" ]]; then
|
||||
fi
|
||||
|
||||
KEYCHAIN_ENTRY_NAME="restic_repo_password"
|
||||
if security find-generic-password -a "$(whoami)" -s "${KEYCHAIN_ENTRY_NAME}" >/dev/null 2>&1 ; then
|
||||
export RESTIC_PASSWORD_COMMAND="security find-generic-password -a \"$(whoami)\" -s \"${KEYCHAIN_ENTRY_NAME}\" -w"
|
||||
local_user="$(id -un 2>/dev/null || whoami)"
|
||||
if security find-generic-password -a "${local_user}" -s "${KEYCHAIN_ENTRY_NAME}" >/dev/null 2>&1 ; then
|
||||
printf -v RESTIC_PASSWORD_COMMAND 'security find-generic-password -a %q -s %q -w' "${local_user}" "${KEYCHAIN_ENTRY_NAME}"
|
||||
export RESTIC_PASSWORD_COMMAND
|
||||
# Source file?
|
||||
elif [[ -f "${HOME}/.resticpass" ]] ; then
|
||||
export RESTIC_PASSWORD_FILE="${HOME}/.resticpass"
|
||||
fi
|
||||
|
||||
# Ensure exclude file exists so restic does not fail when checking exclusions.
|
||||
if [[ ! -f "${EXCLUDE_FILE}" ]]; then
|
||||
echo "Exclude file '${EXCLUDE_FILE}' not found. Creating a default macOS exclude file..."
|
||||
cat << 'EOF' > "${EXCLUDE_FILE}"
|
||||
# Default restic exclusions for macOS
|
||||
.Trash
|
||||
Library/Caches
|
||||
Library/Logs
|
||||
.CFUserTextEncoding
|
||||
EOF
|
||||
fi
|
||||
|
||||
# If the repository does not exist, initialize it.
|
||||
# The user will be prompted for a password, which will be required for all
|
||||
# future interactions with the repository.
|
||||
if ! restic -r "${REPO}" snapshots &> /dev/null; then
|
||||
if ! restic -r "${REPO}" snapshots >/dev/null 2>&1; then
|
||||
echo "Restic repository not found or not accessible. Initializing..."
|
||||
restic init -r "${REPO}"
|
||||
fi
|
||||
|
||||
|
||||
# --- Run Backup ---
|
||||
echo "Starting restic backup..."
|
||||
echo "Source: ${SOURCE_DIR}"
|
||||
echo "Repository: ${REPO}"
|
||||
|
||||
BACKUP_CMD="restic backup \
|
||||
--verbose \
|
||||
--repo \"${REPO}\" \
|
||||
--exclude-file \"${EXCLUDE_FILE}\" \
|
||||
--one-file-system \
|
||||
--tag \"macbook-backup\""
|
||||
BACKUP_ARGS=(
|
||||
"restic" "backup"
|
||||
"--verbose"
|
||||
"--repo" "${REPO}"
|
||||
"--exclude-file" "${EXCLUDE_FILE}"
|
||||
"--one-file-system"
|
||||
"--tag" "macbook-backup"
|
||||
)
|
||||
|
||||
if [[ -n "${UPLOAD_LIMIT}" ]]; then
|
||||
BACKUP_CMD="${BACKUP_CMD} --limit-upload ${UPLOAD_LIMIT}"
|
||||
BACKUP_ARGS+=("--limit-upload" "${UPLOAD_LIMIT}")
|
||||
fi
|
||||
|
||||
BACKUP_CMD="${BACKUP_CMD} \"${SOURCE_DIR}\""
|
||||
BACKUP_ARGS+=("${SOURCE_DIR}")
|
||||
|
||||
eval "${BACKUP_CMD}"
|
||||
"${BACKUP_ARGS[@]}"
|
||||
|
||||
echo "Backup complete."
|
||||
|
||||
|
||||
@@ -5,8 +5,14 @@
|
||||
set -ue
|
||||
|
||||
TOOLS="flameshot scrot"
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
TOOLS="screencapture ${TOOLS}"
|
||||
fi
|
||||
|
||||
SCREENDIR=${SCREENDIR:-${HOME}/Pictures/Screenshots}
|
||||
SCROT_FORMAT="%F-%T.png"
|
||||
# Filename for screencapture
|
||||
FILE_NAME=$(date "+%Y-%m-%d-%H%M%S.png")
|
||||
|
||||
function default_screenshot_command {
|
||||
for tool in ${TOOLS} ; do
|
||||
@@ -41,10 +47,29 @@ function scrot_full_capture {
|
||||
scrot "${SCREENDIR}/${SCROT_FORMAT}"
|
||||
}
|
||||
|
||||
function mac_capture {
|
||||
local mode="${1}"
|
||||
local target="${SCREENDIR}/${FILE_NAME}"
|
||||
case "${mode}" in
|
||||
region)
|
||||
screencapture -i "${target}"
|
||||
;;
|
||||
window)
|
||||
screencapture -i -w "${target}"
|
||||
;;
|
||||
full)
|
||||
screencapture "${target}"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "${CMD}" in
|
||||
region|window|full)
|
||||
mkdir -p "${SCREENDIR}"
|
||||
case "${TOOL}" in
|
||||
screencapture)
|
||||
mac_capture "${CMD}"
|
||||
;;
|
||||
flameshot)
|
||||
case "${CMD}" in
|
||||
region|window)
|
||||
|
||||
60
bin/ssh-sign
60
bin/ssh-sign
@@ -72,15 +72,51 @@ shift # Consume the subcommand
|
||||
# Separate arguments from the file to be signed
|
||||
declare -a remaining_args
|
||||
file_to_sign=""
|
||||
f_provided=false
|
||||
n_provided=false
|
||||
I_provided=false
|
||||
s_provided=false
|
||||
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
# If we see a non-flag argument, assume it's the file to sign.
|
||||
# This works because the file to sign is the only positional argument.
|
||||
if [[ "$1" != -* ]] && [[ -z "$file_to_sign" ]]; then
|
||||
file_to_sign="$1"
|
||||
else
|
||||
remaining_args+=("$1")
|
||||
case "$1" in
|
||||
-f)
|
||||
[[ -z "${2:-}" ]] && error "Option -f requires an argument."
|
||||
remaining_args+=("-f" "$2")
|
||||
f_provided=true
|
||||
shift 2
|
||||
;;
|
||||
-n)
|
||||
[[ -z "${2:-}" ]] && error "Option -n requires an argument."
|
||||
remaining_args+=("-n" "$2")
|
||||
n_provided=true
|
||||
shift 2
|
||||
;;
|
||||
-I)
|
||||
[[ -z "${2:-}" ]] && error "Option -I requires an argument."
|
||||
remaining_args+=("-I" "$2")
|
||||
I_provided=true
|
||||
shift 2
|
||||
;;
|
||||
-s)
|
||||
[[ -z "${2:-}" ]] && error "Option -s requires an argument."
|
||||
remaining_args+=("-s" "$2")
|
||||
s_provided=true
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
-*)
|
||||
error "Unknown option: $1"
|
||||
;;
|
||||
*)
|
||||
if [[ -n "$file_to_sign" ]]; then
|
||||
error "Unexpected positional argument '$1' (already specified '$file_to_sign')."
|
||||
fi
|
||||
file_to_sign="$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# --- Build command based on subcommand ---
|
||||
@@ -90,18 +126,6 @@ CMD_ARGS=("ssh-keygen" "-Y" "$SUBCOMMAND")
|
||||
# Append all the flag-based arguments (-f, -n, -I, -s)
|
||||
CMD_ARGS+=("${remaining_args[@]}")
|
||||
|
||||
# Scan for provided flags to handle defaults correctly
|
||||
f_provided=false
|
||||
n_provided=false
|
||||
I_provided=false
|
||||
s_provided=false
|
||||
for arg in "${remaining_args[@]}"; do
|
||||
[[ "$arg" == "-f" ]] && f_provided=true
|
||||
[[ "$arg" == "-n" ]] && n_provided=true
|
||||
[[ "$arg" == "-I" ]] && I_provided=true
|
||||
[[ "$arg" == "-s" ]] && s_provided=true
|
||||
done
|
||||
|
||||
if [[ "$SUBCOMMAND" == "sign" ]]; then
|
||||
if [[ -z "$file_to_sign" ]]; then
|
||||
error "Path to file to be signed is required for 'sign' command."
|
||||
|
||||
365
bin/update-authorized-keys
Executable file
365
bin/update-authorized-keys
Executable file
@@ -0,0 +1,365 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# update-authorized-keys - Manage ~/.ssh/authorized_keys from multiple sources
|
||||
#
|
||||
# BEHAVIOR:
|
||||
# 1. Collects SSH public keys from one or more source directories (default: ~/.ssh/authorized_keys.d).
|
||||
# 2. Skips empty files and files symlinked to /dev/null (masking).
|
||||
# 3. Deterministically concatenates keys into a "managed block" wrapped in markers:
|
||||
# # BEGIN UPDATE-AUTHORIZED-KEYS
|
||||
# # END UPDATE-AUTHORIZED-KEYS
|
||||
# 4. Deduplicates managed keys: if the same key (including options) is found in multiple files,
|
||||
# it is included once with a comment listing all source filenames.
|
||||
# 5. Preserves "manual" keys found in the target file outside the markers.
|
||||
# 6. Removes manual keys that exactly match a managed key (options + key data).
|
||||
# 7. Validates every proposed key individually using 'ssh-keygen -l -f'.
|
||||
# 8. Optionally validates the whole file with 'authorized-keys-test' if available.
|
||||
# 9. Displays a unified diff and prompts for confirmation before atomic replacement.
|
||||
# 10. Supports a --dry-run mode and a --self-test mode for verifying logic.
|
||||
|
||||
set -o nounset
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
CLEANUP_FILES=()
|
||||
cleanup() {
|
||||
rm -rf "${CLEANUP_FILES[@]}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# Configuration
|
||||
DEFAULT_DIR="${HOME}/.ssh/authorized_keys.d"
|
||||
DEFAULT_TARGET="${HOME}/.ssh/authorized_keys"
|
||||
BEGIN_MARKER="# BEGIN UPDATE-AUTHORIZED-KEYS"
|
||||
END_MARKER="# END UPDATE-AUTHORIZED-KEYS"
|
||||
|
||||
# State
|
||||
SOURCE_DIRS=()
|
||||
TARGET_FILE="${DEFAULT_TARGET}"
|
||||
DRY_RUN=0
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [options]
|
||||
|
||||
Options:
|
||||
--dir DIR Primary directory for managed keys (default: ${DEFAULT_DIR})
|
||||
--extra-dir DIR Additional directory to scan for keys (can be repeated)
|
||||
--target FILE Target authorized_keys file (default: ${DEFAULT_TARGET})
|
||||
--dry-run Show changes and validate without modifying the target
|
||||
--self-test Run internal suite of tests to verify script logic
|
||||
--help Show this help message
|
||||
EOF
|
||||
}
|
||||
|
||||
run_self_test() {
|
||||
echo "Running self-test..."
|
||||
local test_root=$(mktemp -d)
|
||||
CLEANUP_FILES+=("${test_root}")
|
||||
|
||||
local d1="${test_root}/d1"
|
||||
local d2="${test_root}/d2"
|
||||
local target="${test_root}/target"
|
||||
mkdir -p "${d1}" "${d2}"
|
||||
|
||||
local key1="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ8XoR7N7X5XoR7N7X5XoR7N7X5XoR7N7X5XoR7N7X5X key1"
|
||||
local key2="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL9YpS8O8Y6YpS8O8Y6YpS8O8Y6YpS8O8Y6YpS8O8Y6Y key2"
|
||||
local key_man="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM0ZqT9P9Z7ZqT9P9Z7ZqT9P9Z7ZqT9P9Z7ZqT9P9Z7Z manual"
|
||||
local long_opt="environment=\"VAR=VERY_LONG_VALUE_THAT_EXCEEDS_TWENTY_CHARS\""
|
||||
|
||||
echo "${key1}" > "${d1}/k1"
|
||||
echo "${key1}" > "${d2}/k1_dup"
|
||||
echo "${key2}" > "${d2}/k2"
|
||||
echo "${long_opt} ${key1}" > "${d1}/k1_long"
|
||||
echo "${long_opt} ${key2}" > "${d1}/k2_long"
|
||||
ln -s /dev/null "${d1}/masked"
|
||||
|
||||
cat <<EOF > "${target}"
|
||||
${key_man}
|
||||
# This is a manual annotation for key1
|
||||
${key1}
|
||||
EOF
|
||||
|
||||
echo "Executing script in test mode..."
|
||||
# Pipe "y" to handle the TTY check if we are not in a TTY during test
|
||||
echo "y" | "$0" --dir "${d1}" --extra-dir "${d2}" --target "${target}" > /dev/null
|
||||
|
||||
local content=$(cat "${target}")
|
||||
|
||||
echo -n "Check markers... "
|
||||
if [[ "${content}" == *"${BEGIN_MARKER}"* && "${content}" == *"${END_MARKER}"* ]]; then echo "OK"; else echo "FAIL"; exit 1; fi
|
||||
|
||||
echo -n "Check managed deduplication... "
|
||||
if grep -q "Source: k1, k1_dup" "${target}"; then echo "OK"; else echo "FAIL"; exit 1; fi
|
||||
|
||||
echo -n "Check long option deduplication (should NOT deduplicate different keys)... "
|
||||
if grep -q "k1_long" "${target}" && grep -q "k2_long" "${target}"; then echo "OK"; else echo "FAIL"; exit 1; fi
|
||||
|
||||
echo -n "Check manual key preservation... "
|
||||
if grep -q "manual" "${target}"; then echo "OK"; else echo "FAIL"; exit 1; fi
|
||||
|
||||
echo -n "Check manual key filtering... "
|
||||
local manual_count=$(grep -c "${key1}" "${target}")
|
||||
# key1 appears twice in managed block (once plain, once with long opt)
|
||||
# and it was in manual block. The manual one should be removed.
|
||||
# So we expect 2 occurrences in the final file (both in managed block).
|
||||
if [[ ${manual_count} -eq 2 ]]; then echo "OK"; else echo "FAIL (Found ${manual_count} occurrences, expected 2)"; exit 1; fi
|
||||
|
||||
echo -n "Check masking... "
|
||||
if ! grep -q "masked" "${target}"; then echo "OK"; else echo "FAIL"; exit 1; fi
|
||||
|
||||
echo -n "Check user comment preservation... "
|
||||
if grep -q "This is a manual annotation for key1" "${target}"; then echo "OK"; else echo "FAIL"; exit 1; fi
|
||||
|
||||
echo "Self-test passed successfully!"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dir)
|
||||
[[ -z "${2:-}" ]] && { echo "Error: --dir requires an argument" >&2; exit 1; }
|
||||
SOURCE_DIRS+=("$2"); shift 2 ;;
|
||||
--extra-dir)
|
||||
[[ -z "${2:-}" ]] && { echo "Error: --extra-dir requires an argument" >&2; exit 1; }
|
||||
SOURCE_DIRS+=("$2"); shift 2 ;;
|
||||
--target)
|
||||
[[ -z "${2:-}" ]] && { echo "Error: --target requires an argument" >&2; exit 1; }
|
||||
TARGET_FILE="$2"; shift 2 ;;
|
||||
--dry-run) DRY_RUN=1; shift ;;
|
||||
--self-test) run_self_test ;;
|
||||
--help) usage; exit 0 ;;
|
||||
*) echo "Unknown option: $1" >&2; usage; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ${#SOURCE_DIRS[@]} -eq 0 ]]; then
|
||||
SOURCE_DIRS+=("${DEFAULT_DIR}")
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "${TARGET_FILE}")"
|
||||
TMP_FILE=$(mktemp)
|
||||
CLEANUP_FILES+=("${TMP_FILE}")
|
||||
|
||||
# Build a map of key-signature -> user comments from the existing target file.
|
||||
# Comments above keys are preserved into the managed block (# Source: lines are excluded).
|
||||
# Multiple comment lines are joined with SUBSEP (\034) for safe transport through AWK.
|
||||
USER_COMMENTS_FILE=$(mktemp)
|
||||
CLEANUP_FILES+=("${USER_COMMENTS_FILE}")
|
||||
if [[ -f "${TARGET_FILE}" ]]; then
|
||||
awk -v begin="${BEGIN_MARKER}" -v end="${END_MARKER}" '
|
||||
BEGIN { pending="" }
|
||||
$0 == begin { pending=""; next }
|
||||
$0 == end { pending=""; next }
|
||||
/^# Source:/ { next }
|
||||
/^[[:space:]]*#/ {
|
||||
pending = (pending == "" ? $0 : pending SUBSEP $0)
|
||||
next
|
||||
}
|
||||
/^[[:space:]]*$/ { pending=""; next }
|
||||
{
|
||||
n = split($0, parts, " ")
|
||||
sig = ""
|
||||
for (i=1; i<=n; i++) {
|
||||
sig = (sig == "" ? parts[i] : sig " " parts[i])
|
||||
if (parts[i] ~ /^(ssh-|ecdsa-|sk-)/ && i < n) {
|
||||
sig = sig " " parts[i+1]
|
||||
break
|
||||
}
|
||||
}
|
||||
if (sig != "" && pending != "") {
|
||||
print sig "\t" pending
|
||||
}
|
||||
pending = ""
|
||||
}
|
||||
' "${TARGET_FILE}" > "${USER_COMMENTS_FILE}"
|
||||
fi
|
||||
|
||||
collect_keys() {
|
||||
local dirs=("${@}")
|
||||
for dir in "${dirs[@]}"; do
|
||||
if [[ ! -d "${dir}" ]]; then continue; fi
|
||||
# Use a glob to avoid parsing ls
|
||||
for file in "${dir}"/*; do
|
||||
[[ ! -e "${file}" ]] && continue
|
||||
[[ ! -f "${file}" || ! -s "${file}" ]] && continue
|
||||
if [[ -L "${file}" && "$(readlink "${file}")" == "/dev/null" ]]; then continue; fi
|
||||
while read -r line; do
|
||||
[[ -z "${line}" || "${line}" =~ ^[[:space:]]*# ]] && continue
|
||||
# Use a specific delimiter that is unlikely to be in the key or filename
|
||||
# If using tabs, ensure we only split on the first one in AWK
|
||||
printf "%s\t%s\n" "$(basename "${file}")" "${line}"
|
||||
done < "${file}"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# Use a HEREDOC for the complex AWK script to avoid shell interpolation issues
|
||||
MANAGED_BLOCK=$(collect_keys "${SOURCE_DIRS[@]}" | awk -F'\t' -v user_comments_file="${USER_COMMENTS_FILE}" '
|
||||
BEGIN {
|
||||
while ((getline line < user_comments_file) > 0) {
|
||||
tab = index(line, "\t")
|
||||
if (tab > 0) {
|
||||
sig = substr(line, 1, tab - 1)
|
||||
user_comments[sig] = substr(line, tab + 1)
|
||||
}
|
||||
}
|
||||
close(user_comments_file)
|
||||
}
|
||||
{
|
||||
# Splitting on the first tab manually to be robust
|
||||
tab_idx = index($0, "\t")
|
||||
source = substr($0, 1, tab_idx - 1)
|
||||
full_line = substr($0, tab_idx + 1)
|
||||
|
||||
# Signature detection: all options + key type + key data
|
||||
# (Excludes the comment at the end)
|
||||
n = split(full_line, parts, " ")
|
||||
sig = ""
|
||||
for (i=1; i<=n; i++) {
|
||||
sig = (sig == "" ? parts[i] : sig " " parts[i])
|
||||
# A key line is [options] <type> <base64> [comment]
|
||||
# We stop after the base64 part. Key types start with known prefixes.
|
||||
if (parts[i] ~ /^(ssh-|ecdsa-|sk-)/ && i < n) {
|
||||
sig = sig " " parts[i+1]
|
||||
break
|
||||
}
|
||||
}
|
||||
# Fallback if no key type found (should not happen with valid keys)
|
||||
if (sig == "") sig = full_line
|
||||
|
||||
if (!(sig in keys)) {
|
||||
keys[sig] = full_line
|
||||
order[++count] = sig
|
||||
}
|
||||
sources[sig] = (sources[sig] ? sources[sig] ", " : "") source
|
||||
}
|
||||
END {
|
||||
for (i=1; i<=count; i++) {
|
||||
sig = order[i]
|
||||
print "# Source: " sources[sig]
|
||||
if (sig in user_comments) {
|
||||
n = split(user_comments[sig], comment_lines, SUBSEP)
|
||||
for (j=1; j<=n; j++) {
|
||||
print comment_lines[j]
|
||||
}
|
||||
}
|
||||
print keys[sig]
|
||||
}
|
||||
}')
|
||||
|
||||
MANUAL_KEYS=""
|
||||
if [[ -f "${TARGET_FILE}" ]]; then
|
||||
MANUAL_KEYS=$(awk -v begin="${BEGIN_MARKER}" -v end="${END_MARKER}" '
|
||||
BEGIN { inside=0 }
|
||||
$0 == begin { inside=1; next }
|
||||
$0 == end { inside=0; next }
|
||||
!inside { print $0 }
|
||||
' "${TARGET_FILE}")
|
||||
fi
|
||||
|
||||
MANAGED_SIGS_TMP=$(mktemp)
|
||||
CLEANUP_FILES+=("${MANAGED_SIGS_TMP}")
|
||||
echo "${MANAGED_BLOCK}" | awk '/^[^#]/ {
|
||||
n = split($0, parts, " ")
|
||||
sig = ""
|
||||
for (i=1; i<=n; i++) {
|
||||
sig = (sig == "" ? parts[i] : sig " " parts[i])
|
||||
if (parts[i] ~ /^(ssh-|ecdsa-|sk-)/ && i < n) {
|
||||
sig = sig " " parts[i+1]
|
||||
break
|
||||
}
|
||||
}
|
||||
if (sig != "") print sig
|
||||
}' > "${MANAGED_SIGS_TMP}"
|
||||
|
||||
FINAL_MANUAL_KEYS=$(echo "${MANUAL_KEYS}" | awk -v sigs_file="${MANAGED_SIGS_TMP}" '
|
||||
BEGIN {
|
||||
while ((getline line < sigs_file) > 0) {
|
||||
managed[line] = 1
|
||||
}
|
||||
close(sigs_file)
|
||||
}
|
||||
{
|
||||
if ($0 ~ /^[[:space:]]*$/ || $0 ~ /^[[:space:]]*#/) {
|
||||
print $0
|
||||
next
|
||||
}
|
||||
n = split($0, parts, " ")
|
||||
sig = ""
|
||||
for (i=1; i<=n; i++) {
|
||||
sig = (sig == "" ? parts[i] : sig " " parts[i])
|
||||
if (parts[i] ~ /^(ssh-|ecdsa-|sk-)/ && i < n) {
|
||||
sig = sig " " parts[i+1]
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!(sig in managed)) {
|
||||
print $0
|
||||
}
|
||||
}')
|
||||
rm -f "${MANAGED_SIGS_TMP}"
|
||||
|
||||
{
|
||||
if [[ -n "${MANAGED_BLOCK}" ]]; then
|
||||
echo "${BEGIN_MARKER}"
|
||||
echo "${MANAGED_BLOCK}"
|
||||
echo "${END_MARKER}"
|
||||
fi
|
||||
echo "${FINAL_MANUAL_KEYS}"
|
||||
} > "${TMP_FILE}"
|
||||
|
||||
echo "Validating proposed changes..."
|
||||
VALID=1
|
||||
while read -r line; do
|
||||
[[ -z "${line}" || "${line}" =~ ^[[:space:]]*# ]] && continue
|
||||
if ! echo "${line}" | ssh-keygen -l -f - >/dev/null 2>&1; then
|
||||
echo "ERROR: Invalid SSH key detected: ${line}" >&2
|
||||
VALID=0
|
||||
fi
|
||||
done < "${TMP_FILE}"
|
||||
|
||||
if command -v authorized-keys-test >/dev/null 2>&1; then
|
||||
if ! authorized-keys-test "${TMP_FILE}"; then
|
||||
echo "ERROR: Proposed file failed authorized-keys-test." >&2
|
||||
VALID=0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${VALID} -eq 0 ]]; then
|
||||
echo "Validation failed. Aborting." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f "${TARGET_FILE}" ]]; then
|
||||
diff -u "${TARGET_FILE}" "${TMP_FILE}" || true
|
||||
else
|
||||
echo "Target file does not exist. Proposed content:"
|
||||
cat "${TMP_FILE}"
|
||||
fi
|
||||
|
||||
if [[ ${DRY_RUN} -eq 1 ]]; then
|
||||
echo "Dry run complete. No changes made."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -t 0 ]]; then
|
||||
echo -n "Apply these changes to ${TARGET_FILE}? [y/N] "
|
||||
read -r response
|
||||
elif [[ ! -t 0 ]]; then
|
||||
# Read from pipe or file if provided
|
||||
if ! read -r response; then
|
||||
echo "Non-interactive shell detected and no input provided. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${response}" =~ ^([yY][eE][sS]|[yY])$ ]]; then
|
||||
chmod 0600 "${TMP_FILE}"
|
||||
mv "${TMP_FILE}" "${TARGET_FILE}"
|
||||
echo "Changes applied successfully."
|
||||
else
|
||||
echo "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,7 +1,49 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
SKEL_DIR=$(dirname -- "$(readlink -f -- "$HOME/.profile")")
|
||||
cd -- "$SKEL_DIR"
|
||||
cd -- "$(git rev-parse --show-toplevel)"
|
||||
set -eu
|
||||
|
||||
resolve_symlink() {
|
||||
_target="$1"
|
||||
if command -v readlink >/dev/null 2>&1 && readlink -f -- "$_target" >/dev/null 2>&1; then
|
||||
readlink -f -- "$_target"
|
||||
elif command -v python3 >/dev/null 2>&1; then
|
||||
python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$_target"
|
||||
else
|
||||
while [ -L "$_target" ]; do
|
||||
_dir=$(cd -P "$(dirname -- "$_target")" >/dev/null 2>&1 && pwd)
|
||||
_target=$(readlink "$_target")
|
||||
case "$_target" in
|
||||
/*) ;;
|
||||
*) _target="$_dir/$_target" ;;
|
||||
esac
|
||||
done
|
||||
echo "$_target"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -e "$HOME/.profile" ]; then
|
||||
TARGET=$(resolve_symlink "$HOME/.profile")
|
||||
SKEL_DIR=$(dirname -- "$TARGET")
|
||||
else
|
||||
SKEL_DIR=""
|
||||
fi
|
||||
|
||||
REPO_ROOT=""
|
||||
if [ -n "$SKEL_DIR" ] && cd -- "$SKEL_DIR" 2>/dev/null; then
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
if [ -z "$REPO_ROOT" ] || [ ! -f "$REPO_ROOT/install.sh" ]; then
|
||||
SCRIPT_DIR=$(dirname -- "$(resolve_symlink "$0")")
|
||||
if cd -- "$SCRIPT_DIR" 2>/dev/null; then
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
|
||||
fi
|
||||
if [ -z "$REPO_ROOT" ] || [ ! -f "$REPO_ROOT/install.sh" ]; then
|
||||
echo "Error: Could not determine skel repository root." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cd -- "$REPO_ROOT"
|
||||
git pull
|
||||
./install.sh
|
||||
./install.sh "$@"
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
# General aliases, should only be sourced in interactive shells
|
||||
# Try to keep in sync with ~/.config/fish/conf.d/aliases.fish
|
||||
|
||||
# Cryptsetup alias
|
||||
alias luksFormat='cryptsetup luksFormat --type=luks2 --pbkdf-memory=2560000 --pbkdf=argon2id -i 15000 -s 512 -h sha256 -c aes-xts-plain64'
|
||||
|
||||
# Timestamp in a machine-sortable form
|
||||
alias tstamp="date '+%Y%m%d-%H%M%S'"
|
||||
|
||||
@@ -13,12 +10,6 @@ alias mdcode="sed 's/^/ /'"
|
||||
# Intel format plz
|
||||
alias objdump="command objdump -M intel"
|
||||
|
||||
# Drop caches for swap issues
|
||||
alias drop_caches="echo 3 | sudo /usr/bin/tee /proc/sys/vm/drop_caches"
|
||||
|
||||
# dump acpi temperature
|
||||
alias gettemp='printf "%02.2f\n" "$(cat /sys/class/thermal/thermal_zone0/temp)e-3"'
|
||||
|
||||
# get git working directory
|
||||
alias gitroot="git rev-parse --show-toplevel"
|
||||
|
||||
@@ -31,20 +22,40 @@ alias ipy="ipython3 --no-banner"
|
||||
# Skip the header on bc
|
||||
alias bc="command bc -q"
|
||||
|
||||
# Get a decently readable df
|
||||
alias dfh="df -h -x tmpfs -x devtmpfs -x squashfs -x fuse -x efivarfs"
|
||||
|
||||
# Clear the GPG agent
|
||||
alias clear-gpg-agent="echo RELOADAGENT | gpg-connect-agent"
|
||||
|
||||
# Battery details
|
||||
alias bat-details='upower -i $(upower -e | grep battery)'
|
||||
|
||||
# Nvidia refresh rate
|
||||
alias nvidia-refresh-rate='nvidia-settings --display=:0 -q RefreshRate -t'
|
||||
|
||||
# Earthly ssh
|
||||
alias earthly='earthly --ssh-auth-sock ""'
|
||||
|
||||
# to clipboard
|
||||
alias toclip='xclip -selection clipboard'
|
||||
# ESP-IDF
|
||||
alias activate_idf="source ~/.espressif/tools/activate_idf_v*.sh"
|
||||
|
||||
if [ "$(uname)" = "Linux" ]; then
|
||||
# Cryptsetup alias
|
||||
alias luksFormat='cryptsetup luksFormat --type=luks2 --pbkdf-memory=2560000 --pbkdf=argon2id -i 15000 -s 512 -h sha256 -c aes-xts-plain64'
|
||||
|
||||
# Drop caches for swap issues
|
||||
alias drop_caches="echo 3 | sudo /usr/bin/tee /proc/sys/vm/drop_caches"
|
||||
|
||||
# dump acpi temperature
|
||||
alias gettemp='printf "%02.2f\n" "$(cat /sys/class/thermal/thermal_zone0/temp)e-3"'
|
||||
|
||||
# Get a decently readable df
|
||||
alias dfh="df -h -x tmpfs -x devtmpfs -x squashfs -x fuse -x efivarfs"
|
||||
|
||||
# Battery details
|
||||
alias bat-details='upower -i $(upower -e | grep battery)'
|
||||
|
||||
# Nvidia refresh rate
|
||||
alias nvidia-refresh-rate='nvidia-settings --display=:0 -q RefreshRate -t'
|
||||
|
||||
# to clipboard
|
||||
alias toclip='xclip -selection clipboard'
|
||||
elif [ "$(uname)" = "Darwin" ]; then
|
||||
# Get a decently readable df
|
||||
alias dfh="df -h"
|
||||
|
||||
# to clipboard
|
||||
alias toclip='pbcopy'
|
||||
fi
|
||||
|
||||
4
dotfiles/bxignore
Normal file
4
dotfiles/bxignore
Normal file
@@ -0,0 +1,4 @@
|
||||
# Credentials
|
||||
.ssh
|
||||
Passwords.kdbx
|
||||
Passwords.kdbx.age
|
||||
63
dotfiles/commonrc.sh
Normal file
63
dotfiles/commonrc.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC1090
|
||||
|
||||
# common functions for use in shell scripts
|
||||
|
||||
find_first() {
|
||||
while [ "$#" -gt 0 ]; do
|
||||
if test -e "${1}" ; then
|
||||
echo "${1}"
|
||||
return 0
|
||||
fi
|
||||
shift
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
have_command() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Helper function: Returns 0 if the directory is in PATH, 1 otherwise
|
||||
path_contains() {
|
||||
case ":${PATH}:" in
|
||||
*:"$1":*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Prepend a directory to PATH if it's not already there
|
||||
path_prepend() {
|
||||
if [ -d "$1" ] && ! path_contains "$1"; then
|
||||
PATH="$1:${PATH}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Append a directory to PATH if it's not already there
|
||||
path_append() {
|
||||
if [ -d "$1" ] && ! path_contains "$1"; then
|
||||
PATH="${PATH}:$1"
|
||||
fi
|
||||
}
|
||||
|
||||
source_first_existing() {
|
||||
_sfe_script="$(find_first "$@")"
|
||||
_sfe_status=$?
|
||||
|
||||
if [ "$_sfe_status" -eq 0 ]; then
|
||||
. "$_sfe_script"
|
||||
# Clean up our temporary variables before returning success
|
||||
unset -v _sfe_script _sfe_status
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Clean up our temporary variables before returning failure
|
||||
unset -v _sfe_script _sfe_status
|
||||
return 1
|
||||
}
|
||||
|
||||
source_if_existing() {
|
||||
if [ -f "$1" ]; then
|
||||
. "$1"
|
||||
fi
|
||||
}
|
||||
@@ -1,6 +1,3 @@
|
||||
# Cryptsetup alias
|
||||
alias luksFormat 'cryptsetup luksFormat --type=luks2 --pbkdf-memory=2560000 --pbkdf=argon2id -i 15000 -s 512 -h sha256 -c aes-xts-plain64'
|
||||
|
||||
# Timestamp in a machine-sortable form
|
||||
alias tstamp "date '+%Y%m%d-%H%M%S'"
|
||||
|
||||
@@ -10,12 +7,6 @@ alias mdcode "sed 's/^/ /'"
|
||||
# Intel format plz
|
||||
alias objdump "command objdump -M intel"
|
||||
|
||||
# Drop caches for swap issues
|
||||
alias drop_caches "echo 3 | sudo /usr/bin/tee /proc/sys/vm/drop_caches"
|
||||
|
||||
# dump acpi temperature
|
||||
alias gettemp 'printf "%02.2f\n" (cat /sys/class/thermal/thermal_zone0/temp)e-3'
|
||||
|
||||
# get git working directory
|
||||
alias gitroot "git rev-parse --show-toplevel"
|
||||
|
||||
@@ -28,23 +19,40 @@ alias ipy "ipython3 --no-banner"
|
||||
# Skip the header on bc
|
||||
alias bc "command bc -q"
|
||||
|
||||
# Get a decently readable df
|
||||
alias dfh "df -h -x tmpfs -x devtmpfs -x squashfs -x fuse -x efivarfs"
|
||||
|
||||
# Clear the GPG agent
|
||||
alias clear-gpg-agent "echo RELOADAGENT | gpg-connect-agent"
|
||||
|
||||
# Battery details
|
||||
alias bat-details 'upower -i (upower -e | grep battery)'
|
||||
|
||||
# Nvidia refresh rate
|
||||
alias nvidia-refresh-rate 'nvidia-settings --display=:0 -q RefreshRate -t'
|
||||
|
||||
# Earthly ssh
|
||||
alias earthly 'earthly --ssh-auth-sock ""'
|
||||
|
||||
# to clipboard
|
||||
alias toclip 'xclip -selection clipboard'
|
||||
if test (uname) = "Linux"
|
||||
# Cryptsetup alias
|
||||
alias luksFormat 'cryptsetup luksFormat --type=luks2 --pbkdf-memory=2560000 --pbkdf=argon2id -i 15000 -s 512 -h sha256 -c aes-xts-plain64'
|
||||
|
||||
# Drop caches for swap issues
|
||||
alias drop_caches "echo 3 | sudo /usr/bin/tee /proc/sys/vm/drop_caches"
|
||||
|
||||
# dump acpi temperature
|
||||
alias gettemp 'printf "%02.2f\n" (cat /sys/class/thermal/thermal_zone0/temp)e-3'
|
||||
|
||||
# Get a decently readable df
|
||||
alias dfh "df -h -x tmpfs -x devtmpfs -x squashfs -x fuse -x efivarfs"
|
||||
|
||||
# Battery details
|
||||
alias bat-details 'upower -i (upower -e | grep battery)'
|
||||
|
||||
# Nvidia refresh rate
|
||||
alias nvidia-refresh-rate 'nvidia-settings --display=:0 -q RefreshRate -t'
|
||||
|
||||
# to clipboard
|
||||
alias toclip 'xclip -selection clipboard'
|
||||
else if test (uname) = "Darwin"
|
||||
# Get a decently readable df
|
||||
alias dfh "df -h"
|
||||
|
||||
# to clipboard
|
||||
alias toclip 'pbcopy'
|
||||
end
|
||||
|
||||
# On some systems, bat is batcat
|
||||
if not command -v bat >/dev/null 2>&1
|
||||
|
||||
@@ -34,4 +34,6 @@ end
|
||||
fish_add_path --move --path {$HOME}/bin
|
||||
if test (uname) = "Darwin"
|
||||
fish_add_path --move --path {$HOME}/bin/macos
|
||||
else if test (uname) = "Linux"
|
||||
fish_add_path --move --path {$HOME}/bin/linux
|
||||
end
|
||||
|
||||
@@ -9,9 +9,8 @@ uv_venv_auto = true
|
||||
|
||||
[tools]
|
||||
age = "latest"
|
||||
age-plugin-yubikey = "latest"
|
||||
usage = "latest"
|
||||
uv = "latest"
|
||||
uv = "0.11.8"
|
||||
|
||||
[hooks]
|
||||
postinstall = "mise sync python --uv"
|
||||
|
||||
@@ -39,16 +39,3 @@ disabled = true
|
||||
[kubernetes]
|
||||
disabled = false
|
||||
detect_folders = ["k8s"]
|
||||
|
||||
[custom.gemini_context]
|
||||
description = "Displays the current Gemini CLI context"
|
||||
when = "test -n \"$GEMINI_CLI_HOME\""
|
||||
command = """
|
||||
context_dir=\"${XDG_CONFIG_HOME:-$HOME/.config}/gemini\"
|
||||
if [[ \"$GEMINI_CLI_HOME\" == $context_dir/* ]]; then
|
||||
basename \"$GEMINI_CLI_HOME\"
|
||||
fi
|
||||
"""
|
||||
style = "bold blue"
|
||||
format = "♊[$output](blue) "
|
||||
shell = ["/bin/sh", "-c"]
|
||||
|
||||
@@ -19,14 +19,17 @@
|
||||
[difftool]
|
||||
prompt = false
|
||||
|
||||
[difftool "difftastic"]
|
||||
cmd = difft "$LOCAL" "$REMOTE"
|
||||
|
||||
[alias]
|
||||
st = status
|
||||
last = log -1 HEAD
|
||||
# Thanks to
|
||||
# http://durdn.com/blog/2012/11/22/must-have-git-aliases-advanced-examples/
|
||||
logs = log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate
|
||||
logs = log --pretty=format:"%C(yellow)%h%Cred%d %Creset%s%Cblue [%cn]" --decorate
|
||||
lg = log -p
|
||||
ll = log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --numstat
|
||||
ll = log --pretty=format:"%C(yellow)%h%Cred%d %Creset%s%Cblue [%cn]" --decorate --numstat
|
||||
files = ls-files
|
||||
ls = ls-files
|
||||
lol = log --graph --pretty=format:'%C(yellow)%h%Creset %an: %s - %Creset %C(yellow)%d%Creset %Cblue(%cr)%Creset' --abbrev-commit --date=relative
|
||||
@@ -92,8 +95,18 @@
|
||||
process = git-lfs filter-process
|
||||
|
||||
[include]
|
||||
path = ~/.gitconfig.d/aliases
|
||||
path = ~/.gitconfig.d/override
|
||||
path = ~/.gitconfig.d/local
|
||||
|
||||
[includeIf "gitdir:~/personal/"]
|
||||
[includeIf "gitdir/i:~/personal/"]
|
||||
path = ~/.gitconfig.d/personal
|
||||
|
||||
[rerere]
|
||||
enabled = true
|
||||
[lfs]
|
||||
concurrenttransfers = 3
|
||||
[lfs "customtransfer.xet"]
|
||||
path = git-xet
|
||||
args = transfer
|
||||
concurrent = true
|
||||
|
||||
@@ -38,3 +38,4 @@ mise.local.toml
|
||||
.copilot/
|
||||
.cursor/
|
||||
.gemini/
|
||||
.jetskicli/
|
||||
|
||||
@@ -4,16 +4,17 @@
|
||||
# Should only use POSIX constructs.
|
||||
|
||||
# Always load ENV
|
||||
test -f "$HOME/.shenv" && . "$HOME/.shenv"
|
||||
test -f "${HOME}/.shenv" && . "${HOME}/.shenv"
|
||||
|
||||
# Setup GREP_COLORS
|
||||
export GREP_COLOR='01;31'
|
||||
export GREP_COLORS='mt=01;31:mc=01;31:ms=01;31'
|
||||
|
||||
# Setup LS_COLORS
|
||||
if whence dircolors >/dev/null 2>&1 ; then
|
||||
test -f "${HOME}/.dircolors" && \
|
||||
eval "$(dircolors "${HOME}/.dircolors")"
|
||||
if command -v dircolors >/dev/null 2>&1 && test -f "${HOME}/.dircolors" ; then
|
||||
eval "$(dircolors -b "${HOME}/.dircolors" 2>/dev/null)"
|
||||
elif command -v gdircolors >/dev/null 2>&1 && test -f "${HOME}/.dircolors" ; then
|
||||
eval "$(gdircolors -b "${HOME}/.dircolors" 2>/dev/null)"
|
||||
else
|
||||
# Static solarized LS_COLORS
|
||||
LS_COLORS='no=00:fi=00:di=34:ow=34;40:ln=35:pi=30;44:so=35;44:do=35;44:bd=33;44:cd=37;44:or=05;37;41:mi=05;37;41:ex=01;31:*.cmd=01;31:*.exe=01;31:*.com=01;31:*.bat=01;31:*.reg=01;31:*.app=01;31:*.txt=32:*.org=32:*.md=32:*.mkd=32:*.h=32:*.hpp=32:*.c=32:*.C=32:*.cc=32:*.cpp=32:*.cxx=32:*.objc=32:*.cl=32:*.sh=32:*.bash=32:*.csh=32:*.zsh=32:*.el=32:*.vim=32:*.java=32:*.pl=32:*.pm=32:*.py=32:*.rb=32:*.hs=32:*.php=32:*.htm=32:*.html=32:*.shtml=32:*.erb=32:*.haml=32:*.xml=32:*.rdf=32:*.css=32:*.sass=32:*.scss=32:*.less=32:*.js=32:*.coffee=32:*.man=32:*.0=32:*.1=32:*.2=32:*.3=32:*.4=32:*.5=32:*.6=32:*.7=32:*.8=32:*.9=32:*.l=32:*.n=32:*.p=32:*.pod=32:*.tex=32:*.go=32:*.sql=32:*.csv=32:*.sv=32:*.svh=32:*.v=32:*.vh=32:*.vhd=32:*.bmp=33:*.cgm=33:*.dl=33:*.dvi=33:*.emf=33:*.eps=33:*.gif=33:*.jpeg=33:*.jpg=33:*.JPG=33:*.mng=33:*.pbm=33:*.pcx=33:*.pdf=33:*.pgm=33:*.png=33:*.PNG=33:*.ppm=33:*.pps=33:*.ppsx=33:*.ps=33:*.svg=33:*.svgz=33:*.tga=33:*.tif=33:*.tiff=33:*.xbm=33:*.xcf=33:*.xpm=33:*.xwd=33:*.xwd=33:*.yuv=33:*.aac=33:*.au=33:*.flac=33:*.m4a=33:*.mid=33:*.midi=33:*.mka=33:*.mp3=33:*.mpa=33:*.mpeg=33:*.mpg=33:*.ogg=33:*.opus=33:*.ra=33:*.wav=33:*.anx=33:*.asf=33:*.avi=33:*.axv=33:*.flc=33:*.fli=33:*.flv=33:*.gl=33:*.m2v=33:*.m4v=33:*.mkv=33:*.mov=33:*.MOV=33:*.mp4=33:*.mp4v=33:*.mpeg=33:*.mpg=33:*.nuv=33:*.ogm=33:*.ogv=33:*.ogx=33:*.qt=33:*.rm=33:*.rmvb=33:*.swf=33:*.vob=33:*.webm=33:*.wmv=33:*.doc=31:*.docx=31:*.rtf=31:*.odt=31:*.dot=31:*.dotx=31:*.ott=31:*.xls=31:*.xlsx=31:*.ods=31:*.ots=31:*.ppt=31:*.pptx=31:*.odp=31:*.otp=31:*.fla=31:*.psd=31:*.7z=1;35:*.apk=1;35:*.arj=1;35:*.bin=1;35:*.bz=1;35:*.bz2=1;35:*.cab=1;35:*.deb=1;35:*.dmg=1;35:*.gem=1;35:*.gz=1;35:*.iso=1;35:*.jar=1;35:*.msi=1;35:*.rar=1;35:*.rpm=1;35:*.tar=1;35:*.tbz=1;35:*.tbz2=1;35:*.tgz=1;35:*.tx=1;35:*.war=1;35:*.xpi=1;35:*.xz=1;35:*.z=1;35:*.Z=1;35:*.zip=1;35:*.ANSI-30-black=30:*.ANSI-01;30-brblack=01;30:*.ANSI-31-red=31:*.ANSI-01;31-brred=01;31:*.ANSI-32-green=32:*.ANSI-01;32-brgreen=01;32:*.ANSI-33-yellow=33:*.ANSI-01;33-bryellow=01;33:*.ANSI-34-blue=34:*.ANSI-01;34-brblue=01;34:*.ANSI-35-magenta=35:*.ANSI-01;35-brmagenta=01;35:*.ANSI-36-cyan=36:*.ANSI-01;36-brcyan=01;36:*.ANSI-37-white=37:*.ANSI-01;37-brwhite=01;37:*.log=01;32:*~=01;32:*#=01;32:*.bak=01;33:*.BAK=01;33:*.old=01;33:*.OLD=01;33:*.org_archive=01;33:*.off=01;33:*.OFF=01;33:*.dist=01;33:*.DIST=01;33:*.orig=01;33:*.ORIG=01;33:*.swp=01;33:*.swo=01;33:*,v=01;33:*.gpg=34:*.gpg=34:*.pgp=34:*.asc=34:*.3des=34:*.aes=34:*.enc=34:*.sqlite=34:';
|
||||
@@ -27,16 +28,16 @@ if [ "$(uname)" = "Darwin" ] ; then
|
||||
fi
|
||||
|
||||
# Setup for libvirt
|
||||
if [ -z "${LIBVIRT_DEFAULT_URI}" ] ; then
|
||||
if [ "$(id -u)" = "0" ] || (id -g -n | grep -q "\blibvirt\b") ; then
|
||||
LIBVIRT_DEFAULT_URI="qemu:///system"
|
||||
export LIBVIRT_DEFAULT_URI
|
||||
fi
|
||||
if [ -z "${LIBVIRT_DEFAULT_URI:-}" ] ; then
|
||||
export LIBVIRT_DEFAULT_URI="qemu:///system"
|
||||
fi
|
||||
|
||||
# Got rust? (gvim, etc.)
|
||||
if test -d "${HOME}/.cargo/bin" ; then
|
||||
PATH="${PATH}:${HOME}/.cargo/bin"
|
||||
case ":${PATH}:" in
|
||||
*:"${HOME}/.cargo/bin":*) ;;
|
||||
*) PATH="${PATH}:${HOME}/.cargo/bin" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
test -f "${HOME}/.profile.local" && . "${HOME}/.profile.local"
|
||||
|
||||
@@ -45,3 +45,6 @@
|
||||
hibernationfile
|
||||
sleepimage
|
||||
swapfile
|
||||
|
||||
# Android and other big tools
|
||||
/Users/*/.android
|
||||
|
||||
173
dotfiles/shenv
173
dotfiles/shenv
@@ -15,6 +15,7 @@ export DEBEMAIL="david@systemoverlord.com"
|
||||
export DEBFULLNAME="David Tomaschik"
|
||||
export LESS="-MR"
|
||||
export QUOTING_STYLE="literal" # Coreutils quotes
|
||||
export HOMEBREW_NO_ENV_HINTS=1
|
||||
|
||||
# Fix gnome-terminal
|
||||
if [ "$TERM" = "xterm" ] && [ "$COLORTERM" = "gnome-terminal" ] ; then
|
||||
@@ -28,6 +29,9 @@ export WORKON_HOME="$HOME/.virtualenvs"
|
||||
# GPG full key id
|
||||
export GPG_ID=7FD58D9A196DCEEEAD671F94F4D7A7915DEA789B
|
||||
|
||||
# Capture uname early
|
||||
_UNAME="$(uname)"
|
||||
|
||||
# things we need in all interactive shells
|
||||
case "$-" in
|
||||
*i*)
|
||||
@@ -85,7 +89,6 @@ case "$-" in
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
# Opt out of .net telemetry
|
||||
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
|
||||
@@ -96,74 +99,145 @@ export LVM_SUPPRESS_FD_WARNINGS=1
|
||||
export EARTHLY_SSH_AUTH_SOCK=""
|
||||
|
||||
# Handle SSH_AUTH_SOCK for tmux consistency
|
||||
_SSH_AUTH_LINK="${HOME}/.ssh/ssh_auth_sock"
|
||||
case "$-" in
|
||||
*i*)
|
||||
_SSH_AUTH_LINK="${HOME}/.ssh/ssh_auth_sock"
|
||||
|
||||
# Helper to check if a path is our link or points to it
|
||||
_is_link_path() {
|
||||
# Helper to check if a path is our link or points to it
|
||||
_is_link_path() {
|
||||
[ -z "$1" ] && return 1
|
||||
[ "$1" = "${_SSH_AUTH_LINK}" ] && return 0
|
||||
_target="${_SSH_AUTH_LINK:-${HOME}/.ssh/ssh_auth_sock}"
|
||||
[ "$1" = "${_target}" ] && { unset -v _target; return 0; }
|
||||
if [ -L "$1" ] && command -v readlink >/dev/null 2>&1; then
|
||||
_T=$(readlink "$1")
|
||||
# Handle relative symlinks
|
||||
case "${_T}" in /*) ;; *) _T="$(dirname "$1")/${_T}" ;; esac
|
||||
[ "${_T}" = "${_SSH_AUTH_LINK}" ] && return 0
|
||||
[ "${_T}" = "${_target}" ] && { unset -v _target _T; return 0; }
|
||||
unset -v _T
|
||||
fi
|
||||
unset -v _target
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
_CANDIDATE=""
|
||||
# Helper to check if an SSH socket is valid and useful
|
||||
_is_valid_ssh_sock() {
|
||||
[ -z "$1" ] && return 1
|
||||
[ -S "$1" ] || return 1
|
||||
|
||||
# 1. If current environment has a valid socket that is NOT our link, it's a prime candidate (e.g. SSH forwarding).
|
||||
if [ -S "${SSH_AUTH_SOCK:-}" ] && ! _is_link_path "${SSH_AUTH_SOCK}"; then
|
||||
_CANDIDATE="${SSH_AUTH_SOCK}"
|
||||
fi
|
||||
if command -v nc >/dev/null 2>&1; then
|
||||
# Use nc to quickly check if the socket is listening.
|
||||
# We use -N to shutdown the socket after EOF on stdin (for OpenBSD netcat compatibility).
|
||||
if echo '' | nc -w 1 -N -U "$1" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# 2. If no candidate yet, or we're currently using the link, try to find the "real" system agent.
|
||||
if [ -z "${_CANDIDATE}" ] || _is_link_path "${SSH_AUTH_SOCK:-}"; then
|
||||
_FOUND=""
|
||||
if command -v ssh-add >/dev/null 2>&1; then
|
||||
SSH_AUTH_SOCK="$1" ssh-add -l >/dev/null 2>&1
|
||||
case "$?" in
|
||||
0|1) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if command -v nc >/dev/null 2>&1; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to get the path to the socket for the local ssh-agent
|
||||
get_local_ssh_agent_sock() {
|
||||
_found=""
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
_FOUND=$(launchctl getenv SSH_AUTH_SOCK 2>/dev/null)
|
||||
_found=$(launchctl getenv SSH_AUTH_SOCK 2>/dev/null)
|
||||
elif command -v systemctl >/dev/null 2>&1; then
|
||||
# Query systemd socket units directly to avoid environment overrides.
|
||||
for _u in ssh-agent.socket openssh-agent.socket gcr-ssh-agent.socket gpg-agent-ssh.socket; do
|
||||
_P=$(systemctl --user show "${_u}" -p Listen 2>/dev/null | cut -d= -f2- | cut -d' ' -f1)
|
||||
if [ -S "${_P}" ]; then
|
||||
_FOUND="${_P}"
|
||||
_p=$(systemctl --user show "${_u}" -p Listen 2>/dev/null | cut -d= -f2- | cut -d' ' -f1)
|
||||
if ! _is_link_path "${_p}" && _is_valid_ssh_sock "${_p}"; then
|
||||
_found="${_p}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
# Fallback to systemd environment
|
||||
if [ -z "${_FOUND}" ] || _is_link_path "${_FOUND}"; then
|
||||
_FOUND=$(systemctl --user show-environment 2>/dev/null | grep "^SSH_AUTH_SOCK=" | cut -d= -f2-)
|
||||
if [ -z "${_found}" ] || _is_link_path "${_found}" || ! _is_valid_ssh_sock "${_found}"; then
|
||||
_found=$(systemctl --user show-environment 2>/dev/null | grep "^SSH_AUTH_SOCK=" | cut -d= -f2-)
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -S "${_FOUND}" ] && ! _is_link_path "${_FOUND}"; then
|
||||
_CANDIDATE="${_FOUND}"
|
||||
if [ -n "${_found}" ] && ! _is_link_path "${_found}" && _is_valid_ssh_sock "${_found}"; then
|
||||
echo "${_found}"
|
||||
unset -v _found _u _p
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# 3. Last resort: search common paths if we still don't have a valid candidate.
|
||||
if [ ! -S "${_CANDIDATE}" ]; then
|
||||
_U=$(id -u)
|
||||
for _p in "/run/user/${_U}/keyring/ssh" "/run/user/${_U}/ssh-agent.socket" "/run/user/${_U}/openssh_agent" "/run/user/${_U}/gnupg/S.gpg-agent.ssh"; do
|
||||
if [ -S "${_p}" ] && ! _is_link_path "${_p}"; then
|
||||
_CANDIDATE="${_p}"
|
||||
break
|
||||
# Search common fallback paths
|
||||
_u=$(id -u)
|
||||
for _p in "/run/user/${_u}/keyring/ssh" "/run/user/${_u}/ssh-agent.socket" "/run/user/${_u}/openssh_agent" "/run/user/${_u}/gnupg/S.gpg-agent.ssh"; do
|
||||
if ! _is_link_path "${_p}" && _is_valid_ssh_sock "${_p}"; then
|
||||
echo "${_p}"
|
||||
unset -v _found _u _p
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
if [ -z "${_CANDIDATE}" ]; then
|
||||
# Build search path list based on what actually exists
|
||||
_SEARCH=""
|
||||
for _d in "/run/user/${_U}" /tmp; do [ -d "${_d}" ] && _SEARCH="${_SEARCH} ${_d}"; done
|
||||
if [ -n "${_SEARCH}" ]; then
|
||||
_CANDIDATE=$(find ${_SEARCH} -maxdepth 2 -type s -name 'agent.*' 2>/dev/null | grep -F -v "${_SSH_AUTH_LINK}" | head -n 1)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 4. Sync the stable link if we found a valid "real" socket.
|
||||
if [ -S "${_CANDIDATE}" ] && ! _is_link_path "${_CANDIDATE}"; then
|
||||
# Search /run/user/UID and /tmp for agent.* sockets
|
||||
_search=""
|
||||
for _d in "/run/user/${_u}" /tmp; do [ -d "${_d}" ] && _search="${_search} ${_d}"; done
|
||||
if [ -n "${_search}" ]; then
|
||||
for _p in $(find ${_search} -maxdepth 2 -type s -name 'agent.*' 2>/dev/null); do
|
||||
if ! _is_link_path "${_p}" && _is_valid_ssh_sock "${_p}"; then
|
||||
echo "${_p}"
|
||||
unset -v _found _u _p _search _d
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
unset -v _found _u _p _search _d
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to reset SSH_AUTH_SOCK to the local ssh-agent
|
||||
reset_ssh_socket() {
|
||||
_rss_sock=$(get_local_ssh_agent_sock)
|
||||
if [ -n "${_rss_sock}" ]; then
|
||||
_rss_link="${HOME}/.ssh/ssh_auth_sock"
|
||||
mkdir -p "$(dirname "${_rss_link}")"
|
||||
ln -sf "${_rss_sock}" "${_rss_link}"
|
||||
export SSH_AUTH_SOCK="${_rss_link}"
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl --user set-environment SSH_AUTH_SOCK="${_rss_link}" 2>/dev/null
|
||||
fi
|
||||
echo "Reset SSH_AUTH_SOCK to ${_rss_link} -> ${_rss_sock}"
|
||||
unset -v _rss_sock _rss_link
|
||||
return 0
|
||||
else
|
||||
echo "reset_ssh_socket: no valid local ssh-agent socket found." >&2
|
||||
unset -v _rss_sock
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_CANDIDATE=""
|
||||
|
||||
# 1. If current environment has a valid socket that is NOT our link, it's a prime candidate
|
||||
# (e.g. fresh SSH login: sshd sets SSH_AUTH_SOCK to the raw forwarded socket before ssh/rc
|
||||
# rewrites it to the stable symlink; the shell inherits the original raw path).
|
||||
if ! _is_link_path "${SSH_AUTH_SOCK:-}" && _is_valid_ssh_sock "${SSH_AUTH_SOCK:-}"; then
|
||||
_CANDIDATE="${SSH_AUTH_SOCK}"
|
||||
fi
|
||||
|
||||
# 2. Only look for a system agent if the stable link is already broken. If the link is
|
||||
# valid (e.g. a tmux pane where SSH_AUTH_SOCK points to our symlink which ssh/rc just
|
||||
# updated to the forwarded socket), leave it alone — don't clobber it with a local agent.
|
||||
if [ -z "${_CANDIDATE}" ] && ! _is_valid_ssh_sock "${_SSH_AUTH_LINK}"; then
|
||||
_CANDIDATE=$(get_local_ssh_agent_sock)
|
||||
fi
|
||||
|
||||
# 3. Sync the stable link if we found a valid "real" socket.
|
||||
if [ -n "${_CANDIDATE}" ] && ! _is_link_path "${_CANDIDATE}" && _is_valid_ssh_sock "${_CANDIDATE}"; then
|
||||
mkdir -p "$(dirname "${_SSH_AUTH_LINK}")"
|
||||
ln -sf "${_CANDIDATE}" "${_SSH_AUTH_LINK}"
|
||||
export SSH_AUTH_SOCK="${_SSH_AUTH_LINK}"
|
||||
@@ -171,17 +245,18 @@ if [ -S "${_CANDIDATE}" ] && ! _is_link_path "${_CANDIDATE}"; then
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl --user set-environment SSH_AUTH_SOCK="${_SSH_AUTH_LINK}" 2>/dev/null
|
||||
fi
|
||||
elif [ -S "${_SSH_AUTH_LINK}" ]; then
|
||||
elif _is_valid_ssh_sock "${_SSH_AUTH_LINK}"; then
|
||||
# If we found nothing better but the link is valid, use it.
|
||||
export SSH_AUTH_SOCK="${_SSH_AUTH_LINK}"
|
||||
fi
|
||||
fi
|
||||
|
||||
unset _SSH_AUTH_LINK _CANDIDATE _FOUND _T _P _U _u _SEARCH _d
|
||||
unset -f _is_link_path
|
||||
unset _SSH_AUTH_LINK _CANDIDATE
|
||||
;;
|
||||
esac
|
||||
|
||||
# Setup XDG-like dirs on MacOS
|
||||
# Based on https://leebyron.com/til/mac-xdg/
|
||||
if [ "$(uname)" = "Darwin" ] ; then
|
||||
if [ "${_UNAME}" = "Darwin" ] ; then
|
||||
export XDG_BIN_HOME="${XDG_BIN_HOME:-$HOME/.local/bin}"
|
||||
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/Library/Caches}"
|
||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
@@ -190,8 +265,12 @@ if [ "$(uname)" = "Darwin" ] ; then
|
||||
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-$TMPDIR/runtime-$(id -u)}"
|
||||
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
|
||||
export PATH="${HOME}/bin/macos:${PATH}"
|
||||
elif [ "${_UNAME}" = "Linux" ] ; then
|
||||
export PATH="${HOME}/bin/linux:${PATH}"
|
||||
fi
|
||||
|
||||
unset _UNAME
|
||||
|
||||
if test -e "$HOME/.localenv"; then
|
||||
# shellcheck source=/dev/null
|
||||
. "$HOME/.localenv"
|
||||
|
||||
1
dotfiles/ssh/authorized_keys.d/5dea789b_subkey.pub
Normal file
1
dotfiles/ssh/authorized_keys.d/5dea789b_subkey.pub
Normal file
@@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDYQOAB5bJ9DjMXyY67GEI99kK1LG8XF+cWJ4md52rPnOeJd0da7l26bn9NtXCma6DP5gZQArfxHsPh7I4SbYJRYxTCCCE/Jsd8mLB22DcoeY+MqPA2g71j3KrYsvuJC++9GHK2Xc7ZRmhAugEmC/NAdtORBVhtBSAUgyCmUczKHoCAqHmq8j54En8kRYjbvlHPpDsNoRuhcH5uDGBIVkbV7UtBl2oUlRNVw7grs6XS7cPU2zCQSxcrRRuAfV4hmGG2eKaPpieNg0MAAbR0G5ssWW3IuYwd1ys5wA0YQuWUhxadUuYc46/cqyyoVIFlfjxCVTX+2w3900SDPOF/YrOwctAb23+78WN6GPnAmmS3zcmXTGsJiw/mmyBlqYI/JdSgrgI+COlcP0rlF/uklzEywfD91m1lno1u2IApdAumZWHR8aFnpHQXfI6rWc1o/V+RBpz5Xe6D2h9CPT3AE303BV09HGmidb0t6bCKoabTDwvE+KojIcbKBji6g8V6KTM=
|
||||
1
dotfiles/ssh/authorized_keys.d/id_ecdsa_zazu.pub
Normal file
1
dotfiles/ssh/authorized_keys.d/id_ecdsa_zazu.pub
Normal file
@@ -0,0 +1 @@
|
||||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOP0EQthckpi83EoFXtbPnn4Ytd7FYW6Nb3W9ZahqOKhNAqv1owot957ihKHtGKFnYr0Jwgp0TNOdpz6nV9wwCo= david@zazu
|
||||
1
dotfiles/ssh/authorized_keys.d/id_ed25519_baymax.pub
Normal file
1
dotfiles/ssh/authorized_keys.d/id_ed25519_baymax.pub
Normal file
@@ -0,0 +1 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINFlZdKMzY8S/znw16R3X9jO+BaJ30NloH9XWtftjYh6 david@baymax.local
|
||||
1
dotfiles/ssh/authorized_keys.d/id_ed25519_scar.pub
Normal file
1
dotfiles/ssh/authorized_keys.d/id_ed25519_scar.pub
Normal file
@@ -0,0 +1 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBeDzE5KLJh2a9p0u702H9+rvaB1HoLLBU1I2Lx6NUbC david@scar
|
||||
1
dotfiles/ssh/authorized_keys.d/id_sk_ecdsa_zazu.pub
Normal file
1
dotfiles/ssh/authorized_keys.d/id_sk_ecdsa_zazu.pub
Normal file
@@ -0,0 +1 @@
|
||||
sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBF8YzO0pEZ9DKHyqgPZpwlv6s4FBYDunIV23R4VUfiC3dw3P1vX9+tDO2+K65v+0vL2rAuBr5ZAHmDxiY8PzDwoAAAAEc3NoOg== david@zazu-sk
|
||||
@@ -2,19 +2,19 @@
|
||||
|
||||
# Roughly based on this article:
|
||||
# https://werat.github.io/2017/02/04/tmux-ssh-agent-forwarding.html
|
||||
#
|
||||
# NOTE: this file is executed by sshd as a child process, NOT sourced by the
|
||||
# user's shell. Any variable assignments or exports here have no effect on the
|
||||
# shell environment the user will land in.
|
||||
|
||||
REMOTE_LINK="${HOME}/.ssh/ssh_auth_sock"
|
||||
|
||||
if [ -S "${SSH_AUTH_SOCK}" ] ; then
|
||||
SSH_REMOTE_AUTH_SOCK="${SSH_AUTH_SOCK}"
|
||||
export SSH_REMOTE_AUTH_SOCK
|
||||
# Always update the symlink to the latest session's socket.
|
||||
# This ensures that tmux (which uses the static path) always points to a
|
||||
# current agent.
|
||||
mkdir -p "$(dirname "${REMOTE_LINK}")"
|
||||
ln -sf "${SSH_AUTH_SOCK}" "${REMOTE_LINK}"
|
||||
SSH_AUTH_SOCK="${REMOTE_LINK}"
|
||||
export SSH_AUTH_SOCK
|
||||
fi
|
||||
|
||||
# if stdin is a tty, don't do the cookie step
|
||||
|
||||
@@ -45,7 +45,7 @@ set -g window-status-current-style fg=colour235,bg=colour33,bold
|
||||
set -g status-interval 60
|
||||
set -g status-left-length 30
|
||||
set -g status-left '/#h: #S/ '
|
||||
set -g status-right '#{?pane_title,/#{pane_title}/ ,}#(cut -d " " -f 1-3 /proc/loadavg)#[default] #[fg=colour166]%H:%M#[default]'
|
||||
set -g status-right '#{?pane_title,/#{pane_title}/ ,}#(uptime | rev | cut -d":" -f1 | rev | sed s/,//g)#[default] #[fg=colour166]%H:%M#[default]'
|
||||
|
||||
# Advanced mouse mode from http://tangledhelix.com/blog/2012/07/16/tmux-and-mouse-mode/
|
||||
# Toggle mouse on
|
||||
@@ -65,8 +65,9 @@ bind M \
|
||||
display 'Mouse: OFF'
|
||||
|
||||
# tmux X clipboard integration
|
||||
bind C-c run "tmux show-buffer | xsel -i -b"
|
||||
bind C-v run "tmux set-buffer -- \"$(xsel -o -b)\"; tmux paste-buffer"
|
||||
if-shell 'test "$(uname)" = "Darwin"' \
|
||||
'bind C-c run "tmux show-buffer | pbcopy"; bind C-v run "tmux set-buffer -- \"$(pbpaste)\"; tmux paste-buffer"' \
|
||||
'bind C-c run "tmux show-buffer | xsel -i -b"; bind C-v run "tmux set-buffer -- \"$(xsel -o -b)\"; tmux paste-buffer"'
|
||||
|
||||
# List of plugins
|
||||
set -g @plugin 'tmux-plugins/tpm'
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# For interactive shells
|
||||
[[ -n "$ZSH_PROFILE" ]] && {
|
||||
zmodload zsh/datetime
|
||||
zshrc_start_time=$EPOCHREALTIME
|
||||
zmodload zsh/zprof
|
||||
export PS4='+[%D{%f} / %D{%s.%N}] %N:%i> '
|
||||
exec 3>&2 2>/tmp/zsh_startup.log
|
||||
set -x
|
||||
zshrc_start_time=$EPOCHREALTIME
|
||||
}
|
||||
HISTFILE=~/.zhistory
|
||||
HISTSIZE=10000
|
||||
@@ -59,6 +62,8 @@ DIRSTACKSIZE=16
|
||||
|
||||
export OS="$(uname 2>/dev/null || echo "Unknown")"
|
||||
|
||||
source ~/.commonrc.sh
|
||||
|
||||
# Set terminal title
|
||||
case $TERM in
|
||||
# Only set the title for terminals that are likely to support it
|
||||
@@ -163,28 +168,9 @@ bindkey '^r' history-incremental-search-backward
|
||||
# delete really deletes
|
||||
bindkey "^[[3~" delete-char
|
||||
|
||||
source_if_existing() {
|
||||
[[ -f "${1}" ]] && source "${1}"
|
||||
}
|
||||
|
||||
source_first_existing() {
|
||||
while (($#)); do
|
||||
if test -e "${1}" ; then
|
||||
source "${1}"
|
||||
return
|
||||
fi
|
||||
shift
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
have_command() {
|
||||
command -v "${1}" &>/dev/null
|
||||
}
|
||||
|
||||
if test -d ${HOME}/.local/bin ; then
|
||||
export PATH="${HOME}/.local/bin:${PATH}"
|
||||
fi
|
||||
path_prepend "${HOME}/.npm-packages/bin"
|
||||
path_prepend "${HOME}/.local/bin"
|
||||
|
||||
# Source extras and aliases if interactive
|
||||
if [[ $- == *i* ]] ; then
|
||||
@@ -231,7 +217,7 @@ if [[ $- == *i* ]] ; then
|
||||
if [[ ! -f "$DUMPFILE" || ( -n "$newest_comp" && "$newest_comp" -nt "$DUMPFILE" ) ]]; then
|
||||
compinit -i -d "$DUMPFILE"
|
||||
# Asynchronously compile the dump file with an atomic rename
|
||||
{ zcompile "$DUMPFILE.zwc.tmp" "$DUMPFILE" && mv -f "$DUMPFILE.zwc.tmp" "$DUMPFILE.zwc" } &!
|
||||
{ zcompile "$DUMPFILE.zwc.$$.tmp" "$DUMPFILE" && mv -f "$DUMPFILE.zwc.$$.tmp" "$DUMPFILE.zwc" } &!
|
||||
else
|
||||
compinit -C -i -d "$DUMPFILE"
|
||||
fi
|
||||
@@ -270,8 +256,7 @@ if [[ $- == *i* ]] ; then
|
||||
if command -v direnv >/dev/null 2>&1 ; then
|
||||
eval "$(direnv hook zsh)"
|
||||
fi
|
||||
test -e "${HOME}/.iterm2_shell_integration.zsh" && \
|
||||
source "${HOME}/.iterm2_shell_integration.zsh" || true
|
||||
source_if_existing "${HOME}/.iterm2_shell_integration.zsh"
|
||||
# mise, if installed
|
||||
command -v mise >/dev/null 2>&1 && eval "$(mise activate zsh)"
|
||||
|
||||
@@ -286,9 +271,11 @@ if [ -x /usr/bin/ack-grep ] ; then
|
||||
fi
|
||||
|
||||
# I want these first always
|
||||
PATH="${HOME}/bin:${PATH}"
|
||||
path_prepend "${HOME}/bin"
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
PATH="${HOME}/bin/macos:${PATH}"
|
||||
path_prepend "${HOME}/bin/macos"
|
||||
elif [[ "$(uname)" == "Linux" ]]; then
|
||||
path_prepend "${HOME}/bin/linux"
|
||||
fi
|
||||
|
||||
# Load any local settings
|
||||
@@ -314,6 +301,8 @@ typeset -U PATH
|
||||
|
||||
if [[ -n "$ZSH_PROFILE" ]]; then
|
||||
zshrc_end_time=$EPOCHREALTIME
|
||||
set +x
|
||||
exec 2>&3 3>&-
|
||||
# Calculation in ms using zsh floating point math
|
||||
elapsed_ms=$(( (zshrc_end_time - zshrc_start_time) * 1000 ))
|
||||
printf "zshrc done: %.0fms\n" "$elapsed_ms"
|
||||
|
||||
@@ -18,8 +18,15 @@ alert() {
|
||||
icon="error"
|
||||
fi
|
||||
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
# macOS notification
|
||||
local title="Finished: '$*'"
|
||||
local msg="Exit code: $ret"
|
||||
osascript -e "display notification \"$msg\" with title \"$title\""
|
||||
else
|
||||
# Send the notification with the executed command
|
||||
notify-send --urgency=low -i "$icon" "Finished: '$@'"
|
||||
fi
|
||||
|
||||
# Return the original exit code
|
||||
return $ret
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
ANDROID_HOME=$HOME/Library/Android/sdk
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
ANDROID_HOME=$HOME/Library/Android/sdk
|
||||
else
|
||||
ANDROID_HOME=$HOME/Android/Sdk
|
||||
fi
|
||||
|
||||
if test -d $ANDROID_HOME ; then
|
||||
PATH=$PATH:$ANDROID_HOME/emulator:$ANDROID_HOME/platform-tools
|
||||
if test -d "${ANDROID_HOME}" ; then
|
||||
export ANDROID_HOME
|
||||
PATH="${PATH}:${ANDROID_HOME}/emulator:${ANDROID_HOME}/platform-tools"
|
||||
else
|
||||
unset ANDROID_HOME
|
||||
fi
|
||||
|
||||
@@ -6,7 +6,11 @@ if have_command nasm && have_command objdump ; then
|
||||
local TMPF=`mktemp`
|
||||
local bytes
|
||||
local byte
|
||||
$NASM -f elf -o $TMPF $1
|
||||
local format="elf"
|
||||
if [[ "$OSTYPE" == darwin* ]]; then
|
||||
format="macho64"
|
||||
fi
|
||||
$NASM -f $format -o $TMPF $1
|
||||
$OBJDUMP -M intel -d $TMPF | grep '^ ' | cut -f2 | while read -A bytes ; do
|
||||
for byte in $bytes ; do
|
||||
echo -n "\\\\x$byte"
|
||||
|
||||
@@ -14,4 +14,8 @@
|
||||
have_command docker && \
|
||||
missing_comp _docker && \
|
||||
docker completion zsh > $COMPDIR/_docker || true
|
||||
|
||||
have_command resticprofile && \
|
||||
missing_comp _resticprofile && \
|
||||
resticprofile generate --zsh-completion > $COMPDIR/_resticprofile || true
|
||||
} &>/dev/null &!
|
||||
|
||||
@@ -1,26 +1,19 @@
|
||||
function dumpenv {
|
||||
if [ "$(uname)" = "Linux" ]; then
|
||||
tr '\0' '\n' < /proc/${1}/environ
|
||||
elif [ "$(uname)" = "Darwin" ]; then
|
||||
# macOS doesn't have /proc, use ps instead.
|
||||
# Note: this may truncate if environment is very large.
|
||||
ps -p ${1} -wwwe -o command= | tr ' ' '\n' | grep '='
|
||||
fi
|
||||
}
|
||||
|
||||
if test -x "/sbin/starship" ; then
|
||||
_STARSHIP_PATH="/sbin/starship"
|
||||
_STARSHIP_PATH="$(find_first "$(command -v starship)" /sbin/starship "${HOME}/tools/starship/starship" "${HOME}/.local/bin/starship" /usr/local/bin/starship)"
|
||||
if test -n "$_STARSHIP_PATH" ; then
|
||||
function starship_prompt {
|
||||
eval "$(/sbin/starship init zsh)"
|
||||
}
|
||||
elif test -x "${HOME}/tools/starship/starship" ; then
|
||||
_STARSHIP_PATH="${HOME}/tools/starship/starship"
|
||||
function starship_prompt {
|
||||
eval "$($HOME/tools/starship/starship init zsh)"
|
||||
eval "$($_STARSHIP_PATH init zsh)"
|
||||
}
|
||||
fi
|
||||
if test -f ${HOME}/.zprompt ; then
|
||||
if test "$(cat ${HOME}/.zprompt)" = "starship" ; then
|
||||
if test -n "${_STARSHIP_PATH:-}" ; then
|
||||
eval "$(${_STARSHIP_PATH} init zsh)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
unset _STARSHIP_PATH
|
||||
|
||||
function hashall {
|
||||
tee >(md5sum) | tee >(sha1sum) | sha256sum
|
||||
@@ -79,3 +72,27 @@ function generate_secure_key {
|
||||
local BYTES=$((BITS/8))
|
||||
head -c "${BYTES}" /dev/urandom | ${(s: :)ENCODE}
|
||||
}
|
||||
|
||||
function reset-ssh-socket {
|
||||
reset_ssh_socket "$@"
|
||||
}
|
||||
|
||||
function with-local-ssh-agent {
|
||||
local sock
|
||||
sock=$(get_local_ssh_agent_sock)
|
||||
if [[ -z "${sock}" ]] ; then
|
||||
echo "with-local-ssh-agent: no valid local ssh-agent socket found." >&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$#" -eq 0 ] ; then
|
||||
(
|
||||
export SSH_AUTH_SOCK="${sock}"
|
||||
"${SHELL:-zsh}"
|
||||
)
|
||||
else
|
||||
(
|
||||
export SSH_AUTH_SOCK="${sock}"
|
||||
eval "$@"
|
||||
)
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
test -f /usr/share/source-highlight/src-hilite-lesspipe.sh && \
|
||||
# Find src-hilite-lesspipe.sh
|
||||
_SRCHILITE=""
|
||||
for _p in /usr/share/source-highlight/src-hilite-lesspipe.sh /opt/homebrew/bin/src-hilite-lesspipe.sh /usr/local/bin/src-hilite-lesspipe.sh ; do
|
||||
if [ -f "$_p" ] ; then
|
||||
_SRCHILITE="$_p"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$_SRCHILITE" ] ; then
|
||||
function srcless {
|
||||
if [ $# -ne 1 ] ; then
|
||||
echo "$0 <what>" > /dev/stderr
|
||||
echo "Usage: srcless <file>" > /dev/stderr
|
||||
return 1
|
||||
fi
|
||||
/usr/share/source-highlight/src-hilite-lesspipe.sh $1 | less -R
|
||||
"$_SRCHILITE" "$1" | less -R
|
||||
}
|
||||
fi
|
||||
|
||||
unset _SRCHILITE _p
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
# Skelify -- move a file to my .skel and setup symlinks
|
||||
|
||||
function skelify {
|
||||
local -A opts
|
||||
zparseopts -D -A opts -overlay:
|
||||
|
||||
local overlay_name="${opts[--overlay]}"
|
||||
local base_skel_dir="${HOME}/.skel/dotfiles"
|
||||
local extra_args=()
|
||||
if [[ -n "${overlay_name}" ]]; then
|
||||
base_skel_dir="${HOME}/.skel/dotfile_overlays/${overlay_name}"
|
||||
extra_args=(--overlay "${overlay_name}")
|
||||
fi
|
||||
|
||||
local target
|
||||
local whichdir
|
||||
local relhome
|
||||
@@ -10,16 +21,19 @@ function skelify {
|
||||
local fulltarget
|
||||
for target in $~@; do
|
||||
if test -d ${target} ; then
|
||||
skelify ${target}/* || return 1
|
||||
skelify "${extra_args[@]}" ${target}/* || return 1
|
||||
elif test -f ${target} ; then
|
||||
if ! whichdir=$(cd $(dirname $target) && pwd); then
|
||||
echo Could not find directory for $target >/dev/stderr
|
||||
return 1
|
||||
fi
|
||||
fname=$(basename ${target})
|
||||
relhome=${whichdir#${HOME}/}
|
||||
fulltarget="${whichdir}/${fname}"
|
||||
if [[ ${relhome} == ${whichdir} ]] ; then
|
||||
if [[ ${whichdir} == ${HOME} ]] ; then
|
||||
relhome=""
|
||||
elif [[ ${whichdir} == ${HOME}/* ]] ; then
|
||||
relhome=${whichdir#${HOME}/}
|
||||
else
|
||||
echo ${whichdir} is not in home >/dev/stderr
|
||||
return 1
|
||||
fi
|
||||
@@ -32,7 +46,7 @@ function skelify {
|
||||
return 1
|
||||
fi
|
||||
echo ${target}
|
||||
local skeldir="${HOME}/.skel/dotfiles/${relhome}"
|
||||
local skeldir="${base_skel_dir}/${relhome}"
|
||||
mkdir -p "${skeldir}"
|
||||
mv ${target} "${skeldir}/${fname}"
|
||||
ln -s "${skeldir}/${fname}" "${fulltarget}"
|
||||
|
||||
56
dotfiles/zshrc.d/util.zsh
Normal file
56
dotfiles/zshrc.d/util.zsh
Normal file
@@ -0,0 +1,56 @@
|
||||
# utility function to "open" a file
|
||||
o() {
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
open "$@"
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
xdg-open "$@"
|
||||
else
|
||||
echo "Unknown OS"
|
||||
fi
|
||||
}
|
||||
|
||||
# Copy from stdin to the system clipboard
|
||||
syscopy() {
|
||||
if command -v pbcopy >/dev/null 2>&1; then
|
||||
# macOS
|
||||
pbcopy "$@"
|
||||
elif command -v wl-copy >/dev/null 2>&1; then
|
||||
# Linux Wayland
|
||||
wl-copy "$@"
|
||||
elif command -v xclip >/dev/null 2>&1; then
|
||||
# Linux X11
|
||||
xclip -selection clipboard "$@"
|
||||
elif command -v xsel >/dev/null 2>&1; then
|
||||
# Linux X11 (alternative)
|
||||
xsel --clipboard --input "$@"
|
||||
elif command -v clip.exe >/dev/null 2>&1; then
|
||||
# Windows WSL
|
||||
clip.exe "$@"
|
||||
else
|
||||
echo "Error: No clipboard utility found. Please install pbcopy, wl-copy, xclip, or xsel." >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Paste from the system clipboard to stdout
|
||||
syspaste() {
|
||||
if command -v pbpaste >/dev/null 2>&1; then
|
||||
# macOS
|
||||
pbpaste "$@"
|
||||
elif command -v wl-paste >/dev/null 2>&1; then
|
||||
# Linux Wayland
|
||||
wl-paste "$@"
|
||||
elif command -v xclip >/dev/null 2>&1; then
|
||||
# Linux X11
|
||||
xclip -selection clipboard -o "$@"
|
||||
elif command -v xsel >/dev/null 2>&1; then
|
||||
# Linux X11 (alternative)
|
||||
xsel --clipboard --output "$@"
|
||||
elif command -v powershell.exe >/dev/null 2>&1; then
|
||||
# Windows WSL
|
||||
powershell.exe -noprofile -command Get-Clipboard "$@"
|
||||
else
|
||||
echo "Error: No clipboard utility found. Please install pbpaste, wl-paste, xclip, or xsel." >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
165
install.sh
165
install.sh
@@ -7,14 +7,65 @@ set -o errexit
|
||||
set -o shwordsplit 2>/dev/null || true # Make zsh behave like bash
|
||||
|
||||
HOME=${HOME:-$(cd ~ && pwd)}
|
||||
LOCAL_BIN="${HOME}/.local/bin"
|
||||
STARSHIP_INSTALL_HASH="52c64f14a558034ebeb1907ea9364e802b32474576fd3e68265f73bc33cc8fbb"
|
||||
|
||||
# 1. Get the raw script path (handles Bash vs Zsh)
|
||||
TARGET="${BASH_SOURCE[0]}"
|
||||
|
||||
# 2. Loop to resolve symlinks completely
|
||||
while [ -L "$TARGET" ]; do
|
||||
DIR=$(cd -P "$(dirname -- "$TARGET")" &>/dev/null && pwd)
|
||||
TARGET=$(readlink "$TARGET")
|
||||
# If $TARGET is a relative symlink, resolve it relative to the symlink's directory
|
||||
[[ $TARGET != /* ]] && TARGET="$DIR/$TARGET"
|
||||
done
|
||||
|
||||
# 3. Get the final absolute directory
|
||||
SCRIPT_DIR="$(cd -P "$(dirname -- "$TARGET")" &>/dev/null && pwd)"
|
||||
|
||||
have_command() {
|
||||
command -v "${1}" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
raw_sha256sum() {
|
||||
local file="${1}"
|
||||
if [[ -z "${file}" ]]; then
|
||||
echo "Error: No file specified" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ ! -f "${file}" ]]; then
|
||||
echo "Error: File not found: ${file}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if have_command sha256sum ; then
|
||||
sha256sum "${file}" | awk '{print $1}'
|
||||
elif have_command shasum ; then
|
||||
shasum -a 256 "${file}" | awk '{print $1}'
|
||||
else
|
||||
echo "Error: Neither sha256sum nor shasum is available" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
sudo_group() {
|
||||
if [[ "$(id -u)" -eq 0 ]] ; then
|
||||
return 0
|
||||
fi
|
||||
have_command sudo && ( id -Gn | grep -q '\bsudo\b' )
|
||||
}
|
||||
|
||||
maybe_sudo() {
|
||||
if [[ "$(id -u)" -eq 0 ]] ; then
|
||||
"$@"
|
||||
return
|
||||
fi
|
||||
if ! have_command sudo ; then
|
||||
return 1
|
||||
fi
|
||||
sudo "$@"
|
||||
}
|
||||
|
||||
link_directory_contents() {
|
||||
local SRCDIR="${1}"
|
||||
@@ -35,48 +86,6 @@ link_directory_contents() {
|
||||
done
|
||||
}
|
||||
|
||||
ssh_key_already_installed() {
|
||||
# Return 1 if the key isn't already installed, 0 if it is
|
||||
local AK="${HOME}/.ssh/authorized_keys"
|
||||
if [[ ! -f "$AK" ]] ; then
|
||||
return 1
|
||||
fi
|
||||
# Extract the key data (field 2) from the key file, ignoring comments
|
||||
local key_data
|
||||
key_data=$(awk '/^ssh-/ {print $2}' "$1")
|
||||
if [[ -z "${key_data}" ]]; then
|
||||
# Not a valid key file
|
||||
return 1
|
||||
fi
|
||||
# Use grep with fixed-string matching to see if the key is present.
|
||||
# The exit code of grep is 0 on match, 1 on no match, which is perfect.
|
||||
grep -F -q -- "${key_data}" "${AK}"
|
||||
}
|
||||
|
||||
install_ssh_keys() {
|
||||
# Install SSH keys
|
||||
verbose 'Installing SSH keys...'
|
||||
local AK="${HOME}/.ssh/authorized_keys"
|
||||
local key
|
||||
local keydir
|
||||
if [[ "${TRUST_ALL_KEYS}" = 1 ]] ; then
|
||||
keydir="${BASEDIR}/keys/ssh"
|
||||
else
|
||||
keydir="${BASEDIR}/keys/ssh/trusted"
|
||||
fi
|
||||
for key in "${keydir}"/* ; do
|
||||
if [[ ! -f "${key}" ]] ; then
|
||||
continue
|
||||
fi
|
||||
if ssh_key_already_installed "${key}" ; then
|
||||
verbose "Key $(basename "${key}") already installed..."
|
||||
continue
|
||||
fi
|
||||
echo "# $(basename "${key}") added from skel on $(date +%Y-%m-%d)" >> "${AK}"
|
||||
cat "${key}" >> "${AK}"
|
||||
done
|
||||
}
|
||||
|
||||
install_gpg_keys() {
|
||||
have_command gpg || \
|
||||
return 0
|
||||
@@ -90,7 +99,7 @@ install_known_hosts() {
|
||||
verbose 'Installing known hosts...' >&2
|
||||
local skel_hosts="${BASEDIR}/keys/known_hosts"
|
||||
local user_hosts="${HOME}/.ssh/known_hosts"
|
||||
local merge_script="${BASEDIR}/skeltools/merge_authorized_keys"
|
||||
local merge_script="${BASEDIR}/skeltools/merge_known_hosts"
|
||||
|
||||
if [[ ! -f "${skel_hosts}" ]]; then
|
||||
return 0
|
||||
@@ -121,7 +130,10 @@ install_known_hosts() {
|
||||
}
|
||||
|
||||
install_keys() {
|
||||
install_ssh_keys
|
||||
if [[ -x "${BASEDIR}/bin/update-authorized-keys" ]]; then
|
||||
verbose 'Installing SSH keys via update-authorized-keys...'
|
||||
printf 'y\n' | "${BASEDIR}/bin/update-authorized-keys"
|
||||
fi
|
||||
install_gpg_keys
|
||||
install_known_hosts
|
||||
}
|
||||
@@ -139,13 +151,12 @@ read_saved_prefs() {
|
||||
|
||||
save_prefs() {
|
||||
[[ "$SAVE" = 1 ]] || return 0
|
||||
local pref_file=${BASEDIR}/.installed-prefs
|
||||
local pref_file="${BASEDIR}/.installed-prefs"
|
||||
{
|
||||
echo "BASEDIR=\"${BASEDIR}\""
|
||||
echo "MINIMAL=\"${MINIMAL}\""
|
||||
echo "INSTALL_KEYS=\"${INSTALL_KEYS}\""
|
||||
echo "TRUST_ALL_KEYS=\"${TRUST_ALL_KEYS}\""
|
||||
echo "VERBOSE=\"${VERBOSE}\""
|
||||
printf 'BASEDIR=%q\n' "${BASEDIR}"
|
||||
printf 'MINIMAL=%q\n' "${MINIMAL}"
|
||||
printf 'INSTALL_KEYS=%q\n' "${INSTALL_KEYS}"
|
||||
printf 'VERBOSE=%q\n' "${VERBOSE}"
|
||||
} >| "$pref_file"
|
||||
}
|
||||
|
||||
@@ -176,6 +187,55 @@ install_dotfiles() {
|
||||
fi
|
||||
}
|
||||
|
||||
install_starship() {
|
||||
if have_command starship ; then return 0 ; fi
|
||||
|
||||
if have_command brew ; then
|
||||
verbose "Attempting to install Starship via Homebrew..."
|
||||
if brew install starship ; then
|
||||
return 0
|
||||
fi
|
||||
echo "brew install starship failed, trying other methods..." >&2
|
||||
fi
|
||||
|
||||
if have_command apt-get && sudo_group ; then
|
||||
if maybe_sudo apt-get install -qy starship ; then
|
||||
return 0
|
||||
fi
|
||||
echo "apt-get install starship failed, installing locally" >&2
|
||||
fi
|
||||
local tmpd
|
||||
tmpd="$(mktemp -d "${TMPDIR:-/tmp}/starship.XXXXXX")" || return 1
|
||||
|
||||
local install_path="${tmpd}/install.sh"
|
||||
if have_command curl ; then
|
||||
curl -sSL --show-error -o "${install_path}" https://starship.rs/install.sh
|
||||
elif have_command wget ; then
|
||||
wget -q -O "${install_path}" --https-only https://starship.rs/install.sh
|
||||
else
|
||||
echo "No curl or wget available!!" >&2
|
||||
rm -rf "${tmpd}"
|
||||
return 1
|
||||
fi
|
||||
local dl_hash
|
||||
dl_hash="$(raw_sha256sum "${install_path}")"
|
||||
if [[ "$dl_hash" != "${STARSHIP_INSTALL_HASH}" ]] ; then
|
||||
echo "Hash check failed!!" >&2
|
||||
echo "Expected: ${STARSHIP_INSTALL_HASH}, got ${dl_hash} on ${install_path}" >&2
|
||||
rm -rf "${tmpd}"
|
||||
return 1
|
||||
fi
|
||||
if sudo_group ; then
|
||||
if maybe_sudo sh "${install_path}" ; then
|
||||
rm -rf "${tmpd}"
|
||||
return 0
|
||||
fi
|
||||
echo "root installation failed, falling back to user-local" >&2
|
||||
fi
|
||||
sh "${install_path}" -b "${LOCAL_BIN}"
|
||||
rm -rf "${tmpd}"
|
||||
}
|
||||
|
||||
install_main() {
|
||||
if [[ -d "${BASEDIR}/.git" ]] && have_command git ; then
|
||||
if [[ -z "$(git -C "${BASEDIR}" status --porcelain)" ]]; then
|
||||
@@ -185,6 +245,8 @@ install_main() {
|
||||
fi
|
||||
fi
|
||||
[[ "$MINIMAL" = 1 ]] || {
|
||||
mkdir -p "${LOCAL_BIN}"
|
||||
install_starship
|
||||
|
||||
# Install vim-plug if not already present
|
||||
local VIM_PLUG_URL="https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim"
|
||||
@@ -243,10 +305,9 @@ read_saved_prefs
|
||||
|
||||
# Defaults if not passed in or saved.
|
||||
# TODO: use flags instead of environment variables.
|
||||
: ${BASEDIR:=$HOME/.skel}
|
||||
: ${BASEDIR:=${SCRIPT_DIR}}
|
||||
: ${MINIMAL:=0}
|
||||
: ${INSTALL_KEYS:=1}
|
||||
: ${TRUST_ALL_KEYS:=0}
|
||||
: ${VERBOSE:=0}
|
||||
: ${SAVE:=1}
|
||||
|
||||
|
||||
@@ -1,3 +1,51 @@
|
||||
|1|ZWm0E5aueYzKuoY8OrGAI2ZUdWI=|L8KgVjGyomaw47OGrhpPnipXDKU= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKX08QrgyP7du28Re9NlKxLm6aJFUD4F2vWBCuiqo7KNrIPbgjVP9yOwy2gXueC6fbuVQj/C4BdnkgHw9hFXbC0=
|
||||
|1|MjwrIkZqV0wbZ7pWue9nsFREyhk=|lGN2O8BcMHleUkD4yBtYRXSm1Yw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwbTUJWJ3mytxrYPKrzRDIuBRd+/X/3T/QT2gudQfDN/mxkAMTg+uLoObXnUOtfhXD+lXP/s/GKXoPmsV/ausSz2YxBrQQXH7SwCpUq5GRXcl5s43JAJ1MbQq2EA5pa1CEBzUgd/Osu/WaVsKwfABV7QeKhblMfM0a5XcsfawqVbMJ0q/egYiSsWRVTU2iNMXILChJT6WUVoUiDENRnW98iy1qQgY0ge6hr7Gh6m23Fg6yfYDBQrqszbTfFYlqGe54bGlnxZvGp+Ybas02D29whAHwdNCSmDWXW0EvSpyt9WZUm0WOQt3t9RXpKeKLrWH4V/5BFYrONY1GsKuE783tw==
|
||||
|1|UsEB5ylyIdmc4gs4TsYqE570DWY=|HAKqUTgFyTzodg8h6veV5jIa9GY= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC75TncmMQKEnnyw1S/uHcvs88d2M1NTMSUZyqdvFbx/uRB2rlrJiQHK8vyvN+fgRH5x8vde+vz/lAFgySV9RoS676cMuBIC8usF8REX2ghSXiSoGw35gd2ztGiDdU7FLUQYW+8FkR1soRjKZgyHqP/NCr4jBXjqDawDE33MA5LdmYy7fl1RN3oK4sY+LIoUWVv5x1aJdV86m0zbciavpU5szL++rnwcx+nWjDFFP4ntH1XyPGftyYpIAZwX+2Vl0+uMgv6sHazOx1E6vOIMx1UapCeLyWXzJ49P8K4iBZcNPH6h9aYllF4PIJ97Auh+fpFKBPfmHLq4iKCz4kKByy7
|
||||
# ts-jumpbox.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
|
||||
ts-jumpbox.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKwbpYiRqlgLKbaUlt1k4ms14+vTW8LKequepWdqDUUx
|
||||
# ts-jumpbox.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
|
||||
ts-jumpbox.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC2itf2fAUO5OB7BNAL9Js8pmxIwzLnOxRMexf5KGswUQRvaZwtw1CitJiyEcYWBt7zksd/Pupmp42ikPVoH7myQlWRbeEmJEIlMvkFF0pjAWj9kGKVLyFDbqXSkewKtXwbJHSo0l+mEOyq8NLlOwAA977BzNTn4z3KQEfYBQQEqISa8NuLpVOFvtQfvBlW+Xeh6+rIm54gdJVDWRimvZ5/FUMaRHPBdMFcXZW1GpraAHjHMeJXTIJs10qFy+5RwGTL5UlvssI+IPAIAW7o0goWmCnrlTjhvJ3Mnwq2lQhAuH/aDqVTptXwMni8tkvPFEC4LeoXG9pmb04Fd6bxY4RnvWuTmcvqOGAxJmZcqOYp1qWhyIF4TTB5l4h3J27sUtluEkTbIGtxTcPjFYLLC1lyIweoQSjWTmi5Z4wz1qfxIYZY1UXnyAjILvLAA5XAIpTgVfDx9KMAFdRrqaKN1MMFvfkTy7CZOfIkWhBwuOxMmtknsiJi8INZc+2CWUuI3Q8=
|
||||
# ts-jumpbox.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
|
||||
ts-jumpbox.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFs4yUU1aYjy5kq0vr8PFEJUA5s90lYzFTXwHuL9JwtL/wi7tC3I1ifyQnzfZIT8ORMHNGdz/DjNyKkE/rfDhEc=
|
||||
# ts-jumpbox.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
|
||||
# ts-jumpbox.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
|
||||
# omega.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u2
|
||||
omega.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQD7TIDPujGWOMkltfBUKoXOIX9W6KBbqT4qfANNivyjvYeS2joncfoCHTws3vTofHjfyzUSFpnjJSjbwoqTK38CsqSMx06KgpOiiz03+OVbtoBKiwY7smYXh2/vB53+EV4fnM1u/6AqAn0FYT/lUjaY6kBWDppW7PbFKRtO+wShMNfbaY1BTDyEEZRU3PCxR4UDXFO7fQLBiQb/XOyxsSXdRtP6BPrpqxUSq/hNchRo4AP08wtEY5iW9po1RMOFAMKPDND34CyWGbtfnpUCAk9jwKrKDRibRZgIe/xWNcXY9P9zuCSMByB3npo2lG2Em/usiO2awY1pcfrHrlfxJFnD+rzQ9LELwvSB8kPd5xlxZjqmNIvACGEYzR2zdbeOXy+G7biQ7cgELIFRF9aDKOe68sSss3SdS2suAXpqtNBE6l8T9u2jUD0po5EsDcNXPHCS8YLq4wyTpkeDAchX4xm8srycvPD9h4UAE9k+QqjkkbUQw/xpx0SL4pq8Xi6VuO0=
|
||||
# omega.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u2
|
||||
omega.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBL9cVRkixwE7KL112abP+GosO9+MiVUZQqUdRh4ps5O733cJ8tvkqLVkJhEejIFX6BLlmh/l+j/mD4Z8dL/YqmU=
|
||||
# omega.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u2
|
||||
omega.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMoxyWy+cXdpxh/KOhbvzB8Tq7NgWTHofOOpeVzuESe0
|
||||
# omega.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u2
|
||||
# omega.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u2
|
||||
# xi.systemoverlord.com:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
|
||||
# xi.systemoverlord.com:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
|
||||
xi.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCosFo3gGbGQ7PvHzVZ50umQNEILsqkHWnDi2FqHBCV/pQKUlZVuBO2HT0MiV3QkascJ58P4Jj1Ft/ILKvrU5/dDsW8xVs3vJlmHPrmovD93VwuarzlokmzxWPFOEPZIPcQcQcMCt6k4p/6Pb6hbmPGML2N7XGQHGVDFcflusx07wj56lP9xUtdOLcIo9u3rgw2puXqxUNRtx12Dfo9rjGiFFCXCrvFV5BG4utHKSyAOckJQ/oTzy++idM7jaPbnQ0qjH4GMHm2HN8bmWJdHjc6BeBEW4iQrUxNeisM/hKiICZ3kUmeEynx6IlgEXm0UT+AhxZL7BQo9X45pj5AvaU5
|
||||
# xi.systemoverlord.com:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
|
||||
xi.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBN49oL4rzjwfz5F7cUuVhqe9vRzDAE16O5NQvslhpOx3VA7g8qjyK4SmhhRll+N7vS7OvUqswjEIOXFdK2DUGq8=
|
||||
# xi.systemoverlord.com:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
|
||||
xi.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIg6N+lwA6feLnLDlm6Ssp45YjnaeCCQSBzeidmAb7FY
|
||||
# xi.systemoverlord.com:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
|
||||
# chi.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
|
||||
chi.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC7jSON+Pum/scQMwiBH0jI2fKfQ4q6YKBf/Q/uU7RiEzr3g5lRLA3RtFfWYlxSVqRdlQgeTvIRqG6VMQjtxm/UiLaNT82dVSgoSwJnODVWsKzWQNY1nkhGgd/Ue/XQrBi6UFB7QU7iiIHn8FmJDh05jLv4ymp3DuUM6W066cHqVMSslVhsioAJeZJdpFFK0WXbWs8PT83LT1LERP8CMWuaVlF4UxWwaxROA4WwWaUtiMm0e7T9AgCkHmmEWJemrJqkKUBU0BaqyIvF2bP4tNrZXM8EzT+2Dg25BWS6DzP/d7m8umrpQrYP7cbhK0jzNXw/niEjQ7f8ZiuguRGwWBKX0XjMPY36uiBE/bkGiyF2t27nSPyoA/I2CYtArAabVmiNTeK6qpgf1Xo+aBFuotS3+4Ql+9kfzO9ZL05xIBC2PzvL1pqWmTHI4GICLS2EdMks8LW5ZxvjMS0OdrVf1KaMgmr8TbJT+NIqs1SF3H5kmWUtMvQd4YJgU+o88/sO9LM=
|
||||
# chi.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
|
||||
chi.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIo6eEuZ1F1GGnkJqkyUTj4oGZlcADbmdahSiwif6pWcx6uGdSemPjQmhFknPbzpzH8HIUtrg/NSBGAjwVINz5Q=
|
||||
# chi.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
|
||||
chi.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINVUVuOLnuVRiUptQxn+HlUtgv4i5+DMK4uyN4voCB1R
|
||||
# chi.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
|
||||
# chi.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
|
||||
# tau.systemoverlord.com:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
|
||||
tau.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMUffrd05Q6iyHj1vbvBzD+xWqR6c/YivTieWVim+b2wHEEYyh7eHXzldXZdLP3QOQHXWc68QwfSav5jsrVhsxk=
|
||||
# tau.systemoverlord.com:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
|
||||
tau.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/vDSvxXQa20+5OjgQpzxMQZR3m80fsIzHNqfjjAGlVTfPuccMnfCXNgQc8mY8qQTMxbBU4ZlSjntjyIBhWoj5flrTpVjHJgAkntu1dhtDYOp8sd+9CsR/40SX/1l8d6fRzuPSZaVO+RpF9Ym/MrxYH8YprBswl4pzT3/DVCgq3DDNocLzmyjMCgQJXxYpKhlnRSxhLvPHeAi4p0/gHmYhtQe4r0DZ/QaU6a/4bU2shGQyKBUUJbRTrNYwAEukZk+U5AkoQ7N43THB1PtdC0PwmaD2yXHiKzR/6SfLWRBE6TqyQKB0R8+lWWIU5s0Nu512UUS78bchkTtU0mgTpQWP
|
||||
# tau.systemoverlord.com:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
|
||||
tau.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK9+GZcp2imEoxDKY3rxdwGARZ6o/vmPCqrRF9ghxhLa
|
||||
# tau.systemoverlord.com:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
|
||||
# tau.systemoverlord.com:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
|
||||
# zeta.systemoverlord.com:22 SSH-2.0-OpenSSH_10.3p1 Debian-4
|
||||
zeta.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBOPOADAIuJ/khxquXi1/wHyJUp1LqmfLVuHnGoqYouZc7AKcwWDOd30p5bSbrgGMXQC6oflMUsL1VL8hyqZPhs=
|
||||
# zeta.systemoverlord.com:22 SSH-2.0-OpenSSH_10.3p1 Debian-4
|
||||
zeta.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWTvGafS9utruAmLpDdohEiEWSWVq3H6Mj1Z/hwnjVn67UncYDwLJjZem22r6qnW9h8hF9qpIG+XtU9Yk4iEvUk2H9S3gb7UOxwJ29lx2ckFp8V8Ml9t9gwrNpCVL+oiLm+iCmYMctksWbNXuiGRX22/qfeiM2zwyV3tEWbs/ePtVs5RX0EhbqPR5NHazy0NspE+lLsKeoGT5KsjyehStY69ER4iPKJzeiUxYfXj9wafniNiPZPV9jCDH4DIhkUWoOc1DF0cItVGLRnAWFoAEaWoIfC4ou33cuIfk810kf9uwSTgjVtGiGOC9Pemfc3RsFiUtlg4wpyAerBIvJlvrMAdPRhd1Pteg6QzWYbz0/3dGtyURjRg3uZQIiMre3zHHSKDQbdBL5C+9dM+d/PMdN+86GgwfymPHLoUsRpoY/1yxxqq8Zjc7D40amParpXHOkPzMLJy1F8d10QB52ZDx/7ivuPK55WaWiL3jcBLdim/I2te8EWwR0IgKGlkRYL88=
|
||||
# zeta.systemoverlord.com:22 SSH-2.0-OpenSSH_10.3p1 Debian-4
|
||||
zeta.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPLOty9tztaPoyNUY50daxN3l8rM5+Eg1vMfqefgHWLT
|
||||
# zeta.systemoverlord.com:22 SSH-2.0-OpenSSH_10.3p1 Debian-4
|
||||
# zeta.systemoverlord.com:22 SSH-2.0-OpenSSH_10.3p1 Debian-4
|
||||
|
||||
Reference in New Issue
Block a user