Documentation Index
Fetch the complete documentation index at: https://mintlify.com/estebanrfp/gdb/llms.txt
Use this file to discover all available pages before exploring further.
SM (Security Manager) Provides Role-Based Access Control (RBAC), Access Control Lists (ACLs), identity management (WebAuthn, Mnemonic), and security features for GDB instances. This system enables fine-grained permission control over data operations in a distributed P2P environment.
📥 How to Use
The Security Manager (SM) is not imported separately but is activated and attached to your GDB instance during its creation.Enable the Security Manager
To utilize the SM RBAC and identity features, you must enable thesmoption with a configuration object when you initialize GDB. It is mandatory to provide asuperAdminsarray containing at least one superadmin Ethereum address. This is critical to ensure the permission system is functional from the outset, allowing roles to be assigned.Note on Automatic Initialization: When you provide thesmconfiguration object, thegdbfunction automatically handles all necessary internal setup. This includes registering the P2P security middleware, a core feature that relies on theReal-Time Communication moduleto sign and verify data between peers. For this reason,rtc: truemust be enabled alongside the sm configuration. The initialization process also attempts a silent WebAuthn session resume, ensuring the db instance you receive is fully prepared for use.
📖 Overview & Core Concepts
The Security Manager (SM) for GDB integrates several key security aspects:- Identity Management: Users are identified by Ethereum addresses. The system supports:
- WebAuthn: Secure, passwordless authentication using biometrics or hardware keys to protect/unseal a user’s Ethereum private key.
- Mnemonic Phrases: Traditional BIP39 phrases for account creation and recovery.
- Role-Based Access Control (RBAC):
- A configurable hierarchy of roles with default roles:
guest,user,manager,admin,superadmin - Default permissions:
guest:['read', 'sync']user:['write', 'link', 'sync']+ inherits guestmanager:['publish']+ inherits useradmin:['delete']+ inherits managersuperadmin:['assignRole', 'deleteAny']+ inherits admin
- Role assignments are stored within GDB itself, making them part of the synchronized state.
- Custom roles can be defined by passing them in the initial configuration
- A configurable hierarchy of roles with default roles:
- P2P Operation Security:
- Outgoing database operations are cryptographically signed by the active user.
- Incoming operations from peers are verified for signature validity and sender permissions before being applied.
- Local Data Encryption: Authenticated users can encrypt/decrypt data for their own use, tied to their identity.
SoftwareWalletManager (an internal component) handles identity material (private keys, mnemonics) and WebAuthn interactions. The SoftwareSecurityManager (configured on the GDB instance by the SM) enforces P2P security by signing/verifying operations and checking RBAC permissions.
🚀 Core Setup & Lifecycle
The security module is automatically initialized when you create a GDB instance with thesm option. No additional setup calls are required.
Example
Silent WebAuthn Resume (no prompt on refresh)
When the Security Manager initializes, it will attempt to silently resume a WebAuthn-backed session if all of the following are true:- A previous session was completed using WebAuthn on this browser/origin (tracked internally via a localStorage flag).
- WebAuthn registration details exist for this origin (
db.sm.hasExistingWebAuthnRegistration()returnstrue).
- Do not auto-call
db.sm.loginCurrentUserWithWebAuthn()on page load; reserve it for explicit user actions (e.g., clicking “Login with WebAuthn”). - Use
db.sm.hasExistingWebAuthnRegistration()only to decide whether to show the WebAuthn Login button. - Call
db.sm.clearSecurity()to log out and clear the “last session was WebAuthn” flag; subsequent loads will not resume silently until the user logs in again with WebAuthn.
sm: { superAdmins: [...] } configuration. The superAdmins field is mandatory; the SM module will not initialize without it.
db.sm.clearSecurity()
Logs out the current user. This deactivates local signing capability by removing the active signer from GDB’s SoftwareSecurityManager. It also clears any volatile identity information (like a just-generated mnemonic) and removes WebAuthn session flags from local storage. GDB’s SoftwareSecurityManager will revert to (or remain in) a verifier-only mode for incoming P2P operations.
- Returns:
{Promise<void>}
Example
db.sm.setSecurityStateChangeCallback(callback)
Sets a callback function to be notified of changes in the security state. This is useful for dynamic UI updates reflecting login status, active user, etc.
- Parameters:
callback{(securityState: Object) => void | null}– A function that will be called with asecurityStateobject, ornullto remove the existing callback.securityState{Object}:isActive{boolean}– True if a local user session is active with signing capabilities.activeAddress{string | null}– The Ethereum address of the currently active user (if any), ornull.abbrAddr{string}– An abbreviated version of the active address (e.g., “0x1234…abcd”), ready for display. Returns ‘N/A’ if no address is active.isWebAuthnProtected{boolean}– True if the current active session was initiated or is protected by WebAuthn.hasVolatileIdentity{boolean}– True if a new ETH identity has been generated (e.g., viastartNewUserRegistration) and is held in memory but not yet secured by WebAuthn.hasWebAuthnHardwareRegistration{boolean}– True if WebAuthn registration details are found in localStorage for this browser/domain, indicating a WebAuthn credential exists.
- Returns:
{void}
Example
🆔 Identity Management
These methods manage user identities, supporting both WebAuthn and mnemonic-based approaches.db.sm.startNewUserRegistration()
Generates a new, temporary Ethereum identity (address, private key, mnemonic). This identity is volatile (held in memory) and is intended for immediate use, typically followed by protection with WebAuthn or a direct mnemonic-based login. If a security session is already active, clearSecurity() will be called first.
- Returns:
{Promise<{address: string, mnemonic: string, privateKey: string} | null>}– An object containing the new identity details (address, mnemonic, privateKey), ornullif generation fails.
Example
🔒 Secure Data Storage
These functions provide a simple API, similar to GDB’s coreput and get, but with automatic, implicit data encryption tied to the active user’s identity. They use an internal ID prefixing scheme to ensure secure data does not clash with regular GDB nodes.
db.sm.put(originalValue, id?)
- Signature:
(originalValue: any, id?: string): Promise<string>
originalValue is encrypted using a key derived from the active user’s Ethereum identity.
- Parameters:
originalValue{any}– The data to store. It must be JSON-serializable.id{string}(optional) – The ID for this piece of data. If not provided, a new unique ID will be generated and returned.
- Returns:
{Promise<string>}– Theidthat can be used withdb.sm.get()to retrieve the data.
Example
db.sm.get(id, callback?)
- Signature:
(id: string, callback?: Function): Promise<{ result: object | null, unsubscribe?: Function }>
db.sm.put() by the current active user.
- Parameters:
id{string}– The ID of the data to retrieve.callback{Function}(optional) – A function to call with updates. It receives a processed node object.
- Returns:
{Promise<object>}– An object containing:result{object | null}: The processed node object ornullif not found. The node object structure is:id{string}: The node’s ID.value{any}:- If decryption was successful: The original, decrypted data.
- If decryption failed (e.g., not owner, no session): The raw encrypted ciphertext.
edges{Array}: Edges of the node.timestamp{object}: The GDB timestamp of the node.decrypted{boolean}:trueif the data was successfully decrypted,falseotherwise.
unsubscribe{Function}(optional): If acallbackwas provided, this function stops the real-time listener.
Example: Getting Secure Data
db.sm.protectCurrentIdentityWithWebAuthn(ethPrivateKeyForProtection?)
Initiates the WebAuthn registration process to protect an Ethereum private key. The private key is encrypted using a WebAuthn-derived secret and stored in localStorage.
If ethPrivateKeyForProtection (a hex string) is provided, it uses that key. Otherwise, it attempts to use the private key from a volatileIdentity (previously generated by startNewUserRegistration). Upon successful WebAuthn registration, a local signing session is activated with this identity.
- Parameters:
ethPrivateKeyForProtection{string}(optional) – The Ethereum private key (hex string) to protect. If omitted, uses the key from the current volatile identity, if one exists.
- Returns:
{Promise<string | null>}– The Ethereum address of the protected identity if successful, otherwisenull.
Example
db.sm.loginCurrentUserWithWebAuthn()
Initiates the WebAuthn authentication (assertion) process for a user previously registered with WebAuthn on this browser/domain. This requires user interaction with their WebAuthn authenticator (e.g., biometrics, security key). If successful, it decrypts the stored Ethereum private key and activates a local signing session.
- Returns:
{Promise<string | null>}– The Ethereum address of the logged-in user if successful, otherwisenull.
Example
db.sm.loginOrRecoverUserWithMnemonic(mnemonic)
Loads or recovers an Ethereum identity using a provided BIP39 mnemonic phrase. If successful, this identity becomes active for the current session with signing capabilities. The session established this way is not WebAuthn-protected by this call alone; protectCurrentIdentityWithWebAuthn would need to be called subsequently if WebAuthn protection is desired for this identity on this device.
- Parameters:
mnemonic{string}– The BIP39 mnemonic phrase.
- Returns:
{Promise<{address: string, mnemonic: string, privateKey: string} | null>}– An object with the identity details if successful, otherwisenull.
Example
👑 Role Management & Permissions
Custom Roles Configuration
Custom roles are defined by passing them in the initial GDB configuration, not through a separate method call.Example: Defining Custom Roles
db.sm.assignRole(targetUserEthAddress, role, expiresAt?)
Assigns a specified role to a target user’s Ethereum address. Important: This function itself does not perform an RBAC check on the caller; it’s assumed that the caller’s permission to assign roles (typically the 'assignRole' permission) has already been verified. Role assignments are stored as nodes within GDB.
- Signature:
(targetUserEthAddress: string, role: string, expiresAt?: string | Date | number): Promise<void> - Parameters:
targetUserEthAddress{string}– The Ethereum address of the user to whom the role will be assigned.role{string}– The name of the role to assign (e.g.,'user','manager'). Must be a role defined in the active role configuration.expiresAt{string | Date | number}(optional) – An ISO date string, JavaScript Date object, or a timestamp in milliseconds indicating when this role assignment should expire. Ifnullor omitted, the role assignment does not expire.
- Returns:
{Promise<void>}– The promise resolves on successful GDB operation.
Example: Assigning a Role with Expiration
db.sm.executeWithPermission(operationName)
Verifies if the currently authenticated user has the specified operationName permission based on their role. This function should be called before attempting a restricted action.
- Signature:
(operationName: string): Promise<string> - Parameters:
operationName{string}– The name of the permission/action to check (e.g.,'write','delete','assignRole').
- Returns:
{Promise<string>}– A promise that resolves with the Ethereum address of the user if permission is granted. It rejects with an error if permission is denied or if no user is authenticated.
Example: Protected Operation
🔐 Access Control Lists (ACLs)
The ACL submodule provides fine-grained, node-level permissions within GDB. To enable it, setacls: true in the SM configuration.
Example: Enabling ACLs
Key Features
- Node Ownership: The creator of a node is automatically the owner with full permissions.
- Granular Permissions: Grant/revoke specific permissions (‘read’, ‘write’, ‘delete’) per user per node.
- Automatic Enforcement: Middleware validates permissions before operations are applied.
- Integration with Roles: ACL permissions are checked in addition to RBAC roles.
db.sm.acls.set(value, id?)
Creates or updates a node with ACL enforcement. The current user becomes the owner with full permissions.
- Signature:
(value: any, id?: string): Promise<string> - Parameters:
value{any}– The data to store. Must be JSON-serializable.id{string}(optional) – The ID for the node. If not provided, a new unique ID will be generated.
- Returns:
{Promise<string>}– Theidof the created/updated node.
Example
db.sm.acls.grant(nodeId, userAddress, permission)
Grants a specific permission to a user for a node. Only the owner can grant permissions.
- Signature:
(nodeId: string, userAddress: string, permission: string): Promise<void> - Parameters:
nodeId{string}– The ID of the node.userAddress{string}– The Ethereum address of the user to grant permission to.permission{string}– The permission to grant (‘read’, ‘write’, ‘delete’).
- Returns:
{Promise<void>}
Example
db.sm.acls.revoke(nodeId, userAddress, permission)
Revokes a specific permission from a user for a node. Only the owner can revoke permissions.
- Signature:
(nodeId: string, userAddress: string, permission: string): Promise<void> - Parameters:
nodeId{string}– The ID of the node.userAddress{string}– The Ethereum address of the user to revoke permission from.permission{string}– The permission to revoke (‘read’, ‘write’, ‘delete’).
- Returns:
{Promise<void>}
Example
Permission Levels
- ‘read’: Allows viewing the node’s value and edges.
- ‘write’: Allows updating the node’s value and creating edges.
- ‘delete’: Allows removing the node.
ℹ️ UI State & Helper Functions
These are utility functions for querying the current security state, often used for updating user interfaces. All are accessed viadb.sm.
getActiveEthAddress()
- Returns:
{string | null}– The Ethereum address of the active user, ornull.
isSecurityActive()
- Returns:
{boolean}–trueif a user session is active with signing capabilities.
isCurrentSessionProtectedByWebAuthn()
- Returns:
{boolean}–trueif the current session is WebAuthn-based.
hasExistingWebAuthnRegistration()
- Returns:
{boolean}–trueif WebAuthn registration details exist in localStorage for this site.
getMnemonicForDisplayAfterRegistrationOrRecovery()
- Returns:
{string | null}– The mnemonic phrase if a new identity was just generated or recovered and is held in volatile memory. Returnsnullonce the session is purely WebAuthn-based or if no such mnemonic is available. - Caution: Displaying mnemonic phrases should be done with extreme care.
abbrAddr(address)
A utility function to get a shortened, display-friendly version of an Ethereum address.
- Signature:
(address: string): string - Parameters:
address{string}– The full Ethereum address to abbreviate.
- Returns:
{string}– The abbreviated address (e.g., “0x1234…abcd”). Returns an empty string or may error if the input is not a valid address string.
Example
📝 Notes on Decentralization
The current RBAC implementation stores role assignments within GDB itself. While GDB is a P2P database, the authority for assigning roles ultimately relies on the permissions defined (e.g., asuperadminhavingassignRole). All operations are executed client-side. Future research may explore verifying role assignments via smart contracts for a higher degree of decentralized trust. For now, the system functions as a robust proof-of-concept for P2P applications requiring sophisticated access control.
💡 Best Practices & UI/UX Patterns
Building a secure and intuitive user experience for identity management is crucial. These patterns will guide you in creating a robust and user-friendly login/registration flow.1. The Core Principle: A Unified & Clean Interface
For a minimalist design, use a single, non-resizable<textarea> for all mnemonic-related actions. This field serves multiple purposes:
- Input: To paste an existing mnemonic for login/recovery.
- Output: To display a newly generated mnemonic.
textarea { resize: none; }
2. The Initial State: Login & Onboarding
When the app loads and the user is logged out (state.isActive is false):
- Present the primary actions:
[Generate New Identity]-> Callsdb.sm.startNewUserRegistration().[Login with Mnemonic]-> Callsdb.sm.loginOrRecoverUserWithMnemonic().
- Conditionally show the Passkey button:
[Login with Passkey]-> This button should only be visible ifstate.hasWebAuthnHardwareRegistrationistrue. It’s the fastest login path for returning users.
3. The New User Registration Flow (The Critical Path)
Once a user clicks[Generate New Identity], the application enters a temporary “confirmation state”. The UI must guide the user with absolute clarity.
-
Step 1: Display the Mnemonic & Secure the Field.
- The new mnemonic phrase populates the
<textarea>. - Immediately set the
<textarea>to be read-only (textarea.readOnly = true;). This is a critical security and UX measure to prevent accidental edits before the user saves the phrase. - A prominent warning message appears: “SAVE THIS PHRASE SECURELY! This is your only way to recover your account.”
- The new mnemonic phrase populates the
-
Step 2: Update the UI to focus on the next actions.
- A
[Copy Phrase]button should appear. This is the primary mechanism for the user to securely copy their new identity. It should be placed near the mnemonic field. - The
[Generate New Identity]button should be hidden. This is a crucial step to prevent the user from generating multiple identities and losing track of the one they need to save. The focus must shift from creation to action.
- A
-
Step 3: Provide Clear, Non-Exclusive Paths Forward.
- After generation, the user must have two clear options:
- The Recommended Path: A highlighted button like
[Protect Account with Passkey]becomes visible. It callsdb.sm.protectCurrentIdentityWithWebAuthn(). - The Standard Path: The
[Login with Mnemonic]button MUST remain visible and active. This ensures the user can proceed immediately, even if they cannot or choose not to use a passkey.
- The Recommended Path: A highlighted button like
- After generation, the user must have two clear options:
4. The Logged-In State
-
Reactive UI: Once
state.isActivebecomestrue, hide the entire login view and show the main application view. Remember to reset the<textarea>to be editable (readOnly = false) so it’s ready for the next login attempt after a logout. -
Display User Identity Clearly: When showing the user’s address in the UI, avoid displaying the full 42-character string, which is hard to read and takes up too much space.
- Use the provided
state.abbrAddrproperty. The state callback conveniently provides a pre-formatted, abbreviated address (e.g.,0x1234...abcd) ready for display. - This improves readability and provides a better user experience.
- Use the provided
5. General Principles
- Rely on the State Callback:
db.sm.setSecurityStateChangeCallback(updateUI)is your single source of truth. All UI changes (showing/hiding buttons, switching views) should be driven by the properties of thestateobject (isActive,hasVolatileIdentity,hasWebAuthnHardwareRegistration). - Never Store the Mnemonic: Your application logic should never persist the mnemonic phrase. It is ephemeral and should only exist in the UI temporarily during the onboarding process.
- Distinguish Storage vs. Utility:
- Use
db.sm.put()anddb.sm.get()for seamless, encrypted storage within GDB nodes. - Use
db.sm.encryptDataForCurrentUser()anddb.sm.decryptDataForCurrentUser()for flexible, ad-hoc encryption tasks.
- Use
⚠️ API Stability
This Security Manager API is under active development. Breaking changes may occur in future versions. Always consult the project’s CHANGELOG for updates.