| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261 |
1
1
1
1
1
1
1
8
8
1
1
1
1
4
1
4
1
72
72
72
197
6
191
191
1
190
1
189
189
3
186
186
185
1
66
1
370
262
262
262
690
690
262
594
594
594
262
262
258
258
258
332
106
152
14
138
1
4
4
133
133
69
64
86
63
1
4
1
25
25
1
160
160
1
185
185
1
11
11
11
11
1
185
185
262
262
258
108
150
73
| //
// 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 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) {
Error.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 Error(SR.INVALID_CONNECTION_STRING);
} else if (equalDex === 0) {
// empty key name.
throw new Error(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 Error(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 Error(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) {
Eif (userSettings.hasOwnProperty(key)) {
result[key.toLowerCase()] = userSettings[key];
}
}
for (var requirement in requirements) {
Eif (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]);
Eif (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 Error('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) {
Eif (constraints.hasOwnProperty(constraint)) {
var remainingSettings = constraints[constraint](settings);
if (!remainingSettings) {
return false;
} else {
settings = remainingSettings;
}
}
}
return azureUtil.objectKeysLength(settings) === 0;
}; |