dacument 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -79,7 +79,7 @@ Map keys must be JSON-compatible values (`string`, `number`, `boolean`, `null`,
79
79
  Roles are evaluated at the op stamp time (HLC).
80
80
 
81
81
  - Owner: full control (including ownership transfer).
82
- - Manager: can grant editor/viewer/revoked roles.
82
+ - Manager: can grant editor/viewer/revoked roles (cannot change owner).
83
83
  - Editor: can write non-ACL fields.
84
84
  - Viewer: read-only.
85
85
  - Revoked: reads are masked to initial values; writes are rejected.
@@ -164,6 +164,19 @@ If any non-revoked actor is offline and never acks, tombstones are kept.
164
164
  Eventual consistency is achieved when all signed ops are delivered to all
165
165
  replicas. Dacument does not provide transport; use `change` events to wire it up.
166
166
 
167
+ ## Possible threats and how to handle
168
+
169
+ - Key compromise: no rotation exists, so migrate by snapshotting into a new
170
+ dacument with fresh keys.
171
+ - Shared role keys: attribution is role-level, not per-user; treat roles as
172
+ trust groups and log merge events if you need auditing.
173
+ - Insider DoS/flooding: rate-limit ops, cap payload sizes, and monitor merge
174
+ errors at the application layer.
175
+ - Withholding/delivery delays: eventual consistency depends on ops arriving;
176
+ use reliable transport and resync via snapshot when needed.
177
+ - No built-in encryption: use TLS or E2E encryption and treat snapshots as
178
+ sensitive data.
179
+
167
180
  ## Compatibility
168
181
 
169
182
  - ESM only (`type: module`).
@@ -131,6 +131,7 @@ export declare class Dacument<S extends SchemaDefinition> {
131
131
  private emitError;
132
132
  private canWriteField;
133
133
  private canWriteAcl;
134
+ private canWriteAclTarget;
134
135
  private assertWritable;
135
136
  private assertValueType;
136
137
  private assertValueArray;
@@ -671,7 +671,7 @@ export class Dacument {
671
671
  const roleAt = this.aclLog.roleAt(payload.iss, payload.stamp);
672
672
  if (roleAt === signerRole &&
673
673
  isAclPatch(payload.patch) &&
674
- this.canWriteAcl(signerRole, payload.patch.role))
674
+ this.canWriteAclTarget(signerRole, payload.patch.role, payload.patch.target, payload.stamp))
675
675
  allowed = true;
676
676
  }
677
677
  }
@@ -1448,7 +1448,7 @@ export class Dacument {
1448
1448
  if (!isAclPatch(payload.patch))
1449
1449
  return false;
1450
1450
  const patch = payload.patch;
1451
- if (!this.canWriteAcl(signerRole, patch.role))
1451
+ if (!this.canWriteAclTarget(signerRole, patch.role, patch.target, payload.stamp))
1452
1452
  return false;
1453
1453
  const assignment = {
1454
1454
  id: patch.id,
@@ -1871,7 +1871,7 @@ export class Dacument {
1871
1871
  setRole(actorId, role) {
1872
1872
  const stamp = this.clock.next();
1873
1873
  const signerRole = this.aclLog.roleAt(this.actorId, stamp);
1874
- if (!this.canWriteAcl(signerRole, role))
1874
+ if (!this.canWriteAclTarget(signerRole, role, actorId, stamp))
1875
1875
  throw new Error(`Dacument: role '${signerRole}' cannot grant '${role}'`);
1876
1876
  const assignmentId = uuidv7();
1877
1877
  this.queueLocalOp({
@@ -1959,6 +1959,16 @@ export class Dacument {
1959
1959
  return targetRole === "editor" || targetRole === "viewer" || targetRole === "revoked";
1960
1960
  return false;
1961
1961
  }
1962
+ canWriteAclTarget(role, targetRole, targetActorId, stamp) {
1963
+ if (!this.canWriteAcl(role, targetRole))
1964
+ return false;
1965
+ if (role === "manager") {
1966
+ const targetRoleAt = this.aclLog.roleAt(targetActorId, stamp);
1967
+ if (targetRoleAt === "owner")
1968
+ return false;
1969
+ }
1970
+ return true;
1971
+ }
1962
1972
  assertWritable(field, role) {
1963
1973
  if (!this.canWriteField(role))
1964
1974
  throw new Error(`Dacument: role '${role}' cannot write '${field}'`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dacument",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Schema-driven CRDT document with signed ops and role-based ACLs.",
5
5
  "keywords": [
6
6
  "crdt",