#!/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}"