fix: allow share-link users to view/edit and autosave via share token

Users without personal document access can still load/save state when
a valid share token is present, matching the permission level granted
by the share link.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
M1ngdaXie
2026-08-15 14:55:59 +08:00
co-authored by Claude Sonnet 5
parent 7b5558bc94
commit aa67446f7c
5 changed files with 73 additions and 9 deletions
+37 -2
View File
@@ -381,8 +381,6 @@ func (s *DocumentHandlerSuite) TestGetDocumentState_Success() {
s.assertSuccessResponse(w, http.StatusOK)
s.Equal("application/octet-stream", w.Header().Get("Content-Type"))
// State should be empty bytes for new document
s.NotNil(w.Body.Bytes())
}
func (s *DocumentHandlerSuite) TestGetDocumentState_EmptyState() {
@@ -416,6 +414,17 @@ func (s *DocumentHandlerSuite) TestGetDocumentState_InvalidID() {
s.assertErrorResponse(w, http.StatusBadRequest, "bad_request", "Invalid document ID")
}
func (s *DocumentHandlerSuite) TestGetDocumentState_AuthenticatedWithShareToken() {
// Charlie (logged in, not owner/shared) reads Alice's public doc via share link
path := fmt.Sprintf("/api/documents/%s/state?share=%s", s.testData.AlicePublicDoc, s.testData.PublicShareToken)
w, httpReq, err := s.makeAuthRequest("GET", path, nil, s.testData.CharlieID)
s.Require().NoError(err)
s.router.ServeHTTP(w, httpReq)
s.assertSuccessResponse(w, http.StatusOK)
s.Equal("application/octet-stream", w.Header().Get("Content-Type"))
}
// ========================================
// UpdateDocumentState Tests
// ========================================
@@ -458,6 +467,32 @@ func (s *DocumentHandlerSuite) TestUpdateDocumentState_ViewOnlyDenied() {
s.router.ServeHTTP(w, httpReq)
s.assertErrorResponse(w, http.StatusForbidden, "forbidden", "Edit access denied")
}
func (s *DocumentHandlerSuite) TestUpdateDocumentState_AuthenticatedWithEditShareToken() {
// Give Alice's public doc an "edit" share link
ctx := context.Background()
editToken, err := s.store.GenerateShareToken(ctx, s.testData.AlicePublicDoc, "edit")
s.Require().NoError(err)
// Charlie (logged in, not owner/shared) edits via edit share link
req := models.UpdateStateRequest{State: []byte("shared edit")}
path := fmt.Sprintf("/api/documents/%s/state?share=%s", s.testData.AlicePublicDoc, editToken)
w, httpReq, err := s.makeAuthRequest("PUT", path, req, s.testData.CharlieID)
s.Require().NoError(err)
s.router.ServeHTTP(w, httpReq)
s.assertSuccessResponse(w, http.StatusOK)
}
func (s *DocumentHandlerSuite) TestUpdateDocumentState_AuthenticatedWithViewShareTokenDenied() {
// Alice's public doc has a "view" share link (from seed).
// Charlie (logged in) cannot write via a view-only share link.
req := models.UpdateStateRequest{State: []byte("attempt write")}
path := fmt.Sprintf("/api/documents/%s/state?share=%s", s.testData.AlicePublicDoc, s.testData.PublicShareToken)
w, httpReq, err := s.makeAuthRequest("PUT", path, req, s.testData.CharlieID)
s.Require().NoError(err)
s.router.ServeHTTP(w, httpReq)
s.assertErrorResponse(w, http.StatusForbidden, "forbidden", "Edit access denied")
}
func (s *DocumentHandlerSuite) TestUpdateDocumentState_Unauthorized() {
req := models.UpdateStateRequest{