101 lines
2.7 KiB
Go
101 lines
2.7 KiB
Go
/*
|
|
* This API call authenticates a user
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
type AuthenticateRequest struct {
|
|
Accountid int64 `json:"accountid,string"`
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
func authenticateHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
var authenticaterequest AuthenticateRequest
|
|
var err error
|
|
var checkExisting pgx.Row
|
|
var hashText string
|
|
var ok bool
|
|
|
|
response := map[string]interface{}{}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
// Only allow POST method
|
|
if r.Method != http.MethodPost {
|
|
//http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
response["status"] = "error"
|
|
response["message"] = "HTTP POST Method not allowed"
|
|
goto ExitAPICall
|
|
}
|
|
|
|
// Optional: enforce content type
|
|
if r.Header.Get("Content-Type") != "application/json" {
|
|
w.WriteHeader(http.StatusUnsupportedMediaType)
|
|
response["status"] = "error"
|
|
response["message"] = "Content-Type must be application/json"
|
|
goto ExitAPICall
|
|
}
|
|
|
|
// Read body with size limit (protect against huge requests)
|
|
const maxBodyBytes = 1 << 20 // 1 MB
|
|
r.Body = http.MaxBytesReader(w, r.Body, maxBodyBytes)
|
|
|
|
// Decode JSON from request body directly into struct
|
|
log.Println(r.Body)
|
|
err = json.NewDecoder(r.Body).Decode(&authenticaterequest)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
response["status"] = "error"
|
|
response["message"] = "Invalid JSON: " + err.Error()
|
|
goto ExitAPICall
|
|
}
|
|
|
|
log.Println(authenticaterequest)
|
|
|
|
checkExisting = pool.QueryRow(context.Background(),
|
|
"SELECT password_hash FROM identities WHERE accountid = $1 AND provider = $2 AND provider_user_id = $3",
|
|
authenticaterequest.Accountid, "local", authenticaterequest.Username)
|
|
|
|
log.Println("Received Authentication Request: AccountID:", authenticaterequest.Accountid, "Username:", authenticaterequest.Username, "Password:", authenticaterequest.Password)
|
|
|
|
err = checkExisting.Scan(&hashText)
|
|
if err != nil {
|
|
response["status"] = "fail"
|
|
response["message"] = "User account does not exist"
|
|
log.Println(err)
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
goto ExitAPICall
|
|
}
|
|
|
|
log.Println(hashText)
|
|
|
|
ok = verifyPassword(authenticaterequest.Password, hashText)
|
|
if ok == false {
|
|
response["status"] = "fail"
|
|
response["message"] = "Bad password"
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
goto ExitAPICall
|
|
}
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
response["status"] = "success"
|
|
ExitAPICall:
|
|
w.Header().Set("Content-Type", "application/json")
|
|
response["timestamp"] = fmt.Sprintf("%d", time.Now().Unix())
|
|
json.NewEncoder(w).Encode(response)
|
|
|
|
}
|