Compare commits
56 Commits
ff4faf34f6
...
56dbacfd8f
| Author | SHA1 | Date | |
|---|---|---|---|
| 56dbacfd8f | |||
| 7c0dd2185a | |||
| a3554c71f0 | |||
| 706eb62f76 | |||
| 8d1c3e5539 | |||
| d1190bacea | |||
| 67d587518a | |||
| d44c8983d6 | |||
| de0441e9cf | |||
| 6c5f3127bd | |||
| b659989abc | |||
| 13ed470439 | |||
| 10ca6b492a | |||
| 5a8e2f30db | |||
| c0444538e4 | |||
| a376b6f4dd | |||
| 25d440e994 | |||
| 5e34b30e25 | |||
| fbf86d1572 | |||
| 7d380be4a4 | |||
| fcdfa0de1f | |||
| 1e1d40a098 | |||
| 7875d0cee1 | |||
| 83a45b2bae | |||
| e012243194 | |||
| 34397fbb50 | |||
| bc4dac57a2 | |||
| faef305ec0 | |||
| a012b8e62b | |||
| 3c7b531f18 | |||
| d82eb2d366 | |||
| c675d32a20 | |||
| 66709ba136 | |||
| 75b2efc19c | |||
| 0887c39e10 | |||
| 700dcfe444 | |||
| 38ab3d07cb | |||
| f65a3d857a | |||
| 9d7dd26b7d | |||
| 78a14a7feb | |||
| b04632d191 | |||
| a427fc9e05 | |||
| 1c71771cf4 | |||
| 70f9bbc727 | |||
| 68a5ae410c | |||
| 345fa1c53b | |||
| 4fae071bbb | |||
| 3ba095c86e | |||
| 42a1085e77 | |||
| e9d6449f9b | |||
| 02b2cd894b | |||
| 1fac4db005 | |||
| 6872ed49ff | |||
| 11e1ad3afb | |||
| ecb7f984aa | |||
| f106d9b565 |
203
bin/backup_browse.sh
Executable file
203
bin/backup_browse.sh
Executable file
@@ -0,0 +1,203 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# --- SUDO CHECK ---
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo "This script requires root privileges. Re-running with sudo..."
|
||||||
|
exec sudo "$0" "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- HANDLE OPTIONS ---
|
||||||
|
BORG_PASSPHRASE=""
|
||||||
|
SHOW_FOLDERS_ONLY=false
|
||||||
|
SHOW_FILES=true # Default to showing files and directories
|
||||||
|
|
||||||
|
while getopts "k:fp" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
k)
|
||||||
|
BORG_PASSPHRASE=$(<"$OPTARG")
|
||||||
|
if [ -z "$BORG_PASSPHRASE" ]; then
|
||||||
|
echo "Error: The key file is empty."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Using passphrase from key file: $OPTARG"
|
||||||
|
;;
|
||||||
|
f)
|
||||||
|
SHOW_FOLDERS_ONLY=true
|
||||||
|
echo "Only directories will be shown in fzf by default."
|
||||||
|
SHOW_FILES=false
|
||||||
|
;;
|
||||||
|
p)
|
||||||
|
SHOW_FILES=true
|
||||||
|
echo "Both files and directories will be shown in fzf."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 [-k passphrase_file] [-f] [-p] <repo>"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
# --- FALLBACK TO /run/secrets/borg_passwd IF NO KEY FILE ---
|
||||||
|
if [ -z "$BORG_PASSPHRASE" ]; then
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
BORG_PASSPHRASE=$(<"/run/secrets/borg_passwd")
|
||||||
|
echo "Using passphrase from /run/secrets/borg_passwd"
|
||||||
|
else
|
||||||
|
# Prompt user for passphrase if neither -k nor /run/secrets/borg_passwd is available
|
||||||
|
read -s -p "Enter Borg repository passphrase: " BORG_PASSPHRASE
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
export BORG_PASSPHRASE
|
||||||
|
|
||||||
|
# --- DEFAULT REPO ---
|
||||||
|
REPO="${1:-/holocron/backups}"
|
||||||
|
|
||||||
|
# --- CHECK REQUIRED COMMANDS ---
|
||||||
|
for cmd in borg fzf find tree cp mkdir; do
|
||||||
|
command -v "$cmd" >/dev/null || { echo "Error: '$cmd' is required but not installed."; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- LIST ARCHIVES (sorted, newest last) ---
|
||||||
|
mapfile -t archives < <(borg list --format="{archive}{NL}" "$REPO" | sort -r)
|
||||||
|
if [ ${#archives[@]} -eq 0 ]; then
|
||||||
|
echo "No archives found in $REPO"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- FZF ARCHIVE SELECT ---
|
||||||
|
selected=$(printf '%s\n' "${archives[@]}" | fzf --prompt="Select archive: " --height=40% --border)
|
||||||
|
if [ -z "$selected" ]; then
|
||||||
|
echo "No archive selected."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Selected archive: $selected"
|
||||||
|
|
||||||
|
# --- GENERATE A UNIQUE, SHORTER MOUNT POINT ---
|
||||||
|
MOUNT_POINT="/tmp/$(uuidgen | sha256sum | head -c 2)-restore-${selected}"
|
||||||
|
mkdir -p "$MOUNT_POINT"
|
||||||
|
|
||||||
|
# --- MOUNT ARCHIVE ---
|
||||||
|
echo "Mounting '$selected' to $MOUNT_POINT..."
|
||||||
|
borg mount "$REPO::$selected" "$MOUNT_POINT"
|
||||||
|
|
||||||
|
if [ ! -d "$MOUNT_POINT" ]; then
|
||||||
|
echo "Error: mount failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- LIST FILES AND DIRECTORIES ---
|
||||||
|
echo "Scanning files and directories..."
|
||||||
|
if command -v fd >/dev/null 2>&1; then
|
||||||
|
# List both files and directories with fd
|
||||||
|
if [ "$SHOW_FILES" = true ]; then
|
||||||
|
files=$(fd . "$MOUNT_POINT" | sort) # Show both files and directories
|
||||||
|
else
|
||||||
|
files=$(fd --type d . "$MOUNT_POINT" | sort) # Only directories
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Fall back to find if fd is not available
|
||||||
|
if [ "$SHOW_FILES" = true ]; then
|
||||||
|
files=$(find "$MOUNT_POINT" | sort) # Show both files and directories
|
||||||
|
else
|
||||||
|
files=$(find "$MOUNT_POINT" -type d | sort) # Only directories
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$files" ]; then
|
||||||
|
echo "No files or directories found in archive."
|
||||||
|
borg umount "$MOUNT_POINT"
|
||||||
|
rm -rf "$MOUNT_POINT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- FZF FILE/DIRECTORY SELECTION ---
|
||||||
|
if [ "$SHOW_FILES" = true ]; then
|
||||||
|
# If showing files and directories, we pass everything to fzf
|
||||||
|
selected_items=$(printf '%s\n' "$files" | sed "s|$MOUNT_POINT/||" | tac | fzf \
|
||||||
|
--multi \
|
||||||
|
--height=50% \
|
||||||
|
--border \
|
||||||
|
--prompt="Select files or directories to restore: " \
|
||||||
|
--preview "tree -C -L 5 $MOUNT_POINT/$(dirname {})" \
|
||||||
|
--preview-window=right:50% \
|
||||||
|
--delimiter='/' \
|
||||||
|
--with-nth=1..)
|
||||||
|
else
|
||||||
|
# If only showing directories, pass directories to fzf
|
||||||
|
selected_items=$(printf '%s\n' "$files" | sed "s|$MOUNT_POINT/||" | tac | fzf \
|
||||||
|
--multi \
|
||||||
|
--height=50% \
|
||||||
|
--border \
|
||||||
|
--prompt="Select directories to restore: " \
|
||||||
|
--preview "tree -C -d -L 5 $MOUNT_POINT/$(dirname {})" \
|
||||||
|
--preview-window=right:50% \
|
||||||
|
--delimiter='/' \
|
||||||
|
--with-nth=1..)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$selected_items" ]; then
|
||||||
|
echo "No items selected. Exiting."
|
||||||
|
borg umount "$MOUNT_POINT"
|
||||||
|
rm -rf "$MOUNT_POINT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- SUMMARY OF SELECTED ITEMS ---
|
||||||
|
echo "Selected items:"
|
||||||
|
for item in $selected_items; do
|
||||||
|
echo " $item"
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- OPTIONS MENU (concise) ---
|
||||||
|
# Default to option 1 if no input is given
|
||||||
|
echo "Select restore destination: 1) Restore to ./${selected}_restore 2) Restore to original dirs 3) Quit"
|
||||||
|
read -p "Enter your choice (1/2/3) [default: 1]: " choice
|
||||||
|
# Default to option 1 if user presses Enter without providing input
|
||||||
|
choice="${choice:-1}"
|
||||||
|
|
||||||
|
# --- SET RESTORE DESTINATION BASED ON USER CHOICE ---
|
||||||
|
case "$choice" in
|
||||||
|
1)
|
||||||
|
DEST="./${selected}_restore"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
DEST="$MOUNT_POINT"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
echo "Quitting. No items restored."
|
||||||
|
borg umount "$MOUNT_POINT"
|
||||||
|
rm -rf "$MOUNT_POINT"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid choice. Exiting."
|
||||||
|
borg umount "$MOUNT_POINT"
|
||||||
|
rm -rf "$MOUNT_POINT"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
mkdir -p "$DEST"
|
||||||
|
|
||||||
|
# --- RESTORE SELECTED ITEMS (FILES OR DIRECTORIES) ---
|
||||||
|
echo "Restoring selected items..."
|
||||||
|
while IFS= read -r item; do
|
||||||
|
dest_path="$DEST/$item"
|
||||||
|
mkdir -p "$(dirname "$dest_path")"
|
||||||
|
if [ -d "$MOUNT_POINT/$item" ]; then
|
||||||
|
cp -r "$MOUNT_POINT/$item" "$dest_path"
|
||||||
|
else
|
||||||
|
cp -a "$MOUNT_POINT/$item" "$dest_path"
|
||||||
|
fi
|
||||||
|
echo "Restored: $item"
|
||||||
|
done <<< "$selected_items"
|
||||||
|
|
||||||
|
# --- CLEANUP ---
|
||||||
|
borg umount "$MOUNT_POINT"
|
||||||
|
rm -rf "$MOUNT_POINT"
|
||||||
|
echo "Restore complete."
|
||||||
|
|
||||||
173
bin/backup_browse.sh.bak
Executable file
173
bin/backup_browse.sh.bak
Executable file
@@ -0,0 +1,173 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# --- SUDO CHECK ---
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo "This script requires root privileges. Re-running with sudo..."
|
||||||
|
exec sudo "$0" "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- HANDLE -k OPTION FOR KEY FILE ---
|
||||||
|
BORG_PASSPHRASE=""
|
||||||
|
|
||||||
|
while getopts "k:" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
k)
|
||||||
|
BORG_PASSPHRASE=$(<"$OPTARG")
|
||||||
|
if [ -z "$BORG_PASSPHRASE" ]; then
|
||||||
|
echo "Error: The key file is empty."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Using passphrase from key file: $OPTARG"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 [-k passphrase_file] <repo>"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
# --- FALLBACK TO /run/secrets/borg_passwd IF NO KEY FILE ---
|
||||||
|
if [ -z "$BORG_PASSPHRASE" ]; then
|
||||||
|
if [ -f "/run/secrets/borg_passwd" ]; then
|
||||||
|
BORG_PASSPHRASE=$(<"/run/secrets/borg_passwd")
|
||||||
|
echo "Using passphrase from /run/secrets/borg_passwd"
|
||||||
|
else
|
||||||
|
# Prompt user for passphrase if neither -k nor /run/secrets/borg_passwd is available
|
||||||
|
read -s -p "Enter Borg repository passphrase: " BORG_PASSPHRASE
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
export BORG_PASSPHRASE
|
||||||
|
|
||||||
|
# --- DEFAULT REPO ---
|
||||||
|
REPO="${1:-/holocron/backups}"
|
||||||
|
|
||||||
|
# --- CHECK REQUIRED COMMANDS ---
|
||||||
|
for cmd in borg fzf find tree cp mkdir; do
|
||||||
|
command -v "$cmd" >/dev/null || { echo "Error: '$cmd' is required but not installed."; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- LIST ARCHIVES (sorted, newest last) ---
|
||||||
|
mapfile -t archives < <(borg list --format="{archive}{NL}" "$REPO" | sort)
|
||||||
|
if [ ${#archives[@]} -eq 0 ]; then
|
||||||
|
echo "No archives found in $REPO"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- FZF ARCHIVE SELECT ---
|
||||||
|
selected=$(printf '%s\n' "${archives[@]}" | fzf --prompt="Select archive: " --height=40% --border --reverse)
|
||||||
|
if [ -z "$selected" ]; then
|
||||||
|
echo "No archive selected."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Selected archive: $selected"
|
||||||
|
|
||||||
|
# --- GENERATE A UNIQUE, SHORTER MOUNT POINT ---
|
||||||
|
MOUNT_POINT="/tmp/borg-mount-${selected}-$(uuidgen | sha256sum | head -c 6)"
|
||||||
|
mkdir -p "$MOUNT_POINT"
|
||||||
|
|
||||||
|
# --- MOUNT ARCHIVE ---
|
||||||
|
echo "Mounting '$selected' to $MOUNT_POINT..."
|
||||||
|
borg mount "$REPO::$selected" "$MOUNT_POINT"
|
||||||
|
|
||||||
|
if [ ! -d "$MOUNT_POINT" ]; then
|
||||||
|
echo "Error: mount failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- LIST FILES AND DIRECTORIES ---
|
||||||
|
echo "Scanning files and directories..."
|
||||||
|
if command -v fd >/dev/null 2>&1; then
|
||||||
|
# List files and directories using fd (can handle both files and dirs)
|
||||||
|
files=$(fd --type f --type d . "$MOUNT_POINT" | sort)
|
||||||
|
else
|
||||||
|
# Fall back to find if fd is not available
|
||||||
|
files=$(find "$MOUNT_POINT" -type f -o -type d | sort)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$files" ]; then
|
||||||
|
echo "No files or directories found in archive."
|
||||||
|
borg umount "$MOUNT_POINT"
|
||||||
|
rm -rf "$MOUNT_POINT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- HIERARCHICAL FZF FILE/DIRECTORY SELECTION (REVERSED) ---
|
||||||
|
# We reverse the order of files to display the latest (newest) files/folders at the top.
|
||||||
|
selected_files=$(printf '%s\n' "$files" | sed "s|$MOUNT_POINT/||" | tac | fzf \
|
||||||
|
--multi \
|
||||||
|
--height=50% \
|
||||||
|
--border \
|
||||||
|
--prompt="Select files or directories to restore: " \
|
||||||
|
--preview "tree -C -L 5 $MOUNT_POINT/$(dirname {})" \
|
||||||
|
--preview-window=right:50% \
|
||||||
|
--delimiter='/' \
|
||||||
|
--with-nth=1..)
|
||||||
|
|
||||||
|
if [ -z "$selected_files" ]; then
|
||||||
|
echo "No files or directories selected. Exiting."
|
||||||
|
borg umount "$MOUNT_POINT"
|
||||||
|
rm -rf "$MOUNT_POINT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- SUMMARY OF SELECTED FILES/DIRECTORIES ---
|
||||||
|
echo "Selected files and directories:"
|
||||||
|
for file in $selected_files; do
|
||||||
|
echo " $file"
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- OPTIONS MENU (concise) ---
|
||||||
|
# Default to option 1 if no input is given
|
||||||
|
echo "Select restore destination: 1) Restore to ./${selected}_restore 2) Restore to original dirs 3) Quit"
|
||||||
|
read -p "Enter your choice (1/2/3) [default: 1]: " choice
|
||||||
|
# Default to option 1 if user presses Enter without providing input
|
||||||
|
choice="${choice:-1}"
|
||||||
|
|
||||||
|
# --- SET RESTORE DESTINATION BASED ON USER CHOICE ---
|
||||||
|
case "$choice" in
|
||||||
|
1)
|
||||||
|
DEST="./${selected}_restore"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
DEST="$MOUNT_POINT"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
echo "Quitting. No files restored."
|
||||||
|
borg umount "$MOUNT_POINT"
|
||||||
|
rm -rf "$MOUNT_POINT"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid choice. Exiting."
|
||||||
|
borg umount "$MOUNT_POINT"
|
||||||
|
rm -rf "$MOUNT_POINT"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
mkdir -p "$DEST"
|
||||||
|
|
||||||
|
# --- RESTORE FILES AND DIRECTORIES ---
|
||||||
|
echo "Restoring selected files and directories..."
|
||||||
|
while IFS= read -r file; do
|
||||||
|
# Path is already stripped of /tmp, so no need for further modification
|
||||||
|
dest_path="$DEST/$file"
|
||||||
|
mkdir -p "$(dirname "$dest_path")"
|
||||||
|
# If it's a directory, we use cp -r to ensure the directory structure is restored
|
||||||
|
if [ -d "$MOUNT_POINT/$file" ]; then
|
||||||
|
cp -r "$MOUNT_POINT/$file" "$dest_path"
|
||||||
|
else
|
||||||
|
cp -a "$MOUNT_POINT/$file" "$dest_path"
|
||||||
|
fi
|
||||||
|
echo "Restored: $file"
|
||||||
|
done <<< "$selected_files"
|
||||||
|
|
||||||
|
# --- CLEANUP ---
|
||||||
|
borg umount "$MOUNT_POINT"
|
||||||
|
rm -rf "$MOUNT_POINT"
|
||||||
|
echo "Restore complete."
|
||||||
|
|
||||||
64
bin/backup_browse_fzf.sh
Executable file
64
bin/backup_browse_fzf.sh
Executable file
@@ -0,0 +1,64 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# borg-browser.sh — fzf-based Borg archive browser with passphrase prompt
|
||||||
|
|
||||||
|
[ "$EUID" -ne 0 ] && { echo "Please run as root."; exec sudo "$0" "$@"; }
|
||||||
|
|
||||||
|
REPO="/holocron/backups"
|
||||||
|
|
||||||
|
# Prompt once for Borg passphrase
|
||||||
|
read -rs -p "Borg passphrase: " BORG_PASSPHRASE
|
||||||
|
echo
|
||||||
|
export BORG_PASSPHRASE
|
||||||
|
|
||||||
|
# Pick an archive
|
||||||
|
ARCHIVE=$(borg list --short "$REPO" | fzf --prompt="Select archive: ") || {
|
||||||
|
unset BORG_PASSPHRASE
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
[ -z "$ARCHIVE" ] && { unset BORG_PASSPHRASE; exit; }
|
||||||
|
|
||||||
|
# Function to browse directories hierarchically
|
||||||
|
browse_borg_dir() {
|
||||||
|
local prefix="$1"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
# Get immediate children of the current path
|
||||||
|
ITEMS=$(borg list --format='{path}{NL}' "$REPO::$ARCHIVE" \
|
||||||
|
| awk -v p="$prefix" -F/ '
|
||||||
|
BEGIN{n=split(p,a,"/")}
|
||||||
|
index($0,p)==1 && NF>n {
|
||||||
|
if (NF==n+1) print $NF;
|
||||||
|
else print $(n+1)"/";
|
||||||
|
}' \
|
||||||
|
| sort -u)
|
||||||
|
|
||||||
|
[ -z "$ITEMS" ] && { echo "No items found in $prefix"; return; }
|
||||||
|
|
||||||
|
SELECTION=$(echo -e "../\n$ITEMS" | fzf --prompt="${prefix:-/}> ")
|
||||||
|
case "$SELECTION" in
|
||||||
|
"../")
|
||||||
|
prefix="${prefix%/*}"
|
||||||
|
prefix="${prefix%/}"
|
||||||
|
;;
|
||||||
|
"")
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
*/)
|
||||||
|
prefix="${prefix:+$prefix/}${SELECTION%/}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
local fullpath="${prefix:+$prefix/}$SELECTION"
|
||||||
|
echo "Selected file: $fullpath"
|
||||||
|
read -rp "Extract it here? [y/N]: " yn
|
||||||
|
if [[ $yn =~ ^[Yy]$ ]]; then
|
||||||
|
borg extract "$REPO::$ARCHIVE" "$fullpath"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
browse_borg_dir ""
|
||||||
|
unset BORG_PASSPHRASE
|
||||||
|
|
||||||
18
flake.lock
generated
18
flake.lock
generated
@@ -40,7 +40,8 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"sops-nix": "sops-nix"
|
"sops-nix": "sops-nix",
|
||||||
|
"vpn-confinement": "vpn-confinement"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sops-nix": {
|
"sops-nix": {
|
||||||
@@ -62,6 +63,21 @@
|
|||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"vpn-confinement": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1759956062,
|
||||||
|
"narHash": "sha256-NUZu0Rb0fwUjfdp51zMm0xM3lcK8Kw4c97LLog7+JjA=",
|
||||||
|
"owner": "Maroka-chan",
|
||||||
|
"repo": "VPN-Confinement",
|
||||||
|
"rev": "fabe7247b720b5eb4c3c053e24a2b3b70e64c52b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "Maroka-chan",
|
||||||
|
"repo": "VPN-Confinement",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# flake for blakes nixos config
|
# flake for blakes nixos config
|
||||||
# define new devices in outputs
|
# define new devices in outputs
|
||||||
# generation: 116 current 2025-10-08 19:06:36 25.05.20251006.20c4598 6.12.50 *
|
# generation: 147 current 2025-10-09 01:08:24 25.05.20251006.20c4598 6.12.50 *
|
||||||
{
|
{
|
||||||
description = "blakes nix config";
|
description = "blakes nix config";
|
||||||
inputs = {
|
inputs = {
|
||||||
@@ -13,9 +13,11 @@
|
|||||||
url = "github:Mic92/sops-nix";
|
url = "github:Mic92/sops-nix";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
vpn-confinement = {
|
||||||
|
url = "github:Maroka-chan/VPN-Confinement";
|
||||||
};
|
};
|
||||||
|
};
|
||||||
outputs = { self, nixpkgs, home-manager, ... }@inputs:
|
outputs = { self, nixpkgs, home-manager, vpn-confinement, ... }@inputs:
|
||||||
let
|
let
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
@@ -27,6 +29,7 @@
|
|||||||
modules = [
|
modules = [
|
||||||
./hosts/snowbelle/configuration.nix
|
./hosts/snowbelle/configuration.nix
|
||||||
inputs.home-manager.nixosModules.default
|
inputs.home-manager.nixosModules.default
|
||||||
|
vpn-confinement.nixosModules.default
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
vaniville = nixpkgs.lib.nixosSystem {
|
vaniville = nixpkgs.lib.nixosSystem {
|
||||||
|
|||||||
@@ -18,8 +18,9 @@
|
|||||||
docker.enable = true;
|
docker.enable = true;
|
||||||
syncthing.enable = true;
|
syncthing.enable = true;
|
||||||
tailscale.enable = true;
|
tailscale.enable = true;
|
||||||
vpns.enable = true;
|
vpns.enable = false;
|
||||||
vpns.wg_mex = false;
|
vpns.wg_mex = false;
|
||||||
|
vpn-confinement.enable = false;
|
||||||
nvidia.enable = true;
|
nvidia.enable = true;
|
||||||
};
|
};
|
||||||
homelab = {
|
homelab = {
|
||||||
@@ -41,47 +42,69 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# enable users
|
# configure users & groups
|
||||||
users = {
|
users = {
|
||||||
blake.enable = true;
|
blake.enable = true; # main user, home manager
|
||||||
|
groups.media = { gid = 700; }; # user for share permissions with mediastack
|
||||||
|
defaultUserShell = pkgs.zsh; # the goat
|
||||||
};
|
};
|
||||||
|
|
||||||
users.groups.media = { gid = 700; };
|
# boot (systemd is going on me)
|
||||||
|
boot.loader.systemd-boot.enable = true; # systemd your pretty cool ya know
|
||||||
# testing!
|
|
||||||
#boot.kernelParams = [ "quiet" ]; # remove splash
|
|
||||||
#boot.plymouth.enable = true;
|
|
||||||
boot.initrd.systemd.enable = true; # optional, for nicer initrd logs
|
|
||||||
|
|
||||||
|
|
||||||
# use the systemd-boot EFI boot loader.
|
|
||||||
boot.loader.systemd-boot.enable = true;
|
|
||||||
boot.loader.efi.canTouchEfiVariables = true;
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
boot.initrd.systemd.enable = true; # better logging
|
||||||
|
|
||||||
# setup hostname and networking stack
|
# setup hostname and networking stack
|
||||||
networking.hostName = "snowbelle"; # Define your hostname.
|
services.resolved = {
|
||||||
networking.networkmanager.enable = true; # Easiest to use and most distros use this by default.
|
enable = true;
|
||||||
networking.hostId = "3e6e7055";
|
fallbackDns = [ "1.1.1.1" "9.9.9.9" ];
|
||||||
|
dnsovertls = "opportunistic";
|
||||||
|
};
|
||||||
|
networking = {
|
||||||
|
hostName = "snowbelle"; # hostname
|
||||||
|
hostId = "3e6e7055"; # zfs wants this
|
||||||
|
networkmanager = {
|
||||||
|
enable = true; # the goat
|
||||||
|
dns = "systemd-resolved"; # the backup dancer!
|
||||||
|
ensureProfiles.profiles = {
|
||||||
|
vpn = {
|
||||||
|
ethernet.mac-address = "7a:e4:07:8d:22:76";
|
||||||
|
connection.type = "vlan";
|
||||||
|
connection.id = "vpn";
|
||||||
|
connection.interface-name = "enp89s0.69"; # or just "vpn-vlan"
|
||||||
|
vlan.interface-name = "enp89s0.69"; # or just "vpn-vlan"
|
||||||
|
vlan.parent = "enp89s0";
|
||||||
|
vlan.id = 69;
|
||||||
|
#ipv4.dns = "9.9.9.9";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
# set timezone
|
# set timezone
|
||||||
time.timeZone = "America/Chicago";
|
time.timeZone = "America/Chicago";
|
||||||
|
|
||||||
# define shell
|
# define shell
|
||||||
programs.zsh.enable = true;
|
programs.zsh.enable = true;
|
||||||
users.defaultUserShell = pkgs.zsh;
|
|
||||||
|
|
||||||
# package install list
|
# package install list
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
vim
|
git
|
||||||
lf
|
age
|
||||||
rsync
|
rsync
|
||||||
wget
|
wget
|
||||||
git
|
curl
|
||||||
iptables
|
fzf
|
||||||
nettools
|
fd
|
||||||
neofetch
|
tree
|
||||||
|
vim
|
||||||
|
lf
|
||||||
btop
|
btop
|
||||||
age
|
neofetch
|
||||||
|
usbutils
|
||||||
|
inetutils
|
||||||
|
iptables
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ let
|
|||||||
cfg = config.modules.services.prowlarr;
|
cfg = config.modules.services.prowlarr;
|
||||||
ids = 2004;
|
ids = 2004;
|
||||||
default_port = 9696;
|
default_port = 9696;
|
||||||
data_dir = "/var/lib/prowlarr";
|
data_dir = "/var/lib/private";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.modules.services.prowlarr = {
|
options.modules.services.prowlarr = {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ in
|
|||||||
# internal reverse proxy entry
|
# internal reverse proxy entry
|
||||||
services.nginx.virtualHosts."jellyfin.snowbelle.lan" = {
|
services.nginx.virtualHosts."jellyfin.snowbelle.lan" = {
|
||||||
enableACME = false;
|
enableACME = false;
|
||||||
forceSSL = false;
|
forceSSL = true;
|
||||||
sslCertificate = config.sops.secrets."ssl_blakedheld_crt".path;
|
sslCertificate = config.sops.secrets."ssl_blakedheld_crt".path;
|
||||||
sslCertificateKey = config.sops.secrets."ssl_blakedheld_key".path;
|
sslCertificateKey = config.sops.secrets."ssl_blakedheld_key".path;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.modules.services.qbittorrent;
|
cfg = config.modules.services.qbittorrent;
|
||||||
ids = 2003;
|
|
||||||
default_port = 8080;
|
default_port = 8080;
|
||||||
data_dir = "/var/lib/qBittorrent";
|
data_dir = "/var/lib/qBittorrent";
|
||||||
|
ids = 2003;
|
||||||
|
vpn_inf = "enp89s0.69"; # vpn interfacve
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.modules.services.qbittorrent = {
|
options.modules.services.qbittorrent = {
|
||||||
@@ -49,21 +50,43 @@ in
|
|||||||
profileDir = data_dir;
|
profileDir = data_dir;
|
||||||
webuiPort = cfg.port;
|
webuiPort = cfg.port;
|
||||||
# torrentingPort = cfg.port;
|
# torrentingPort = cfg.port;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# override umask to make permissions work out
|
# override umask to make permissions work out
|
||||||
systemd.services.qbittorrent.serviceConfig = {
|
systemd.services.qbittorrent = {
|
||||||
|
serviceConfig = {
|
||||||
UMask = lib.mkForce "0007";
|
UMask = lib.mkForce "0007";
|
||||||
# User = "qbittorrent";
|
|
||||||
# Group = "qbittorrent";
|
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.extraCommands = ''
|
||||||
|
iptables -F QBIT
|
||||||
|
iptables -X QBIT
|
||||||
|
iptables -N QBIT
|
||||||
|
iptables -A OUTPUT -m owner --uid-owner ${toString ids} -j QBIT
|
||||||
|
iptables -A QBIT -o ${vpn_inf} -j ACCEPT
|
||||||
|
iptables -A QBIT -p udp --dport 53 -o ${vpn_inf} -j ACCEPT
|
||||||
|
iptables -A QBIT -p tcp --dport 53 -o ${vpn_inf} -j ACCEPT
|
||||||
|
iptables -A QBIT -p tcp -d 127.0.0.1 --dport ${toString cfg.port} -j ACCEPT
|
||||||
|
iptables -A QBIT -p tcp -o enp89s0 -d 10.0.0.0/8 --dport ${toString cfg.port} -j ACCEPT
|
||||||
|
iptables -A QBIT -j DROP
|
||||||
|
'';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# # add systemd service to VPN network namespace
|
||||||
|
# vpnConfinement = {
|
||||||
|
# enable = true;
|
||||||
|
# vpnNamespace = "wgmex";
|
||||||
|
# };
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
# # open firewall
|
# # open firewall
|
||||||
# networking.firewall.allowedTCPPorts = [ cfg.port ];
|
# networking.firewall.allowedTCPPorts = [ cfg.port ];
|
||||||
|
|
||||||
# internal reverse proxy entry
|
# internal reverse proxy entry
|
||||||
services.nginx.virtualHosts.".snowbelle.lan" = {
|
services.nginx.virtualHosts."qbit.snowbelle.lan" = {
|
||||||
enableACME = false;
|
enableACME = false;
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
sslCertificate = config.sops.secrets."ssl_blakedheld_crt".path;
|
sslCertificate = config.sops.secrets."ssl_blakedheld_crt".path;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
./docker.nix
|
./docker.nix
|
||||||
./tailscale.nix
|
./tailscale.nix
|
||||||
./vpns.nix
|
./vpns.nix
|
||||||
|
./vpn-confinement.nix
|
||||||
./syncthing.nix
|
./syncthing.nix
|
||||||
./nvidia.nix
|
./nvidia.nix
|
||||||
];
|
];
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
modules.system.docker.enable = lib.mkDefault false;
|
modules.system.docker.enable = lib.mkDefault false;
|
||||||
modules.system.tailscale.enable = lib.mkDefault true;
|
modules.system.tailscale.enable = lib.mkDefault true;
|
||||||
modules.system.vpns.enable = lib.mkDefault false;
|
modules.system.vpns.enable = lib.mkDefault false;
|
||||||
|
modules.system.vpn-confinement.enable = lib.mkDefault false;
|
||||||
modules.system.syncthing.enable = lib.mkDefault false;
|
modules.system.syncthing.enable = lib.mkDefault false;
|
||||||
modules.system.nvidia.enable = lib.mkDefault false;
|
modules.system.nvidia.enable = lib.mkDefault false;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,12 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
useRoutingFeatures = "both";
|
useRoutingFeatures = "both";
|
||||||
authKeyFile = authkey_file;
|
authKeyFile = authkey_file;
|
||||||
|
extraUpFlags = [
|
||||||
|
"--accept-routes=false" # true is equilivant to useRoutingFeatures = "client" (breaks shit)
|
||||||
|
"--accept-dns=true" # explicitly allow resolved
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# declare authkey secrets
|
# declare authkey secrets
|
||||||
sops.secrets = {
|
sops.secrets = {
|
||||||
"tailscale_authkey" = {
|
"tailscale_authkey" = {
|
||||||
|
|||||||
41
modules/system/vpn-confinement.nix
Normal file
41
modules/system/vpn-confinement.nix
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{ pkgs, config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.modules.system.vpn-confinement;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.modules.system.vpn-confinement = {
|
||||||
|
enable = lib.mkEnableOption "enables vpn-confinement";
|
||||||
|
|
||||||
|
# toggle for mullvad mexico w/ openvpn
|
||||||
|
vpncon_mex = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "enable pia vpn to mexico using openvpn";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
|
# Define VPN network namespace
|
||||||
|
vpnNamespaces.wgmex = {
|
||||||
|
enable = true;
|
||||||
|
wireguardConfigFile = "/etc/wireguard/mullvad.conf";
|
||||||
|
accessibleFrom = [
|
||||||
|
"10.0.0.0/8"
|
||||||
|
];
|
||||||
|
portMappings = [
|
||||||
|
{ from = 7103; to = 7103; }
|
||||||
|
];
|
||||||
|
openVPNPorts = [{
|
||||||
|
port = 51820;
|
||||||
|
protocol = "both";
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
# secrets only if VPN is enabled
|
||||||
|
sops.secrets = {
|
||||||
|
"vpncon_mex_config" = { owner = "root"; group = "root"; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -14,6 +14,8 @@ pia_auth: ENC[AES256_GCM,data:rwAu4f5XVS4v4FCLj2zXAegIZeRPLIzUVv6TCrdfg9RGSDJYHg
|
|||||||
openvpn_pia_mexico_config: ENC[AES256_GCM,data:59HQ3OZ0QKq92jI=,iv:DZTNvfi6kLXG7dsNkPcXUmXhAG2UdPZBy/L9eWNmRdE=,tag:ndxDDQNL2z1fjxFfU2VRwQ==,type:str]
|
openvpn_pia_mexico_config: ENC[AES256_GCM,data:59HQ3OZ0QKq92jI=,iv:DZTNvfi6kLXG7dsNkPcXUmXhAG2UdPZBy/L9eWNmRdE=,tag:ndxDDQNL2z1fjxFfU2VRwQ==,type:str]
|
||||||
#ENC[AES256_GCM,data:mbIgMJBhL8nWJzl8q2dFL8XtO1Xa1Q==,iv:caYHYp1boK9wRgCcQe40HTWT/HxAIvYe+HyaruI53Vc=,tag:S6wowhAHObEcs7z8FimZ1g==,type:comment]
|
#ENC[AES256_GCM,data:mbIgMJBhL8nWJzl8q2dFL8XtO1Xa1Q==,iv:caYHYp1boK9wRgCcQe40HTWT/HxAIvYe+HyaruI53Vc=,tag:S6wowhAHObEcs7z8FimZ1g==,type:comment]
|
||||||
wg_mex_key: ENC[AES256_GCM,data:vxDXixo6X6D33+p21L4hB0/yCH+TvMHZl991BkRsE/jdz7rzZuJF+zI7h+Q=,iv:8WR+feHXNUcat8DB2wY7wpos+P7TzgRF7rFD0fYosjY=,tag:p9b9ck0/VZjyLxtHut3n5Q==,type:str]
|
wg_mex_key: ENC[AES256_GCM,data:vxDXixo6X6D33+p21L4hB0/yCH+TvMHZl991BkRsE/jdz7rzZuJF+zI7h+Q=,iv:8WR+feHXNUcat8DB2wY7wpos+P7TzgRF7rFD0fYosjY=,tag:p9b9ck0/VZjyLxtHut3n5Q==,type:str]
|
||||||
|
#ENC[AES256_GCM,data:3ATkokBKeOp97uORzaePROrKKfG94ic=,iv:MNJRh6Vrso1heqNUJc0M4xGNcMLGwcF9IzoiQ5+SS+g=,tag:xj8Actwkirvq4GE+Ly1M9w==,type:comment]
|
||||||
|
vpncon_mex_config: ENC[AES256_GCM,data:4i356X97sBoRliskmh5ewcEwZHkpo37IhPcemKVdWJgWFWtA+AhTeEo4KQ3dRA1H/n8VjVX7CKZKPDxpmHfcUlnTLT0agtOjjyjf60kWoL8noJqcbDB4wGiYT910rPToVnYMFk0H2lerYp+/n2bhg8BHxn++VlPOOZsgla4El+FNXUqhScpAawySPSF36ocdRJ3r3DuflIhnTBXxSZukMf9Ux1uaFldSG7KasCQlStKy9O2Odd2AvAuGXOHch5KecRPT3WnonQ8oDJpuxbeaosLmtJKHL9oeXHPId2Unc1GNoOpnDC3Y/xGnrPb9WFXWYOSQ/1A3mNKwnVq0FEhluVbqodES4PVIlCS0koiQJq15P15G2z0jO+OhAQrRI5vn3Fki5A==,iv:tQvTpzhl7F7niigAXl61FMHbg6QqI2R7yGD/C2lwOR4=,tag:c+CVLd6lGrAfm38pFXOXTw==,type:str]
|
||||||
#ENC[AES256_GCM,data:CO5nrcDbgymnEmCvuTexOBEMncuNM5lQ,iv:6HrxqSN6e7ODuz09MIFgPbIqDCKQySRDaKk5Wdu4HoQ=,tag:JBRjZeEdOg+trohfanO6Mg==,type:comment]
|
#ENC[AES256_GCM,data:CO5nrcDbgymnEmCvuTexOBEMncuNM5lQ,iv:6HrxqSN6e7ODuz09MIFgPbIqDCKQySRDaKk5Wdu4HoQ=,tag:JBRjZeEdOg+trohfanO6Mg==,type:comment]
|
||||||
vaultwarden_admin_token: ENC[AES256_GCM,data:G1v3N064ci0Fw5EtTzaryailWpsv6f4w6eoHp2vjXIBtIlScdQk1Q0W+eDNRk8Wr2C3ysTXQNbyYismNsls+jeS3W+YqkKL4fnh3a5UTzQrMqvaH11n3ak0X9R9vmt+ZJXBrUrAOKJ6RPHJJSWenhjDB77kwEdQ=,iv:f8X+x/AdmZ3b3dtcSFrxGgA2tCgDRpgddjlVu3mdCmM=,tag:c0MXljVvhwOdvrb/8hWlsQ==,type:str]
|
vaultwarden_admin_token: ENC[AES256_GCM,data:G1v3N064ci0Fw5EtTzaryailWpsv6f4w6eoHp2vjXIBtIlScdQk1Q0W+eDNRk8Wr2C3ysTXQNbyYismNsls+jeS3W+YqkKL4fnh3a5UTzQrMqvaH11n3ak0X9R9vmt+ZJXBrUrAOKJ6RPHJJSWenhjDB77kwEdQ=,iv:f8X+x/AdmZ3b3dtcSFrxGgA2tCgDRpgddjlVu3mdCmM=,tag:c0MXljVvhwOdvrb/8hWlsQ==,type:str]
|
||||||
#ENC[AES256_GCM,data:2ESzSsQZqKdjD7OXN8ZPThj6g9acJREe,iv:aDFPB0vs8NNo8ExLcJw7qtQvWbCb1XK6TJrHSK86qss=,tag:z+dypHAGUjEXP7Y9MHYWwg==,type:comment]
|
#ENC[AES256_GCM,data:2ESzSsQZqKdjD7OXN8ZPThj6g9acJREe,iv:aDFPB0vs8NNo8ExLcJw7qtQvWbCb1XK6TJrHSK86qss=,tag:z+dypHAGUjEXP7Y9MHYWwg==,type:comment]
|
||||||
@@ -29,7 +31,7 @@ sops:
|
|||||||
U0tmdFBuZnJES3piOTZNV0VKQmQ0eVUKCWRQ/flLzmpC64WyLoipklZBmrkpYiUg
|
U0tmdFBuZnJES3piOTZNV0VKQmQ0eVUKCWRQ/flLzmpC64WyLoipklZBmrkpYiUg
|
||||||
PRu+itNolpPTHm96pe+P93g2iP0wgekG0cX21wkiU2xaLF3dY2FEIA==
|
PRu+itNolpPTHm96pe+P93g2iP0wgekG0cX21wkiU2xaLF3dY2FEIA==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2025-10-08T20:46:50Z"
|
lastmodified: "2025-10-09T00:57:39Z"
|
||||||
mac: ENC[AES256_GCM,data:kSWpiorgrx4Ohv/ZpUCKuBy+g3VZ95UjaOeotUwXJzao3qbHHAKIRLCJnlJPjMDyT3aZc8AF3urQunl65LDHYAisTV1LxTAeFSsWm4xkJ5DcyhvTHh1yxa+G9lGZ6mBQK60Hg92+fqwS43ObYz8hwoVeeKXc0ZSwDqI5d8gSF9o=,iv:gVonEcRQTupdLEYgAfgI10L86h6q+PFdgpLHNsLHB/8=,tag:Rd2nlookzmUc0ZWnC/f1Dg==,type:str]
|
mac: ENC[AES256_GCM,data:NCsVDJnzb/x6/InOrE7Aco1bEfbcOA0t5mEQOO/tSM4uj5QjDeCTUyfzfK0A7LHdQSMvRpZLZuz7xDg/WA/QLe0F/CdA1h5HJucpop4NWN/bnJrVNIcik/YlvB6xSWojimZF9sbWZQQb2lPsn3GWt9wIHIHWlBhjIMfHHpLANq8=,iv:yQgpRv+xCvKcBYCyVac66egptSbF/8vi4TtQ5vL5xWQ=,tag:JdsI0yAecTnNO9UiE2IEwQ==,type:str]
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.11.0
|
version: 3.11.0
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ alias ds='du -hs'
|
|||||||
|
|
||||||
# shortcuts
|
# shortcuts
|
||||||
alias vswap='cd ~/.local/state/nvim/swap'
|
alias vswap='cd ~/.local/state/nvim/swap'
|
||||||
|
alias rswap='rm ~/.local/state/nvim/swap/*'
|
||||||
alias tn='lf ~/documents/holocron/notes/tech'
|
alias tn='lf ~/documents/holocron/notes/tech'
|
||||||
alias nhc='lf ~/documents/holocron/work/nhc'
|
alias nhc='lf ~/documents/holocron/work/nhc'
|
||||||
alias diary='cd ~/documents/holocron/notes/journal/diary'
|
alias diary='cd ~/documents/holocron/notes/journal/diary'
|
||||||
@@ -65,6 +66,7 @@ alias egrep='egrep --color=auto'
|
|||||||
# scripts
|
# scripts
|
||||||
alias rebuild='sh ~/.nix/bin/rebuild.sh'
|
alias rebuild='sh ~/.nix/bin/rebuild.sh'
|
||||||
alias perms='sudo sh ~/.nix/bin/perms.sh'
|
alias perms='sudo sh ~/.nix/bin/perms.sh'
|
||||||
|
alias bb='sudo sh ~/.nix/bin/backup_browse.sh'
|
||||||
|
|
||||||
# tools
|
# tools
|
||||||
alias v='nvim'
|
alias v='nvim'
|
||||||
|
|||||||
Reference in New Issue
Block a user