Channels

    +

    About Sync Gateway Channels and their part in data routing for secure cloud-to-edge enterprise data synchronization.
    Sync Gateway’s Channels are a key part of a flexible approach to data routing and access control.
    In this topic we look at how to implement access-control and document routing using Channels.

    Related concepts topics: Users | Roles | Channels | Revisions | Tombstones

    Introduction

    Sync Gateway uses Channels to make it easy to share a database’s documents across a large user base whilst retaining effective access control. They serve as a security conduit between the document and a user:

    • Every user is granted access to a list of channels.

    • Every document in the database is assigned a list of channels it is distributed to.

    This dual-purpose is reflected in the way you use channels:

    • By granting a user access to a channel, you are imposing access control

    • By assigning a document to a channel you are imposing document routing

    Use-cases

    You typically will use channels to:

    • Control who can access what

    • Partition your data set

    • Enable users to access just the documents they need

    • Minimize the amount of data synced to mobile devices

    Channels and Wildcards

    Sync Gateway provides two special channels and a channel wildcard character:

    • The Public Channel ('!') — is a channel for publicly available documents. It provides for the public dissemination of documents.

    • The All Documents Channel ('*') — is a single, internal channel, comprising all documents from all channels. All documents are implicitly assigned this channel.

    • The All Channels Wildcard ('*') — used when granting user access, this wildcard grants access to any document in any channel.

    See: Example 1 for a Sync function that shows how you might use these channels and wildcards.

    Public Channel

    The Public Channel is referred to by the symbol ('!'). It is ideal for use in making information available across the user community.

    You assign a document to the public (!) channel using the channel(channel) function.

    Documents assigned to this channel can be accessed by all users; even users assigned no specific channel access.

    New users are automatically granted access to the channel.

    For an example of how to use the public channel — see: Example 1

    All Documents Channel

    Assignment to the all documents (*) channel [1] is automatic and implicit. You cannot explicitly assign documents to the channel or remove documents from it.

    This channel should not be confused with the use of the All Channels Wildcard in access grants.

    All Channels Wildcard

    The All Channels wildcard is referred to by the symbol ('*').

    You make dynamic user access grants in the sync function using the access(username, channel) method — for more, see: Add Access.

    Granting a user access with the all channels wildcard gives them access to any channel, and any document in any channel, including those from private channels.

    Replications by users with all channels wildcard access will pull all documents. Because of this potential for syncing large volumes of data (sync pulls all documents in the bucket), users with all channels wildcard access should use a channel filter to explicitly name the channel(s) to be sync’d.

    Note: Users granted access using the all channels wildcard do not inherit requireAccess(<channel>) rights to any specific channel.

    Always use a filter in conjunction with the all channels wildcard, to avoid sync unnecessarily pulling large numbers of documents to mobile devices.

    For an example of how to use the all channels wildcard — see: Example 1

    Using Channels in the Sync function

    Here we show the use of the public channel and all channels wildcard in a Sync function. The function provides for:

    • Document Routing — it routes public documents to the public channel

    • Access Control  — it grants users with an admin role access to all documents in all channels.

    Example 1. Using channels and wildcards
    // "sync": `
    function sync(doc, oldDoc) {
    
      /* Validation -- add validation rules here */
      // e.g. Verify the requesting user is the oldDoc's user
      if ((oldDoc != null) && (oldDoc.username)) {
       	requireUser(oldDoc.username);
      }
    
      ourChannel = "channel." + getUserName());
    
      /* Routing -- add channel routing rules here */
      // e.g. add public docs to the public channel.
      if (doc.isPublic) {
        channel('!');
      } else {
        channel(ourChannel); (1)
      }
    
      /* Access Control -- add user access rules here */
      // If this is an admin user, grant access to 'all documents'
      if (doc.type == 'user') {
        requireRole('admin');
        access(doc.username, '*'); (2)
      }
    
       // If this is a ticket, require user have access to ourChannel
      if (doc.type == 'ticket') {
        requireAccess(ourChannel); (3)
        //  further processing as required
      }
    
      //  further processing as required
    
      /* Supporting Functions */
      function getUserName() {
        return (isDelete() ? oldDoc.username : doc.username);
      }
    }
    // `
    1 If the document is public, we assign it to the public channel, using the public channel wildcard; otherwise we assign it to the user’s channel.
    2 For documents of type user, if the user has an admin role, we grant them access to all documents using the all channels wildcard.
    3 For documents of type ticket, we require the user to have explicit access to 'ourChannel'. Users with access granted only using the all channels wildcard will not satisfy this criteria.

    Inspect a Document

    You can use the admin REST API to see the channels that documents are assigned to.

    Issue a _all_docs request as follows:

    http://localhost:4984/travel-sample/_all_docs?channels=true

    The output response will be similar to that shown in Example 2.

    Example 2. Output from Inspect Document
    {
      "rows": [
        {
          "id": "foo",
          "key": "foo",
          "value": {
            "channels": [ (1)
              "short",
              "word"
            ],
            "rev": "1-86effb929acbf953905dd0e3974f6051"
          }
        }
      ],
      "total_rows": 16,
      "update_seq": 26
    }
    1 The output shows that the document is distributed to two channels: short and word.

    Add to Channel

    You assign documents to channels in a Sync Function. You can provide this function in the configuration file (databases.$db.sync). The Sync Function is a JavaScript function that takes a document body as input and, based on the document content, decides what channels to assign the document to (see the Function Definition).

    Based on the contents of the document, the Sync Function can call channel(channel) to add the document to one or more channels — see Example 3 This makes it accessible to users who have access to those channels, and will cause the document to be pulled by users that are subscribed to those channels.

    Example 3. Routing Documents
    function (doc, oldDoc) {
      channel("foo"); (1)
    }
    1 The Sync Function routes incoming documents to a channel named foo.

    Channels are created as documents are assigned to them. The Sync Function cannot reference any external state and must return the same results every time it’s called on the same input.

    Valid channel names consist of text letters [A–Z, a–z], digits [0–9], and a few special characters [= + / . , _ @]. Channel names are case-sensitive. Channels with no documents assigned to them are empty.

    If you don’t supply a Sync Function in the configuration file, Sync Gateway uses the default Sync Function. This default function is really only useful for experimentation and development.

    You are advised to write a Sync Function that provides validation, routing and access-control appropriate to your business needs — see: Sync Function for more on sync functions.

    Remove from Channel

    If the document was previously routed to a channel, but the current call to the sync function (for an updated revision) doesn’t route it to that channel, the document is removed from the channel.

    This may cause users to lose access to that document. If that happens, the next time Couchbase Lite pulls changes from the gateway, it will purge the document from the database and trigger the document replication listener on Couchbase Lite with the AccessRemoved flag.

    Related Couchbase Lite content

    Limits and Constraints

    Channel Limits

    Table 1. Guidance on Channel Assignment Limits
    Element Limiting factor Guidance Limit (Channels)

    Channels per document

    The amount of memory consumed by the combined number of channels and access grants must fit within the maximum 1Mb xattr size limit — see: Table 2.

    50

    Channels per user

    The amount of memory consumed by channels must fit within the 20 MB available on Couchbase Server docs for storing metadata — see: Table 2
    Note that the memory is retained for as long as the replication remains active.

    1,000

    Sync Metadata Limits

    Every time a document is assigned to a new channel, the channel name is appended to that document’s sync metadata.

    Therefore, a document’s set of channels is limited by the allowed sync metadata size described in Table 2.

    Table 2. Size Limits for Sync Metadata
    Value of enable_shared_bucket_access Size (Mb per Document)

    false

    20

    true

    1

    Sync Gateway will assign a document to a new channel as long as the sync metadata remains under the allowed limit.

    What to do when your channel count exceeds the usable space for sync metadata?

    In order to lower the sync metadata size per document, you can do one of the following:

    • Lower the number of channels per document.

    • Shorten the channel names. A shorter channel name will occupy less space ("customer==0030169303" vs "cs==0030169303").

    • Lower the revs_limit value. Indeed, a copy of channel metadata is retained for each revision of a document.