| % Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| % use this file except in compliance with the License. You may obtain a copy of |
| % the License at |
| % |
| % http://www.apache.org/licenses/LICENSE-2.0 |
| % |
| % Unless required by applicable law or agreed to in writing, software |
| % distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| % WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| % License for the specific language governing permissions and limitations under |
| % the License. |
| |
| -define(REP_DB_DOC_VALIDATE_FUN, <<" |
| function(newDoc, oldDoc, userCtx) { |
| function reportError(error_msg) { |
| log('Error writing document `' + newDoc._id + |
| '\\' to the replicator database: ' + error_msg); |
| throw({forbidden: error_msg}); |
| } |
| |
| function validateEndpoint(endpoint, fieldName) { |
| if ((typeof endpoint !== 'string') && |
| ((typeof endpoint !== 'object') || (endpoint === null))) { |
| |
| reportError('The `' + fieldName + '\\' property must exist' + |
| ' and be either a string or an object.'); |
| } |
| |
| if (typeof endpoint === 'object') { |
| if ((typeof endpoint.url !== 'string') || !endpoint.url) { |
| reportError('The url property must exist in the `' + |
| fieldName + '\\' field and must be a non-empty string.'); |
| } |
| |
| if ((typeof endpoint.auth !== 'undefined') && |
| ((typeof endpoint.auth !== 'object') || |
| endpoint.auth === null)) { |
| |
| reportError('`' + fieldName + |
| '.auth\\' must be a non-null object.'); |
| } |
| |
| if ((typeof endpoint.headers !== 'undefined') && |
| ((typeof endpoint.headers !== 'object') || |
| endpoint.headers === null)) { |
| |
| reportError('`' + fieldName + |
| '.headers\\' must be a non-null object.'); |
| } |
| } |
| } |
| |
| var isReplicator = (userCtx.roles.indexOf('_replicator') >= 0); |
| var isAdmin = (userCtx.roles.indexOf('_admin') >= 0); |
| |
| if (oldDoc && !newDoc._deleted && !isReplicator && |
| (oldDoc._replication_state === 'triggered')) { |
| reportError('Only the replicator can edit replication documents ' + |
| 'that are in the triggered state.'); |
| } |
| |
| if (!newDoc._deleted) { |
| validateEndpoint(newDoc.source, 'source'); |
| validateEndpoint(newDoc.target, 'target'); |
| |
| if ((typeof newDoc.create_target !== 'undefined') && |
| (typeof newDoc.create_target !== 'boolean')) { |
| |
| reportError('The `create_target\\' field must be a boolean.'); |
| } |
| |
| if ((typeof newDoc.continuous !== 'undefined') && |
| (typeof newDoc.continuous !== 'boolean')) { |
| |
| reportError('The `continuous\\' field must be a boolean.'); |
| } |
| |
| if ((typeof newDoc.doc_ids !== 'undefined') && |
| !isArray(newDoc.doc_ids)) { |
| |
| reportError('The `doc_ids\\' field must be an array of strings.'); |
| } |
| |
| if ((typeof newDoc.selector !== 'undefined') && |
| (typeof newDoc.selector !== 'object')) { |
| |
| reportError('The `selector\\' field must be an object.'); |
| } |
| |
| if ((typeof newDoc.filter !== 'undefined') && |
| ((typeof newDoc.filter !== 'string') || !newDoc.filter)) { |
| |
| reportError('The `filter\\' field must be a non-empty string.'); |
| } |
| |
| if ((typeof newDoc.doc_ids !== 'undefined') && |
| (typeof newDoc.selector !== 'undefined')) { |
| |
| reportError('`doc_ids\\' field is incompatible with `selector\\'.'); |
| } |
| |
| if ( ((typeof newDoc.doc_ids !== 'undefined') || |
| (typeof newDoc.selector !== 'undefined')) && |
| (typeof newDoc.filter !== 'undefined') ) { |
| |
| reportError('`filter\\' field is incompatible with `selector\\' and `doc_ids\\'.'); |
| } |
| |
| if ((typeof newDoc.query_params !== 'undefined') && |
| ((typeof newDoc.query_params !== 'object') || |
| newDoc.query_params === null)) { |
| |
| reportError('The `query_params\\' field must be an object.'); |
| } |
| |
| if (newDoc.user_ctx) { |
| var user_ctx = newDoc.user_ctx; |
| |
| if ((typeof user_ctx !== 'object') || (user_ctx === null)) { |
| reportError('The `user_ctx\\' property must be a ' + |
| 'non-null object.'); |
| } |
| |
| if (!(user_ctx.name === null || |
| (typeof user_ctx.name === 'undefined') || |
| ((typeof user_ctx.name === 'string') && |
| user_ctx.name.length > 0))) { |
| |
| reportError('The `user_ctx.name\\' property must be a ' + |
| '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 (!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 (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.'); |
| } |
| } |
| } |
| } |
| ">>). |