Browse Source

FIX: Image not being saved on ToDo drag&drop category change; FEATURE: Using emails instead of logins

master
parent
commit
c14ca0f431
  1. 12
      pages/category.html
  2. 24
      pages/login.html
  3. 29
      pages/register.html
  4. 14
      src/db/db.go
  5. 10
      src/db/db_test.go
  6. 26
      src/db/group.go
  7. 36
      src/db/todo.go
  8. 36
      src/db/user.go
  9. 8
      src/server/api_test.go
  10. 48
      src/server/endpoints.go
  11. 48
      src/server/validation.go

12
pages/category.html

@ -111,9 +111,9 @@
<tr draggable="true" id="todo-{{.ID}}" ondragstart="dragStart(event);">
{{ if not .Image }}
<!-- Display transparent white pixel -->
<td><img src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' width="64px" height="64px"></td>
<td><img class="todo-image" src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' width="64px" height="64px"></td>
{{ else }}
<td><img src='{{ printf "%s" .Image }}' width="64px" height="64px"></td>
<td><img class="todo-image" src='{{ printf "%s" .Image }}' width="64px" height="64px"></td>
{{ end }}
<td class="todo-text text-wrap text-break">{{ .Text }}</td>
<td class="todo-created">{{ .TimeCreated }}</td>
@ -240,15 +240,15 @@ async function drop(event) {
return;
}
// Add a copy of this ToDo in the corresponding group
let result = await postNewTodo({
// Update todo's group ID
let result = await updateTodo(todoId, {
text: draggedTodo.getElementsByClassName("todo-text")[0].innerText,
groupId: Number(targetGroupId),
dueUnix: Number(draggedTodo.getElementsByClassName("todo-due-unix")[0].innerText),
image: Array.from(draggedTodo.getElementsByClassName("todo-image")[0].src, char => char.charCodeAt(0))
});
// Delete this ToDo in this group
await deleteTodoRefresh(todoId);
window.location.reload();
}
document.addEventListener('DOMContentLoaded', async function() {

24
pages/login.html

@ -8,14 +8,14 @@
<h3 class="h3 mb-3 fw-normal">Log in</h3>
<form onsubmit="return false;">
<div class="mb-3 input-group">
<img src="/static/images/universal-access.svg" alt="Login" class="input-group-text">
<img src="/static/images/envelope-at.svg" alt="Email" class="input-group-text">
<input
type="text"
type="email"
class="form-control"
id="input-login"
aria-describedby="Login"
aria-label="Login"
placeholder="Login"
id="input-email"
aria-describedby="Email"
aria-label="email@example.com"
placeholder="email@example.com"
required
minlength="3">
</div>
@ -42,21 +42,21 @@
<script>
async function logIn() {
let loginInput = document.getElementById("input-login");
let login = String(loginInput.value).trim();
if (login.length < 3) {
let emailInput = document.getElementById("input-email");
if (!emailInput.reportValidity()) {
return;
}
let email = String(emailInput.value).trim();
let passwordInput = document.getElementById("input-password");
let password = String(passwordInput.value);
if (password.length < 3) {
if (!passwordInput.reportValidity()) {
return;
}
let password = String(passwordInput.value);
password = sha256(password);
// Check if auth info is indeed valid
let response = await doLogin({login: login, password: password});
let response = await doLogin({email: email, password: password});
if (response.ok) {
window.location.replace("/");
} else {

29
pages/register.html

@ -8,19 +8,6 @@
<img src="/static/images/info-circle.svg" alt="Information"></span>
</h3>
<form onsubmit="return false;">
<div class="mb-3 input-group">
<img src="/static/images/universal-access.svg" alt="Login" class="input-group-text">
<input
type="text"
class="form-control"
id="input-login"
aria-describedby="Login"
aria-label="Login"
placeholder="Login"
required
minlength="3">
</div>
<div class="mb-3 input-group">
<img src="/static/images/envelope-at.svg" alt="Email" class="input-group-text">
<input
@ -55,27 +42,21 @@
<script>
async function register() {
let loginInput = document.getElementById("input-login");
let login = String(loginInput.value).trim();
if (login.length < 3) {
return;
}
let emailInput = document.getElementById("input-email");
let email = String(emailInput.value).trim();
if (email.length < 3) {
if (!emailInput.reportValidity()) {
return;
}
let email = String(emailInput.value).trim();
let passwordInput = document.getElementById("input-password");
let password = String(passwordInput.value);
if (password.length < 3) {
if (!passwordInput.reportValidity()) {
return;
}
let password = String(passwordInput.value);
let passwordSHA256 = sha256(password);
let postData = {
login: login,
email: email,
password: passwordSHA256,
};

14
src/db/db.go

@ -33,10 +33,10 @@ type DB struct {
func setUpTables(db *DB) error {
// Users
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS users(
login TEXT PRIMARY KEY UNIQUE,
email TEXT NOT NULL UNIQUE,
email TEXT PRIMARY KEY UNIQUE,
password TEXT NOT NULL,
time_created_unix INTEGER)`,
time_created_unix INTEGER,
confirmed_email INTEGER)`,
)
if err != nil {
return err
@ -47,9 +47,9 @@ func setUpTables(db *DB) error {
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT,
time_created_unix INTEGER,
owner_login TEXT NOT NULL,
owner_email TEXT NOT NULL,
removable INTEGER,
FOREIGN KEY(owner_login) REFERENCES users(login))`,
FOREIGN KEY(owner_email) REFERENCES users(email))`,
)
if err != nil {
return err
@ -62,12 +62,12 @@ func setUpTables(db *DB) error {
text TEXT NOT NULL,
time_created_unix INTEGER,
due_unix INTEGER,
owner_login TEXT NOT NULL,
owner_email TEXT NOT NULL,
is_done INTEGER,
completion_time_unix INTEGER,
image BLOB,
FOREIGN KEY(group_id) REFERENCES todo_groups(id),
FOREIGN KEY(owner_login) REFERENCES users(login))`,
FOREIGN KEY(owner_email) REFERENCES users(email))`,
)
if err != nil {
return err

10
src/db/db_test.go

@ -32,7 +32,7 @@ func TestApi(t *testing.T) {
// User
user := User{
Login: "user1",
Email: "user1@mail.ru",
Password: "ruohguoeruoger",
TimeCreatedUnix: 12421467,
}
@ -42,7 +42,7 @@ func TestApi(t *testing.T) {
t.Fatalf("failed to create user: %s", err)
}
dbUser, err := db.GetUser(user.Login)
dbUser, err := db.GetUser(user.Email)
if err != nil {
t.Fatalf("failed to retrieve created user: %s", err)
}
@ -55,7 +55,7 @@ func TestApi(t *testing.T) {
group := TodoGroup{
Name: "group1",
TimeCreatedUnix: 13524534,
OwnerLogin: user.Login,
OwnerEmail: user.Email,
}
err = db.CreateTodoGroup(group)
@ -82,7 +82,7 @@ func TestApi(t *testing.T) {
Text: "Do the dishes",
TimeCreatedUnix: dbGroup.TimeCreatedUnix,
DueUnix: 0,
OwnerLogin: user.Login,
OwnerEmail: user.Email,
}
err = db.CreateTodo(todo)
if err != nil {
@ -90,7 +90,7 @@ func TestApi(t *testing.T) {
}
// Now deletion
err = db.DeleteUserClean(user.Login)
err = db.DeleteUserClean(user.Email)
if err != nil {
t.Fatalf("couldn't cleanly delete user with all TODOs: %s", err)
}

26
src/db/group.go

@ -20,7 +20,6 @@ package db
import (
"database/sql"
"time"
)
// Todo group structure
@ -28,16 +27,16 @@ type TodoGroup struct {
ID uint64 `json:"id"`
Name string `json:"name"`
TimeCreatedUnix uint64 `json:"timeCreatedUnix"`
OwnerLogin string `json:"ownerLogin"`
OwnerEmail string `json:"ownerEmail"`
Removable bool `json:"removable"`
TimeCreated string
}
func NewTodoGroup(name string, timeCreatedUnix uint64, ownerLogin string, removable bool) TodoGroup {
func NewTodoGroup(name string, timeCreatedUnix uint64, ownerEmail string, removable bool) TodoGroup {
return TodoGroup{
Name: name,
TimeCreatedUnix: timeCreatedUnix,
OwnerLogin: ownerLogin,
OwnerEmail: ownerEmail,
Removable: removable,
}
}
@ -45,10 +44,10 @@ func NewTodoGroup(name string, timeCreatedUnix uint64, ownerLogin string, remova
// Creates a new TODO group in the database
func (db *DB) CreateTodoGroup(group TodoGroup) error {
_, err := db.Exec(
"INSERT INTO todo_groups(name, time_created_unix, owner_login, removable) VALUES(?, ?, ?, ?)",
"INSERT INTO todo_groups(name, time_created_unix, owner_email, removable) VALUES(?, ?, ?, ?)",
group.Name,
group.TimeCreatedUnix,
group.OwnerLogin,
group.OwnerEmail,
group.Removable,
)
@ -61,20 +60,15 @@ func scanTodoGroup(rows *sql.Rows) (*TodoGroup, error) {
&newTodoGroup.ID,
&newTodoGroup.Name,
&newTodoGroup.TimeCreatedUnix,
&newTodoGroup.OwnerLogin,
&newTodoGroup.OwnerEmail,
&newTodoGroup.Removable,
)
if err != nil {
return nil, err
}
// Convert to Basic time
timeCreated := time.Unix(int64(newTodoGroup.TimeCreatedUnix), 0)
if timeCreated.Year() == 1970 {
newTodoGroup.TimeCreated = "None"
} else {
newTodoGroup.TimeCreated = timeCreated.Format(time.DateOnly)
}
// Convert to Basic time string
newTodoGroup.TimeCreated = unixToTimeStr(newTodoGroup.TimeCreatedUnix)
return &newTodoGroup, nil
}
@ -178,13 +172,13 @@ func (db *DB) UpdateTodoGroup(groupID uint64, updatedGroup TodoGroup) error {
return err
}
func (db *DB) DoesUserOwnGroup(groupId uint64, login string) bool {
func (db *DB) DoesUserOwnGroup(groupId uint64, email string) bool {
group, err := db.GetTodoGroup(groupId)
if err != nil {
return false
}
if group.OwnerLogin != login {
if group.OwnerEmail != email {
return false
}

36
src/db/todo.go

@ -30,7 +30,7 @@ type Todo struct {
Text string `json:"text"`
TimeCreatedUnix uint64 `json:"timeCreatedUnix"`
DueUnix uint64 `json:"dueUnix"`
OwnerLogin string `json:"ownerLogin"`
OwnerEmail string `json:"ownerEmail"`
IsDone bool `json:"isDone"`
CompletionTimeUnix uint64 `json:"completionTimeUnix"`
Image []byte `json:"image"`
@ -56,7 +56,7 @@ func scanTodo(rows *sql.Rows) (*Todo, error) {
&newTodo.Text,
&newTodo.TimeCreatedUnix,
&newTodo.DueUnix,
&newTodo.OwnerLogin,
&newTodo.OwnerEmail,
&newTodo.IsDone,
&newTodo.CompletionTimeUnix,
&newTodo.Image,
@ -117,12 +117,12 @@ func (db *DB) GetTodos() ([]*Todo, error) {
// Creates a new TODO in the database
func (db *DB) CreateTodo(todo Todo) error {
_, err := db.Exec(
"INSERT INTO todos(group_id, text, time_created_unix, due_unix, owner_login, is_done, completion_time_unix, image) VALUES(?, ?, ?, ?, ?, ?, ?, ?)",
"INSERT INTO todos(group_id, text, time_created_unix, due_unix, owner_email, is_done, completion_time_unix, image) VALUES(?, ?, ?, ?, ?, ?, ?, ?)",
todo.GroupID,
todo.Text,
todo.TimeCreatedUnix,
todo.DueUnix,
todo.OwnerLogin,
todo.OwnerEmail,
todo.IsDone,
todo.CompletionTimeUnix,
todo.Image,
@ -158,12 +158,12 @@ func (db *DB) UpdateTodo(todoID uint64, updatedTodo Todo) error {
}
// Searches and retrieves TODO groups created by the user
func (db *DB) GetAllUserTodoGroups(login string) ([]*TodoGroup, error) {
func (db *DB) GetAllUserTodoGroups(email string) ([]*TodoGroup, error) {
var todoGroups []*TodoGroup
rows, err := db.Query(
"SELECT * FROM todo_groups WHERE owner_login=?",
login,
"SELECT * FROM todo_groups WHERE owner_email=?",
email,
)
if err != nil {
return nil, err
@ -182,12 +182,12 @@ func (db *DB) GetAllUserTodoGroups(login string) ([]*TodoGroup, error) {
}
// Searches and retrieves TODOs created by the user
func (db *DB) GetAllUserTodos(login string) ([]*Todo, error) {
func (db *DB) GetAllUserTodos(email string) ([]*Todo, error) {
var todos []*Todo
rows, err := db.Query(
"SELECT * FROM todos WHERE owner_login=?",
login,
"SELECT * FROM todos WHERE owner_email=?",
email,
)
if err != nil {
return nil, err
@ -207,32 +207,32 @@ func (db *DB) GetAllUserTodos(login string) ([]*Todo, error) {
}
// Deletes all information regarding TODOs of specified user
func (db *DB) DeleteAllUserTodos(login string) error {
func (db *DB) DeleteAllUserTodos(email string) error {
_, err := db.Exec(
"DELETE FROM todos WHERE owner_login=?",
login,
"DELETE FROM todos WHERE owner_email=?",
email,
)
return err
}
// Deletes all information regarding TODO groups of specified user
func (db *DB) DeleteAllUserTodoGroups(login string) error {
func (db *DB) DeleteAllUserTodoGroups(email string) error {
_, err := db.Exec(
"DELETE FROM todo_groups WHERE owner_login=?",
login,
"DELETE FROM todo_groups WHERE owner_email=?",
email,
)
return err
}
func (db *DB) DoesUserOwnTodo(todoId uint64, login string) bool {
func (db *DB) DoesUserOwnTodo(todoId uint64, email string) bool {
todo, err := db.GetTodo(todoId)
if err != nil {
return false
}
if todo.OwnerLogin != login {
if todo.OwnerEmail != email {
return false
}

36
src/db/user.go

@ -22,16 +22,16 @@ import "database/sql"
// User structure
type User struct {
Login string `json:"login"`
Email string `json:"email"`
Password string `json:"password"`
TimeCreatedUnix uint64 `json:"timeCreatedUnix"`
ConfirmedEmail bool `json:"confirmedEmail"`
}
func scanUser(rows *sql.Rows) (*User, error) {
rows.Next()
var user User
err := rows.Scan(&user.Login, &user.Email, &user.Password, &user.TimeCreatedUnix)
err := rows.Scan(&user.Email, &user.Password, &user.TimeCreatedUnix, &user.ConfirmedEmail)
if err != nil {
return nil, err
}
@ -39,9 +39,9 @@ func scanUser(rows *sql.Rows) (*User, error) {
return &user, nil
}
// Searches for user with login and returns it
func (db *DB) GetUser(login string) (*User, error) {
rows, err := db.Query("SELECT * FROM users WHERE login=?", login)
// Searches for user with email and returns it
func (db *DB) GetUser(email string) (*User, error) {
rows, err := db.Query("SELECT * FROM users WHERE email=?", email)
if err != nil {
return nil, err
}
@ -58,50 +58,52 @@ func (db *DB) GetUser(login string) (*User, error) {
// Creates a new user in the database
func (db *DB) CreateUser(newUser User) error {
_, err := db.Exec(
"INSERT INTO users(login, email, password, time_created_unix) VALUES(?, ?, ?, ?)",
newUser.Login,
"INSERT INTO users(email, password, time_created_unix, confirmed_email) VALUES(?, ?, ?, ?)",
newUser.Email,
newUser.Password,
newUser.TimeCreatedUnix,
newUser.ConfirmedEmail,
)
return err
}
// Deletes user with given login
func (db *DB) DeleteUser(login string) error {
// Deletes user with given email address
func (db *DB) DeleteUser(email string) error {
_, err := db.Exec(
"DELETE FROM users WHERE login=?",
login,
"DELETE FROM users WHERE email=?",
email,
)
return err
}
// Updades user's email address, password, email confirmation with given email address
func (db *DB) UserUpdate(newUser User) error {
_, err := db.Exec(
"UPDATE users SET email=? password=? WHERE login=?",
"UPDATE users SET email=?, password=?, confirmed_email=? WHERE email=?",
newUser.Email,
newUser.Password,
newUser.Login,
newUser.ConfirmedEmail,
newUser.Email,
)
return err
}
// Deletes a user and all his TODOs (with groups) as well
func (db *DB) DeleteUserClean(login string) error {
err := db.DeleteAllUserTodoGroups(login)
func (db *DB) DeleteUserClean(email string) error {
err := db.DeleteAllUserTodoGroups(email)
if err != nil {
return err
}
err = db.DeleteAllUserTodos(login)
err = db.DeleteAllUserTodos(email)
if err != nil {
return err
}
err = db.DeleteUser(login)
err = db.DeleteUser(email)
if err != nil {
return err
}

8
src/server/api_test.go

@ -54,7 +54,7 @@ func TestApi(t *testing.T) {
// Create a new user
newUser := db.User{
Login: "user1",
Email: "user1",
Password: "ruohguoeruoger",
TimeCreatedUnix: 12421467,
}
@ -81,7 +81,7 @@ func TestApi(t *testing.T) {
// newGroup := db.TodoGroup{
// Name: "group1",
// TimeCreatedUnix: 13524534,
// OwnerUsername: newUser.Login,
// OwnerUsername: newUser.Email,
// }
// newGroupBytes, err := json.Marshal(&newGroup)
// if err != nil {
@ -92,7 +92,7 @@ func TestApi(t *testing.T) {
// if err != nil {
// t.Fatalf("failed to create a new POST request to create a new TODO group: %s", err)
// }
// req.Header.Add(RequestHeaderAuthKey, fmt.Sprintf("%s%s%s", newUser.Login, RequestHeaderAuthSeparator, newUser.Password))
// req.Header.Add(RequestHeaderAuthKey, fmt.Sprintf("%s%s%s", newUser.Email, RequestHeaderAuthSeparator, newUser.Password))
// req.Header.Add(RequestHeaderEncodedB64, "false")
// resp, err = http.DefaultClient.Do(req)
@ -116,7 +116,7 @@ func TestApi(t *testing.T) {
Text: "Do the dishes",
TimeCreatedUnix: uint64(time.Now().UnixMicro()),
DueUnix: uint64(time.Now().Add(time.Hour * 5).UnixMicro()),
OwnerLogin: newUser.Login,
OwnerEmail: newUser.Email,
}
newTodoBytes, err := json.Marshal(&newTodo)

48
src/server/endpoints.go

@ -65,30 +65,30 @@ func (s *Server) EndpointUserCreate(w http.ResponseWriter, req *http.Request) {
// Insert into DB
err = s.db.CreateUser(user)
if err != nil {
logger.Error("[Server][EndpointUserCreate] Failed to insert new user \"%s\" data: %s", user.Login, err)
logger.Error("[Server][EndpointUserCreate] Failed to insert new user \"%s\" data: %s", user.Email, err)
http.Error(w, "Failed to create user", http.StatusInternalServerError)
return
}
logger.Info("[Server][EndpointUserCreate] Created a new user with login \"%s\"", user.Login)
logger.Info("[Server][EndpointUserCreate] Created a new user with email \"%s\"", user.Email)
// Create a non-removable default category
err = s.db.CreateTodoGroup(db.NewTodoGroup(
"Notes",
uint64(time.Now().Unix()),
user.Login,
user.Email,
false,
))
if err != nil {
http.Error(w, "Failed to create default group", http.StatusInternalServerError)
logger.Error("[Server][EndpojntUserCreate] Failed to create a default group for %s: %s", user.Login, err)
logger.Error("[Server][EndpojntUserCreate] Failed to create a default group for %s: %s", user.Email, err)
return
}
// Send cookie
http.SetCookie(w, &http.Cookie{
Name: "auth",
Value: fmt.Sprintf("%s:%s", user.Login, user.Password),
Value: fmt.Sprintf("%s:%s", user.Email, user.Password),
SameSite: http.SameSiteStrictMode,
HttpOnly: false,
Path: "/",
@ -122,7 +122,7 @@ func (s *Server) EndpointUserLogin(w http.ResponseWriter, req *http.Request) {
}
// Check auth data
userDB, err := s.db.GetUser(user.Login)
userDB, err := s.db.GetUser(user.Email)
if err != nil {
logger.Error("[Server][EndpointUserLogin] Failed to fetch user information from DB: %s", err)
http.Error(w, "Failed to fetch user information", http.StatusInternalServerError)
@ -137,7 +137,7 @@ func (s *Server) EndpointUserLogin(w http.ResponseWriter, req *http.Request) {
// Send cookie
http.SetCookie(w, &http.Cookie{
Name: "auth",
Value: fmt.Sprintf("%s:%s", user.Login, user.Password),
Value: fmt.Sprintf("%s:%s", user.Email, user.Password),
SameSite: http.SameSiteStrictMode,
HttpOnly: false,
Path: "/",
@ -177,10 +177,10 @@ func (s *Server) EndpointUserUpdate(w http.ResponseWriter, req *http.Request) {
}
// Check whether the user in request is the user specified in JSON
login := GetLoginFromReq(req)
if login != user.Login {
email := GetLoginFromReq(req)
if email != user.Email {
// Gotcha!
logger.Warning("[Server][EndpointUserUpdate] %s tried to update user information of %s!", login, user.Login)
logger.Warning("[Server][EndpointUserUpdate] %s tried to update user information of %s!", email, user.Email)
http.Error(w, "Logins do not match", http.StatusForbidden)
return
}
@ -189,11 +189,11 @@ func (s *Server) EndpointUserUpdate(w http.ResponseWriter, req *http.Request) {
err = s.db.UserUpdate(user)
if err != nil {
http.Error(w, "Failed to update user", http.StatusInternalServerError)
logger.Error("[Server][EndpointUserUpdate] Failed to update \"%s\": %s", user.Login, err)
logger.Error("[Server][EndpointUserUpdate] Failed to update \"%s\": %s", user.Email, err)
return
}
logger.Info("[Server][EndpointUserUpdate] Updated a user with login \"%s\"", user.Login)
logger.Info("[Server][EndpointUserUpdate] Updated a user with email \"%s\"", user.Email)
w.WriteHeader(http.StatusOK)
}
@ -212,15 +212,15 @@ func (s *Server) EndpointUserDelete(w http.ResponseWriter, req *http.Request) {
}
// Delete
login := GetLoginFromReq(req)
err := s.db.DeleteUser(login)
email := GetLoginFromReq(req)
err := s.db.DeleteUser(email)
if err != nil {
http.Error(w, "Failed to delete user", http.StatusInternalServerError)
logger.Error("[Server][EndpointUserDelete] Failed to delete \"%s\": %s", login, err)
logger.Error("[Server][EndpointUserDelete] Failed to delete \"%s\": %s", email, err)
return
}
logger.Info("[Server][EndpointUserDelete] Deleted a user with login \"%s\"", login)
logger.Info("[Server][EndpointUserDelete] Deleted a user with email \"%s\"", email)
w.WriteHeader(http.StatusOK)
}
@ -239,17 +239,17 @@ func (s *Server) EndpointUserGet(w http.ResponseWriter, req *http.Request) {
}
// Get information from the database
login := GetLoginFromReq(req)
userDB, err := s.db.GetUser(login)
email := GetLoginFromReq(req)
userDB, err := s.db.GetUser(email)
if err != nil {
logger.Error("[Server][EndpointUserGet] Failed to retrieve information on \"%s\": %s", login, err)
logger.Error("[Server][EndpointUserGet] Failed to retrieve information on \"%s\": %s", email, err)
http.Error(w, "Failed to fetch information", http.StatusInternalServerError)
return
}
userDBBytes, err := json.Marshal(&userDB)
if err != nil {
logger.Error("[Server][EndpointUserGet] Failed to marshal information on \"%s\": %s", login, err)
logger.Error("[Server][EndpointUserGet] Failed to marshal information on \"%s\": %s", email, err)
http.Error(w, "Failed to marshal information", http.StatusInternalServerError)
return
}
@ -446,7 +446,7 @@ func (s *Server) EndpointTodoCreate(w http.ResponseWriter, req *http.Request) {
return
}
newTodo.OwnerLogin = GetLoginFromReq(req)
newTodo.OwnerEmail = GetLoginFromReq(req)
newTodo.TimeCreatedUnix = uint64(time.Now().Unix())
err = s.db.CreateTodo(newTodo)
if err != nil {
@ -457,7 +457,7 @@ func (s *Server) EndpointTodoCreate(w http.ResponseWriter, req *http.Request) {
// Success!
w.WriteHeader(http.StatusOK)
logger.Info("[Server] Created a new TODO for %s", newTodo.OwnerLogin)
logger.Info("[Server] Created a new TODO for %s", newTodo.OwnerEmail)
}
func (s *Server) EndpointUserTodosGet(w http.ResponseWriter, req *http.Request) {
@ -582,7 +582,7 @@ func (s *Server) EndpointTodoGroupCreate(w http.ResponseWriter, req *http.Reques
}
// Add group to the database
newGroup.OwnerLogin = GetLoginFromReq(req)
newGroup.OwnerEmail = GetLoginFromReq(req)
newGroup.TimeCreatedUnix = uint64(time.Now().Unix())
newGroup.Removable = true
err = s.db.CreateTodoGroup(newGroup)
@ -593,7 +593,7 @@ func (s *Server) EndpointTodoGroupCreate(w http.ResponseWriter, req *http.Reques
// Success!
w.WriteHeader(http.StatusOK)
logger.Info("[Server] Created a new TODO group for %s", newGroup.OwnerLogin)
logger.Info("[Server] Created a new TODO group for %s", newGroup.OwnerEmail)
}
func (s *Server) EndpointTodoGroupGet(w http.ResponseWriter, req *http.Request) {

48
src/server/validation.go

@ -26,26 +26,20 @@ import (
)
const (
MinimalLoginLength uint = 3
MinimalEmailLength uint = 3
MinimalPasswordLength uint = 5
MaxLoginLength uint = 60
MaxEmailLength uint = 60
MaxPasswordLength uint = 250
MaxTodoLength uint = 150
)
// Check if user is valid. Returns false and a reason-string if not
func IsUserValid(user db.User) (bool, string) {
if uint(len(user.Login)) < MinimalLoginLength {
return false, "Login is too small"
if uint(len(user.Email)) < MinimalEmailLength {
return false, "Email is too small"
}
if uint(len(user.Login)) > MaxLoginLength {
return false, fmt.Sprintf("Login is too big; Login should be up to %d characters", MaxLoginLength)
}
for _, char := range user.Login {
if char < 0x21 || char > 0x7E {
// Not printable ASCII char!
return false, "Login has a non printable ASCII character"
}
if uint(len(user.Email)) > MaxEmailLength {
return false, fmt.Sprintf("Email is too big; Email should be up to %d characters", MaxEmailLength)
}
if uint(len(user.Password)) < MinimalPasswordLength {
@ -54,19 +48,13 @@ func IsUserValid(user db.User) (bool, string) {
if uint(len(user.Password)) > MaxPasswordLength {
return false, fmt.Sprintf("Password is too big; Password should be up to %d characters", MaxPasswordLength)
}
for _, char := range user.Password {
if char < 0x21 || char > 0x7E {
// Not printable ASCII char!
return false, "Password has a non printable ASCII character"
}
}
return true, ""
}
// Checks if such a user exists and compares passwords. Returns true if such user exists and passwords do match
func IsUserAuthorized(db *db.DB, user db.User) bool {
userDB, err := db.GetUser(user.Login)
userDB, err := db.GetUser(user.Email)
if err != nil {
return false
}
@ -78,7 +66,7 @@ func IsUserAuthorized(db *db.DB, user db.User) bool {
return true
}
// Returns login and password from a cookie. If an error is encountered, returns empty strings
// Returns email and password from a cookie. If an error is encountered, returns empty strings
func AuthFromCookie(cookie *http.Cookie) (string, string) {
if cookie == nil {
return "", ""
@ -98,35 +86,35 @@ checks if such a user exists and compares passwords.
Returns true if such user exists and passwords do match
*/
func IsUserAuthorizedReq(req *http.Request, dbase *db.DB) bool {
var login, password string
var email, password string
var ok bool
login, password, ok = req.BasicAuth()
if !ok || login == "" || password == "" {
email, password, ok = req.BasicAuth()
if !ok || email == "" || password == "" {
cookie, err := req.Cookie("auth")
if err != nil {
return false
}
login, password = AuthFromCookie(cookie)
email, password = AuthFromCookie(cookie)
}
return IsUserAuthorized(dbase, db.User{
Login: login,
Email: email,
Password: password,
})
}
// Returns login value from basic auth or from cookie if the former does not exist
// Returns email value from basic auth or from cookie if the former does not exist
func GetLoginFromReq(req *http.Request) string {
login, _, ok := req.BasicAuth()
if !ok || login == "" {
email, _, ok := req.BasicAuth()
if !ok || email == "" {
cookie, err := req.Cookie("auth")
if err != nil {
return ""
}
login, _ = AuthFromCookie(cookie)
email, _ = AuthFromCookie(cookie)
}
return login
return email
}

Loading…
Cancel
Save