This repository has been archived on 2024-03-16. You can view files and clone it, but cannot push or open issues or pull requests.
maddy-hostux-check-password/main.go

113 lines
2.6 KiB
Go

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() {
// Opens the SQLite database
dbFile, dbFileSet := os.LookupEnv("HOSTUX_EMAIL_DATABASE_SQLITE")
if !dbFileSet {
logMessage("Environment variable HOSTUX_EMAIL_DATABASE_SQLITE must be set.")
os.Exit(2)
}
db, err := sql.Open("sqlite3", dbFile)
if err != nil {
logMessage("Error opening database:", err)
os.Exit(2)
}
defer db.Close()
// Reads stdin input (email address, password, each ends with \n)
var emailAddress, password string
logMessage("Enter email address:")
fmt.Scanln(&emailAddress)
logMessage("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 {
logMessage("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 {
logMessage("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 {
logMessage("Database error: ", err)
os.Exit(2)
}
logMessage("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
logMessage("Authentication failed: account not found or password incorrect")
os.Exit(1)
}
func logMessage(args ...interface{}) error {
// Print the message to the console
fmt.Println(args...)
// Log to file if required
logFile, logFileSet := os.LookupEnv("HOSTUX_EMAIL_CHECKPW_LOGFILE")
if logFileSet {
// Open the file in append mode, create it if it doesn't exist
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
// Write the message to the file
_, err = fmt.Fprintln(file, args...)
if err != nil {
return err
}
}
return nil
}