summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/couchdb/couch_js_functions.hrl30
-rw-r--r--src/couchdb/couch_rep.erl15
-rw-r--r--src/couchdb/couch_replication_manager.erl6
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.