Add user/password login handler.

This commit is contained in:
Kailash Nadh 2024-04-10 00:20:48 +05:30
parent bc80600e57
commit 2c14cf49e9
7 changed files with 59 additions and 3 deletions

View file

@ -156,3 +156,30 @@ func handleDeleteUsers(c echo.Context) error {
return c.JSON(http.StatusOK, okResp{true})
}
// handleLoginUser logs a user in with a username and password.
func handleLoginUser(c echo.Context) error {
var (
app = c.Get("app").(*App)
)
u := struct {
Username string `json:"username"`
Password string `json:"password"`
}{}
if !strHasLen(u.Username, 1, stdInputMaxLen) {
return echo.NewHTTPError(http.StatusBadRequest, app.i18n.Ts("globals.messages.invalidFields", "name", "username"))
}
if !strHasLen(u.Password, 8, stdInputMaxLen) {
return echo.NewHTTPError(http.StatusBadRequest, app.i18n.Ts("globals.messages.invalidFields", "name", "password"))
}
_, err := app.core.LoginUser(u.Username, u.Password)
if err != nil {
return err
}
return c.JSON(http.StatusOK, okResp{true})
}

View file

@ -603,8 +603,9 @@
"users.username": "Username",
"users.usernameHelp": "Used with password login",
"users.password": "Password",
"users.invalidLogin": "Invalid username or password",
"users.passwordRepeat": "Repeat password",
"users.passwordEnable": "Enable password login",
"users.passwordEnable": "Enable logging in with password",
"users.passwordMismatch": "Passwords don't match",
"users.cantDelete": "User(s) couldn't be deleted. There has to be at least one 'super' user."
}

View file

@ -1,6 +1,7 @@
package core
import (
"database/sql"
"net/http"
"github.com/knadh/listmonk/models"
@ -86,3 +87,19 @@ func (c *Core) DeleteUsers(ids []int) error {
return nil
}
// LoginUser attempts to log the given user_id in by matching the password.
func (c *Core) LoginUser(username, password string) (models.User, error) {
var out models.User
if err := c.q.LoginUser.Get(&out, username, password); err != nil {
if err == sql.ErrNoRows {
return out, echo.NewHTTPError(http.StatusForbidden,
c.i18n.T("users.invalidLogin"))
}
return out, echo.NewHTTPError(http.StatusInternalServerError,
c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.users}", "error", pqErrMsg(err)))
}
return out, nil
}

View file

@ -12,6 +12,8 @@ import (
func V3_1_0(db *sqlx.DB, fs stuffbin.FileSystem, ko *koanf.Koanf, lo *log.Logger) error {
if _, err := db.Exec(`
DO $$
CREATE EXTENSION IF NOT EXISTS pgcrypto;
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'user_status') THEN
CREATE TYPE user_status AS ENUM ('enabled', 'disabled', 'super');

View file

@ -112,6 +112,7 @@ type Queries struct {
UpdateUser *sqlx.Stmt `query:"update-user"`
DeleteUsers *sqlx.Stmt `query:"delete-users"`
GetUsers *sqlx.Stmt `query:"get-users"`
LoginUser *sqlx.Stmt `query:"login-user"`
}
// CompileSubscriberQueryTpl takes an arbitrary WHERE expressions

View file

@ -1025,13 +1025,13 @@ SELECT JSON_BUILD_OBJECT('version', (SELECT VERSION()),
'size_mb', (SELECT ROUND(pg_database_size((SELECT CURRENT_DATABASE()))/(1024^2)))) AS info;
-- name: create-user
INSERT INTO users (username, password_login, password, email, name, status) VALUES($1, $2, $3, $4, $5, $6) RETURNING *;
INSERT INTO users (username, password_login, password, email, name, status) VALUES($1, $2, (CASE WHEN $2 AND $3 != '' THEN CRYPT($3, GEN_SALT('bf')) ELSE NULL END), $4, $5, $6) RETURNING *;
-- name: update-user
UPDATE users SET
username=(CASE WHEN $2 != '' THEN $2 ELSE username END),
password_login=$3,
password=(CASE WHEN $3 = TRUE THEN (CASE WHEN $4 != '' THEN $4 ELSE password END) ELSE NULL END),
password=(CASE WHEN $3 = TRUE THEN (CASE WHEN $4 != '' THEN CRYPT($4, GEN_SALT('bf')) ELSE password END) ELSE NULL END),
email=(CASE WHEN $5 != '' THEN $5 ELSE email END),
name=(CASE WHEN $6 != '' THEN $6 ELSE name END),
status=(CASE WHEN $7 != '' THEN $7::user_status ELSE status END)
@ -1045,3 +1045,9 @@ DELETE FROM users WHERE id = ALL($1) AND (SELECT num FROM u) > 0;
-- name: get-users
SELECT * FROM users WHERE $1=0 OR id=$1 ORDER BY created_at;
-- name: login-user
WITH u AS (
SELECT * FROM users WHERE username=$1 AND status = 'enabled' AND password_login = TRUE
)
SELECT * FROM u WHERE CRYPT($2, password) = password;

View file

@ -9,6 +9,8 @@ DROP TYPE IF EXISTS bounce_type CASCADE; CREATE TYPE bounce_type AS ENUM ('soft'
DROP TYPE IF EXISTS template_type CASCADE; CREATE TYPE template_type AS ENUM ('campaign', 'tx');
DROP TYPE IF EXISTS user_status CASCADE; CREATE TYPE user_status AS ENUM ('enabled', 'disabled', 'super');
CREATE EXTENSION pgcrypto;
-- subscribers
DROP TABLE IF EXISTS subscribers CASCADE;
CREATE TABLE subscribers (