orbitdb/docs/ACCESS_CONTROLLERS.md
Hayden Young 5ab0bcdbf5
Docs (#66)
* docs: Access controllers.

* test: Re-open an existing db using its address.

* docs: Simple db interaction.

* docs: Basic Identities.

* docs: Storage.

* docs: Implementing a custom database.

* docs: Example OrbitDB AC.

* docs: Use identity id when customizing access.

* docs: canAppend.

* docs: Graphically describe log joining.

* docs: Update db types.

* docs: Sync-ing.

* docs: Reverse flow arrows.

* docs: Logical clock.

* docs: DB address and manifest.

* docs: Move ops description to db.

* docs: CRDT.

* docs: Peer discovery, connecting ipfs nodes, orbitdb replication.

* docs: Change file name case to match other documentation solutions (e.g. IPFS/libp2p).

* docs: Links to CRDT papers.

* docs: A getting started to get up and running quickly.

* docs: Move replication to own readme.

* docs: Links to various js-libp2p connection config.

* docs: Examples for connecting two node servers.

* docs: Server to browser connection.

* docs: Replication how-to.

* docs: Remove SYNC.

* docs: Simplify oplog discussion.

* docs: Connecting to IPFS in the browser.

* docs: Topics moved to separate docs.
2023-05-05 00:33:36 +08:00

4.9 KiB

Access Controllers

Access controllers define the write access a user has to a database. By default, write access is limited to the user who created the database. Access controllers provide a way in which write access can be expanded to users other than the database creator.

An access controller is passed when a database is opened for the first time. Once created, the database's write access will be limited to only those users who are listed. By default, only the user creating the database will have write access.

Different access controllers can be assigned to the database using the AccessController param and passing it to OrbitDB's open function.

const orbitdb = await OrbitDB()
const db = orbitdb.open('my-db', { AccessController: SomeAccessController() })

OrbitDB is bundled with two AccessControllers; IPFSAccessController, an immutable access controller which uses IPFS to store the access settings, and OrbitDBAccessController, a mutable access controller which uses OrbitDB's keyvalue database to store one or more permissions.

IPFS Access Controller

By default, the database db will use the IPFSAccessController and allow only the creator to write to the database.

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

To change write access, pass the IPFSAccessController with the write parameter and an array of one or more Identity ids:

const identities = await Identities()
const identity1 = identities.createIdentity('userA')
const identity2 = identities.createIdentity('userB')

const orbitdb = await OrbitDB()
const db = orbitdb.open('my-db', { AccessController: IPFSAccessController(write: [identity1.id, identity2.id]) })

To allow anyone to write to the database, specify the wildcard '*':

const orbitdb = await OrbitDB()
const db = orbitdb.open('my-db', { AccessController: IPFSAccessController(write: ['*']) })

OrbitDB Access Controller

The OrbitDB access controller provides configurable write access using grant and revoke.

const identities = await Identities()
const identity1 = identities.createIdentity('userA')
const identity2 = identities.createIdentity('userB')

const orbitdb = await OrbitDB()
const db = orbitdb.open('my-db', { AccessController: OrbitDBAccessController(write: [identity1.id]) })

db.access.grant('write', identity2.id)
db.access.revoke('write', identity2.id)

When granting or revoking access, a capability and the identity's id must be defined.

Grant and revoke are not limited to 'write' access only. A custom access capability can be specified, for example, db.access.grant('custom-access', identity1.id).

Custom Access Controller

Access can be customized by implementing a custom access controller. To implement a custom access controller, specify:

  • A curried function with the function signature async ({ orbitdb, identities, address }),
  • A type constant,
  • A canAppend function with the param entry.
const type = 'custom'

const CustomAccessController = () => async ({ orbitdb, identities, address }) => {
  address = '/custom/access-controller'

  const canAppend = (entry) => {

  }
}

CustomAccessController.type = type

Additional configuration can be passed to the access controller by adding one or more parameters to the CustomAccessController function. For example, passing a configurable object parameter with the variable write:

const CustomAccessController = ({ write }) => async ({ orbitdb, identities, address }) => {
}

The canAppend function

The main driver of the access controller is the canAppend function. This specifies whether an identity can or cannot add an item to the operations log (or any other mechanism requiring access authorization).

How the custom access controller evaluates access will be determined by its use case, but in most instances, the canAppend function will want to check whether the entry being created can be written to the database (and underlying operations log). Therefore, the entry's identity will need to be used to retrieve the identity's id:

write = [identity.id]

const canAppend = async (entry) => {
  const writerIdentity = await identities.getIdentity(entry.identity)
  if (!writerIdentity) {
    return false
  }

  const { id } = writerIdentity

  if (write.includes(id) || write.includes('*')) {
    return identities.verifyIdentity(writerIdentity)
  }
  return false
}

In the above example, the entry.identity will be the hash of the identity. Using this hash, the entire identity can be retrieved and the identity's id is used to verify write access. write.includes('*') is wildcard write and would allow any identity to write to the operations log.

Using a custom access controller with OrbitDB

Before passing the custom access controller to the open function, it must be added to OrbitDB's AccessControllers:

AccessControllers.add(CustomAccessController)
const orbitdb = await OrbitDB()
const db = await orbitdb.open('my-db', { AccessController: CustomAccessController(params) })