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
Note: A shallow document only contains history after a certain version point. Operations before the shallow start point are not included, but the document remains fully functional for collaboration.
250
250
251
+
### Redacting Sensitive Content
252
+
253
+
Loro allows you to redact specific segments of document history while preserving the rest. This is particularly useful when:
254
+
255
+
1. A user accidentally pastes sensitive information (like passwords or API keys) into the document
256
+
2. You need to remove just the sensitive part of the history while keeping older and newer edits intact
257
+
3. You want to share document history with sensitive segments sanitized
258
+
259
+
Here's how to use the redaction functionality:
260
+
261
+
```typescript
262
+
const doc =newLoroDoc();
263
+
doc.setPeerId("1");
264
+
265
+
// Create some content to be redacted
266
+
const text =doc.getText("text");
267
+
text.insert(0, "Sensitive information");
268
+
doc.commit();
269
+
270
+
const map =doc.getMap("map");
271
+
map.set("password", "secret123");
272
+
map.set("public", "public information");
273
+
doc.commit();
274
+
275
+
// Export JSON updates
276
+
const jsonUpdates =doc.exportJsonUpdates();
277
+
278
+
// Define version range to redact (redact the text content)
279
+
const versionRange = {
280
+
"1": [0, 21] // Redact the "Sensitive information"
Redaction applies these rules to preserve document structure while removing sensitive content:
300
+
- Preserves delete and move operations
301
+
- Replaces text insertion content with Unicode replacement characters '�'
302
+
- Substitutes list and map insert values with null
303
+
- Maintains structure of nested containers
304
+
- Replaces text mark values with null
305
+
- Preserves map keys and text annotation keys
306
+
307
+
Note that redaction doesn't remove the operations completely - it just replaces the sensitive content with placeholders. If you need to completely remove portions of history, see the section on shallow snapshots in the [Tips](./tips.md) section.
308
+
309
+
#### Important: Synchronization Considerations
310
+
311
+
Both redaction and shallow snapshots maintain future synchronization consistency, but your application is responsible for ensuring all peers get the sanitized version. Otherwise, old instances of the document with sensitive information will still exist on other peers.
2. If it's impossible to initialize all child containers when the map container is initialized, prefer initializing them at the root level rather than as nested containers.
77
77
- You can use `doc.getMap("user." + userId)` instead of `doc.getMap("user").getOrCreateContainer(userId, new LoroMap())` to avoid this problem.
78
78
</details>
79
+
80
+
---
81
+
82
+
##### Use redaction to safely share document history
83
+
84
+
There are times when users might accidentally paste sensitive information (like API keys, passwords, or personal data) into a collaborative document. When this happens, you need a way to remove just that sensitive content from the document history without compromising the rest of the document's integrity.
85
+
86
+
<details>
87
+
<summary>How to safely redact sensitive content</summary>
88
+
89
+
Loro provides a `redactJsonUpdates` function that allows you to selectively redact operations within specific version ranges.
90
+
91
+
For example, if a user accidentally pastes a password or API key into a document:
92
+
93
+
```typescript
94
+
const doc =newLoroDoc();
95
+
doc.setPeerId("1");
96
+
97
+
// Create some content to be redacted
98
+
const text =doc.getText("text");
99
+
text.insert(0, "Sensitive information");
100
+
doc.commit();
101
+
102
+
const map =doc.getMap("map");
103
+
map.set("password", "secret123");
104
+
map.set("public", "public information");
105
+
doc.commit();
106
+
107
+
// Export JSON updates
108
+
const jsonUpdates =doc.exportJsonUpdates();
109
+
110
+
// Define version range to redact (redact the text content)
111
+
const versionRange = {
112
+
"1": [0, 21] // Redact the "Sensitive information"
This approach is safer than manually editing document content because:
140
+
141
+
1. It maintains document structure and CRDT consistency
142
+
2. It keeps key metadata like operation IDs and dependencies intact
143
+
3. It allows concurrent editing to continue working after redaction
144
+
4. It selectively redacts only specific operations, not the entire document
145
+
146
+
The redaction process follows these rules:
147
+
- Preserves delete, tree move, and list move operations
148
+
- Replaces text insertion content with Unicode replacement characters '�'
149
+
- Substitutes list and map insert values with null
150
+
- Maintains structure of child containers
151
+
- Replaces text mark values with null
152
+
- Preserves map keys and text annotation keys
153
+
154
+
**Important**: Your application needs to ensure that all peers receive the redacted version, otherwise the original document with sensitive information will still exist on other peers.
155
+
156
+
</details>
157
+
158
+
---
159
+
160
+
##### Use shallow snapshots to completely remove old history
161
+
162
+
When you need to completely remove ALL history older than a certain version point, shallow snapshots provide the solution.
163
+
164
+
<details>
165
+
<summary>How to remove old history with shallow snapshots</summary>
166
+
167
+
Shallow snapshots create a new document that preserves the current state but completely eliminates all history before a specified point, similar to Git's shallow clone functionality.
168
+
169
+
```typescript
170
+
const doc =newLoroDoc();
171
+
doc.setPeerId("1");
172
+
173
+
// Old history - will be completely removed
174
+
const text =doc.getText("text");
175
+
text.insert(0, "This document has a long history with many edits");
176
+
doc.commit();
177
+
text.insert(0, "Including some potentially sensitive information. ");
178
+
doc.commit();
179
+
180
+
// More recent history - will be preserved
181
+
text.delete(11, 55); // Remove the middle part
182
+
text.insert(11, "with sanitized history");
183
+
doc.commit();
184
+
185
+
// Create a sanitized version that removes ALL history before current point
186
+
const sanitizedSnapshot =doc.export({
187
+
mode: "shallow-snapshot",
188
+
frontiers: doc.oplogFrontiers()
189
+
});
190
+
191
+
// Create a new document from the sanitized snapshot
// But ALL history before the snapshot point is completely removed
200
+
console.log(sanitizedDoc.isShallow()); // true
201
+
console.log(sanitizedDoc.shallowSinceFrontiers()); // Shows the starting point
202
+
```
203
+
204
+
This approach is useful for:
205
+
206
+
1. Completely removing all old history that might contain various sensitive information
207
+
2. Significantly reducing document size by eliminating unnecessary history
208
+
3. Creating clean document instances after certain milestones
209
+
4. Ensuring old operations cannot be recovered or examined
210
+
211
+
Compared to redaction:
212
+
- Shallow snapshots completely remove all operations before a version point
213
+
- Redaction selectively replaces just specific content with placeholders
214
+
215
+
**Important**: While both methods maintain future synchronization consistency, your application must distribute the sanitized document to all peers. Otherwise, the original document with sensitive information will still exist on other clients.
216
+
217
+
**When to use each approach**:
218
+
- Use **redaction** when you need to sanitize specific operations (like an accidental password paste) while preserving older history
219
+
- Use **shallow snapshots** when you want to completely eliminate all history before a certain point
0 commit comments