203 lines
4.6 KiB
Go
203 lines
4.6 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright © 2022 Roberto Hidalgo <nidito@un.rob.mx>
|
|
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"git.rob.mx/nidito/puerta/internal/user"
|
|
"github.com/SherClockHolmes/webpush-go"
|
|
"github.com/julienschmidt/httprouter"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/upper/db/v4"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
func sendError(w http.ResponseWriter, err error) {
|
|
logrus.Error(err)
|
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
}
|
|
|
|
func writeJSON(w http.ResponseWriter, data any) error {
|
|
res, err := json.Marshal(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
w.Header().Add("content-type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
_, err = w.Write(res)
|
|
return err
|
|
}
|
|
|
|
func listUsers(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
users := []*user.User{}
|
|
if err := _db.Collection("user").Find().All(&users); err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, users)
|
|
}
|
|
|
|
func userFromRequest(r *http.Request, u *user.User) (*user.User, error) {
|
|
dec := json.NewDecoder(r.Body)
|
|
res := &user.User{}
|
|
if err := dec.Decode(&res); err != nil {
|
|
return nil, err
|
|
}
|
|
logrus.Debugf("Unserialized user data: %v", res)
|
|
|
|
if u == nil {
|
|
u = &user.User{
|
|
Handle: res.Handle,
|
|
}
|
|
}
|
|
|
|
u.Name = res.Name
|
|
u.Expires = res.Expires
|
|
u.Greeting = res.Greeting
|
|
u.IsAdmin = res.IsAdmin
|
|
u.IsNotified = res.IsNotified
|
|
u.Require2FA = res.Require2FA
|
|
u.Schedule = res.Schedule
|
|
u.TTL = res.TTL
|
|
|
|
if res.Password != "" {
|
|
password, err := bcrypt.GenerateFromPassword([]byte(res.Password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
u.Password = string(password)
|
|
}
|
|
|
|
return u, nil
|
|
|
|
}
|
|
|
|
func createUser(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
user, err := userFromRequest(r, nil)
|
|
if err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
|
|
if _, err := _db.Collection("user").Insert(user); err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusCreated)
|
|
}
|
|
|
|
func getUser(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
|
this := user.User{}
|
|
idString := params.ByName("id")
|
|
|
|
if err := _db.Get(&this, db.Cond{"handle": idString}); err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, this)
|
|
}
|
|
|
|
func updateUser(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
|
logrus.Infof("updating user: %s", params.ByName("id"))
|
|
user := user.User{}
|
|
if err := _db.Get(&user, db.Cond{"handle": params.ByName("id")}); err != nil {
|
|
logrus.Error(err)
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
|
|
modified, err := userFromRequest(r, &user)
|
|
if err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
|
|
if err := _db.Collection("user").UpdateReturning(modified); err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
func deleteUser(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
|
err := _db.Collection("user").Find(db.Cond{"handle": params.ByName("id")}).Delete()
|
|
if err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
func createSubscription(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
|
u := user.FromContext(r)
|
|
dec := json.NewDecoder(r.Body)
|
|
res := &webpush.Subscription{}
|
|
if err := dec.Decode(&res); err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
logrus.Infof("Unserialized subscription data: %v", res)
|
|
|
|
sub := &user.Subscription{
|
|
UserID: u.ID,
|
|
Data: &user.WPS{Subscription: res},
|
|
}
|
|
|
|
ins, err := _db.Collection("subscription").Insert(sub)
|
|
if err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
|
|
logrus.Infof("Created subscription for: %s (%v)", u.Handle, ins)
|
|
w.WriteHeader(http.StatusCreated)
|
|
w.Write([]byte(`{"status": "ok"}`))
|
|
}
|
|
|
|
func deleteSubscription(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
|
u := user.FromContext(r)
|
|
|
|
dec := json.NewDecoder(r.Body)
|
|
res := &webpush.Subscription{}
|
|
if err := dec.Decode(&res); err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
encoded, err := json.Marshal(res)
|
|
|
|
if err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
|
|
err = _db.Collection("subscription").Find(db.Cond{"user": u.ID, "data": db.Like(fmt.Sprintf("%%%s%%", encoded))}).Delete()
|
|
if err != nil {
|
|
sendError(w, fmt.Errorf("could not delete subscription: %s", err))
|
|
return
|
|
}
|
|
|
|
logrus.Infof("Deleted subscription for: %s (%s)", u.Handle, encoded)
|
|
w.WriteHeader(http.StatusCreated)
|
|
w.Write([]byte(`{"status": "ok"}`))
|
|
}
|
|
|
|
func rexRecords(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
|
records := []*auditLog{}
|
|
err := _db.Collection("log").Find().OrderBy("-timestamp").Limit(20).All(&records)
|
|
if err != nil {
|
|
sendError(w, err)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, records)
|
|
}
|