fix: address critical shell injection and add Fish shell support

Fixes from second PR #8 review:

Critical fixes:
- Show how to actually USE $ESCAPED_PATH in final command (not just escape it)
- Add Fish shell function syntax support (uses functions not aliases)
- Add existing alias/function replacement with user confirmation
- Reorder backup timing (after user confirms, before modifying)

Improvements:
- Example output now shows path with spaces to demonstrate escaping
- Added Fish shell syntax explanation section
- Added security considerations section
- Updated "How It Works" for both Bash/Zsh and Fish
- Clear step-by-step command generation with $ESCAPED_PATH

This ensures the shell injection vulnerability is truly fixed by showing
explicit usage of the escaped path variable in the final command generation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Noah Brier
2025-10-07 12:33:42 -04:00
co-authored by Claude
parent eddbf61f92
commit 6c6a567590
+142 -14
View File
@@ -121,30 +121,74 @@ echo "📝 Config file: $CONFIG_FILE"
ESCAPED_PATH="${ESCAPED_PATH//\\/\\\\}" ESCAPED_PATH="${ESCAPED_PATH//\\/\\\\}"
``` ```
4. **Check if already installed**: Search config file for existing 4. **Check if already installed**: Search config file for existing
`claudesidian` alias `claudesidian` alias/function
5. **Create backup**: Before modifying, create timestamped backup of config file ```bash
# Check for existing alias/function
if grep -q "alias claudesidian\|function claudesidian" "$CONFIG_FILE"; then
echo "⚠️ Found existing claudesidian command:"
grep -A 3 "claudesidian" "$CONFIG_FILE"
echo ""
read -p "Replace it? (yes/no): " replace_answer
if [[ ! "$replace_answer" =~ ^[Yy] ]]; then
echo "Installation cancelled. Existing command preserved."
exit 0
fi
# Mark for replacement (will remove before adding new one)
REPLACING=true
fi
```
5. **Get user confirmation**: Show what will be added and get final confirmation
6. **Create backup**: Only if proceeding with modification
```bash ```bash
# Create backup with timestamp # Create backup with timestamp
BACKUP_FILE="$CONFIG_FILE.backup-$(date +%Y%m%d-%H%M%S)" BACKUP_FILE="$CONFIG_FILE.backup-$(date +%Y%m%d-%H%M%S)"
cp "$CONFIG_FILE" "$BACKUP_FILE" cp "$CONFIG_FILE" "$BACKUP_FILE"
echo "💾 Backup created: $BACKUP_FILE" echo "💾 Backup created: $BACKUP_FILE"
``` ```
6. **Add alias**: Append to config file if not present, using double-quoted path 7. **Build the safe alias/function command**: Use the escaped path from step 3
7. **Show success message**: With instructions to reload shell ```bash
# CRITICAL: Use $ESCAPED_PATH in the command (not raw $VAULT_PATH)
if [ "$SHELL_TYPE" = "fish" ]; then
# Fish uses function syntax, not alias
COMMAND_TEXT="function claudesidian
cd \"$ESCAPED_PATH\" && (claude --resume 2>/dev/null; or claude)
cd -
end"
else
# Bash/Zsh use alias syntax
# IMPORTANT: Use double quotes around $ESCAPED_PATH to preserve escaping
COMMAND_TEXT="alias claudesidian='(cd \"$ESCAPED_PATH\" && (claude --resume 2>/dev/null || claude))'"
fi
```
8. **Remove old command if replacing**:
```bash
if [ "$REPLACING" = true ]; then
# Remove old alias/function before adding new one
sed -i.tmp '/alias claudesidian\|function claudesidian/,/^end$/d' "$CONFIG_FILE"
rm -f "$CONFIG_FILE.tmp"
fi
```
9. **Add command to config file**: Append using the escaped command text
```bash
echo "$COMMAND_TEXT" >> "$CONFIG_FILE"
```
10. **Show success message**: With instructions to reload shell
## Example Output ## Example Output
**Bash/Zsh Example (with spaces in path to demonstrate escaping):**
``` ```
🔧 Installing claudesidian command... 🔧 Installing claudesidian command...
📁 Vault path: /home/user/my-vault 📁 Vault path: /home/user/My Obsidian Vault
🐚 Shell detected: zsh 🐚 Shell detected: zsh
📝 Config file: /home/user/.zshrc 📝 Config file: /home/user/.zshrc
💾 Backup created: /home/user/.zshrc.backup-20250107-143025 💾 Backup created: /home/user/.zshrc.backup-20250107-143025
✅ Installed! Added to /home/user/.zshrc: ✅ Installed! Added to /home/user/.zshrc:
alias claudesidian='(cd "/home/user/my-vault" && (claude --resume 2>/dev/null || claude))' alias claudesidian='(cd "/home/user/My Obsidian Vault" && (claude --resume 2>/dev/null || claude))'
🔄 To activate, run: 🔄 To activate, run:
source ~/.zshrc source ~/.zshrc
@@ -154,6 +198,31 @@ echo "📝 Config file: $CONFIG_FILE"
✨ Test it: Type 'claudesidian' from any directory! ✨ Test it: Type 'claudesidian' from any directory!
``` ```
**Fish Shell Example:**
```
🔧 Installing claudesidian command...
📁 Vault path: /home/user/My Obsidian Vault
🐚 Shell detected: fish
📝 Config file: /home/user/.config/fish/config.fish
💾 Backup created: /home/user/.config/fish/config.fish.backup-20250107-143025
✅ Installed! Added to /home/user/.config/fish/config.fish:
function claudesidian
cd "/home/user/My Obsidian Vault" && (claude --resume 2>/dev/null; or claude)
cd -
end
🔄 To activate, run:
source ~/.config/fish/config.fish
Or start a new terminal session.
✨ Test it: Type 'claudesidian' from any directory!
```
## Handling Special Characters ## Handling Special Characters
The implementation properly handles paths with: The implementation properly handles paths with:
@@ -164,18 +233,59 @@ The implementation properly handles paths with:
Paths are double-quoted and any embedded quotes/backslashes are escaped. Paths are double-quoted and any embedded quotes/backslashes are escaped.
## Fish Shell Support
Fish shell uses different syntax than Bash/Zsh:
**Bash/Zsh (alias):**
```bash
alias claudesidian='(cd "/path" && command)'
```
**Fish (function):**
```fish
function claudesidian
cd "/path" && (command; or fallback)
cd -
end
```
Key differences:
- Fish uses `function` keyword instead of `alias` for complex commands
- Fish uses `; or` instead of `||` for fallback logic
- Fish uses `cd -` to return to previous directory (instead of subshell)
- Multi-line function definition instead of single-line alias
The installation automatically detects Fish and uses the correct syntax.
## Security Considerations
This command modifies your shell configuration file (a sensitive operation).
Safety measures:
- **You'll see exactly what will be added** before any changes
- **Timestamped backup is automatically created** before modification
- **Vault path is properly escaped** to prevent injection attacks
- **Only the claudesidian command is modified** - nothing else in your config
- **Asks permission** before replacing existing commands
If anything goes wrong, restore from: `$CONFIG_FILE.backup-YYYYMMDD-HHMMSS`
## Important Notes ## Important Notes
- The command uses a subshell `()` so it returns to your original directory - The command uses a subshell `()` (or `cd -` in Fish) so it returns to your
after original directory after
- Automatically tries to resume existing sessions, falls back to new session - Automatically tries to resume existing sessions, falls back to new session
- If alias already exists, ask user if they want to replace it - If alias/function already exists, asks user if they want to replace it
- Always show what will be added before modifying config files - Always shows what will be added before modifying config files
- **Always create timestamped backup** of config file before modifying (format: - **Always creates timestamped backup** of config file before modifying (format:
`YYYYMMDD-HHMMSS`) `YYYYMMDD-HHMMSS`)
- Backups are kept indefinitely - users can manually clean up old backups if - Backups are kept indefinitely - users can manually clean up old backups if
needed needed
- Show backup location so users know where to restore from if needed - Shows backup location so users know where to restore from if needed
## Usage Examples ## Usage Examples
@@ -201,7 +311,7 @@ Install for specific shell (override auto-detection):
## How It Works ## How It Works
The alias uses a clever pattern: **Bash/Zsh (alias with subshell):**
```bash ```bash
alias claudesidian='(cd "/path/to/vault" && (claude --resume 2>/dev/null || claude))' alias claudesidian='(cd "/path/to/vault" && (claude --resume 2>/dev/null || claude))'
@@ -212,4 +322,22 @@ alias claudesidian='(cd "/path/to/vault" && (claude --resume 2>/dev/null || clau
2. `claude --resume 2>/dev/null` - Tries to resume existing session, suppresses 2. `claude --resume 2>/dev/null` - Tries to resume existing session, suppresses
error error
3. `|| claude` - If resume fails (no session), starts new session 3. `|| claude` - If resume fails (no session), starts new session
4. After Claude exits, returns to original directory automatically 4. After Claude exits, subshell closes and returns to original directory
automatically
**Fish (function with cd -):**
```fish
function claudesidian
cd "/path/to/vault" && (claude --resume 2>/dev/null; or claude)
cd -
end
```
1. `cd "/path/to/vault"` - Changes to vault directory (path is double-quoted for
safety)
2. `claude --resume 2>/dev/null` - Tries to resume existing session, suppresses
error
3. `; or claude` - If resume fails (no session), starts new session (Fish
syntax)
4. `cd -` - Returns to previous directory after Claude exits