You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by de...@apache.org on 2013/12/23 17:03:08 UTC

[2/4] git commit: updated refs/heads/ENCODE-EVERYTHING to f3c9b4c

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.


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/b76563b0
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/b76563b0
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/b76563b0

Branch: refs/heads/ENCODE-EVERYTHING
Commit: b76563b0d79747007fd323663f54b6c26cabc88a
Parents: 02fa02e
Author: suelockwood <de...@apache.org>
Authored: Fri Dec 20 14:16:23 2013 -0500
Committer: suelockwood <de...@apache.org>
Committed: Mon Dec 23 11:02:43 2013 -0500

----------------------------------------------------------------------
 src/fauxton/app/mixins.js                       |  9 ++++++++
 src/fauxton/app/modules/databases/base.js       |  5 ++--
 src/fauxton/app/modules/databases/resources.js  | 23 +++++++++++--------
 src/fauxton/app/modules/databases/views.js      |  8 +++----
 src/fauxton/app/modules/documents/resources.js  | 24 ++++++++++++--------
 src/fauxton/app/modules/documents/routes.js     |  8 +++----
 src/fauxton/app/modules/documents/views.js      | 23 ++++++++++++-------
 src/fauxton/app/templates/databases/item.html   |  3 ++-
 .../templates/documents/index_menu_item.html    |  2 +-
 9 files changed, 67 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/b76563b0/src/fauxton/app/mixins.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/mixins.js b/src/fauxton/app/mixins.js
index b17e15c..15af3ee 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;
 });
 

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b76563b0/src/fauxton/app/modules/databases/base.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/modules/databases/base.js b/src/fauxton/app/modules/databases/base.js
index 2e768e9..6ff12c6 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;

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b76563b0/src/fauxton/app/modules/databases/resources.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/modules/databases/resources.js b/src/fauxton/app/modules/databases/resources.js
index a577847..2e66176 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
         };
       });

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b76563b0/src/fauxton/app/modules/databases/views.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/modules/databases/views.js b/src/fauxton/app/modules/databases/views.js
index 02b0297..0b4e0b0 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) {

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b76563b0/src/fauxton/app/modules/documents/resources.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/modules/documents/resources.js b/src/fauxton/app/modules/documents/resources.js
index 8633605..a171cae 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;
     },
 

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b76563b0/src/fauxton/app/modules/documents/routes.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/modules/documents/routes.js b/src/fauxton/app/modules/documents/routes.js
index b8b74b6..4727cdc 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();

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b76563b0/src/fauxton/app/modules/documents/views.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/modules/documents/views.js b/src/fauxton/app/modules/documents/views.js
index 9f95686..94fe699 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);
           }

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b76563b0/src/fauxton/app/templates/databases/item.html
----------------------------------------------------------------------
diff --git a/src/fauxton/app/templates/databases/item.html b/src/fauxton/app/templates/databases/item.html
index 701e58e..e2f8071 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>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b76563b0/src/fauxton/app/templates/documents/index_menu_item.html
----------------------------------------------------------------------
diff --git a/src/fauxton/app/templates/documents/index_menu_item.html b/src/fauxton/app/templates/documents/index_menu_item.html
index 1b141b2..7ca9012 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>