summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsuelockwood <deathbear@apache.org>2013-12-20 14:16:23 -0500
committersuelockwood <deathbear@apache.org>2013-12-23 12:20:29 -0500
commit8c333157b335d40225323d34d54c3f5e31e1c40d (patch)
tree796555bc96ab5241050d2635243f0a3fa8a8fc7c
parenta6d55bbfce42a2c1967ba6c26f82b4c3f85d8e7e (diff)
downloadcouchdb-8c333157b335d40225323d34d54c3f5e31e1c40d.tar.gz
URL ENCODE ALL THE THINGS.
Mixin added to test for bad characters that get through couch validation & encode when found. Do not encode already encoded entries. mixin added for scrubbing special characters out of names used as CSS selectors SafeIDs used wherever there is a URL in views redirects & models. Better parsing of _design doc names (use regex) Allow the use of couchdb special characters / _ , $ etc in names for DBs, Views, Search Indexes etc, without breaking everything.
-rw-r--r--src/fauxton/app/mixins.js9
-rw-r--r--src/fauxton/app/modules/databases/base.js5
-rw-r--r--src/fauxton/app/modules/databases/resources.js23
-rw-r--r--src/fauxton/app/modules/databases/views.js8
-rw-r--r--src/fauxton/app/modules/documents/resources.js24
-rw-r--r--src/fauxton/app/modules/documents/routes.js8
-rw-r--r--src/fauxton/app/modules/documents/views.js23
-rw-r--r--src/fauxton/app/templates/databases/item.html3
-rw-r--r--src/fauxton/app/templates/documents/index_menu_item.html2
9 files changed, 67 insertions, 38 deletions
diff --git a/src/fauxton/app/mixins.js b/src/fauxton/app/mixins.js
index b17e15c2d..15af3ee32 100644
--- a/src/fauxton/app/mixins.js
+++ b/src/fauxton/app/mixins.js
@@ -51,6 +51,15 @@ function($, _ ) {
};
};
+ mixins.removeSpecialCharacters = function(name){
+ return name.replace(/[^\w\s]/gi,"");
+ };
+
+ mixins.safeURLName = function(name){
+ var checkforBad = name.match(/[\$\-/_,+-]/g);
+ return (checkforBad !== null)?encodeURIComponent(name):name;
+ };
+
return mixins;
});
diff --git a/src/fauxton/app/modules/databases/base.js b/src/fauxton/app/modules/databases/base.js
index 2e768e961..6ff12c646 100644
--- a/src/fauxton/app/modules/databases/base.js
+++ b/src/fauxton/app/modules/databases/base.js
@@ -27,9 +27,10 @@ function(app, FauxtonAPI, Databases, Views) {
// Utility functions
Databases.databaseUrl = function(database) {
- var name = _.isObject(database) ? database.id : database;
+ var name = _.isObject(database) ? database.id : database,
+ dbname = app.mixins.safeURLName(name);
- return ["/database/", name, "/_all_docs?limit=" + Databases.DocLimit].join('');
+ return ["/database/", dbname, "/_all_docs?limit=" + Databases.DocLimit].join('');
};
return Databases;
diff --git a/src/fauxton/app/modules/databases/resources.js b/src/fauxton/app/modules/databases/resources.js
index a577847da..2e66176d9 100644
--- a/src/fauxton/app/modules/databases/resources.js
+++ b/src/fauxton/app/modules/databases/resources.js
@@ -51,18 +51,23 @@ function(app, FauxtonAPI, Documents) {
url: function(context) {
if (context === "index") {
- return "/database/" + this.id + "/_all_docs";
+ return "/database/" + this.safeID() + "/_all_docs";
} else if (context === "web-index") {
- return "#/database/"+ encodeURIComponent(this.get("name")) + "/_all_docs?limit=" + Databases.DocLimit;
+ return "#/database/"+ this.safeID() + "/_all_docs?limit=" + Databases.DocLimit;
} else if (context === "changes") {
- return "/database/" + this.id + "/_changes?descending=true&limit=100&include_docs=true";
+ return "/database/" + this.safeID() + "/_changes?descending=true&limit=100&include_docs=true";
} else if (context === "app") {
- return "/database/" + this.id;
+ return "/database/" + this.safeID();
} else {
- return app.host + "/" + this.id;
+ return app.host + "/" + this.safeID();
}
},
-
+ safeName: function(){
+ return app.mixins.safeURLName(this.get("name"));
+ },
+ safeID: function() {
+ return app.mixins.safeURLName(this.id);
+ },
buildChanges: function (params) {
this.changes = new Databases.Changes({
database: this,
@@ -86,7 +91,7 @@ function(app, FauxtonAPI, Documents) {
query = "?" + $.param(this.params);
}
- return app.host + '/' + this.database.id + '/_changes' + query;
+ return app.host + '/' + this.database.safeID() + '/_changes' + query;
},
parse: function (resp) {
@@ -97,7 +102,7 @@ function(app, FauxtonAPI, Documents) {
Databases.Status = Backbone.Model.extend({
url: function() {
- return app.host + "/" + this.database.id;
+ return app.host + "/" + this.database.safeID();
},
initialize: function(options) {
@@ -156,7 +161,7 @@ function(app, FauxtonAPI, Documents) {
// TODO: pagination!
return _.map(resp, function(database) {
return {
- id: encodeURIComponent(database),
+ id: app.mixins.safeURLName(database),
name: database
};
});
diff --git a/src/fauxton/app/modules/databases/views.js b/src/fauxton/app/modules/databases/views.js
index 02b0297b7..0b4e0b046 100644
--- a/src/fauxton/app/modules/databases/views.js
+++ b/src/fauxton/app/modules/databases/views.js
@@ -29,7 +29,7 @@ function(app, Components, FauxtonAPI, Databases) {
},
serialize: function() {
return {
- encoded: encodeURIComponent(this.model.get("name")),
+ encoded: app.mixins.safeURLName(this.model.get("name")),
database: this.model,
docLimit: Databases.DocLimit
};
@@ -82,7 +82,7 @@ function(app, Components, FauxtonAPI, Databases) {
// TODO: switch to using a model, or Databases.databaseUrl()
// Neither of which are in scope right now
// var db = new Database.Model({id: dbname});
- var url = ["/database/", encodeURIComponent(dbname), "/_all_docs?limit=" + Databases.DocLimit].join('');
+ var url = ["/database/", app.mixins.safeURLName(dbname), "/_all_docs?limit=" + Databases.DocLimit].join('');
FauxtonAPI.navigate(url);
}
},
@@ -159,7 +159,7 @@ function(app, Components, FauxtonAPI, Databases) {
return;
}
db = new this.collection.model({
- id: encodeURIComponent(name),
+ id: name,
name: name
});
notification = FauxtonAPI.addNotification({msg: "Creating database."});
@@ -169,7 +169,7 @@ function(app, Components, FauxtonAPI, Databases) {
type: "success",
clear: true
});
- var route = "#/database/" + name + "/_all_docs?limit=" + Databases.DocLimit;
+ var route = "#/database/" + app.mixins.safeURLName(name) + "/_all_docs?limit=" + Databases.DocLimit;
app.router.navigate(route, { trigger: true });
}
).error(function(xhr) {
diff --git a/src/fauxton/app/modules/documents/resources.js b/src/fauxton/app/modules/documents/resources.js
index 863360518..a171caed5 100644
--- a/src/fauxton/app/modules/documents/resources.js
+++ b/src/fauxton/app/modules/documents/resources.js
@@ -27,7 +27,7 @@ function(app, FauxtonAPI) {
if (context === "app") {
return this.getDatabase().url("app") + "/" + this.safeID();
} else {
- return app.host + "/" + this.getDatabase().id + "/" + this.id;
+ return app.host + "/" + this.getDatabase().safeID() + "/" + this.safeID();
}
},
@@ -139,7 +139,7 @@ function(app, FauxtonAPI) {
// treated separately. For instance, we could default into the
// json editor for docs, or into a ddoc specific page.
safeID: function() {
- return this.id.replace('/', '%2F');
+ return app.mixins.safeURLName(this.id);
},
destroy: function() {
@@ -177,7 +177,7 @@ function(app, FauxtonAPI) {
copy: function (copyId) {
return $.ajax({
type: 'COPY',
- url: '/' + this.database.id + '/' + this.id,
+ url: '/' + this.database.safeID() + '/' + this.safeID(),
headers: {Destination: copyId}
});
},
@@ -200,7 +200,7 @@ function(app, FauxtonAPI) {
if (context === "app") {
return this.database.url("app") + "/" + this.safeID() + '/_info';
} else {
- return app.host + "/" + this.database.id + "/" + this.id + '/_info';
+ return app.host + "/" + this.database.safeID() + "/" + this.safeID() + '/_info';
}
},
@@ -209,7 +209,8 @@ function(app, FauxtonAPI) {
// treated separately. For instance, we could default into the
// json editor for docs, or into a ddoc specific page.
safeID: function() {
- return this.id.replace('/', '%2F');
+ var ddoc = this.id.replace(/_design\//,"");
+ return "_design/"+app.mixins.safeURLName(ddoc);
}
});
@@ -226,12 +227,15 @@ function(app, FauxtonAPI) {
url: function(context) {
if (!this.isEditable()) return false;
- return this.collection.database.url(context) + "/" + this.id;
+ return this.collection.database.url(context) + "/" + this.safeID();
},
isEditable: function() {
return this.docType() != "reduction";
},
+ safeID: function() {
+ return app.mixins.safeURLName(this.id);
+ },
prettyJSON: function() {
//var data = this.get("doc") ? this.get("doc") : this;
@@ -275,9 +279,9 @@ function(app, FauxtonAPI) {
}
if (context === 'app') {
- return 'database/' + this.database.id + "/_all_docs" + query;
+ return 'database/' + this.database.safeID() + "/_all_docs" + query;
}
- return app.host + "/" + this.database.id + "/_all_docs" + query;
+ return app.host + "/" + this.database.safeID() + "/_all_docs" + query;
},
simple: function () {
@@ -402,8 +406,10 @@ function(app, FauxtonAPI) {
if (context === 'app') {
startOfUrl = 'database';
}
+ var design = app.mixins.safeURLName(this.design),
+ view = app.mixins.safeURLName(this.view);
- var url = [startOfUrl, this.database.id, "_design", this.design, this.idxType, this.view];
+ var url = [startOfUrl, this.database.safeID(), "_design", design, this.idxType, view];
return url.join("/") + query;
},
diff --git a/src/fauxton/app/modules/documents/routes.js b/src/fauxton/app/modules/documents/routes.js
index b8b74b669..4727cdc78 100644
--- a/src/fauxton/app/modules/documents/routes.js
+++ b/src/fauxton/app/modules/documents/routes.js
@@ -92,7 +92,7 @@ function(app, FauxtonAPI, Documents, Databases) {
doc.copy(newId).then(function () {
doc.set({_id: newId});
docView.forceRender();
- FauxtonAPI.navigate('/database/' + database.id + '/' + newId, {trigger: true});
+ FauxtonAPI.navigate('/database/' + database.safeID() + '/' + app.mixins.safeURLName(newId), {trigger: true});
FauxtonAPI.addNotification({
msg: "Document has been duplicated."
});
@@ -162,7 +162,7 @@ function(app, FauxtonAPI, Documents, Databases) {
var docOptions = app.getParams();
docOptions.include_docs = true;
- this.databaseName = encodeURIComponent(options[0]);
+ this.databaseName = app.mixins.safeURLName(options[0]);
this.data = {
database: new Databases.Model({id:this.databaseName})
@@ -259,7 +259,7 @@ function(app, FauxtonAPI, Documents, Databases) {
ddocInfo: ddocInfo
}));
- this.sidebar.setSelectedTab(ddoc + '_' + view);
+ this.sidebar.setSelectedTab(app.mixins.removeSpecialCharacters(ddoc) + '_' + app.mixins.removeSpecialCharacters(view));
this.crumbs = function () {
return [
@@ -373,7 +373,7 @@ function(app, FauxtonAPI, Documents, Databases) {
},
initialize: function (route, masterLayout, options) {
- this.databaseName = encodeURIComponent(options[0]);
+ this.databaseName = app.mixins.safeURLName(options[0]);
this.database = new Databases.Model({id: this.databaseName});
var docOptions = app.getParams();
diff --git a/src/fauxton/app/modules/documents/views.js b/src/fauxton/app/modules/documents/views.js
index 9f95686c0..94fe699be 100644
--- a/src/fauxton/app/modules/documents/views.js
+++ b/src/fauxton/app/modules/documents/views.js
@@ -420,6 +420,11 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum
index: this.index,
ddoc: this.ddoc,
database: this.database,
+ index_clean: app.mixins.removeSpecialCharacters(this.index),
+ ddoc_clean: app.mixins.removeSpecialCharacters(this.ddoc),
+ index_encoded: app.mixins.safeURLName(this.index),
+ ddoc_encoded: app.mixins.safeURLName(this.ddoc),
+ database_encoded: app.mixins.safeURLName(this.database),
selected: this.selected
};
},
@@ -798,7 +803,7 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum
establish: function() {
var promise = this.model.fetch(),
- databaseId = this.database.id,
+ databaseId = this.database.safeID(),
deferred = $.Deferred();
promise.then(function () {
@@ -831,7 +836,7 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum
this.model.save().then(function () {
editor.editSaved();
- FauxtonAPI.navigate('/database/' + that.database.id + '/' + that.model.id);
+ FauxtonAPI.navigate('/database/' + that.database.safeID() + '/' + that.model.id);
}).fail(function(xhr) {
var responseText = JSON.parse(xhr.responseText).reason;
notification = FauxtonAPI.addNotification({
@@ -1270,7 +1275,7 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum
}
promise.then(function () {
- FauxtonAPI.navigate('/database/' + that.database.id + '/_all_docs?limit=' + Databases.DocLimit);
+ FauxtonAPI.navigate('/database/' + that.database.safeID() + '/_all_docs?limit=' + Databases.DocLimit);
FauxtonAPI.triggerRouteEvent('reloadDesignDocs');
});
},
@@ -1308,16 +1313,18 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum
});
if (that.newView) {
- var fragment = '/database/' + that.database.id +'/' + ddocName + '/_view/' + viewName;
+ var fragment = '/database/' + that.database.safeID() +'/' + ddoc.safeID() + '/_view/' + app.mixins.safeURLName(viewName);
FauxtonAPI.navigate(fragment, {trigger: false});
that.newView = false;
- that.ddocID = ddoc.id;
+ that.ddocID = ddoc.safeID();
that.viewName = viewName;
that.ddocInfo = ddoc;
that.showIndex = true;
that.render();
- FauxtonAPI.triggerRouteEvent('reloadDesignDocs',{selectedTab: ddocName.replace('_design/','') + '_' + viewName});
+ FauxtonAPI.triggerRouteEvent('reloadDesignDocs', {
+ selectedTab: app.mixins.removeSpecialCharacters(ddocName.replace(/_design\//,'')) + '_' + app.mixins.removeSpecialCharacters(viewName)
+ });
}
if (that.reduceFunStr !== reduceVal) {
@@ -1614,7 +1621,7 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum
var docId = this.$('#jump-to-doc-id').val().trim();
if (this.database.allDocs.where({"_id":docId}).length > 0){
- FauxtonAPI.navigate('/database/' + this.database.id +'/' + docId, {trigger: true});
+ FauxtonAPI.navigate('/database/' + app.mixins.safeURLName(this.database.id) +'/' + app.mixins.safeURLName(docId), {trigger: true});
} else {
FauxtonAPI.addNotification({
msg: 'Document ID does not exist.',
@@ -1707,7 +1714,7 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum
this.collection.each(function(design) {
if (design.has('doc')){
- var ddoc = design.id.split('/')[1];
+ var ddoc = design.id.replace(/_design\//,"");
if (design.get('doc').views){
this.buildIndexList(design.get('doc').views, "views", ddoc);
}
diff --git a/src/fauxton/app/templates/databases/item.html b/src/fauxton/app/templates/databases/item.html
index 701e58e71..e2f80712f 100644
--- a/src/fauxton/app/templates/databases/item.html
+++ b/src/fauxton/app/templates/databases/item.html
@@ -19,5 +19,6 @@ the License.
<td><%= database.status.numDocs() %></td>
<td><%= database.status.updateSeq() %></td>
<td>
- <a class="db-actions btn fonticon-replicate set-replication-start" href="#/replication/<%= database.get("name") %>"></a>
+ <a class="db-actions btn fonticon-replicate set-replication-start" title="Replicate <%= database.get("name") %>" href="#/replication/new/<%=encoded%>"></a>
+ <a class="db-actions btn icon-lock set-permissions" title="Set permissions for <%= database.get("name") %>" href="#/database/<%=encoded%>/permissions"></a>
</td>
diff --git a/src/fauxton/app/templates/documents/index_menu_item.html b/src/fauxton/app/templates/documents/index_menu_item.html
index 1b141b292..7ca9012e6 100644
--- a/src/fauxton/app/templates/documents/index_menu_item.html
+++ b/src/fauxton/app/templates/documents/index_menu_item.html
@@ -12,6 +12,6 @@ License for the specific language governing permissions and limitations under
the License.
-->
-<a id="<%= ddoc %>_<%= index %>" href="#database/<%= database %>/_design/<%= ddoc %>/_view/<%= index %>" class="toggle-view">
+<a id="<%= ddoc_clean %>_<%= index_clean %>" href="#database/<%= database_encoded %>/_design/<%= ddoc_encoded %>/_view/<%= index_encoded %>" class="toggle-view">
<%= ddoc %><span class="divider">/</span><%= index %>
</a>