UNPKG

azure-storage

Version:

Microsoft Azure Storage Client Library for Node.js

262 lines (224 loc) 8.13 kB
// // Copyright (c) Microsoft and contributors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // // See the License for the specific language governing permissions and // limitations under the License. // var util = require('util'); var azureUtil = require('../util/util'); var errors = require('../errors/errors'); var SR = require('../util/sr'); var Constants = require('../util/constants'); exports = module.exports; /** * The default protocol. */ exports.DEFAULT_PROTOCOL = Constants.HTTPS; var NoMatchError = function (msg, constr) { errors.captureStackTrace(this, constr || this); this.message = msg || 'Error'; }; util.inherits(NoMatchError, Error); NoMatchError.prototype.name = 'NoMatchError'; exports.NoMatchError = NoMatchError; /** * Throws an exception if the connection string format does not match any of the * available formats. * * @param {string} connectionString The invalid formatted connection string. * @return none */ exports.noMatchConnectionString = function (connectionString) { throw new NoMatchError('The provided connection string "' + connectionString + '" does not have complete configuration settings.'); }; /** * Throws an exception if the settings dont match any of the * available formats. * * @param {object} settings The invalid settings. * @return none */ exports.noMatchSettings = function (settings) { throw new NoMatchError('The provided settings ' + JSON.stringify(settings) + ' are not complete.'); }; /** * Parses the connection string and then validate that the parsed keys belong to * the validSettingKeys * * @param {string} connectionString The user provided connection string. * @param {array} validKeys The valid keys. * @return {array} The tokenized connection string keys. */ exports.parseAndValidateKeys = function (connectionString, validKeys) { var parsedConnectionString = { }; // parse key/value pairs from connection string var pairs = connectionString.split(';'); for (var m = 0; m < pairs.length; m++) { if (pairs[m].length === 0) { continue; } var equalDex = pairs[m].indexOf('='); if (equalDex < 0) { throw new SyntaxError(SR.INVALID_CONNECTION_STRING); } else if (equalDex === 0) { // empty key name. throw new SyntaxError(SR.INVALID_CONNECTION_STRING_EMPTY_KEY); } var key = pairs[m].substring(0, equalDex); // assure that all given keys are valid. if (!azureUtil.inArrayInsensitive(key, validKeys)) { throw new SyntaxError(util.format(SR.INVALID_CONNECTION_STRING_BAD_KEY, key)); } var value = pairs[m].substring(equalDex + 1); if(typeof parsedConnectionString[key] === 'undefined'){ parsedConnectionString[key] = value; } else { // duplicate key name throw new SyntaxError(util.format(SR.INVALID_CONNECTION_STRING_DUPLICATE_KEY, key)); } } return parsedConnectionString; }; /** * Creates an anonymous function that acts as predicate to perform a validation. * * @param array {requirements} The array of conditions to satisfy. * @param boolean {isRequired} Either these conditions are all required or all * optional. * @param boolean {atLeastOne} Indicates that at least one requirement must * succeed. * @return {function} */ exports.getValidator = function (requirements, isRequired, atLeastOne) { return function (userSettings) { var oneFound = false; var result = { }; for (var key in userSettings) { if (userSettings.hasOwnProperty(key)) { result[key.toLowerCase()] = userSettings[key]; } } for (var requirement in requirements) { if (requirements.hasOwnProperty(requirement)) { var settingName = requirements[requirement].SettingName.toLowerCase(); // Check if the setting name exists in the provided user settings. if (result[settingName]) { // Check if the provided user setting value is valid. var validationFunc = requirements[requirement].SettingConstraint; var isValid = validationFunc(result[settingName]); if (isValid) { // Remove the setting as indicator for successful validation. delete result[settingName]; oneFound = true; } } else if (isRequired) { // If required then fail because the setting does not exist return null; } } } if (atLeastOne) { // At least one requirement must succeed, otherwise fail. return oneFound ? result : null; } else { return result; } }; }; /** * Creates a setting value condition that validates it is one of the * passed valid values. * * @param {string} name The setting key name. * @return {array} */ exports.setting = function (name) { var validValues = Array.prototype.slice.call(arguments, 1, arguments.length); var predicate = function (settingValue) { var validValuesString = JSON.stringify(validValues); if (validValues.length === 0) { // No restrictions, succeed. return true; } // Check to find if the settingValue is valid or not. for (var index = 0; index < validValues.length; index++) { if (settingValue.toString() == validValues[index].toString()) { // SettingValue is found in valid values set, succeed. return true; } } // settingValue is missing in valid values set, fail. throw new RangeError('The provided config value ' + settingValue + ' does not belong to the valid values subset:\n' + validValuesString); }; return exports.settingWithFunc(name, predicate); }; /** * Creates an "at lease one" predicate for the provided list of requirements. * * @return callable */ exports.atLeastOne = function () { var allSettings = arguments; return exports.getValidator(allSettings, false, true); }; /** * Creates an optional predicate for the provided list of requirements. * * @return {function} */ exports.optional = function () { var optionalSettings = arguments; return exports.getValidator(optionalSettings, false, false); }; /** * Creates an required predicate for the provided list of requirements. * * @return {function} */ exports.allRequired = function () { var requiredSettings = arguments; return exports.getValidator(requiredSettings, true, false); }; /** * Creates a setting value condition using the passed predicate. * * @param {string} name The setting key name. * @param {function} predicate The setting value predicate. * @return {array} */ exports.settingWithFunc = function (name, predicate) { var requirement = {}; requirement.SettingName = name; requirement.SettingConstraint = predicate; return requirement; }; /** * Tests to see if a given list of settings matches a set of filters exactly. * * @param array $settings The settings to check. * @return boolean If any filter returns null, false. If there are any settings * left over after all filters are processed, false. Otherwise true. */ exports.matchedSpecification = function (settings) { var constraints = Array.prototype.slice.call(arguments, 1, arguments.length); for (var constraint in constraints) { if (constraints.hasOwnProperty(constraint)) { var remainingSettings = constraints[constraint](settings); if (!remainingSettings) { return false; } else { settings = remainingSettings; } } } return azureUtil.objectKeysLength(settings) === 0; };