package mailmux import ( "bufio" "errors" "fmt" "io" "math/rand" "os" "strings" ) func randomLine(f *os.File) (string, error) { fi, err := f.Stat() if err != nil { return "", err } offset := rand.Int63n(fi.Size()) offset, err = f.Seek(offset, io.SeekStart) if err != nil { return "", err } br := bufio.NewReader(f) for { b, err := br.ReadByte() if b == '\n' { break } if err != nil { return "", err } } line, err := br.ReadString('\n') if errors.Is(err, io.EOF) { // the file ends without a newline - no problem } else if err != nil { return "", err } line = strings.TrimSpace(line) if line == "" { // empty line. we're either at the end or hit a blank line. try again return randomLine(f) } return line, nil } // RandomUsername generates a random username from the dictionary file at dictpath. // The dictionary file should be a newline delimited text file, one word per line. // On Unix systems, the file /usr/share/dic/words is a suitable file. func RandomUsername(dictpath string) (string, error) { f, err := os.Open(dictpath) if err != nil { return "", fmt.Errorf("open dictionary: %w", err) } defer f.Close() first, err := randomLine(f) if err != nil { return "", fmt.Errorf("first random word: %w", err) } first = strings.ToLower(first) second, err := randomLine(f) if err != nil { return "", fmt.Errorf("second random word: %w", err) } second = strings.ToLower(second) return fmt.Sprintf("%s_%s%02d", first, second, rand.Intn(99)), nil }