or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

access-controllers.mdaddress-management.mddatabase-types.mdidentity-system.mdindex.mdoplog-system.mdorbitdb-factory.mdstorage-backends.md

access-controllers.mddocs/

0

# Access Controllers

1

2

Access controllers provide a pluggable system for managing database permissions in OrbitDB. They determine who can write to databases, read from them, and perform administrative operations.

3

4

## Capabilities

5

6

### Access Controller System

7

8

Register and manage access controllers for different permission models.

9

10

```javascript { .api }

11

/**

12

* Registers a custom access controller

13

* @param accessController Access controller implementation with type property

14

* @throws "AccessController does not contain required field 'type'"

15

* @throws "AccessController '${type}' already added"

16

*/

17

function useAccessController(accessController: AccessController): void;

18

19

interface AccessController {

20

/** Unique type identifier for this access controller */

21

type: string;

22

/** Checks if an entry can be appended to the log */

23

canAppend(entry: Entry, identityProvider: IdentityProvider): Promise<boolean>;

24

/** Optional: grants capabilities to identities */

25

grant?(capability: string, identity: string): Promise<void>;

26

/** Optional: revokes capabilities from identities */

27

revoke?(capability: string, identity: string): Promise<void>;

28

}

29

```

30

31

**Usage Examples:**

32

33

```javascript

34

import { useAccessController } from '@orbitdb/core';

35

36

// Register a custom access controller

37

const MyAccessController = {

38

type: 'my-custom-ac',

39

async canAppend(entry, identityProvider) {

40

// Custom permission logic

41

return entry.identity === 'allowed-user-id';

42

}

43

};

44

45

useAccessController(MyAccessController);

46

47

// Use the custom access controller

48

const db = await orbitdb.open('protected-db', {

49

AccessController: MyAccessController

50

});

51

```

52

53

### IPFS Access Controller

54

55

The default access controller that uses IPFS for permission management.

56

57

```javascript { .api }

58

interface IPFSAccessController extends AccessController {

59

type: 'ipfs';

60

61

/**

62

* Checks if an identity can append entries to the database

63

* @param entry The entry being added

64

* @param identityProvider Identity provider for verification

65

* @returns Promise resolving to true if allowed

66

*/

67

canAppend(entry: Entry, identityProvider: IdentityProvider): Promise<boolean>;

68

69

/**

70

* Grants write permission to an identity

71

* @param capability The capability to grant (typically 'write')

72

* @param identity The identity to grant permission to

73

*/

74

grant(capability: string, identity: string): Promise<void>;

75

76

/**

77

* Revokes permission from an identity

78

* @param capability The capability to revoke

79

* @param identity The identity to revoke permission from

80

*/

81

revoke(capability: string, identity: string): Promise<void>;

82

}

83

```

84

85

**Usage Examples:**

86

87

```javascript

88

import { createOrbitDB, IPFSAccessController } from '@orbitdb/core';

89

90

const ipfs = await createHelia();

91

const orbitdb = await createOrbitDB({ ipfs });

92

93

// Create database with IPFS access controller (default)

94

const db = await orbitdb.open('my-db', {

95

AccessController: IPFSAccessController

96

});

97

98

// Grant write access to another identity

99

await db.access.grant('write', 'another-peer-id');

100

101

// Check if current identity can write

102

const canWrite = await db.access.canAppend(someEntry, identityProvider);

103

console.log('Can write:', canWrite);

104

```

105

106

### OrbitDB Access Controller

107

108

Enhanced access controller with OrbitDB-specific features.

109

110

```javascript { .api }

111

interface OrbitDBAccessController extends AccessController {

112

type: 'orbitdb';

113

114

/**

115

* Checks if an identity can append entries with OrbitDB-specific rules

116

* @param entry The entry being added

117

* @param identityProvider Identity provider for verification

118

* @returns Promise resolving to true if allowed

119

*/

120

canAppend(entry: Entry, identityProvider: IdentityProvider): Promise<boolean>;

121

}

122

```

123

124

**Usage Examples:**

125

126

```javascript

127

import { createOrbitDB, OrbitDBAccessController } from '@orbitdb/core';

128

129

const ipfs = await createHelia();

130

const orbitdb = await createOrbitDB({ ipfs });

131

132

// Create database with OrbitDB access controller

133

const db = await orbitdb.open('enhanced-db', {

134

AccessController: OrbitDBAccessController

135

});

136

137

// OrbitDB access controller provides enhanced permission checking

138

const entry = await createSomeEntry();

139

const canAppend = await db.access.canAppend(entry, orbitdb.identities);

140

```

141

142

### Custom Access Controllers

143

144

Create custom access controllers for specific permission models.

145

146

```javascript { .api }

147

/**

148

* Template for custom access controller implementation

149

*/

150

interface CustomAccessController extends AccessController {

151

type: string;

152

canAppend(entry: Entry, identityProvider: IdentityProvider): Promise<boolean>;

153

grant?(capability: string, identity: string): Promise<void>;

154

revoke?(capability: string, identity: string): Promise<void>;

155

/** Optional: validate access controller configuration */

156

validate?(config: any): boolean;

157

/** Optional: serialize access controller state */

158

serialize?(): any;

159

/** Optional: deserialize access controller state */

160

deserialize?(data: any): void;

161

}

162

```

163

164

**Usage Examples:**

165

166

```javascript

167

import { useAccessController } from '@orbitdb/core';

168

169

// Role-based access controller

170

const RoleBasedAccessController = {

171

type: 'role-based',

172

roles: new Map(), // identity -> role mapping

173

permissions: new Map(), // role -> permissions mapping

174

175

async canAppend(entry, identityProvider) {

176

const identity = entry.identity;

177

const role = this.roles.get(identity);

178

const permissions = this.permissions.get(role);

179

180

return permissions && permissions.includes('write');

181

},

182

183

async grant(capability, identity) {

184

// Grant role to identity

185

this.roles.set(identity, capability);

186

},

187

188

async revoke(capability, identity) {

189

// Remove role from identity

190

this.roles.delete(identity);

191

},

192

193

// Custom methods

194

setRole(identity, role) {

195

this.roles.set(identity, role);

196

},

197

198

defineRole(role, permissions) {

199

this.permissions.set(role, permissions);

200

}

201

};

202

203

// Register the custom access controller

204

useAccessController(RoleBasedAccessController);

205

206

// Use in database creation

207

const db = await orbitdb.open('role-based-db', {

208

AccessController: RoleBasedAccessController

209

});

210

211

// Configure roles and permissions

212

db.access.defineRole('admin', ['read', 'write', 'delete']);

213

db.access.defineRole('user', ['read', 'write']);

214

db.access.setRole('user123', 'user');

215

db.access.setRole('admin456', 'admin');

216

```

217

218

### Multi-Signature Access Controller

219

220

Example of a more complex access controller requiring multiple signatures.

221

222

```javascript

223

const MultiSigAccessController = {

224

type: 'multisig',

225

requiredSignatures: 2,

226

authorizedSigners: new Set(),

227

pendingOperations: new Map(),

228

229

async canAppend(entry, identityProvider) {

230

const identity = entry.identity;

231

232

// Check if signer is authorized

233

if (!this.authorizedSigners.has(identity)) {

234

return false;

235

}

236

237

const operationId = this.getOperationId(entry);

238

const signatures = this.pendingOperations.get(operationId) || new Set();

239

signatures.add(identity);

240

241

if (signatures.size >= this.requiredSignatures) {

242

// Enough signatures, allow operation

243

this.pendingOperations.delete(operationId);

244

return true;

245

} else {

246

// Store signature and wait for more

247

this.pendingOperations.set(operationId, signatures);

248

return false;

249

}

250

},

251

252

getOperationId(entry) {

253

// Create deterministic ID for the operation

254

return `${entry.payload.op}-${entry.payload.key}-${JSON.stringify(entry.payload.value)}`;

255

},

256

257

addSigner(identity) {

258

this.authorizedSigners.add(identity);

259

},

260

261

removeSigner(identity) {

262

this.authorizedSigners.delete(identity);

263

}

264

};

265

266

useAccessController(MultiSigAccessController);

267

```

268

269

### Time-Based Access Controller

270

271

Access controller with time-based permissions.

272

273

```javascript

274

const TimeBasedAccessController = {

275

type: 'time-based',

276

permissions: new Map(), // identity -> { start, end, capabilities }

277

278

async canAppend(entry, identityProvider) {

279

const identity = entry.identity;

280

const permission = this.permissions.get(identity);

281

282

if (!permission) {

283

return false;

284

}

285

286

const now = Date.now();

287

const isTimeValid = now >= permission.start && now <= permission.end;

288

const hasCapability = permission.capabilities.includes('write');

289

290

return isTimeValid && hasCapability;

291

},

292

293

async grant(capability, identity) {

294

const existing = this.permissions.get(identity) || { capabilities: [] };

295

if (!existing.capabilities.includes(capability)) {

296

existing.capabilities.push(capability);

297

this.permissions.set(identity, existing);

298

}

299

},

300

301

// Custom methods

302

grantTimeLimited(identity, capabilities, startTime, endTime) {

303

this.permissions.set(identity, {

304

start: startTime,

305

end: endTime,

306

capabilities: Array.isArray(capabilities) ? capabilities : [capabilities]

307

});

308

},

309

310

extendPermission(identity, newEndTime) {

311

const permission = this.permissions.get(identity);

312

if (permission) {

313

permission.end = newEndTime;

314

this.permissions.set(identity, permission);

315

}

316

}

317

};

318

319

useAccessController(TimeBasedAccessController);

320

321

// Usage

322

const db = await orbitdb.open('time-limited-db', {

323

AccessController: TimeBasedAccessController

324

});

325

326

// Grant write access for 1 hour

327

const oneHour = 60 * 60 * 1000;

328

db.access.grantTimeLimited(

329

'temp-user-id',

330

['read', 'write'],

331

Date.now(),

332

Date.now() + oneHour

333

);

334

```

335

336

### Access Controller Configuration

337

338

Configure access controllers when creating databases.

339

340

```javascript

341

import { createOrbitDB, IPFSAccessController } from '@orbitdb/core';

342

343

const ipfs = await createHelia();

344

const orbitdb = await createOrbitDB({ ipfs });

345

346

// Configure access controller with initial permissions

347

const adminDb = await orbitdb.open('admin-db', {

348

AccessController: IPFSAccessController({

349

write: ['admin-identity-1', 'admin-identity-2'],

350

admin: ['admin-identity-1']

351

})

352

});

353

354

// Public read-only database

355

const publicDb = await orbitdb.open('public-db', {

356

AccessController: IPFSAccessController({

357

write: [orbitdb.identity.id], // Only creator can write

358

read: ['*'] // Anyone can read

359

})

360

});

361

```

362

363

### Error Handling

364

365

Handle access control errors appropriately.

366

367

```javascript

368

import { createOrbitDB } from '@orbitdb/core';

369

370

const ipfs = await createHelia();

371

const orbitdb = await createOrbitDB({ ipfs });

372

373

try {

374

const db = await orbitdb.open('protected-db');

375

await db.add('Some data');

376

} catch (error) {

377

if (error.message.includes('Access denied')) {

378

console.error('Permission denied: Cannot write to this database');

379

console.log('Current identity:', orbitdb.identity.id);

380

} else if (error.message.includes('AccessController')) {

381

console.error('Access controller error:', error.message);

382

} else {

383

console.error('Unexpected error:', error.message);

384

}

385

}

386

387

// Check permissions before attempting operations

388

const db = await orbitdb.open('some-db');

389

const testEntry = { /* mock entry */ };

390

const canWrite = await db.access.canAppend(testEntry, orbitdb.identities);

391

392

if (canWrite) {

393

await db.add('Data');

394

} else {

395

console.log('No write permission for current identity');

396

}

397

```

398

399

## Integration with Database Operations

400

401

Access controllers are automatically invoked during database operations:

402

403

```javascript

404

// When adding data, access controller checks permissions

405

const db = await orbitdb.open('my-db');

406

407

// This triggers access controller's canAppend method

408

await db.add('New data'); // May throw if access denied

409

410

// Same for other database operations

411

await db.put('key', 'value'); // For KeyValue databases

412

await db.del('key'); // For deletion operations

413

```

414

415

Access controllers provide fine-grained control over database permissions while maintaining the distributed and decentralized nature of OrbitDB.