summaryrefslogtreecommitdiff
path: root/share
diff options
context:
space:
mode:
authorDamien F. Katz <damien@apache.org>2008-11-11 19:45:50 +0000
committerDamien F. Katz <damien@apache.org>2008-11-11 19:45:50 +0000
commit9044fc0234ed65056f087a86c7c117922f2a2c75 (patch)
treeea87133de1e3617c5d3d7366983b7f7039d6cffd /share
parent538f455f2e2842d5caa33ed300d28b3cd52599b3 (diff)
Check in of initial validation and authorization work. This work is incomplete, as there is not yet any way of restricting who can update the design docs.
git-svn-id: https://svn.apache.org/repos/asf/incubator/couchdb/trunk@713132 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'share')
-rw-r--r--share/server/main.js14
-rw-r--r--share/www/script/couch.js99
-rw-r--r--share/www/script/couch_tests.js59
3 files changed, 127 insertions, 45 deletions
diff --git a/share/server/main.js b/share/server/main.js
index df184c1c..bdb03c60 100644
--- a/share/server/main.js
+++ b/share/server/main.js
@@ -153,7 +153,19 @@ while (cmd = eval(readline())) {
print("[true," + toJSON(reductions) + "]");
}
break;
-
+ case "validate":
+ var funSrc = cmd[1];
+ var newDoc = cmd[2];
+ var oldDoc = cmd[3];
+ var userCtx = cmd[4];
+ var validateFun = compileFunction(funSrc);
+ try {
+ validateFun(newDoc, oldDoc, userCtx);
+ print("1");
+ } catch (error) {
+ print(toJSON(error));
+ }
+ break;
default:
print(toJSON({error: "query_server_error",
reason: "unknown command '" + cmd[0] + "'"}));
diff --git a/share/www/script/couch.js b/share/www/script/couch.js
index 87bba88a..cc50ad2e 100644
--- a/share/www/script/couch.js
+++ b/share/www/script/couch.js
@@ -13,18 +13,18 @@
// A simple class to represent a database. Uses XMLHttpRequest to interface with
// the CouchDB server.
-function CouchDB(name) {
- this.name = name
+function CouchDB(name, options) {
+ this.name = name;
this.uri = "/" + encodeURIComponent(name) + "/";
- request = CouchDB.request;
+ request = function(method, uri, requestOptions) {
+ return CouchDB.request(method, uri, combine(requestOptions, options));
+ }
// Creates the database on the server
this.createDb = function() {
var req = request("PUT", this.uri);
- var result = JSON.parse(req.responseText);
- if (req.status != 201)
- throw result;
- return result;
+ maybeThrowError(req);
+ return JSON.parse(req.responseText);
}
// Deletes the database on the server
@@ -32,10 +32,8 @@ function CouchDB(name) {
var req = request("DELETE", this.uri);
if (req.status == 404)
return false;
- var result = JSON.parse(req.responseText);
- if (req.status != 200)
- throw result;
- return result;
+ maybeThrowError(req);
+ return JSON.parse(req.responseText);
}
// Save a document to the database
@@ -47,9 +45,8 @@ function CouchDB(name) {
req = request("PUT", this.uri + encodeURIComponent(doc._id) + encodeOptions(options), {
body: JSON.stringify(doc)
});
+ maybeThrowError(req);
var result = JSON.parse(req.responseText);
- if (req.status != 201)
- throw result;
doc._rev = result.rev;
return result;
}
@@ -59,18 +56,15 @@ function CouchDB(name) {
var req = request("GET", this.uri + encodeURIComponent(docId) + encodeOptions(options));
if (req.status == 404)
return null;
- var result = JSON.parse(req.responseText);
- if (req.status != 200)
- throw result;
- return result;
+ maybeThrowError(req);
+ return JSON.parse(req.responseText);
}
// Deletes a document from the database
this.deleteDoc = function(doc) {
var req = request("DELETE", this.uri + encodeURIComponent(doc._id) + "?rev=" + doc._rev);
+ maybeThrowError(req);
var result = JSON.parse(req.responseText);
- if (req.status != 200)
- throw result;
doc._rev = result.rev; //record rev in input document
doc._deleted = true;
return result;
@@ -79,9 +73,8 @@ function CouchDB(name) {
// Deletes an attachment from a document
this.deleteDocAttachment = function(doc, attachment_name) {
var req = request("DELETE", this.uri + encodeURIComponent(doc._id) + "/" + attachment_name + "?rev=" + doc._rev);
+ maybeThrowError(req);
var result = JSON.parse(req.responseText);
- if (req.status != 200)
- throw result;
doc._rev = result.rev; //record rev in input document
return result;
}
@@ -102,9 +95,8 @@ function CouchDB(name) {
var req = request("POST", this.uri + "_bulk_docs" + encodeOptions(options), {
body: JSON.stringify({"docs": docs})
});
+ maybeThrowError(req);
var result = JSON.parse(req.responseText);
- if (req.status != 201)
- throw result;
for (var i = 0; i < docs.length; i++) {
docs[i]._rev = result.new_revs[i].rev;
}
@@ -129,10 +121,8 @@ function CouchDB(name) {
headers: {"Content-Type": "application/json"},
body: JSON.stringify(body)
});
- var result = JSON.parse(req.responseText);
- if (req.status != 200)
- throw result;
- return result;
+ maybeThrowError(req);
+ return JSON.parse(req.responseText);
}
this.view = function(viewname, options, keys) {
@@ -147,19 +137,15 @@ function CouchDB(name) {
}
if (req.status == 404)
return null;
- var result = JSON.parse(req.responseText);
- if (req.status != 200)
- throw result;
- return result;
+ maybeThrowError(req);
+ return JSON.parse(req.responseText);
}
// gets information about the database
this.info = function() {
var req = request("GET", this.uri);
- var result = JSON.parse(req.responseText);
- if (req.status != 200)
- throw result;
- return result;
+ maybeThrowError(req);
+ return JSON.parse(req.responseText);
}
this.allDocs = function(options,keys) {
@@ -172,18 +158,14 @@ function CouchDB(name) {
body: JSON.stringify({keys:keys})
});
}
- var result = JSON.parse(req.responseText);
- if (req.status != 200)
- throw result;
- return result;
+ maybeThrowError(req);
+ return JSON.parse(req.responseText);
}
this.compact = function() {
var req = request("POST", this.uri + "_compact");
- var result = JSON.parse(req.responseText);
- if (req.status != 202)
- throw result;
- return result;
+ maybeThrowError(req);
+ return JSON.parse(req.responseText);
}
// Convert a options object to an url query string.
@@ -209,6 +191,35 @@ function CouchDB(name) {
function toJSON(obj) {
return obj !== null ? JSON.stringify(obj) : null;
}
+
+ function combine(object1, object2) {
+ if (!object2) {
+ return object1;
+ }
+ if (!object1) {
+ return object2;
+ }
+ for (var name in object2) {
+ object1[name] = object2[name];
+ }
+ return object1;
+ }
+
+ function maybeThrowError(req) {
+ if (req.status >= 400) {
+ if (req.responseText) {
+ try {
+ var result = JSON.parse(req.responseText);
+ } catch (ParseError) {
+ var result = {error:"unknown", reason:req.responseText};
+ }
+ } else {
+ var result = {};
+ }
+ result.http_status = req.status;
+ throw result;
+ }
+ }
}
CouchDB.allDbs = function() {
@@ -247,7 +258,7 @@ CouchDB.request = function(method, uri, options) {
} else {
throw new Error("No XMLHTTPRequest support detected");
}
- req.open(method, uri, false);
+ req.open(method, uri, false, options.username, options.password);
if (options.headers) {
var headers = options.headers;
for (var headerName in headers) {
diff --git a/share/www/script/couch_tests.js b/share/www/script/couch_tests.js
index 2553df9b..bc1e83da 100644
--- a/share/www/script/couch_tests.js
+++ b/share/www/script/couch_tests.js
@@ -1918,6 +1918,65 @@ var tests = {
// you can get a single key
xhr = CouchDB.request("GET", "/_config/test/foo");
T(xhr.responseText == '"bar"');
+ },
+
+ security : function(debug) {
+ var db = new CouchDB("test_suite_db");
+ db.deleteDb();
+ db.createDb();
+ if (debug) debugger;
+
+ var designDoc = {
+ _id:"_design/test",
+ language: "javascript",
+ validate_doc_update: "(" + (function (newDoc, oldDoc, userCtx) {
+ // docs should have an author field.
+ if (!newDoc.author) {
+ throw {error:"forbidden",
+ reason:"Documents must have an author field",
+ http_status:403};
+ }
+ if (oldDoc && oldDoc.author != userCtx.name) {
+ throw {error:"unauthorized",
+ reason:"You are not the author of this document. You jerk.",
+ headers:
+ {"WWW-Authenticate": "Basic realm=\"" + userCtx.db + "\""},
+ http_status:401};
+ }
+ }).toString() + ")"
+ }
+
+ db.save(designDoc);
+
+ var userDb = new CouchDB("test_suite_db", {username:"test user", password:"foo"});
+
+ try {
+ userDb.save({foo:1});
+ T(false && "Can't get here. Should have thrown an error");
+ } catch (e) {
+ T(e.error == "forbidden");
+ T(e.http_status == 403);
+ }
+
+ userDb.save({_id:"testdoc", foo:1, author:"test user"});
+
+ var doc = userDb.open("testdoc");
+ doc.foo=2;
+ userDb.save(doc);
+
+ var user2Db = new CouchDB("test_suite_db", {username:"test user2"});
+
+ var doc = user2Db.open("testdoc");
+ doc.foo=3;
+ try {
+ user2Db.save(doc);
+ T(false && "Can't get here. Should have thrown an error 2");
+ } catch (e) {
+ T(e.error == "unauthorized");
+ T(e.http_status == 401);
+ }
+
+
}
};