diff options
Diffstat (limited to 'src/couchdb')
-rw-r--r-- | src/couchdb/couch_js_functions.hrl | 30 | ||||
-rw-r--r-- | src/couchdb/couch_rep.erl | 15 | ||||
-rw-r--r-- | src/couchdb/couch_replication_manager.erl | 6 |
3 files changed, 33 insertions, 18 deletions
diff --git a/src/couchdb/couch_js_functions.hrl b/src/couchdb/couch_js_functions.hrl index 1e3ed4e9..d07eead5 100644 --- a/src/couchdb/couch_js_functions.hrl +++ b/src/couchdb/couch_js_functions.hrl @@ -182,12 +182,6 @@ } if (newDoc.user_ctx) { - if (!isAdmin) { - reportError('Delegated replications (use of the ' + - '`user_ctx\\' property) can only be triggered by ' + - 'administrators.'); - } - var user_ctx = newDoc.user_ctx; if ((typeof user_ctx !== 'object') || (user_ctx === null)) { @@ -204,24 +198,40 @@ 'non-empty string or null.'); } + if (!isAdmin && (user_ctx.name !== userCtx.name)) { + reportError('The given `user_ctx.name\\' is not valid'); + } + if (user_ctx.roles && !isArray(user_ctx.roles)) { reportError('The `user_ctx.roles\\' property must be ' + 'an array of strings.'); } - if (user_ctx.roles) { + if (!isAdmin && user_ctx.roles) { for (var i = 0; i < user_ctx.roles.length; i++) { var role = user_ctx.roles[i]; if (typeof role !== 'string' || role.length === 0) { reportError('Roles must be non-empty strings.'); } - if (role[0] === '_') { - reportError('System roles (starting with an ' + - 'underscore) are not allowed.'); + if (userCtx.roles.indexOf(role) === -1) { + reportError('Invalid role (`' + role + + '\\') in the `user_ctx\\''); } } } + } else { + if (!isAdmin) { + reportError('The `user_ctx\\' property is missing (it is ' + + 'optional for admins only).'); + } + } + } else { + if (!isAdmin) { + if (!oldDoc.user_ctx || (oldDoc.user_ctx.name !== userCtx.name)) { + reportError('Replication documents can only be deleted by ' + + 'admins or by the users who created them.'); + } } } } diff --git a/src/couchdb/couch_rep.erl b/src/couchdb/couch_rep.erl index 49a82e5d..fd323f7f 100644 --- a/src/couchdb/couch_rep.erl +++ b/src/couchdb/couch_rep.erl @@ -899,13 +899,14 @@ update_rep_doc(RepDb, #doc{body = {RepDocBody}} = RepDoc, KVs) -> RepDocBody, KVs ), - % might not succeed - when the replication doc is deleted right - % before this update (not an error) - couch_db:update_doc( - RepDb, - RepDoc#doc{body = {NewRepDocBody}}, - [] - ). + case NewRepDocBody of + RepDocBody -> + ok; + _ -> + % might not succeed - when the replication doc is deleted right + % before this update (not an error) + couch_db:update_doc(RepDb, RepDoc#doc{body = {NewRepDocBody}}, []) + end. % RFC3339 timestamps. % Note: doesn't include the time seconds fraction (RFC3339 says it's optional). diff --git a/src/couchdb/couch_replication_manager.erl b/src/couchdb/couch_replication_manager.erl index 6101c9c5..6537c8b2 100644 --- a/src/couchdb/couch_replication_manager.erl +++ b/src/couchdb/couch_replication_manager.erl @@ -253,7 +253,7 @@ process_update(State, {Change}) -> rep_user_ctx({RepDoc}) -> case get_value(<<"user_ctx">>, RepDoc) of undefined -> - #user_ctx{roles = [<<"_admin">>]}; + #user_ctx{}; {UserCtx} -> #user_ctx{ name = get_value(<<"name">>, UserCtx, null), @@ -307,6 +307,10 @@ start_replication(Server, {RepProps} = RepDoc, RepId, UserCtx, MaxRetries) -> ok = gen_server:call(Server, {triggered, RepId}, infinity), couch_rep:get_result(Pid, RepId, RepDoc, UserCtx); Error -> + couch_rep:update_rep_doc( + RepDoc, + [{<<"_replication_state">>, <<"error">>}, + {<<"_replication_id">>, ?l2b(element(1, RepId))}]), keep_retrying( Server, RepId, RepDoc, UserCtx, Error, ?INITIAL_WAIT, MaxRetries) end. |