+
+
+
-
+
Categories
+
+
+
-
{{ range .Groups }}
-
{{ end }}
-
+
-
+
+
+
+
+
+
+
+
{{ range .Groups }}
-
-
-
-
+
+
+
{{ end }}
\ No newline at end of file
diff --git a/pages/login.html b/pages/login.html
index d500c0a..e96fba6 100644
--- a/pages/login.html
+++ b/pages/login.html
@@ -44,7 +44,7 @@ async function logIn() {
password = sha256(password);
// Check if auth info is indeed valid
- let response = await getUser();
+ let response = await doLogin({login: login, password: password});
if (response.ok) {
window.location.replace("/");
} else {
diff --git a/scripts/api.js b/scripts/api.js
index 65a805c..be99b61 100644
--- a/scripts/api.js
+++ b/scripts/api.js
@@ -26,6 +26,10 @@ async function postNewUser(newUser) {
return post("/api/user/create", newUser)
}
+async function doLogin(userInformation) {
+ return post("/api/user/login", userInformation)
+}
+
async function get(url) {
return fetch(url, {
method: "GET",
@@ -66,6 +70,10 @@ async function deleteTodo(id) {
return del("/api/todo/delete/"+id);
}
+async function deleteCategory(id) {
+ return del("/api/group/delete/"+id);
+}
+
async function update(url, json) {
return post(url, json);
}
diff --git a/scripts/auth.js b/scripts/auth.js
index d35fadf..d0db963 100644
--- a/scripts/auth.js
+++ b/scripts/auth.js
@@ -1,7 +1,19 @@
/*
- 2024 Kasyanov Nikolay Alexeyevich (Unbewohnte)
+ 2024 Kasyanov Nikolay Alexeevich (Unbewohnte)
*/
+function getCookie(name){
+ return document.cookie.split(';').some(c => {
+ return c.trim().startsWith(name + '=');
+ });
+}
+
+function forgetAuthInfo() {
+ if(getCookie("auth")) {
+ document.cookie = "auth" + "=" + ";expires=Thu, 01 Jan 1970 00:00:01 GMT";
+ }
+}
+
/**
* [js-sha256]{@link https://github.com/emn178/js-sha256}
*
diff --git a/src/server/endpoints.go b/src/server/endpoints.go
index fe8651f..76ca9a8 100644
--- a/src/server/endpoints.go
+++ b/src/server/endpoints.go
@@ -97,6 +97,55 @@ func (s *Server) EndpointUserCreate(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
}
+func (s *Server) EndpointUserLogin(w http.ResponseWriter, req *http.Request) {
+ if req.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ // Retrieve user data
+ defer req.Body.Close()
+
+ contents, err := io.ReadAll(req.Body)
+ if err != nil {
+ logger.Error("[Server][EndpointUserLogin] Failed to read request body: %s", err)
+ http.Error(w, "Failed to read request body", http.StatusInternalServerError)
+ return
+ }
+
+ var user db.User
+ err = json.Unmarshal(contents, &user)
+ if err != nil {
+ logger.Error("[Server][EndpointUserLogin] Failed to unmarshal user data: %s", err)
+ http.Error(w, "User JSON unmarshal error", http.StatusInternalServerError)
+ return
+ }
+
+ // Check auth data
+ userDB, err := s.db.GetUser(user.Login)
+ 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)
+ return
+ }
+
+ if user.Password != userDB.Password {
+ http.Error(w, "Failed auth", http.StatusForbidden)
+ return
+ }
+
+ // Send cookie
+ http.SetCookie(w, &http.Cookie{
+ Name: "auth",
+ Value: fmt.Sprintf("%s:%s", user.Login, user.Password),
+ SameSite: http.SameSiteStrictMode,
+ HttpOnly: false,
+ Path: "/",
+ Secure: true,
+ })
+ w.WriteHeader(http.StatusOK)
+}
+
func (s *Server) EndpointUserUpdate(w http.ResponseWriter, req *http.Request) {
if req.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
@@ -436,43 +485,47 @@ func (s *Server) EndpointTodoGroupDelete(w http.ResponseWriter, req *http.Reques
// Delete an existing group
defer req.Body.Close()
- // Read body
- body, err := io.ReadAll(req.Body)
- if err != nil {
- logger.Warning("[Server] Failed to read request body to possibly delete a TODO group: %s", err)
- http.Error(w, "Failed to read body", http.StatusInternalServerError)
+ // Check if given user actually owns this group
+ if !IsUserAuthorizedReq(req, s.db) {
+ http.Error(w, "Invalid user auth data", http.StatusForbidden)
return
}
- // Unmarshal JSON
- var group db.TodoGroup
- err = json.Unmarshal(body, &group)
+ // Get group ID
+ groupId, err := strconv.ParseUint(path.Base(req.URL.Path), 10, 64)
if err != nil {
- logger.Warning("[Server] Received invalid TODO group JSON for deletion: %s", err)
- http.Error(w, "Invalid TODO group JSON", http.StatusBadRequest)
+ http.Error(w, "Bad Category ID", http.StatusBadRequest)
return
}
- // Check if given user actually owns this group
- if !IsUserAuthorizedReq(req, s.db) {
- http.Error(w, "Invalid user auth data", http.StatusForbidden)
+ if !s.db.DoesUserOwnGroup(groupId, GetLoginFromReq(req)) {
+ http.Error(w, "You don't own this group", http.StatusForbidden)
return
}
- if !s.db.DoesUserOwnGroup(group.ID, GetLoginFromReq(req)) {
- http.Error(w, "You don't own this group", http.StatusForbidden)
+ groupDB, err := s.db.GetTodoGroup(groupId)
+ if err != nil {
+ logger.Error("[Server][EndpointGroupDelete] Failed to fetch TODO group with Id %d: %s", groupId, err)
+ http.Error(w, "Failed to retrieve TODO group", http.StatusInternalServerError)
return
}
- // Now delete
- err = s.db.DeleteTodoGroup(group.ID)
+ if !groupDB.Removable {
+ // Not removable
+ http.Error(w, "Not removable", http.StatusBadRequest)
+ return
+ }
+
+ // Delete
+ err = s.db.DeleteTodoGroup(groupId)
if err != nil {
- logger.Error("[Server] Failed to delete %s's TODO group: %s", GetLoginFromReq(req), err)
+ logger.Error("[Server][EndpointGroupDelete] Failed to delete %s's TODO group: %s", GetLoginFromReq(req), err)
http.Error(w, "Failed to delete TODO group", http.StatusInternalServerError)
return
}
// Success!
+ logger.Info("[Server][EndpointGroupDelete] Deleted group ID: %d for %s", groupId, GetLoginFromReq(req))
w.WriteHeader(http.StatusOK)
}
@@ -505,6 +558,7 @@ func (s *Server) EndpointTodoGroupCreate(w http.ResponseWriter, req *http.Reques
// Add group to the database
newGroup.OwnerLogin = GetLoginFromReq(req)
newGroup.TimeCreatedUnix = uint64(time.Now().Unix())
+ newGroup.Removable = true
err = s.db.CreateTodoGroup(newGroup)
if err != nil {
http.Error(w, "Failed to create TODO group", http.StatusInternalServerError)
diff --git a/src/server/server.go b/src/server/server.go
index 570e538..91bc299 100644
--- a/src/server/server.go
+++ b/src/server/server.go
@@ -192,6 +192,7 @@ func New(config conf.Conf) (*Server, error) {
mux.HandleFunc("/api/user/delete", server.EndpointUserDelete) // Non specific
mux.HandleFunc("/api/user/update", server.EndpointUserUpdate) // Non specific
mux.HandleFunc("/api/user/create", server.EndpointUserCreate) // Non specific
+ mux.HandleFunc("/api/user/login", server.EndpointUserLogin) // Non specific
mux.HandleFunc("/api/todo/create", server.EndpointTodoCreate) // Non specific
mux.HandleFunc("/api/todo/get", server.EndpointUserTodosGet) // Non specific
mux.HandleFunc("/api/todo/delete/", server.EndpointTodoDelete) // Specific
diff --git a/static/images/arrows-fullscreen.svg b/static/images/arrows-fullscreen.svg
new file mode 100644
index 0000000..7633e3f
--- /dev/null
+++ b/static/images/arrows-fullscreen.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
-
-
- {{ .Name }}
-Jump here
+
+
+
+
-
{{ end }}
+
+
+ {{ if .Removable }}
+
+
+ {{ .TimeCreated }}
+ {{ .Name }}
+Jump here
+
+
- {{ .TimeCreatedUnix }}
+ {{ end }}
-
-
-