mirror of
https://github.com/Matir/skel.git
synced 2026-05-26 13:35:42 -07:00
Compare commits
149 Commits
2023-08-20
...
ce973d5bbf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce973d5bbf | ||
|
|
f326992306 | ||
|
|
7f76b24cb9 | ||
|
|
a5b08680c5 | ||
|
|
2510f1ad87 | ||
|
|
b6af18017b | ||
|
|
829f7ae1de | ||
|
|
6fd9769ccc | ||
|
|
758c59bc8e | ||
|
|
39e003f666 | ||
|
|
5b1bb1c233 | ||
|
|
2e0ebb4d6f | ||
|
|
31aeca1b73 | ||
|
|
7006974bb3 | ||
|
|
92fb8cb47d | ||
|
|
a46ee1f24c | ||
|
|
c1b565f2c5 | ||
|
|
0ded57fa46 | ||
|
|
f1495add30 | ||
|
|
a6146c2763 | ||
|
|
60f68f11a2 | ||
|
|
a1262e9fba | ||
|
|
d5a3ed41c6 | ||
|
|
295ef071ee | ||
|
|
313c16bdc9 | ||
|
|
fad65e2aaa | ||
|
|
00696b23fa | ||
|
|
1c0c5dd32b | ||
|
|
8cac819127 | ||
|
|
0ebc32e30a | ||
|
|
a0378fb583 | ||
|
|
3cad40f858 | ||
|
|
6bda0bb639 | ||
|
|
c1d0045f44 | ||
|
|
f50edc1fa6 | ||
|
|
9ab1f9c298 | ||
|
|
cdbc40d1e8 | ||
|
|
487dbe3751 | ||
|
|
aea7b0927e | ||
|
|
645b631afc | ||
|
|
b631471b0c | ||
|
|
fb7636f5f1 | ||
|
|
20a5885031 | ||
|
|
21b24b2c2f | ||
|
|
122dc2075b | ||
|
|
c0fd99afd6 | ||
|
|
0ebb331cb3 | ||
|
|
bddd4ed107 | ||
|
|
a92b05a51c | ||
|
|
5a49dd95b2 | ||
|
|
d9223c92dc | ||
|
|
4c9038c33d | ||
|
|
9a04b847ec | ||
|
|
c1ef9f5e7a | ||
|
|
5a4d04ea43 | ||
|
|
f4e3447eb7 | ||
|
|
ff0a7d150d | ||
|
|
657d30c381 | ||
|
|
5cc08e472e | ||
|
|
89ae97145e | ||
|
|
d50faa1ec6 | ||
|
|
243da55c86 | ||
|
|
0e491395da | ||
|
|
b7cbf90ac7 | ||
|
|
9e1ad38f94 | ||
|
|
821c2f8b80 | ||
|
|
4e3b466044 | ||
|
|
fe5b74511f | ||
|
|
f80b029ae3 | ||
|
|
d4a4d8ee19 | ||
|
|
375ff434f2 | ||
|
|
e270bac5f2 | ||
|
|
2b31d4d5d2 | ||
|
|
91920fef0e | ||
|
|
f2faccd93f | ||
|
|
dea3f289c2 | ||
|
|
61d00103bf | ||
|
|
2122c88e03 | ||
|
|
7064a5d5a1 | ||
|
|
ae344d6dba | ||
|
|
d7b6095c47 | ||
|
|
c7777ede0b | ||
|
|
6c2c12faeb | ||
|
|
7e9a87afdd | ||
|
|
d6cd16e9f0 | ||
|
|
3548113a7d | ||
|
|
f3e82690f8 | ||
|
|
d596d10678 | ||
|
|
0406395ea0 | ||
|
|
c9ed72a5a6 | ||
|
|
5e65608c39 | ||
|
|
acb13c6908 | ||
|
|
9b9330db45 | ||
|
|
4743b635aa | ||
|
|
bbeb451251 | ||
|
|
5057ab890b | ||
|
|
ee7f78e99c | ||
|
|
0b5ca1cefc | ||
|
|
ab2f62345f | ||
|
|
05df603332 | ||
|
|
ca71dea284 | ||
|
|
00bbe65691 | ||
|
|
de8d2cf608 | ||
|
|
a81e6e9e8d | ||
|
|
52d05c400d | ||
|
|
83b7adf1ca | ||
|
|
f6d7f22a77 | ||
|
|
746653d28d | ||
|
|
695cef6cb3 | ||
|
|
e0eebe2641 | ||
|
|
d5024a536d | ||
|
|
d10f82d088 | ||
|
|
6ffae42e33 | ||
|
|
5658c61627 | ||
|
|
e227b65d6d | ||
|
|
569199a280 | ||
|
|
61e81f33c8 | ||
|
|
422c56139f | ||
|
|
15c118583a | ||
|
|
31c2783286 | ||
|
|
1131b46e44 | ||
|
|
fecdf1f67e | ||
|
|
38c21397cf | ||
|
|
b2eff8284c | ||
|
|
ef902daa1c | ||
|
|
42361045bc | ||
|
|
a45afefca4 | ||
|
|
d40eb6b0a7 | ||
|
|
2c26051817 | ||
|
|
b7b16e20a6 | ||
|
|
f6573e30b2 | ||
|
|
43e8661036 | ||
|
|
55823417eb | ||
|
|
eab08b1c95 | ||
|
|
560f803455 | ||
|
|
c6fe0ff1c8 | ||
|
|
05c910e675 | ||
|
|
efe093471c | ||
|
|
e99d20e47e | ||
|
|
a3fb4c5e66 | ||
|
|
f9a48c70c4 | ||
|
|
d072e3a5dd | ||
|
|
ce13fbc610 | ||
|
|
45be3e45f1 | ||
|
|
442127f7c1 | ||
|
|
87797ca803 | ||
|
|
7c1c5cfbd7 | ||
|
|
6a9358cd21 | ||
|
|
a195f0310d |
6
.Brewfile.ignore
Normal file
6
.Brewfile.ignore
Normal file
@@ -0,0 +1,6 @@
|
||||
# Add package names here to ignore them in Brewfile updates.
|
||||
# One package per line.
|
||||
# Example:
|
||||
# iterm2
|
||||
# wget
|
||||
orbstack
|
||||
5
.gemini/settings.json
Normal file
5
.gemini/settings.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"context": {
|
||||
"fileName": "AGENTS.md"
|
||||
}
|
||||
}
|
||||
3
.git-crypt/.gitattributes
vendored
3
.git-crypt/.gitattributes
vendored
@@ -1,3 +0,0 @@
|
||||
# Do not edit this file. To specify the files to encrypt, create your own
|
||||
# .gitattributes file in the directory where your files are.
|
||||
* !filter !diff
|
||||
Binary file not shown.
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
private_dotfiles/** filter=git-crypt diff=git-crypt
|
||||
|
||||
80
.githooks/githooks.sh
Executable file
80
.githooks/githooks.sh
Executable file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# --- 1. Identity Resolution ---
|
||||
# Finds the physical location of this script, regardless of symlinks
|
||||
REAL_PATH=$(realpath "$0")
|
||||
REAL_NAME=$(basename "$REAL_PATH")
|
||||
HOOKS_DIR=$(dirname "$REAL_PATH")
|
||||
CALLED_AS=$(basename "$0")
|
||||
|
||||
# --- 2. Self-Installation / Sync Logic ---
|
||||
if [ "$CALLED_AS" == "$REAL_NAME" ]; then
|
||||
echo "🔧 Synchronizing Git Hook Dispatcher..."
|
||||
|
||||
# Point Git to this directory
|
||||
git config core.hooksPath "$HOOKS_DIR"
|
||||
|
||||
# Create symlinks for any [hook-name].d directories found
|
||||
for d in "$HOOKS_DIR"/*.d/; do
|
||||
[ -d "$d" ] || continue
|
||||
HOOK_NAME=$(basename "$d" .d)
|
||||
TARGET="$HOOKS_DIR/$HOOK_NAME"
|
||||
|
||||
if [ ! -L "$TARGET" ]; then
|
||||
ln -sf "$REAL_NAME" "$TARGET"
|
||||
chmod +x "$TARGET"
|
||||
echo " ✨ Linked: $HOOK_NAME"
|
||||
fi
|
||||
done
|
||||
|
||||
# Cleanup: Remove symlinks that no longer have a matching .d directory
|
||||
for link in "$HOOKS_DIR"/*; do
|
||||
if [ -L "$link" ] && [ "$(basename "$link")" != "$REAL_NAME" ]; then
|
||||
if [ ! -d "${link}.d" ]; then
|
||||
rm "$link"
|
||||
echo " 🗑️ Removed: $(basename "$link")"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "✅ Done."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- 3. Selective Stdin Buffering ---
|
||||
# Buffer stdin only for hooks that expect it to prevent hanging/performance hits
|
||||
STDIN_DATA=""
|
||||
case "$CALLED_AS" in
|
||||
pre-push|post-rewrite|pre-receive|post-receive|reference-transaction)
|
||||
# Check if stdin has data (is not a terminal)
|
||||
if [ ! -t 0 ]; then
|
||||
STDIN_DATA=$(cat)
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- 4. Dispatch Logic ---
|
||||
SUB_HOOK_DIR="${HOOKS_DIR}/${CALLED_AS}.d"
|
||||
|
||||
if [ -d "$SUB_HOOK_DIR" ]; then
|
||||
# Sort files naturally so 01- runs before 02-
|
||||
for script in $(ls "$SUB_HOOK_DIR" | sort); do
|
||||
FULL_PATH="$SUB_HOOK_DIR/$script"
|
||||
[ -x "$FULL_PATH" ] || continue
|
||||
|
||||
# Replay stdin if we captured it, otherwise execute normally
|
||||
if [ -n "$STDIN_DATA" ]; then
|
||||
echo "$STDIN_DATA" | "$FULL_PATH" "$@"
|
||||
else
|
||||
"$FULL_PATH" "$@"
|
||||
fi
|
||||
|
||||
# Exit immediately if any sub-script fails
|
||||
EXIT_CODE=$?
|
||||
if [ $EXIT_CODE -ne 0 ]; then
|
||||
echo "❌ Hook '$CALLED_AS' failed at: $script"
|
||||
exit $EXIT_CODE
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
exit 0
|
||||
1
.githooks/pre-commit
Symbolic link
1
.githooks/pre-commit
Symbolic link
@@ -0,0 +1 @@
|
||||
githooks.sh
|
||||
20
.githooks/pre-commit.d/05-check-brewfile
Executable file
20
.githooks/pre-commit.d/05-check-brewfile
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Check if Brewfile needs updating
|
||||
if [[ "$(uname)" != "Darwin" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# We use the script we just created
|
||||
UPDATE_SCRIPT="bin/macos/update_brewfile"
|
||||
|
||||
if [[ -x "$UPDATE_SCRIPT" ]]; then
|
||||
# Run in dry-run mode and see if there's output
|
||||
DIFF_OUTPUT=$("$UPDATE_SCRIPT" --dry-run 2>/dev/null)
|
||||
if [[ "$DIFF_OUTPUT" == *"Changes detected"* ]]; then
|
||||
echo "⚠️ Brewfile is out of sync with your installed packages."
|
||||
echo " Run '$UPDATE_SCRIPT' to synchronize it."
|
||||
echo ""
|
||||
# We don't fail the commit, just warn.
|
||||
fi
|
||||
fi
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,5 +4,6 @@ installed-prefs
|
||||
*~
|
||||
*.bak
|
||||
local_dotfiles
|
||||
dotfile_overlays
|
||||
dotfile_overlays/*
|
||||
!dotfile_overlays/.keep
|
||||
!dotfile_overlays/README
|
||||
|
||||
25
.gitmodules
vendored
25
.gitmodules
vendored
@@ -1,24 +1 @@
|
||||
[submodule "dotfiles/vim/pack/matir/opt/solarized8"]
|
||||
path = dotfiles/vim/pack/matir/opt/solarized8
|
||||
url = https://github.com/lifepillar/vim-solarized8.git
|
||||
fetchRecurseSubmodules = true
|
||||
[submodule "dotfiles/vim/pack/matir/start/surround"]
|
||||
path = dotfiles/vim/pack/matir/start/surround
|
||||
url = https://github.com/tpope/vim-surround.git
|
||||
fetchRecurseSubmodules = true
|
||||
[submodule "dotfiles/vim/pack/matir/start/editorconfig"]
|
||||
path = dotfiles/vim/pack/matir/start/editorconfig
|
||||
url = https://github.com/editorconfig/editorconfig-vim.git
|
||||
fetchRecurseSubmodules = true
|
||||
[submodule "dotfiles/vim/pack/matir/start/fugitive"]
|
||||
path = dotfiles/vim/pack/matir/start/fugitive
|
||||
url = https://github.com/tpope/vim-fugitive
|
||||
fetchRecurseSubmodules = true
|
||||
[submodule "dotfiles/vim/pack/matir/start/ctrlp"]
|
||||
path = dotfiles/vim/pack/matir/start/ctrlp
|
||||
url = https://github.com/ctrlpvim/ctrlp.vim.git
|
||||
fetchRecurseSubmodules = true
|
||||
[submodule "dotfiles/tmux/tmux-logging"]
|
||||
path = dotfiles/tmux/tmux-logging
|
||||
url = https://github.com/tmux-plugins/tmux-logging.git
|
||||
fetchRecurseSubmodules = true
|
||||
|
||||
|
||||
69
AGENTS.md
Normal file
69
AGENTS.md
Normal file
@@ -0,0 +1,69 @@
|
||||
## Installation and Environment
|
||||
|
||||
This is a set of dotfiles and utilities for setting up my personal environment
|
||||
on POSIX-style environments. It is cloned from github and installed from the
|
||||
`install.sh` script.
|
||||
|
||||
It mostly relies on symlinking dotfiles and other resources into the appropriate
|
||||
locations, but also installs dependencies in various ways.
|
||||
|
||||
I primarily target Debian Linux-based (Debian, Ubuntu, and Kali Linux) systems
|
||||
as well as MacOS. Other platforms are lower priorities. Shell scripts ending
|
||||
in `.sh` should use only POSIX features unless there is a shebang line at the
|
||||
beginning suggesting a different shell will be used.
|
||||
|
||||
`zsh` and `fish` are the key interactive shells to be configured, but `bash`
|
||||
may also be used at times.
|
||||
|
||||
## Project Structure
|
||||
|
||||
* `bin/`: Contains executable scripts symlinked to `~/bin/`. Subdirectories like `macos/`, `restic/`, and `setup/` are included.
|
||||
* `dotfiles/`: Contains configuration files (dotfiles) symlinked to the home directory.
|
||||
* `dotfile_overlays/`: Each directory within is symlinked to the home directory, allowing for modular or git-submodule-based configurations.
|
||||
* `local_dotfiles/`: If present, its contents are symlinked to the home directory (ignored by git).
|
||||
* `packages/`: Contains lists of packages (one per line) for different environments or toolsets.
|
||||
* `keys/`: Contains SSH keys (`ssh/`), GPG keys (`gpg/`), and a `known_hosts` file to be installed/merged.
|
||||
* `skeltools/`: Internal utilities used by the installation scripts.
|
||||
* `sysctl/` and `udev/`: Linux system configuration files.
|
||||
* `Brewfile`: Homebrew package list for macOS environments.
|
||||
* `install.sh`: The primary installation script for symlinking and basic setup.
|
||||
|
||||
## Notes on Security Issues
|
||||
|
||||
It is safe to have scripts and tools re-invoke themselves with sudo when they
|
||||
require elevated privileges, as these are my own. Do not attempt to remove
|
||||
these use cases.
|
||||
|
||||
## Making Changes
|
||||
|
||||
**IMPORTANT**: Only make those changes which are explicitly requested. If you
|
||||
identify other issues, notify me about them, but do not suggest changes until I
|
||||
ask for them.
|
||||
|
||||
When making large changes, explain your chain of thought transparently and
|
||||
explain solution design.
|
||||
|
||||
If making changes that affects how the user installs the tools, update
|
||||
`README.md` accordingly.
|
||||
|
||||
### Adding a new dotfile
|
||||
|
||||
1. Place the new dotfile in the `dotfiles/` directory.
|
||||
2. Alternatively, use `dotfile_overlays/` if the dotfile belongs to a specific group or submodule.
|
||||
3. The `install.sh` script will automatically symlink it to the home directory.
|
||||
|
||||
### Adding a new script to `bin/`
|
||||
|
||||
1. Add the new script to the `bin/` directory (or an appropriate subdirectory).
|
||||
2. Ensure the script is executable (`chmod +x`).
|
||||
|
||||
### Adding a new package
|
||||
|
||||
1. Identify the appropriate package list in the `packages/` directory (e.g., `packages/cli`, `packages/kali`).
|
||||
2. Add the new package name to the list (one per line).
|
||||
3. If a new package set is required, create a new file in the `packages/` directory.
|
||||
4. For macOS-specific packages, also consider adding them to the `Brewfile`.
|
||||
|
||||
### Platform-specific changes
|
||||
|
||||
When making changes that are specific to a platform (e.g., Debian vs. macOS), please check for existing conventions in the `install.sh` script or other files. Use conditional logic (e.g., checking `uname`) to apply platform-specific settings.
|
||||
106
Brewfile
Normal file
106
Brewfile
Normal file
@@ -0,0 +1,106 @@
|
||||
tap "dart-lang/dart"
|
||||
tap "sass/sass"
|
||||
brew "ack"
|
||||
brew "acme.sh"
|
||||
brew "age"
|
||||
brew "autoconf"
|
||||
brew "automake"
|
||||
brew "b2-tools"
|
||||
brew "bat"
|
||||
brew "cask"
|
||||
brew "ccache"
|
||||
brew "certbot"
|
||||
brew "cmake"
|
||||
brew "colima"
|
||||
brew "devcontainer"
|
||||
brew "difftastic"
|
||||
brew "dfu-util"
|
||||
brew "direnv"
|
||||
brew "duck"
|
||||
brew "earthly"
|
||||
brew "esptool"
|
||||
brew "gh"
|
||||
brew "ghidra", link: false
|
||||
brew "git"
|
||||
brew "git-delta"
|
||||
brew "git-lfs"
|
||||
brew "gnupg"
|
||||
brew "go"
|
||||
brew "gradle"
|
||||
brew "htop"
|
||||
brew "httpie"
|
||||
brew "huggingface-cli"
|
||||
brew "hugo"
|
||||
brew "imagemagick"
|
||||
brew "john-jumbo"
|
||||
brew "jq"
|
||||
brew "lima"
|
||||
brew "mise"
|
||||
brew "mosh"
|
||||
brew "neovim"
|
||||
brew "ninja"
|
||||
brew "nmap"
|
||||
brew "protobuf"
|
||||
brew "p7zip"
|
||||
brew "pipenv"
|
||||
brew "pipx"
|
||||
brew "pkgconf"
|
||||
brew "pwgen"
|
||||
brew "pwntools"
|
||||
brew "qemu"
|
||||
brew "restic"
|
||||
brew "ripgrep"
|
||||
brew "ruby"
|
||||
brew "ruby@3.3"
|
||||
brew "rustup"
|
||||
brew "scroll-reverser"
|
||||
brew "shellcheck"
|
||||
brew "smartmontools"
|
||||
brew "starship"
|
||||
brew "tmux"
|
||||
brew "uv"
|
||||
brew "virtualenvwrapper"
|
||||
brew "wget"
|
||||
brew "yt-dlp"
|
||||
brew "zlib"
|
||||
brew "zsh-syntax-highlighting"
|
||||
brew "sass/sass/migrator"
|
||||
brew "sass/sass/sass"
|
||||
cask "codeql"
|
||||
cask "cyberduck"
|
||||
cask "font-fira-code-nerd-font"
|
||||
cask "font-fira-mono-nerd-font"
|
||||
cask "font-go-mono-nerd-font"
|
||||
cask "font-hack-nerd-font"
|
||||
cask "font-inconsolata-nerd-font"
|
||||
cask "font-symbols-only-nerd-font"
|
||||
cask "font-terminess-ttf-nerd-font"
|
||||
cask "ghidra"
|
||||
cask "gimp"
|
||||
cask "github"
|
||||
cask "iterm2"
|
||||
cask "macfuse"
|
||||
cask "meld"
|
||||
cask "mitmproxy"
|
||||
cask "raycast"
|
||||
cask "rectangle"
|
||||
cask "scroll-reverser"
|
||||
cask "temurin"
|
||||
cask "veracrypt"
|
||||
cask "zulu@17"
|
||||
|
||||
def is_corp?
|
||||
# Check for MDM enrollment (Enrolled via DEP: Yes)
|
||||
`profiles status -type enrollment 2>/dev/null`.include?("Enrolled via DEP: Yes")
|
||||
end
|
||||
|
||||
# non-corp
|
||||
if !is_corp?
|
||||
brew "bazel"
|
||||
brew "openssh"
|
||||
cask "claude-code"
|
||||
cask "cryptomator"
|
||||
cask "gcloud-cli"
|
||||
cask "google-cloud-sdk"
|
||||
cask "orbstack"
|
||||
end
|
||||
62
README.md
62
README.md
@@ -1,16 +1,24 @@
|
||||
### About ###
|
||||
|
||||
This is a repository of configuration files that I like to have on all the
|
||||
machines that I use. I can just clone the repository and run "repo/setup.sh"
|
||||
and get most things setup the way I like them.
|
||||
machines that I use. For new systems, you can bootstrap by running the
|
||||
included `clone.sh` script:
|
||||
|
||||
```bash
|
||||
curl -L https://raw.githubusercontent.com/Matir/skel/master/clone.sh | bash
|
||||
```
|
||||
|
||||
Alternatively, you can manually clone the repository and run `./install.sh`.
|
||||
|
||||
This started just as dotfiles, but expanded to include SSH keys, GPG keys,
|
||||
packages I like installed, and an ever-growing setup script. There are various
|
||||
and an ever-growing setup script. There are various
|
||||
options to install just parts of it, such as on a machine where I only have a
|
||||
user account but no root.
|
||||
|
||||
This now uses [git-crypt](https://github.com/AGWA/git-crypt) to protect
|
||||
`private_dotfiles` for things I don't want to splash all over the internet. :)
|
||||
This environment supports using `dotfile_overlays/` or `local_dotfiles/` to
|
||||
manage machine-specific or private configurations. You can use
|
||||
[git-crypt](https://github.com/AGWA/git-crypt) on these overlay directories
|
||||
for things you don't want to splash all over the internet. :)
|
||||
I still wouldn't check in anything terribly sensitive, like private keys.
|
||||
|
||||
### Usefulness ###
|
||||
@@ -22,16 +30,52 @@ dotfiles. ;)
|
||||
|
||||
### Options ###
|
||||
|
||||
### macOS-like Copy/Paste ###
|
||||
|
||||
To address keyboard shortcut conflicts between operating systems, this environment
|
||||
now supports using `Alt+C` for copy and `Alt+V` for paste, similar to macOS.
|
||||
This functionality is context-aware: it will automatically use `Ctrl+Shift+C/V`
|
||||
in terminals and `Ctrl+C/V` in all other applications.
|
||||
|
||||
This feature requires the following packages to be installed:
|
||||
|
||||
- `xbindkeys`: To listen for the keyboard shortcuts.
|
||||
- `xdotool`: To send the appropriate keypresses.
|
||||
|
||||
On Debian-based systems (like Ubuntu or Kali), you can install them with:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install xbindkeys xdotool
|
||||
```
|
||||
|
||||
After installation, the functionality will be enabled automatically on your
|
||||
next login.
|
||||
|
||||
On macOS, you can install the recommended packages using the included `Brewfile`:
|
||||
|
||||
```bash
|
||||
brew bundle install
|
||||
```
|
||||
|
||||
### Packages ###
|
||||
|
||||
The `packages/` directory contains lists of recommended packages. You can
|
||||
manually install a set (e.g., on a Debian-based system) using:
|
||||
|
||||
```bash
|
||||
grep -v "^#" packages/cli | xargs sudo apt-get install -y
|
||||
```
|
||||
|
||||
```
|
||||
BASEDIR: Where the skel framework is installed. Defaults to $HOME/.skel
|
||||
MINIMAL: Don't do things that require git clones or installation of anything
|
||||
not included in my .skel. (Defaults to 0, installs everything.)
|
||||
not included in my .skel. (e.g., skips vim-plug, TPM) (Defaults to 0)
|
||||
INSTALL_KEYS: Install GnuPG and SSH keys. SSH keys are placed in
|
||||
authorized_keys. (Defaults to 1, installs keys.)
|
||||
TRUST_ALL_KEYS: Allow all keys to be used for SSH login, versus a small subset.
|
||||
INSTALL_PKGS: Install common packages, if on a Debian-like system.
|
||||
(Defaults to opposite of $MINIMAL.)
|
||||
SAVE: Save the install options to ${BASEDIR}/installed-prefs
|
||||
VERBOSE: Enable verbose output during installation. (Defaults to 0)
|
||||
SAVE: Save the install options to ${BASEDIR}/.installed-prefs
|
||||
```
|
||||
|
||||
### TODO ###
|
||||
|
||||
70
bin/add_hosts_entry
Normal file
70
bin/add_hosts_entry
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# vim: set ft=python:
|
||||
|
||||
import datetime
|
||||
import ipaddress
|
||||
import os
|
||||
import sys
|
||||
import sys.path
|
||||
|
||||
|
||||
def generate_hosts_entry(ip_address_str, hostnames):
|
||||
"""
|
||||
Generates a string formatted for /etc/hosts after validating the IP address.
|
||||
|
||||
Args:
|
||||
ip_address_str (str): The IP address string.
|
||||
hostnames (list): A list of hostname strings.
|
||||
|
||||
Returns:
|
||||
str: A formatted string for /etc/hosts, or None if validation fails.
|
||||
"""
|
||||
try:
|
||||
# Validate the IP address
|
||||
ip = ipaddress.ip_address(ip_address_str)
|
||||
except ValueError:
|
||||
print(f"Error: '{ip_address_str}' is not a valid IP address.", file=sys.stderr)
|
||||
return None
|
||||
|
||||
# Join hostnames with spaces
|
||||
hostnames_str = " ".join(hostnames)
|
||||
|
||||
# Return the formatted line
|
||||
return f"{ip} {hostnames_str}"
|
||||
|
||||
|
||||
def append_hosts_entry(entry, hosts_file="/etc/hosts"):
|
||||
when = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
|
||||
try:
|
||||
with open(hosts_file, "a") as fp:
|
||||
fp.write(f"# Added by add_hosts_entry {when}\n{entry}\n")
|
||||
return True
|
||||
except PermissionError:
|
||||
if os.geteuid() == 0:
|
||||
print(f"Error: failed opening {hosts_file} for writing.",
|
||||
file=sys.stderr)
|
||||
return False
|
||||
return relaunch_with_sudo()
|
||||
|
||||
|
||||
def relaunch_with_sudo():
|
||||
script_abspath = os.path.abspath(sys.argv[0])
|
||||
os.execvp("sudo", [script_abspath] + sys.argv[1:])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Check for correct number of arguments
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: python3 generate_hosts_entry.py <ip_address> <hostname1> [hostname2 ...]", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
ip_to_add = sys.argv[1]
|
||||
hostnames_to_add = sys.argv[2:]
|
||||
|
||||
# Generate the entry
|
||||
entry = generate_hosts_entry(ip_to_add, hostnames_to_add)
|
||||
if not entry:
|
||||
sys.exit(1)
|
||||
if not append_hosts_entry(entry):
|
||||
sys.exit(1)
|
||||
@@ -3,6 +3,11 @@
|
||||
set -o nounset
|
||||
set -o errexit
|
||||
|
||||
if [ "$(uname)" != "Linux" ]; then
|
||||
echo "Error: This backup script is only intended for use on Linux." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DEFAULT=`echo /media/${USER}/[bB]ackup/${USER}/`
|
||||
DEST="${1:-${DEFAULT}}"
|
||||
|
||||
|
||||
@@ -835,14 +835,14 @@ case "$1" in
|
||||
fi
|
||||
cd /proc
|
||||
N=$2
|
||||
if [ -d $N ] ; then
|
||||
if [ -d "$N" ] ; then
|
||||
# read permissions?
|
||||
if [ ! -r $N/exe ] ; then
|
||||
if [ ! -r "$N/exe" ] ; then
|
||||
if !(root_privs) ; then
|
||||
printf "\033[31mNo read permissions for '/proc/$N/exe' (run as root).\033[m\n\n"
|
||||
printf "\033[31mNo read permissions for '/proc/%s/exe' (run as root).\033[m\n\n" "$N"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! `readlink $N/exe` ] ; then
|
||||
if [ ! "$(readlink "$N/exe")" ] ; then
|
||||
printf "\033[31mPermission denied. Requested process ID belongs to a kernel thread.\033[m\n\n"
|
||||
exit 1
|
||||
fi
|
||||
@@ -860,9 +860,9 @@ case "$1" in
|
||||
printf "\033[31mError: libc not found.\033[m\n\n"
|
||||
exit 1
|
||||
fi
|
||||
printf "* Process name (PID) : %s (%d)\n" `head -1 $N/status | cut -b 7-` $N
|
||||
FS_chk_func_libc=( $(readelf -s $FS_libc | grep _chk@@ | awk '{ print $8 }' | cut -c 3- | sed -e 's/_chk@.*//') )
|
||||
FS_functions=( $(readelf -s $2/exe | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//') )
|
||||
printf "* Process name (PID) : %s (%d)\n" "$(head -1 "$N/status" | cut -b 7-)" "$N"
|
||||
FS_chk_func_libc=( $(readelf -s "$FS_libc" | grep _chk@@ | awk '{ print $8 }' | cut -c 3- | sed -e 's/_chk@.*//') )
|
||||
FS_functions=( $(readelf -s "$2/exe" | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//') )
|
||||
|
||||
FS_libc_check
|
||||
FS_binary_check
|
||||
|
||||
148
bin/cloudy.sh
Executable file
148
bin/cloudy.sh
Executable file
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ueo pipefail
|
||||
shopt -s extglob
|
||||
|
||||
# get libraries
|
||||
. ${HOME}/.local/lib/bash/tui.sh
|
||||
|
||||
COMMANDS=(
|
||||
gctx
|
||||
kctx
|
||||
)
|
||||
|
||||
_make_extglob() {
|
||||
local IFS='|'
|
||||
echo "@($*)"
|
||||
}
|
||||
|
||||
CMD_PATTERN=$(_make_extglob "${COMMANDS[@]}")
|
||||
|
||||
usage() {
|
||||
echo "Available Subcommands:"
|
||||
printf " - %-10s\n" "${COMMANDS[@]}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
_gctx_set() {
|
||||
gcloud config configurations activate "${1}" </dev/null
|
||||
}
|
||||
|
||||
_gctx_choose() {
|
||||
local lines=()
|
||||
local default=''
|
||||
local maxnamelen=0
|
||||
local active name description
|
||||
while IFS=$'\t' read -r active name description ; do
|
||||
(( maxnamelen = ( ${#name} > maxnamelen ) ? ${#name} : maxnamelen ))
|
||||
if [[ "$active" == "True" ]] ; then
|
||||
default="${name}"
|
||||
fi
|
||||
lines+=("${name}" "${description}")
|
||||
done < <(gcloud config configurations list \
|
||||
--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}"
|
||||
else
|
||||
echo "No option selected, leaving unchanged."
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
_gctx_new() {
|
||||
local cname="${1:-}"
|
||||
if test -z "${cname}" ; then
|
||||
echo "Usage: gctx new <new name>" >&2
|
||||
return 1
|
||||
fi
|
||||
gcloud config configurations create "${cname}"
|
||||
}
|
||||
|
||||
_gctx_name() {
|
||||
gcloud info --format='value(config.active_config_name)'
|
||||
}
|
||||
|
||||
_gctx_clone() {
|
||||
# save old config
|
||||
local oldconfig=()
|
||||
local line
|
||||
while IFS= read -r line ; do
|
||||
old_config+=("$line")
|
||||
done < <(gcloud config configurations describe "$(_gctx_name)" --format='multi(properties:format="flattened[separator=\" \"]")')
|
||||
|
||||
# create new
|
||||
_gctx_new "${1:-}"
|
||||
|
||||
# set config
|
||||
for line in "${oldconfig[@]}" ; do
|
||||
local keyname="${line%% *}"
|
||||
local keypath="${keyname//\.//}"
|
||||
local value="${line#* }"
|
||||
gcloud config set "${keypath}" "${value}"
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
gctx() {
|
||||
local subcmd="${1:-}"
|
||||
shift || true
|
||||
case "${subcmd}" in
|
||||
clone)
|
||||
_gctx_clone "$@"
|
||||
return
|
||||
;;
|
||||
new)
|
||||
_gctx_new "$@"
|
||||
return
|
||||
;;
|
||||
show)
|
||||
gcloud config configurations list --filter="is_active=True" \
|
||||
--format='table(name, properties.core.account, properties.core.project, properties.compute.zone:label=COMPUTE_DEFAULT_ZONE, properties.compute.region:label=COMPUTE_DEFAULT_REGION)' \
|
||||
"$@"
|
||||
;;
|
||||
list)
|
||||
gcloud config configurations list "$@"
|
||||
return
|
||||
;;
|
||||
activate)
|
||||
_gctx_set "$@"
|
||||
return
|
||||
;;
|
||||
""|choose)
|
||||
_gctx_choose
|
||||
return
|
||||
;;
|
||||
*)
|
||||
if _gctx_set "${subcmd}" 2>/dev/null ; then
|
||||
return 0
|
||||
fi
|
||||
echo "Usage: gctx [show|list|new|choose|clone|<name>]" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
kctx() {
|
||||
return 0
|
||||
}
|
||||
|
||||
INVOKED_AS=$(basename "$0")
|
||||
# shellcheck disable=SC2053
|
||||
if [[ "$INVOKED_AS" == $CMD_PATTERN ]] ; then
|
||||
CMD="${INVOKED_AS}"
|
||||
else
|
||||
CMD="${1:-}"
|
||||
shift || usage
|
||||
fi
|
||||
|
||||
|
||||
# shellcheck disable=SC2254
|
||||
case "${CMD}" in
|
||||
${CMD_PATTERN})
|
||||
"${CMD}" "$@"
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
8
bin/darwin-env.sh
Executable file
8
bin/darwin-env.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/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
|
||||
93
bin/fix-broken-symlinks.sh
Executable file
93
bin/fix-broken-symlinks.sh
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
|
||||
# A script to find and remove broken symbolic links in a directory.
|
||||
#
|
||||
# OPTIONS:
|
||||
# -y: Automatically remove all broken links without confirmation.
|
||||
# -q: Quiet mode. Suppress all non-error output.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# --- Default settings ---
|
||||
FORCE_DELETE=0
|
||||
QUIET=0
|
||||
TARGET_DIR="."
|
||||
|
||||
# --- Helper function for logging ---
|
||||
log() {
|
||||
if [ "${QUIET}" -eq 0 ]; then
|
||||
echo "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Usage function ---
|
||||
usage() {
|
||||
echo "Usage: $0 [-y] [-q] [TARGET_DIRECTORY]"
|
||||
echo " -y: Yes. Automatically remove broken symlinks without confirmation."
|
||||
echo " -q: Quiet. Suppress all output except for errors."
|
||||
echo " TARGET_DIRECTORY: The directory to scan. Defaults to the current directory."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Parse command-line options ---
|
||||
while getopts "yq" opt; do
|
||||
case ${opt} in
|
||||
y)
|
||||
FORCE_DELETE=1
|
||||
;;
|
||||
q)
|
||||
QUIET=1
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1)) # Remove the parsed options
|
||||
|
||||
# --- Set target directory ---
|
||||
# Use the first remaining argument as the target directory.
|
||||
if [ -n "$1" ]; then
|
||||
TARGET_DIR="$1"
|
||||
fi
|
||||
|
||||
if [ ! -d "${TARGET_DIR}" ]; then
|
||||
echo "Error: Directory '${TARGET_DIR}' not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Searching for broken symlinks in '${TARGET_DIR}'..."
|
||||
|
||||
# --- Main logic ---
|
||||
# Find broken symlinks and process them.
|
||||
find "${TARGET_DIR}" -type l ! -exec test -e {} \; -print0 | while IFS= read -r -d '' link; do
|
||||
if [ "${FORCE_DELETE}" -eq 1 ]; then
|
||||
# No confirmation needed, just delete.
|
||||
if rm "${link}"; then
|
||||
log "Removed '${link}'."
|
||||
else
|
||||
# Errors should still be reported.
|
||||
echo "Failed to remove '${link}'." >&2
|
||||
fi
|
||||
else
|
||||
# If in quiet mode but not force mode, we can't prompt, so we skip.
|
||||
if [ "${QUIET}" -eq 1 ]; then
|
||||
continue
|
||||
fi
|
||||
# Ask the user for confirmation.
|
||||
read -p "Remove broken symlink '${link}'? [y/N] " -n 1 -r
|
||||
echo # Move to a new line after input.
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
if rm "${link}"; then
|
||||
log "Removed '${link}'."
|
||||
else
|
||||
echo "Failed to remove '${link}'." >&2
|
||||
fi
|
||||
else
|
||||
log "Skipped '${link}'."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
log "Cleanup complete."
|
||||
@@ -3,8 +3,12 @@
|
||||
CHROME=`which google-chrome`
|
||||
|
||||
if [ `id -u` != "0" ] ; then
|
||||
exec $CHROME "$@"
|
||||
exec "$CHROME" "$@"
|
||||
fi
|
||||
|
||||
CMD="${CHROME} --user-data-dir=${HOME}/.chrome-data-dir \"$@\""
|
||||
su -c "${CMD}" chromeuser
|
||||
args=()
|
||||
for x in "$@"; do
|
||||
args+=("$(printf %q "$x")")
|
||||
done
|
||||
|
||||
su -c "$CHROME --user-data-dir=${HOME}/.chrome-data-dir ${args[*]}" chromeuser
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
LOCKTIME="${SCREENSAVER_MIN:-5}"
|
||||
LOCKER="i3lock -c 000000"
|
||||
# intentionally want word splitting below
|
||||
# do not quote this
|
||||
/usr/bin/xss-lock -- ${LOCKER} &
|
||||
exec /usr/bin/xautolock \
|
||||
-time "${LOCKTIME}" \
|
||||
|
||||
137
bin/install_ansible.sh
Executable file
137
bin/install_ansible.sh
Executable file
@@ -0,0 +1,137 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
|
||||
# --- Helper Functions ---
|
||||
info() { echo "[INFO] $1"; }
|
||||
warn() { echo "[WARN] $1"; }
|
||||
error() { echo "[ERROR] $1" >&2; exit 1; }
|
||||
|
||||
# --- Main Logic ---
|
||||
|
||||
# 1. Check if Ansible is already installed
|
||||
if command -v ansible >/dev/null 2>&1; then
|
||||
info "Ansible is already installed at $(command -v ansible)."
|
||||
exit 0
|
||||
fi
|
||||
info "Ansible not found. Attempting installation..."
|
||||
|
||||
# 2. Try user-space installation (no sudo)
|
||||
info "--- Attempting user-space installation (no sudo required) ---"
|
||||
|
||||
# Try pipx first, as it's the cleanest user-space method
|
||||
if command -v pipx >/dev/null 2>&1; then
|
||||
info "Found pipx. Trying to install Ansible with it..."
|
||||
if pipx install ansible;
|
||||
then
|
||||
# pipx requires adding ~/.local/bin to PATH, which might not be sourced yet.
|
||||
# Check the executable directly.
|
||||
if [[ -x "${HOME}/.local/bin/ansible" ]]; then
|
||||
info "Ansible installed successfully with pipx."
|
||||
info "Please ensure '${HOME}/.local/bin' is in your PATH."
|
||||
info "You may need to restart your shell or run: export PATH=\"$HOME/.local/bin:$PATH\""
|
||||
exit 0
|
||||
else
|
||||
warn "pipx install seemed to succeed, but ansible executable not found where expected."
|
||||
fi
|
||||
else
|
||||
warn "pipx install ansible failed."
|
||||
fi
|
||||
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_$$"
|
||||
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}..."
|
||||
python3 -m venv "${VENV_PATH}"
|
||||
if "${VENV_PATH}/bin/pip" install --quiet ansible;
|
||||
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 "(You may need to source ~/.profile or restart your shell)."
|
||||
exit 0
|
||||
else
|
||||
warn "Failed to install ansible into the virtual environment."
|
||||
rm -rf "${VENV_PATH}" # Clean up failed attempt
|
||||
fi
|
||||
else
|
||||
info "Python's venv module not available or failed to create a test environment."
|
||||
fi
|
||||
|
||||
# 3. Fallback to sudo installation
|
||||
info "--- User-space installation failed. Falling back to system-wide installation (sudo required) ---"
|
||||
|
||||
if ! command -v sudo >/dev/null 2>&1; then
|
||||
error "sudo command not found. Cannot attempt system-wide installation. Aborting."
|
||||
fi
|
||||
|
||||
# Prompt for sudo password upfront so it doesn't happen in the middle of the script
|
||||
info "Sudo privileges are required. You may be prompted for your password."
|
||||
if ! sudo -v; then
|
||||
error "Failed to acquire sudo privileges. Aborting."
|
||||
fi
|
||||
|
||||
# Detect package manager and install
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
info "Detected Debian-based system (apt)."
|
||||
sudo apt-get update -y
|
||||
info "Attempting to install 'ansible' package..."
|
||||
if sudo apt-get install -y ansible;
|
||||
then
|
||||
info "System package 'ansible' installed successfully."
|
||||
else
|
||||
warn "Failed to install 'ansible' package directly. Trying to install prerequisites for user-space install..."
|
||||
if sudo apt-get install -y pipx;
|
||||
then
|
||||
info "Installed pipx. Attempting to install Ansible with it..."
|
||||
if pipx install ansible;
|
||||
then
|
||||
info "Ansible installed successfully with pipx."
|
||||
info "Please ensure '${HOME}/.local/bin' is in your PATH."
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
error "Failed to install 'ansible' or 'pipx' via apt. Aborting."
|
||||
fi
|
||||
fi
|
||||
elif command -v dnf >/dev/null 2>&1; then
|
||||
info "Detected Red Hat-based system (dnf)."
|
||||
info "Attempting to install 'ansible-core' package..."
|
||||
if ! sudo dnf install -y ansible-core;
|
||||
then
|
||||
error "Failed to install ansible-core via dnf. Aborting."
|
||||
fi
|
||||
elif command -v pacman >/dev/null 2>&1; then
|
||||
info "Detected Arch-based system (pacman)."
|
||||
info "Attempting to install 'ansible' package..."
|
||||
if ! sudo pacman -Syu --noconfirm ansible;
|
||||
then
|
||||
error "Failed to install ansible via pacman. Aborting."
|
||||
fi
|
||||
elif command -v brew >/dev/null 2>&1; then
|
||||
info "Detected macOS (brew)."
|
||||
info "Attempting to install 'ansible' package..."
|
||||
if ! brew install ansible;
|
||||
then
|
||||
error "Failed to install ansible via brew. Aborting."
|
||||
fi
|
||||
else
|
||||
error "Could not detect a known package manager (apt, dnf, pacman, brew). Aborting."
|
||||
fi
|
||||
|
||||
# 4. Final verification
|
||||
info "--- Verifying final installation ---"
|
||||
if command -v ansible >/dev/null 2>&1; then
|
||||
info "Ansible successfully installed at $(command -v ansible)."
|
||||
exit 0
|
||||
else
|
||||
error "Installation attempted but the 'ansible' command is still not available. Please check the output for errors."
|
||||
fi
|
||||
92
bin/install_package.sh
Normal file
92
bin/install_package.sh
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Attempt to install packages regardless of OS
|
||||
|
||||
set -ue
|
||||
|
||||
is_sourced() {
|
||||
if [ -n "${ZSH_VERSION:-}" ]; then
|
||||
case $ZSH_EVAL_CONTEXT in *:file:*) return 0;; esac
|
||||
else # Add additional POSIX-compatible shell names here, if needed.
|
||||
case ${0##*/} in dash|-dash|bash|-bash|ksh|-ksh|sh|-sh) return 0;; esac
|
||||
fi
|
||||
return 1 # NOT sourced.
|
||||
}
|
||||
|
||||
# Format is <apt name>:<manager>:<alternate name>
|
||||
# Use "-" for alternate name if not available
|
||||
PACKAGE_ALIASES=$(cat <<'EOF'
|
||||
binfmt-support:brew:-
|
||||
cryptsetup:brew:-
|
||||
lvm2:brew:-
|
||||
EOF
|
||||
)
|
||||
|
||||
package_alias() {
|
||||
local manager="$1"
|
||||
local package="$2"
|
||||
local alias=$(echo "$PACKAGE_ALIASES" | \
|
||||
awk -F: -v manager="${manager}" -v package="${package}" \
|
||||
'$1 == package && $2 == manager { print $3 }' 2>/dev/null)
|
||||
echo "${alias:-${package}}"
|
||||
}
|
||||
|
||||
install_package() {
|
||||
local package="$1"
|
||||
|
||||
# Check for apt-get
|
||||
if command -v apt-get &> /dev/null; then
|
||||
package=$(package_alias apt "${package}")
|
||||
if [ "$package" == "-" ] ; then
|
||||
echo "Package not available on this platform"
|
||||
return 1
|
||||
fi
|
||||
echo "Installing '$package' using apt-get..."
|
||||
sudo apt-get install -y -- "$package"
|
||||
return 0
|
||||
elif command -v yum &> /dev/null; then
|
||||
package=$(package_alias yum "${package}")
|
||||
if [ "$package" == "-" ] ; then
|
||||
echo "Package not available on this platform"
|
||||
return 1
|
||||
fi
|
||||
echo "Installing '$package' using yum..."
|
||||
sudo yum install -y -- "$package"
|
||||
return 0
|
||||
elif command -v pacman &> /dev/null; then
|
||||
package=$(package_alias pacman "${package}")
|
||||
if [ "$package" == "-" ] ; then
|
||||
echo "Package not available on this platform"
|
||||
return 1
|
||||
fi
|
||||
echo "Installing '$package' using pacman..."
|
||||
sudo pacman -S -- "$package"
|
||||
return 0
|
||||
# For macOS, assume Homebrew is installed
|
||||
elif command -v brew &> /dev/null; then
|
||||
package=$(package_alias brew "${package}")
|
||||
if [ "$package" == "-" ] ; then
|
||||
echo "Package not available on this platform"
|
||||
return 1
|
||||
fi
|
||||
echo "Installing '$package' using Homebrew..."
|
||||
brew install -- "$package"
|
||||
return 0
|
||||
else
|
||||
echo "Error: No suitable package manager found."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_sourced || {
|
||||
# Get the package name from the command line argument
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: $0 <package_name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
package_name="$1"
|
||||
|
||||
# Call the install function
|
||||
install_package "$package_name"
|
||||
}
|
||||
203
bin/install_tool
203
bin/install_tool
@@ -2,6 +2,9 @@
|
||||
|
||||
set -ue
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
trap 'rm -rf -- "${TMPDIR}"' EXIT
|
||||
|
||||
REINSTALL=0
|
||||
PACKAGES=1
|
||||
|
||||
@@ -72,8 +75,7 @@ function download {
|
||||
SRC=${1}
|
||||
DST=${2}
|
||||
echo -n "Downloading ${SRC} to ${DST}..." >&2
|
||||
# TODO: consider curl instead?
|
||||
wget --no-server-response -q -O "${DST}" --content-disposition "${SRC}"
|
||||
curl -fL -o "${DST}" "${SRC}"
|
||||
echo " done." >&2
|
||||
}
|
||||
|
||||
@@ -118,6 +120,13 @@ function deb_only {
|
||||
fi
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
function require_pipx {
|
||||
command -v pipx >/dev/null 2>&1 || die "Requires pipx"
|
||||
}
|
||||
@@ -125,16 +134,17 @@ function require_pipx {
|
||||
# Begin main tool selection
|
||||
case ${TOOL} in
|
||||
john)
|
||||
deb_only
|
||||
makedest_or_die
|
||||
install_pkgs libssl-dev git build-essential yasm libgmp-dev libpcap-dev \
|
||||
pkg-config libbz2-dev libopenmpi-dev openmpi-bin libnss3-dev \
|
||||
libkrb5-dev libgmp-dev
|
||||
jtemp=$(mktemp -d)
|
||||
jtemp="${TMPDIR}/john"
|
||||
mkdir -p "${jtemp}"
|
||||
git clone https://github.com/magnumripper/JohnTheRipper.git "${jtemp}/john"
|
||||
cd "${jtemp}/john/src"
|
||||
cd "${jtemp}/john/src" || exit
|
||||
./configure && make -sj2
|
||||
cp -r "${jtemp}"/john/run/* "${DESTDIR}"
|
||||
rm -rf "${jtemp}"
|
||||
# Persistent files
|
||||
mkdir -p "${HOME}/.john"
|
||||
touch "${HOME}/.john/john.pot"
|
||||
@@ -144,15 +154,15 @@ case ${TOOL} in
|
||||
wordlists)
|
||||
makedest
|
||||
download \
|
||||
http://downloads.skullsecurity.org/passwords/rockyou.txt.bz2 \
|
||||
"http://downloads.skullsecurity.org/passwords/rockyou.txt.bz2" \
|
||||
"${DESTDIR}/rockyou.txt.bz2"
|
||||
bunzip2 "${DESTDIR}/rockyou.txt.bz2"
|
||||
download \
|
||||
http://downloads.skullsecurity.org/passwords/phpbb.txt.bz2 \
|
||||
"http://downloads.skullsecurity.org/passwords/phpbb.txt.bz2" \
|
||||
"${DESTDIR}/phpbb.txt.bz2"
|
||||
bunzip2 "${DESTDIR}/phpbb.txt.bz2"
|
||||
download \
|
||||
http://downloads.skullsecurity.org/passwords/hak5.txt.bz2 \
|
||||
"http://downloads.skullsecurity.org/passwords/hak5.txt.bz2" \
|
||||
"${DESTDIR}/hak5.txt.bz2"
|
||||
bunzip2 "${DESTDIR}/hak5.txt.bz2"
|
||||
;;
|
||||
@@ -165,19 +175,15 @@ case ${TOOL} in
|
||||
gcloud)
|
||||
makedest_or_die
|
||||
gbase="https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/"
|
||||
# TODO: find a way to make this version independent
|
||||
gsdk="google-cloud-sdk-385.0.0-linux-x86_64.tar.gz"
|
||||
download "${gbase}${gsdk}" /tmp/gcloud.tar.gz
|
||||
tar zxf /tmp/gcloud.tar.gz --strip-components=1 -C "${DESTDIR}"
|
||||
rm /tmp/gcloud.tar.gz
|
||||
gsdk=$(curl -s https://cloud.google.com/sdk/docs/install-sdk | grep -o "google-cloud-sdk-[0-9.]*-linux-x86_64.tar.gz" | head -n 1)
|
||||
download "${gbase}${gsdk}" "${TMPDIR}/gcloud.tar.gz"
|
||||
tar zxf "${TMPDIR}/gcloud.tar.gz" --strip-components=1 -C "${DESTDIR}"
|
||||
add_bin_symlink bin/gcloud
|
||||
;;
|
||||
android-sdk)
|
||||
# TODO: find a way to make this version independent
|
||||
asdk="https://dl.google.com/android/repository/platform-tools_r31.0.2-linux.zip"
|
||||
download ${asdk} /tmp/android-tools.zip
|
||||
unzip -d "${DESTDIR}" /tmp/android-tools.zip
|
||||
rm /tmp/android-tools.zip
|
||||
asdk=$(curl -s https://developer.android.com/studio/releases/platform-tools | grep -o "https://dl.google.com/android/repository/platform-tools_r[0-9.]*-linux.zip" | head -n 1)
|
||||
download "${asdk}" "${TMPDIR}/android-tools.zip"
|
||||
unzip -d "${DESTDIR}" "${TMPDIR}/android-tools.zip"
|
||||
# Install components
|
||||
"${DESTDIR}/tools/bin/sdkmanager" "emulator" "platform-tools"
|
||||
;;
|
||||
@@ -198,12 +204,10 @@ case ${TOOL} in
|
||||
;;
|
||||
mitmproxy)
|
||||
makedest_or_die
|
||||
ver=$(python3 -c 'from urllib import request; import json; print(json.load(request.urlopen("https://api.github.com/repos/mitmproxy/mitmproxy/releases/latest"))["tag_name"].replace("v",""))')
|
||||
download \
|
||||
"https://snapshots.mitmproxy.org/${ver}/mitmproxy-${ver}-linux.tar.gz" \
|
||||
/tmp/mitmproxy.tar.gz
|
||||
tar zx -C "${DESTDIR}" -f /tmp/mitmproxy.tar.gz
|
||||
rm /tmp/mitmproxy.tar.gz
|
||||
"$(get_latest_github_release_url "mitmproxy/mitmproxy" ".*-linux\\.tar\\.gz")" \
|
||||
"${TMPDIR}/mitmproxy.tar.gz"
|
||||
tar zx -C "${DESTDIR}" -f "${TMPDIR}/mitmproxy.tar.gz"
|
||||
add_bin_symlink mitmproxy
|
||||
add_bin_symlink mitmweb
|
||||
add_bin_symlink mitmdump
|
||||
@@ -211,55 +215,58 @@ case ${TOOL} in
|
||||
esp)
|
||||
makedest_or_die
|
||||
src="https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz"
|
||||
download ${src} /tmp/esp32.tar.gz
|
||||
tar zx -C "${DESTDIR}" -f /tmp/esp32.tar.gz
|
||||
rm /tmp/esp32.tar.gz
|
||||
download "${src}" "${TMPDIR}/esp32.tar.gz"
|
||||
tar zx -C "${DESTDIR}" -f "${TMPDIR}/esp32.tar.gz"
|
||||
git clone --recursive https://github.com/espressif/esp-idf.git "${DESTDIR}/esp-idf"
|
||||
;;
|
||||
dex2jar)
|
||||
makedest_or_die
|
||||
src="https://github.com/pxb1988/dex2jar/releases/download/2.0/dex-tools-2.0.zip"
|
||||
download ${src} /tmp/dex2jar.zip
|
||||
tmpd=$(mktemp -d)
|
||||
unzip -d "${tmpd}" /tmp/dex2jar.zip
|
||||
mv "${tmpd}"/* "${DESTDIR}"
|
||||
rm /tmp/dex2jar.zip
|
||||
rm -rf "${tmpd}"
|
||||
src="https://github.com/pxb1988/dex2jar/releases/download/v2.4/dex-tools-v2.4.zip"
|
||||
download "${src}" "${TMPDIR}/dex2jar.zip"
|
||||
tmpd="${TMPDIR}/dex2jar"
|
||||
mkdir -p "${tmpd}"
|
||||
unzip -d "${tmpd}" "${TMPDIR}/dex2jar.zip"
|
||||
mv "${tmpd}"/dex-tools-*/* "${DESTDIR}"
|
||||
rm "${DESTDIR}"/*.bat
|
||||
chmod +x "${DESTDIR}"/*.sh
|
||||
;;
|
||||
proxmark3)
|
||||
deb_only
|
||||
install_pkgs p7zip git build-essential libreadline5 libreadline-dev \
|
||||
libusb-0.1-4 libusb-dev libqt4-dev perl pkg-config wget libncurses5-dev \
|
||||
gcc-arm-none-eabi libstdc++-arm-none-eabi-newlib
|
||||
src="https://github.com/Proxmark/proxmark3.git"
|
||||
git clone "${src}" "${DESTDIR}"
|
||||
cd "${DESTDIR}"
|
||||
cd "${DESTDIR}" || exit
|
||||
make -sj2
|
||||
check_sudo && sudo /bin/sh -c \
|
||||
"cp -rf driver/78-mm-usb-device-blacklist.rules \
|
||||
/etc/udev/rules.d/77-mm-usb-device-blacklist.rules &&
|
||||
/etc/udev/rules.d/77-mm-usb-device-blacklist.rules &&\
|
||||
udevadm control --reload-rules"
|
||||
;;
|
||||
pm3iceman)
|
||||
deb_only
|
||||
# arch:
|
||||
# sudo pacman -Syu git base-devel readline bzip2 lz4 arm-none-eabi-gcc arm-none-eabi-newlib qt5-base bluez python gd --needed
|
||||
install_pkgs git ca-certificates build-essential pkg-config \
|
||||
libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev \
|
||||
libbz2-dev libbluetooth-dev libpython3-dev libssl-dev
|
||||
src="https://github.com/RfidResearchGroup/proxmark3.git"
|
||||
git clone "${src}" "${DESTDIR}"
|
||||
cd "${DESTDIR}"
|
||||
cd "${DESTDIR}" || exit
|
||||
make clean && make -sj2
|
||||
check_sudo && sudo /bin/sh -c \
|
||||
"cp -rf ./driver/77-pm3-usb-device-blacklist.rules \
|
||||
/etc/udev/rules.d/77-pm3-usb-device-blacklist.rules &&
|
||||
/etc/udev/rules.d/77-pm3-usb-device-blacklist.rules &&\
|
||||
udevadm control --reload-rules"
|
||||
add_bin_symlink pm3
|
||||
;;
|
||||
cyberchef)
|
||||
makedest
|
||||
cd "${DESTDIR}"
|
||||
src=$(python3 -c 'from urllib import request; import json; print(json.load(request.urlopen("https://api.github.com/repos/gchq/CyberChef/releases/latest"))["assets"][0]["browser_download_url"])')
|
||||
download "${src}" "${DESTDIR}/cyberchef.zip"
|
||||
cd "${DESTDIR}" || exit
|
||||
download \
|
||||
"$(get_latest_github_release_url "gchq/CyberChef" ".*\\.zip")" \
|
||||
"${DESTDIR}/cyberchef.zip"
|
||||
unzip -d "${DESTDIR}" "${DESTDIR}/cyberchef.zip"
|
||||
ln -sf CyberChef*.html "${DESTDIR}/cyberchef.html"
|
||||
;;
|
||||
@@ -268,8 +275,9 @@ case ${TOOL} in
|
||||
download \
|
||||
https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool \
|
||||
"${DESTDIR}/apktool"
|
||||
jar_url=$(curl -s https://bitbucket.org/iBotPeaches/apktool/downloads/ | grep -o "/iBotPeaches/apktool/downloads/apktool_[0-9.]*.jar" | head -n 1)
|
||||
download \
|
||||
https://bitbucket.org/iBotPeaches/apktool/downloads/apktool_2.3.3.jar \
|
||||
"https://bitbucket.org${jar_url}" \
|
||||
"${DESTDIR}/apktool.jar"
|
||||
chmod +x "${DESTDIR}/apktool"
|
||||
add_bin_symlink apktool
|
||||
@@ -292,8 +300,14 @@ case ${TOOL} in
|
||||
PYTHON="${PYTHON}${PYVER}"
|
||||
"${PYTHON}" -m pip install --target "${PY_PACKAGES}" -Ur "${DESTDIR}/requirements.txt"
|
||||
"${PYTHON}" -m pip install --target "${PY_PACKAGES}" -U capstone unicorn
|
||||
# capstone package is broken
|
||||
cp "${PY_PACKAGES}/usr/lib/*/dist-packages/capstone/libcapstone.so" "${PY_PACKAGES}/capstone"
|
||||
# capstone package is broken, find and copy the library manually
|
||||
capstone_so_path=$(find "${PY_PACKAGES}/usr/lib" -name "libcapstone.so" -type f)
|
||||
if [ -z "${capstone_so_path}" ]; then
|
||||
die "Could not find libcapstone.so for pwndbg."
|
||||
elif [ "$(echo "${capstone_so_path}" | wc -l)" -ne 1 ]; then
|
||||
die "Found multiple libcapstone.so files for pwndbg, aborting."
|
||||
fi
|
||||
cp "${capstone_so_path}" "${PY_PACKAGES}/capstone/"
|
||||
;;
|
||||
gef)
|
||||
makedest_or_die
|
||||
@@ -306,6 +320,7 @@ case ${TOOL} in
|
||||
"${DESTDIR}/gef.py"
|
||||
;;
|
||||
aflplusplus)
|
||||
deb_only
|
||||
install_pkgs libtool-bin libglib2.0-dev libpixman-1-dev clang clang-tools \
|
||||
llvm python3-setuptools
|
||||
git clone "https://github.com/vanhauser-thc/AFLplusplus" "${DESTDIR}"
|
||||
@@ -326,22 +341,19 @@ case ${TOOL} in
|
||||
;;
|
||||
cura)
|
||||
makedest
|
||||
ver=$(python3 -c 'from urllib import request; import json; print(json.load(request.urlopen("https://api.github.com/repos/Ultimaker/Cura/releases/latest"))["name"].replace("v",""))')
|
||||
echo "Latest Cura is ${ver}"
|
||||
download \
|
||||
"https://github.com/Ultimaker/Cura/releases/download/${ver}/Cura-${ver}.AppImage" \
|
||||
"$(get_latest_github_release_url "Ultimaker/Cura" ".*\\.AppImage")" \
|
||||
"${DESTDIR}/Cura.AppImage"
|
||||
chmod +x "${DESTDIR}/Cura.AppImage"
|
||||
add_bin_symlink "Cura.AppImage" cura
|
||||
;;
|
||||
rr)
|
||||
deb_only
|
||||
ver=$(python3 -c 'from urllib import request; import json; print(json.load(request.urlopen("https://api.github.com/repos/mozilla/rr/releases/latest"))["name"])')
|
||||
echo "Latest rr is ${ver}"
|
||||
check_sudo
|
||||
download \
|
||||
"https://github.com/mozilla/rr/releases/download/${ver}/rr-${ver}-Linux-$(uname -m).deb" \
|
||||
"/tmp/rr.deb"
|
||||
sudo dpkg -i /tmp/rr.deb
|
||||
"$(get_latest_github_release_url "mozilla/rr" ".*-Linux-.*\\.deb")" \
|
||||
"${TMPDIR}/rr.deb"
|
||||
sudo dpkg -i "${TMPDIR}/rr.deb"
|
||||
;;
|
||||
nmap-parse-output)
|
||||
git clone --depth 1 \
|
||||
@@ -357,38 +369,40 @@ fi
|
||||
EOF
|
||||
;;
|
||||
logiops)
|
||||
deb_only
|
||||
install_pkgs cmake libevdev-dev libudev-dev libconfig++-dev checkinstall
|
||||
git clone "https://github.com/PixlOne/logiops.git" "${DESTDIR}"
|
||||
mkdir -p "${DESTDIR}/build"
|
||||
cd "${DESTDIR}/build"
|
||||
cd "${DESTDIR}/build" || exit
|
||||
cmake ..
|
||||
make
|
||||
check_sudo
|
||||
sudo checkinstall --pkgname logiops --maintainer "${USER}" -y
|
||||
;;
|
||||
aws)
|
||||
DN=$(mktemp -d)
|
||||
cd "${DN}"
|
||||
DN="${TMPDIR}/aws"
|
||||
mkdir -p "${DN}"
|
||||
cd "${DN}" || exit
|
||||
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "${DN}/awscliv2.zip"
|
||||
unzip "${DN}/awscliv2.zip"
|
||||
mv "${DN}/aws/dist" "${DESTDIR}"
|
||||
add_bin_symlink aws
|
||||
rm -rf ${DN}
|
||||
;;
|
||||
tmpmail)
|
||||
install_pkgs curl w3m jq
|
||||
mkdir -p ${DESTDIR}
|
||||
curl -L "https://git.io/tmpmail" > ${DESTDIR}/tmpmail
|
||||
chmod +x ${DESTDIR}/tmpmail
|
||||
mkdir -p "${DESTDIR}"
|
||||
download "https://git.io/tmpmail" "${DESTDIR}/tmpmail"
|
||||
chmod +x "${DESTDIR}/tmpmail"
|
||||
add_bin_symlink tmpmail
|
||||
;;
|
||||
gf)
|
||||
install_pkgs golang-go silversearcher-ag
|
||||
go install github.com/tomnomnom/gf@latest
|
||||
mkdir -p ${HOME}/.config
|
||||
if test -d ${HOME}/.config/gf ; then
|
||||
git -C ${HOME}/.config/gf pull
|
||||
mkdir -p "${HOME}/.config"
|
||||
if test -d "${HOME}/.config/gf" ; then
|
||||
git -C "${HOME}/.config/gf" pull
|
||||
else
|
||||
git clone https://github.com/Matir/gf-patterns.git ${HOME}/.config/gf
|
||||
git clone https://github.com/Matir/gf-patterns.git "${HOME}/.config/gf"
|
||||
fi
|
||||
;;
|
||||
gron)
|
||||
@@ -408,9 +422,9 @@ EOF
|
||||
;;
|
||||
cht.sh)
|
||||
install_pkgs rlwrap
|
||||
mkdir -p ${DESTDIR}
|
||||
curl https://cht.sh/:cht.sh > ${DESTDIR}/cht.sh
|
||||
chmod +x ${DESTDIR}/cht.sh
|
||||
mkdir -p "${DESTDIR}"
|
||||
download "https://cht.sh/:cht.sh" "${DESTDIR}/cht.sh"
|
||||
chmod +x "${DESTDIR}/cht.sh"
|
||||
add_bin_symlink cht.sh
|
||||
;;
|
||||
age)
|
||||
@@ -418,9 +432,10 @@ EOF
|
||||
go install filippo.io/age/cmd/age-keygen@latest
|
||||
;;
|
||||
docker-compose)
|
||||
mkdir -p ${DESTDIR}
|
||||
mkdir -p "${DESTDIR}"
|
||||
latest_version=$(curl -s "https://api.github.com/repos/docker/compose/releases/latest" | jq -r '.tag_name')
|
||||
curl -L \
|
||||
"https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" \
|
||||
"https://github.com/docker/compose/releases/download/${latest_version}/docker-compose-$(uname -s)-$(uname -m)" \
|
||||
-o "${DESTDIR}/docker-compose"
|
||||
chmod +x "${DESTDIR}/docker-compose"
|
||||
add_bin_symlink docker-compose
|
||||
@@ -453,13 +468,13 @@ EOF
|
||||
echo "Must be able to run as sudo."
|
||||
exit 1
|
||||
fi
|
||||
dpkg_url=$(curl https://api.github.com/repos/dandavison/delta/releases/latest | \
|
||||
jq -r '.assets[] | select(.name|test(".*_amd64.deb")) | select(.name|test(".*musl.*")|not) | .browser_download_url')
|
||||
dpkg_name="/tmp/delta_amd64.deb"
|
||||
dpkg_url=$(get_latest_github_release_url "dandavison/delta" ".*_amd64.deb")
|
||||
dpkg_name="${TMPDIR}/delta_amd64.deb"
|
||||
download "${dpkg_url}" "${dpkg_name}"
|
||||
sudo dpkg -i "${dpkg_name}"
|
||||
;;
|
||||
ropper)
|
||||
deb_only
|
||||
install_pkgs python3-z3
|
||||
pip3 install --user pyvex ropper
|
||||
;;
|
||||
@@ -476,41 +491,40 @@ EOF
|
||||
ln -sf "${DESTDIR}/completion/_kubens.zsh" "${COMPDIR}"
|
||||
;;
|
||||
starship)
|
||||
mkdir -p ${DESTDIR}
|
||||
mkdir -p "${DESTDIR}"
|
||||
download \
|
||||
"https://github.com/starship/starship/releases/latest/download/starship-x86_64-unknown-linux-musl.tar.gz" \
|
||||
/tmp/starship.tar.gz
|
||||
tar -C ${DESTDIR} -zxf /tmp/starship.tar.gz starship
|
||||
"https://github.com/starship/starship/releases/latest/download/starship-$(uname -m)-unknown-linux-musl.tar.gz" \
|
||||
"${TMPDIR}/starship.tar.gz"
|
||||
tar -C "${DESTDIR}" -zxf "${TMPDIR}/starship.tar.gz" starship
|
||||
add_bin_symlink starship
|
||||
;;
|
||||
arduino-cli)
|
||||
mkdir -p "${DESTDIR}"
|
||||
download \
|
||||
"https://downloads.arduino.cc/arduino-cli/arduino-cli_latest_Linux_64bit.tar.gz" \
|
||||
/tmp/arduino-cli.tar.gz
|
||||
tar -C "${DESTDIR}" -zxf /tmp/arduino-cli.tar.gz arduino-cli
|
||||
"${TMPDIR}/arduino-cli.tar.gz"
|
||||
tar -C "${DESTDIR}" -zxf "${TMPDIR}/arduino-cli.tar.gz" arduino-cli
|
||||
add_bin_symlink arduino-cli
|
||||
;;
|
||||
ghidra)
|
||||
zip_url=$(curl https://api.github.com/repos/NationalSecurityAgency/ghidra/releases/latest | \
|
||||
jq -r '.assets[] | select(.name|test(".*.zip")) | .browser_download_url')
|
||||
download "${zip_url}" /tmp/ghidra.zip
|
||||
unzip -d "${DESTDIR}" /tmp/ghidra.zip
|
||||
mv ${DESTDIR}/*/* ${DESTDIR}
|
||||
zip_url=$(get_latest_github_release_url "NationalSecurityAgency/ghidra" ".*\\.zip")
|
||||
download "${zip_url}" "${TMPDIR}/ghidra.zip"
|
||||
unzip -d "${DESTDIR}" "${TMPDIR}/ghidra.zip"
|
||||
mv "${DESTDIR}"/*/* "${DESTDIR}"
|
||||
add_bin_symlink ghidraRun ghidra
|
||||
;;
|
||||
doctl)
|
||||
# TODO: other architectures
|
||||
tar_url=$(curl https://api.github.com/repos/digitalocean/doctl/releases/latest | \
|
||||
jq -r '.assets[] | select(.name|test(".*linux-amd64\\.tar\\.gz")) | .browser_download_url')
|
||||
download "${tar_url}" /tmp/doctl.tar.gz
|
||||
tar_url=$(get_latest_github_release_url "digitalocean/doctl" ".*linux-amd64\\.tar\\.gz")
|
||||
download "${tar_url}" "${TMPDIR}/doctl.tar.gz"
|
||||
mkdir -p "${DESTDIR}"
|
||||
tar -C "${DESTDIR}" -zxf /tmp/doctl.tar.gz "doctl"
|
||||
tar -C "${DESTDIR}" -zxf "${TMPDIR}/doctl.tar.gz" "doctl"
|
||||
add_bin_symlink doctl
|
||||
;;
|
||||
rustup)
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
|
||||
sh -s -- --no-modify-path -y
|
||||
rustup_init="${TMPDIR}/rustup-init.sh"
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o "${rustup_init}"
|
||||
sh "${rustup_init}" --no-modify-path -y
|
||||
;;
|
||||
igrep)
|
||||
if ! command -v cargo >/dev/null 2>&1 ; then
|
||||
@@ -526,6 +540,21 @@ EOF
|
||||
fq)
|
||||
go install github.com/wader/fq@latest
|
||||
;;
|
||||
mise)
|
||||
if command -v brew >/dev/null 2>&1; then
|
||||
brew install mise
|
||||
else
|
||||
curl -sSL https://mise.jdx.dev/gpg-key.pub | gpg --import
|
||||
INSTALL_FILE_AND_SIG="${TMPDIR}/install.sh.sig"
|
||||
download "https://mise.jdx.dev/install.sh.sig" "${INSTALL_FILE_AND_SIG}"
|
||||
DECRYPTED_SCRIPT="${TMPDIR}/mise_install.sh"
|
||||
if gpg --assert-signer 24853EC9F655CE80B48E6C3A8B81C9D17413A06D --decrypt -o "${DECRYPTED_SCRIPT}" "${INSTALL_FILE_AND_SIG}" >/dev/null 2>&1; then
|
||||
sh "${DECRYPTED_SCRIPT}"
|
||||
else
|
||||
die "gpg verification or decryption failed for mise installer"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unknown tool: ${TOOL}" >/dev/stderr
|
||||
list_tools
|
||||
|
||||
546
bin/macos/chromebundles.py
Executable file
546
bin/macos/chromebundles.py
Executable file
@@ -0,0 +1,546 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import plistlib
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageEnhance
|
||||
|
||||
|
||||
DEFAULT_CHROME_APP = Path("/Applications/Google Chrome.app")
|
||||
DEFAULT_APPS_DIR = Path.home() / "Applications" / "Chrome Containers"
|
||||
|
||||
# Edit this list for your containers.
|
||||
CONTAINERS = [
|
||||
# {
|
||||
# "name": "Chrome Work",
|
||||
# "bundle_id": "com.example.chrome.work",
|
||||
# "mode": "persistent",
|
||||
# "profile_dir": str(Path.home() / ".chrome-work"),
|
||||
# "badge_path": str(Path.home() / ".chrome-container-badges" / "briefcase.svg"),
|
||||
# },
|
||||
{
|
||||
"name": "Chrome Family",
|
||||
"bundle_id": "com.example.chrome.family",
|
||||
"mode": "persistent",
|
||||
"profile_dir": str(Path.home() / ".chrome-family"),
|
||||
"badge_path": str(Path.home() / ".chrome-container-badges" / "family.svg"),
|
||||
},
|
||||
{
|
||||
"name": "Chrome Research",
|
||||
"bundle_id": "com.example.chrome.research",
|
||||
"mode": "persistent",
|
||||
"profile_dir": str(Path.home() / ".chrome-research"),
|
||||
"badge_path": str(Path.home() / ".chrome-container-badges" / "research.svg"),
|
||||
},
|
||||
{
|
||||
"name": "Chrome Ephemeral",
|
||||
"bundle_id": "com.example.chrome.ephemeral",
|
||||
"mode": "ephemeral",
|
||||
"profile_dir": None,
|
||||
"badge_path": str(Path.home() / ".chrome-container-badges" / "fire.svg"),
|
||||
},
|
||||
]
|
||||
|
||||
DEFAULT_COLOR_FACTOR = 0.55
|
||||
DEFAULT_BRIGHTNESS_FACTOR = 0.94
|
||||
DEFAULT_CONTRAST_FACTOR = 0.97
|
||||
DEFAULT_BADGE_FRACTION = 0.50
|
||||
DEFAULT_PADDING_FRACTION = 0.03
|
||||
DEFAULT_BADGE_OPACITY = 0.96
|
||||
|
||||
|
||||
def run(cmd, check=True, capture_output=False, text=True):
|
||||
return subprocess.run(cmd, check=check, capture_output=capture_output, text=text)
|
||||
|
||||
|
||||
def require_tool(name: str):
|
||||
if shutil.which(name) is None:
|
||||
print(f"Missing required tool: {name}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parse_icon_size(path: Path):
|
||||
name = path.name
|
||||
if not name.endswith(".png") or not name.startswith("icon_"):
|
||||
return (0, 0)
|
||||
|
||||
stem = name[:-4]
|
||||
rest = stem[len("icon_"):]
|
||||
scale = 1
|
||||
if rest.endswith("@2x"):
|
||||
rest = rest[:-3]
|
||||
scale = 2
|
||||
|
||||
try:
|
||||
left, right = rest.split("x", 1)
|
||||
return (int(left) * scale, int(right) * scale)
|
||||
except Exception:
|
||||
return (0, 0)
|
||||
|
||||
|
||||
def find_source_icns(app_path: Path) -> Path:
|
||||
info_plist = app_path / "Contents" / "Info.plist"
|
||||
resources_dir = app_path / "Contents" / "Resources"
|
||||
|
||||
if not info_plist.exists():
|
||||
raise FileNotFoundError(f"Missing Info.plist: {info_plist}")
|
||||
if not resources_dir.exists():
|
||||
raise FileNotFoundError(f"Missing Resources directory: {resources_dir}")
|
||||
|
||||
with info_plist.open("rb") as f:
|
||||
plist = plistlib.load(f)
|
||||
|
||||
icon_name = plist.get("CFBundleIconFile")
|
||||
if icon_name:
|
||||
if not icon_name.endswith(".icns"):
|
||||
icon_name += ".icns"
|
||||
candidate = resources_dir / icon_name
|
||||
if candidate.exists():
|
||||
return candidate
|
||||
|
||||
chrome_named = sorted(resources_dir.glob("*[Cc]hrome*.icns"))
|
||||
if chrome_named:
|
||||
return chrome_named[0]
|
||||
|
||||
any_icns = sorted(resources_dir.glob("*.icns"))
|
||||
if any_icns:
|
||||
return any_icns[0]
|
||||
|
||||
raise FileNotFoundError(f"No .icns file found in {resources_dir}")
|
||||
|
||||
|
||||
def extract_iconset(icns_path: Path, out_iconset: Path):
|
||||
run(["iconutil", "-c", "iconset", str(icns_path), "-o", str(out_iconset)])
|
||||
|
||||
|
||||
def largest_png(iconset_dir: Path) -> Path:
|
||||
pngs = list(iconset_dir.glob("*.png"))
|
||||
if not pngs:
|
||||
raise FileNotFoundError(f"No PNGs found in {iconset_dir}")
|
||||
pngs.sort(key=lambda p: parse_icon_size(p)[0] * parse_icon_size(p)[1], reverse=True)
|
||||
return pngs[0]
|
||||
|
||||
|
||||
def rasterize_svg(svg_path: Path, out_png: Path, size: int = 1024):
|
||||
# Prefer librsvg if installed.
|
||||
if shutil.which("rsvg-convert"):
|
||||
run([
|
||||
"rsvg-convert",
|
||||
"-w", str(size),
|
||||
"-h", str(size),
|
||||
"-o", str(out_png),
|
||||
str(svg_path),
|
||||
])
|
||||
return
|
||||
|
||||
# Fallback to Inkscape CLI if available.
|
||||
if shutil.which("inkscape"):
|
||||
run([
|
||||
"inkscape",
|
||||
str(svg_path),
|
||||
"--export-type=png",
|
||||
f"--export-filename={out_png}",
|
||||
"-w", str(size),
|
||||
"-h", str(size),
|
||||
])
|
||||
return
|
||||
|
||||
raise RuntimeError(
|
||||
f"SVG badge provided but no SVG rasterizer found for {svg_path}. "
|
||||
"Install librsvg (rsvg-convert) or Inkscape."
|
||||
)
|
||||
|
||||
|
||||
def load_badge_image(badge_path: Path, temp_dir: Path) -> Image.Image | None:
|
||||
if not badge_path.exists():
|
||||
print(f"Warning: badge file not found, skipping overlay: {badge_path}")
|
||||
return None
|
||||
|
||||
suffix = badge_path.suffix.lower()
|
||||
|
||||
if suffix == ".png":
|
||||
return Image.open(badge_path).convert("RGBA")
|
||||
|
||||
if suffix == ".svg":
|
||||
rasterized = temp_dir / f"{badge_path.stem}.png"
|
||||
rasterize_svg(badge_path, rasterized, size=1024)
|
||||
return Image.open(rasterized).convert("RGBA")
|
||||
|
||||
raise RuntimeError(
|
||||
f"Unsupported badge format for {badge_path}. "
|
||||
"Supported formats: .png, .svg"
|
||||
)
|
||||
|
||||
|
||||
def compose_icon(
|
||||
base_png: Path,
|
||||
badge_path: str | None,
|
||||
out_master: Path,
|
||||
color_factor: float,
|
||||
brightness_factor: float,
|
||||
contrast_factor: float,
|
||||
badge_fraction: float,
|
||||
padding_fraction: float,
|
||||
badge_opacity: float,
|
||||
temp_dir: Path,
|
||||
):
|
||||
base = Image.open(base_png).convert("RGBA")
|
||||
|
||||
muted = ImageEnhance.Color(base).enhance(color_factor)
|
||||
muted = ImageEnhance.Brightness(muted).enhance(brightness_factor)
|
||||
muted = ImageEnhance.Contrast(muted).enhance(contrast_factor)
|
||||
|
||||
result = muted.copy()
|
||||
|
||||
if badge_path:
|
||||
badge = load_badge_image(Path(badge_path).expanduser(), temp_dir)
|
||||
if badge is not None:
|
||||
w, h = result.size
|
||||
|
||||
max_badge_w = int(w * badge_fraction)
|
||||
max_badge_h = int(h * badge_fraction)
|
||||
pad = max(4, int(w * padding_fraction))
|
||||
|
||||
bw, bh = badge.size
|
||||
scale = min(max_badge_w / bw, max_badge_h / bh)
|
||||
new_size = (max(1, int(bw * scale)), max(1, int(bh * scale)))
|
||||
badge = badge.resize(new_size, Image.LANCZOS)
|
||||
|
||||
if badge_opacity < 1.0:
|
||||
alpha = badge.getchannel("A")
|
||||
alpha = ImageEnhance.Brightness(alpha).enhance(badge_opacity)
|
||||
badge.putalpha(alpha)
|
||||
|
||||
x = w - badge.width - pad
|
||||
y = h - badge.height - pad
|
||||
result.alpha_composite(badge, (x, y))
|
||||
|
||||
result.save(out_master)
|
||||
|
||||
|
||||
def build_iconset_from_master(master_png: Path, out_iconset: Path):
|
||||
out_iconset.mkdir(parents=True, exist_ok=True)
|
||||
img = Image.open(master_png).convert("RGBA")
|
||||
|
||||
sizes = [
|
||||
("icon_16x16.png", 16),
|
||||
("icon_16x16@2x.png", 32),
|
||||
("icon_32x32.png", 32),
|
||||
("icon_32x32@2x.png", 64),
|
||||
("icon_128x128.png", 128),
|
||||
("icon_128x128@2x.png", 256),
|
||||
("icon_256x256.png", 256),
|
||||
("icon_256x256@2x.png", 512),
|
||||
("icon_512x512.png", 512),
|
||||
("icon_512x512@2x.png", 1024),
|
||||
]
|
||||
|
||||
for filename, size in sizes:
|
||||
resized = img.resize((size, size), Image.LANCZOS)
|
||||
resized.save(out_iconset / filename)
|
||||
|
||||
|
||||
def iconset_to_icns(iconset_dir: Path, out_icns: Path):
|
||||
run(["iconutil", "-c", "icns", str(iconset_dir), "-o", str(out_icns)])
|
||||
|
||||
|
||||
def make_launch_script(chrome_bin: Path, mode: str, profile_dir: str | None) -> str:
|
||||
chrome_bin_escaped = str(chrome_bin).replace("\\", "\\\\").replace('"', '\\"')
|
||||
|
||||
if mode == "persistent":
|
||||
if not profile_dir:
|
||||
raise ValueError("Persistent container requires profile_dir")
|
||||
profile_dir_escaped = profile_dir.replace("\\", "\\\\").replace('"', '\\"')
|
||||
return f"""#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
CHROME_BIN="{chrome_bin_escaped}"
|
||||
PROFILE_DIR="{profile_dir_escaped}"
|
||||
|
||||
mkdir -p "$PROFILE_DIR"
|
||||
|
||||
exec "$CHROME_BIN" \\
|
||||
--user-data-dir="$PROFILE_DIR" \\
|
||||
--no-first-run \\
|
||||
--no-default-browser-check \\
|
||||
--new-window
|
||||
"""
|
||||
elif mode == "ephemeral":
|
||||
return f"""#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
CHROME_BIN="{chrome_bin_escaped}"
|
||||
PROFILE_DIR="$(mktemp -d /tmp/chrome-ephemeral-XXXXXX)"
|
||||
|
||||
cleanup() {{
|
||||
rm -rf "$PROFILE_DIR"
|
||||
}}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
exec "$CHROME_BIN" \\
|
||||
--user-data-dir="$PROFILE_DIR" \\
|
||||
--no-first-run \\
|
||||
--no-default-browser-check \\
|
||||
--new-window
|
||||
"""
|
||||
else:
|
||||
raise ValueError(f"Unknown mode: {mode}")
|
||||
|
||||
|
||||
def write_plist(app_name: str, bundle_id: str, plist_path: Path):
|
||||
plist = {
|
||||
"CFBundleDisplayName": app_name,
|
||||
"CFBundleExecutable": "launch",
|
||||
"CFBundleIdentifier": bundle_id,
|
||||
"CFBundleName": app_name,
|
||||
"CFBundlePackageType": "APPL",
|
||||
"CFBundleShortVersionString": "1.0",
|
||||
"CFBundleVersion": "1",
|
||||
"LSMinimumSystemVersion": "12.0",
|
||||
"NSHighResolutionCapable": True,
|
||||
"CFBundleIconFile": "applet",
|
||||
}
|
||||
with plist_path.open("wb") as f:
|
||||
plistlib.dump(plist, f)
|
||||
|
||||
|
||||
def codesign_app(app_dir: Path):
|
||||
try:
|
||||
run(["/usr/bin/codesign", "--force", "--deep", "--sign", "-", str(app_dir)])
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Warning: codesign failed for {app_dir}: {e}")
|
||||
|
||||
|
||||
def sanitize_container(container: dict) -> dict:
|
||||
required = ["name", "bundle_id", "mode"]
|
||||
for key in required:
|
||||
if key not in container or not container[key]:
|
||||
raise ValueError(f"Container missing required key: {key}")
|
||||
|
||||
mode = container["mode"]
|
||||
if mode not in {"persistent", "ephemeral"}:
|
||||
raise ValueError(f"Invalid mode for {container['name']}: {mode}")
|
||||
|
||||
if mode == "persistent" and not container.get("profile_dir"):
|
||||
raise ValueError(f"Persistent container missing profile_dir: {container['name']}")
|
||||
|
||||
return container
|
||||
|
||||
|
||||
def container_matches_filter(name: str, only_names: set[str]) -> bool:
|
||||
if not only_names:
|
||||
return True
|
||||
return name in only_names
|
||||
|
||||
|
||||
def build_icon_for_app(
|
||||
source_icns: Path,
|
||||
badge_path: str | None,
|
||||
out_icns: Path,
|
||||
color_factor: float,
|
||||
brightness_factor: float,
|
||||
contrast_factor: float,
|
||||
badge_fraction: float,
|
||||
padding_fraction: float,
|
||||
badge_opacity: float,
|
||||
):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
tmpdir = Path(tmp)
|
||||
base_iconset = tmpdir / "base.iconset"
|
||||
new_iconset = tmpdir / "new.iconset"
|
||||
master_png = tmpdir / "master.png"
|
||||
|
||||
extract_iconset(source_icns, base_iconset)
|
||||
base_png = largest_png(base_iconset)
|
||||
size = parse_icon_size(base_png)
|
||||
print(f" Base icon source: {base_png.name} ({size[0]}x{size[1]})")
|
||||
|
||||
compose_icon(
|
||||
base_png=base_png,
|
||||
badge_path=badge_path,
|
||||
out_master=master_png,
|
||||
color_factor=color_factor,
|
||||
brightness_factor=brightness_factor,
|
||||
contrast_factor=contrast_factor,
|
||||
badge_fraction=badge_fraction,
|
||||
padding_fraction=padding_fraction,
|
||||
badge_opacity=badge_opacity,
|
||||
temp_dir=tmpdir,
|
||||
)
|
||||
build_iconset_from_master(master_png, new_iconset)
|
||||
iconset_to_icns(new_iconset, out_icns)
|
||||
|
||||
|
||||
def create_or_update_container(
|
||||
container: dict,
|
||||
apps_dir: Path,
|
||||
chrome_bin: Path,
|
||||
source_icns: Path,
|
||||
force: bool,
|
||||
update_icons_only: bool,
|
||||
codesign: bool,
|
||||
color_factor: float,
|
||||
brightness_factor: float,
|
||||
contrast_factor: float,
|
||||
badge_fraction: float,
|
||||
padding_fraction: float,
|
||||
badge_opacity: float,
|
||||
):
|
||||
app_name = container["name"]
|
||||
bundle_id = container["bundle_id"]
|
||||
mode = container["mode"]
|
||||
profile_dir = container.get("profile_dir")
|
||||
badge_path = container.get("badge_path")
|
||||
|
||||
app_dir = apps_dir / f"{app_name}.app"
|
||||
contents_dir = app_dir / "Contents"
|
||||
macos_dir = contents_dir / "MacOS"
|
||||
resources_dir = contents_dir / "Resources"
|
||||
out_icns = resources_dir / "applet.icns"
|
||||
|
||||
exists = app_dir.exists()
|
||||
|
||||
if update_icons_only:
|
||||
if not exists:
|
||||
print(f"Skipping missing app for icon update: {app_dir}")
|
||||
return
|
||||
print(f"Updating icon only for {app_name}...")
|
||||
resources_dir.mkdir(parents=True, exist_ok=True)
|
||||
build_icon_for_app(
|
||||
source_icns,
|
||||
badge_path,
|
||||
out_icns,
|
||||
color_factor,
|
||||
brightness_factor,
|
||||
contrast_factor,
|
||||
badge_fraction,
|
||||
padding_fraction,
|
||||
badge_opacity,
|
||||
)
|
||||
if codesign:
|
||||
codesign_app(app_dir)
|
||||
print(f" Updated icon: {out_icns}")
|
||||
return
|
||||
|
||||
if exists and not force:
|
||||
print(f"Skipping existing app: {app_dir}")
|
||||
return
|
||||
|
||||
if exists and force:
|
||||
print(f"Recreating existing app: {app_dir}")
|
||||
shutil.rmtree(app_dir)
|
||||
else:
|
||||
print(f"Creating {app_name}...")
|
||||
|
||||
macos_dir.mkdir(parents=True, exist_ok=True)
|
||||
resources_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
write_plist(app_name, bundle_id, contents_dir / "Info.plist")
|
||||
|
||||
launch_script = make_launch_script(chrome_bin, mode, profile_dir)
|
||||
launch_path = macos_dir / "launch"
|
||||
launch_path.write_text(launch_script, encoding="utf-8")
|
||||
launch_path.chmod(launch_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
|
||||
if mode == "persistent":
|
||||
Path(profile_dir).expanduser().mkdir(parents=True, exist_ok=True)
|
||||
|
||||
build_icon_for_app(
|
||||
source_icns,
|
||||
badge_path,
|
||||
out_icns,
|
||||
color_factor,
|
||||
brightness_factor,
|
||||
contrast_factor,
|
||||
badge_fraction,
|
||||
padding_fraction,
|
||||
badge_opacity,
|
||||
)
|
||||
|
||||
if codesign:
|
||||
codesign_app(app_dir)
|
||||
|
||||
print(f" Created: {app_dir}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Create and manage Chrome container wrapper apps on macOS.")
|
||||
parser.add_argument("--chrome-app", default=str(DEFAULT_CHROME_APP), help="Path to Chrome app bundle")
|
||||
parser.add_argument("--apps-dir", default=str(DEFAULT_APPS_DIR), help="Directory for generated wrapper apps")
|
||||
parser.add_argument("--force", action="store_true", help="Recreate containers even if they already exist")
|
||||
parser.add_argument("--update-icons-only", action="store_true", help="Only rebuild icons for existing containers")
|
||||
parser.add_argument("--no-codesign", action="store_true", help="Skip ad-hoc codesigning")
|
||||
parser.add_argument(
|
||||
"--only",
|
||||
action="append",
|
||||
default=[],
|
||||
help="Limit to specific container name; can be passed multiple times",
|
||||
)
|
||||
parser.add_argument("--color-factor", type=float, default=DEFAULT_COLOR_FACTOR)
|
||||
parser.add_argument("--brightness-factor", type=float, default=DEFAULT_BRIGHTNESS_FACTOR)
|
||||
parser.add_argument("--contrast-factor", type=float, default=DEFAULT_CONTRAST_FACTOR)
|
||||
parser.add_argument("--badge-fraction", type=float, default=DEFAULT_BADGE_FRACTION)
|
||||
parser.add_argument("--padding-fraction", type=float, default=DEFAULT_PADDING_FRACTION)
|
||||
parser.add_argument("--badge-opacity", type=float, default=DEFAULT_BADGE_OPACITY)
|
||||
args = parser.parse_args()
|
||||
|
||||
require_tool("iconutil")
|
||||
|
||||
chrome_app = Path(args.chrome_app).expanduser().resolve()
|
||||
apps_dir = Path(args.apps_dir).expanduser().resolve()
|
||||
chrome_bin = chrome_app / "Contents" / "MacOS" / "Google Chrome"
|
||||
|
||||
if not chrome_bin.exists():
|
||||
print(f"Chrome binary not found: {chrome_bin}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
import PIL # noqa: F401
|
||||
except ImportError:
|
||||
print("Pillow is required. Install it with:", file=sys.stderr)
|
||||
print(" python3 -m pip install --user pillow", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
source_icns = find_source_icns(chrome_app)
|
||||
apps_dir.mkdir(parents=True, exist_ok=True)
|
||||
only_names = set(args.only)
|
||||
|
||||
print(f"Using Python: {sys.executable}")
|
||||
print(f"Using Chrome app: {chrome_app}")
|
||||
print(f"Using source icon: {source_icns}")
|
||||
print(f"Apps directory: {apps_dir}")
|
||||
print()
|
||||
|
||||
for raw_container in CONTAINERS:
|
||||
container = sanitize_container(raw_container)
|
||||
if not container_matches_filter(container["name"], only_names):
|
||||
continue
|
||||
|
||||
create_or_update_container(
|
||||
container=container,
|
||||
apps_dir=apps_dir,
|
||||
chrome_bin=chrome_bin,
|
||||
source_icns=source_icns,
|
||||
force=args.force,
|
||||
update_icons_only=args.update_icons_only,
|
||||
codesign=not args.no_codesign,
|
||||
color_factor=args.color_factor,
|
||||
brightness_factor=args.brightness_factor,
|
||||
contrast_factor=args.contrast_factor,
|
||||
badge_fraction=args.badge_fraction,
|
||||
padding_fraction=args.padding_fraction,
|
||||
badge_opacity=args.badge_opacity,
|
||||
)
|
||||
print()
|
||||
|
||||
print("Done.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
156
bin/macos/update_brewfile
Executable file
156
bin/macos/update_brewfile
Executable file
@@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import re
|
||||
import sys
|
||||
import argparse
|
||||
import difflib
|
||||
|
||||
# Regex to match brew/cask/tap/mas lines
|
||||
PKG_RE = re.compile(r'^\s*(brew|cask|tap|mas)\s+["\']([^"\']+)["\'](.*)$')
|
||||
|
||||
def get_repo_root():
|
||||
try:
|
||||
root = subprocess.check_output(['git', 'rev-parse', '--show-toplevel'],
|
||||
stderr=subprocess.STDOUT).decode().strip()
|
||||
return root
|
||||
except subprocess.CalledProcessError:
|
||||
return os.getcwd()
|
||||
|
||||
def get_ignore_list(repo_root):
|
||||
ignore = set()
|
||||
paths = [
|
||||
os.path.join(repo_root, '.Brewfile.ignore'),
|
||||
os.path.expanduser('~/.Brewfile.ignore'),
|
||||
os.path.expanduser('~/.config/homebrew/ignore')
|
||||
]
|
||||
for path in paths:
|
||||
if os.path.exists(path):
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
line = line.split('#')[0].strip()
|
||||
if line:
|
||||
ignore.add(line)
|
||||
return ignore
|
||||
|
||||
def get_current_packages():
|
||||
"""Runs brew bundle dump and returns lines."""
|
||||
try:
|
||||
output = subprocess.check_output(['brew', 'bundle', 'dump', '--file=-'],
|
||||
stderr=subprocess.DEVNULL).decode()
|
||||
return output.splitlines()
|
||||
except subprocess.CalledProcessError:
|
||||
print("Error: 'brew bundle dump' failed. Is homebrew installed?", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def parse_brewfile(content):
|
||||
"""
|
||||
Parses Brewfile content.
|
||||
Returns:
|
||||
- conditional_pkgs: set of (type, name)
|
||||
- preserved_footer: string (everything from first conditional onwards)
|
||||
"""
|
||||
lines = content.splitlines()
|
||||
conditional_pkgs = set()
|
||||
|
||||
# Find the start of the first conditional block
|
||||
first_conditional_idx = -1
|
||||
in_conditional = 0
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith(('if ', 'unless ', 'case ')) and not stripped.endswith('; end'):
|
||||
if first_conditional_idx == -1:
|
||||
# Look back for comments that might belong to this block
|
||||
j = i - 1
|
||||
while j >= 0 and (lines[j].strip().startswith('#') or not lines[j].strip()):
|
||||
j -= 1
|
||||
first_conditional_idx = j + 1
|
||||
in_conditional += 1
|
||||
|
||||
if in_conditional > 0:
|
||||
match = PKG_RE.match(line)
|
||||
if match:
|
||||
conditional_pkgs.add((match.group(1), match.group(2)))
|
||||
|
||||
if stripped == 'end' or stripped.endswith('; end'):
|
||||
in_conditional -= 1
|
||||
|
||||
if first_conditional_idx == -1:
|
||||
return set(), ""
|
||||
|
||||
footer = "\n".join(lines[first_conditional_idx:])
|
||||
return conditional_pkgs, footer
|
||||
|
||||
def main(args):
|
||||
repo_root = get_repo_root()
|
||||
brewfile_path = os.path.join(repo_root, 'Brewfile')
|
||||
|
||||
if not os.path.exists(brewfile_path):
|
||||
print(f"Error: Brewfile not found at {brewfile_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
with open(brewfile_path) as f:
|
||||
old_content = f.read()
|
||||
|
||||
conditional_pkgs, footer = parse_brewfile(old_content)
|
||||
ignore_list = get_ignore_list(repo_root)
|
||||
|
||||
dumped_lines = get_current_packages()
|
||||
|
||||
new_unconditional_lines = []
|
||||
|
||||
for line in dumped_lines:
|
||||
match = PKG_RE.match(line)
|
||||
if match:
|
||||
pkg_type, pkg_name = match.group(1), match.group(2)
|
||||
if pkg_name in ignore_list:
|
||||
continue
|
||||
if (pkg_type, pkg_name) in conditional_pkgs:
|
||||
continue
|
||||
|
||||
# If it's not a package line (e.g. comment from dump), we can skip or keep
|
||||
if line.strip():
|
||||
new_unconditional_lines.append(line)
|
||||
|
||||
# Sort lines by type (tap, brew, cask, mas) then name
|
||||
def sort_key(line):
|
||||
match = PKG_RE.match(line)
|
||||
if not match: return (4, line)
|
||||
order = {'tap': 0, 'brew': 1, 'cask': 2, 'mas': 3}
|
||||
return (order.get(match.group(1), 4), match.group(2))
|
||||
|
||||
new_unconditional_lines.sort(key=sort_key)
|
||||
|
||||
# Build new content
|
||||
new_content = "\n".join(new_unconditional_lines)
|
||||
if footer:
|
||||
if new_unconditional_lines:
|
||||
new_content += "\n\n"
|
||||
new_content += footer.strip() + "\n"
|
||||
else:
|
||||
new_content += "\n"
|
||||
|
||||
if new_content == old_content:
|
||||
print("Brewfile is already up to date.")
|
||||
else:
|
||||
if args.dry_run:
|
||||
print("Changes detected (dry run):")
|
||||
diff = difflib.unified_diff(
|
||||
old_content.splitlines(keepends=True),
|
||||
new_content.splitlines(keepends=True),
|
||||
fromfile='Brewfile (original)',
|
||||
tofile='Brewfile (new)'
|
||||
)
|
||||
sys.stdout.writelines(diff)
|
||||
else:
|
||||
with open(brewfile_path, 'w') as f:
|
||||
f.write(new_content)
|
||||
print("Brewfile updated.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Update Brewfile while preserving conditionals.")
|
||||
parser.add_argument("--dry-run", action="store_true", help="Show changes without applying them.")
|
||||
args = parser.parse_args()
|
||||
main(args)
|
||||
@@ -5,7 +5,7 @@ function list_nvidia_installed {
|
||||
}
|
||||
|
||||
function hold_or_unhold {
|
||||
apt-mark "${1:-hold}" $(list_nvidia_installed)
|
||||
list_nvidia_installed | xargs apt-mark "${1:-hold}"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
|
||||
@@ -37,7 +37,7 @@ function volume {
|
||||
|
||||
case "$1" in
|
||||
mute|micmute|volume)
|
||||
$*
|
||||
"$@"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command!"
|
||||
|
||||
46
bin/prune-broken-symlinks.sh
Executable file
46
bin/prune-broken-symlinks.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2039,SC2086
|
||||
|
||||
set -o nounset
|
||||
|
||||
prune_broken_symlinks() {
|
||||
ask=1
|
||||
dir="."
|
||||
|
||||
if [ "${1:-}" = "-y" ]; then
|
||||
ask=0
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ -n "${1:-}" ]; then
|
||||
dir="$1"
|
||||
fi
|
||||
|
||||
# Check if there are any broken symlinks first
|
||||
broken_links=$(find -L "$dir" -xdev -type l -print 2>/dev/null)
|
||||
if [ -z "$broken_links" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$ask" -eq 1 ]; then
|
||||
# Print broken links
|
||||
echo "$broken_links"
|
||||
|
||||
printf "Delete these links? [y/N] "
|
||||
read -r reply
|
||||
case "$reply" in
|
||||
[yY]*)
|
||||
;;
|
||||
*)
|
||||
echo "Aborted."
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Perform deletion
|
||||
find -L "$dir" -xdev -type l -exec rm -- {} + 2>/dev/null
|
||||
}
|
||||
|
||||
# Execute the function
|
||||
prune_broken_symlinks "$@"
|
||||
@@ -43,6 +43,6 @@ function get_bridge_ifaces {
|
||||
bridge link | grep "master ${1}" | cut -d: -f2 | cut -d@ -f1
|
||||
}
|
||||
|
||||
for iface in $(get_bridge_ifaces "${BRIDGE}") ; do
|
||||
get_bridge_ifaces "${BRIDGE}" | while IFS= read -r iface ; do
|
||||
handle_iface "$iface"
|
||||
done
|
||||
|
||||
5
bin/remove-wine-associations
Executable file
5
bin/remove-wine-associations
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
rm -f ~/.local/share/applications/wine*.desktop
|
||||
update-desktop-database ~/.local/share/applications
|
||||
rm -f ~/.local/share/mime/packages/x-wine*.xml
|
||||
update-mime-database ~/.local/share/mime
|
||||
83
bin/resign_for_debug.sh
Executable file
83
bin/resign_for_debug.sh
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Default values
|
||||
FORCE=false
|
||||
TARGET_PATH=""
|
||||
DEST_PATH=""
|
||||
|
||||
# Parse flags (looking for -f)
|
||||
while getopts "f" opt; do
|
||||
case $opt in
|
||||
f) FORCE=true ;;
|
||||
*) echo "Usage: $0 [-f] <binary_name_or_path> [destination]"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
# Check for first argument
|
||||
if [ -z "$1" ]; then
|
||||
echo "Error: No binary specified."
|
||||
echo "Usage: $0 [-f] <binary_name_or_path> [destination]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 1. Resolve the Source Binary
|
||||
if [[ "$1" == *"/"* ]]; then
|
||||
SOURCE_BIN="$1"
|
||||
else
|
||||
SOURCE_BIN=$(command -v "$1")
|
||||
fi
|
||||
|
||||
if [ ! -f "$SOURCE_BIN" ]; then
|
||||
echo "Error: Could not find binary at '$1'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. Determine Destination Path
|
||||
if [ -n "$2" ]; then
|
||||
DEST_PATH="$2"
|
||||
# If destination is a directory, append the basename
|
||||
if [ -d "$DEST_PATH" ]; then
|
||||
DEST_PATH="${DEST_PATH%/}/$(basename "$SOURCE_BIN")"
|
||||
fi
|
||||
else
|
||||
# No destination given: create a temp directory
|
||||
TMP_DIR=$(mktemp -d -t "debug_unlock_XXXXXX")
|
||||
DEST_PATH="$TMP_DIR/$(basename "$SOURCE_BIN")"
|
||||
echo "Notice: No destination provided. Using temp path: $DEST_PATH"
|
||||
fi
|
||||
|
||||
# 3. Check for Collision
|
||||
if [ -f "$DEST_PATH" ] && [ "$FORCE" = false ]; then
|
||||
echo "Error: Destination '$DEST_PATH' already exists. Use -f to overwrite."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 4. Copy and Sign
|
||||
cp -f "$SOURCE_BIN" "$DEST_PATH"
|
||||
chmod +x "$DEST_PATH"
|
||||
|
||||
ENTITLEMENTS_FILE=$(mktemp)
|
||||
cat <<EOF > "$ENTITLEMENTS_FILE"
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.get-task-allow</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
echo "Unlocking: $SOURCE_BIN -> $DEST_PATH"
|
||||
codesign -s - --entitlements "$ENTITLEMENTS_FILE" -f "$DEST_PATH" 2>/dev/null
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Success! You can now debug: $DEST_PATH"
|
||||
else
|
||||
echo "❌ Error: Code signing failed."
|
||||
fi
|
||||
|
||||
rm "$ENTITLEMENTS_FILE"
|
||||
26
bin/restic.sh
Executable file
26
bin/restic.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script to execute a restic backup script specific to the current hostname.
|
||||
#
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
# Get the current hostname
|
||||
HOSTNAME=$(hostname)
|
||||
|
||||
# Define the directory where hostname-specific scripts are stored
|
||||
RESTIC_SCRIPTS_DIR="${HOME}/bin/restic"
|
||||
|
||||
# Construct the full path to the hostname-specific script
|
||||
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}"
|
||||
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
|
||||
exit 1
|
||||
fi
|
||||
165
bin/restic/baymax
Executable file
165
bin/restic/baymax
Executable file
@@ -0,0 +1,165 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# A script to backup a single-user MacBook using restic to either a local
|
||||
# filesystem or Backblaze B2.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
# --- Configuration ---
|
||||
# Directory to be backed up.
|
||||
# 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"
|
||||
|
||||
# --- Functions ---
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") [-l /path/to/repo | -b [bucket]] [-u UPLOAD_LIMIT]
|
||||
|
||||
A script to backup a single-user MacBook using restic.
|
||||
|
||||
Options:
|
||||
-l <path> Backup to a local filesystem repository at the given path.
|
||||
-b [bucket] Backup to a Backblaze B2 bucket. The bucket name is optional.
|
||||
If not provided, it will be read from the B2_BUCKET_NAME
|
||||
environment variable.
|
||||
-u <limit> Limit the upload speed to the given value in KB/s.
|
||||
-h Show this help message.
|
||||
EOF
|
||||
}
|
||||
|
||||
# --- Main Script ---
|
||||
# Check if restic is installed
|
||||
if ! command -v restic &> /dev/null; then
|
||||
echo "Error: restic command not found." >&2
|
||||
echo "Please install restic first: https://restic.net/" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKUP_MODE=""
|
||||
REPO=""
|
||||
UPLOAD_LIMIT=""
|
||||
|
||||
while getopts ":l:bu:h" opt; do
|
||||
case ${opt} in
|
||||
l)
|
||||
BACKUP_MODE="local"
|
||||
REPO="${OPTARG}"
|
||||
;;
|
||||
b)
|
||||
BACKUP_MODE="b2"
|
||||
if [[ ${OPTIND} -le $# && "${!OPTIND}" != -* ]]; then
|
||||
REPO="b2:${!OPTIND}:"
|
||||
OPTIND=$((OPTIND + 1))
|
||||
fi
|
||||
;;
|
||||
u)
|
||||
UPLOAD_LIMIT="${OPTARG}"
|
||||
;;
|
||||
h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -${OPTARG}" >&2
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
:)
|
||||
echo "Option -${OPTARG} requires an argument." >&2
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# --- Pre-run checks ---
|
||||
if [[ -z "${BACKUP_MODE}" ]]; then
|
||||
echo "Error: You must specify a backup mode (-l or -b)." >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${BACKUP_MODE}" == "b2" ]]; then
|
||||
if [[ -f "${HOME}/.resticb2" ]] ; then
|
||||
. "${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
|
||||
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
|
||||
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
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
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"
|
||||
# Source file?
|
||||
elif [[ -f "${HOME}/.resticpass" ]] ; then
|
||||
export RESTIC_PASSWORD_FILE="${HOME}/.resticpass"
|
||||
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
|
||||
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\""
|
||||
|
||||
if [[ -n "${UPLOAD_LIMIT}" ]]; then
|
||||
BACKUP_CMD="${BACKUP_CMD} --limit-upload ${UPLOAD_LIMIT}"
|
||||
fi
|
||||
|
||||
BACKUP_CMD="${BACKUP_CMD} \"${SOURCE_DIR}\""
|
||||
|
||||
eval "${BACKUP_CMD}"
|
||||
|
||||
echo "Backup complete."
|
||||
|
||||
# --- Prune old snapshots (optional, but recommended) ---
|
||||
# Keeps the last 7 daily, 4 weekly, and 6 monthly snapshots.
|
||||
echo "Pruning old snapshots..."
|
||||
restic forget \
|
||||
--repo "${REPO}" \
|
||||
--keep-daily 7 \
|
||||
--keep-weekly 4 \
|
||||
--keep-monthly 6 \
|
||||
--prune
|
||||
|
||||
echo "Pruning complete."
|
||||
echo "Restic backup script finished."
|
||||
37
bin/restic/scar
Executable file
37
bin/restic/scar
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ue
|
||||
|
||||
export RESTIC_DEFAULT_BE="google"
|
||||
export RESTIC_PASSWORD_FILE=${HOME}/.restic-password
|
||||
|
||||
case "${RESTIC_BACKEND:=${RESTIC_DEFAULT_BE}}" in
|
||||
google)
|
||||
export GOOGLE_PROJECT_ID=systemoverlord.com:systemoverlord
|
||||
export GOOGLE_APPLICATION_CREDENTIALS=${HOME}/.config/boto/restic-creds.json
|
||||
export RESTIC_REPOSITORY="gs:systemoverlord-backups-scar-2:/"
|
||||
;;
|
||||
b2)
|
||||
. "${HOME}/.restic-backups-scar-creds"
|
||||
export AWS_ACCESS_KEY_ID
|
||||
export AWS_SECRET_ACCESS_KEY
|
||||
export RESTIC_REPOSITORY="s3:s3.us-west-004.backblazeb2.com/systemoverlord-backups-scar"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown restic backend $RESTIC_BACKEND" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
cd "${HOME}"
|
||||
|
||||
if [ -z "${1}" ] ; then
|
||||
|
||||
restic backup \
|
||||
--files-from "${HOME}/.restic-backup" \
|
||||
--limit-upload 5000 \
|
||||
--limit-download 10000
|
||||
|
||||
else
|
||||
restic "$@"
|
||||
fi
|
||||
@@ -25,14 +25,6 @@ function flameshot_gui_capture {
|
||||
flameshot gui -p "${SCREENDIR}"
|
||||
}
|
||||
|
||||
function flameshot_region_capture {
|
||||
flameshot_gui_capture
|
||||
}
|
||||
|
||||
function flameshot_window_capture {
|
||||
flameshot_gui_capture
|
||||
}
|
||||
|
||||
function flameshot_full_capture {
|
||||
flameshot full -p "${SCREENDIR}"
|
||||
}
|
||||
@@ -52,7 +44,35 @@ function scrot_full_capture {
|
||||
case "${CMD}" in
|
||||
region|window|full)
|
||||
mkdir -p "${SCREENDIR}"
|
||||
${TOOL}_${CMD}_capture
|
||||
case "${TOOL}" in
|
||||
flameshot)
|
||||
case "${CMD}" in
|
||||
region|window)
|
||||
flameshot_gui_capture
|
||||
;;
|
||||
full)
|
||||
flameshot_full_capture
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
scrot)
|
||||
case "${CMD}" in
|
||||
region)
|
||||
scrot_region_capture
|
||||
;;
|
||||
window)
|
||||
scrot_window_capture
|
||||
;;
|
||||
full)
|
||||
scrot_full_capture
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unknown or unsupported tool '${TOOL}'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
set -ue
|
||||
|
||||
VER="v2.2.2"
|
||||
VER="v3.4.0"
|
||||
|
||||
FONTS=(
|
||||
https://github.com/ryanoasis/nerd-fonts/releases/download/${VER}/DejaVuSansMono.zip
|
||||
@@ -13,14 +13,21 @@ FONTS=(
|
||||
https://github.com/ryanoasis/nerd-fonts/releases/download/${VER}/OpenDyslexic.zip
|
||||
)
|
||||
|
||||
FPATH=${HOME}/.fonts/nerdfonts
|
||||
mkdir -p ${FPATH}
|
||||
cd ${FPATH}
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
FPATH="${HOME}/Library/Fonts"
|
||||
else
|
||||
FPATH="${HOME}/.local/share/fonts/nerdfonts"
|
||||
fi
|
||||
|
||||
for f in ${FONTS[@]}; do
|
||||
BN=$(basename $f)
|
||||
wget -O ${FPATH}/${BN} ${f}
|
||||
unzip -o -d ${FPATH} ${FPATH}/${BN}
|
||||
mkdir -p "${FPATH}"
|
||||
cd "${FPATH}"
|
||||
|
||||
for f in "${FONTS[@]}"; do
|
||||
BN=$(basename "$f")
|
||||
wget -O "${FPATH}/${BN}" "$f"
|
||||
unzip -o -d "${FPATH}" "${FPATH}/${BN}"
|
||||
done
|
||||
|
||||
if command -v fc-cache >/dev/null 2>&1; then
|
||||
fc-cache -v
|
||||
fi
|
||||
|
||||
18
bin/setup/spicerandr.sh
Normal file
18
bin/setup/spicerandr.sh
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ue
|
||||
|
||||
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
|
||||
export DISPLAY=:0
|
||||
export XAUTHORITY=$(eval echo "~$desktopuser")/.Xauthority
|
||||
/usr/bin/xrandr --output $(/usr/bin/xrandr | awk '/ connected/{print $1; exit; }') --auto
|
||||
EOF
|
||||
chmod 755 /usr/local/bin/x-resize
|
||||
|
||||
cat >/etc/udev/rules.d/50-resize.rules <<"EOF"
|
||||
ACTION=="change",KERNEL=="card0", SUBSYSTEM=="drm", RUN+="/usr/local/bin/x-resize"
|
||||
EOF
|
||||
chmod 644 /etc/udev/rules.d/50-resize.rules
|
||||
36
bin/smart-copy-paste
Executable file
36
bin/smart-copy-paste
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# smart-copy-paste
|
||||
#
|
||||
# This script provides context-aware copy and paste operations, mimicking
|
||||
# macOS behavior (Alt+C/V) while correctly handling terminals that require
|
||||
# the Shift key.
|
||||
|
||||
# Exit silently if xdotool is not installed.
|
||||
if ! command -v xdotool > /dev/null; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the class name of the currently focused window.
|
||||
# We need to get the window on focus, to avoid issues with transparent terminals.
|
||||
class=$(xdotool getwindowclassname "$(xdotool getwindowfocus)")
|
||||
|
||||
# Semicolon-separated list of terminal class names.
|
||||
terminals='Gnome-terminal;Xfce4-terminal;konsole;xterm;URxvt;Terminator;Alacritty;kitty;wezterm'
|
||||
|
||||
# Determine the keystroke based on the window type and the argument passed.
|
||||
if echo "$terminals" | grep -q "$class"; then
|
||||
# This is a terminal, so use Shift.
|
||||
if [ "$1" = "copy" ]; then
|
||||
xdotool key --clearmodifiers ctrl+shift+c
|
||||
elif [ "$1" = "paste" ]; then
|
||||
xdotool key --clearmodifiers ctrl+shift+v
|
||||
fi
|
||||
else
|
||||
# This is a standard GUI app.
|
||||
if [ "$1" = "copy" ]; then
|
||||
xdotool key --clearmodifiers ctrl+c
|
||||
elif [ "$1" = "paste" ]; then
|
||||
xdotool key --clearmodifiers ctrl+v
|
||||
fi
|
||||
fi
|
||||
164
bin/ssh-sign
Executable file
164
bin/ssh-sign
Executable file
@@ -0,0 +1,164 @@
|
||||
#!/bin/bash
|
||||
# A robust wrapper for ssh-keygen to sign and verify files.
|
||||
|
||||
# --- Color Codes for Output ---
|
||||
COLOR_RED='\033[0;31m'
|
||||
COLOR_GREEN='\033[0;32m'
|
||||
COLOR_NONE='\033[0m' # No Color
|
||||
|
||||
# --- Default values ---
|
||||
DEFAULT_SIGNING_KEY="$HOME/.ssh/id_signing"
|
||||
DEFAULT_ALLOWED_SIGNERS="$HOME/.ssh/allowed_signers"
|
||||
DEFAULT_IDENTITY="david@systemoverlord.com"
|
||||
DEFAULT_NAMESPACE="file"
|
||||
|
||||
# --- Usage Message ---
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") <sign|verify> [OPTIONS] [FILE]
|
||||
|
||||
A wrapper for 'ssh-keygen -Y' to simplify file signing and verification.
|
||||
|
||||
COMMANDS:
|
||||
sign Sign a file. The path to the file to be signed is provided as a positional argument.
|
||||
verify Verify a signature. The original file content is read from stdin.
|
||||
|
||||
OPTIONS:
|
||||
-f <file> For 'sign': Path to the private key for signing.
|
||||
Defaults to '$DEFAULT_SIGNING_KEY' if it exists.
|
||||
For 'verify': Path to the allowed_signers file.
|
||||
Defaults to '$DEFAULT_ALLOWED_SIGNERS'.
|
||||
-n <namespace> Signature namespace.
|
||||
Defaults to '$DEFAULT_NAMESPACE'.
|
||||
-I <identity> For 'verify': The identity to check the signature against.
|
||||
Defaults to '$DEFAULT_IDENTITY'.
|
||||
-s <sig_file> For 'verify': Path to the signature file to verify (e.g., file.sig). REQUIRED for verify.
|
||||
-h, --help Show this help message.
|
||||
|
||||
EXAMPLE USAGE:
|
||||
# Sign a file using the default key
|
||||
$(basename "$0") sign release.tar.gz
|
||||
|
||||
# Sign a file with a specific key
|
||||
$(basename "$0") sign -f ~/.ssh/id_ed25519_my_signing_key release.tar.gz
|
||||
|
||||
# Verify a signature using default allowed_signers and identity
|
||||
cat release.tar.gz | $(basename "$0") verify -s release.tar.gz.sig
|
||||
|
||||
# Verify a signature with a specific allowed_signers file and identity
|
||||
cat release.tar.gz | $(basename "$0") verify -f ./my_signers -I other@example.com -s release.tar.gz.sig
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Helper for error messages ---
|
||||
error() {
|
||||
echo -e "${COLOR_RED}Error: $1${COLOR_NONE}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Main Script Logic ---
|
||||
|
||||
if [[ "$1" != "sign" && "$1" != "verify" ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
SUBCOMMAND=$1
|
||||
shift # Consume the subcommand
|
||||
|
||||
# --- Argument Parsing and Validation ---
|
||||
|
||||
# Separate arguments from the file to be signed
|
||||
declare -a remaining_args
|
||||
file_to_sign=""
|
||||
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")
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
# --- Build command based on subcommand ---
|
||||
declare -a CMD_ARGS
|
||||
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."
|
||||
fi
|
||||
|
||||
# Set default signing key if -f was not provided
|
||||
if ! $f_provided; then
|
||||
if [[ ! -f "$DEFAULT_SIGNING_KEY" ]]; then
|
||||
error "Default signing key not found at '$DEFAULT_SIGNING_KEY'. Specify one with -f."
|
||||
fi
|
||||
CMD_ARGS+=("-f" "$DEFAULT_SIGNING_KEY")
|
||||
fi
|
||||
|
||||
# Set default namespace if -n was not provided
|
||||
if ! $n_provided; then
|
||||
CMD_ARGS+=("-n" "$DEFAULT_NAMESPACE")
|
||||
fi
|
||||
|
||||
# The file to sign MUST be the last argument for ssh-keygen
|
||||
CMD_ARGS+=("$file_to_sign")
|
||||
|
||||
elif [[ "$SUBCOMMAND" == "verify" ]]; then
|
||||
if [[ -n "$file_to_sign" ]]; then
|
||||
error "The 'verify' command reads from stdin and does not accept a positional file argument. Found '$file_to_sign'."
|
||||
fi
|
||||
if ! $s_provided; then
|
||||
error "Signature file must be provided with -s for 'verify' command."
|
||||
fi
|
||||
|
||||
# Set default allowed_signers if -f was not provided
|
||||
if ! $f_provided; then
|
||||
if [[ ! -f "$DEFAULT_ALLOWED_SIGNERS" ]]; then
|
||||
error "Default allowed signers file not found at '$DEFAULT_ALLOWED_SIGNERS'. Specify one with -f."
|
||||
fi
|
||||
CMD_ARGS+=("-f" "$DEFAULT_ALLOWED_SIGNERS")
|
||||
fi
|
||||
|
||||
# Set default identity if -I was not provided
|
||||
if ! $I_provided; then
|
||||
CMD_ARGS+=("-I" "$DEFAULT_IDENTITY")
|
||||
fi
|
||||
|
||||
# Set default namespace if -n was not provided
|
||||
if ! $n_provided; then
|
||||
CMD_ARGS+=("-n" "$DEFAULT_NAMESPACE")
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Execute and Report ---
|
||||
|
||||
# We capture the output and stderr to show it to the user
|
||||
if output=$("${CMD_ARGS[@]}" 2>&1); then
|
||||
echo -e "${COLOR_GREEN}Success:${COLOR_NONE}"
|
||||
echo "$output"
|
||||
exit 0
|
||||
else
|
||||
echo -e "${COLOR_RED}Command Failed:${COLOR_NONE}"
|
||||
echo "$output" >&2
|
||||
exit 1
|
||||
fi
|
||||
@@ -7,7 +7,7 @@ fi
|
||||
|
||||
if [ `whoami` != "root" ] ; then
|
||||
if which sudo >/dev/null 2>&1 ; then
|
||||
sudo $0 $*
|
||||
sudo "$0" "$@"
|
||||
exit
|
||||
fi
|
||||
echo "Sorry, this requires root." >&2
|
||||
|
||||
7
bin/update_skel
Executable file
7
bin/update_skel
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
SKEL_DIR=$(dirname -- "$(readlink -f -- "$HOME/.profile")")
|
||||
cd -- "$SKEL_DIR"
|
||||
cd -- "$(git rev-parse --show-toplevel)"
|
||||
git pull
|
||||
./install.sh
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"background-color": "rgba(0, 43, 54, 1)",
|
||||
"cursor-color": "rgba(238, 232, 213, 0.5)",
|
||||
"color-palette-overrides": {
|
||||
"0": "#073642",
|
||||
"1": "#dc322f",
|
||||
"2": "#859900",
|
||||
"3": "#b58900",
|
||||
"4": "#268bd2",
|
||||
"5": "#d33682",
|
||||
"6": "#2aa198",
|
||||
"7": "#eee8d5",
|
||||
"8": "#002b36",
|
||||
"9": "#cb4b16",
|
||||
"10": "#586e75",
|
||||
"11": "#657b83",
|
||||
"12": "#839496",
|
||||
"13": "#6c71c4",
|
||||
"14": "#93a1a1",
|
||||
"15": "#fdf6e3"
|
||||
},
|
||||
"font-family": "\"Inconsolata\", \"DejaVu Sans Mono\", \"Noto Sans Mono\", \"Everson Mono\", FreeMono, Menlo, Terminal, monospace",
|
||||
"font-size": "15",
|
||||
"foreground-color": "rgba(238, 232, 213, 1)",
|
||||
"user-css": "https://cdn.jsdelivr.net/gh/wernight/powerline-web-fonts@ba4426cb0c0b05eb6cb342c7719776a41e1f2114/PowerlineFonts.css"
|
||||
}
|
||||
71
clone.sh
71
clone.sh
@@ -2,23 +2,68 @@
|
||||
|
||||
set -ue
|
||||
|
||||
# Script to clone and install
|
||||
|
||||
# Wrapped in a function to prevent incomplete execution if download is
|
||||
# interrupted
|
||||
function installer_main {
|
||||
if ! command -v git >/dev/null 2>&1 ; then
|
||||
( if [ "$EUID" != 0 ] ; then
|
||||
sudo apt install -y git
|
||||
# --- Helper function to install git ---
|
||||
install_git() {
|
||||
echo "Git not found. Attempting to install..." >&2
|
||||
case "$(uname)" in
|
||||
Darwin)
|
||||
if command -v brew >/dev/null 2>&1; then
|
||||
echo "Using Homebrew to install git..." >&2
|
||||
brew install git
|
||||
else
|
||||
apt install -y git
|
||||
fi ) || ( echo 'Failed to install git!' >/dev/stderr; false)
|
||||
echo "Error: Homebrew not found on your macOS system." >&2
|
||||
echo "Please install Homebrew first by visiting https://brew.sh/ then run this script again." >&2
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
Linux)
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
echo "Using apt-get to install git..." >&2
|
||||
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
|
||||
sudo apt-get update && sudo apt-get install -y git
|
||||
else
|
||||
apt-get update && apt-get install -y git
|
||||
fi
|
||||
else
|
||||
echo "Error: This script requires 'apt-get' on Linux to install git." >&2
|
||||
echo "Please install git using your system's package manager and run this script again." >&2
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unsupported operating system '$(uname)'." >&2
|
||||
echo "Please install git manually and run this script again." >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- Main script logic ---
|
||||
installer_main() {
|
||||
# 1. Check for git, and try to install it if it's missing.
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
install_git
|
||||
# Final check after attempting installation
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
echo "ERROR: git installation failed or was not found." >&2
|
||||
echo "Please install git manually and re-run this script." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
git clone https://github.com/Matir/skel.git ${HOME}/.skel
|
||||
# 2. Clone the repository if it doesn't exist
|
||||
local dest="${HOME}/.skel"
|
||||
if [ -d "${dest}" ]; then
|
||||
echo "Repository already exists in ${dest}. Skipping clone." >&2
|
||||
else
|
||||
echo "Cloning repository..." >&2
|
||||
git clone --depth 1 https://github.com/Matir/skel.git "${dest}"
|
||||
fi
|
||||
|
||||
${HOME}/.skel/install.sh
|
||||
${HOME}/.skel/install.sh packages minimal
|
||||
# 3. Run the main installer
|
||||
echo "Running main installer..." >&2
|
||||
"${dest}/install.sh"
|
||||
}
|
||||
|
||||
installer_main
|
||||
|
||||
|
||||
16
darwin-env.plist
Normal file
16
darwin-env.plist
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.user.loadvars</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/bin/sh</string>
|
||||
<string>-c</string>
|
||||
<string>~/bin/darwin-env.sh || true</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,24 +0,0 @@
|
||||
[media-keys]
|
||||
screensaver=['<Primary><Alt>l', 'XF86ScreenSaver']
|
||||
|
||||
[wm]
|
||||
move-to-workspace-1=['<Shift><Super>exclam']
|
||||
move-to-workspace-2=['<Shift><Super>at']
|
||||
move-to-workspace-3=['<Shift><Super>numbersign']
|
||||
move-to-workspace-4=['<Shift><Super>dollar']
|
||||
move-to-workspace-5=['<Shift><Super>percent']
|
||||
move-to-workspace-6=['<Shift><Super>asciicircum']
|
||||
move-to-workspace-7=['<Shift><Super>ampersand']
|
||||
move-to-workspace-8=['<Shift><Super>asterisk']
|
||||
move-to-workspace-9=['<Shift><Super>parenleft']
|
||||
switch-to-workspace-4=['<Super>4']
|
||||
switch-to-workspace-1=['<Super>1']
|
||||
switch-to-workspace-10=['<Super>0']
|
||||
switch-to-workspace-3=['<Super>3']
|
||||
switch-to-workspace-8=['<Super>8']
|
||||
switch-to-workspace-5=['<Super>5']
|
||||
move-to-workspace-10=['<Shift><Super>parenright']
|
||||
switch-to-workspace-2=['<Super>2']
|
||||
switch-to-workspace-9=['<Super>9']
|
||||
switch-to-workspace-6=['<Super>6']
|
||||
switch-to-workspace-7=['<Super>7']
|
||||
1
dotfile_overlays/README
Normal file
1
dotfile_overlays/README
Normal file
@@ -0,0 +1 @@
|
||||
Each directory in this directory will be symlinked as dotfiles.
|
||||
@@ -1,3 +1,4 @@
|
||||
--follow
|
||||
--pager=less -LMXRF
|
||||
--smart-case
|
||||
--ignore-dir=match:bazel-.*
|
||||
|
||||
@@ -1,26 +1,9 @@
|
||||
# General aliases, should only be sourced in interactive shells
|
||||
|
||||
# Add an "alert" alias for long running commands. Use like so:
|
||||
# sleep 10; alert
|
||||
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
|
||||
# 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'
|
||||
|
||||
# Colors
|
||||
if ls --version >/dev/null 2>&1 ; then
|
||||
alias ls='ls --color=auto'
|
||||
fi
|
||||
if [ `uname` != 'Darwin' -a `uname` != 'NetBSD' -a `uname` != 'FreeBSD' -a `uname` != 'OpenBSD' ] ; then
|
||||
# Should have a better way to check for GNU versions
|
||||
alias grep='grep --color=auto'
|
||||
alias egrep='egrep --color=auto'
|
||||
alias fgrep='fgrep --color=auto'
|
||||
fi
|
||||
|
||||
# Easy upgrade
|
||||
alias dist-upgrade="sudo sh -c 'apt-get update && apt-get -y dist-upgrade'"
|
||||
|
||||
# Timestamp in a machine-sortable form
|
||||
alias tstamp="date '+%Y%m%d-%H%M%S'"
|
||||
|
||||
@@ -30,9 +13,6 @@ alias mdcode="sed 's/^/ /'"
|
||||
# Intel format plz
|
||||
alias objdump="command objdump -M intel"
|
||||
|
||||
# Useful directory utilities
|
||||
alias dircount="for d in * ; do find \$d -type d | wc -l | tr -d '\n' ; echo ' ' \$d ; done | sort -n"
|
||||
|
||||
# Drop caches for swap issues
|
||||
alias drop_caches="echo 3 | sudo /usr/bin/tee /proc/sys/vm/drop_caches"
|
||||
|
||||
@@ -46,13 +26,13 @@ alias gitroot="git rev-parse --show-toplevel"
|
||||
alias sshanon="ssh -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no"
|
||||
|
||||
# Straight to ipython
|
||||
alias ipy="ipython3"
|
||||
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"
|
||||
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"
|
||||
@@ -65,3 +45,6 @@ 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'
|
||||
|
||||
15
dotfiles/config/Code/User/settings.json
Normal file
15
dotfiles/config/Code/User/settings.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"editor.accessibilitySupport": "off",
|
||||
"telemetry.telemetryLevel": "off",
|
||||
"dotfiles.repository": "matir/skel",
|
||||
"dotfiles.targetPath": "~/.skel",
|
||||
"remote.defaultExtensionsIfInstalledLocally": [],
|
||||
"mise.configureExtensionsAutomatically": true,
|
||||
"kilo-code.debug": false,
|
||||
"kilo-code.allowedCommands": [
|
||||
"git log",
|
||||
"git diff",
|
||||
"git show"
|
||||
],
|
||||
"kilo-code.deniedCommands": []
|
||||
}
|
||||
5
dotfiles/config/direnv/lib/mise.sh
Normal file
5
dotfiles/config/direnv/lib/mise.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
if command -v mise ; then
|
||||
use_mise() {
|
||||
eval "$(mise direnv activate)"
|
||||
}
|
||||
fi
|
||||
16
dotfiles/config/direnv/lib/python.sh
Normal file
16
dotfiles/config/direnv/lib/python.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
layout_python() {
|
||||
local DIR_NAME="$(basename $(pwd))"
|
||||
VIRTUAL_ENV="${VIRTUAL_ENV:-$(pwd)/.venv/${DIR_NAME}}"
|
||||
local PYBIN="$(command -v python 2>/dev/null || command -v python3 2>/dev/null)"
|
||||
if [[ -z "${PYBIN}" ]]; then
|
||||
log_error "No python found!"
|
||||
return 1
|
||||
fi
|
||||
if [[ ! -d $VIRTUAL_ENV ]]; then
|
||||
log_status "No virtual environment exists. Executing \`${PYBIN} -m venv ${VIRTUAL_ENV}\`."
|
||||
"${PYBIN}" -m venv "${VIRTUAL_ENV}"
|
||||
fi
|
||||
|
||||
# Activate the virtual environment
|
||||
. $VIRTUAL_ENV/bin/activate
|
||||
}
|
||||
77
dotfiles/config/fish/conf.d/aliases.fish
Normal file
77
dotfiles/config/fish/conf.d/aliases.fish
Normal file
@@ -0,0 +1,77 @@
|
||||
# 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'"
|
||||
|
||||
# Prepare code for markdown
|
||||
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"
|
||||
|
||||
# SSH without host key checking
|
||||
alias sshanon "ssh -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no"
|
||||
|
||||
# Straight to ipython
|
||||
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'
|
||||
|
||||
# On some systems, bat is batcat
|
||||
if not command -v bat >/dev/null 2>&1
|
||||
if command -v batcat >/dev/null 2>&1
|
||||
alias bat (command -v batcat)
|
||||
end
|
||||
end
|
||||
|
||||
# FFUF aliases
|
||||
if command -v ffuf >/dev/null 2>&1
|
||||
if test -d $HOME/tools/seclists
|
||||
alias ffuf-files "ffuf -c -w $HOME/tools/seclists/Discovery/Web-Content/raft-large-files.txt"
|
||||
alias ffuf-dirs "ffuf -c -w $HOME/tools/seclists/Discovery/Web-Content/raft-large-directories.txt"
|
||||
alias ffuf-quick "ffuf -c -w $HOME/tools/seclists/Discovery/Web-Content/quickhits.txt"
|
||||
end
|
||||
end
|
||||
|
||||
if grep --help 2>/dev/null | grep -q 'color'
|
||||
# Should have a better way to check for GNU versions
|
||||
alias grep 'grep --color=auto'
|
||||
alias egrep 'egrep --color=auto'
|
||||
alias fgrep 'fgrep --color=auto'
|
||||
end
|
||||
|
||||
# Detect which `ls` flavor is in use and use the right flag for colors.
|
||||
if ls --help 2>&1 | grep -q -- '--color'
|
||||
alias ls 'ls --color=auto' # GNU `ls`
|
||||
else if test (uname) = "Darwin"
|
||||
alias ls 'ls -G' # macOS `ls`
|
||||
end
|
||||
14
dotfiles/config/fish/conf.d/fish_frozen_key_bindings.fish
Normal file
14
dotfiles/config/fish/conf.d/fish_frozen_key_bindings.fish
Normal file
@@ -0,0 +1,14 @@
|
||||
# This file was created by fish when upgrading to version 4.3, to migrate
|
||||
# the 'fish_key_bindings' variable from its old default scope (universal)
|
||||
# to its new default scope (global). We recommend you delete this file
|
||||
# and configure key bindings in ~/.config/fish/config.fish if needed.
|
||||
|
||||
# set --global fish_key_bindings fish_default_key_bindings
|
||||
|
||||
# Prior to version 4.3, fish shipped an event handler that runs
|
||||
# `set --universal fish_key_bindings fish_default_key_bindings`
|
||||
# whenever the fish_key_bindings variable is erased.
|
||||
# This means that as long as any fish < 4.3 is still running on this system,
|
||||
# we cannot complete the migration.
|
||||
# As a workaround, erase the universal variable at every shell startup.
|
||||
set --erase --universal fish_key_bindings
|
||||
48
dotfiles/config/fish/conf.d/fish_frozen_theme.fish
Normal file
48
dotfiles/config/fish/conf.d/fish_frozen_theme.fish
Normal file
@@ -0,0 +1,48 @@
|
||||
# This file was created by fish when upgrading to version 4.3, to migrate
|
||||
# theme variables from universal to global scope.
|
||||
# Don't edit this file, as it will be written by the web-config tool (`fish_config`).
|
||||
# To customize your theme, delete this file and see
|
||||
# help interactive#syntax-highlighting
|
||||
# or
|
||||
# man fish-interactive | less +/^SYNTAX.HIGHLIGHTING
|
||||
# for appropriate commands to add to ~/.config/fish/config.fish instead.
|
||||
# See also the release notes for fish 4.3.0 (run `help relnotes`).
|
||||
|
||||
set --global fish_color_autosuggestion 4D5566
|
||||
set --global fish_color_cancel --reverse
|
||||
set --global fish_color_command 39BAE6
|
||||
set --global fish_color_comment 626A73
|
||||
set --global fish_color_cwd 59C2FF
|
||||
set --global fish_color_cwd_root red
|
||||
set --global fish_color_end F29668
|
||||
set --global fish_color_error FF3333
|
||||
set --global fish_color_escape 95E6CB
|
||||
set --global fish_color_history_current --bold
|
||||
set --global fish_color_host normal
|
||||
set --global fish_color_host_remote yellow
|
||||
set --global fish_color_keyword 39BAE6
|
||||
set --global fish_color_match F07178
|
||||
set --global fish_color_normal B3B1AD
|
||||
set --global fish_color_operator E6B450
|
||||
set --global fish_color_option B3B1AD
|
||||
set --global fish_color_param B3B1AD
|
||||
set --global fish_color_quote C2D94C
|
||||
set --global fish_color_redirection FFEE99
|
||||
set --global fish_color_search_match --background=E6B450
|
||||
set --global fish_color_selection --background=E6B450
|
||||
set --global fish_color_status red
|
||||
set --global fish_color_user brgreen
|
||||
set --global fish_color_valid_path --underline
|
||||
set --global fish_pager_color_background
|
||||
set --global fish_pager_color_completion normal
|
||||
set --global fish_pager_color_description B3A06D
|
||||
set --global fish_pager_color_prefix normal --bold --underline
|
||||
set --global fish_pager_color_progress brwhite --background=cyan
|
||||
set --global fish_pager_color_secondary_background
|
||||
set --global fish_pager_color_secondary_completion
|
||||
set --global fish_pager_color_secondary_description
|
||||
set --global fish_pager_color_secondary_prefix
|
||||
set --global fish_pager_color_selected_background --background=E6B450
|
||||
set --global fish_pager_color_selected_completion
|
||||
set --global fish_pager_color_selected_description
|
||||
set --global fish_pager_color_selected_prefix
|
||||
34
dotfiles/config/fish/config.fish
Normal file
34
dotfiles/config/fish/config.fish
Normal file
@@ -0,0 +1,34 @@
|
||||
if test -x /opt/homebrew/bin/brew
|
||||
/opt/homebrew/bin/brew shellenv fish | source
|
||||
if test -d (brew --prefix)"/share/fish/completions"
|
||||
set -p fish_complete_path (brew --prefix)/share/fish/completions
|
||||
end
|
||||
|
||||
if test -d (brew --prefix)"/share/fish/vendor_completions.d"
|
||||
set -p fish_complete_path (brew --prefix)/share/fish/vendor_completions.d
|
||||
end
|
||||
|
||||
# mise, if installed
|
||||
if type -q mise
|
||||
mise activate fish | source
|
||||
end
|
||||
end
|
||||
|
||||
if command -q starship
|
||||
starship init fish --print-full-init | source
|
||||
end
|
||||
|
||||
function install_fisher
|
||||
if not test -e ~/.config/fish/functions/fisher.fish
|
||||
echo "Installing Fisher for fish shell..."
|
||||
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source
|
||||
fisher install jorgebucaran/fisher
|
||||
end
|
||||
end
|
||||
|
||||
if status --is-interactive
|
||||
install_fisher
|
||||
end
|
||||
|
||||
# Want this at the bottom to put this path first
|
||||
fish_add_path --move --path {$HOME}/bin
|
||||
2
dotfiles/config/fish/fish_plugins
Normal file
2
dotfiles/config/fish/fish_plugins
Normal file
@@ -0,0 +1,2 @@
|
||||
jorgebucaran/fisher
|
||||
wfxr/forgit
|
||||
@@ -1,34 +0,0 @@
|
||||
# This file contains fish universal variable definitions.
|
||||
# VERSION: 3.0
|
||||
SETUVAR EDITOR:vim
|
||||
SETUVAR __fish_initialized:3400
|
||||
SETUVAR fish_color_autosuggestion:586e75
|
||||
SETUVAR fish_color_cancel:\x2dr
|
||||
SETUVAR fish_color_command:93a1a1
|
||||
SETUVAR fish_color_comment:586e75
|
||||
SETUVAR fish_color_cwd:green
|
||||
SETUVAR fish_color_cwd_root:red
|
||||
SETUVAR fish_color_end:268bd2
|
||||
SETUVAR fish_color_error:dc322f
|
||||
SETUVAR fish_color_escape:00a6b2
|
||||
SETUVAR fish_color_history_current:\x2d\x2dbold
|
||||
SETUVAR fish_color_host:normal
|
||||
SETUVAR fish_color_host_remote:yellow
|
||||
SETUVAR fish_color_match:\x2d\x2dbackground\x3dbrblue
|
||||
SETUVAR fish_color_normal:normal
|
||||
SETUVAR fish_color_operator:00a6b2
|
||||
SETUVAR fish_color_param:839496
|
||||
SETUVAR fish_color_quote:657b83
|
||||
SETUVAR fish_color_redirection:6c71c4
|
||||
SETUVAR fish_color_search_match:bryellow\x1e\x2d\x2dbackground\x3dblack
|
||||
SETUVAR fish_color_selection:white\x1e\x2d\x2dbold\x1e\x2d\x2dbackground\x3dbrblack
|
||||
SETUVAR fish_color_status:red
|
||||
SETUVAR fish_color_user:brgreen
|
||||
SETUVAR fish_color_valid_path:\x2d\x2dunderline
|
||||
SETUVAR fish_greeting:Welcome\x20to\x20fish\x2c\x20the\x20friendly\x20interactive\x20shell\x0aType\x20\x60help\x60\x20for\x20instructions\x20on\x20how\x20to\x20use\x20fish
|
||||
SETUVAR fish_key_bindings:fish_default_key_bindings
|
||||
SETUVAR fish_pager_color_completion:B3A06D
|
||||
SETUVAR fish_pager_color_description:B3A06D
|
||||
SETUVAR fish_pager_color_prefix:cyan\x1e\x2d\x2dunderline
|
||||
SETUVAR fish_pager_color_progress:brwhite\x1e\x2d\x2dbackground\x3dcyan
|
||||
SETUVAR fish_pager_color_selected_background:\x2dr
|
||||
8
dotfiles/config/fish/functions/cdgr.fish
Normal file
8
dotfiles/config/fish/functions/cdgr.fish
Normal file
@@ -0,0 +1,8 @@
|
||||
# Change to the root of the git repository.
|
||||
# If not in a git repo, do nothing.
|
||||
function cdgr
|
||||
set git_root (git rev-parse --show-toplevel 2>/dev/null)
|
||||
if test -n "$git_root"
|
||||
cd "$git_root"
|
||||
end
|
||||
end
|
||||
15
dotfiles/config/gemini/settings.json
Normal file
15
dotfiles/config/gemini/settings.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"editor": {
|
||||
"mode": "vim"
|
||||
},
|
||||
"context": {
|
||||
"includeFiles": [
|
||||
"/usr/local/google/home/davidtomaschik/.skel/GEMINI.md",
|
||||
"/usr/local/google/home/davidtomaschik/.skel/AGENTS.md"
|
||||
]
|
||||
},
|
||||
"experimental": {
|
||||
"skills": true,
|
||||
"planMode": true
|
||||
}
|
||||
}
|
||||
@@ -9,3 +9,4 @@ pager: !!null less -R
|
||||
# Aliases allow you to create nicknames for gh commands
|
||||
aliases:
|
||||
co: pr checkout
|
||||
version: "1"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Beware! This file is rewritten by htop when settings are changed in the interface.
|
||||
# The parser is also very primitive, and not human-friendly.
|
||||
htop_version=3.2.2
|
||||
htop_version=3.4.1-3.4.1
|
||||
config_reader_min_version=3
|
||||
fields=0 48 17 18 38 39 40 2 46 47 49 1
|
||||
hide_kernel_threads=1
|
||||
@@ -27,6 +27,7 @@ show_cpu_usage=1
|
||||
show_cpu_frequency=0
|
||||
show_cpu_temperature=0
|
||||
degree_fahrenheit=0
|
||||
show_cached_memory=1
|
||||
update_process_names=0
|
||||
account_guest_in_cpu_meter=0
|
||||
color_scheme=6
|
||||
@@ -48,16 +49,16 @@ all_branches_collapsed=0
|
||||
screen:Main=PID USER PRIORITY NICE M_VIRT M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME Command
|
||||
.sort_key=PERCENT_CPU
|
||||
.tree_sort_key=PID
|
||||
.tree_view=0
|
||||
.tree_view_always_by_pid=0
|
||||
.tree_view=0
|
||||
.sort_direction=-1
|
||||
.tree_sort_direction=1
|
||||
.all_branches_collapsed=0
|
||||
screen:I/O=PID USER IO_PRIORITY IO_RATE IO_READ_RATE IO_WRITE_RATE PERCENT_SWAP_DELAY PERCENT_IO_DELAY Command
|
||||
.sort_key=IO_RATE
|
||||
.tree_sort_key=PID
|
||||
.tree_view=0
|
||||
.tree_view_always_by_pid=0
|
||||
.tree_view=0
|
||||
.sort_direction=-1
|
||||
.tree_sort_direction=1
|
||||
.all_branches_collapsed=0
|
||||
|
||||
19
dotfiles/config/mise/config.toml
Normal file
19
dotfiles/config/mise/config.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[settings]
|
||||
experimental = true
|
||||
|
||||
[settings.pipx]
|
||||
uvx = true
|
||||
|
||||
[settings.python]
|
||||
uv_venv_auto = true
|
||||
|
||||
[tools]
|
||||
age = "latest"
|
||||
usage = "latest"
|
||||
uv = "latest"
|
||||
|
||||
[hooks]
|
||||
postinstall = "mise sync python --uv"
|
||||
|
||||
[env]
|
||||
UV_PROJECT_ENVIRONMENT = { value='{% if env.PROJECT_SLUG %}{{ env.HOME}}/.cache/uv-venvs/{{ env.PROJECT_SLUG }}{% endif %}', tools = true }
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
[directory]
|
||||
fish_style_pwd_dir_length = 1
|
||||
truncate_to_repo = false
|
||||
|
||||
[gcloud]
|
||||
# This is just too noisy
|
||||
disabled = true
|
||||
symbol = "️🇬️ "
|
||||
format = "on [$symbol$project]($style) "
|
||||
detect_env_vars = ["STARSHIP_SHOW_GCLOUD"]
|
||||
|
||||
[status]
|
||||
disabled = false
|
||||
@@ -17,3 +18,36 @@ show_always = true
|
||||
|
||||
[ruby]
|
||||
detect_variables = []
|
||||
|
||||
[shell]
|
||||
fish_indicator = '🐟 '
|
||||
zsh_indicator = ''
|
||||
bash_indicator = ''
|
||||
powershell_indicator = '_'
|
||||
unknown_indicator = '??'
|
||||
style = 'cyan bold'
|
||||
disabled = false
|
||||
format = '[$indicator]($style)'
|
||||
|
||||
[pulumi]
|
||||
disabled = true
|
||||
|
||||
[docker_context]
|
||||
# really long paths when DOCKER_HOST is set
|
||||
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) "
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/dev/null
|
||||
181
dotfiles/config/wezterm/wezterm.lua
Normal file
181
dotfiles/config/wezterm/wezterm.lua
Normal file
@@ -0,0 +1,181 @@
|
||||
|
||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
||||
Dload Upload Total Spent Left Speed
|
||||
|
||||
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0-- https://wezfurlong.org/wezterm/config/files.html
|
||||
-- https://alexplescan.com/posts/2024/08/10/wezterm/
|
||||
-- https://github.com/wez/wezterm/issues/6112
|
||||
-- https://github.com/wez/wezterm/issues/5754
|
||||
local wezterm = require "wezterm"
|
||||
local config = wezterm.config_builder()
|
||||
local action = wezterm.action
|
||||
local mux = wezterm.mux
|
||||
|
||||
config.audible_bell = "Disabled"
|
||||
config.check_for_updates = false -- managed by brew
|
||||
config.set_environment_variables = {
|
||||
PATH = '/opt/homebrew/bin:/usr/local/bin/:' .. os.getenv('PATH')
|
||||
}
|
||||
|
||||
local function scheme_for_appearance(a)
|
||||
return a:find("Dark") and "Catppuccin Macchiato" or "Catppuccin Latte"
|
||||
end
|
||||
|
||||
config.font = wezterm.font { family = 'JetBrains Mono', weight = 'Medium', harfbuzz_features = { 'calt=0', 'clig=0', 'liga=0' } }
|
||||
config.font_size = 15.0
|
||||
config.line_height = 1.0
|
||||
config.bold_brightens_ansi_colors = true
|
||||
config.color_scheme = scheme_for_appearance(wezterm.gui.get_appearance())
|
||||
config.macos_window_background_blur = 20
|
||||
config.window_background_opacity = 0.96
|
||||
|
||||
config.window_decorations = 'RESIZE|INTEGRATED_BUTTONS'
|
||||
config.window_padding = { left = '0.5cell', right = '0.5cell', top = '1.5cell', bottom = '0.5cell' }
|
||||
config.enable_tab_bar = true
|
||||
config.use_fancy_tab_bar = false
|
||||
config.tab_bar_at_bottom = true
|
||||
config.tab_max_width = 32
|
||||
config.show_new_tab_button_in_tab_bar = false
|
||||
-- config.hide_tab_bar_if_only_one_tab = true -- sometimes procude wrong window size on maximize
|
||||
|
||||
config.default_cursor_style = 'BlinkingBar'
|
||||
config.animation_fps = 1
|
||||
config.cursor_blink_rate = 500
|
||||
config.prefer_egl = true
|
||||
config.max_fps = 60
|
||||
|
||||
config.enable_scroll_bar = true
|
||||
config.scrollback_lines = 10000
|
||||
|
||||
-- makes wezterm to work like tmux; see also: https://bower.sh/zmx-session-persistence
|
||||
config.default_gui_startup_args = { 'connect', 'unix' }
|
||||
config.window_close_confirmation = 'NeverPrompt'
|
||||
|
||||
local function maximize_window(window)
|
||||
if not window.gui_window then return end
|
||||
|
||||
local screen = wezterm.gui.screens().active
|
||||
local guiwin = window:gui_window()
|
||||
if not screen or not guiwin then return end
|
||||
|
||||
-- window:gui_window():maximize() -- have long animation
|
||||
guiwin:set_position(screen.x, screen.y)
|
||||
guiwin:set_inner_size(screen.width, screen.height)
|
||||
end
|
||||
|
||||
-- https://github.com/wez/wezterm/issues/3299#issuecomment-2145712082
|
||||
wezterm.on("gui-startup", function(cmd)
|
||||
local tab, pane, window = mux.spawn_window(cmd or {})
|
||||
maximize_window(window)
|
||||
end)
|
||||
|
||||
wezterm.on("gui-attached", function(window)
|
||||
local workspace = mux.get_active_workspace()
|
||||
for _, window in ipairs(mux.all_windows()) do
|
||||
if window:get_workspace() == workspace then
|
||||
maximize_window(window)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
wezterm.on("window-resized", function(window, pane)
|
||||
maximize_window(window)
|
||||
end)
|
||||
|
||||
-- see also https://wezterm.org/config/lua/wezterm/battery_info.html
|
||||
wezterm.on("format-tab-title", function(tab, tabs, panes, config, hover, max_width)
|
||||
local title = (tab.tab_title ~= "" and tab.tab_title) or tab.active_pane.title
|
||||
title = title:lower()
|
||||
|
||||
local prefix = tostring(tab.tab_index + 1) .. ":"
|
||||
local width = math.max(1, max_width - (#prefix + 2))
|
||||
title = wezterm.truncate_right(title, width)
|
||||
|
||||
return " " .. prefix .. title .. " "
|
||||
end)
|
||||
|
||||
-- https://github.com/wezterm/wezterm/issues/1988#issuecomment-2462216249
|
||||
local function search_cmd(window, pane)
|
||||
window:perform_action(action.Search 'CurrentSelectionOrEmptyString', pane)
|
||||
window:perform_action(action.Multiple {
|
||||
action.CopyMode 'ClearPattern',
|
||||
action.CopyMode 'ClearSelectionMode',
|
||||
action.CopyMode 'MoveToScrollbackBottom'
|
||||
}, pane)
|
||||
end
|
||||
|
||||
config.keys = {
|
||||
{ key = 'q', mods = 'CMD', action = wezterm.action.Nop }, -- prevent accidental quit
|
||||
{ key = 't', mods = 'CMD', action = action.SpawnTab 'CurrentPaneDomain' },
|
||||
{ key = 'd', mods = 'CMD', action = action.SplitHorizontal { domain = 'CurrentPaneDomain' } },
|
||||
{ key = 'd', mods = 'CMD|SHIFT', action = action.SplitVertical { domain = 'CurrentPaneDomain' } },
|
||||
{ key = 'k', mods = 'CMD', action = action.ClearScrollback 'ScrollbackAndViewport' },
|
||||
{ key = 'w', mods = 'CMD', action = action.CloseCurrentPane { confirm
|
||||
100 6869 100 6869 0 0 42178 0 --:--:-- --:--:-- --:--:-- 42401
|
||||
= false } },
|
||||
{ key = 'w', mods = 'CMD|SHIFT', action = action.CloseCurrentTab { confirm = false } },
|
||||
{ key = 'a', mods = 'CMD', action = action.SelectTextAtMouseCursor 'SemanticZone', },
|
||||
{ key = 'LeftArrow', mods = 'CMD', action = action.SendKey { key = 'Home' } },
|
||||
{ key = 'RightArrow', mods = 'CMD', action = action.SendKey { key = 'End' } },
|
||||
{ key = 'Backspace', mods = 'CMD', action = action.SendKey({ mods = "CTRL", key = "u" }) },
|
||||
{ key = 'Backspace', mods = 'OPT', action = action.SendKey({ mods = "CTRL", key = "w" }) },
|
||||
{ key = 'P', mods = 'CMD|SHIFT', action = action.ActivateCommandPalette },
|
||||
{ key = 'f', mods = 'CMD', action = wezterm.action_callback(search_cmd) },
|
||||
{ key = ',', mods = 'CMD', action = action.SpawnCommandInNewTab { cwd = wezterm.home_dir, args = { 'code', wezterm.config_file } } },
|
||||
{ key = 'E', mods = 'CMD|SHIFT', action = action.PromptInputLine {
|
||||
description = 'Enter tab title (empty to unset):',
|
||||
action = wezterm.action_callback(function(window, _, line)
|
||||
window:active_tab():set_title(line)
|
||||
end),
|
||||
}},
|
||||
}
|
||||
|
||||
config.mouse_bindings = {
|
||||
{ event = { Up = { streak = 1, button = "Left" } }, mods = "NONE", action = action.Nop },
|
||||
{ event = { Up = { streak = 1, button = "Left" } }, mods = "CMD", action = action.OpenLinkAtMouseCursor },
|
||||
-- Disable CMD + LeftClick window drag (make it behave like normal select)
|
||||
-- { event = { Drag = { streak = 1, button = 'Left' } }, mods = "CMD", action = action.Nop },
|
||||
{ event = { Drag = { streak = 1, button = "Left" } }, mods = "CMD", action = action.ExtendSelectionToMouseCursor("Cell") },
|
||||
}
|
||||
|
||||
-- https://code.visualstudio.com/docs/configure/command-line#_opening-vs-code-with-urls
|
||||
-- path-symbols: [\w@\.\/\-\[\]\(\)]
|
||||
|
||||
local function path_exists(path)
|
||||
local ok, _, _ = wezterm.run_child_process { "test", "-e", path }
|
||||
return ok
|
||||
end
|
||||
|
||||
config.hyperlink_rules = wezterm.default_hyperlink_rules()
|
||||
-- config.hyperlink_rules = {}
|
||||
|
||||
table.insert(config.hyperlink_rules, {
|
||||
regex = [[((?:[\w@\.\/\-\[\]\(\)]+\/)+[\w@\.\/\-\[\]\(\)]+\.\w+)\b]],
|
||||
format = "vscode://file/$PWD/$1",
|
||||
highlight = 1,
|
||||
})
|
||||
|
||||
table.insert(config.hyperlink_rules, {
|
||||
regex = [[((?:[\w@\.\/\-\[\]\(\)]+\/)+[\w@\.\/\-\[\]\(\)]+\.\w+):(\d+):(\d+)]],
|
||||
format = "vscode://file/$PWD/$1:$2:$3",
|
||||
highlight = 1,
|
||||
})
|
||||
|
||||
wezterm.on("open-uri", function(window, pane, uri)
|
||||
if uri:find("$PWD") then
|
||||
local cwd_uri = pane:get_current_working_dir()
|
||||
local before, after = uri:match("^(.-)$PWD/(.+)$")
|
||||
wezterm.log_info(before, after, path_exists(after))
|
||||
if path_exists(after) then
|
||||
uri = before .. after
|
||||
else
|
||||
uri = uri:gsub("$PWD", cwd_uri.file_path)
|
||||
end
|
||||
|
||||
wezterm.log_info(uri)
|
||||
wezterm.open_with(uri)
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end)
|
||||
6
dotfiles/config/ycm_extra_conf.py
Normal file
6
dotfiles/config/ycm_extra_conf.py
Normal file
@@ -0,0 +1,6 @@
|
||||
def Settings( **kwargs ):
|
||||
client_data = kwargs[ 'client_data' ]
|
||||
return {
|
||||
'interpreter_path': client_data[ 'g:ycm_python_interpreter_path' ] or '/usr/bin/python3',
|
||||
'sys_path': client_data[ 'g:ycm_python_sys_path' ]
|
||||
}
|
||||
22
dotfiles/gemini/settings.json
Normal file
22
dotfiles/gemini/settings.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"security": {
|
||||
"auth": {
|
||||
"selectedType": "oauth-personal"
|
||||
}
|
||||
},
|
||||
"context": {
|
||||
"fileName": [
|
||||
"AGENTS.md",
|
||||
"GEMINI.md"
|
||||
]
|
||||
},
|
||||
"selectedAuthType": "gemini-api-key",
|
||||
"general": {
|
||||
"vimMode": true,
|
||||
"sessionRetention": {
|
||||
"enabled": true,
|
||||
"maxAge": "30d",
|
||||
"warningAcknowledged": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
[user]
|
||||
name = David Tomaschik
|
||||
signingKey = 0x5DEA789B
|
||||
useConfigOnly = true
|
||||
|
||||
[core]
|
||||
excludesfile = ~/.gitignore
|
||||
@@ -50,6 +50,7 @@
|
||||
[url "ssh://git@github.com/"]
|
||||
pushInsteadOf = "github:"
|
||||
pushInsteadOf = "github://"
|
||||
pushInsteadOf = "https://github.com/"
|
||||
|
||||
[url "git://gist.github.com/"]
|
||||
insteadOf = "gist:"
|
||||
@@ -71,9 +72,6 @@
|
||||
[mergetool]
|
||||
prompt = false
|
||||
|
||||
[include]
|
||||
path = ~/.gitconfig.local
|
||||
|
||||
[pull]
|
||||
rebase = false
|
||||
|
||||
@@ -86,3 +84,16 @@
|
||||
[delta]
|
||||
navigate = true
|
||||
line-numbers = true
|
||||
|
||||
[filter "lfs"]
|
||||
required = true
|
||||
clean = git-lfs clean -- %f
|
||||
smudge = git-lfs smudge -- %f
|
||||
process = git-lfs filter-process
|
||||
|
||||
[include]
|
||||
path = ~/.gitconfig.d/override
|
||||
path = ~/.gitconfig.d/local
|
||||
|
||||
[includeIf "gitdir:~/personal/"]
|
||||
path = ~/.gitconfig.d/personal
|
||||
|
||||
5
dotfiles/gitconfig.d/override
Normal file
5
dotfiles/gitconfig.d/override
Normal file
@@ -0,0 +1,5 @@
|
||||
[user]
|
||||
email = david@systemoverlord.com
|
||||
|
||||
[github]
|
||||
user = matir
|
||||
2
dotfiles/gitconfig.d/personal
Normal file
2
dotfiles/gitconfig.d/personal
Normal file
@@ -0,0 +1,2 @@
|
||||
[user]
|
||||
email = david@systemoverlord.com
|
||||
@@ -27,3 +27,14 @@ id_ed25519
|
||||
|
||||
# These files should basically never be committed
|
||||
.env
|
||||
|
||||
# Mise local
|
||||
mise.local.toml
|
||||
|
||||
# AI Tool Configs
|
||||
.aider/
|
||||
.claude/
|
||||
.continue/
|
||||
.copilot/
|
||||
.cursor/
|
||||
.gemini/
|
||||
|
||||
@@ -2,4 +2,3 @@ default-cache-ttl 7200
|
||||
default-cache-ttl-ssh 7200
|
||||
max-cache-ttl 86400
|
||||
max-cache-ttl-ssh 86400
|
||||
enable-ssh-support
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
try:
|
||||
import os, IPython
|
||||
from traitlets import config
|
||||
os.environ['PYTHONSTARTUP'] = '' # Prevent running this again
|
||||
IPython.start_ipython()
|
||||
cfg = config.Config()
|
||||
cfg.TerminalIPythonApp.display_banner = False
|
||||
IPython.start_ipython(config=cfg)
|
||||
raise SystemExit
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
60
dotfiles/ipython/profile_default/startup/05-venv-manager.py
Normal file
60
dotfiles/ipython/profile_default/startup/05-venv-manager.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import os
|
||||
import sys
|
||||
from IPython.terminal import prompts
|
||||
|
||||
def _setup_environment():
|
||||
ip = get_ipython()
|
||||
if not ip:
|
||||
return
|
||||
|
||||
# 1. SEARCH LOGIC: Walk up the tree for a venv
|
||||
active_venv_name = None
|
||||
curr = os.getcwd()
|
||||
|
||||
while True:
|
||||
for venv_name in ['.venv', 'env', 'venv']:
|
||||
venv_path = os.path.join(curr, venv_name)
|
||||
if os.path.isdir(venv_path):
|
||||
# Platform-specific site-packages path
|
||||
py_ver = f"python{sys.version_info.major}.{sys.version_info.minor}"
|
||||
site_pkgs = os.path.join(venv_path, 'lib', py_ver, 'site-packages')
|
||||
|
||||
if os.path.exists(site_pkgs):
|
||||
if site_pkgs not in sys.path:
|
||||
sys.path.insert(0, site_pkgs)
|
||||
sys.prefix = venv_path
|
||||
active_venv_name = os.path.basename(venv_path)
|
||||
break
|
||||
|
||||
if active_venv_name or os.path.exists(os.path.join(curr, '.git')):
|
||||
break
|
||||
|
||||
parent = os.path.dirname(curr)
|
||||
if parent == curr:
|
||||
break
|
||||
curr = parent
|
||||
|
||||
# 2. PROMPT LOGIC: Inject venv name into the UI
|
||||
class VenvPrompts(prompts.Prompts):
|
||||
|
||||
_prompts = prompts
|
||||
|
||||
def in_prompt_tokens(self):
|
||||
tokens = []
|
||||
if active_venv_name:
|
||||
tokens.append((self._prompts.Token.Prompt, f'({active_venv_name}) '))
|
||||
|
||||
tokens.extend([
|
||||
(self._prompts.Token.Prompt, 'In ['),
|
||||
(self._prompts.Token.PromptNum, str(self.shell.execution_count)),
|
||||
(self._prompts.Token.Prompt, ']: '),
|
||||
])
|
||||
return tokens
|
||||
|
||||
ip.prompts = VenvPrompts(ip)
|
||||
|
||||
# Execute the setup
|
||||
_setup_environment()
|
||||
|
||||
# cleanup
|
||||
del _setup_environment, prompts
|
||||
@@ -1,415 +0,0 @@
|
||||
servers = (
|
||||
{
|
||||
address = "ircs.overthewire.org";
|
||||
chatnet = "overthewire";
|
||||
port = "6697";
|
||||
use_ssl = "yes";
|
||||
ssl_verify = "no";
|
||||
autoconnect = "yes";
|
||||
},
|
||||
{
|
||||
address = "irc.secfo.org";
|
||||
chatnet = "secfo";
|
||||
port = "7000";
|
||||
use_ssl = "yes";
|
||||
ssl_verify = "no";
|
||||
autoconnect = "yes";
|
||||
},
|
||||
{
|
||||
address = "irc.hackint.eu";
|
||||
chatnet = "hackint";
|
||||
port = "9999";
|
||||
use_ssl = "yes";
|
||||
ssl_verify = "no";
|
||||
autoconnect = "yes";
|
||||
},
|
||||
{
|
||||
address = "irc.geekshed.net";
|
||||
chatnet = "geekshed";
|
||||
port = "6697";
|
||||
use_ssl = "yes";
|
||||
ssl_verify = "no";
|
||||
autoconnect = "no";
|
||||
},
|
||||
{
|
||||
address = "irc.rpis.ec";
|
||||
chatnet = "rpisec";
|
||||
port = "6697";
|
||||
use_ssl = "yes";
|
||||
ssl_verify = "no";
|
||||
autoconnect = "yes";
|
||||
},
|
||||
{
|
||||
address = "chat.freenode.net";
|
||||
chatnet = "freenode";
|
||||
port = "7000";
|
||||
use_ssl = "yes";
|
||||
ssl_cert = "~/.irssi/matir.pem";
|
||||
ssl_verify = "yes";
|
||||
ssl_capath = "/etc/ssl/certs";
|
||||
family = "inet";
|
||||
autoconnect = "yes";
|
||||
}
|
||||
);
|
||||
|
||||
chatnets = {
|
||||
OFTC = {
|
||||
type = "IRC";
|
||||
max_kicks = "1";
|
||||
max_msgs = "3";
|
||||
max_whois = "30";
|
||||
};
|
||||
overthewire = { type = "IRC"; nick = "Matir"; };
|
||||
secfo = { type = "IRC"; };
|
||||
hackint = { type = "IRC"; nick = "Matir"; };
|
||||
freenode = {
|
||||
type = "IRC";
|
||||
nick = "Matir";
|
||||
username = "matir";
|
||||
realname = "Matir";
|
||||
max_kicks = "1";
|
||||
max_msgs = "4";
|
||||
max_modes = "4";
|
||||
max_whois = "1";
|
||||
};
|
||||
geekshed = {
|
||||
type = "IRC";
|
||||
nick = "KF4MDV";
|
||||
username = "kf4mdv";
|
||||
realname = "David";
|
||||
};
|
||||
rpisec = { type = "IRC"; };
|
||||
};
|
||||
|
||||
channels = (
|
||||
{ name = "#kali-linux"; chatnet = "freenode"; autojoin = "yes"; },
|
||||
{ name = "#hak5"; chatnet = "secfo"; autojoin = "yes"; },
|
||||
{ name = "#wargames"; chatnet = "overthewire"; autojoin = "yes"; },
|
||||
{ name = "#social"; chatnet = "overthewire"; autojoin = "yes"; },
|
||||
{ name = "#openvpn"; chatnet = "freenode"; autojoin = "yes"; },
|
||||
{ name = "#amateria"; chatnet = "overthewire"; autojoin = "yes"; },
|
||||
{ name = "#io"; chatnet = "overthewire"; autojoin = "yes"; },
|
||||
{ name = "#radare"; chatnet = "freenode"; autojoin = "yes"; },
|
||||
{ name = "#vulnhub"; chatnet = "freenode"; autojoin = "yes"; },
|
||||
{ name = "#redditnet"; chatnet = "geekshed"; autojoin = "yes"; },
|
||||
{ name = "#rpisec"; chatnet = "rpisec"; autojoin = "yes"; },
|
||||
{ name = "#offsec"; chatnet = "freenode"; autojoin = "yes"; },
|
||||
{ name = "#offtopicsec"; chatnet = "freenode"; autojoin = "yes"; }
|
||||
);
|
||||
|
||||
aliases = {
|
||||
J = "join";
|
||||
WJOIN = "join -window";
|
||||
WQUERY = "query -window";
|
||||
LEAVE = "part";
|
||||
BYE = "quit";
|
||||
EXIT = "quit";
|
||||
SIGNOFF = "quit";
|
||||
DESCRIBE = "action";
|
||||
DATE = "time";
|
||||
HOST = "userhost";
|
||||
LAST = "lastlog";
|
||||
SAY = "msg *";
|
||||
WI = "whois";
|
||||
WII = "whois $0 $0";
|
||||
WW = "whowas";
|
||||
W = "who";
|
||||
N = "names";
|
||||
M = "msg";
|
||||
T = "topic";
|
||||
C = "clear";
|
||||
CL = "clear";
|
||||
K = "kick";
|
||||
KB = "kickban";
|
||||
KN = "knockout";
|
||||
BANS = "ban";
|
||||
B = "ban";
|
||||
MUB = "unban *";
|
||||
UB = "unban";
|
||||
IG = "ignore";
|
||||
UNIG = "unignore";
|
||||
SB = "scrollback";
|
||||
UMODE = "mode $N";
|
||||
WC = "window close";
|
||||
WN = "window new hide";
|
||||
SV = "say Irssi $J ($V) - http://irssi.org/";
|
||||
GOTO = "sb goto";
|
||||
CHAT = "dcc chat";
|
||||
RUN = "SCRIPT LOAD";
|
||||
CALC = "exec - if command -v bc >/dev/null 2>&1\\; then printf '%s=' '$*'\\; echo '$*' | bc -l\\; else echo bc was not found\\; fi";
|
||||
SBAR = "STATUSBAR";
|
||||
INVITELIST = "mode $C +I";
|
||||
Q = "QUERY";
|
||||
"MANUAL-WINDOWS" = "set use_status_window off;set autocreate_windows off;set autocreate_query_level none;set autoclose_windows off;set reuse_unused_windows on;save";
|
||||
EXEMPTLIST = "mode $C +e";
|
||||
ATAG = "WINDOW SERVER";
|
||||
UNSET = "set -clear";
|
||||
RESET = "set -default";
|
||||
};
|
||||
|
||||
statusbar = {
|
||||
# formats:
|
||||
# when using {templates}, the template is shown only if it's argument isn't
|
||||
# empty unless no argument is given. for example {sb} is printed always,
|
||||
# but {sb $T} is printed only if $T isn't empty.
|
||||
|
||||
items = {
|
||||
# start/end text in statusbars
|
||||
barstart = "{sbstart}";
|
||||
barend = "{sbend}";
|
||||
|
||||
topicbarstart = "{topicsbstart}";
|
||||
topicbarend = "{topicsbend}";
|
||||
|
||||
# treated "normally", you could change the time/user name to whatever
|
||||
time = "{sb $Z}";
|
||||
user = "{sb {sbnickmode $cumode}$N{sbmode $usermode}{sbaway $A}}";
|
||||
|
||||
# treated specially .. window is printed with non-empty windows,
|
||||
# window_empty is printed with empty windows
|
||||
window = "{sb $winref:$tag/$itemname{sbmode $M}}";
|
||||
window_empty = "{sb $winref{sbservertag $tag}}";
|
||||
prompt = "{prompt $[.15]itemname}";
|
||||
prompt_empty = "{prompt $winname}";
|
||||
topic = " $topic";
|
||||
topic_empty = " Irssi v$J - http://www.irssi.org";
|
||||
|
||||
# all of these treated specially, they're only displayed when needed
|
||||
lag = "{sb Lag: $0-}";
|
||||
act = "{sb Act: $0-}";
|
||||
more = "-- more --";
|
||||
};
|
||||
|
||||
# there's two type of statusbars. root statusbars are either at the top
|
||||
# of the screen or at the bottom of the screen. window statusbars are at
|
||||
# the top/bottom of each split window in screen.
|
||||
default = {
|
||||
# the "default statusbar" to be displayed at the bottom of the window.
|
||||
# contains all the normal items.
|
||||
window = {
|
||||
disabled = "yes";
|
||||
|
||||
# window, root
|
||||
type = "window";
|
||||
# top, bottom
|
||||
placement = "bottom";
|
||||
# number
|
||||
position = "1";
|
||||
# active, inactive, always
|
||||
visible = "active";
|
||||
|
||||
# list of items in statusbar in the display order
|
||||
items = {
|
||||
barstart = { priority = "100"; };
|
||||
time = { };
|
||||
user = { };
|
||||
window = { };
|
||||
window_empty = { };
|
||||
lag = { priority = "-1"; };
|
||||
more = { priority = "-1"; alignment = "right"; };
|
||||
barend = { priority = "100"; alignment = "right"; };
|
||||
};
|
||||
};
|
||||
|
||||
# statusbar to use in inactive split windows
|
||||
window_inact = {
|
||||
type = "window";
|
||||
placement = "bottom";
|
||||
position = "1";
|
||||
visible = "inactive";
|
||||
items = {
|
||||
barstart = { priority = "100"; };
|
||||
window = { };
|
||||
window_empty = { };
|
||||
more = { priority = "-1"; alignment = "right"; };
|
||||
barend = { priority = "100"; alignment = "right"; };
|
||||
};
|
||||
};
|
||||
|
||||
# we treat input line as yet another statusbar :) It's possible to
|
||||
# add other items before or after the input line item.
|
||||
prompt = {
|
||||
type = "root";
|
||||
placement = "bottom";
|
||||
# we want to be at the bottom always
|
||||
position = "100";
|
||||
visible = "always";
|
||||
items = {
|
||||
prompt = { priority = "-1"; };
|
||||
prompt_empty = { priority = "-1"; };
|
||||
# treated specially, this is the real input line.
|
||||
input = { priority = "10"; };
|
||||
};
|
||||
};
|
||||
|
||||
# topicbar
|
||||
topic = {
|
||||
type = "root";
|
||||
placement = "top";
|
||||
position = "1";
|
||||
visible = "always";
|
||||
items = {
|
||||
topicbarstart = { priority = "100"; };
|
||||
time = { priority = "100"; };
|
||||
topic = { };
|
||||
topic_empty = { };
|
||||
window_empty = { alignment = "right"; };
|
||||
user = { priority = "100"; alignment = "right"; };
|
||||
topicbarend = { priority = "100"; alignment = "right"; };
|
||||
};
|
||||
};
|
||||
placement = { items = { }; disabled = "yes"; };
|
||||
remove = { disabled = "yes"; };
|
||||
awl_0 = {
|
||||
items = {
|
||||
barstart = { priority = "100"; };
|
||||
awl_0 = { };
|
||||
barend = { priority = "100"; alignment = "right"; };
|
||||
};
|
||||
};
|
||||
awl_1 = {
|
||||
items = {
|
||||
barstart = { priority = "100"; };
|
||||
awl_1 = { };
|
||||
barend = { priority = "100"; alignment = "right"; };
|
||||
};
|
||||
};
|
||||
awl_2 = {
|
||||
items = {
|
||||
barstart = { priority = "100"; };
|
||||
awl_2 = { };
|
||||
barend = { priority = "100"; alignment = "right"; };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
settings = {
|
||||
core = {
|
||||
real_name = "Matir";
|
||||
user_name = "matir";
|
||||
nick = "Matir";
|
||||
log_timestamp = "%Y%m%d %H%M";
|
||||
};
|
||||
"fe-text" = { actlist_sort = "refnum"; };
|
||||
"fe-common/core" = {
|
||||
autolog = "yes";
|
||||
autolog_path = "~/irclogs/%Y/%m/$tag/$0.log";
|
||||
autoclose_query = "1800";
|
||||
autocreate_own_query = "no";
|
||||
show_nickmode_empty = "no";
|
||||
term_charset = "utf-8";
|
||||
};
|
||||
"perl/core/scripts" = {
|
||||
awl_shared_sbar = "OFF";
|
||||
awl_viewer = "no";
|
||||
awl_block = "-15";
|
||||
awl_maxlines = "3";
|
||||
awl_height_adjust = "2";
|
||||
awl_hide_empty = "0";
|
||||
};
|
||||
};
|
||||
windows = {
|
||||
1 = { immortal = "yes"; name = "(status)"; level = "ALL"; };
|
||||
2 = {
|
||||
items = (
|
||||
{
|
||||
type = "CHANNEL";
|
||||
chat_type = "IRC";
|
||||
name = "#kali-linux";
|
||||
tag = "freenode";
|
||||
}
|
||||
);
|
||||
};
|
||||
3 = {
|
||||
items = (
|
||||
{
|
||||
type = "CHANNEL";
|
||||
chat_type = "IRC";
|
||||
name = "#radare";
|
||||
tag = "freenode";
|
||||
}
|
||||
);
|
||||
};
|
||||
4 = {
|
||||
items = (
|
||||
{
|
||||
type = "CHANNEL";
|
||||
chat_type = "IRC";
|
||||
name = "#vulnhub";
|
||||
tag = "freenode";
|
||||
}
|
||||
);
|
||||
};
|
||||
5 = {
|
||||
items = (
|
||||
{
|
||||
type = "CHANNEL";
|
||||
chat_type = "IRC";
|
||||
name = "#openvpn";
|
||||
tag = "freenode";
|
||||
}
|
||||
);
|
||||
};
|
||||
6 = {
|
||||
items = (
|
||||
{
|
||||
type = "CHANNEL";
|
||||
chat_type = "IRC";
|
||||
name = "#wargames";
|
||||
tag = "overthewire";
|
||||
}
|
||||
);
|
||||
};
|
||||
7 = {
|
||||
items = (
|
||||
{
|
||||
type = "CHANNEL";
|
||||
chat_type = "IRC";
|
||||
name = "#social";
|
||||
tag = "overthewire";
|
||||
}
|
||||
);
|
||||
};
|
||||
8 = {
|
||||
items = (
|
||||
{
|
||||
type = "CHANNEL";
|
||||
chat_type = "IRC";
|
||||
name = "#amateria";
|
||||
tag = "overthewire";
|
||||
}
|
||||
);
|
||||
};
|
||||
9 = {
|
||||
items = (
|
||||
{
|
||||
type = "CHANNEL";
|
||||
chat_type = "IRC";
|
||||
name = "#io";
|
||||
tag = "overthewire";
|
||||
}
|
||||
);
|
||||
};
|
||||
10 = {
|
||||
items = (
|
||||
{
|
||||
type = "CHANNEL";
|
||||
chat_type = "IRC";
|
||||
name = "#RedditNet";
|
||||
tag = "geekshed";
|
||||
}
|
||||
);
|
||||
};
|
||||
11 = {
|
||||
items = (
|
||||
{
|
||||
type = "CHANNEL";
|
||||
chat_type = "IRC";
|
||||
name = "#hak5";
|
||||
tag = "secfo";
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
mainwindows = { 1 = { first_line = "1"; lines = "78"; }; };
|
||||
logs = { };
|
||||
@@ -1,297 +0,0 @@
|
||||
# When testing changes, the easiest way to reload the theme is with /RELOAD.
|
||||
# This reloads the configuration file too, so if you did any changes remember
|
||||
# to /SAVE it first. Remember also that /SAVE overwrites the theme file with
|
||||
# old data so keep backups :)
|
||||
|
||||
# TEMPLATES:
|
||||
|
||||
# The real text formats that irssi uses are the ones you can find with
|
||||
# /FORMAT command. Back in the old days all the colors and texts were mixed
|
||||
# up in those formats, and it was really hard to change the colors since you
|
||||
# might have had to change them in tens of different places. So, then came
|
||||
# this templating system.
|
||||
|
||||
# Now the /FORMATs don't have any colors in them, and they also have very
|
||||
# little other styling. Most of the stuff you need to change is in this
|
||||
# theme file. If you can't change something here, you can always go back
|
||||
# to change the /FORMATs directly, they're also saved in these .theme files.
|
||||
|
||||
# So .. the templates. They're those {blahblah} parts you see all over the
|
||||
# /FORMATs and here. Their usage is simply {name parameter1 parameter2}.
|
||||
# When irssi sees this kind of text, it goes to find "name" from abstracts
|
||||
# block below and sets "parameter1" into $0 and "parameter2" into $1 (you
|
||||
# can have more parameters of course). Templates can have subtemplates.
|
||||
# Here's a small example:
|
||||
# /FORMAT format hello {colorify {underline world}}
|
||||
# abstracts = { colorify = "%G$0-%n"; underline = "%U$0-%U"; }
|
||||
# When irssi expands the templates in "format", the final string would be:
|
||||
# hello %G%Uworld%U%n
|
||||
# ie. underlined bright green "world" text.
|
||||
# and why "$0-", why not "$0"? $0 would only mean the first parameter,
|
||||
# $0- means all the parameters. With {underline hello world} you'd really
|
||||
# want to underline both of the words, not just the hello (and world would
|
||||
# actually be removed entirely).
|
||||
|
||||
# COLORS:
|
||||
|
||||
# You can find definitions for the color format codes in docs/formats.txt.
|
||||
|
||||
# There's one difference here though. %n format. Normally it means the
|
||||
# default color of the terminal (white mostly), but here it means the
|
||||
# "reset color back to the one it was in higher template". For example
|
||||
# if there was /FORMAT test %g{foo}bar, and foo = "%Y$0%n", irssi would
|
||||
# print yellow "foo" (as set with %Y) but "bar" would be green, which was
|
||||
# set at the beginning before the {foo} template. If there wasn't the %g
|
||||
# at start, the normal behaviour of %n would occur. If you _really_ want
|
||||
# to use the terminal's default color, use %N.
|
||||
|
||||
#############################################################################
|
||||
|
||||
# default foreground color (%N) - -1 is the "default terminal color"
|
||||
default_color = "-1";
|
||||
|
||||
# print timestamp/servertag at the end of line, not at beginning
|
||||
info_eol = "false";
|
||||
|
||||
# these characters are automatically replaced with specified color
|
||||
# (dark grey by default)
|
||||
replaces = { "[]=" = "%K$*%n"; };
|
||||
|
||||
abstracts = {
|
||||
##
|
||||
## generic
|
||||
##
|
||||
|
||||
# text to insert at the beginning of each non-message line
|
||||
line_start = "%B-%n!%B-%n ";
|
||||
|
||||
# timestamp styling, nothing by default
|
||||
timestamp = "$*";
|
||||
|
||||
# any kind of text that needs hilighting, default is to bold
|
||||
hilight = "%_$*%_";
|
||||
|
||||
# any kind of error message, default is bright red
|
||||
error = "%R$*%n";
|
||||
|
||||
# channel name is printed
|
||||
channel = "%_$*%_";
|
||||
|
||||
# nick is printed
|
||||
nick = "%_$*%_";
|
||||
|
||||
# nick host is printed
|
||||
nickhost = "[$*]";
|
||||
|
||||
# server name is printed
|
||||
server = "%_$*%_";
|
||||
|
||||
# some kind of comment is printed
|
||||
comment = "[$*]";
|
||||
|
||||
# reason for something is printed (part, quit, kick, ..)
|
||||
reason = "{comment $*}";
|
||||
|
||||
# mode change is printed ([+o nick])
|
||||
mode = "{comment $*}";
|
||||
|
||||
##
|
||||
## channel specific messages
|
||||
##
|
||||
|
||||
# highlighted nick/host is printed (joins)
|
||||
channick_hilight = "%C$*%n";
|
||||
chanhost_hilight = "{nickhost %c$*%n}";
|
||||
|
||||
# nick/host is printed (parts, quits, etc.)
|
||||
channick = "%c$*%n";
|
||||
chanhost = "{nickhost $*}";
|
||||
|
||||
# highlighted channel name is printed
|
||||
channelhilight = "%c$*%n";
|
||||
|
||||
# ban/ban exception/invite list mask is printed
|
||||
ban = "%c$*%n";
|
||||
|
||||
##
|
||||
## messages
|
||||
##
|
||||
|
||||
# the basic styling of how to print message, $0 = nick mode, $1 = nick
|
||||
msgnick = "%K<%n$0$1-%K>%n %|";
|
||||
|
||||
# message from you is printed. "msgownnick" specifies the styling of the
|
||||
# nick ($0 part in msgnick) and "ownmsgnick" specifies the styling of the
|
||||
# whole line.
|
||||
|
||||
# Example1: You want the message text to be green:
|
||||
# ownmsgnick = "{msgnick $0 $1-}%g";
|
||||
# Example2.1: You want < and > chars to be yellow:
|
||||
# ownmsgnick = "%Y{msgnick $0 $1-%Y}%n";
|
||||
# (you'll also have to remove <> from replaces list above)
|
||||
# Example2.2: But you still want to keep <> grey for other messages:
|
||||
# pubmsgnick = "%K{msgnick $0 $1-%K}%n";
|
||||
# pubmsgmenick = "%K{msgnick $0 $1-%K}%n";
|
||||
# pubmsghinick = "%K{msgnick $1 $0$2-%n%K}%n";
|
||||
# ownprivmsgnick = "%K{msgnick $*%K}%n";
|
||||
# privmsgnick = "%K{msgnick %R$*%K}%n";
|
||||
|
||||
# $0 = nick mode, $1 = nick
|
||||
ownmsgnick = "{msgnick $0 $1-}";
|
||||
ownnick = "%_$*%n";
|
||||
|
||||
# public message in channel, $0 = nick mode, $1 = nick
|
||||
pubmsgnick = "{msgnick $0 $1-}";
|
||||
pubnick = "%N$*%n";
|
||||
|
||||
# public message in channel meant for me, $0 = nick mode, $1 = nick
|
||||
pubmsgmenick = "{msgnick $0 $1-}";
|
||||
menick = "%Y$*%n";
|
||||
|
||||
# public highlighted message in channel
|
||||
# $0 = highlight color, $1 = nick mode, $2 = nick
|
||||
pubmsghinick = "{msgnick $1 $0$2-%n}";
|
||||
|
||||
# channel name is printed with message
|
||||
msgchannel = "%K:%c$*%n";
|
||||
|
||||
# private message, $0 = nick, $1 = host
|
||||
privmsg = "[%R$0%K(%r$1-%K)%n] ";
|
||||
|
||||
# private message from you, $0 = "msg", $1 = target nick
|
||||
ownprivmsg = "[%r$0%K(%R$1-%K)%n] ";
|
||||
|
||||
# own private message in query
|
||||
ownprivmsgnick = "{msgnick $*}";
|
||||
ownprivnick = "%_$*%n";
|
||||
|
||||
# private message in query
|
||||
privmsgnick = "{msgnick %R$*%n}";
|
||||
|
||||
##
|
||||
## Actions (/ME stuff)
|
||||
##
|
||||
|
||||
# used internally by this theme
|
||||
action_core = "%_ * $*%n";
|
||||
|
||||
# generic one that's used by most actions
|
||||
action = "{action_core $*} ";
|
||||
|
||||
# own action, both private/public
|
||||
ownaction = "{action $*}";
|
||||
|
||||
# own action with target, both private/public
|
||||
ownaction_target = "{action_core $0}%K:%c$1%n ";
|
||||
|
||||
# private action sent by others
|
||||
pvtaction = "%_ (*) $*%n ";
|
||||
pvtaction_query = "{action $*}";
|
||||
|
||||
# public action sent by others
|
||||
pubaction = "{action $*}";
|
||||
|
||||
|
||||
##
|
||||
## other IRC events
|
||||
##
|
||||
|
||||
# whois
|
||||
whois = "%# $[8]0 : $1-";
|
||||
|
||||
# notices
|
||||
ownnotice = "[%r$0%K(%R$1-%K)]%n ";
|
||||
notice = "%K-%M$*%K-%n ";
|
||||
pubnotice_channel = "%K:%m$*";
|
||||
pvtnotice_host = "%K(%m$*%K)";
|
||||
servernotice = "%g!$*%n ";
|
||||
|
||||
# CTCPs
|
||||
ownctcp = "[%r$0%K(%R$1-%K)] ";
|
||||
ctcp = "%g$*%n";
|
||||
|
||||
# wallops
|
||||
wallop = "%_$*%n: ";
|
||||
wallop_nick = "%n$*";
|
||||
wallop_action = "%_ * $*%n ";
|
||||
|
||||
# netsplits
|
||||
netsplit = "%R$*%n";
|
||||
netjoin = "%C$*%n";
|
||||
|
||||
# /names list
|
||||
names_prefix = "";
|
||||
names_nick = "[%_$0%_$1-] ";
|
||||
names_nick_op = "{names_nick $*}";
|
||||
names_nick_halfop = "{names_nick $*}";
|
||||
names_nick_voice = "{names_nick $*}";
|
||||
names_users = "[%g$*%n]";
|
||||
names_channel = "%G$*%n";
|
||||
|
||||
# DCC
|
||||
dcc = "%g$*%n";
|
||||
dccfile = "%_$*%_";
|
||||
|
||||
# DCC chat, own msg/action
|
||||
dccownmsg = "[%r$0%K($1-%K)%n] ";
|
||||
dccownnick = "%R$*%n";
|
||||
dccownquerynick = "%_$*%n";
|
||||
dccownaction = "{action $*}";
|
||||
dccownaction_target = "{action_core $0}%K:%c$1%n ";
|
||||
|
||||
# DCC chat, others
|
||||
dccmsg = "[%G$1-%K(%g$0%K)%n] ";
|
||||
dccquerynick = "%G$*%n";
|
||||
dccaction = "%_ (*dcc*) $*%n %|";
|
||||
|
||||
##
|
||||
## statusbar
|
||||
##
|
||||
|
||||
# default background for all statusbars. You can also give
|
||||
# the default foreground color for statusbar items.
|
||||
sb_background = "%4%w";
|
||||
|
||||
# default backround for "default" statusbar group
|
||||
#sb_default_bg = "%4";
|
||||
# background for prompt / input line
|
||||
sb_prompt_bg = "%n";
|
||||
# background for info statusbar
|
||||
sb_info_bg = "%8";
|
||||
# background for topicbar (same default)
|
||||
#sb_topic_bg = "%4";
|
||||
|
||||
# text at the beginning of statusbars. sb-item already puts
|
||||
# space there,so we don't use anything by default.
|
||||
sbstart = "";
|
||||
# text at the end of statusbars. Use space so that it's never
|
||||
# used for anything.
|
||||
sbend = " ";
|
||||
|
||||
topicsbstart = "{sbstart $*}";
|
||||
topicsbend = "{sbend $*}";
|
||||
|
||||
prompt = "[$*] ";
|
||||
|
||||
sb = " %c[%n$*%c]%n";
|
||||
sbmode = "(%c+%n$*)";
|
||||
sbaway = " (%GzZzZ%n)";
|
||||
sbservertag = ":$0 (change with ^X)";
|
||||
sbnickmode = "$0";
|
||||
|
||||
# activity in statusbar
|
||||
|
||||
# ',' separator
|
||||
sb_act_sep = "%c$*";
|
||||
# normal text
|
||||
sb_act_text = "%c$*";
|
||||
# public message
|
||||
sb_act_msg = "%W$*";
|
||||
# hilight
|
||||
sb_act_hilight = "%M$*";
|
||||
# hilight with specified color, $0 = color, $1 = text
|
||||
sb_act_hilight_color = "$0$1-%n";
|
||||
};
|
||||
formats = {
|
||||
"Irssi::Script::adv_windowlist" = { awl_display_header = ""; };
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
|
||||
lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
|
||||
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
|
||||
dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
|
||||
SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
|
||||
A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
|
||||
MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
|
||||
d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
|
||||
cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
|
||||
0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
|
||||
M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
|
||||
MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
|
||||
oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
|
||||
DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
|
||||
oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
|
||||
VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
|
||||
dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
|
||||
bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
|
||||
BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
|
||||
//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
|
||||
CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
|
||||
CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
|
||||
3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
|
||||
KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
|
||||
-----END CERTIFICATE-----
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
../adv_windowlist.pl
|
||||
@@ -1 +0,0 @@
|
||||
../cap_sasl.pl
|
||||
@@ -1,272 +0,0 @@
|
||||
use strict;
|
||||
use Irssi;
|
||||
use vars qw($VERSION %IRSSI);
|
||||
# $Id$
|
||||
|
||||
use MIME::Base64;
|
||||
|
||||
$VERSION = "1.3";
|
||||
|
||||
%IRSSI = (
|
||||
authors => 'Michael Tharp and Jilles Tjoelker',
|
||||
contact => 'gxti@partiallystapled.com',
|
||||
name => 'cap_sasl.pl',
|
||||
description => 'Implements PLAIN SASL authentication mechanism for use with charybdis ircds, and enables CAP MULTI-PREFIX',
|
||||
license => 'GNU General Public License',
|
||||
url => 'http://ircv3.atheme.org/extensions/sasl-3.1',
|
||||
);
|
||||
|
||||
my %sasl_auth = ();
|
||||
my %mech = ();
|
||||
|
||||
sub timeout;
|
||||
|
||||
sub server_connected {
|
||||
my $server = shift;
|
||||
$server->send_raw_now("CAP LS");
|
||||
}
|
||||
|
||||
sub event_cap {
|
||||
my ($server, $args, $nick, $address) = @_;
|
||||
my ($subcmd, $caps, $tosend);
|
||||
|
||||
$tosend = '';
|
||||
if ($args =~ /^\S+ (\S+) :(.*)$/) {
|
||||
$subcmd = uc $1;
|
||||
$caps = ' '.$2.' ';
|
||||
if ($subcmd eq 'LS') {
|
||||
$tosend .= ' multi-prefix' if $caps =~ / multi-prefix /i;
|
||||
$tosend .= ' sasl' if $caps =~ / sasl /i && defined($sasl_auth{$server->{tag}});
|
||||
$tosend =~ s/^ //;
|
||||
$server->print('', "CLICAP: supported by server:$caps");
|
||||
if (!$server->{connected}) {
|
||||
if ($tosend eq '') {
|
||||
$server->send_raw_now("CAP END");
|
||||
} else {
|
||||
$server->print('', "CLICAP: requesting: $tosend");
|
||||
$server->send_raw_now("CAP REQ :$tosend");
|
||||
}
|
||||
}
|
||||
Irssi::signal_stop();
|
||||
} elsif ($subcmd eq 'ACK') {
|
||||
$server->print('', "CLICAP: now enabled:$caps");
|
||||
if ($caps =~ / sasl /i) {
|
||||
$sasl_auth{$server->{tag}}{buffer} = '';
|
||||
if($mech{$sasl_auth{$server->{tag}}{mech}}) {
|
||||
$server->send_raw_now("AUTHENTICATE " . $sasl_auth{$server->{tag}}{mech});
|
||||
Irssi::timeout_add_once(5000, \&timeout, $server->{tag});
|
||||
}else{
|
||||
$server->print('', 'SASL: attempted to start unknown mechanism "' . $sasl_auth{$server->{tag}}{mech} . '"');
|
||||
}
|
||||
}
|
||||
elsif (!$server->{connected}) {
|
||||
$server->send_raw_now("CAP END");
|
||||
}
|
||||
Irssi::signal_stop();
|
||||
} elsif ($subcmd eq 'NAK') {
|
||||
$server->print('', "CLICAP: refused:$caps");
|
||||
if (!$server->{connected}) {
|
||||
$server->send_raw_now("CAP END");
|
||||
}
|
||||
Irssi::signal_stop();
|
||||
} elsif ($subcmd eq 'LIST') {
|
||||
$server->print('', "CLICAP: currently enabled:$caps");
|
||||
Irssi::signal_stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub event_authenticate {
|
||||
my ($server, $args, $nick, $address) = @_;
|
||||
my $sasl = $sasl_auth{$server->{tag}};
|
||||
return unless $sasl && $mech{$sasl->{mech}};
|
||||
|
||||
$sasl->{buffer} .= $args;
|
||||
return if length($args) == 400;
|
||||
|
||||
my $data = $sasl->{buffer} eq '+' ? '' : decode_base64($sasl->{buffer});
|
||||
my $out = $mech{$sasl->{mech}}($sasl, $data);
|
||||
$out = '' unless defined $out;
|
||||
$out = $out eq '' ? '+' : encode_base64($out, '');
|
||||
|
||||
while(length $out >= 400) {
|
||||
my $subout = substr($out, 0, 400, '');
|
||||
$server->send_raw_now("AUTHENTICATE $subout");
|
||||
}
|
||||
if(length $out) {
|
||||
$server->send_raw_now("AUTHENTICATE $out");
|
||||
}else{ # Last piece was exactly 400 bytes, we have to send some padding to indicate we're done
|
||||
$server->send_raw_now("AUTHENTICATE +");
|
||||
}
|
||||
|
||||
$sasl->{buffer} = '';
|
||||
Irssi::signal_stop();
|
||||
}
|
||||
|
||||
sub event_saslend {
|
||||
my ($server, $args, $nick, $address) = @_;
|
||||
|
||||
my $data = $args;
|
||||
$data =~ s/^\S+ :?//;
|
||||
# need this to see it, ?? -- jilles
|
||||
$server->print('', $data);
|
||||
if (!$server->{connected}) {
|
||||
$server->send_raw_now("CAP END");
|
||||
}
|
||||
}
|
||||
|
||||
sub timeout {
|
||||
my $tag = shift;
|
||||
my $server = Irssi::server_find_tag($tag);
|
||||
if(!$server->{connected}) {
|
||||
$server->print('', "SASL: authentication timed out");
|
||||
$server->send_raw_now("CAP END");
|
||||
}
|
||||
}
|
||||
|
||||
sub cmd_sasl {
|
||||
my ($data, $server, $item) = @_;
|
||||
|
||||
if ($data ne '') {
|
||||
Irssi::command_runsub ('sasl', $data, $server, $item);
|
||||
} else {
|
||||
cmd_sasl_show(@_);
|
||||
}
|
||||
}
|
||||
|
||||
sub cmd_sasl_set {
|
||||
my ($data, $server, $item) = @_;
|
||||
|
||||
if (my($net, $u, $p, $m) = $data =~ /^(\S+) (\S+) (\S+) (\S+)$/) {
|
||||
if($mech{uc $m}) {
|
||||
$sasl_auth{$net}{user} = $u;
|
||||
$sasl_auth{$net}{password} = $p;
|
||||
$sasl_auth{$net}{mech} = uc $m;
|
||||
Irssi::print("SASL: added $net: [$m] $sasl_auth{$net}{user} *");
|
||||
}else{
|
||||
Irssi::print("SASL: unknown mechanism $m");
|
||||
}
|
||||
} elsif ($data =~ /^(\S+)$/) {
|
||||
$net = $1;
|
||||
if (defined($sasl_auth{$net})) {
|
||||
delete $sasl_auth{$net};
|
||||
Irssi::print("SASL: deleted $net");
|
||||
} else {
|
||||
Irssi::print("SASL: no entry for $net");
|
||||
}
|
||||
} else {
|
||||
Irssi::print("SASL: usage: /sasl set <net> <user> <password or keyfile> <mechanism>");
|
||||
}
|
||||
}
|
||||
|
||||
sub cmd_sasl_show {
|
||||
#my ($data, $server, $item) = @_;
|
||||
my $net;
|
||||
my $count = 0;
|
||||
|
||||
foreach $net (keys %sasl_auth) {
|
||||
Irssi::print("SASL: $net: [$sasl_auth{$net}{mech}] $sasl_auth{$net}{user} *");
|
||||
$count++;
|
||||
}
|
||||
Irssi::print("SASL: no networks defined") if !$count;
|
||||
}
|
||||
|
||||
sub cmd_sasl_save {
|
||||
#my ($data, $server, $item) = @_;
|
||||
my $file = Irssi::get_irssi_dir()."/sasl.auth";
|
||||
open FILE, "> $file" or return;
|
||||
foreach my $net (keys %sasl_auth) {
|
||||
printf FILE ("%s\t%s\t%s\t%s\n", $net, $sasl_auth{$net}{user}, $sasl_auth{$net}{password}, $sasl_auth{$net}{mech});
|
||||
}
|
||||
close FILE;
|
||||
Irssi::print("SASL: auth saved to $file");
|
||||
}
|
||||
|
||||
sub cmd_sasl_load {
|
||||
#my ($data, $server, $item) = @_;
|
||||
my $file = Irssi::get_irssi_dir()."/sasl.auth";
|
||||
|
||||
open FILE, "< $file" or return;
|
||||
%sasl_auth = ();
|
||||
while (<FILE>) {
|
||||
chomp;
|
||||
my ($net, $u, $p, $m) = split (/\t/, $_, 4);
|
||||
$m ||= "PLAIN";
|
||||
if($mech{uc $m}) {
|
||||
$sasl_auth{$net}{user} = $u;
|
||||
$sasl_auth{$net}{password} = $p;
|
||||
$sasl_auth{$net}{mech} = uc $m;
|
||||
}else{
|
||||
Irssi::print("SASL: unknown mechanism $m");
|
||||
}
|
||||
}
|
||||
close FILE;
|
||||
Irssi::print("SASL: auth loaded from $file");
|
||||
}
|
||||
|
||||
sub cmd_sasl_mechanisms {
|
||||
Irssi::print("SASL: mechanisms supported: " . join(" ", keys %mech));
|
||||
}
|
||||
|
||||
Irssi::signal_add_first('server connected', \&server_connected);
|
||||
Irssi::signal_add('event cap', \&event_cap);
|
||||
Irssi::signal_add('event authenticate', \&event_authenticate);
|
||||
Irssi::signal_add('event 903', 'event_saslend');
|
||||
Irssi::signal_add('event 904', 'event_saslend');
|
||||
Irssi::signal_add('event 905', 'event_saslend');
|
||||
Irssi::signal_add('event 906', 'event_saslend');
|
||||
Irssi::signal_add('event 907', 'event_saslend');
|
||||
|
||||
Irssi::command_bind('sasl', \&cmd_sasl);
|
||||
Irssi::command_bind('sasl load', \&cmd_sasl_load);
|
||||
Irssi::command_bind('sasl save', \&cmd_sasl_save);
|
||||
Irssi::command_bind('sasl set', \&cmd_sasl_set);
|
||||
Irssi::command_bind('sasl show', \&cmd_sasl_show);
|
||||
Irssi::command_bind('sasl mechanisms', \&cmd_sasl_mechanisms);
|
||||
|
||||
$mech{PLAIN} = sub {
|
||||
my($sasl, $data) = @_;
|
||||
my $u = $sasl->{user};
|
||||
my $p = $sasl->{password};
|
||||
|
||||
join("\0", $u, $u, $p);
|
||||
};
|
||||
|
||||
eval {
|
||||
require Crypt::OpenSSL::Bignum;
|
||||
require Crypt::DH;
|
||||
require Crypt::Blowfish;
|
||||
require Math::BigInt;
|
||||
sub bin2bi { return Crypt::OpenSSL::Bignum->new_from_bin(shift)->to_decimal } # binary to BigInt
|
||||
sub bi2bin { return Crypt::OpenSSL::Bignum->new_from_decimal((shift)->bstr)->to_bin } # BigInt to binary
|
||||
$mech{'DH-BLOWFISH'} = sub {
|
||||
my($sasl, $data) = @_;
|
||||
my $u = $sasl->{user};
|
||||
my $pass = $sasl->{password};
|
||||
|
||||
# Generate private key and compute secret key
|
||||
my($p, $g, $y) = unpack("(n/a*)3", $data);
|
||||
my $dh = Crypt::DH->new(p => bin2bi($p), g => bin2bi($g));
|
||||
$dh->generate_keys;
|
||||
|
||||
my $secret = bi2bin($dh->compute_secret(bin2bi($y)));
|
||||
my $pubkey = bi2bin($dh->pub_key);
|
||||
|
||||
# Pad the password to the nearest multiple of blocksize and encrypt
|
||||
$pass .= "\0";
|
||||
$pass .= chr(rand(256)) while length($pass) % 8;
|
||||
|
||||
my $cipher = Crypt::Blowfish->new($secret);
|
||||
my $crypted = '';
|
||||
while(length $pass) {
|
||||
my $clear = substr($pass, 0, 8, '');
|
||||
$crypted .= $cipher->encrypt($clear);
|
||||
}
|
||||
|
||||
pack("n/a*Z*a*", $pubkey, $u, $crypted);
|
||||
};
|
||||
};
|
||||
|
||||
cmd_sasl_load();
|
||||
|
||||
# vim: ts=4
|
||||
107
dotfiles/local/lib/bash/tui.sh
Normal file
107
dotfiles/local/lib/bash/tui.sh
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# verify array support
|
||||
if eval '_t=(1)' 2>/dev/null; then
|
||||
unset _t
|
||||
else
|
||||
echo "Error: This script requires a shell with array and local variable support (like Bash or Zsh)." >&2
|
||||
(return 0 2>/dev/null) && return 1 || exit 1
|
||||
fi
|
||||
|
||||
select_entry() {
|
||||
# interactive selection from a list
|
||||
# usage: select_entry "$prompt" "$default"
|
||||
local prompt="${1:-Select an entry}"
|
||||
local default_choice="${2:-}"
|
||||
local input_data
|
||||
|
||||
if [[ -t 0 ]] ; then
|
||||
echo "select_entry should be used with piped input" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
input_data=$(cat)
|
||||
|
||||
if [[ -z "$input_data" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local display_prompt="$prompt"
|
||||
if [[ -n "$default_choice" ]]; then
|
||||
display_prompt="$prompt [$default_choice]"
|
||||
fi
|
||||
|
||||
if [[ -z "${NO_FZF:-}" ]] && command -v fzf >/dev/null 2>&1; then
|
||||
local fzf_input="$input_data"
|
||||
|
||||
# If a default is provided, move that line to the very top
|
||||
# so fzf's cursor starts on it.
|
||||
if [[ -n "$default_choice" ]]; then
|
||||
local default_line
|
||||
default_line=$(echo "$input_data" | grep "^$default_choice\([[:space:]]\|$\)")
|
||||
if [[ -n "$default_line" ]]; then
|
||||
# Remove the original line and prepend it to the top
|
||||
fzf_input=$(printf "%s\n%s" "$default_line" "$(echo "$input_data" | grep -v "^$default_choice\([[:space:]]\|$\)")")
|
||||
fi
|
||||
fi
|
||||
|
||||
local choice
|
||||
choice=$(echo "$fzf_input" | \
|
||||
fzf --prompt="$prompt: " --accept-nth 1 --height '~100%' --reverse)
|
||||
if [[ -z "$choice" ]]; then
|
||||
[[ -n "$default_choice" ]] && echo "$default_choice" && return 0
|
||||
return 1
|
||||
fi
|
||||
echo "${choice}"
|
||||
return 0
|
||||
else
|
||||
local i=1
|
||||
local lines=()
|
||||
|
||||
printf "\n--- %s ---\n" "$prompt" >&2
|
||||
|
||||
# Load lines into an array
|
||||
while IFS= read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
printf "%2d) %s\n" "$i" "$line"
|
||||
lines[i]="$line"
|
||||
((i++))
|
||||
done <<< "$input_data"
|
||||
|
||||
local count=$((i - 1))
|
||||
|
||||
printf "%s (1-%d or word): " "$display_prompt" "$count" >&2
|
||||
read -r choice
|
||||
|
||||
if [[ -z "$choice" ]]; then
|
||||
if [[ -n "$default_choice" ]]; then
|
||||
echo "$default_choice"
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Match logic
|
||||
if [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= count )); then
|
||||
echo "${lines[$choice]}" | awk '{print $1}'
|
||||
else
|
||||
# Iterate to find word match
|
||||
local found=0
|
||||
for (( j=1; j<=count; j++ )); do
|
||||
local current_line="${lines[$j]}"
|
||||
local first_word="${current_line%%[[:space:]]*}"
|
||||
if [[ "$choice" == "$first_word" ]]; then
|
||||
echo "$first_word"
|
||||
found=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $found -eq 0 ]]; then
|
||||
echo "Invalid selection: $choice" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
1
dotfiles/npmrc
Normal file
1
dotfiles/npmrc
Normal file
@@ -0,0 +1 @@
|
||||
prefix = ${HOME}/.npm-packages
|
||||
47
dotfiles/restic_exclude.darwin
Normal file
47
dotfiles/restic_exclude.darwin
Normal file
@@ -0,0 +1,47 @@
|
||||
# Restic exclude file for macOS
|
||||
|
||||
# General Cache Folders
|
||||
/Users/*/Library/Caches
|
||||
/Users/*/.cache
|
||||
.Trash
|
||||
/private/var/folders
|
||||
|
||||
# Specific Application Caches
|
||||
/Users/*/Library/Application Support/Google/Chrome/Default/Application Cache
|
||||
/Users/*/Library/Application Support/Firefox/Profiles/*.default/cache2
|
||||
/Users/*/Library/Application Support/Spotify/PersistentCache
|
||||
/Users/*/Library/Metadata/CoreSpotlight
|
||||
|
||||
# Developer related
|
||||
/Users/*/.m2
|
||||
/Users/*/.gradle
|
||||
/Users/*/node_modules
|
||||
/Users/*/go/pkg
|
||||
/Users/*/.espressif
|
||||
|
||||
# Virtual Machine Disks
|
||||
/Users/*/VirtualBox VMs
|
||||
/Users/*/Parallels
|
||||
|
||||
# Cloud Storage (to avoid backing up already synced files)
|
||||
/Users/*/Dropbox
|
||||
/Users/*/Google Drive
|
||||
/Users/*/.onedrive
|
||||
|
||||
# Other
|
||||
/Users/*/Music/iTunes/iTunes Music Library.xml
|
||||
/Users/*/Music/iTunes/Previous iTunes Libraries
|
||||
|
||||
# macOS specific
|
||||
/Users/*/.DS_Store
|
||||
/Users/*/Public/Drop Box
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
hibernationfile
|
||||
sleepimage
|
||||
swapfile
|
||||
12
dotfiles/ripgreprc
Normal file
12
dotfiles/ripgreprc
Normal file
@@ -0,0 +1,12 @@
|
||||
# ignore case unless there's an uppercase in the pattern
|
||||
--smart-case
|
||||
|
||||
# generally stay in one file system
|
||||
--one-file-system
|
||||
|
||||
# avoid lines too long
|
||||
--max-columns=120
|
||||
--max-columns-preview
|
||||
|
||||
# Never search in .git
|
||||
--glob=!.git/*
|
||||
@@ -41,5 +41,7 @@ Downloads
|
||||
SpiderOak Hive
|
||||
Unity
|
||||
VirtualBox VMs
|
||||
go
|
||||
tmp
|
||||
tools
|
||||
PDFs.tar.bz2
|
||||
|
||||
@@ -1 +1,9 @@
|
||||
rvm_silence_path_mismatch_check_flag=1
|
||||
export rvm_environments_path="${HOME}/.rvm/environments"
|
||||
export rvm_gems_path="${HOME}/.rvm/gems"
|
||||
export rvm_gems_cache_path="${HOME}/.rvm/gems_cache"
|
||||
export rvm_wrappers_path="${HOME}/.rvm/wrappers"
|
||||
export rvm_create_flag="1"
|
||||
export rvm_user_path="${HOME}/.rvm/user"
|
||||
export rvm_log_path="${HOME}/.rvm/log"
|
||||
export rvm_pkgs_path="${HOME}/.rvm/pkgs"
|
||||
|
||||
124
dotfiles/shenv
124
dotfiles/shenv
@@ -1,12 +1,14 @@
|
||||
#!/bin/sh
|
||||
# Sourced by zshrc as well as bash.
|
||||
# Should only use POSIX shell constructs.
|
||||
# shellcheck shell=sh
|
||||
|
||||
umask 027
|
||||
|
||||
# Paths and preferences
|
||||
export PYTHONPATH="$HOME/.python:$PYTHONPATH"
|
||||
export GOPATH="$HOME/go:$HOME/Projects/Go:/usr/share/gocode"
|
||||
export PATH="$HOME/bin:$HOME/bin/tools:/sbin:/usr/sbin:$PATH:$HOME/go/bin"
|
||||
export PATH="$HOME/bin:$HOME/bin/tools:/sbin:/usr/sbin:$PATH:$HOME/go/bin:$HOME/.npm-packages/bin"
|
||||
export VISUAL=vim
|
||||
export EDITOR=vim
|
||||
export DEBEMAIL="david@systemoverlord.com"
|
||||
@@ -20,6 +22,15 @@ if [ "$TERM" = "xterm" ] && [ "$COLORTERM" = "gnome-terminal" ] ; then
|
||||
export TERM="xterm-256color"
|
||||
fi
|
||||
|
||||
# For virtualenvwrapper
|
||||
export WORKON_HOME="$HOME/.virtualenvs"
|
||||
|
||||
# GPG full key id
|
||||
export GPG_ID=7FD58D9A196DCEEEAD671F94F4D7A7915DEA789B
|
||||
|
||||
# things we need in all interactive shells
|
||||
case "$-" in
|
||||
*i*)
|
||||
# Terminal preferences for i3
|
||||
if [ -z "${TERMINAL}" ] ; then
|
||||
for t in urxvt gnome-terminal; do
|
||||
@@ -39,12 +50,6 @@ if [ -z "${BROWSER}" ] ; then
|
||||
done
|
||||
fi
|
||||
|
||||
# For virtualenvwrapper
|
||||
export WORKON_HOME=$HOME/.virtualenvs
|
||||
|
||||
# GPG full key id
|
||||
export GPG_ID=7FD58D9A196DCEEEAD671F94F4D7A7915DEA789B
|
||||
|
||||
# Setup locale
|
||||
if test -x /usr/bin/locale ; then
|
||||
for l in en_US.utf8 en_US.UTF-8 C.UTF-8 C.utf8 C ; do
|
||||
@@ -77,6 +82,9 @@ else
|
||||
export LC_IDENTIFICATION=C
|
||||
fi
|
||||
export LC_COLLATE=C
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
# Opt out of .net telemetry
|
||||
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
@@ -87,5 +95,105 @@ export LVM_SUPPRESS_FD_WARNINGS=1
|
||||
# Default disable SSH forwarding in EARTHLY
|
||||
export EARTHLY_SSH_AUTH_SOCK=""
|
||||
|
||||
# Handle SSH_AUTH_SOCK for tmux consistency
|
||||
_SSH_AUTH_LINK="${HOME}/.ssh/ssh_auth_sock"
|
||||
|
||||
# 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
|
||||
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
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_CANDIDATE=""
|
||||
|
||||
# 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
|
||||
|
||||
# 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 [ "$(uname)" = "Darwin" ]; then
|
||||
_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}"
|
||||
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-)
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -S "${_FOUND}" ] && ! _is_link_path "${_FOUND}"; then
|
||||
_CANDIDATE="${_FOUND}"
|
||||
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
|
||||
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
|
||||
mkdir -p "$(dirname "${_SSH_AUTH_LINK}")"
|
||||
ln -sf "${_CANDIDATE}" "${_SSH_AUTH_LINK}"
|
||||
export SSH_AUTH_SOCK="${_SSH_AUTH_LINK}"
|
||||
# Update systemd if present to keep everything in sync
|
||||
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
|
||||
# If we found nothing better but the link is valid, use it.
|
||||
export SSH_AUTH_SOCK="${_SSH_AUTH_LINK}"
|
||||
fi
|
||||
|
||||
unset _SSH_AUTH_LINK _CANDIDATE _FOUND _T _P _U _u _SEARCH _d
|
||||
unset -f _is_link_path
|
||||
|
||||
# Setup XDG-like dirs on MacOS
|
||||
# Based on https://leebyron.com/til/mac-xdg/
|
||||
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}"
|
||||
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||
# Using id -u for better POSIX compatibility than $UID
|
||||
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-$TMPDIR/runtime-$(id -u)}"
|
||||
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
|
||||
fi
|
||||
|
||||
if test -e "$HOME/.localenv"; then
|
||||
# shellcheck source=/dev/null
|
||||
test -e "$HOME/.localenv" && . "$HOME/.localenv"
|
||||
. "$HOME/.localenv"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
# Added by OrbStack: 'orb' SSH host for Linux machines
|
||||
# This only works if it's at the top of ssh_config (before any Host blocks).
|
||||
# This won't be added again if you remove it.
|
||||
Include ~/.orbstack/ssh/config
|
||||
|
||||
# Universal Settings
|
||||
Protocol 2
|
||||
|
||||
Host *
|
||||
# Add the post-quantum (PQ) KEX algorithms to the front of the default list.
|
||||
# The client will try them in this order before falling back to standard ones.
|
||||
# The (+) syntax requires OpenSSH 7.8 or newer.
|
||||
KexAlgorithms +mlkem768x25519-sha256,sntrup761x25519-sha512@openssh.com
|
||||
|
||||
# Permit Local Overrides
|
||||
Include ~/.ssh/config.d/*
|
||||
|
||||
@@ -8,20 +19,20 @@ Include ~/.ssh/config.d/*
|
||||
HashKnownHosts no
|
||||
|
||||
# Enable canonicalization, unless overridden
|
||||
CanonicalizeHostname yes
|
||||
CanonicalizeHostname always
|
||||
CanonicalizeFallbackLocal yes
|
||||
CanonicalDomains systemoverlord.com
|
||||
CanonicalizeMaxDots 0
|
||||
|
||||
# Defaults (May be Overridden)
|
||||
Host *.*
|
||||
CheckHostIP yes
|
||||
|
||||
Host *.cloudshell.dev
|
||||
# Cloudshell hostnames are too long for unix sockets
|
||||
ControlMaster no
|
||||
|
||||
Match canonical all
|
||||
Match exec "test -d \"$XDG_RUNTIME_DIR\" && mkdir -p $XDG_RUNTIME_DIR/sshsock" final
|
||||
ControlPath ${XDG_RUNTIME_DIR}/sshsock/%C
|
||||
|
||||
# Anything set earlier will take precedence, so these are defaults
|
||||
Match final
|
||||
CheckHostIP no
|
||||
ControlMaster auto
|
||||
ControlPath ~/.ssh/master/%r@%h:%p
|
||||
@@ -33,4 +44,4 @@ Match canonical all
|
||||
ServerAliveCountMax 3
|
||||
UpdateHostKeys yes
|
||||
User david
|
||||
VerifyHostKeyDNS yes
|
||||
VerifyHostKeyDNS ask
|
||||
|
||||
@@ -5,23 +5,28 @@
|
||||
|
||||
REMOTE_LINK="${HOME}/.ssh/ssh_auth_sock"
|
||||
|
||||
if [ "${1:-}" = "force" ] && [ -S "${SSH_AUTH_SOCK}" ] ; then
|
||||
ln -sf "${SSH_AUTH_SOCK}" "${REMOTE_LINK}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test \! -S "${REMOTE_LINK}" -a -S "${SSH_AUTH_SOCK}" ; then
|
||||
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
|
||||
if [ ! -t 0 ] ; then
|
||||
# Handle X forwarding, per sshd(8)
|
||||
if read proto cookie && [ -n "$DISPLAY" ]; then
|
||||
if [ `echo $DISPLAY | cut -c1-10` = 'localhost:' ]; then
|
||||
if read -r proto cookie && [ -n "$DISPLAY" ]; then
|
||||
if [ "$(echo "$DISPLAY" | cut -c1-10)" = 'localhost:' ]; then
|
||||
# X11UseLocalhost=yes
|
||||
echo add unix:`echo $DISPLAY |
|
||||
cut -c11-` $proto $cookie
|
||||
echo add "unix:$(echo "$DISPLAY" | cut -c11-)" "$proto" "$cookie"
|
||||
else
|
||||
# X11UseLocalhost=no
|
||||
echo add $DISPLAY $proto $cookie
|
||||
echo add "$DISPLAY $proto $cookie"
|
||||
fi | xauth -q -
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -19,15 +19,16 @@ set -g pane-base-index 1
|
||||
|
||||
# Terminal emulator window title
|
||||
set -g set-titles on
|
||||
set -g set-titles-string '#h:#S:#I.#P #W'
|
||||
set -g set-titles-string '#h:#S:#I.#P #W#{?pane_title, (#{pane_title}),}'
|
||||
|
||||
# Set keybindings
|
||||
set -g mode-keys vi
|
||||
set -g status-keys vi
|
||||
|
||||
# Set a 256color $TERM variable so programs inside tmux know they can use 256
|
||||
# colors
|
||||
set -g default-terminal screen-256color
|
||||
# Set a terminal name but also enable 24 bit support in tmux
|
||||
set -g default-terminal tmux-256color
|
||||
set -as terminal-features ",xterm-256color:RGB"
|
||||
set-env -g COLORTERM "truecolor"
|
||||
|
||||
# Activity
|
||||
setw -g monitor-activity on
|
||||
@@ -43,8 +44,8 @@ source-file ~/.tmux/tmux-solarized-256.conf
|
||||
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 '/#S/ '
|
||||
set -g status-right '#(cut -d " " -f 1-3 /proc/loadavg)#[default] #[fg=colour166]%H:%M#[default]'
|
||||
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]'
|
||||
|
||||
# Advanced mouse mode from http://tangledhelix.com/blog/2012/07/16/tmux-and-mouse-mode/
|
||||
# Toggle mouse on
|
||||
@@ -67,12 +68,10 @@ bind M \
|
||||
bind C-c run "tmux show-buffer | xsel -i -b"
|
||||
bind C-v run "tmux set-buffer -- \"$(xsel -o -b)\"; tmux paste-buffer"
|
||||
|
||||
# Enable logging module, if available
|
||||
run-shell "~/.tmux/tmux-logging/logging.tmux || true"
|
||||
|
||||
# Enable TMUX Plugin Manager
|
||||
# install with:
|
||||
# git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
|
||||
# List of plugins
|
||||
set -g @plugin 'tmux-plugins/tpm'
|
||||
set -g @plugin 'tmux-plugins/tmux-sensible'
|
||||
run-shell "~/.tmux/plugins/tpm/tpm || true"
|
||||
set -g @plugin 'tmux-plugins/tmux-logging'
|
||||
|
||||
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
|
||||
run '~/.tmux/plugins/tpm/tpm'
|
||||
|
||||
Submodule dotfiles/tmux/tmux-logging deleted from 4717cbd4c8
Submodule dotfiles/vim/pack/matir/opt/solarized8 deleted from 7b6399093c
Submodule dotfiles/vim/pack/matir/start/editorconfig deleted from 8f6eba5fd6
Submodule dotfiles/vim/pack/matir/start/fugitive deleted from 2a53d79248
Submodule dotfiles/vim/pack/matir/start/surround deleted from f51a26d371
40
dotfiles/vim/plugin/hexedit.vim
Normal file
40
dotfiles/vim/plugin/hexedit.vim
Normal file
@@ -0,0 +1,40 @@
|
||||
" Mediocre Hex editing in vim
|
||||
" Source: http://vim.wikia.com/wiki/Improved_hex_editing
|
||||
|
||||
command -bar Hexmode call ToggleHex()
|
||||
function ToggleHex()
|
||||
" hex mode should be considered a read-only operation
|
||||
" save values for modified and read-only for restoration later,
|
||||
" and clear the read-only flag for now
|
||||
let l:modified=&mod
|
||||
let l:oldreadonly=&readonly
|
||||
let &readonly=0
|
||||
let l:oldmodifiable=&modifiable
|
||||
let &modifiable=1
|
||||
if !exists("b:editHex") || !b:editHex
|
||||
" save old options
|
||||
let b:oldft=&ft
|
||||
let b:oldbin=&bin
|
||||
" set new options
|
||||
setlocal binary " make sure it overrides any textwidth, etc.
|
||||
let &ft="xxd"
|
||||
" set status
|
||||
let b:editHex=1
|
||||
" switch to hex editor
|
||||
%!xxd
|
||||
else
|
||||
" restore old options
|
||||
let &ft=b:oldft
|
||||
if !b:oldbin
|
||||
setlocal nobinary
|
||||
endif
|
||||
" set status
|
||||
let b:editHex=0
|
||||
" return to normal editing
|
||||
%!xxd -r
|
||||
endif
|
||||
" restore values for modified and read only state
|
||||
let &mod=l:modified
|
||||
let &readonly=l:oldreadonly
|
||||
let &modifiable=l:oldmodifiable
|
||||
endfunction
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user