Database | ULID-Role (ULID is member's user dbid as a ulid) | |
---|---|---|
Purpose | Track a member's role and engagement databases. | |
Cardinality |
exactly one ULID-Role database per member
exactly one RoleItem per member
|
|
Source Code | ||
Items | src/ts/dbitems/ULID-Role.ts | |
Zod Models | ||
item | RoleItem |
|
item.item | RoleRecord |
|
Attributes | ||
itemId | roledbid - dbid of member's Role database | |
item: | RoleRecord |
|
kind | 'role' | |
mnum | number of member in the Members db (first is 1) | |
role | 'host', 'guest' or 'removed' | |
roledbids |
object mapping member number to dbid of ULID-Role database for member (guest only has own) |
|
publicdbids: | ||
members | dbid of Members database | |
user |
dbid of member's User database. The ULID-Role database name uses the ULID form of user as a prefix. |
|
partnerdbids |
object mapping member number to PartnerIds object for member(guest only has own) |
|
PartnerIds |
||
bundles | dbid of ULID-Bundles database for bundles and share credentials shared with guest |
Description
Each member in an engagement has a Role which identifies the member's role (host, guest or removed) and the dbids of databases containing engagement data.
The name of the database is ULID-Role where ULID is the member's User database dbid represented as a ulid. For
example 2EAJ7WP8YW9RFAKFAZAS2C2Z04-Role
is the name of the ULID-Role database for the user whose
User database dbid is 4e548fcb-23dc-4e1e-a9bd-5f5644c17c04
.
The ULID-Role database represents the 'root' of the tree of databases a member sees in an engagement.
one per one per member engagement AppID ╶╶╶╶╶╶╶╶▶ ULID-Role ╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶▶ Members + database database RoleID (1 item) (1 per member) ╵ shared with all members ╵ ╵ ╵ ╵ member's profile all profiles ╵ ╵ member's topics all topics ╵ └╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶▶ User ◀╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶┘ ╵ database ╵ Partner databases (only shared between host and guest) ╵ └╶╶╶╶╶╶╶╶╶▶ ULID-Bundles owned by host database
The member's ULID-Role database plays an important part in the authentication process. The 'AppIdUlid' and 'Role dbulid' from the engagement URL identify the Members database which determines the participants in the engagement.
Need
It may not be obvious why this table is necessary given that Userbase provides the getDatabases ↗︎ API. The issue is nothing in Userbase prohibits any user from sharing a database with any other user in the same AppID. The Userbase SDK allows users to create whatever databases they like so applications should not blindly process databases shared with a user.
Securepub uses the ULID-Role database to ensure unauthorized Userbase users in the same AppID cannot spoof members by sharing databases which appear as legitimate databases in an engagement. Such attempts won't work because Securepub only recognizes databases "reachable" from the member's ULID-Role database.
Ownership and Access
The host of the engagement is the owner of all ULID-Role databases.
The host's ULID-Role database is created when the engagement is created.
Other ULID-Role databases are created when the Host adds members to the engagement.
Zod models
The following Zod models show how the Userbase items are represented in memory.
Note that in addition to the values specified by the Userbase Item interface the kind and database attributes are added during deserialization.
export type RoleItem = z.infer<typeof RoleItem>;
export const RoleItem = z.object({
kind: z.literal('roleitem'),
itemId: z.string(),
item: RoleRecord,
updatedBy: z.custom<Attribution>(),
database: z.custom<Database>()
}).strip();
export type RoleRecord = z.infer<typeof RoleRecord>;
export const RoleRecord = z.object({
kind: z.literal('role'),
mnum: z.number(),
role: z.union([
z.literal("host"),
z.literal("guest"),
z.literal("removed")
]),
roledbids: z.record(z.string(), z.string().uuid()),
publicdbids: PublicIds,
partnerdbids: z.record(z.string(), PartnerIds)
}).strip();
export type PublicIds = z.infer<typeof PublicIds>;
export const PublicIds = z.object({
members: z.string().uuid(),
user: z.string().uuid(),
});
export type PartnerIds = z.infer<typeof PartnerIds>;
export const PartnerIds = z.object({
bundles: z.string().uuid(),
activity: z.string().uuid()
});