package main import ( "encoding/base64" "fmt" "log" "net/http" "strings" "sync/atomic" ) var ( // requestCounter stores the number of HTTP requests (excluding /stats). requestCounter uint64 ) // colorComponentKeys defines the names for the color components in their encoding order. // The encoding process described uses 9 components, but output is only for the first 8. var colorComponentKeys = []string{ "PRIMARY_COLOR", "SECONDARY_COLOR", "ROOT_COLOR", "TIME_COLOR", "ERR_COLOR", "SEPARATOR_COLOR", "BORDCOL", "PATH_COLOR", // The 9th component (C9, potentially "Reset") is decoded but not listed for output. } // decodeAndPrintColorsHandler processes requests with encoded color data. func decodeAndPrintColorsHandler(w http.ResponseWriter, r *http.Request) { encodedData := strings.TrimPrefix(r.URL.Path, "/") // 1. Convert URL-safe Base64 characters back to standard Base64. // The Vue code replaces '+' with '-', '/' with '_', and removes padding. standardBase64 := strings.ReplaceAll(encodedData, "-", "+") standardBase64 = strings.ReplaceAll(standardBase64, "_", "/") // 2. Decode Base64 string to bytes. // RawStdEncoding handles Base64 without padding. // The Vue code generates an 8-character string from 6 bytes, which means no padding. decodedBytes, err := base64.RawStdEncoding.DecodeString(standardBase64) if err != nil { http.Error(w, fmt.Sprintf("Base64 decoding failed: %v. Input: '%s'", err, encodedData), http.StatusBadRequest) return } if len(decodedBytes) != 6 { http.Error(w, fmt.Sprintf("Decoded data must be 6 bytes long, got %d bytes from input '%s'", len(decodedBytes), encodedData), http.StatusBadRequest) return } // 3. Unpack 6 bytes into nine 5-bit values (C1 to C9). // Based on the Vue frontend's "Byte Packing" description: // Byte 1: C1_b4 C1_b3 C1_b2 C1_b1 C1_b0 C2_b4 C2_b3 C2_b2 // Byte 2: C2_b1 C2_b0 C3_b4 C3_b3 C3_b2 C3_b1 C3_b0 C4_b4 // Byte 3: C4_b3 C4_b2 C4_b1 C4_b0 C5_b4 C5_b3 C5_b2 C5_b1 // Byte 4: C5_b0 C6_b4 C6_b3 C6_b2 C6_b1 C6_b0 C7_b4 C7_b3 // Byte 5: C7_b2 C7_b1 C7_b0 C8_b4 C8_b3 C8_b2 C8_b1 C8_b0 // Byte 6: C9_b4 C9_b3 C9_b2 C9_b1 C9_b0 0 0 0 (padding) fiveBitValues := make([]byte, 9) b := decodedBytes fiveBitValues[0] = b[0] >> 3 // C1 fiveBitValues[1] = ((b[0] & 0x07) << 2) | (b[1] >> 6) // C2 fiveBitValues[2] = (b[1] & 0x3E) >> 1 // C3 fiveBitValues[3] = ((b[1] & 0x01) << 4) | (b[2] >> 4) // C4 fiveBitValues[4] = ((b[2] & 0x0F) << 1) | (b[3] >> 7) // C5 fiveBitValues[5] = (b[3] & 0x7C) >> 2 // C6 fiveBitValues[6] = ((b[3] & 0x03) << 3) | (b[4] >> 5) // C7 fiveBitValues[7] = b[4] & 0x1F // C8 fiveBitValues[8] = b[5] >> 3 // C9 var result strings.Builder // 4. For each of the first 8 components, generate the bash color code. for i := 0; i < 8; i++ { val5bit := fiveBitValues[i] // Extract attributes from the 5-bit value: // (base_color_0_7 << 2) | (light_bit << 1) | bold_bit baseColor07 := (val5bit >> 2) & 0x07 // 3 MSB for base color (0-7) lightBit := (val5bit >> 1) & 0x01 // 1 bit for light state boldBit := val5bit & 0x01 // 1 bit for bold state // Convert to ANSI color codes baseAnsiCode := baseColor07 + 30 // Base colors are 30-37 actualAnsiCode := baseAnsiCode if lightBit == 1 { actualAnsiCode += 60 // Bright colors are 90-97 } styleAttr := 0 // Style: 0 for normal if boldBit == 1 { styleAttr = 1 // Style: 1 for bold } // Format as bash-compatible string: \[\033[