Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/scripts/dev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ source "$SCRIPT_DIR/utils.sh"

update_apt_cache

dotfiles_root="$PROJECT_ROOT/src/dotfiles"
dotfiles_config_root="$dotfiles_root/config"
dotfiles_home_root="$dotfiles_root/home"

# Node.js + npm from NodeSource (https://github.com/nodesource/distributions)
NODE_MAJOR=24
nodesource_key="/etc/apt/keyrings/nodesource.gpg"
Expand Down Expand Up @@ -84,10 +88,10 @@ neovim_packages=(
install_apt_packages "${neovim_packages[@]}"

# Dotfiles: XDG app configs (Neovim lazy.nvim bootstraps in config/nvim/init.lua — no Packer)
dotfiles_config_root="$PROJECT_ROOT/src/dotfiles/config"
xdg_config_home="${XDG_CONFIG_HOME:-$HOME/.config}"
ensure_directory "$xdg_config_home"
if [[ -d "$dotfiles_config_root" ]]; then
shopt -s dotglob nullglob
for entry in "$dotfiles_config_root"/*; do
[[ -e "$entry" ]] || continue
name=$(basename "$entry")
Expand All @@ -96,6 +100,7 @@ if [[ -d "$dotfiles_config_root" ]]; then
cp -r "$entry" "$dest" 2>>"$ERROR_LOG_FILE" || true
fi
done
shopt -u dotglob nullglob
fi

dev_tools=(
Expand Down Expand Up @@ -129,7 +134,7 @@ if [[ ! -f "$HOME/.gitconfig" ]]; then
fi

vim_config_file="$HOME/.vimrc"
vim_source_file="$PROJECT_ROOT/src/dotfiles/home/.vimrc"
vim_source_file="$dotfiles_home_root/.vimrc"
if [[ ! -f "$vim_config_file" && -f "$vim_source_file" ]]; then
copy_file_safe "$vim_source_file" "$vim_config_file"
copy_file_safe "$vim_source_file" "$vim_config_file"
fi
85 changes: 80 additions & 5 deletions src/scripts/security.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,88 @@ if [[ -f "$protonvpn_deb" ]] && [[ -s "$protonvpn_deb" ]]; then
fi
fi

# Proton Pass desktop .deb — canonical URLs live in version.json (linked from
# https://www.proton.me/support/set-up-proton-pass-linux). Legacy ProtonPass.deb
# URLs often redirect or no longer serve the package bytes reliably.
proton_pass_deb="$TEMP_DIR/proton-pass.deb"
download_file_safe "https://proton.me/download/PassDesktop/linux/x64/ProtonPass.deb" "$proton_pass_deb"
if [[ -f "$proton_pass_deb" ]] && [[ -s "$proton_pass_deb" ]]; then
if file "$proton_pass_deb" 2>/dev/null | grep -q "Debian binary"; then
sudo dpkg -i "$proton_pass_deb" 2>>"$ERROR_LOG_FILE" || true
sudo apt-get install -f -y 2>>"$ERROR_LOG_FILE" || true
proton_pass_version_json_urls=(
"https://www.proton.me/download/PassDesktop/linux/x64/version.json"
"https://proton.me/download/PassDesktop/linux/x64/version.json"
)

proton_pass_is_valid_deb() {
local candidate="$1"
[[ -s "$candidate" ]] || return 1
if command -v dpkg-deb >/dev/null 2>&1 && dpkg-deb -I "$candidate" >/dev/null 2>&1; then
return 0
fi
# Fallback when dpkg-deb is unavailable: Debian packages are usually ar(5) archives.
[[ "$(head -c 8 "$candidate" 2>/dev/null | tr -d '\0')" == $'!<arch>\n' ]] || \
[[ "$(head -c 7 "$candidate" 2>/dev/null | tr -d '\0')" == '!<arch>' ]]
}

proton_pass_resolve_latest_stable_deb_url() {
local json_path="$TEMP_DIR/proton-pass-version.json"
local base_url deb_url=""
for base_url in "${proton_pass_version_json_urls[@]}"; do
rm -f "$json_path" 2>/dev/null || true
if ! curl -fsSL --connect-timeout 30 --max-time 120 --retry 3 --retry-delay 2 \
-A "Mozilla/5.0 (X11; Linux x86_64)" \
"$base_url" -o "$json_path" 2>>"$ERROR_LOG_FILE"; then
continue
fi
[[ -s "$json_path" ]] || continue
if command -v python3 >/dev/null 2>&1; then
deb_url=$(python3 -c '
import json, sys
path = sys.argv[1]
with open(path, encoding="utf-8") as fp:
data = json.load(fp)
for rel in data.get("Releases", []):
if rel.get("CategoryName") != "Stable":
continue
for item in rel.get("File", []):
url = (item.get("Url") or "").strip()
if not url.endswith(".deb"):
continue
ident = item.get("Identifier") or ""
if "Debian" in ident or ident.startswith(".deb"):
print(url)
sys.exit(0)
sys.exit(1)
' "$json_path" 2>>"$ERROR_LOG_FILE") || deb_url=""
[[ -n "$deb_url" ]] && printf '%s' "$deb_url" && return 0
fi
done
return 1
}

proton_pass_urls=()
if resolved=$(proton_pass_resolve_latest_stable_deb_url); then
proton_pass_urls+=("$resolved")
fi
proton_pass_urls+=(
"https://proton.me/download/PassDesktop/linux/x64/ProtonPass.deb"
"https://www.proton.me/download/PassDesktop/linux/x64/ProtonPass.deb"
)

proton_pass_downloaded=0
for proton_pass_url in "${proton_pass_urls[@]}"; do
[[ -n "$proton_pass_url" ]] || continue
rm -f "$proton_pass_deb" 2>/dev/null || true
if curl -fsSL --connect-timeout 30 --max-time 600 --retry 3 --retry-delay 2 --retry-all-errors \
-A "Mozilla/5.0 (X11; Linux x86_64)" \
"$proton_pass_url" -o "$proton_pass_deb" 2>>"$ERROR_LOG_FILE" && proton_pass_is_valid_deb "$proton_pass_deb"; then
proton_pass_downloaded=1
break
fi
done

if [[ "$proton_pass_downloaded" -eq 1 ]]; then
sudo dpkg -i "$proton_pass_deb" 2>>"$ERROR_LOG_FILE" || true
sudo apt-get install -f -y 2>>"$ERROR_LOG_FILE" || true
else
log_error "Failed to download a valid Proton Pass Debian package"
fi

proton_pass_cli="$TEMP_DIR/proton-pass-cli"
Expand Down
21 changes: 17 additions & 4 deletions src/scripts/shell.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ source "$SCRIPT_DIR/utils.sh"

update_apt_cache

dotfiles_root="$PROJECT_ROOT/src/dotfiles"
dotfiles_home_root="$dotfiles_root/home"

shell_packages=(
"zsh"
"tmux"
Expand Down Expand Up @@ -76,22 +79,32 @@ fi
# Ghostty and other XDG configs under ~/.config are installed from src/dotfiles/config/ in dev.sh

tmux_config_file="$HOME/.tmux.conf"
tmux_source_file="$PROJECT_ROOT/src/dotfiles/home/.tmux.conf"
tmux_source_file="$dotfiles_home_root/.tmux.conf"

if [[ ! -f "$tmux_config_file" && -f "$tmux_source_file" ]]; then
copy_file_safe "$tmux_source_file" "$tmux_config_file"
fi

zsh_config_file="$HOME/.zshrc"
zsh_source_file="$PROJECT_ROOT/src/dotfiles/home/.zshrc"
zsh_source_file="$dotfiles_home_root/.zshrc"

if [[ ! -f "$zsh_config_file" && -f "$zsh_source_file" ]]; then
copy_file_safe "$zsh_source_file" "$zsh_config_file"
printf '%s\n' "$PROJECT_ROOT/src/dotfiles" >"$HOME/.dotfiles_path" 2>>"$ERROR_LOG_FILE" || true
fi

# Keep the zsh DOTFILES cache in sync so home/.zshrc can source home/zsh/<os>.zsh.
if [[ -d "$dotfiles_home_root/zsh" ]]; then
current_dotfiles_path=""
if [[ -f "$HOME/.dotfiles_path" ]]; then
IFS= read -r current_dotfiles_path <"$HOME/.dotfiles_path" || true
fi
if [[ "$current_dotfiles_path" != "$dotfiles_root" ]]; then
printf '%s\n' "$dotfiles_root" >"$HOME/.dotfiles_path" 2>>"$ERROR_LOG_FILE" || true
fi
fi

bashrc_config_file="$HOME/.bashrc"
bashrc_source_file="$PROJECT_ROOT/src/dotfiles/home/.bashrc"
bashrc_source_file="$dotfiles_home_root/.bashrc"
if [[ ! -f "$bashrc_config_file" && -f "$bashrc_source_file" ]]; then
copy_file_safe "$bashrc_source_file" "$bashrc_config_file"
fi
Expand Down
Loading