Rooms

Discret data synchronization uses fined grained access rights to decide which data needs to be synchronized with peers. Every tuple can be put in a Room that defines a set of rights:

Each tuple can be in a single Room, but can be moved across Rooms.

When inserting or mutating a tuple belonging to a Room, the access rights will be used to verify that the peer has the necessary rights do perform the action.

When connecting with other peers, the Rooms will be used to known which data needs to be synchronized with those peers. Other peers will not receive data from Rooms they don't belong to.

When synchronising data, each tuple will be checked to ensure received data have the necessary rights in the Rooms

Schéma

The Room data model is the following:

sys{
    Room {
        admin: [sys.UserAuth],
        authorisations:[sys.Authorisation]
    }
    
    Authorisation {
        name: String,
        rights:[sys.EntityRight] ,
        users:[sys.UserAuth],
        user_admin: [sys.UserAuth],
    }
    
    UserAuth{
        verif_key: Base64,
        enabled: Boolean default true,
    }
    
    EntityRight {
        entity: String,
        mutate_self: Boolean,
        mutate_all: Boolean,
    }
}

The Room entity is the root and contains:

The Authorisation entity contains access rights for a Room. A Room can contains several authorizations:

The UserAuth entity defines users:

Every users defined in a Room have a read only access on all data. The EntityRight entity defines the mutation rights for an entity:

while not recommended, it is possible to global mutation rights on all entities by setting the * wildcard in the entity field. Wilcard right will only be used if an inserted entity is not defined in a EntityRight.

To guarantee data integrity, some Room modifications constraint are enforced:

Inseting data in a Room

Every tuple have a room_id system field that references a Room identifier.

For example, if $room_id is the identifier of an existing Room, the following query will insert a Person tuple in the Room

mutate {
    Person{
        room_id: $room_id
        name: "Alice"
    }
}

During the creation process, the tupple will be signed with your cryptographic signature key and your verifying key will be inserted in the verifying_key system field.

The tuple signature and an verifying key will then be used to ensure that you have the right to insert this data in the Room.

Example: access rights for a Blog

To create a blog, we will use this simplified data model.

blog {
    Article {
        title: String,
        content: String
    }

    Comment {
        article: blog.Article
        comment: String
    }
}

The blog author must have the following rights

A blog reader must have the following rights

The blog Room will be created using the following query:

1mutate {
2 sys.Room{
3 admin: [{
4 verif_key:$admin_user
5 }]
6 authorisations:[{
7 name:"authors"
8 rights:[
9 {
10 entity:"blog.Article"
11 mutate_self:true
12 mutate_all:true
13 },
14 {
15 entity:"blog.Comment"
16 mutate_self:true
17 mutate_all:true
18 }
19 ]
20 users:[{
21 verif_key:$author
22 }]
23 },{
24 name:"readers"
25 rights:[ {
26 entity:"blog.Comment"
27 mutate_self:true
28 mutate_all:false
29 }]
30 users:[{
31 verif_key:$reader_1
32 },{
33 verif_key:$reader_1
34 }]
35 }]
36 }
37}

Lines 7 to 23 create authorizations for the authors, and line 24 to 34 create authorizations for readers.

You can notice that:

Example: a shared calendar

This example is more complex than the previous one and show interactions between several Rooms.

We want to have two different access rights between an appointment dates and its details. For example:

As every Room users have access to every data, we need to define two Rooms:

We will use this simplified data model:

cal {
    Calendar {
        name: String,
        appointments: [cal.Appointment],
    }

    Appointment {
        start: Integer,
        end: Integer,
        detail: cal.AppointmentDetail
    }

    AppointmentDetail {
        title: String,
    }
}

The following users will be used:

The $room_calendar Room is created using the query:

mutate {
    sys.Room{
        admin: [{
            verif_key:$author
        }]
        authorisations:[{
            name:"authors"
            rights:[
                {
                    entity:"cal.Calendar"
                    mutate_self:true
                    mutate_all:true
                },
                {
                    entity:"cal.Appointment"
                    mutate_self:true
                    mutate_all:true
                }
            ]
            users:[{
                verif_key:$author
            }]
        },{
            name:"readers"
            users:[{
                verif_key:$team_user
            },{
                verif_key:$collaborator
            }]
        }]
    }
}

Users that are not the author don't have any mutation rights, so no rights are defined for the readers authorization.

The $room_cal_detail Room is created using the query:

mutate {
    sys.Room{
        admin: [{
            verif_key:$author
        }]
        authorisations:[{
            name:"authors"
            rights:[
                {
                    entity:"cal.AppointmentDetail"
                    mutate_self:true
                    mutate_all:true
                }
            ]
            users:[{
                verif_key:$author
            }]
        },{
            name:"readers"
            users:[{
                verif_key:$team_user
            }]
        }]
    }
}

You will notice that $team_user is the only one allowed in the readers authorization.

A new calendar will be created with the following query:

mutate {
    res: cal.Calendar{
        room_id: $room_calendar
        name: "my calendar"
    }
}

For a calendar with an id set to $calendar_id, a new appointment will be inserted with the following query:

mutate {
    cal.Calendar {
        id: $calendar_id
        appointments:[{
            room_id: $room_calendar_id
            start:  1720770000000
            end:    1720780000000
            detail:{
                room_id: $room_cal_detail_id
                title: "An important meeting"
            }
        }]
    }
}

The following query will retrieve the appointments:

query {
    res: cal.Calendar(
        id=$calendar_id
    ) {
        name
        appointments(
            nullable(detail)
            ){
            start
            end
            detail {
                title
            }
        }
    }
}

The $team_user user will get the following result:

{
    "res":[{
        "name":"my calendar",
        "appointments":[{
            "start":1720770000000,
            "end":1720780000000,
            "detail":{
                "title":"An important meeting"
            }
        }]
    }]
}

The $collaborator user who cannot access the details wil get the following result:

{
    "res":[{
        "name":"my calendar",
        "appointments":[{
            "start":1720770000000,
            "end":1720780000000,
            "detail":null
        }]
    }]
}