mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-09-22 00:20:47 +02:00
🧑💻 Kernel serve CardDAV service on path /carddav/
(#12895)
* 🎨 add CardDAV server * 🎨 change CardDAV principals path * 🎨 implement load contacts feature * 🎨 implement save contacts feature * 🎨 implement address books CURD * 🐛 fix CardDAV method `OPTIONS` * 🎨 implement addresses CURD * 🎨 implement CardDAV `REPORT` method * 🎨 parse *.vcf file with multiple vCard
This commit is contained in:
parent
96194f7dae
commit
c110b9ff13
6 changed files with 1020 additions and 19 deletions
|
@ -32,6 +32,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/88250/gulu"
|
||||
"github.com/emersion/go-webdav/carddav"
|
||||
"github.com/gin-contrib/gzip"
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-contrib/sessions/cookie"
|
||||
|
@ -47,17 +48,63 @@ import (
|
|||
"golang.org/x/net/webdav"
|
||||
)
|
||||
|
||||
const (
|
||||
MethodMkcol = "MKCOL"
|
||||
MethodCopy = "COPY"
|
||||
MethodMove = "MOVE"
|
||||
MethodLock = "LOCK"
|
||||
MethodUnlock = "UNLOCK"
|
||||
MethodPropFind = "PROPFIND"
|
||||
MethodPropPatch = "PROPPATCH"
|
||||
MethodReport = "REPORT"
|
||||
)
|
||||
|
||||
var (
|
||||
cookieStore = cookie.NewStore([]byte("ATN51UlxVq1Gcvdf"))
|
||||
WebDavMethod = []string{
|
||||
"OPTIONS",
|
||||
"GET", "HEAD",
|
||||
"POST", "PUT",
|
||||
"DELETE",
|
||||
"MKCOL",
|
||||
"COPY", "MOVE",
|
||||
"LOCK", "UNLOCK",
|
||||
"PROPFIND", "PROPPATCH",
|
||||
cookieStore = cookie.NewStore([]byte("ATN51UlxVq1Gcvdf"))
|
||||
HttpMethods = []string{
|
||||
http.MethodGet,
|
||||
http.MethodHead,
|
||||
http.MethodPost,
|
||||
http.MethodPut,
|
||||
http.MethodPatch,
|
||||
http.MethodDelete,
|
||||
http.MethodConnect,
|
||||
http.MethodOptions,
|
||||
http.MethodTrace,
|
||||
}
|
||||
WebDavMethods = []string{
|
||||
http.MethodOptions,
|
||||
http.MethodHead,
|
||||
http.MethodGet,
|
||||
http.MethodPost,
|
||||
http.MethodPut,
|
||||
http.MethodDelete,
|
||||
|
||||
MethodMkcol,
|
||||
MethodCopy,
|
||||
MethodMove,
|
||||
MethodLock,
|
||||
MethodUnlock,
|
||||
MethodPropFind,
|
||||
MethodPropPatch,
|
||||
}
|
||||
CardDavMethods = []string{
|
||||
http.MethodOptions,
|
||||
http.MethodHead,
|
||||
http.MethodGet,
|
||||
http.MethodPost,
|
||||
http.MethodPut,
|
||||
http.MethodDelete,
|
||||
|
||||
MethodMkcol,
|
||||
// MethodCopy,
|
||||
// MethodMove,
|
||||
// MethodLock,
|
||||
// MethodUnlock,
|
||||
MethodPropFind,
|
||||
MethodPropPatch,
|
||||
|
||||
MethodReport,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -88,6 +135,7 @@ func Serve(fastMode bool) {
|
|||
serveAppearance(ginServer)
|
||||
serveWebSocket(ginServer)
|
||||
serveWebDAV(ginServer)
|
||||
serveCardDAV(ginServer)
|
||||
serveExport(ginServer)
|
||||
serveWidgets(ginServer)
|
||||
servePlugins(ginServer)
|
||||
|
@ -616,10 +664,19 @@ func serveWebDAV(ginServer *gin.Engine) {
|
|||
}
|
||||
|
||||
ginGroup := ginServer.Group("/webdav", model.CheckAuth, model.CheckAdminRole)
|
||||
ginGroup.Match(WebDavMethod, "/*path", func(c *gin.Context) {
|
||||
// ginGroup.Any NOT support extension methods (PROPFIND etc.)
|
||||
ginGroup.Match(WebDavMethods, "/*path", func(c *gin.Context) {
|
||||
if util.ReadOnly {
|
||||
switch c.Request.Method {
|
||||
case "POST", "PUT", "DELETE", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", "PROPPATCH":
|
||||
case http.MethodPost,
|
||||
http.MethodPut,
|
||||
http.MethodDelete,
|
||||
MethodMkcol,
|
||||
MethodCopy,
|
||||
MethodMove,
|
||||
MethodLock,
|
||||
MethodUnlock,
|
||||
MethodPropPatch:
|
||||
c.AbortWithError(http.StatusForbidden, fmt.Errorf(model.Conf.Language(34)))
|
||||
return
|
||||
}
|
||||
|
@ -628,6 +685,40 @@ func serveWebDAV(ginServer *gin.Engine) {
|
|||
})
|
||||
}
|
||||
|
||||
func serveCardDAV(ginServer *gin.Engine) {
|
||||
// REF: https://github.com/emersion/hydroxide/blob/master/carddav/carddav.go
|
||||
handler := carddav.Handler{
|
||||
Backend: &model.CardDavBackend{},
|
||||
Prefix: model.CardDavPrincipalsPath,
|
||||
}
|
||||
|
||||
ginServer.Match(CardDavMethods, "/.well-known/carddav", func(c *gin.Context) {
|
||||
handler.ServeHTTP(c.Writer, c.Request)
|
||||
})
|
||||
|
||||
ginGroup := ginServer.Group(model.CardDavPrefixPath, model.CheckAuth, model.CheckAdminRole)
|
||||
ginGroup.Match(CardDavMethods, "/*path", func(c *gin.Context) {
|
||||
// logging.LogDebugf("CardDAV -> [%s] %s", c.Request.Method, c.Request.URL.String())
|
||||
if util.ReadOnly {
|
||||
switch c.Request.Method {
|
||||
case http.MethodPost,
|
||||
http.MethodPut,
|
||||
http.MethodDelete,
|
||||
MethodMkcol,
|
||||
MethodCopy,
|
||||
MethodMove,
|
||||
MethodLock,
|
||||
MethodUnlock,
|
||||
MethodPropPatch:
|
||||
c.AbortWithError(http.StatusForbidden, fmt.Errorf(model.Conf.Language(34)))
|
||||
return
|
||||
}
|
||||
}
|
||||
handler.ServeHTTP(c.Writer, c.Request)
|
||||
// logging.LogDebugf("CardDAV <- [%s] %v", c.Request.Method, c.Writer.Status())
|
||||
})
|
||||
}
|
||||
|
||||
func shortReqMsg(msg []byte) []byte {
|
||||
s := gulu.Str.FromBytes(msg)
|
||||
max := 128
|
||||
|
@ -644,15 +735,32 @@ func shortReqMsg(msg []byte) []byte {
|
|||
}
|
||||
|
||||
func corsMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
allowMethods := strings.Join(HttpMethods, ", ")
|
||||
allowWebDavMethods := strings.Join(WebDavMethods, ", ")
|
||||
allowCardDavMethods := strings.Join(CardDavMethods, ", ")
|
||||
|
||||
return func(c *gin.Context) {
|
||||
c.Header("Access-Control-Allow-Origin", "*")
|
||||
c.Header("Access-Control-Allow-Credentials", "true")
|
||||
c.Header("Access-Control-Allow-Headers", "origin, Content-Length, Content-Type, Authorization")
|
||||
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS")
|
||||
c.Header("Access-Control-Allow-Private-Network", "true")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
if strings.HasPrefix(c.Request.RequestURI, "/webdav/") {
|
||||
c.Header("Access-Control-Allow-Methods", allowWebDavMethods)
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(c.Request.RequestURI, "/carddav/") {
|
||||
c.Header("Access-Control-Allow-Methods", allowCardDavMethods)
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("Access-Control-Allow-Methods", allowMethods)
|
||||
|
||||
switch c.Request.Method {
|
||||
case http.MethodOptions:
|
||||
c.Header("Access-Control-Max-Age", "600")
|
||||
c.AbortWithStatus(204)
|
||||
return
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue