commit 0a2077c04c6094a2ce997a1905077bc17b807715 Author: Louis Guidez Date: Tue Feb 27 13:39:34 2024 +0000 first working commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f8c0c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.sqlite +build \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ed35b99 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +# Makefile for building the Go module +APP_NAME := maddy-hostux-check-password + +# Set the source directory +SRC_DIR := . + +# Go files +SRC := $(wildcard $(SRC_DIR)/*.go) + +# Build directory +BUILD_DIR := ./build + +# Set the Go compiler +GO := go + +# Flags for go build +BUILD_FLAGS := -o $(BUILD_DIR)/$(APP_NAME) + +.PHONY: all build clean + +all: build + +build: $(BUILD_DIR)/$(APP_NAME) + +$(BUILD_DIR)/$(APP_NAME): $(SRC) + @mkdir -p $(BUILD_DIR) + $(GO) build $(BUILD_FLAGS) $(SRC_DIR) + +clean: + rm -rf $(BUILD_DIR) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..58a1c0a --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module main + +go 1.21.6 + +require ( + github.com/mattn/go-sqlite3 v1.14.22 + golang.org/x/crypto v0.20.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4a9a217 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000..61bbd13 --- /dev/null +++ b/main.go @@ -0,0 +1,89 @@ +package main + +import ( + "database/sql" + "fmt" + "os" + "time" + + _ "github.com/mattn/go-sqlite3" + "golang.org/x/crypto/bcrypt" +) + +/** + * Exit codes: + * 0: authentication successful + * 1: authentication failed (email address not found or password mismatch + * 2: other error + */ +func main() { + // Checks usage + if len(os.Args) != 2 { + fmt.Println("Usage: hostux_check_credentials [database.sqlite]") + os.Exit(2) + } + + // Opens the SQLite database + dbFile := os.Args[1] + db, err := sql.Open("sqlite3", dbFile) + if err != nil { + fmt.Println("Error opening database:", err) + os.Exit(2) + } + defer db.Close() + + // Reads stdin input (email address, password, each ends with \n) + var emailAddress, password string + fmt.Println("Enter email address:") + fmt.Scanln(&emailAddress) + fmt.Println("Enter password:") + fmt.Scanln(&password) + + // Finds database records + rows, err := db.Query(`SELECT eap.id, eap.password FROM "email-addresses" AS ea + LEFT JOIN "email-addresses-passwords" AS eap ON ea.emailAddress = eap.emailAddress + WHERE ea.emailAddress = ?`, emailAddress) + if err != nil { + fmt.Println("Database error: ", err) + os.Exit(2) + } + defer rows.Close() + + // Loops through records + for rows.Next() { + var hashedPassword string + var id int + + err := rows.Scan(&id, &hashedPassword) + if err != nil { + fmt.Println("Database error: ", err) + os.Exit(2) + } + + // Compares provided password with database + err = bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) + if err == nil { + // No error = the passwords match + // Update lastAccess time + rows.Close() + _, err := db.Exec(`UPDATE "email-addresses-passwords" + SET lastAccess = ? + WHERE id = ?`, time.Now().Format(time.RFC3339), id) + + if err != nil { + fmt.Println("Database error: ", err) + os.Exit(2) + } + + fmt.Println("Authentication successful") + os.Exit(0) + } + } + + // If we have not returned by now, it means that: + // * either there were no records + // * or no record matched the provided password + + fmt.Println("Authentication failed: account not found or password incorrect") + os.Exit(1) +}