Plato on Github
Report Home
service/sanitization.js
Maintainability
68.65
Lines of code
312
Difficulty
49.85
Estimated Errors
1.45
Function weight
By Complexity
By SLOC
/** * @ngdoc object * @name pascalprecht.translate.$translateSanitizationProvider * * @description * * Configurations for $translateSanitization */ angular.module('pascalprecht.translate').provider('$translateSanitization', $translateSanitizationProvider); function $translateSanitizationProvider () { 'use strict'; var $sanitize, $sce, currentStrategy = null, // TODO change to either 'sanitize', 'escape' or ['sanitize', 'escapeParameters'] in 3.0. hasConfiguredStrategy = false, hasShownNoStrategyConfiguredWarning = false, strategies; /** * Definition of a sanitization strategy function * @callback StrategyFunction * @param {string|object} value - value to be sanitized (either a string or an interpolated value map) * @param {string} mode - either 'text' for a string (translation) or 'params' for the interpolated params * @return {string|object} */ /** * @ngdoc property * @name strategies * @propertyOf pascalprecht.translate.$translateSanitizationProvider * * @description * Following strategies are built-in: * <dl> * <dt>sanitize</dt> * <dd>Sanitizes HTML in the translation text using $sanitize</dd> * <dt>escape</dt> * <dd>Escapes HTML in the translation</dd> * <dt>sanitizeParameters</dt> * <dd>Sanitizes HTML in the values of the interpolation parameters using $sanitize</dd> * <dt>escapeParameters</dt> * <dd>Escapes HTML in the values of the interpolation parameters</dd> * <dt>escaped</dt> * <dd>Support legacy strategy name 'escaped' for backwards compatibility (will be removed in 3.0)</dd> * </dl> * */ strategies = { sanitize: function (value, mode/*, context*/) { if (mode === 'text') { value = htmlSanitizeValue(value); } return value; }, escape: function (value, mode/*, context*/) { if (mode === 'text') { value = htmlEscapeValue(value); } return value; }, sanitizeParameters: function (value, mode/*, context*/) { if (mode === 'params') { value = mapInterpolationParameters(value, htmlSanitizeValue); } return value; }, escapeParameters: function (value, mode/*, context*/) { if (mode === 'params') { value = mapInterpolationParameters(value, htmlEscapeValue); } return value; }, sce: function (value, mode, context) { if (mode === 'text') { value = htmlTrustValue(value); } else if (mode === 'params') { if (context !== 'filter') { // do html escape in filter context #1101 value = mapInterpolationParameters(value, htmlEscapeValue); } } return value; }, sceParameters: function (value, mode/*, context*/) { if (mode === 'params') { value = mapInterpolationParameters(value, htmlTrustValue); } return value; } }; // Support legacy strategy name 'escaped' for backwards compatibility. // TODO should be removed in 3.0 strategies.escaped = strategies.escapeParameters; /** * @ngdoc function * @name pascalprecht.translate.$translateSanitizationProvider#addStrategy * @methodOf pascalprecht.translate.$translateSanitizationProvider * * @description * Adds a sanitization strategy to the list of known strategies. * * @param {string} strategyName - unique key for a strategy * @param {StrategyFunction} strategyFunction - strategy function * @returns {object} this */ this.addStrategy = function (strategyName, strategyFunction) { strategies[strategyName] = strategyFunction; return this; }; /** * @ngdoc function * @name pascalprecht.translate.$translateSanitizationProvider#removeStrategy * @methodOf pascalprecht.translate.$translateSanitizationProvider * * @description * Removes a sanitization strategy from the list of known strategies. * * @param {string} strategyName - unique key for a strategy * @returns {object} this */ this.removeStrategy = function (strategyName) { delete strategies[strategyName]; return this; }; /** * @ngdoc function * @name pascalprecht.translate.$translateSanitizationProvider#useStrategy * @methodOf pascalprecht.translate.$translateSanitizationProvider * * @description * Selects a sanitization strategy. When an array is provided the strategies will be executed in order. * * @param {string|StrategyFunction|array} strategy The sanitization strategy / strategies which should be used. Either a name of an existing strategy, a custom strategy function, or an array consisting of multiple names and / or custom functions. * @returns {object} this */ this.useStrategy = function (strategy) { hasConfiguredStrategy = true; currentStrategy = strategy; return this; }; /** * @ngdoc object * @name pascalprecht.translate.$translateSanitization * @requires $injector * @requires $log * * @description * Sanitizes interpolation parameters and translated texts. * */ this.$get = function ($injector, $log) { var cachedStrategyMap = {}; var applyStrategies = function (value, mode, context, selectedStrategies) { angular.forEach(selectedStrategies, function (selectedStrategy) { if (angular.isFunction(selectedStrategy)) { value = selectedStrategy(value, mode, context); } else if (angular.isFunction(strategies[selectedStrategy])) { value = strategies[selectedStrategy](value, mode, context); } else if (angular.isString(strategies[selectedStrategy])) { if (!cachedStrategyMap[strategies[selectedStrategy]]) { try { cachedStrategyMap[strategies[selectedStrategy]] = $injector.get(strategies[selectedStrategy]); } catch (e) { cachedStrategyMap[strategies[selectedStrategy]] = function() {}; throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\''); } } value = cachedStrategyMap[strategies[selectedStrategy]](value, mode, context); } else { throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\''); } }); return value; }; // TODO: should be removed in 3.0 var showNoStrategyConfiguredWarning = function () { if (!hasConfiguredStrategy && !hasShownNoStrategyConfiguredWarning) { $log.warn('pascalprecht.translate.$translateSanitization: No sanitization strategy has been configured. This can have serious security implications. See http://angular-translate.github.io/docs/#/guide/19_security for details.'); hasShownNoStrategyConfiguredWarning = true; } }; if ($injector.has('$sanitize')) { $sanitize = $injector.get('$sanitize'); } if ($injector.has('$sce')) { $sce = $injector.get('$sce'); } return { /** * @ngdoc function * @name pascalprecht.translate.$translateSanitization#useStrategy * @methodOf pascalprecht.translate.$translateSanitization * * @description * Selects a sanitization strategy. When an array is provided the strategies will be executed in order. * * @param {string|StrategyFunction|array} strategy The sanitization strategy / strategies which should be used. Either a name of an existing strategy, a custom strategy function, or an array consisting of multiple names and / or custom functions. */ useStrategy: (function (self) { return function (strategy) { self.useStrategy(strategy); }; })(this), /** * @ngdoc function * @name pascalprecht.translate.$translateSanitization#sanitize * @methodOf pascalprecht.translate.$translateSanitization * * @description * Sanitizes a value. * * @param {string|object} value The value which should be sanitized. * @param {string} mode The current sanitization mode, either 'params' or 'text'. * @param {string|StrategyFunction|array} [strategy] Optional custom strategy which should be used instead of the currently selected strategy. * @param {string} [context] The context of this call: filter, service. Default is service * @returns {string|object} sanitized value */ sanitize: function (value, mode, strategy, context) { if (!currentStrategy) { showNoStrategyConfiguredWarning(); } if (!strategy && strategy !== null) { strategy = currentStrategy; } if (!strategy) { return value; } if (!context) { context = 'service'; } var selectedStrategies = angular.isArray(strategy) ? strategy : [strategy]; return applyStrategies(value, mode, context, selectedStrategies); } }; }; var htmlEscapeValue = function (value) { var element = angular.element('<div></div>'); element.text(value); // not chainable, see #1044 return element.html(); }; var htmlSanitizeValue = function (value) { if (!$sanitize) { throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as \'escape\'.'); } return $sanitize(value); }; var htmlTrustValue = function (value) { if (!$sce) { throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sce service.'); } return $sce.trustAsHtml(value); }; var mapInterpolationParameters = function (value, iteratee, stack) { if (angular.isDate(value)) { return value; } else if (angular.isObject(value)) { var result = angular.isArray(value) ? [] : {}; if (!stack) { stack = []; } else { if (stack.indexOf(value) > -1) { throw new Error('pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object'); } } stack.push(value); angular.forEach(value, function (propertyValue, propertyKey) { /* Skipping function properties. */ if (angular.isFunction(propertyValue)) { return; } result[propertyKey] = mapInterpolationParameters(propertyValue, iteratee, stack); }); stack.splice(-1, 1); // remove last return result; } else if (angular.isNumber(value)) { return value; } else if (value === true || value === false) { return value; } else if (!angular.isUndefined(value) && value !== null) { return iteratee(value); } else { return value; } }; }