at main 5.1 kB view raw
1package log 2 3import ( 4 "fmt" 5 "io" 6 "log" 7 "os" 8 "strings" 9 "time" 10) 11 12var ( 13 verboseLog *log.Logger 14 infoLog *log.Logger 15 errorLog *log.Logger 16) 17 18func Init(verbose bool) { 19 infoWriter := os.Stdout 20 verboseWriter := io.Discard 21 if verbose { 22 verboseWriter = os.Stdout 23 } 24 25 // Use no flags, we'll add our own ISO 8601 timestamps 26 infoLog = log.New(infoWriter, "", 0) 27 verboseLog = log.New(verboseWriter, "", 0) 28 errorLog = log.New(os.Stderr, "", 0) 29} 30 31// timestamp returns current time with milliseconds (local time, no timezone) 32func timestamp() string { 33 return time.Now().Format("2006-01-02T15:04:05.000") 34} 35 36func Verbose(format string, v ...interface{}) { 37 verboseLog.Printf("%s [VERBOSE] %s", timestamp(), fmt.Sprintf(format, v...)) 38} 39 40func Info(format string, v ...interface{}) { 41 infoLog.Printf("%s [INFO] %s", timestamp(), fmt.Sprintf(format, v...)) 42} 43 44func Warn(format string, v ...interface{}) { 45 infoLog.Printf("%s [WARN] %s", timestamp(), fmt.Sprintf(format, v...)) 46} 47 48func Error(format string, v ...interface{}) { 49 errorLog.Printf("%s [ERROR] %s", timestamp(), fmt.Sprintf(format, v...)) 50} 51 52func Fatal(format string, v ...interface{}) { 53 errorLog.Fatalf("%s [FATAL] %s", timestamp(), fmt.Sprintf(format, v...)) 54} 55 56// Banner prints a startup banner 57func Banner(version string) { 58 banner := ` 59╔════════════════════════════════════════════════════════════╗ 60║ ║ 61║ █████╗ ████████╗███████╗ ██████╗ █████╗ ███╗ ██╗ ║ 62║ ██╔══██╗╚══██╔══╝██╔════╝██╔════╝██╔══██╗████╗ ██║ ║ 63║ ███████║ ██║ ███████╗██║ ███████║██╔██╗ ██║ ║ 64║ ██╔══██║ ██║ ╚════██║██║ ██╔══██║██║╚██╗██║ ║ 65║ ██║ ██║ ██║ ███████║╚██████╗██║ ██║██║ ╚████║ ║ 66║ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝ ║ 67║ ║ 68║ AT Protocol Network Scanner & Indexer ║ 69║ Version %s ║ 70║ ║ 71╚════════════════════════════════════════════════════════════╝ 72` 73 fmt.Printf(banner, padVersion(version)) 74} 75 76// padVersion pads the version string to fit the banner 77func padVersion(version string) string { 78 targetLen := 7 79 if len(version) < targetLen { 80 padding := strings.Repeat(" ", (targetLen-len(version))/2) 81 return padding + version + padding 82 } 83 return version 84} 85 86// RedactPassword redacts passwords from connection strings 87func RedactPassword(connStr string) string { 88 // Handle PostgreSQL URI format: postgresql://user:password@host/db 89 // Pattern: find everything between :// and @ that contains a colon 90 if strings.Contains(connStr, "://") && strings.Contains(connStr, "@") { 91 // Find the credentials section 92 parts := strings.SplitN(connStr, "://", 2) 93 if len(parts) == 2 { 94 scheme := parts[0] 95 remainder := parts[1] 96 97 // Find the @ symbol 98 atIndex := strings.Index(remainder, "@") 99 if atIndex > 0 { 100 credentials := remainder[:atIndex] 101 hostAndDb := remainder[atIndex:] 102 103 // Check if there's a password (look for colon in credentials) 104 colonIndex := strings.Index(credentials, ":") 105 if colonIndex > 0 { 106 username := credentials[:colonIndex] 107 return fmt.Sprintf("%s://%s:***%s", scheme, username, hostAndDb) 108 } 109 } 110 } 111 } 112 113 // Handle key-value format: host=localhost password=secret user=myuser 114 if strings.Contains(connStr, "password=") { 115 parts := strings.Split(connStr, " ") 116 for i, part := range parts { 117 if strings.HasPrefix(part, "password=") { 118 parts[i] = "password=***" 119 } 120 } 121 return strings.Join(parts, " ") 122 } 123 124 return connStr 125} 126 127// PrintConfig prints configuration summary 128func PrintConfig(items map[string]string) { 129 Info("=== Configuration ===") 130 maxKeyLen := 0 131 for key := range items { 132 if len(key) > maxKeyLen { 133 maxKeyLen = len(key) 134 } 135 } 136 137 for key, value := range items { 138 padding := strings.Repeat(" ", maxKeyLen-len(key)) 139 140 // Redact database connection strings 141 displayValue := value 142 if strings.Contains(key, "Database Path") || strings.Contains(key, "Connection") || strings.Contains(strings.ToLower(key), "password") { 143 displayValue = RedactPassword(value) 144 } 145 146 fmt.Printf(" %s:%s %s\n", key, padding, displayValue) 147 } 148 Info("====================") 149}