You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit ee112a7
Browse filesBrowse the repository at this point in the historyBrowse files
`manage:comments`, `manage:navigation`, `read:glossary`, `manage:glossary` (`PAGE_PERMISSIONS` in `models/groups.ts`). A group grants them through **rules**:
(`PAGE_PERMISSIONS` in `models/groups.ts`). A group grants them through **rules**:
583
584
each rule names some of them (`roles`) plus how it addresses pages (`match` + `path`, or tags) and
584
585
what it does with them (`mode`: ALLOW / DENY / FORCEALLOW). Nothing is granted by default, and when
585
586
several rules match, the most specific one wins — `helpers/pageRules.ts` documents the ordering.
@@ -617,6 +618,12 @@ Consequences worth knowing:
617
618
`groups.checkLocaleAccess(actor, permission, siteId, locale)`; `checkAccess` routes them there too.
618
619
`manage:glossary` in a locale implies `read:glossary` there. Neither is in the Guests group's seeded
619
620
DENY rule, where it would outrank any ALLOW an administrator wrote for guests later.
621
+
-**`read:notes` and `write:notes` ignore the path too**, and are asked in the site's PRIMARY locale,
622
+
since a live note belongs to a site and to no locale (`liveNotes.permissionsFor`). `write:notes`
623
+
implies `read:notes`. The Users group is seeded with `read:notes` only, so out of the box any account
624
+
can open a shared note and only administrators can start one. The guests group may be granted
625
+
`read:notes` (it is in `GUEST_ROLES`, not in the seeded DENY rule) and never `write:notes`, which
626
+
`permissionsFor` refuses to a requester with no account whatever the rules say.
620
627
-**A page that is not live is its editors' alone.** Live is `published`, or `scheduled` inside its
621
628
window (`publishStartDate` inclusive, `publishEndDate` exclusive); the dates gate nothing on a
622
629
`published` page, where `publishStartDate` is what a blog post is dated by. Any other page is seen —
@@ -1332,26 +1339,42 @@ menu. **`dev/specs/glossary.md` is the design**; `models/glossary.ts`, `api/glos
1332
1339
1333
1340
### Live notes
1334
1341
1335
-
A markdown scratch document written together in real time at `/n/<key>` (HedgeDoc-style), by anybody
1336
-
signed in who holds the URL. `models/liveNotes.ts`, `api/liveNotes.ts`, the note room in
1342
+
A markdown scratch document written together in real time at `/n/<key>` (HedgeDoc-style), by whoever
1343
+
holds the URL and may use notes on the site. `models/liveNotes.ts`, `api/liveNotes.ts`, the note room in
1337
1344
`core/collab.ts`; on the frontend `pages/LiveNote.vue`, `stores/liveNote.js`, and `EditorMarkdown.vue`
1338
-
under its `noteKey` prop. The site switch is `features.liveNotes`, which also needs
1345
+
under its `noteKey` prop. The site switch is `features.liveNotes` (on by default), which also needs
1339
1346
`collaborativeEditing`.
1340
1347
1341
-
-**Not a page.** No tree entry, no page rules, no render, no save. The 24-character key (~143 bits,
1342
-
`crypto`) is the credential, so it never goes in a log or an audit entry (record `noteId`), nor in
1348
+
-**Two permissions bound everything else**: `read:notes` to open a note and follow it live, and
1349
+
`write:notes` to create one, write in one, and own one (see [Permissions](#permissions)). The
1350
+
frontend learns them from `GET /sites/:siteId/notes/_access` (`liveNoteStore.ensureAccess`) — `_`
1351
+
because `access` is a key somebody could pick. A guest holding `read:notes` reads through the same
1352
+
routes and joins the room as a reader, with no awareness state of its own (every guest shares one
1353
+
placeholder id); a guest is never handed the Editor, Publish to Page, or an image upload.
1354
+
1355
+
-**Not a page.** No tree entry, no path for a page rule to match, no render, no save. The key is the credential: 24
1356
+
characters from `crypto` (~143 bits) for a note made at `/n`, or whatever somebody typed — visiting
1357
+
`/n/<key>` for a key no note on the site has yet creates one under it (1–64 of `[A-Za-z0-9-]`,
1358
+
case-sensitive, unique per site; `KEY_PATTERN`, mirrored as `NOTE_KEY_PATTERN` in
1359
+
`stores/liveNote.js`). Only a navigation creates, and only for somebody holding `write:notes` — anybody
1360
+
else is told there is no such note: a note deleted under its readers reloads as gone.
1361
+
Either way it never goes in a log or an audit entry (record `noteId`), nor in
1343
1362
any listing but its creator's own: **Profile → My Live Notes** (`GET /sites/:siteId/notes`,
1344
1363
`liveNotes.listByCreator`) lists only the notes the caller created, whose keys they already hold. Beyond the key, `liveNotes.rightsFor` is the only thing that decides access. Owners (the
1345
-
creator, plus `manage:system`) can always do everything, and everybody else gets what `access`
1346
-
allows (`editable` / `locked` / `private`). Every route and the socket ask it; nothing works it out
1347
-
for itself.
1364
+
creator while they hold `write:notes`, plus `manage:system`) can always do everything, and everybody
1365
+
else gets what `access`allows (`editable` / `locked` / `private`) within their own `read:notes` /
1366
+
`write:notes`. Every route and the socket ask it; nothing works it out for itself.
1348
1367
-**The collaboration room is the storage.** A note room (id `note:<noteId>`) persists its Yjs
1349
1368
document through `liveNotes.persist`: 2s after the last edit, at least every 10s while typing goes
1350
1369
on, and once more when it closes. It writes under the row lock and merges into what is stored,
1351
1370
because several instances may each hold the note open. `state` is the Yjs document itself, never
1352
1371
re-seeded from text, so a client that reconnects with offline edits merges into the same document
1353
1372
instead of duplicating it. `content` and `title` are derived from `state` on every write.
1354
1373
`titleOf` (backend) and `noteTitleOf` (`stores/liveNote.js`) must agree.
1374
+
-**An untouched note is deleted after a day** (`liveNotes.purgeUntouched`, hourly off
1375
+
`SYSTEM_SCHEDULE`): empty content, no revision, and `updatedAt` older than
1376
+
`UNTOUCHED_NOTE_TTL_HOURS`. Only typing moves `updatedAt`, so opening a note does not keep it, and a
1377
+
note written and then cleared keeps its history and is not touched.
1355
1378
-**Revisions** are whole copies, taken at most every `REVISION_INTERVAL_MS` (5 min) and when the last
1356
1379
participant leaves, and only when the content changed.
1357
1380
-**Deleting a note or changing its access doesn't reach open rooms by itself.** The route calls
@@ -1361,7 +1384,7 @@ under its `noteKey` prop. The site switch is `features.liveNotes`, which also ne
1361
1384
every storage target gets them. The type is read from the bytes (PNG, JPEG, GIF, WebP, SVG) and SVG
1362
1385
goes through `uploadScanSVG`. `groups.checkAccess` says no to every page permission under `n/` for
1363
1386
everybody, which is what hides it from the File Manager and every API. `/_files/` serves it to
1364
-
anybody signed in instead, and the tree refuses `n` as a new root name. `liveNoteImages` lists each
1387
+
anybody holding `read:notes` on the site instead, guests included, and the tree refuses `n` as a new root name. `liveNoteImages` lists each
1365
1388
note's images, and `liveNotes.delete` removes them with the note. The images are kept until then,
1366
1389
even after the text stops showing them, because a revision may still use them.
1367
1390
-**Publish to Page** (`publishToPage` in `LiveNote.vue`) makes a page of a note in the browser, with
0 commit comments