mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUACAMOLE-926: Correct parameter values in import file to correct case if possible.
This commit is contained in:
@@ -200,7 +200,8 @@ angular.module('import').factory('connectionParseService',
|
|||||||
/**
|
/**
|
||||||
* Returns a promise that will resolve to a transformer function that will
|
* Returns a promise that will resolve to a transformer function that will
|
||||||
* perform various checks and transforms relating to the connection group
|
* perform various checks and transforms relating to the connection group
|
||||||
* tree heirarchy. It will:
|
* tree hierarchy, pushing any errors into the resolved connection object.
|
||||||
|
* It will:
|
||||||
* - Ensure that a connection specifies either a valid group path (no path
|
* - Ensure that a connection specifies either a valid group path (no path
|
||||||
* defaults to ROOT), or a valid parent group identifier, but not both
|
* defaults to ROOT), or a valid parent group identifier, but not both
|
||||||
* - Ensure that this connection does not duplicate another connection
|
* - Ensure that this connection does not duplicate another connection
|
||||||
@@ -243,19 +244,24 @@ angular.module('import').factory('connectionParseService',
|
|||||||
let op = DirectoryPatch.Operation.ADD;
|
let op = DirectoryPatch.Operation.ADD;
|
||||||
|
|
||||||
// If both are specified, the parent group is ambigious
|
// If both are specified, the parent group is ambigious
|
||||||
if (providedIdentifier && connection.group)
|
if (providedIdentifier && connection.group) {
|
||||||
throw new ParseError({
|
connection.errors.push(new ParseError({
|
||||||
message: 'Only one of group or parentIdentifier can be set',
|
message: 'Only one of group or parentIdentifier can be set',
|
||||||
key: 'IMPORT.ERROR_AMBIGUOUS_PARENT_GROUP'
|
key: 'IMPORT.ERROR_AMBIGUOUS_PARENT_GROUP'
|
||||||
});
|
}));
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
// If a parent group identifier is present, but not valid
|
// If a parent group identifier is present, but not valid
|
||||||
else if (providedIdentifier && !groupPathsByIdentifier[providedIdentifier])
|
else if (providedIdentifier
|
||||||
throw new ParseError({
|
&& !groupPathsByIdentifier[providedIdentifier]) {
|
||||||
|
connection.errors.push(new ParseError({
|
||||||
message: 'No group with identifier: ' + providedIdentifier,
|
message: 'No group with identifier: ' + providedIdentifier,
|
||||||
key: 'IMPORT.ERROR_INVALID_GROUP_IDENTIFIER',
|
key: 'IMPORT.ERROR_INVALID_GROUP_IDENTIFIER',
|
||||||
variables: { IDENTIFIER: providedIdentifier }
|
variables: { IDENTIFIER: providedIdentifier }
|
||||||
});
|
}));
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
// If the parent identifier is valid, use it to determine the path
|
// If the parent identifier is valid, use it to determine the path
|
||||||
else if (providedIdentifier) {
|
else if (providedIdentifier) {
|
||||||
@@ -272,11 +278,13 @@ angular.module('import').factory('connectionParseService',
|
|||||||
group = connection.group;
|
group = connection.group;
|
||||||
|
|
||||||
// If the provided group isn't a string, it can never be valid
|
// If the provided group isn't a string, it can never be valid
|
||||||
if (typeof group !== 'string')
|
if (typeof group !== 'string') {
|
||||||
throw new ParseError({
|
connection.errors.push(new ParseError({
|
||||||
message: 'Invalid group type - must be a string',
|
message: 'Invalid group type - must be a string',
|
||||||
key: 'IMPORT.ERROR_INVALID_GROUP_TYPE'
|
key: 'IMPORT.ERROR_INVALID_GROUP_TYPE'
|
||||||
});
|
}));
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
// Allow the group to start with a leading slash instead instead
|
// Allow the group to start with a leading slash instead instead
|
||||||
// of explicitly requiring the root connection group
|
// of explicitly requiring the root connection group
|
||||||
@@ -295,12 +303,14 @@ angular.module('import').factory('connectionParseService',
|
|||||||
parentIdentifier = groupPathsByIdentifier[group];
|
parentIdentifier = groupPathsByIdentifier[group];
|
||||||
|
|
||||||
// If the group doesn't match anything in the tree
|
// If the group doesn't match anything in the tree
|
||||||
if (!parentIdentifier)
|
if (!parentIdentifier) {
|
||||||
throw new ParseError({
|
connection.errors.push(new ParseError({
|
||||||
message: 'No group found named: ' + connection.group,
|
message: 'No group found named: ' + connection.group,
|
||||||
key: 'IMPORT.ERROR_INVALID_GROUP',
|
key: 'IMPORT.ERROR_INVALID_GROUP',
|
||||||
variables: { GROUP: connection.group }
|
variables: { GROUP: connection.group }
|
||||||
});
|
}));
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,12 +325,12 @@ angular.module('import').factory('connectionParseService',
|
|||||||
|
|
||||||
// Error out if this is a duplicate of a connection already in the
|
// Error out if this is a duplicate of a connection already in the
|
||||||
// file
|
// file
|
||||||
if (!!_.get(connectionsInFile, path))
|
if (!!_.get(connectionsInFile, path))
|
||||||
throw new ParseError({
|
connection.errors.push(new ParseError({
|
||||||
message: 'Duplicate connection in file: ' + path,
|
message: 'Duplicate connection in file: ' + path,
|
||||||
key: 'IMPORT.ERROR_DUPLICATE_CONNECTION_IN_FILE',
|
key: 'IMPORT.ERROR_DUPLICATE_CONNECTION_IN_FILE',
|
||||||
variables: { NAME: connection.name, PATH: group }
|
variables: { NAME: connection.name, PATH: group }
|
||||||
});
|
}));
|
||||||
|
|
||||||
// Mark the current path as already seen in the file
|
// Mark the current path as already seen in the file
|
||||||
_.setWith(connectionsInFile, path, connection, Object);
|
_.setWith(connectionsInFile, path, connection, Object);
|
||||||
@@ -329,17 +339,18 @@ angular.module('import').factory('connectionParseService',
|
|||||||
const existingIdentifier = _.get(connectionIdsByGroupAndName,
|
const existingIdentifier = _.get(connectionIdsByGroupAndName,
|
||||||
[parentIdentifier, connection.name]);
|
[parentIdentifier, connection.name]);
|
||||||
|
|
||||||
let importMode;
|
// The default behavior is to create connections if no conflict
|
||||||
|
let importMode = ImportConnection.ImportMode.CREATE;
|
||||||
let identifier;
|
let identifier;
|
||||||
|
|
||||||
// If updates to existing connections are disallowed
|
// If updates to existing connections are disallowed
|
||||||
if (existingIdentifier && importConfig.existingConnectionMode ===
|
if (existingIdentifier && importConfig.existingConnectionMode ===
|
||||||
ConnectionImportConfig.ExistingConnectionMode.REJECT)
|
ConnectionImportConfig.ExistingConnectionMode.REJECT)
|
||||||
throw new ParseError({
|
connection.errors.push(new ParseError({
|
||||||
message: 'Rejecting update to existing connection: ' + path,
|
message: 'Rejecting update to existing connection: ' + path,
|
||||||
key: 'IMPORT.ERROR_REJECT_UPDATE_CONNECTION',
|
key: 'IMPORT.ERROR_REJECT_UPDATE_CONNECTION',
|
||||||
variables: { NAME: connection.name, PATH: group }
|
variables: { NAME: connection.name, PATH: group }
|
||||||
});
|
}));
|
||||||
|
|
||||||
// If the connection is being replaced, set the existing identifer
|
// If the connection is being replaced, set the existing identifer
|
||||||
else if (existingIdentifier) {
|
else if (existingIdentifier) {
|
||||||
@@ -347,7 +358,6 @@ angular.module('import').factory('connectionParseService',
|
|||||||
importMode = ImportConnection.ImportMode.REPLACE;
|
importMode = ImportConnection.ImportMode.REPLACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, just create a new connection
|
|
||||||
else
|
else
|
||||||
importMode = ImportConnection.ImportMode.CREATE;
|
importMode = ImportConnection.ImportMode.CREATE;
|
||||||
|
|
||||||
@@ -359,13 +369,22 @@ angular.module('import').factory('connectionParseService',
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise that resolves to a map of all valid protocols to the
|
* Returns a promise that resolves to a map of all valid protocols to a map
|
||||||
* boolean value "true", i.e. a set of all valid protocols.
|
* of connection parameter names to a map of lower-cased and trimmed option
|
||||||
|
* values for that parameter to the actual valid option value.
|
||||||
*
|
*
|
||||||
* @returns {Promise.<Object.<String, Boolean>>}
|
* This format is designed for easy retrieval of corrected parameter values
|
||||||
* A promise that resolves to a set of all valid protocols.
|
* if the user-provided value matches a valid option except for case or
|
||||||
|
* leading/trailing whitespace.
|
||||||
|
*
|
||||||
|
* If a parameter has no options (i.e. any string value is allowed), the
|
||||||
|
* parameter name will map to a null value.
|
||||||
|
*
|
||||||
|
* @returns {Promise.<Object.<String, Object.<String, Object.<String, String>>>>}
|
||||||
|
* A promise that resolves to a map of all valid protocols to parameter
|
||||||
|
* names to valid values.
|
||||||
*/
|
*/
|
||||||
function getValidProtocols() {
|
function getProtocolParameterOptions() {
|
||||||
|
|
||||||
// The current data source - the one that the connections will be
|
// The current data source - the one that the connections will be
|
||||||
// imported into
|
// imported into
|
||||||
@@ -373,67 +392,109 @@ angular.module('import').factory('connectionParseService',
|
|||||||
|
|
||||||
// Fetch the protocols and convert to a set of valid protocol names
|
// Fetch the protocols and convert to a set of valid protocol names
|
||||||
return schemaService.getProtocols(dataSource).then(
|
return schemaService.getProtocols(dataSource).then(
|
||||||
protocols => _.mapValues(protocols, () => true));
|
protocols => _.mapValues(protocols, ({connectionForms}) => {
|
||||||
|
|
||||||
|
const fieldMap = {};
|
||||||
|
|
||||||
|
// Go through all the connection forms and get the fields for each
|
||||||
|
connectionForms.forEach(({fields}) => fields.forEach(field => {
|
||||||
|
|
||||||
|
const { name, options } = field;
|
||||||
|
|
||||||
|
// Set the value to null to indicate that there are no options
|
||||||
|
if (!options)
|
||||||
|
fieldMap[name] = null;
|
||||||
|
|
||||||
|
// Set the value to a map of lowercased/trimmed option values
|
||||||
|
// to actual option values
|
||||||
|
else
|
||||||
|
fieldMap[name] = _.mapKeys(
|
||||||
|
options, option => option.trim().toLowerCase());
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
return fieldMap;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of field-level errors for the provided connection,
|
* Resolves to function that will perform field-level (not connection
|
||||||
* such as missing or invalid fields that are not dependant on the
|
* hierarchy dependent) checks and transforms to a provided connection,
|
||||||
* connection group heirarchy.
|
* returning the transformed connection.
|
||||||
*
|
*
|
||||||
* @param {ImportConnection} connection
|
* @returns {Promise.<Function.<ImportConnection, ImportConnection>>}
|
||||||
* The connection object to check field values on.
|
* A promise resolving to a function that will apply field-level
|
||||||
*
|
* transforms and checks to a provided connection, returning the
|
||||||
* @param {Object.<String, Boolean>} protocols
|
* transformed connection.
|
||||||
* A set of valid protocols, such as the one returned by
|
|
||||||
* getValidProtocols().
|
|
||||||
*
|
|
||||||
* @returns {ParseError[]}
|
|
||||||
* A list of field-level errors for the provided connection.
|
|
||||||
*/
|
*/
|
||||||
function getFieldErrors(connection, protocols) {
|
function getFieldTransformer() {
|
||||||
const connectionErrors = [];
|
|
||||||
|
|
||||||
// Ensure that a protocol was specified for this connection
|
return getProtocolParameterOptions().then(protocols => connection => {
|
||||||
const protocol = connection.protocol;
|
|
||||||
if (!protocol)
|
|
||||||
connectionErrors.push(new ParseError({
|
|
||||||
message: 'Missing required protocol field',
|
|
||||||
key: 'IMPORT.ERROR_REQUIRED_PROTOCOL_CONNECTION'
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Ensure that a valid protocol was specified for this connection
|
// Ensure that a protocol was specified for this connection
|
||||||
if (!protocols[protocol])
|
const protocol = connection.protocol;
|
||||||
connectionErrors.push(new ParseError({
|
if (!protocol)
|
||||||
message: 'Invalid protocol: ' + protocol,
|
connection.errors.push(new ParseError({
|
||||||
key: 'IMPORT.ERROR_INVALID_PROTOCOL',
|
message: 'Missing required protocol field',
|
||||||
variables: { PROTOCOL: protocol }
|
key: 'IMPORT.ERROR_REQUIRED_PROTOCOL_CONNECTION'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Ensure that a name was specified for this connection
|
// Ensure that a valid protocol was specified for this connection
|
||||||
if (!connection.name)
|
if (!protocols[protocol])
|
||||||
connectionErrors.push(new ParseError({
|
connection.errors.push(new ParseError({
|
||||||
message: 'Missing required name field',
|
message: 'Invalid protocol: ' + protocol,
|
||||||
key: 'IMPORT.ERROR_REQUIRED_NAME_CONNECTION'
|
key: 'IMPORT.ERROR_INVALID_PROTOCOL',
|
||||||
}));
|
variables: { PROTOCOL: protocol }
|
||||||
|
}));
|
||||||
|
|
||||||
// Ensure that the specified user list, if any, is an array
|
// Ensure that a name was specified for this connection
|
||||||
const users = connection.users;
|
if (!connection.name)
|
||||||
if (users && !Array.isArray(users))
|
connection.errors.push(new ParseError({
|
||||||
connectionErrors.push(new ParseError({
|
message: 'Missing required name field',
|
||||||
message: 'Invalid users list - must be an array',
|
key: 'IMPORT.ERROR_REQUIRED_NAME_CONNECTION'
|
||||||
key: 'IMPORT.ERROR_INVALID_USERS_TYPE'
|
}));
|
||||||
}));
|
|
||||||
|
|
||||||
// Ensure that the specified user list, if any, is an array
|
// Ensure that the specified user list, if any, is an array
|
||||||
const groups = connection.groups;
|
const users = connection.users;
|
||||||
if (groups && !Array.isArray(groups))
|
if (users && !Array.isArray(users))
|
||||||
connectionErrors.push(new ParseError({
|
connection.errors.push(new ParseError({
|
||||||
message: 'Invalid groups list - must be an array',
|
message: 'Invalid users list - must be an array',
|
||||||
key: 'IMPORT.ERROR_INVALID_USER_GROUPS_TYPE'
|
key: 'IMPORT.ERROR_INVALID_USERS_TYPE'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return connectionErrors;
|
// Ensure that the specified user list, if any, is an array
|
||||||
|
const groups = connection.groups;
|
||||||
|
if (groups && !Array.isArray(groups))
|
||||||
|
connection.errors.push(new ParseError({
|
||||||
|
message: 'Invalid groups list - must be an array',
|
||||||
|
key: 'IMPORT.ERROR_INVALID_USER_GROUPS_TYPE'
|
||||||
|
}));
|
||||||
|
|
||||||
|
// If the protocol is not valid, there's no point in trying to check
|
||||||
|
// parameter case sensitivity
|
||||||
|
if (!protocols[protocol])
|
||||||
|
return connection;
|
||||||
|
|
||||||
|
_.forEach(connection.parameters, (value, name) => {
|
||||||
|
|
||||||
|
// Convert the provided value to the format that would match
|
||||||
|
// the lookup object format
|
||||||
|
const comparisonValue = value.toLowerCase().trim();
|
||||||
|
|
||||||
|
// The validated / corrected option value for this connection
|
||||||
|
// parameter, if any
|
||||||
|
const validOptionValue = _.get(
|
||||||
|
protocols, [protocol, name, comparisonValue]);
|
||||||
|
|
||||||
|
// If the provided value fuzzily matches a valid option value,
|
||||||
|
// use the valid option value instead
|
||||||
|
if (validOptionValue)
|
||||||
|
connection.parameters[name] = validOptionValue;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -469,12 +530,12 @@ angular.module('import').factory('connectionParseService',
|
|||||||
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
|
|
||||||
// Get the tree transformer and valid protocol set
|
// Get the tree transformer and relevant protocol information
|
||||||
return $q.all({
|
return $q.all({
|
||||||
treeTransformer : getTreeTransformer(importConfig),
|
fieldTransformer : getFieldTransformer(),
|
||||||
protocols : getValidProtocols()
|
treeTransformer : getTreeTransformer(importConfig),
|
||||||
})
|
})
|
||||||
.then(({treeTransformer, protocols}) =>
|
.then(({fieldTransformer, treeTransformer}) =>
|
||||||
connectionData.reduce((parseResult, data) => {
|
connectionData.reduce((parseResult, data) => {
|
||||||
|
|
||||||
const { patches, users, groups, groupPaths } = parseResult;
|
const { patches, users, groups, groupPaths } = parseResult;
|
||||||
@@ -485,26 +546,14 @@ angular.module('import').factory('connectionParseService',
|
|||||||
connectionObject = transform(connectionObject);
|
connectionObject = transform(connectionObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
// All errors encountered while running the connection through the
|
// Apply the field level transforms
|
||||||
// provided transform, starting with those encountered during
|
connectionObject = fieldTransformer(connectionObject);
|
||||||
// the provided transforms, and any errors from missing fields
|
|
||||||
const connectionErrors = [
|
|
||||||
..._.get(connectionObject, 'errors', []),
|
|
||||||
...getFieldErrors(connectionObject, protocols)
|
|
||||||
];
|
|
||||||
|
|
||||||
// Determine the connection's place in the connection group tree
|
// Apply the connection group hierarchy transforms
|
||||||
try {
|
connectionObject = treeTransformer(connectionObject);
|
||||||
connectionObject = treeTransformer(connectionObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there was a problem with the connection group heirarchy
|
|
||||||
catch (error) {
|
|
||||||
connectionErrors.push(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are any errors for this connection, fail the whole batch
|
// If there are any errors for this connection, fail the whole batch
|
||||||
if (connectionErrors.length)
|
if (connectionObject.errors.length)
|
||||||
parseResult.hasErrors = true;
|
parseResult.hasErrors = true;
|
||||||
|
|
||||||
// The value for the patch is a full-fledged Connection
|
// The value for the patch is a full-fledged Connection
|
||||||
@@ -559,7 +608,7 @@ angular.module('import').factory('connectionParseService',
|
|||||||
groupPaths[index] = connectionObject.group;
|
groupPaths[index] = connectionObject.group;
|
||||||
|
|
||||||
// Save the errors for this connection into the parse result
|
// Save the errors for this connection into the parse result
|
||||||
parseResult.errors[index] = connectionErrors;
|
parseResult.errors[index] = connectionObject.errors;
|
||||||
|
|
||||||
// Add this connection index to the list for each user
|
// Add this connection index to the list for each user
|
||||||
_.forEach(connectionObject.users, identifier => {
|
_.forEach(connectionObject.users, identifier => {
|
||||||
@@ -700,8 +749,10 @@ angular.module('import').factory('connectionParseService',
|
|||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produce a ParseResult
|
// Produce a ParseResult, making sure that each record is converted to
|
||||||
return parseConnectionData(importConfig, connectionData);
|
// the ImportConnection type before further parsing
|
||||||
|
return parseConnectionData(importConfig, connectionData,
|
||||||
|
[connection => new ImportConnection(connection)]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -740,8 +791,10 @@ angular.module('import').factory('connectionParseService',
|
|||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produce a ParseResult
|
// Produce a ParseResult, making sure that each record is converted to
|
||||||
return parseConnectionData(importConfig, connectionData);
|
// the ImportConnection type before further parsing
|
||||||
|
return parseConnectionData(importConfig, connectionData,
|
||||||
|
[connection => new ImportConnection(connection)]);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user