fix: access control (#870)

pull/871/head
boojack 3 years ago committed by GitHub
parent f888c62840
commit 3556ae4e65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -46,7 +46,7 @@ type Memo struct {
type MemoCreate struct { type MemoCreate struct {
// Standard fields // Standard fields
CreatorID int CreatorID int `json:"-"`
// Domain specific fields // Domain specific fields
Visibility Visibility `json:"visibility"` Visibility Visibility `json:"visibility"`
@ -73,11 +73,11 @@ type MemoPatch struct {
} }
type MemoFind struct { type MemoFind struct {
ID *int `json:"id"` ID *int
// Standard fields // Standard fields
RowStatus *RowStatus `json:"rowStatus"` RowStatus *RowStatus
CreatorID *int `json:"creatorId"` CreatorID *int
// Domain specific fields // Domain specific fields
Pinned *bool Pinned *bool

@ -9,15 +9,15 @@ type MemoOrganizer struct {
Pinned bool Pinned bool
} }
type MemoOrganizerFind struct { type MemoOrganizerUpsert struct {
MemoID int MemoID int `json:"-"`
UserID int UserID int `json:"-"`
Pinned bool `json:"pinned"`
} }
type MemoOrganizerUpsert struct { type MemoOrganizerFind struct {
MemoID int MemoID int
UserID int UserID int
Pinned bool `json:"pinned"`
} }
type MemoOrganizerDelete struct { type MemoOrganizerDelete struct {

@ -8,7 +8,7 @@ type MemoResource struct {
} }
type MemoResourceUpsert struct { type MemoResourceUpsert struct {
MemoID int MemoID int `json:"-"`
ResourceID int ResourceID int
UpdatedTs *int64 UpdatedTs *int64
} }

@ -20,7 +20,7 @@ type Resource struct {
type ResourceCreate struct { type ResourceCreate struct {
// Standard fields // Standard fields
CreatorID int CreatorID int `json:"-"`
// Domain specific fields // Domain specific fields
Filename string `json:"filename"` Filename string `json:"filename"`

@ -16,7 +16,7 @@ type Shortcut struct {
type ShortcutCreate struct { type ShortcutCreate struct {
// Standard fields // Standard fields
CreatorID int CreatorID int `json:"-"`
// Domain specific fields // Domain specific fields
Title string `json:"title"` Title string `json:"title"`

@ -7,7 +7,7 @@ type Tag struct {
type TagUpsert struct { type TagUpsert struct {
Name string Name string
CreatorID int CreatorID int `json:"-"`
} }
type TagFind struct { type TagFind struct {

@ -50,7 +50,7 @@ type UserSetting struct {
} }
type UserSettingUpsert struct { type UserSettingUpsert struct {
UserID int UserID int `json:"-"`
Key UserSettingKey `json:"key"` Key UserSettingKey `json:"key"`
Value string `json:"value"` Value string `json:"value"`
} }

@ -84,7 +84,7 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find host user").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find host user").SetInternal(err)
} }
if signup.Role == api.Host && hostUser != nil { if signup.Role == api.Host && hostUser != nil {
return echo.NewHTTPError(http.StatusUnauthorized, "Site Host existed, please contact the site host to signin account firstly.").SetInternal(err) return echo.NewHTTPError(http.StatusUnauthorized, "Site Host existed, please contact the site host to signin account firstly").SetInternal(err)
} }
systemSettingAllowSignUpName := api.SystemSettingAllowSignUpName systemSettingAllowSignUpName := api.SystemSettingAllowSignUpName
@ -103,7 +103,7 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
} }
} }
if !allowSignUpSettingValue && hostUser != nil { if !allowSignUpSettingValue && hostUser != nil {
return echo.NewHTTPError(http.StatusUnauthorized, "Site Host existed, please contact the site host to signin account firstly.").SetInternal(err) return echo.NewHTTPError(http.StatusUnauthorized, "Site Host existed, please contact the site host to signin account firstly").SetInternal(err)
} }
userCreate := &api.UserCreate{ userCreate := &api.UserCreate{
@ -114,7 +114,7 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
OpenID: common.GenUUID(), OpenID: common.GenUUID(),
} }
if err := userCreate.Validate(); err != nil { if err := userCreate.Validate(); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid user create format.").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Invalid user create format").SetInternal(err)
} }
passwordHash, err := bcrypt.GenerateFromPassword([]byte(signup.Password), bcrypt.DefaultCost) passwordHash, err := bcrypt.GenerateFromPassword([]byte(signup.Password), bcrypt.DefaultCost)

@ -24,9 +24,7 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
} }
memoCreate := &api.MemoCreate{ memoCreate := &api.MemoCreate{}
CreatorID: userID,
}
if err := json.NewDecoder(c.Request().Body).Decode(memoCreate); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(memoCreate); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post memo request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post memo request").SetInternal(err)
} }
@ -57,6 +55,7 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
} }
} }
memoCreate.CreatorID = userID
memo, err := s.Store.CreateMemo(ctx, memoCreate) memo, err := s.Store.CreateMemo(ctx, memoCreate)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create memo").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create memo").SetInternal(err)
@ -98,13 +97,15 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("memoId"))).SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("memoId"))).SetInternal(err)
} }
memoFind := &api.MemoFind{ memo, err := s.Store.FindMemo(ctx, &api.MemoFind{
ID: &memoID, ID: &memoID,
CreatorID: &userID, })
} if err != nil {
if _, err := s.Store.FindMemo(ctx, memoFind); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo").SetInternal(err)
} }
if memo.CreatorID != userID {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
currentTs := time.Now().Unix() currentTs := time.Now().Unix()
memoPatch := &api.MemoPatch{ memoPatch := &api.MemoPatch{
@ -115,7 +116,7 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch memo request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch memo request").SetInternal(err)
} }
memo, err := s.Store.PatchMemo(ctx, memoPatch) memo, err = s.Store.PatchMemo(ctx, memoPatch)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch memo").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch memo").SetInternal(err)
} }
@ -173,7 +174,7 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
} }
tag := c.QueryParam("tag") tag := c.QueryParam("tag")
if tag != "" { if tag != "" {
contentSearch := "#" + tag + " " contentSearch := "#" + tag
memoFind.ContentSearch = &contentSearch memoFind.ContentSearch = &contentSearch
} }
visibilityListStr := c.QueryParam("visibility") visibilityListStr := c.QueryParam("visibility")
@ -229,129 +230,6 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
return nil return nil
}) })
g.GET("/memo/amount", func(c echo.Context) error {
ctx := c.Request().Context()
normalRowStatus := api.Normal
memoFind := &api.MemoFind{
RowStatus: &normalRowStatus,
}
if userID, err := strconv.Atoi(c.QueryParam("userId")); err == nil {
memoFind.CreatorID = &userID
}
memoList, err := s.Store.FindMemoList(ctx, memoFind)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo list").SetInternal(err)
}
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(len(memoList))); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode memo amount").SetInternal(err)
}
return nil
})
g.GET("/memo/stats", func(c echo.Context) error {
ctx := c.Request().Context()
normalStatus := api.Normal
memoFind := &api.MemoFind{
RowStatus: &normalStatus,
}
if creatorID, err := strconv.Atoi(c.QueryParam("creatorId")); err == nil {
memoFind.CreatorID = &creatorID
}
if memoFind.CreatorID == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Missing user id to find memo")
}
currentUserID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
memoFind.VisibilityList = []api.Visibility{api.Public}
} else {
if *memoFind.CreatorID != currentUserID {
memoFind.VisibilityList = []api.Visibility{api.Public, api.Protected}
} else {
memoFind.VisibilityList = []api.Visibility{api.Public, api.Protected, api.Private}
}
}
list, err := s.Store.FindMemoList(ctx, memoFind)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch memo list").SetInternal(err)
}
displayTsList := []int64{}
for _, memo := range list {
displayTsList = append(displayTsList, memo.DisplayTs)
}
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(displayTsList)); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode memo stats response").SetInternal(err)
}
return nil
})
g.GET("/memo/all", func(c echo.Context) error {
ctx := c.Request().Context()
memoFind := &api.MemoFind{}
_, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
memoFind.VisibilityList = []api.Visibility{api.Public}
} else {
memoFind.VisibilityList = []api.Visibility{api.Public, api.Protected}
}
pinnedStr := c.QueryParam("pinned")
if pinnedStr != "" {
pinned := pinnedStr == "true"
memoFind.Pinned = &pinned
}
tag := c.QueryParam("tag")
if tag != "" {
contentSearch := "#" + tag + " "
memoFind.ContentSearch = &contentSearch
}
visibilityListStr := c.QueryParam("visibility")
if visibilityListStr != "" {
visibilityList := []api.Visibility{}
for _, visibility := range strings.Split(visibilityListStr, ",") {
visibilityList = append(visibilityList, api.Visibility(visibility))
}
memoFind.VisibilityList = visibilityList
}
if limit, err := strconv.Atoi(c.QueryParam("limit")); err == nil {
memoFind.Limit = limit
}
if offset, err := strconv.Atoi(c.QueryParam("offset")); err == nil {
memoFind.Offset = offset
}
// Only fetch normal status memos.
normalStatus := api.Normal
memoFind.RowStatus = &normalStatus
list, err := s.Store.FindMemoList(ctx, memoFind)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch all memo list").SetInternal(err)
}
sort.Slice(list, func(i, j int) bool {
return list[i].DisplayTs > list[j].DisplayTs
})
if memoFind.Limit != 0 {
list = list[memoFind.Offset:common.Min(len(list), memoFind.Offset+memoFind.Limit)]
}
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(list)); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode all memo list response").SetInternal(err)
}
return nil
})
g.GET("/memo/:memoId", func(c echo.Context) error { g.GET("/memo/:memoId", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
memoID, err := strconv.Atoi(c.Param("memoId")) memoID, err := strconv.Atoi(c.Param("memoId"))
@ -400,13 +278,12 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
if !ok { if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
} }
memoOrganizerUpsert := &api.MemoOrganizerUpsert{ memoOrganizerUpsert := &api.MemoOrganizerUpsert{}
MemoID: memoID,
UserID: userID,
}
if err := json.NewDecoder(c.Request().Body).Decode(memoOrganizerUpsert); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(memoOrganizerUpsert); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post memo organizer request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post memo organizer request").SetInternal(err)
} }
memoOrganizerUpsert.MemoID = memoID
memoOrganizerUpsert.UserID = userID
err = s.Store.UpsertMemoOrganizer(ctx, memoOrganizerUpsert) err = s.Store.UpsertMemoOrganizer(ctx, memoOrganizerUpsert)
if err != nil { if err != nil {
@ -440,12 +317,12 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
currentTs := time.Now().Unix() currentTs := time.Now().Unix()
memoResourceUpsert := &api.MemoResourceUpsert{ memoResourceUpsert := &api.MemoResourceUpsert{
MemoID: memoID,
UpdatedTs: &currentTs, UpdatedTs: &currentTs,
} }
if err := json.NewDecoder(c.Request().Body).Decode(memoResourceUpsert); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(memoResourceUpsert); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post memo resource request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post memo resource request").SetInternal(err)
} }
memoResourceUpsert.MemoID = memoID
if _, err := s.Store.UpsertMemoResource(ctx, memoResourceUpsert); err != nil { if _, err := s.Store.UpsertMemoResource(ctx, memoResourceUpsert); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert memo resource").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert memo resource").SetInternal(err)
@ -488,26 +365,127 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
return nil return nil
}) })
g.DELETE("/memo/:memoId/resource/:resourceId", func(c echo.Context) error { g.GET("/memo/amount", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
memoID, err := strconv.Atoi(c.Param("memoId")) normalRowStatus := api.Normal
memoFind := &api.MemoFind{
RowStatus: &normalRowStatus,
}
if userID, err := strconv.Atoi(c.QueryParam("userId")); err == nil {
memoFind.CreatorID = &userID
}
memoList, err := s.Store.FindMemoList(ctx, memoFind)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Memo ID is not a number: %s", c.Param("memoId"))).SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo list").SetInternal(err)
} }
resourceID, err := strconv.Atoi(c.Param("resourceId"))
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(len(memoList))); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode memo amount").SetInternal(err)
}
return nil
})
g.GET("/memo/stats", func(c echo.Context) error {
ctx := c.Request().Context()
normalStatus := api.Normal
memoFind := &api.MemoFind{
RowStatus: &normalStatus,
}
if creatorID, err := strconv.Atoi(c.QueryParam("creatorId")); err == nil {
memoFind.CreatorID = &creatorID
}
if memoFind.CreatorID == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Missing user id to find memo")
}
currentUserID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
memoFind.VisibilityList = []api.Visibility{api.Public}
} else {
if *memoFind.CreatorID != currentUserID {
memoFind.VisibilityList = []api.Visibility{api.Public, api.Protected}
} else {
memoFind.VisibilityList = []api.Visibility{api.Public, api.Protected, api.Private}
}
}
list, err := s.Store.FindMemoList(ctx, memoFind)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Resource ID is not a number: %s", c.Param("resourceId"))).SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch memo list").SetInternal(err)
} }
memoResourceDelete := &api.MemoResourceDelete{ displayTsList := []int64{}
MemoID: &memoID, for _, memo := range list {
ResourceID: &resourceID, displayTsList = append(displayTsList, memo.DisplayTs)
} }
if err := s.Store.DeleteMemoResource(ctx, memoResourceDelete); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch resource list").SetInternal(err) c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(displayTsList)); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode memo stats response").SetInternal(err)
} }
return nil
})
return c.JSON(http.StatusOK, true) g.GET("/memo/all", func(c echo.Context) error {
ctx := c.Request().Context()
memoFind := &api.MemoFind{}
_, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
memoFind.VisibilityList = []api.Visibility{api.Public}
} else {
memoFind.VisibilityList = []api.Visibility{api.Public, api.Protected}
}
pinnedStr := c.QueryParam("pinned")
if pinnedStr != "" {
pinned := pinnedStr == "true"
memoFind.Pinned = &pinned
}
tag := c.QueryParam("tag")
if tag != "" {
contentSearch := "#" + tag + " "
memoFind.ContentSearch = &contentSearch
}
visibilityListStr := c.QueryParam("visibility")
if visibilityListStr != "" {
visibilityList := []api.Visibility{}
for _, visibility := range strings.Split(visibilityListStr, ",") {
visibilityList = append(visibilityList, api.Visibility(visibility))
}
memoFind.VisibilityList = visibilityList
}
if limit, err := strconv.Atoi(c.QueryParam("limit")); err == nil {
memoFind.Limit = limit
}
if offset, err := strconv.Atoi(c.QueryParam("offset")); err == nil {
memoFind.Offset = offset
}
// Only fetch normal status memos.
normalStatus := api.Normal
memoFind.RowStatus = &normalStatus
list, err := s.Store.FindMemoList(ctx, memoFind)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch all memo list").SetInternal(err)
}
sort.Slice(list, func(i, j int) bool {
return list[i].DisplayTs > list[j].DisplayTs
})
if memoFind.Limit != 0 {
list = list[memoFind.Offset:common.Min(len(list), memoFind.Offset+memoFind.Limit)]
}
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(list)); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode all memo list response").SetInternal(err)
}
return nil
}) })
g.DELETE("/memo/:memoId", func(c echo.Context) error { g.DELETE("/memo/:memoId", func(c echo.Context) error {
@ -516,19 +494,20 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
if !ok { if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
} }
memoID, err := strconv.Atoi(c.Param("memoId")) memoID, err := strconv.Atoi(c.Param("memoId"))
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("memoId"))).SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("memoId"))).SetInternal(err)
} }
memoFind := &api.MemoFind{ memo, err := s.Store.FindMemo(ctx, &api.MemoFind{
ID: &memoID, ID: &memoID,
CreatorID: &userID, })
} if err != nil {
if _, err := s.Store.FindMemo(ctx, memoFind); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo").SetInternal(err)
} }
if memo.CreatorID != userID {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
memoDelete := &api.MemoDelete{ memoDelete := &api.MemoDelete{
ID: memoID, ID: memoID,
@ -542,4 +521,40 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)
}) })
g.DELETE("/memo/:memoId/resource/:resourceId", func(c echo.Context) error {
ctx := c.Request().Context()
userID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
}
memoID, err := strconv.Atoi(c.Param("memoId"))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Memo ID is not a number: %s", c.Param("memoId"))).SetInternal(err)
}
resourceID, err := strconv.Atoi(c.Param("resourceId"))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Resource ID is not a number: %s", c.Param("resourceId"))).SetInternal(err)
}
memo, err := s.Store.FindMemo(ctx, &api.MemoFind{
ID: &memoID,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo").SetInternal(err)
}
if memo.CreatorID != userID {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
memoResourceDelete := &api.MemoResourceDelete{
MemoID: &memoID,
ResourceID: &resourceID,
}
if err := s.Store.DeleteMemoResource(ctx, memoResourceDelete); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch resource list").SetInternal(err)
}
return c.JSON(http.StatusOK, true)
})
} }

@ -56,13 +56,12 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
} }
resourceCreate := &api.ResourceCreate{ resourceCreate := &api.ResourceCreate{
CreatorID: userID,
Filename: filename, Filename: filename,
Type: filetype, Type: filetype,
Size: size, Size: size,
Blob: fileBytes, Blob: fileBytes,
CreatorID: userID,
} }
resource, err := s.Store.CreateResource(ctx, resourceCreate) resource, err := s.Store.CreateResource(ctx, resourceCreate)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create resource").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create resource").SetInternal(err)
@ -158,6 +157,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
c.Response().Writer.WriteHeader(http.StatusOK) c.Response().Writer.WriteHeader(http.StatusOK)
c.Response().Writer.Header().Set("Content-Type", resource.Type) c.Response().Writer.Header().Set("Content-Type", resource.Type)
c.Response().Writer.Header().Set(echo.HeaderContentSecurityPolicy, "default-src 'self'")
if _, err := c.Response().Writer.Write(resource.Blob); err != nil { if _, err := c.Response().Writer.Write(resource.Blob); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to write resource blob").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to write resource blob").SetInternal(err)
} }
@ -177,23 +177,26 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
} }
resourceFind := &api.ResourceFind{ resourceFind := &api.ResourceFind{
ID: &resourceID, ID: &resourceID,
CreatorID: &userID,
} }
if _, err := s.Store.FindResource(ctx, resourceFind); err != nil { resource, err := s.Store.FindResource(ctx, resourceFind)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find resource").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find resource").SetInternal(err)
} }
if resource.CreatorID != userID {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
currentTs := time.Now().Unix() currentTs := time.Now().Unix()
resourcePatch := &api.ResourcePatch{ resourcePatch := &api.ResourcePatch{
ID: resourceID,
UpdatedTs: &currentTs, UpdatedTs: &currentTs,
} }
if err := json.NewDecoder(c.Request().Body).Decode(resourcePatch); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(resourcePatch); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch resource request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch resource request").SetInternal(err)
} }
resource, err := s.Store.PatchResource(ctx, resourcePatch) resource.ID = resourceID
resource, err = s.Store.PatchResource(ctx, resourcePatch)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch resource").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch resource").SetInternal(err)
} }
@ -224,8 +227,8 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find resource").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find resource").SetInternal(err)
} }
if resource == nil { if resource.CreatorID != userID {
return echo.NewHTTPError(http.StatusNotFound, "Not find resource").SetInternal(err) return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
} }
resourceDelete := &api.ResourceDelete{ resourceDelete := &api.ResourceDelete{

@ -21,13 +21,12 @@ func (s *Server) registerShortcutRoutes(g *echo.Group) {
if !ok { if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
} }
shortcutCreate := &api.ShortcutCreate{ shortcutCreate := &api.ShortcutCreate{}
CreatorID: userID,
}
if err := json.NewDecoder(c.Request().Body).Decode(shortcutCreate); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(shortcutCreate); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post shortcut request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post shortcut request").SetInternal(err)
} }
shortcutCreate.CreatorID = userID
shortcut, err := s.Store.CreateShortcut(ctx, shortcutCreate) shortcut, err := s.Store.CreateShortcut(ctx, shortcutCreate)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create shortcut").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create shortcut").SetInternal(err)
@ -45,21 +44,36 @@ func (s *Server) registerShortcutRoutes(g *echo.Group) {
g.PATCH("/shortcut/:shortcutId", func(c echo.Context) error { g.PATCH("/shortcut/:shortcutId", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
}
shortcutID, err := strconv.Atoi(c.Param("shortcutId")) shortcutID, err := strconv.Atoi(c.Param("shortcutId"))
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("shortcutId"))).SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("shortcutId"))).SetInternal(err)
} }
shortcutFind := &api.ShortcutFind{
ID: &shortcutID,
}
shortcut, err := s.Store.FindShortcut(ctx, shortcutFind)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find shortcut").SetInternal(err)
}
if shortcut.CreatorID != userID {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
currentTs := time.Now().Unix() currentTs := time.Now().Unix()
shortcutPatch := &api.ShortcutPatch{ shortcutPatch := &api.ShortcutPatch{
ID: shortcutID,
UpdatedTs: &currentTs, UpdatedTs: &currentTs,
} }
if err := json.NewDecoder(c.Request().Body).Decode(shortcutPatch); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(shortcutPatch); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch shortcut request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch shortcut request").SetInternal(err)
} }
shortcut, err := s.Store.PatchShortcut(ctx, shortcutPatch) shortcutPatch.ID = shortcutID
shortcut, err = s.Store.PatchShortcut(ctx, shortcutPatch)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch shortcut").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch shortcut").SetInternal(err)
} }
@ -73,17 +87,12 @@ func (s *Server) registerShortcutRoutes(g *echo.Group) {
g.GET("/shortcut", func(c echo.Context) error { g.GET("/shortcut", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
shortcutFind := &api.ShortcutFind{} userID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
if userID, err := strconv.Atoi(c.QueryParam("creatorId")); err == nil { return echo.NewHTTPError(http.StatusBadRequest, "Missing user id to find shortcut")
shortcutFind.CreatorID = &userID }
} else { shortcutFind := &api.ShortcutFind{
userID, ok := c.Get(getUserIDContextKey()).(int) CreatorID: &userID,
if !ok {
return echo.NewHTTPError(http.StatusBadRequest, "Missing user id to find shortcut")
}
shortcutFind.CreatorID = &userID
} }
list, err := s.Store.FindShortcutList(ctx, shortcutFind) list, err := s.Store.FindShortcutList(ctx, shortcutFind)
@ -122,11 +131,26 @@ func (s *Server) registerShortcutRoutes(g *echo.Group) {
g.DELETE("/shortcut/:shortcutId", func(c echo.Context) error { g.DELETE("/shortcut/:shortcutId", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
}
shortcutID, err := strconv.Atoi(c.Param("shortcutId")) shortcutID, err := strconv.Atoi(c.Param("shortcutId"))
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("shortcutId"))).SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("shortcutId"))).SetInternal(err)
} }
shortcutFind := &api.ShortcutFind{
ID: &shortcutID,
}
shortcut, err := s.Store.FindShortcut(ctx, shortcutFind)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find shortcut").SetInternal(err)
}
if shortcut.CreatorID != userID {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
shortcutDelete := &api.ShortcutDelete{ shortcutDelete := &api.ShortcutDelete{
ID: &shortcutID, ID: &shortcutID,
} }

@ -76,13 +76,24 @@ func (s *Server) registerSystemRoutes(g *echo.Group) {
systemStatus.AdditionalScript = value.(string) systemStatus.AdditionalScript = value.(string)
} else if systemSetting.Name == api.SystemSettingCustomizedProfileName { } else if systemSetting.Name == api.SystemSettingCustomizedProfileName {
valueMap := value.(map[string]interface{}) valueMap := value.(map[string]interface{})
systemStatus.CustomizedProfile = api.CustomizedProfile{ systemStatus.CustomizedProfile = api.CustomizedProfile{}
Name: valueMap["name"].(string), if v := valueMap["name"]; v != nil {
LogoURL: valueMap["logoUrl"].(string), systemStatus.CustomizedProfile.Name = v.(string)
Description: valueMap["description"].(string), }
Locale: valueMap["locale"].(string), if v := valueMap["logoUrl"]; v != nil {
Appearance: valueMap["appearance"].(string), systemStatus.CustomizedProfile.LogoURL = v.(string)
ExternalURL: valueMap["externalUrl"].(string), }
if v := valueMap["description"]; v != nil {
systemStatus.CustomizedProfile.Description = v.(string)
}
if v := valueMap["locale"]; v != nil {
systemStatus.CustomizedProfile.Locale = v.(string)
}
if v := valueMap["appearance"]; v != nil {
systemStatus.CustomizedProfile.Appearance = v.(string)
}
if v := valueMap["externalUrl"]; v != nil {
systemStatus.CustomizedProfile.ExternalURL = v.(string)
} }
} }
} }
@ -125,9 +136,7 @@ func (s *Server) registerSystemRoutes(g *echo.Group) {
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
} }
if user == nil { if user == nil || user.Role != api.Host {
return echo.NewHTTPError(http.StatusNotFound, "Current signin user not found")
} else if user.Role != api.Host {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
} }

@ -23,9 +23,7 @@ func (s *Server) registerTagRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
} }
tagUpsert := &api.TagUpsert{ tagUpsert := &api.TagUpsert{}
CreatorID: userID,
}
if err := json.NewDecoder(c.Request().Body).Decode(tagUpsert); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(tagUpsert); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post tag request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post tag request").SetInternal(err)
} }
@ -33,6 +31,7 @@ func (s *Server) registerTagRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusBadRequest, "Tag name shouldn't be empty") return echo.NewHTTPError(http.StatusBadRequest, "Tag name shouldn't be empty")
} }
tagUpsert.CreatorID = userID
tag, err := s.Store.UpsertTag(ctx, tagUpsert) tag, err := s.Store.UpsertTag(ctx, tagUpsert)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert tag").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert tag").SetInternal(err)
@ -82,31 +81,18 @@ func (s *Server) registerTagRoutes(g *echo.Group) {
g.GET("/tag/suggestion", func(c echo.Context) error { g.GET("/tag/suggestion", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
return echo.NewHTTPError(http.StatusBadRequest, "Missing user session")
}
contentSearch := "#" contentSearch := "#"
normalRowStatus := api.Normal normalRowStatus := api.Normal
memoFind := api.MemoFind{ memoFind := api.MemoFind{
CreatorID: &userID,
ContentSearch: &contentSearch, ContentSearch: &contentSearch,
RowStatus: &normalRowStatus, RowStatus: &normalRowStatus,
} }
if userID, err := strconv.Atoi(c.QueryParam("creatorId")); err == nil {
memoFind.CreatorID = &userID
}
currentUserID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
if memoFind.CreatorID == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Missing user id to find memo")
}
memoFind.VisibilityList = []api.Visibility{api.Public}
} else {
if memoFind.CreatorID == nil {
memoFind.CreatorID = &currentUserID
} else {
memoFind.VisibilityList = []api.Visibility{api.Public, api.Protected}
}
}
memoList, err := s.Store.FindMemoList(ctx, &memoFind) memoList, err := s.Store.FindMemoList(ctx, &memoFind)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo list").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo list").SetInternal(err)

@ -29,18 +29,20 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user by id").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user by id").SetInternal(err)
} }
if currentUser.Role != api.Host { if currentUser.Role != api.Host {
return echo.NewHTTPError(http.StatusUnauthorized, "Only Host user can create member.") return echo.NewHTTPError(http.StatusUnauthorized, "Only Host user can create member")
} }
userCreate := &api.UserCreate{ userCreate := &api.UserCreate{}
OpenID: common.GenUUID(),
}
if err := json.NewDecoder(c.Request().Body).Decode(userCreate); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(userCreate); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post user request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post user request").SetInternal(err)
} }
if userCreate.Role == api.Host {
return echo.NewHTTPError(http.StatusForbidden, "Could not create host user")
}
userCreate.OpenID = common.GenUUID()
if err := userCreate.Validate(); err != nil { if err := userCreate.Validate(); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid user create format.").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Invalid user create format").SetInternal(err)
} }
passwordHash, err := bcrypt.GenerateFromPassword([]byte(userCreate.Password), bcrypt.DefaultCost) passwordHash, err := bcrypt.GenerateFromPassword([]byte(userCreate.Password), bcrypt.DefaultCost)
@ -74,6 +76,7 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
for _, user := range userList { for _, user := range userList {
// data desensitize // data desensitize
user.OpenID = "" user.OpenID = ""
user.Email = ""
} }
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
@ -159,6 +162,7 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
if user != nil { if user != nil {
// data desensitize // data desensitize
user.OpenID = "" user.OpenID = ""
user.Email = ""
} }
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
@ -192,14 +196,14 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
currentTs := time.Now().Unix() currentTs := time.Now().Unix()
userPatch := &api.UserPatch{ userPatch := &api.UserPatch{
ID: userID,
UpdatedTs: &currentTs, UpdatedTs: &currentTs,
} }
if err := json.NewDecoder(c.Request().Body).Decode(userPatch); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(userPatch); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch user request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch user request").SetInternal(err)
} }
userPatch.ID = userID
if err := userPatch.Validate(); err != nil { if err := userPatch.Validate(); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid user patch format.").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Invalid user patch format").SetInternal(err)
} }
if userPatch.Password != nil && *userPatch.Password != "" { if userPatch.Password != nil && *userPatch.Password != "" {

Loading…
Cancel
Save