first working commit
This commit is contained in:
commit
0a2077c04c
5 changed files with 133 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*.sqlite
|
||||||
|
build
|
30
Makefile
Normal file
30
Makefile
Normal file
|
@ -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)
|
8
go.mod
Normal file
8
go.mod
Normal file
|
@ -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
|
||||||
|
)
|
4
go.sum
Normal file
4
go.sum
Normal file
|
@ -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=
|
89
main.go
Normal file
89
main.go
Normal file
|
@ -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)
|
||||||
|
}
|
Reference in a new issue