We've just pushed a Sync Gateway
revision that changes the way your JavaScript sync() functions work. If you're doing any document validation in your sync function, you'll need to make some changes after updating to this revision.
The Summary:
The third parameter to sync(), usually called userCtx, used to be an object with a "user" property whose value was the name of the user making the change, and a "roles" property whose value was an array of that user's roles.
This userCtx object is now opaque — you can't get the actual username or roles out of it. Instead, you call methods on it to check whether the author of the revision is a specific user or has a specific role. If these tests fail, those methods will throw an exception that terminates the sync function and returns a 403 to the client, just as if you'd thrown the exception yourself.
Example:
Let's say documents should only be modified by the user listed in their "owner" property.
The old validation:
function(doc, oldDoc, userCtx) {
if (oldDoc) {
if (userCtx.user != oldDoc.owner) throw({"forbidden", "not the owner"});
}
}
The new validation:
function(doc, oldDoc, userCtx) {
if (oldDoc) {
userCtx.requireUser(oldDoc.owner);
}
}
There's more documentation of the new API
here.
Why The Change?
There are conditions in which your sync function will be called when there isn't any specific user involved. Some of these are:
- The database's sync function is modified; this requires it to be re-run on every existing document, since channel/access assignments might be different
- A PUT/POST request made on the gateway's admin port
- A replication between two databases on the gateway (or from a foreign database to the gateway's admin port)
In these cases there aren't any reasonable values to put in the userCtx parameter. But if we left userCtx null, or an empty object, sync functions that didn't take this into account might break when run in those cases. For example, the function might throw an exception when dereferencing a null userCtx, or mistakenly reject a document because the current user name is null.
We decided the safest way to guard against this is to prevent sync functions from making direct comparisons. Instead, they call methods that check for particular users or roles. In the no-specific-user cases, those methods will do nothing, so the sync function will keep working.
—Jens