2024-05-08 01:10:58 +01:00
|
|
|
package daisy
|
|
|
|
|
|
|
|
import (
|
2024-10-11 17:05:18 +01:00
|
|
|
"embed"
|
2024-05-13 16:21:09 +01:00
|
|
|
"git.sr.ht/~sircmpwn/tokidoki/storage"
|
|
|
|
"github.com/1f349/cardcaldav"
|
|
|
|
"github.com/emersion/go-webdav"
|
2024-05-08 01:10:58 +01:00
|
|
|
"github.com/emersion/go-webdav/carddav"
|
|
|
|
"net/http"
|
2024-10-11 17:05:18 +01:00
|
|
|
"path"
|
2024-05-13 16:21:09 +01:00
|
|
|
"path/filepath"
|
2024-10-11 17:05:18 +01:00
|
|
|
"strings"
|
2024-05-08 01:10:58 +01:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2024-10-11 17:05:18 +01:00
|
|
|
//go:embed web/dist
|
|
|
|
var webEmbedded embed.FS
|
|
|
|
|
2024-05-08 01:10:58 +01:00
|
|
|
type Conf struct {
|
|
|
|
Listen string `json:"listen"`
|
2024-05-13 16:21:09 +01:00
|
|
|
DB string `json:"db"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type daisyHandler struct {
|
2024-05-14 11:11:02 +01:00
|
|
|
auth AuthProvider
|
2024-05-13 16:21:09 +01:00
|
|
|
backend carddav.Backend
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *daisyHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
principlePath, err := d.auth.CurrentUserPrincipal(req.Context())
|
|
|
|
if err != nil {
|
|
|
|
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var homeSets []webdav.BackendSuppliedHomeSet
|
2024-10-11 17:05:18 +01:00
|
|
|
homeSetPath, err := d.backend.AddressBookHomeSetPath(req.Context())
|
2024-05-13 16:21:09 +01:00
|
|
|
if err != nil {
|
|
|
|
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2024-10-11 17:05:18 +01:00
|
|
|
homeSets = append(homeSets, carddav.NewAddressBookHomeSet(homeSetPath))
|
2024-05-13 16:21:09 +01:00
|
|
|
|
|
|
|
if req.URL.Path == principlePath {
|
|
|
|
opts := webdav.ServePrincipalOptions{
|
|
|
|
CurrentUserPrincipalPath: principlePath,
|
|
|
|
HomeSets: homeSets,
|
|
|
|
Capabilities: []webdav.Capability{
|
|
|
|
carddav.CapabilityAddressBook,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
webdav.ServePrincipal(rw, req, &opts)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.URL.Path == "/" {
|
2024-10-11 17:05:18 +01:00
|
|
|
http.ServeFileFS(rw, req, webEmbedded, "web/dist/index.html")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if after, found := strings.CutPrefix(req.URL.Path, "/assets/"); found {
|
|
|
|
if strings.Contains(after, "..") {
|
|
|
|
http.Error(rw, "400 Bad Request", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
http.ServeFileFS(rw, req, webEmbedded, path.Join("web/dist/assets", after))
|
2024-05-13 16:21:09 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
http.NotFound(rw, req)
|
2024-05-08 01:10:58 +01:00
|
|
|
}
|
|
|
|
|
2024-05-14 11:11:02 +01:00
|
|
|
type AuthProvider interface {
|
|
|
|
cardcaldav.ProviderMiddleware
|
|
|
|
webdav.UserPrincipalBackend
|
|
|
|
}
|
|
|
|
|
2024-05-08 01:10:58 +01:00
|
|
|
func NewHttpServer(conf Conf, wd string) *http.Server {
|
2024-05-13 16:21:09 +01:00
|
|
|
cardcaldav.SetupLogger(Logger)
|
2024-05-14 11:11:02 +01:00
|
|
|
principle := NullAuth(cardcaldav.NewAuth(conf.DB, Logger))
|
2024-05-13 16:21:09 +01:00
|
|
|
|
|
|
|
_, cardStorage, err := storage.NewFilesystem(filepath.Join(wd, "storage"), "/calendar/", "/contacts/", principle)
|
|
|
|
if err != nil {
|
|
|
|
Logger.Fatal("Failed to load storage backend", "err", err)
|
2024-05-08 01:10:58 +01:00
|
|
|
}
|
2024-05-13 16:21:09 +01:00
|
|
|
cardHandler := &carddav.Handler{Backend: cardStorage}
|
|
|
|
|
|
|
|
handler := &daisyHandler{
|
|
|
|
auth: principle,
|
|
|
|
backend: cardStorage,
|
|
|
|
}
|
|
|
|
|
|
|
|
r := http.NewServeMux()
|
|
|
|
r.Handle("/", handler)
|
|
|
|
r.Handle("/.well-known/carddav", cardHandler)
|
|
|
|
r.Handle("/{user}/contacts/", cardHandler)
|
|
|
|
|
|
|
|
r2 := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
t := time.Now()
|
|
|
|
r.ServeHTTP(rw, req)
|
|
|
|
td := time.Since(t)
|
|
|
|
Logger.Debug("Request", "method", req.Method, "url", req.URL.String(), "remote", req.RemoteAddr, "dur", td.String())
|
|
|
|
})
|
2024-05-08 01:10:58 +01:00
|
|
|
|
|
|
|
return &http.Server{
|
|
|
|
Addr: conf.Listen,
|
2024-05-13 16:21:09 +01:00
|
|
|
Handler: principle.Middleware(r2),
|
2024-05-08 01:10:58 +01:00
|
|
|
ReadTimeout: time.Minute,
|
|
|
|
ReadHeaderTimeout: time.Minute,
|
|
|
|
WriteTimeout: time.Minute,
|
|
|
|
IdleTimeout: time.Minute,
|
|
|
|
MaxHeaderBytes: 2500,
|
|
|
|
}
|
|
|
|
}
|