···5151 // AccessToken is the ATProto access token for WebSocket auth.
5252 // Empty string if user has no ATProto session.
5353 AccessToken string
5454+ // IsOwner is true when the current user owns (created) the document.
5555+ IsOwner bool
5456 // IsCollaborator is true when the current user is in the collaborators list.
5557 IsCollaborator bool
5658}
···339341 doc.RKey = rkey
340342341343 // Fetch ATProto session to pass access token to the WebSocket client.
342342- editData := &DocumentEditData{Document: doc}
344344+ // The user is always the owner here since we fetched the doc via client.DID().
345345+ editData := &DocumentEditData{Document: doc, IsOwner: true}
343346 if session, err := h.DB.GetATProtoSession(user.ID); err == nil && session != nil {
344347 editData.AccessToken = session.AccessToken
345348 // Check if this user is listed as a collaborator on the doc.
···486489 }
487490 doc.RKey = rkey
488491489489- session, err := h.DB.GetATProtoSession(user.ID)
490490- if err != nil || session == nil {
491491- http.Error(w, "Unauthorized", http.StatusForbidden)
492492- return
493493- }
494494-495495- parts := strings.Split(doc.URI, "/")
496496- ownerDID := ""
497497- if len(parts) >= 2 {
498498- ownerDID = parts[1]
499499- }
500500- if ownerDID == "" || session.DID != ownerDID {
501501- http.Error(w, "Unauthorized", http.StatusForbidden)
502502- return
503503- }
504504-492492+ // The document was fetched via client.DID(), so the current user is always the owner.
505493 if len(doc.Collaborators) >= 5 {
506494 http.Error(w, "Maximum collaborators reached", http.StatusBadRequest)
507495 return
508496 }
509497510510- invite, err := collaboration.CreateInvite(h.DB, rkey, session.DID)
498498+ invite, err := collaboration.CreateInvite(h.DB, rkey, client.DID())
511499 if err != nil {
512500 log.Printf("DocumentInvite: create invite: %v", err)
513501 http.Error(w, "Failed to create invite", http.StatusInternalServerError)