feat: convert to shell script and improve documentation

This commit is contained in:
robojerk 2025-06-03 15:14:37 -07:00
parent 96a5720497
commit 0ecdeadfd5
5 changed files with 527 additions and 238 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
hidden_docs/

View file

@ -12,6 +12,14 @@ function Test-TokenFormat {
return $Token -match '^[a-fA-F0-9]{64}$'
}
# Function to validate Forgejo URL format
function Test-ForgejoUrl {
param([string]$Url)
# Basic URL validation - allows IP addresses and domain names
$urlRegex = '^https?://[a-zA-Z0-9.-]+(:\d+)?$|^[a-zA-Z0-9.-]+(:\d+)?$'
return $Url -match $urlRegex
}
# Function to generate signature
function Get-SshSignature {
param(
@ -78,12 +86,24 @@ function Get-SshSignature {
return $signature
}
# --- Get Forgejo Location ---
$forgejoLocation = ""
while (-not (Test-ForgejoUrl -Url $forgejoLocation)) {
$forgejoLocation = Read-Host "Please enter your Forgejo location (e.g., forgejo.example.com or 192.168.1.100:3000)"
if (-not (Test-ForgejoUrl -Url $forgejoLocation)) {
Write-Host "Invalid format. Please enter a valid URL or IP address." -ForegroundColor Red
}
}
# Remove http:// or https:// if present
$forgejoLocation = $forgejoLocation -replace '^https?://', ''
# --- SSH Key Generation ---
# Get user's email for key comment
$email = ""
while (-not (Test-EmailFormat -Email $email)) {
$email = Read-Host "Please enter your email address for your SSH key comment"
$email = Read-Host "Please enter your email address for your SSH key comment (e.g., user@example.com)"
if (-not (Test-EmailFormat -Email $email)) {
Write-Host "Invalid email format. Please try again." -ForegroundColor Red
}
@ -128,17 +148,10 @@ Write-Host "Please copy the FOLLOWING ENTIRE KEY and paste it into Forgejo:" -Fo
Get-Content $publicKeyPath
Write-Host "---------------------------" -ForegroundColor Green
# Show key fingerprint for verification
$keyFingerprint = (ssh-keygen -lf $publicKeyPath).Split(' ')[1]
Write-Host "`nKey Fingerprint (verify this matches in Forgejo):" -ForegroundColor Yellow
Write-Host $keyFingerprint -ForegroundColor Cyan
Write-Host "`nIMPORTANT: Make sure this fingerprint matches exactly in Forgejo!" -ForegroundColor Yellow
Write-Host "If it doesn't match, the key verification will fail." -ForegroundColor Yellow
# --- Forgejo Web Server Instructions ---
Write-Host "`n--- Next Steps (Manual on Forgejo Web Server) ---" -ForegroundColor Cyan
Write-Host "1. Login to your Forgejo web server (e.g., https://git.raines.xyz)"
Write-Host "1. Login to your Forgejo web server (e.g., https://$forgejoLocation)"
Write-Host "2. Click on your profile avatar (top right corner)"
Write-Host "3. Select 'Settings'"
Write-Host "4. In the left sidebar, click on 'SSH / GPG Keys'"
@ -146,9 +159,8 @@ Write-Host "5. Click the 'Add Key' button"
Write-Host "6. Give your key a descriptive 'Title' (e.g., 'My Laptop Key')"
Write-Host "7. PASTE the public key shown ABOVE into the 'Content' text area"
Write-Host "8. Click 'Add Key'."
Write-Host "9. After adding, verify that the fingerprint matches: $keyFingerprint" -ForegroundColor Yellow
Write-Host "10. Click the 'Verify' button next to your new key."
Write-Host "11. Copy the challenge token (the long hexadecimal string) provided by Forgejo."
Write-Host "9. After adding, click the 'Verify' button next to your new key."
Write-Host "10. Copy the challenge token (the long hexadecimal string) provided by Forgejo."
# --- Key Verification ---
$verificationPassed = $false
@ -189,9 +201,9 @@ while (-not $verificationPassed -and $attempts -lt $maxAttempts) {
Write-Host "------------------------------------" -ForegroundColor Green
Write-Host "`n--- Final Steps (Manual on Forgejo Web Server) ---" -ForegroundColor Cyan
Write-Host "12. Paste the signature above into the verification box in Forgejo."
Write-Host "13. Click 'Verify'. You should see 'Successfully verified'."
Write-Host "14. Once verified, you can now test your SSH connection to Forgejo."
Write-Host "11. Paste the signature above into the verification box in Forgejo."
Write-Host "12. Click 'Verify'. You should see 'Successfully verified'."
Write-Host "13. Once verified, you can now test your SSH connection to Forgejo."
# Check verification status
Write-Host "`n--- Verification Status Check ---" -ForegroundColor Yellow
@ -230,7 +242,7 @@ while (-not $verificationPassed -and $attempts -lt $maxAttempts) {
Write-Host "`n--- SSH Config Setup (Optional) ---" -ForegroundColor Yellow
$setupConfig = Read-Host "Would you like to set up your SSH config for easier connections? (Y/N)"
if ($setupConfig -eq 'Y') {
$forgejoHost = Read-Host "Enter your Forgejo hostname (e.g., git.raines.xyz)"
$forgejoHost = $forgejoLocation
$forgejoUser = Read-Host "Enter your Forgejo username"
$sshConfigPath = "$env:USERPROFILE\.ssh\config"
@ -253,40 +265,26 @@ Host $forgejoHost
New-Item -ItemType Directory -Path "$env:USERPROFILE\.ssh" | Out-Null
}
# Check if config file exists and has duplicate entries
# Read existing config content as a single raw string
$existingRawConfig = ""
if (Test-Path $sshConfigPath) {
Write-Host "`nChecking for existing SSH config entries..." -ForegroundColor Yellow
$existingConfig = Get-Content $sshConfigPath
$hasDuplicate = $existingConfig -match "Host $forgejoHost"
if ($hasDuplicate.Count -gt 1) {
Write-Host "Found duplicate entries for $forgejoHost. Cleaning up config file..." -ForegroundColor Yellow
# Create backup of existing config
$backupPath = "$sshConfigPath.backup"
Copy-Item $sshConfigPath $backupPath
Write-Host "Created backup at: $backupPath" -ForegroundColor Yellow
# Remove all existing entries for this host
$newConfig = $existingConfig | Where-Object {
-not ($_ -match "Host $forgejoHost" -or
($_ -match "^\s+(HostName|User|IdentityFile|PreferredAuthentications|PubkeyAuthentication|PasswordAuthentication)" -and
$existingConfig[$existingConfig.IndexOf($_) - 1] -match "Host $forgejoHost"))
$existingRawConfig = Get-Content $sshConfigPath -Raw
}
# Add new config
$newConfig += $configContent
Set-Content -Path $sshConfigPath -Value $newConfig
Write-Host "Updated SSH config with clean entry for $forgejoHost" -ForegroundColor Green
} else {
# No duplicates, just append
Add-Content -Path $sshConfigPath -Value $configContent
Write-Host "Added new SSH config entry for $forgejoHost" -ForegroundColor Green
}
} else {
# Create new config file
Set-Content -Path $sshConfigPath -Value $configContent
Write-Host "Created new SSH config file with entry for $forgejoHost" -ForegroundColor Green
}
# Define regex pattern to find and remove existing block for this host
# (?smi) flags: s=singleline (dot matches newline), m=multiline (^ and $ match start/end of line), i=case-insensitive
# ^Host\s+$([regex]::Escape($forgejoHost))\s*\r?\n - Matches the "Host" line
# (?:^\s*(?:HostName|User|IdentityFile|PreferredAuthentications|PubkeyAuthentication|PasswordAuthentication).*\r?\n)* - Matches subsequent indented config lines
$pattern = "(?smi)^Host\s+$([regex]::Escape($forgejoHost))\s*\r?\n(?:^\s*(?:HostName|User|IdentityFile|PreferredAuthentications|PubkeyAuthentication|PasswordAuthentication).*\r?\n)*"
# Remove existing block(s) for this host
$updatedRawConfig = $existingRawConfig -replace $pattern, ""
# Append the new configuration block
$updatedRawConfig += $configContent
# Write the updated content back to the file
Set-Content -Path $sshConfigPath -Value $updatedRawConfig.Trim() # Trim any leading/trailing whitespace from the whole file
Write-Host "`nSSH config has been updated. You can now connect using:" -ForegroundColor Green
Write-Host "ssh $forgejoHost" -ForegroundColor Cyan
@ -322,7 +320,7 @@ Host $forgejoHost
Write-Host "`n--- Testing SSH Connection ---" -ForegroundColor Yellow
$testConnection = Read-Host "Would you like to test your SSH connection now? (Y/N)"
if ($testConnection -eq 'Y') {
$forgejoHost = Read-Host "Enter your Forgejo hostname (e.g., git.raines.xyz)"
$forgejoHost = $forgejoLocation
$forgejoUser = Read-Host "Enter your Forgejo username"
Write-Host "`nTesting connection to $forgejoUser@$forgejoHost with verbose output..." -ForegroundColor Yellow
$testResult = ssh -v -T "$forgejoUser@$forgejoHost" 2>&1

330
forgejo-ssh-key-setup.sh Normal file
View file

@ -0,0 +1,330 @@
#!/bin/sh
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
NC='\033[0m' # No Color
# Function to validate email format
validate_email() {
echo "$1" | grep -E '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' >/dev/null
return $?
}
# Function to validate token format
validate_token() {
echo "$1" | grep -E '^[a-fA-F0-9]{64}$' >/dev/null
return $?
}
# Function to validate Forgejo URL format
validate_forgejo_url() {
echo "$1" | grep -E '^https?://[a-zA-Z0-9.-]+(:[0-9]+)?$|^[a-zA-Z0-9.-]+(:[0-9]+)?$' >/dev/null
return $?
}
# Function to generate signature
generate_signature() {
local token="$1"
local private_key_path="$2"
# Validate parameters
if [ ! -f "$private_key_path" ]; then
echo -e "${RED}Error: Private key not found at path: $private_key_path${NC}"
exit 1
fi
# Normalize token format
token=$(echo "$token" | tr '[:upper:]' '[:lower:]' | tr -d ' ')
# Debug: Check token format
echo -e "\n${GRAY}Debug: Token format check:${NC}"
echo -e "${GRAY}Length: ${#token}${NC}"
echo -e "${GRAY}Format: $(echo "$token" | grep -E '^[a-f0-9]{64}$' >/dev/null && echo "valid" || echo "invalid")${NC}"
# Generate signature
echo -e "\n${GRAY}Generating signature...${NC}"
signature=$(echo -n "$token" | ssh-keygen -Y sign -n gitea -f "$private_key_path" 2>&1)
# Debug: Check raw output
echo -e "\n${GRAY}Debug: Raw signature output:${NC}"
echo "$signature" | while IFS= read -r line; do
echo -e "${GRAY} $line${NC}"
done
# Filter the output to get only the signature block
signature=$(echo "$signature" | grep -E '^(-----BEGIN SSH SIGNATURE-----|-----END SSH SIGNATURE-----|[A-Za-z0-9+/=]+)$')
# Debug: Check filtered signature
echo -e "\n${GRAY}Debug: Filtered signature:${NC}"
echo "$signature" | while IFS= read -r line; do
echo -e "${GRAY} $line${NC}"
done
# Verify signature format
if ! echo "$signature" | grep -q '^-----BEGIN SSH SIGNATURE-----' || \
! echo "$signature" | grep -q '-----END SSH SIGNATURE-----' || \
! echo "$signature" | grep -E '^-----BEGIN SSH SIGNATURE-----\r?\n[A-Za-z0-9+/=]+\r?\n-----END SSH SIGNATURE-----\r?$' >/dev/null; then
echo -e "${YELLOW}Warning: Signature format may be incorrect or incomplete.${NC}"
fi
echo "$signature"
}
# --- Get Forgejo Location ---
forgejo_location=""
while ! validate_forgejo_url "$forgejo_location"; do
echo -e "\n${CYAN}Please enter your Forgejo location (e.g., forgejo.example.com or 192.168.1.100:3000)${NC}"
read -r forgejo_location
if ! validate_forgejo_url "$forgejo_location"; then
echo -e "${RED}Invalid format. Please enter a valid URL or IP address.${NC}"
fi
done
# Remove http:// or https:// if present
forgejo_location=$(echo "$forgejo_location" | sed -E 's|^https?://||')
# --- SSH Key Generation ---
# Get user's email for key comment
email=""
while ! validate_email "$email"; do
echo -e "\n${CYAN}Please enter your email address for your SSH key comment (e.g., user@example.com)${NC}"
read -r email
if ! validate_email "$email"; then
echo -e "${RED}Invalid email format. Please try again.${NC}"
fi
done
# Generate SSH key
echo -e "\n${CYAN}--- Generating SSH Key ---${NC}"
echo -e "${YELLOW}You'll be prompted for a passphrase. Please remember it and keep it safe!${NC}"
private_key_path="$HOME/.ssh/id_ed25519"
public_key_path="$HOME/.ssh/id_ed25519.pub"
# Check if key already exists
if [ -f "$private_key_path" ]; then
echo -e "\n${YELLOW}Warning: An SSH key already exists at '$private_key_path'.${NC}"
echo -e "${YELLOW}Do you want to overwrite it? (y/N)${NC}"
read -r overwrite
if [ "$overwrite" != "y" ] && [ "$overwrite" != "Y" ]; then
echo -e "${RED}Key generation cancelled. Exiting.${NC}"
exit 1
fi
fi
# Execute ssh-keygen
ssh-keygen -t ed25519 -C "$email" -f "$private_key_path"
if [ $? -ne 0 ]; then
echo -e "${RED}Error generating SSH key. Please check your SSH installation.${NC}"
exit 1
fi
# Add key to SSH agent
echo -e "\n${YELLOW}--- Adding Key to SSH Agent ---${NC}"
echo -e "${YELLOW}This avoids re-entering your passphrase. You might be prompted for your passphrase now.${NC}"
ssh-add "$private_key_path"
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to add key to SSH agent. You may need to start the SSH agent manually.${NC}"
echo -e "${YELLOW}To start the agent manually, run: eval \$(ssh-agent -s)${NC}"
fi
# Display the public key
echo -e "\n${GREEN}--- Your Public Key ---${NC}"
echo -e "${GREEN}Please copy the FOLLOWING ENTIRE KEY and paste it into Forgejo:${NC}"
cat "$public_key_path"
echo -e "${GREEN}---------------------------${NC}"
# --- Forgejo Web Server Instructions ---
echo -e "\n${CYAN}--- Next Steps (Manual on Forgejo Web Server) ---${NC}"
echo "1. Login to your Forgejo web server (e.g., https://$forgejo_location)"
echo "2. Click on your profile avatar (top right corner)"
echo "3. Select 'Settings'"
echo "4. In the left sidebar, click on 'SSH / GPG Keys'"
echo "5. Click the 'Add Key' button"
echo "6. Give your key a descriptive 'Title' (e.g., 'My Laptop Key')"
echo "7. PASTE the public key shown ABOVE into the 'Content' text area"
echo "8. Click 'Add Key'."
echo "9. After adding, click the 'Verify' button next to your new key."
echo "10. Copy the challenge token (the long hexadecimal string) provided by Forgejo."
# --- Key Verification ---
verification_passed=false
max_attempts=3
attempts=0
while [ "$verification_passed" = false ] && [ $attempts -lt $max_attempts ]; do
attempts=$((attempts + 1))
# Get and validate the token
token=""
while ! validate_token "$token"; do
echo -e "\n${YELLOW}--- Key Verification (Attempt $attempts of $max_attempts) ---${NC}"
echo -e "${YELLOW}Please get a fresh token from Forgejo (tokens expire after a few minutes)${NC}"
read -r token
if ! validate_token "$token"; then
echo -e "${RED}Invalid token format. Token should be 64 hexadecimal characters.${NC}"
fi
done
# Verify the token
echo -e "\n${YELLOW}Verifying key with Forgejo...${NC}"
echo -e "${YELLOW}Running verification command using private key: $private_key_path${NC}"
echo -e "${YELLOW}--------------------------------------------------------${NC}"
# Generate signature
verification_output=$(generate_signature "$token" "$private_key_path")
echo -e "\n${GREEN}--- Copy and Paste the Signature ---${NC}"
echo -e "${GREEN}Please copy the FOLLOWING ENTIRE BLOCK (including BEGIN and END lines) and paste it back into the Forgejo web verification box:${NC}"
echo ""
echo "$verification_output"
echo ""
echo -e "${GREEN}------------------------------------${NC}"
echo -e "\n${CYAN}--- Final Steps (Manual on Forgejo Web Server) ---${NC}"
echo "11. Paste the signature above into the verification box in Forgejo."
echo "12. Click 'Verify'. You should see 'Successfully verified'."
echo "13. Once verified, you can now test your SSH connection to Forgejo."
# Check verification status
echo -e "\n${YELLOW}--- Verification Status Check ---${NC}"
echo -e "${YELLOW}Did the verification pass in the Forgejo web interface? (y/N)${NC}"
read -r verification_status
if [ "$verification_status" = "y" ] || [ "$verification_status" = "Y" ]; then
verification_passed=true
else
echo -e "\n${RED}Verification failed. Here are some troubleshooting steps:${NC}"
echo -e "${YELLOW}1. Make sure you copied the ENTIRE signature block, including BEGIN and END lines${NC}"
echo -e "${YELLOW}2. Check that there are no extra spaces or line breaks in the signature${NC}"
echo -e "${YELLOW}3. Verify that the token was entered correctly${NC}"
echo -e "${YELLOW}4. The token may have expired - get a fresh token from Forgejo${NC}"
echo -e "${YELLOW}5. Try again with a new token${NC}"
if [ $attempts -lt $max_attempts ]; then
echo -e "\n${YELLOW}Let's try again with a new token...${NC}"
else
echo -e "\n${RED}Maximum verification attempts reached. Please check your key and try again later.${NC}"
exit 1
fi
fi
done
# --- SSH Config Setup ---
echo -e "\n${YELLOW}--- SSH Config Setup (Optional) ---${NC}"
echo -e "${YELLOW}Would you like to set up your SSH config for easier connections? (y/N)${NC}"
read -r setup_config
if [ "$setup_config" = "y" ] || [ "$setup_config" = "Y" ]; then
echo -e "${YELLOW}Enter your Forgejo username:${NC}"
read -r forgejo_user
ssh_config_path="$HOME/.ssh/config"
ssh_private_key_path="$private_key_path"
# Create config content
config_content="# Forgejo Configuration
Host $forgejo_location
HostName $forgejo_location
User $forgejo_user
IdentityFile $ssh_private_key_path
PreferredAuthentications publickey
PubkeyAuthentication yes
PasswordAuthentication no
"
# Create .ssh directory if it doesn't exist
mkdir -p "$HOME/.ssh"
# Read existing config
if [ -f "$ssh_config_path" ]; then
existing_config=$(cat "$ssh_config_path")
else
existing_config=""
fi
# Remove existing block for this host using sed
updated_config=$(echo "$existing_config" | sed -E "/^Host[[:space:]]+$forgejo_location[[:space:]]*$/,/^[^[:space:]]/d")
# Append new config
updated_config="$updated_config
$config_content"
# Write updated config
echo "$updated_config" > "$ssh_config_path"
echo -e "\n${GREEN}SSH config has been updated. You can now connect using:${NC}"
echo -e "${CYAN}ssh $forgejo_location${NC}"
echo -e "\n${YELLOW}Your SSH config is located at: $ssh_config_path${NC}"
# Wait a moment for the key to be fully processed
echo -e "\n${YELLOW}Waiting a moment for the key to be fully processed...${NC}"
sleep 5
# Test the connection
echo -e "\n${YELLOW}--- Testing SSH Connection ---${NC}"
echo -e "${YELLOW}Testing connection to $forgejo_location with verbose output...${NC}"
test_output=$(ssh -v -T "$forgejo_location" 2>&1)
ssh_exit_code=$?
if [ "$ssh_exit_code" -eq 1 ]; then
# Exit code 1 typically means success for ssh -T without remote command
echo -e "${GREEN}Connection successful! You can now use Git with your Forgejo repository.${NC}"
elif [ "$ssh_exit_code" -eq 0 ]; then
# This can happen if ssh does run an implicit command or due to specific server configs
echo -e "${YELLOW}Warning: SSH command returned exit code 0. This might indicate a successful connection, but verify manually if expected.${NC}"
echo -e "${GREEN}Connection successful! You can now use Git with your Forgejo repository.${NC}"
else
echo -e "${RED}Connection test failed. Here are some troubleshooting steps:${NC}"
# Display the verbose output of the failed ssh command
echo "$test_output" | while IFS= read -r line; do echo -e "${RED} $line${NC}"; done
echo -e "${YELLOW}1. Verify that your SSH key is properly added to your Forgejo account:${NC}"
echo -e "${YELLOW} - Check that the key appears in your SSH keys list${NC}"
echo -e "${YELLOW} - Verify that the key fingerprint matches: $(ssh-keygen -lf "$public_key_path" | cut -d' ' -f2)${NC}"
echo -e "${YELLOW}2. Check your SSH config:${NC}"
echo -e "${YELLOW} - Verify the hostname is correct: $forgejo_location${NC}"
echo -e "${YELLOW} - Verify the username is correct: $forgejo_user${NC}"
echo -e "${YELLOW} - Check that the key path is correct: $ssh_private_key_path${NC}"
echo -e "${YELLOW}3. Try connecting manually with verbose output:${NC}"
echo -e "${CYAN} ssh -v -T $forgejo_user@$forgejo_location${NC}"
echo -e "${YELLOW}Note: SSH returned exit code $ssh_exit_code.${NC}"
exit 1
fi
else
# If user didn't set up SSH config, still offer to test connection
echo -e "\n${YELLOW}--- Testing SSH Connection ---${NC}"
echo -e "${YELLOW}Would you like to test your SSH connection now? (y/N)${NC}"
read -r test_connection
if [ "$test_connection" = "y" ] || [ "$test_connection" = "Y" ]; then
echo -e "${YELLOW}Enter your Forgejo username:${NC}"
read -r forgejo_user
echo -e "\n${YELLOW}Testing connection to $forgejo_user@$forgejo_location with verbose output...${NC}"
test_output=$(ssh -v -T "$forgejo_user@$forgejo_location" 2>&1)
ssh_exit_code=$?
if [ "$ssh_exit_code" -eq 1 ]; then
echo -e "${GREEN}Connection successful! You can now use Git with your Forgejo repository.${NC}"
elif [ "$ssh_exit_code" -eq 0 ]; then
echo -e "${YELLOW}Warning: SSH command returned exit code 0. This might indicate a successful connection, but verify manually if expected.${NC}"
echo -e "${GREEN}Connection successful! You can now use Git with your Forgejo repository.${NC}"
else
echo -e "${RED}Connection test failed. Here are some troubleshooting steps:${NC}"
# Display the verbose output of the failed ssh command
echo "$test_output" | while IFS= read -r line; do echo -e "${RED} $line${NC}"; done
echo -e "${YELLOW}1. Verify that your SSH key is properly added to your Forgejo account:${NC}"
echo -e "${YELLOW} - Check that the key appears in your SSH keys list${NC}"
echo -e "${YELLOW} - Verify that the key fingerprint matches: $(ssh-keygen -lf "$public_key_path" | cut -d' ' -f2)${NC}"
echo -e "${YELLOW}2. Try connecting manually with verbose output:${NC}"
echo -e "${CYAN} ssh -v -T $forgejo_user@$forgejo_location${NC}"
echo -e "${YELLOW}Note: SSH returned exit code $ssh_exit_code.${NC}"
exit 1
fi
fi
fi
echo -e "\n${GREEN}Process for SSH key setup and verification completed!${NC}"

View file

@ -1,158 +0,0 @@
# Analysis of SSH Key Verification Failure
## Observations from the Output
1. **Key Generation**
- Successfully generated ED25519 key
- Key fingerprint: SHA256:k4SR6Pnp3se+9CzgZjnHYS+FAP/gyNHnbRB8s/Z1KC8
- Public key was generated and displayed correctly
2. **Verification Attempts**
- Three attempts were made with different tokens
- Each attempt followed the same process
- All attempts failed with the same error
- The signature format appears correct (has BEGIN/END markers)
3. **Token Handling**
- Tokens were 64-character hex strings
- Each attempt used a fresh token
- Token format validation passed
4. **Error Message Analysis**
- Forgejo reports: "The provided SSH key, signature or token do not match or token is out-of-date"
- This suggests either:
* The signature format is incorrect
* The token has expired
* There's a mismatch between the key and signature
* The signature includes extra data
## Potential Issues
1. **Signature Generation**
- The `echo -n` command might not be working as expected in PowerShell
- PowerShell's echo might be adding extra characters or line endings
- The signature might include the "Signing data on standard input" line
- The signature output might include debug/informational messages that should be filtered
2. **Token Processing**
- The token might need to be processed differently (e.g., remove any whitespace)
- The token might need to be in a specific format (uppercase/lowercase)
- The token might need to be handled as raw bytes
3. **SSH Key Format**
- The key might need to be in a specific format for Forgejo
- The key comment might be affecting the verification
- The key permissions might need to be set correctly
4. **Forgejo Requirements**
- Forgejo might expect a specific signature format
- The namespace (-n forgejo_token) might need to be different
- The verification process might have changed in recent Forgejo versions
## Prioritized Action Plan
### 1. Verify echo -n Behavior (HIGHEST PRIORITY)
```powershell
# Test echo -n behavior in isolation
echo -n "test" | Format-Hex # Check for any trailing newlines (0A)
# Expected output should show only the hex for "test" without 0A at the end
```
### 2. Refine Signature Output Filtering (HIGHEST PRIORITY)
```powershell
# Test current output
$testToken = "a" * 64 # Create a dummy 64-char hex string
$testSignature = echo -n $testToken | ssh-keygen -Y sign -n forgejo_token -f "$privateKeyPath" 2>&1
$testSignature | Measure-Object -Character -Line # Check character/line counts
$testSignature -match "Signing data on standard input" # See if the phrase is there
# Implement filtering
$rawSignatureOutput = echo -n $Token | ssh-keygen -Y sign -n forgejo_token -f $privateKeyPath 2>&1
$verificationOutput = ($rawSignatureOutput | Where-Object {
$_ -match '^(-----BEGIN SSH SIGNATURE-----|-----END SSH SIGNATURE-----|[A-Za-z0-9+/=]+)$'
} -join "`n").Trim()
# Verify filtered output
$verificationOutput | Format-Hex # Check for any hidden characters
```
### 3. Manual Test Process (HIGH PRIORITY)
1. Get a fresh token from Forgejo
2. In a regular PowerShell window, run:
```powershell
echo -n <token> | ssh-keygen -Y sign -n forgejo_token -f ~/.ssh/id_ed25519
```
3. Copy the output manually and paste into Forgejo
4. If this works, the issue is in the script's output handling
5. Compare the manual signature with the script-generated one
### 4. Token Normalization (MEDIUM PRIORITY)
```powershell
# Add to token processing
$token = $token.Trim().ToLower() # Normalize token format
# Verify token format
$token | Format-Hex # Check for any hidden characters
```
### 5. Key Comment Test (MEDIUM PRIORITY)
1. Generate a new key without the comment:
```powershell
ssh-keygen -t ed25519 -f $privateKeyPath # Remove -C $email
```
2. Try the verification process with the new key
### 6. Alternative Token Passing Methods (LOW PRIORITY)
```powershell
# Option 1: Using temporary file
"$Token" | Out-File -FilePath temp_token.txt -Encoding ascii -NoNewline
$signature = ssh-keygen -Y sign -n forgejo_token -f $privateKeyPath < temp_token.txt 2>&1
Remove-Item temp_token.txt
# Option 2: Using stdin stream
$stdin = New-Object System.IO.StringReader($Token)
$signature = ssh-keygen -Y sign -n forgejo_token -f $privateKeyPath -InputObject $stdin 2>&1
```
## Questions to Consider
1. Does Forgejo provide any specific requirements for the signature format?
2. Are there any known issues with PowerShell's handling of binary data?
3. Should we try a different approach to passing the token to ssh-keygen?
4. Is there a way to verify the signature format before submitting it?
5. Could the key comment be causing issues with the verification?
## Next Steps
1. Verify `echo -n` behavior in isolation
2. Implement the signature output filtering
3. Perform the manual test to verify the basic process
4. Add token normalization
5. Test without key comment
6. If needed, try alternative token passing methods
## Debugging Tips
1. Use `Measure-Object` to check output lengths and line counts
2. Use `Format-Hex` to inspect for hidden characters
3. Compare manual vs. script-generated signatures
4. Check for any hidden characters in the output
5. Verify the exact format of the signature block
6. Monitor the token format throughout the process
7. Document the exact error message from Forgejo
## Implementation Notes
1. **Function Parameter Verification**
- Ensure `Get-SshSignature` receives correct `$privateKeyPath`
- Add parameter validation in the function
- Log the actual path being used
2. **Output Inspection**
- Add debug logging for raw and filtered output
- Compare lengths and formats at each step
- Document any differences between manual and script output
3. **Error Handling**
- Add specific error messages for each failure case
- Log the exact format of the signature being sent
- Document any differences from expected format

180
readme.md
View file

@ -1,44 +1,162 @@
This is a powershell script that will create a a ssh key
assume forgejo is installed (via docker)
ask for email address
run
# Forgejo SSH Key Setup Script
A robust script that automates the process of creating and configuring SSH keys for Forgejo. This script provides a user-friendly interface for generating ED25519 SSH keys, configuring SSH settings, and verifying the connection with your Forgejo instance.
<details>
<summary><strong>PowerShell Version (Windows)</strong></summary>
## Prerequisites
- PowerShell 7 or later
- OpenSSH client installed
- Forgejo instance running
## Usage
1. Run the script:
```powershell
echo "Please remember your passphrase. Write it down. Keep it safe"
ssh-keygen -t ed25519 -C "rraines@gmail.com"
.\forgejo-ssh-key-setup.ps1
```
These file are create
C:\Users\{user}\.ssh\id_ed25519
C:\Users\{user}\.ssh\id_ed25519.pub
2. Follow the prompts:
- Enter your email address
- Create a passphrase (optional but recommended)
- Copy the public key when displayed
- Add the key to Forgejo
- Verify the key using the challenge token
Use cat ( or cat equivalent on powershell) to view "C:\Users\{user}\.ssh\id_ed25519.pub"
## SSH Key Location
```powershell
cls
# Copy the contents below
cat "C:\Users\{user}\.ssh\id_ed25519.pub"
The script creates these files:
```
C:\Users\{user}\.ssh\id_ed25519 # Private key
C:\Users\{user}\.ssh\id_ed25519.pub # Public key
```
Login to your forgejo web server
Click on your **profile avatar** (top right corner)
Select **"Settings"**.
In the left sidebar, click on **"SSH / GPG Keys"**.
Click the **"Add Key"** button.
Give your key a descriptive **"Title"** (e.g., "Rob's Laptop Key").
Paste the entire public key into the "Content" text area.
After adding, you'll see your key listed. Click the **"Verify"** button next to it.
* Forgejo will provide a unique **challenge token** and three different commands. You need to run one of these commands in your local terminal.
</details>
```powershell
echo "Please copy the token on the web page"
echo "for example c9fb7f60219b73d1819d9fe548a43e3a041484f8d7466dd212b4e8cde9e0e3d8"
<details>
<summary><strong>Shell Script Version (Unix/Linux/macOS/WSL)</strong></summary>
## Prerequisites
- Unix-like operating system (Linux, macOS, WSL)
- OpenSSH client installed
- `sh` shell (POSIX-compliant)
- Forgejo instance running
## Usage
1. Make the script executable:
```bash
chmod +x forgejo-ssh-key-setup.sh
```
set $TOKEN to what the user inputs
Verify that the inputted token matches the required parameters. i.e. length, no spaces etc
2. Run the script:
```bash
./forgejo-ssh-key-setup.sh
```
run "cmd /c "<NUL set /p=`"$TOKEN`"| ssh-keygen"
3. Follow the interactive prompts:
- Enter your Forgejo location (e.g., `forgejo.example.com` or `192.168.1.100:3000`)
- Enter your email address
- Create a passphrase (optional but recommended)
- Copy the public key when displayed
- Add the key to Forgejo
- Verify the key using the challenge token
```powershell
Paste the contents into the window and ***verify***
## SSH Key Location
The script creates these files in your home directory:
```
~/.ssh/id_ed25519 # Private key
~/.ssh/id_ed25519.pub # Public key
```
</details>
## Features
- Generates ED25519 SSH key pair
- Validates email format
- Adds key to SSH agent
- Configures SSH config file with robust duplicate entry handling
- Verifies key with Forgejo using challenge-response
- Tests SSH connection with proper exit code handling
- Comprehensive error handling and troubleshooting
- Colorized output for better readability
- Support for custom Forgejo locations (including ports)
## SSH Config
The script can optionally configure your SSH config file with these settings:
```
Host your-forgejo-host
HostName your-forgejo-host
User your-username
IdentityFile ~/.ssh/id_ed25519
PreferredAuthentications publickey
PubkeyAuthentication yes
PasswordAuthentication no
```
## Forgejo Setup
1. Login to your Forgejo web server
2. Click on your profile avatar (top right corner)
3. Select "Settings"
4. In the left sidebar, click on "SSH / GPG Keys"
5. Click the "Add Key" button
6. Give your key a descriptive "Title" (e.g., "My Laptop Key")
7. Paste the entire public key into the "Content" text area
8. Click "Add Key"
9. After adding, click the "Verify" button next to your new key
10. Copy the challenge token provided by Forgejo
11. Run the verification command in your terminal
## Troubleshooting
<details>
<summary><strong>PowerShell Version</strong></summary>
If you encounter issues:
1. Check that your SSH key is properly added to your Forgejo account
2. Verify the key fingerprint matches
3. Ensure your SSH config is correct
4. Check the connection with verbose output: `ssh -v -p 222 git@your-forgejo-server`
</details>
<details>
<summary><strong>Shell Script Version</strong></summary>
If you encounter issues:
1. **Key Verification Fails**:
- Make sure you copied the ENTIRE signature block
- Check for extra spaces or line breaks
- Verify the token was entered correctly
- Get a fresh token if the current one expired
2. **SSH Connection Fails**:
- Check that your SSH key is properly added to your Forgejo account
- Verify the key fingerprint matches
- Ensure your SSH config is correct
- Check the connection with verbose output: `ssh -v -T git@your-forgejo-server`
3. **SSH Agent Issues**:
- Start the SSH agent manually: `eval $(ssh-agent -s)`
- Add your key manually: `ssh-add ~/.ssh/id_ed25519`
## Exit Codes
The script uses these exit codes:
- `0`: Success
- `1`: General error or connection test failure
- Other codes: SSH-specific errors
</details>
## License
This project is open source and available under the MIT License.