Issues (524)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

js/form.jsx (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
/* global Q */
2
var validator = require("validator");
3
var _ = require('underscore');
4
5
var React = require("react");
6
7
var InputMixin = require("./FormInputMixin.jsx");
8
var Input = require("./FormInput.jsx");
9
var Textarea = require("./FormTextArea.jsx");
10
var Select = require("./FormSelect.jsx");
11
var CheckboxSet = require("./FormCheckboxSet.jsx");
12
var Password = require("./FormPassword.jsx");
13
var PasswordConfirm = require("./FormPasswordConfirm.jsx");
14
15
// Create a validation method that can be used as:
16
// equalsField|"firstFieldID"|"secondFieldID"
17
validator.extend('equalsField', function(string, firstFieldID, secondFieldID) {
18
	var first = document.getElementById(firstFieldID);
19
	var second = document.getElementById(secondFieldID);
20
	var firstValue = '';
21
	if (first.value) {
22
		firstValue = first.value;
23
	}
24
	var secondValue = '';
25
	if (second.value) {
26
		secondValue = second.value;
27
	}
28
	return firstValue === secondValue;
29
});
30
31
var Form = React.createClass({
32
33
	getInitialState: function () {
34
		return {
35
			isSubmitting: this.props.initialIsSubmitting || false,
36
			securityID: this.props.securityID,
37
			securityTokenName: this.props.securityTokenName || 'DispatcherSecurityID'
38
		};
39
	},
40
41
	componentWillMount: function () {
42
		// We add a model to use when submitting the form
43
		this.model = {};
44
		// We create a map of traversed inputs
45
		this.inputs = {};
46
		// these are the child components that will be rendered
47
		this.amendedChildren = React.Children.map(this.props.children, this.amendChildren);
48
	},
49
50
	componentWillReceiveProps: function(nextProps) {
51
		if (!nextProps.securityID) {
52
			return;
53
		}
54
		this.setState({
55
			securityID: nextProps.securityID
56
		});
57
	},
58
59
	componentWillUpdate: function(nextProps) {
60
		// these are the child components that will be rendered
61
		this.amendedChildren = React.Children.map(nextProps.children, this.amendChildren);
62
	},
63
64
	/**
65
	 * Triggers global form error.
66
	 */
67
	setErrorOnForm: function(message) {
68
		var msg = message;
69
		if (!msg) {
70
			msg = 'Unspecified server error occured. Try again or contact the helpdesk if the problem persists.';
71
		}
72
73
		this.setState({
74
			serverMessage: msg,
75
			serverMessageType: 'error'
76
		});
77
	},
78
79
	/**
80
	 * Triggers errors on form fields matching passed object's keys.
81
	 */
82
	setErrorsOnInputs: function (errors) {
83
		var formError = [];
84
		_.keys(errors).forEach(function (name) {
85
86
			if (typeof this.inputs[name] !== 'undefined' && this.inputs[name]) {
87
				var component = this.inputs[name];
88
89
				component.setState({
90
					isValid: false,
91
					serverError: errors[name]
92
				});
93
			} else {
94
				// If the field does not exist, fall back to the global form error.
95
				formError.push(errors[name]);
96
			}
97
98
		}.bind(this));
99
100
		if (formError.length > 0) {
101
			this.setErrorOnForm(formError.join('<br/>'));
102
		}
103
	},
104
105
	// Submit the form if all fields validation passes and redirect if the
106
	// return contains a 'RedirectTo' value
107
	submit: function (event) {
108
		event.stopPropagation();
109
		event.preventDefault();
110
111
		if (!this.validateForm()) {
112
			return;
113
		}
114
115
		this.updateModel();
116
117
		this.setState({ isSubmitting: true });
118
119
		var self = this;
120
		var postData = {
121
			Details: JSON.stringify(this.model)
122
		};
123
		postData[this.state.securityTokenName] = this.state.securityID;
124
		Q($.ajax({
125
			type: "POST",
126
			url: this.props.url,
127
			data: postData
128
		})).then(function(data) {
129
			if (data.NewSecurityID) {
130
				self.setState({ securityID: data.NewSecurityID });
131
			}
132
			if (self.props.afterSuccess) {
133
				self.props.afterSuccess(data);
134
			} else {
135
				self.afterSuccess(data);
136
			}
137
		}, function(response) {
138
			self.afterFailure(response);
139
			self.setState({ isSubmitting: false });
140
		}).catch(function(errorMessage) {
141
			console.error(errorMessage); // eslint-disable-line no-console
142
		});
143
	},
144
145
	afterSuccess: function(data) {
146
		if (data.RedirectTo) {
147
			window.location.href = data.RedirectTo;
148
		}
149
	},
150
151
	afterFailure: function(response) {
152
		this.setState({ isSubmitting: false });
153
154
		var ct = response.getResponseHeader("content-type") || "";
155
		if (ct.indexOf('json') > -1) {
156
			// The response may be parse-able JSON with "InputErrors" structure holding field-specific errors.
157
			var json = {};
158
			try {
159
				json = JSON.parse(response.responseText);
160
			} catch (e) {
161
				var errMsg = 'Received badly formatted response. Try again or contact ';
162
				errMsg += 'the helpdesk if the problem persists.';
163
				this.setErrorOnForm(errMsg);
164
			}
165
166
			if (typeof json.NewSecurityID !== 'undefined') {
167
				this.setState({ securityID: json.NewSecurityID });
168
			}
169
170
			if (_.size(json.InputErrors) > 0) {
171
				this.setErrorsOnInputs(json.InputErrors);
172
			} else {
173
				this.setErrorOnForm(null);
174
			}
175
		} else {
176
			// No JSON, use the message literally.
177
			this.setErrorOnForm(response.responseText);
178
		}
179
	},
180
181
	validateForm: function () {
182
183
		var allIsValid = true;
184
185
		var inputs = this.inputs;
186
		var self = this;
187
		// Validate all the Input components
188
		_.keys(inputs).forEach(function (name) {
189
190
			if (!self.validate(inputs[name])) {
191
				allIsValid = false;
192
			}
193
		});
194
		this.setState({ isValid: allIsValid });
195
		return allIsValid;
196
	},
197
198
	// The validate method grabs what it needs from the component,
199
	// validates the component and then validates the form
200
	validate: function (component) {
201
202
		if (!component.props.validations) {
203
			return true;
204
		}
205
206
		var isValid = true;
207
208
		if (component.state.value || component.props.required) {
209
210
			component.props.validations.split('/').forEach(function (validation) {
211
				// By splitting on "|" we get an array of arguments that we pass
212
				// to the validator. ex.: isLength|5 -> ['isLength', '5']
213
				var args = validation.split('|');
214
215
				var validateMethod = args.shift();
216
217
				// We use JSON.parse to convert the string values passed to the
218
				// correct type. Ex. 'isLength|1' will make '1' an actual number
219
				args = args.map(function (arg) {
220
					return JSON.parse(arg);
221
				});
222
223
				args = [component.state.value].concat(args);
224
225
				if (typeof validator[validateMethod] !== 'function') {
226
					var debugWarning = 'Validation method "' + validateMethod;
227
					debugWarning += '" on component "' + component.props.name + '" doesn\'t exists';
228
					console.warn(debugWarning); // eslint-disable-line no-console
229
				} else {
230
					// this is effectively a call to something like:
231
					// `validator.isLength('valueFromInput', 5)`
232
					isValid = (validator[validateMethod].apply(validator, args));
233
				}
234
			});
235
236
			component.setState({
237
				isValid: isValid,
238
				serverError: null
239
			});
240
		}
241
242
		return isValid;
243
	},
244
245
	// This is called on submit and updates the model with the values from the
246
	// child input components and the latest CSRF token
247
	updateModel: function () {
248
		_.keys(this.inputs).forEach(function (name) {
249
			this.model[name] = this.inputs[name].state.value;
250
		}.bind(this));
251
	},
252
253
	// Child input components will call this method when they are mounting
254
	attachToForm: function (component) {
255
		this.inputs[component.props.name] = component;
256
		this.model[component.props.name] = component.state.value;
257
	},
258
259
	// Child input components will call this method when they are unmounting
260
	detachFromForm: function (component) {
261
		delete this.inputs[component.props.name];
262
		delete this.model[component.props.name];
263
	},
264
265
	// We will need to clone the child component(s) because we need to add and
266
	// change their properties to them. ReactJS doesn't allow you to change
267
	// properties because they are immutable.
268
	amendChildren: function(child) {
269
270
		if (!child || !child.props) {
271
			return child;
272
		}
273
274
		// If this component has a child components, we need to amend them as well
275
		var children = [];
276
		if (child.props.children) {
277
			children = React.Children.map(child.props.children, this.amendChildren);
278
		}
279
280
		// Child is not a Input component so just change the (eventual) children props
281
		if (typeof child.props.name === 'undefined') {
282
			return React.cloneElement(child, {children: children});
283
		}
284
285
		var validations = child.props.validations;
286
		// Dynamically add a 'required' validation
287
		if (child.props.required) {
288
			validations = validations ? validations + '/' : '';
289
			validations += 'isLength|1';
290
		}
291
292
		return React.cloneElement(child, {
293
			attachToForm: this.attachToForm,
294
			detachFromForm: this.detachFromForm,
295
			validations: validations,
296
			children: children
297
		});
298
	},
299
300
	render: function () {
301
		var message = "";
302
		if (this.state.serverMessage) {
303
			message = (
304
				<div
305
					className={'alert alert-' + this.state.serverMessageType}
306
					dangerouslySetInnerHTML={{__html:this.state.serverMessage}}
0 ignored issues
show
Dangerous property 'dangerouslySetInnerHTML' found
Loading history...
307
				/>
308
			);
309
		}
310
311
		var cancelButton = null;
312
313
		if (this.props.cancelButton) {
314
			cancelButton = this.props.cancelButton;
315
		}
316
317
		var buttonTitle = 'Submit';
318
		if (this.props.buttonTitle) {
319
			buttonTitle = this.props.buttonTitle;
320
		}
321
		var buttonSubmittingTitle = "Submitting";
322
		if (this.props.buttonSubmittingTitle) {
323
			buttonSubmittingTitle = this.props.buttonSubmittingTitle;
324
		}
325
		return (
326
			<form onSubmit={this.submit} className="form">
327
				{message}
328
				{this.amendedChildren}
329
				<div className="btn-toolbar">
330
					<button
331
						className="btn btn-primary"
332
						type="submit"
333
						disabled={this.state.isSubmitting}
334
					>
335
						{this.state.isSubmitting ? buttonSubmittingTitle : buttonTitle}
336
					</button>
337
					{cancelButton}
338
				</div>
339
			</form>
340
		);
341
	}
342
});
343
344
exports.Form = Form;
345
exports.InputMixin = InputMixin;
346
exports.Input = Input;
347
exports.Textarea = Textarea;
348
exports.Select = Select;
349
exports.CheckboxSet = CheckboxSet;
350
exports.Password = Password;
351
exports.PasswordConfirm = PasswordConfirm;
352