From 70f470abeb4c73654e088a9b0666f51121fba631 Mon Sep 17 00:00:00 2001 From: James Kassemi Date: Wed, 16 Oct 2013 16:56:49 -0600 Subject: [PATCH 1/2] Lock expression enables locking records Adds a lock expression to the grammar for event expressions and metric expressions - a string that can be appended automatically to an expression prior to parsing that limits the results the expression has access to. This doesn't let us open the Cube server to the public directly, but it does allow us to rewrite the expression in requests through an intermediate service to help prohibit access: expression= sum(nginx_requests.size):nginx_requests.eq(user, 'rocky') limits the sum to the nginx_requests with a 'user' attribute of 'rocky,' assuming, you store that parameter in nginx_requests, of course. So, we can allow the client to send an expression, tack on the lock expression with our web app after authenticating the user, and then forward the request to cube and send back the response to the client while limiting access to the underlying records. Utilizes the core filter parsing already in place. --- .gitignore | 3 + lib/cube/event-expression.js | 118 +++++++++++++++++++++++++++------ lib/cube/event-expression.peg | 9 ++- lib/cube/event.js | 6 ++ lib/cube/metric-expression.js | 118 +++++++++++++++++++++++++++------ lib/cube/metric-expression.peg | 9 ++- package.json | 2 +- test/event-expression-test.js | 12 +++- test/metric-expression-test.js | 14 +++- 9 files changed, 243 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 40c0619e..3698b2b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ node_modules .jshintrc Procfile +*.un~ +*.swo +*.swp diff --git a/lib/cube/event-expression.js b/lib/cube/event-expression.js index baaf39e7..4278f61e 100644 --- a/lib/cube/event-expression.js +++ b/lib/cube/event-expression.js @@ -120,35 +120,111 @@ module.exports = (function(){ } - var savedPos0 = pos; - var savedPos1 = pos; - var result3 = parse__(); - if (result3 !== null) { - var result4 = parse_event_expression(); - if (result4 !== null) { - var result5 = parse__(); - if (result5 !== null) { - var result1 = [result3, result4, result5]; + var savedPos2 = pos; + var savedPos3 = pos; + var result10 = parse__(); + if (result10 !== null) { + var result11 = parse_event_expression(); + if (result11 !== null) { + var result12 = parse__(); + if (result12 !== null) { + if (input.substr(pos, 1) === ":") { + var result13 = ":"; + pos += 1; + } else { + var result13 = null; + if (reportMatchFailures) { + matchFailed("\":\""); + } + } + if (result13 !== null) { + var result14 = parse__(); + if (result14 !== null) { + var result15 = parse_event_expression(); + if (result15 !== null) { + var result16 = parse__(); + if (result16 !== null) { + var result8 = [result10, result11, result12, result13, result14, result15, result16]; + } else { + var result8 = null; + pos = savedPos3; + } + } else { + var result8 = null; + pos = savedPos3; + } + } else { + var result8 = null; + pos = savedPos3; + } + } else { + var result8 = null; + pos = savedPos3; + } } else { - var result1 = null; - pos = savedPos1; + var result8 = null; + pos = savedPos3; } } else { - var result1 = null; - pos = savedPos1; + var result8 = null; + pos = savedPos3; } } else { - var result1 = null; - pos = savedPos1; + var result8 = null; + pos = savedPos3; } - var result2 = result1 !== null - ? (function(expression) { expression.source = input; return expression; })(result1[1]) + var result9 = result8 !== null + ? (function(expression, lock_expression) { + var uf = expression.filter; + expression.type = lock_expression.type; + expression.filter = function(filter) { uf(filter); lock_expression.filter(filter); }; + return expression; + })(result8[1], result8[5]) : null; - if (result2 !== null) { - var result0 = result2; + if (result9 !== null) { + var result7 = result9; } else { - var result0 = null; - pos = savedPos0; + var result7 = null; + pos = savedPos2; + } + if (result7 !== null) { + var result0 = result7; + } else { + var savedPos0 = pos; + var savedPos1 = pos; + var result4 = parse__(); + if (result4 !== null) { + var result5 = parse_event_expression(); + if (result5 !== null) { + var result6 = parse__(); + if (result6 !== null) { + var result2 = [result4, result5, result6]; + } else { + var result2 = null; + pos = savedPos1; + } + } else { + var result2 = null; + pos = savedPos1; + } + } else { + var result2 = null; + pos = savedPos1; + } + var result3 = result2 !== null + ? (function(expression) { expression.source = input; return expression; })(result2[1]) + : null; + if (result3 !== null) { + var result1 = result3; + } else { + var result1 = null; + pos = savedPos0; + } + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; } diff --git a/lib/cube/event-expression.peg b/lib/cube/event-expression.peg index 560744f2..b8167387 100644 --- a/lib/cube/event-expression.peg +++ b/lib/cube/event-expression.peg @@ -73,7 +73,14 @@ } start - = _ expression:event_expression _ { expression.source = input; return expression; } + = _ expression:event_expression _ ":" _ lock_expression:event_expression _ +{ + var uf = expression.filter; + expression.type = lock_expression.type; + expression.filter = function(filter) { uf(filter); lock_expression.filter(filter); }; + return expression; + } + / _ expression:event_expression _ { expression.source = input; return expression; } event_expression = value:event_value_expression filters:(_ "." _ event_filter_expression)* diff --git a/lib/cube/event.js b/lib/cube/event.js index a8d4c42a..eacb3cfd 100644 --- a/lib/cube/event.js +++ b/lib/cube/event.js @@ -168,6 +168,12 @@ exports.getter = function(db) { // Copy any expression filters into the query object. var filter = {t: {$gte: start, $lt: stop}}; + + if("filter" in request){ + var additionalFilter = JSON.decode(filter); + + } + expression.filter(filter); // Request any needed fields. diff --git a/lib/cube/metric-expression.js b/lib/cube/metric-expression.js index c0e15b8d..4553a1af 100644 --- a/lib/cube/metric-expression.js +++ b/lib/cube/metric-expression.js @@ -131,35 +131,111 @@ module.exports = (function(){ } - var savedPos0 = pos; - var savedPos1 = pos; - var result3 = parse__(); - if (result3 !== null) { - var result4 = parse_metric_additive_expression(); - if (result4 !== null) { - var result5 = parse__(); - if (result5 !== null) { - var result1 = [result3, result4, result5]; + var savedPos2 = pos; + var savedPos3 = pos; + var result10 = parse__(); + if (result10 !== null) { + var result11 = parse_metric_additive_expression(); + if (result11 !== null) { + var result12 = parse__(); + if (result12 !== null) { + if (input.substr(pos, 1) === ":") { + var result13 = ":"; + pos += 1; + } else { + var result13 = null; + if (reportMatchFailures) { + matchFailed("\":\""); + } + } + if (result13 !== null) { + var result14 = parse__(); + if (result14 !== null) { + var result15 = parse_event_expression(); + if (result15 !== null) { + var result16 = parse__(); + if (result16 !== null) { + var result8 = [result10, result11, result12, result13, result14, result15, result16]; + } else { + var result8 = null; + pos = savedPos3; + } + } else { + var result8 = null; + pos = savedPos3; + } + } else { + var result8 = null; + pos = savedPos3; + } + } else { + var result8 = null; + pos = savedPos3; + } } else { - var result1 = null; - pos = savedPos1; + var result8 = null; + pos = savedPos3; } } else { - var result1 = null; - pos = savedPos1; + var result8 = null; + pos = savedPos3; } } else { - var result1 = null; - pos = savedPos1; + var result8 = null; + pos = savedPos3; } - var result2 = result1 !== null - ? (function(expression) { return expression; })(result1[1]) + var result9 = result8 !== null + ? (function(expression, lock_expression) { + var uf = expression.filter; + expression.type = lock_expression.type; + expression.filter = function(filter){ uf(filter); lock_expression.filter(filter); }; + return expression; + })(result8[1], result8[5]) : null; - if (result2 !== null) { - var result0 = result2; + if (result9 !== null) { + var result7 = result9; } else { - var result0 = null; - pos = savedPos0; + var result7 = null; + pos = savedPos2; + } + if (result7 !== null) { + var result0 = result7; + } else { + var savedPos0 = pos; + var savedPos1 = pos; + var result4 = parse__(); + if (result4 !== null) { + var result5 = parse_metric_additive_expression(); + if (result5 !== null) { + var result6 = parse__(); + if (result6 !== null) { + var result2 = [result4, result5, result6]; + } else { + var result2 = null; + pos = savedPos1; + } + } else { + var result2 = null; + pos = savedPos1; + } + } else { + var result2 = null; + pos = savedPos1; + } + var result3 = result2 !== null + ? (function(expression) { return expression; })(result2[1]) + : null; + if (result3 !== null) { + var result1 = result3; + } else { + var result1 = null; + pos = savedPos0; + } + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; } diff --git a/lib/cube/metric-expression.peg b/lib/cube/metric-expression.peg index 80aa9bcf..789a9e6e 100644 --- a/lib/cube/metric-expression.peg +++ b/lib/cube/metric-expression.peg @@ -104,7 +104,14 @@ } start - = _ expression:metric_additive_expression _ { return expression; } + = _ expression:metric_additive_expression _ ":" _ lock_expression:event_expression _ +{ + var uf = expression.filter; + expression.type = lock_expression.type; + expression.filter = function(filter){ uf(filter); lock_expression.filter(filter); }; + return expression; + } + / _ expression:metric_additive_expression _ { return expression; } metric_additive_expression = head:metric_multiplicative_expression tail:(_ additive_operator _ metric_additive_expression)* { return compoundMetric(head, tail); } diff --git a/package.json b/package.json index 3991731e..dea5fd0c 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "dependencies": { "mongodb": "~1.3.18", "node-static": "0.6.5", - "pegjs": "0.7.0", + "pegjs": "0.6.2", "vows": "0.7.0", "websocket": "1.0.8", "websocket-server": "1.4.04" diff --git a/test/event-expression-test.js b/test/event-expression-test.js index 9f12a79b..d14bcd6d 100644 --- a/test/event-expression-test.js +++ b/test/event-expression-test.js @@ -236,8 +236,18 @@ suite.addBatch({ parser.parse("test.in(i, [\"foo\", 42])").filter(filter); assert.deepEqual(filter, {"d.i": {$in: ["foo", 42]}}); } + }, + "lock expression": { + "lock expression merges additional filters": function() { + var filter = {}; + parser.parse("test.gt(i, 42):test.le(i, 52)").filter(filter); + assert.deepEqual(filter, {"d.i": {$gt: 42, $lte: 52}}); + }, + "lock expression results in expected type": function() { + var e = parser.parse("test1.gt(i, 42):test.le(i, 52)"); + assert.equal(e.type, "test") + } } - }); suite.export(module); diff --git a/test/metric-expression-test.js b/test/metric-expression-test.js index 0fd39844..ea7ac708 100644 --- a/test/metric-expression-test.js +++ b/test/metric-expression-test.js @@ -5,7 +5,7 @@ var vows = require("vows"), var suite = vows.describe("metric-expression"); suite.addBatch({ - + "a simple unary expression, sum(test)": { topic: parser.parse("sum(test)"), "is unary (has no associated binary operator)": function(e) { @@ -295,9 +295,19 @@ suite.addBatch({ var filter = {}; parser.parse("sum(test.in(i, [\"foo\", 42]))").filter(filter); assert.deepEqual(filter, {"d.i": {$in: ["foo", 42]}}); + }, + }, + "lock expression": { + "lock expression merges additional filters": function() { + var filter = {}; + parser.parse("sum(test.gt(i, 42)):test.le(i, 52)").filter(filter); + assert.deepEqual(filter, {"d.i": {$gt: 42, $lte: 52}}); + }, + "lock expression results in expected type": function() { + var e = parser.parse("sum(test1.gt(i, 42)):test.le(i, 52)"); + assert.equal(e.type, "test") } } - }); suite.export(module); From 62a13ee73c5b3046a70dec320d34d44cc8a756a0 Mon Sep 17 00:00:00 2001 From: James Kassemi Date: Wed, 16 Oct 2013 17:20:10 -0600 Subject: [PATCH 2/2] Woah! How'd you get in there, additionalFilter? (removing a few lines from some play-around code I mistakenly pushed up) --- lib/cube/event.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/cube/event.js b/lib/cube/event.js index eacb3cfd..a8d4c42a 100644 --- a/lib/cube/event.js +++ b/lib/cube/event.js @@ -168,12 +168,6 @@ exports.getter = function(db) { // Copy any expression filters into the query object. var filter = {t: {$gte: start, $lt: stop}}; - - if("filter" in request){ - var additionalFilter = JSON.decode(filter); - - } - expression.filter(filter); // Request any needed fields.