// $TheSupernovaDuo: akyuu,v master 2023/4/14 21:2:6 yakumo_izuru Exp $ // See LICENSE for copyright details package main import ( "bufio" "errors" "log" "os" "strings" ) const ( loginsFile = "logins.txt" feedsDir = "feeds" ipDelaysFile = "ip_delays.txt" pwResetFile = "password_reset.txt" pwResetWaitFile = "password_reset_wait.txt" ) var ( certPath string dataDir string feedsPath string ipDelaysPath string keyPath string loginsPath string pwResetPath string pwResetWaitPath string templPath string ) func createFileIfNotExists(path string) { if _, err := os.Stat(path); err != nil { file, err := os.Create(path) if err != nil { log.Fatal("Can't create file: ", err) } file.Close() } } func openFile(path string) *os.File { file, err := os.Open(path) if err != nil { file.Close() log.Fatal("Can't open file for reading", err) } return file } func linesFromFile(path string) []string { text, err := os.ReadFile(path) if err != nil { log.Fatal("Can't read file", err) } if string(text) == "" { return []string{} } return strings.Split(string(text), "\n") } func writeAtomic(path, text string) { tmpFile := path + "_tmp" if err := os.WriteFile(tmpFile, []byte(text), 0600); err != nil { log.Fatal("Trouble writing file", err) } if err := os.Rename(path, path+"_"); err != nil { log.Fatal("Trouble moving file", err) } if err := os.Rename(tmpFile, path); err != nil { log.Fatal("Trouble moving file", err) } if err := os.Remove(path + "_"); err != nil { log.Fatal("Trouble removing file", err) } } func writeLinesAtomic(path string, lines []string) { writeAtomic(path, strings.Join(lines, "\n")) } func appendToFile(path string, msg string) { text, err := os.ReadFile(path) if err != nil { log.Fatal("Can't read file", err) } writeAtomic(path, string(text)+msg+"\n") } func removeLineStartingWith(path, token string) { lines := linesFromFile(path) lineNumber := -1 for lineCount := 0; lineCount < len(lines); lineCount += 1 { line := lines[lineCount] tokens := strings.Split(line, "\t") if 0 == strings.Compare(token, tokens[0]) { lineNumber = lineCount break } } lines = append(lines[:lineNumber], lines[lineNumber+1:]...) writeLinesAtomic(path, lines) } func removeLineFromFile(path string, lineNumber int) { lines := linesFromFile(ipDelaysPath) lines = append(lines[:lineNumber], lines[lineNumber+1:]...) writeLinesAtomic(path, lines) } func replaceLineStartingWith(path, token, newLine string) { lines := linesFromFile(path) for i, line := range lines { tokens := strings.Split(line, "\t") if 0 == strings.Compare(token, tokens[0]) { lines[i] = newLine break } } writeLinesAtomic(path, lines) } func tokensFromLine(scanner *bufio.Scanner, nTokensExpected int) []string { if !scanner.Scan() { return []string{} } line := scanner.Text() tokens := strings.Split(line, "\t") if len(tokens) != nTokensExpected { log.Fatal("Line in file had unexpected number of tokens") } return tokens } func getFromFileEntryFor(path, token string, numberTokensExpected int) ([]string, error) { file := openFile(path) defer file.Close() scanner := bufio.NewScanner(bufio.NewReader(file)) tokens := tokensFromLine(scanner, numberTokensExpected) for 0 != len(tokens) { if 0 == strings.Compare(tokens[0], token) { return tokens[1:], nil } tokens = tokensFromLine(scanner, numberTokensExpected) } return []string{}, errors.New("") } func initFilesAndDirs() { log.Println("Using as templates dir:", templPath) log.Println("Using as data dir:", dataDir) loginsPath = dataDir + "/" + loginsFile feedsPath = dataDir + "/" + feedsDir ipDelaysPath = dataDir + "/" + ipDelaysFile pwResetPath = dataDir + "/" + pwResetFile pwResetWaitPath = dataDir + "/" + pwResetWaitFile if "" != keyPath { log.Println("Using TLS.") if _, err := os.Stat(certPath); err != nil { log.Fatal("No certificate file found.") } if _, err := os.Stat(keyPath); err != nil { log.Fatal("No server key file found.") } } createFileIfNotExists(loginsPath) createFileIfNotExists(pwResetPath) createFileIfNotExists(pwResetWaitPath) createFileIfNotExists(ipDelaysPath) _ = os.Mkdir(feedsPath, 0700) }