Comparing version 2.2.2 to 2.3.0
@@ -111,3 +111,4 @@ 'use strict'; | ||
DELETE_TABLE: 'DeleteTable', | ||
DELETE_ENTITY: 'DeleteEntity' | ||
DELETE_ENTITY: 'DeleteEntity', | ||
QUERY_TABLE: 'QueryTable' | ||
} | ||
@@ -114,0 +115,0 @@ } |
@@ -67,2 +67,32 @@ 'use strict'; | ||
queryTable(request) { | ||
const coll = this.db.getCollection(Tables.Tables); | ||
const payload = []; | ||
if (request.tableName !== undefined) { | ||
const result = coll.chain() | ||
.find({ name: request.tableName }) | ||
.data(); | ||
// there must be a table since we are validating its existence in validation pipeline | ||
payload.push(new TableProxy(result[0])); | ||
return BbPromise.resolve(new AzuriteTableResponse({ payload: payload })); | ||
} | ||
let result; | ||
if (request.filter !== undefined) { | ||
result = coll.chain() | ||
.where((item) => { | ||
return eval(request.filter) | ||
}) | ||
.data(); | ||
} else { // Returning all tables | ||
result = coll.chain() | ||
.find({}) | ||
.data(); | ||
} | ||
for (const table of result) { | ||
payload.push(new TableProxy(table)); | ||
} | ||
return BbPromise.resolve(new AzuriteTableResponse({ payload: payload })); | ||
} | ||
_getTable(name) { | ||
@@ -69,0 +99,0 @@ const coll = this.db.getCollection(Tables.Tables); |
@@ -8,2 +8,3 @@ 'use strict'; | ||
deleteEntity = require('./../../actions/table/DeleteEntity'), | ||
queryTable = require('./../../actions/table/QueryTable'), | ||
createTable = require('./../../actions/table/CreateTable'); | ||
@@ -40,2 +41,6 @@ | ||
deleteEntity.process(request, res); | ||
} | ||
actions[Operations.QUERY_TABLE] = (request, res) => { | ||
queryTable.process(request, res); | ||
} |
@@ -67,2 +67,7 @@ 'use strict'; | ||
.run(EntityIfMatchVal); | ||
} | ||
validations[Operations.QUERY_TABLE] = (valContext) => { | ||
valContext | ||
.run(TableExistsVal) | ||
} |
@@ -6,2 +6,3 @@ 'use strict'; | ||
Constants = require('./../../core/Constants'), | ||
ODataMode = require('./../../core/Constants').ODataMode, | ||
N = require('./../../core/HttpHeaderNames'); | ||
@@ -19,6 +20,6 @@ | ||
this._initHttpProps(req.headers); | ||
this.accept = this._parseAccept(this.httpProps[N.ACCEPT]); | ||
this.accept = this._parseAccept(this.httpProps[N.ACCEPT]) || ODataMode.NONE; | ||
this.payload = RequestPayloadParser.parse(this.httpProps[N.CONTENT_TYPE], req.body); | ||
this.tableName = this.payload.TableName || req.params[0].replace(/[\('\)]/g, ''); | ||
this.tableName = this.payload.TableName || req.params[0].replace(/[\('\)]/g, '') || undefined; | ||
@@ -31,2 +32,7 @@ const res = this._parseEntityKeys(req.params[1] || ''), | ||
this.filter = req.query.$filter ? this._mapFilterQueryString(decodeURI(req.query.$filter)) : undefined; | ||
// Maximum of 1000 items at one time are allowed, | ||
// see https://docs.microsoft.com/rest/api/storageservices/query-timeout-and-pagination | ||
this.top = req.query.$top || 1000; | ||
if (Object.keys(this.payload).length === 0 && this.payload.constructor === Object) { | ||
@@ -38,3 +44,3 @@ this.payload === undefined; | ||
_initHttpProps(httpHeaders) { | ||
this.httpProps[N.CONTENT_TYPE] = httpHeaders[N.CONTENT_TYPE] || `application/json;`; | ||
this.httpProps[N.CONTENT_TYPE] = httpHeaders[N.CONTENT_TYPE] || `application/json`; | ||
this.httpProps[N.ACCEPT] = httpHeaders[N.ACCEPT] || `application/json;odata=nometadata`; | ||
@@ -69,4 +75,44 @@ this.httpProps[N.PREFER] = httpHeaders[N.PREFER] || `return-content`; | ||
} | ||
_mapFilterQueryString(filter) { | ||
filter = filter | ||
// ignoring these query keywords since we compare simply on string-level | ||
.replace(/\bdatetime\b/g, '') | ||
.replace(/\bguid\b/g, '') | ||
// A simple quotation mark is escaped with another one (i.e. ''). | ||
// Since we will evaluate this string we replace simple quotation marks indictaing strings with template quotation marks | ||
.replace(/''/g, '@') | ||
.replace(/'/g, '`') | ||
.replace(/@/g, `'`) | ||
// Mapping 'TableName' to 'name' which is used internally as attribute name | ||
.replace(/\bTableName\b/g, 'name') | ||
// Mapping operators | ||
.replace(/\beq\b/g, '===') | ||
.replace(/\bgt\b/g, '>') | ||
.replace(/\bge\b/g, '>=') | ||
.replace(/\blt\b/g, '<') | ||
.replace(/\ble\b/g, '<=') | ||
.replace(/\bne\b/g, '!==') | ||
.replace(/\band\b/g, '&&') | ||
.replace(/\bor\b/g, '||') | ||
.replace(/\bnot\b/g, '!'); | ||
// if a token is neither a number, nor a boolean, nor a string enclosed with quotation marks it is an operand | ||
// Operands are attributes of the object used within the where clause of LokiJS, thus we need to prepend each | ||
// attribute with an object identifier 'item'. | ||
let transformedQuery = ''; | ||
for (const token of filter.split(' ')) { | ||
if (!token.match(/\d+/) && | ||
token !== 'true' && token !== 'false' && | ||
!token.includes('`') && | ||
!['===', '>', '>=', '<', '<=', '!==', '&&', '||', '!'].includes(token)) { | ||
transformedQuery += `item.${token} `; | ||
} else { | ||
transformedQuery += `${token} `; | ||
} | ||
} | ||
return transformedQuery; | ||
} | ||
} | ||
module.exports = AzuriteTableRequest; |
@@ -7,3 +7,3 @@ 'use strict'; | ||
class AzuriteTableResponse { | ||
constructor({ proxy = undefined }) { | ||
constructor({ proxy = undefined, payload = undefined }) { | ||
this.proxy = proxy; | ||
@@ -14,2 +14,3 @@ this.httpProps = {}; | ||
this.httpProps[N.REQUEST_ID] = uuidV1(); | ||
this.payload = payload; | ||
} | ||
@@ -16,0 +17,0 @@ |
@@ -10,10 +10,10 @@ 'use strict' | ||
parse(contentType, body) { | ||
if (body.length === 0) { | ||
if (!body.length || body.length === 0) { | ||
return {}; | ||
} | ||
switch (contentType) { | ||
case 'application/atom+xml;': | ||
case 'application/atom+xml': | ||
throw new IAError(`accept value of 'atom+xml' is currently not supported by Azurite`); | ||
break; | ||
case 'application/json;': | ||
case 'application/json': | ||
const txt = body.toString('utf8'); | ||
@@ -20,0 +20,0 @@ return JSON.parse(txt); |
@@ -15,2 +15,4 @@ 'use strict'; | ||
.get((req, res, next) => { | ||
req.azuriteOperation = Operations.QUERY_TABLE; | ||
req.azuriteRequest = new AzuriteTableRequest({ req: req }); | ||
next(); | ||
@@ -17,0 +19,0 @@ }) |
@@ -10,4 +10,4 @@ 'use strict'; | ||
validate({ table = undefined }) { | ||
if (table === undefined) { | ||
validate({ request = undefined, table = undefined }) { | ||
if (request.tableName !== undefined && table === undefined) { | ||
throw new AError(ErrorCodes.TableNotFound); | ||
@@ -14,0 +14,0 @@ } |
{ | ||
"name": "azurite", | ||
"version": "2.2.2", | ||
"version": "2.3.0", | ||
"description": "A lightweight server clone of Azure Blob, Queue, and Table Storage that simulates most of the commands supported by it with minimal dependencies.", | ||
@@ -5,0 +5,0 @@ "scripts": { |
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
384577
179
7590
1