90 lines
2.1 KiB
Go
90 lines
2.1 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() {
|
||
|
// 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)
|
||
|
}
|