couchdb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Robert Samuel Newson <>
Subject Re: Capturing UserCtx automatically
Date Wed, 19 Feb 2014 10:24:32 GMT
validate_doc_update cannot modify the document for the reasons you state.

As I said when you asked on IRC, you can write a validate_doc_update function that refuses
any update to a document that doesn’t also add information to that document about the change
being made. That is, you can insist that users include an accurate audit trail when they update
documents, and couchdb will reject any write that doesn’t do so. A rough sketch;

validate_doc_update(oldDoc, newDoc, userCtx) {

  if (newDoc.audit_trail[0].user != {
    throw({forbidden: "You didn’t add your name to the audit trail!"});

You’d obviously need to verify that the other items in doc.audit_trail are identical to
the ones in oldDoc, etc, but it’s possible.

To make adhering to these constraints easier for users, you can write a document update handler
that automatically generates an audit entry and adds it to the start or end of the audit_trail


On 19 Feb 2014, at 06:54, Gowtham Tamizharasan <> wrote:

> Hi all,
> We want to capture the user details of the person who creates or modifies a
> document. Now, I understand that in couch context, even a replication job
> is a 'user' that is modifying the DB.
> I'd ideally like to just use Changes API. It is almost perfect - except -
> we don't see the 'user' in the changes API output.
> So, I'm thinking of modifying validate_doc_update erlang function such that
> it will extract username from UserCtx and set a "_user" field in the
> document. However, this will surely interfere with replication. Am I
> correct?
> While we can "work around" this problem by putting some convention in the
> users db (if "replication user" role then don't modify _user). Is this
> approach good enough and will this work?
> So the modification will have be here, correct?
> In couch_db.erl:469: (
> )
> validate_doc_update(Db, Doc, GetDiskDocFun) ->
>    DiskDoc = GetDiskDocFun(),
>    JsonCtx = couch_util:json_user_ctx(Db),
>    SecObj = get_security(Db),
>    try [case Fun(Doc, DiskDoc, JsonCtx, SecObj) of
>            % INSERT HACK HERE
>            ok -> ok;
>            Error -> throw(Error)
>        end || Fun <- Db#db.validate_doc_funs],
>        ok
>    catch
>        throw:Error ->
>            Error
>    end.
> Another question: Can we use an _ field (like "_user") and will it just
> work? Or do I have to modify elsewhere too?
> In other words, do I have to explicitly do a transfer_fields? How do I now
> ensure _user value gets stored? From what we see, _id is written back like
> this:
> transfer_fields([{<<"_id">>, Id} | Rest], Doc) ->
>    validate_docid(Id),
>    transfer_fields(Rest, Doc#doc{id=Id});
> That means, I must invent a way to store the user also? like :
> *transfer_fields([{<<"_user">>, User} | Rest], Doc) ->*
> *    %My falidation for _User field, *
> *    transfer_fields(Rest, Doc#doc{user=User});*
> what about retrieval? how ll my *"_user"* field get stored, and how can i
> retrieve it?
> Regards,
> Gowtham.
> -- 
> _____________________________________________________________
> The information contained in this communication is intended solely for the 
> use of the individual or entity to whom it is addressed and others 
> authorized to receive it. It may contain confidential or legally privileged 
> information. If you are not the intended recipient you are hereby notified 
> that any disclosure, copying, distribution or taking any action in reliance 
> on the contents of this information is strictly prohibited and may be 
> unlawful. If you have received this communication in error, please notify 
> us immediately by responding to this email and then delete it from your 
> system. The firm is neither liable for the proper and complete transmission 
> of the information contained in this communication nor for any delay in its 
> receipt.

View raw message