aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorWouter Admiraal <wouter.admiraal@sonarsource.com>2020-11-30 15:02:02 +0100
committersonartech <sonartech@sonarsource.com>2020-12-03 20:06:38 +0000
commit112871533342442cbdd5bf18028ef924dfc52c6f (patch)
tree8b77606a7c99576f26071b52ba7a53c81ca0ba27 /server
parent07cd210069bba37cc26a7bbadfcc7e99bd6bbe98 (diff)
downloadsonarqube-112871533342442cbdd5bf18028ef924dfc52c6f.tar.gz
sonarqube-112871533342442cbdd5bf18028ef924dfc52c6f.zip
SONAR-13984 Do not use email address from controlled input
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx37
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx66
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap292
3 files changed, 372 insertions, 23 deletions
diff --git a/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx
index ad34b04c5b2..90fe52ce511 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx
@@ -35,7 +35,7 @@ interface State {
subject: string;
message: string;
loading: boolean;
- success: boolean;
+ success?: string;
error?: string;
}
@@ -48,8 +48,7 @@ export class EmailForm extends React.PureComponent<Props, State> {
recipient: this.props.currentUser.email || '',
subject: translate('email_configuration.test.subject'),
message: translate('email_configuration.test.message_text'),
- loading: false,
- success: false
+ loading: false
};
}
@@ -71,11 +70,11 @@ export class EmailForm extends React.PureComponent<Props, State> {
handleFormSubmit = (event: React.FormEvent) => {
event.preventDefault();
- this.setState({ success: false, error: undefined, loading: true });
+ this.setState({ success: undefined, error: undefined, loading: true });
const { recipient, subject, message } = this.state;
sendTestEmail(recipient, subject, message).then(() => {
if (this.mounted) {
- this.setState({ success: true, loading: false });
+ this.setState({ success: recipient, loading: false });
}
}, this.handleError);
};
@@ -93,6 +92,7 @@ export class EmailForm extends React.PureComponent<Props, State> {
};
render() {
+ const { error, loading, message, recipient, subject, success } = this.state;
return (
<div className="settings-definition">
<div className="settings-definition-left">
@@ -102,20 +102,17 @@ export class EmailForm extends React.PureComponent<Props, State> {
</div>
<form className="settings-definition-right" onSubmit={this.handleFormSubmit}>
- {this.state.success && (
+ {success && (
<div className="form-field">
<Alert variant="success">
- {translateWithParameters(
- 'email_configuration.test.email_was_sent_to_x',
- this.state.recipient
- )}
+ {translateWithParameters('email_configuration.test.email_was_sent_to_x', success)}
</Alert>
</div>
)}
- {this.state.error != null && (
+ {error !== undefined && (
<div className="form-field">
- <Alert variant="error">{this.state.error}</Alert>
+ <Alert variant="error">{error}</Alert>
</div>
)}
@@ -126,12 +123,12 @@ export class EmailForm extends React.PureComponent<Props, State> {
</label>
<input
className="settings-large-input"
- disabled={this.state.loading}
+ disabled={loading}
id="test-email-to"
onChange={this.onRecipientChange}
required={true}
type="email"
- value={this.state.recipient}
+ value={recipient}
/>
</div>
<div className="form-field">
@@ -140,11 +137,11 @@ export class EmailForm extends React.PureComponent<Props, State> {
</label>
<input
className="settings-large-input"
- disabled={this.state.loading}
+ disabled={loading}
id="test-email-subject"
onChange={this.onSubjectChange}
type="text"
- value={this.state.subject}
+ value={subject}
/>
</div>
<div className="form-field">
@@ -154,19 +151,19 @@ export class EmailForm extends React.PureComponent<Props, State> {
</label>
<textarea
className="settings-large-input"
- disabled={this.state.loading}
+ disabled={loading}
id="test-email-message"
onChange={this.onMessageChange}
required={true}
rows={5}
- value={this.state.message}
+ value={message}
/>
</div>
- <SubmitButton disabled={this.state.loading}>
+ <SubmitButton disabled={loading}>
{translate('email_configuration.test.send')}
</SubmitButton>
- {this.state.loading && <DeferredSpinner className="spacer-left" />}
+ {loading && <DeferredSpinner className="spacer-left" />}
</form>
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx
index e98ad8f8707..b5e7b2e10f6 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx
@@ -17,11 +17,75 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+/* eslint-disable sonarjs/no-duplicate-string */
import { shallow } from 'enzyme';
import * as React from 'react';
+import { change, submit, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
+import { sendTestEmail } from '../../../../api/settings';
import { mockLoggedInUser } from '../../../../helpers/testMocks';
import { EmailForm } from '../EmailForm';
+jest.mock('sonar-ui-common/helpers/request', () => ({
+ parseError: jest.fn().mockResolvedValue('Error message')
+}));
+
+jest.mock('../../../../api/settings', () => ({
+ sendTestEmail: jest.fn().mockResolvedValue(null)
+}));
+
it('should render correctly', () => {
- expect(shallow(<EmailForm currentUser={mockLoggedInUser()} />)).toMatchSnapshot();
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot('default');
+ wrapper.setState({ loading: true });
+ expect(wrapper).toMatchSnapshot('sending');
+ wrapper.setState({ loading: false, success: 'email@example.com' });
+ expect(wrapper).toMatchSnapshot('success');
+ wrapper.setState({ success: undefined, error: 'Some error message' });
+ expect(wrapper).toMatchSnapshot('error');
});
+
+it('should correctly control the inputs', () => {
+ const wrapper = shallowRender();
+
+ change(wrapper.find('#test-email-to'), 'new@recipient.com');
+ expect(wrapper.state().recipient).toBe('new@recipient.com');
+
+ change(wrapper.find('#test-email-subject'), 'New subject');
+ expect(wrapper.state().subject).toBe('New subject');
+
+ change(wrapper.find('#test-email-message'), 'New message');
+ expect(wrapper.state().message).toBe('New message');
+});
+
+it('should correctly test the email sending', async () => {
+ const wrapper = shallowRender();
+
+ submit(wrapper.find('form'));
+ expect(sendTestEmail).toHaveBeenCalledWith(
+ 'luke@skywalker.biz',
+ 'email_configuration.test.subject',
+ 'email_configuration.test.message_text'
+ );
+ expect(wrapper.state().loading).toBe(true);
+
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper.state().loading).toBe(false);
+ expect(wrapper.state().error).toBeUndefined();
+ expect(wrapper.state().success).toBe('luke@skywalker.biz');
+
+ (sendTestEmail as jest.Mock).mockRejectedValueOnce(null);
+
+ submit(wrapper.find('form'));
+
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper.state().success).toBeUndefined();
+ expect(wrapper.state().error).toBe('Error message');
+});
+
+function shallowRender(props: Partial<EmailForm['props']> = {}) {
+ return shallow<EmailForm>(
+ <EmailForm currentUser={mockLoggedInUser({ email: 'luke@skywalker.biz' })} {...props} />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap
index cc15cb3104d..96b6595eb05 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render correctly 1`] = `
+exports[`should render correctly: default 1`] = `
<div
className="settings-definition"
>
@@ -37,7 +37,295 @@ exports[`should render correctly 1`] = `
onChange={[Function]}
required={true}
type="email"
- value=""
+ value="luke@skywalker.biz"
+ />
+ </div>
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="test-email-subject"
+ >
+ email_configuration.test.subject
+ </label>
+ <input
+ className="settings-large-input"
+ disabled={false}
+ id="test-email-subject"
+ onChange={[Function]}
+ type="text"
+ value="email_configuration.test.subject"
+ />
+ </div>
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="test-email-message"
+ >
+ email_configuration.test.message
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <textarea
+ className="settings-large-input"
+ disabled={false}
+ id="test-email-message"
+ onChange={[Function]}
+ required={true}
+ rows={5}
+ value="email_configuration.test.message_text"
+ />
+ </div>
+ <SubmitButton
+ disabled={false}
+ >
+ email_configuration.test.send
+ </SubmitButton>
+ </form>
+</div>
+`;
+
+exports[`should render correctly: error 1`] = `
+<div
+ className="settings-definition"
+>
+ <div
+ className="settings-definition-left"
+ >
+ <h3
+ className="settings-definition-name"
+ >
+ email_configuration.test.title
+ </h3>
+ </div>
+ <form
+ className="settings-definition-right"
+ onSubmit={[Function]}
+ >
+ <div
+ className="form-field"
+ >
+ <Alert
+ variant="error"
+ >
+ Some error message
+ </Alert>
+ </div>
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="test-email-to"
+ >
+ email_configuration.test.to_address
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ className="settings-large-input"
+ disabled={false}
+ id="test-email-to"
+ onChange={[Function]}
+ required={true}
+ type="email"
+ value="luke@skywalker.biz"
+ />
+ </div>
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="test-email-subject"
+ >
+ email_configuration.test.subject
+ </label>
+ <input
+ className="settings-large-input"
+ disabled={false}
+ id="test-email-subject"
+ onChange={[Function]}
+ type="text"
+ value="email_configuration.test.subject"
+ />
+ </div>
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="test-email-message"
+ >
+ email_configuration.test.message
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <textarea
+ className="settings-large-input"
+ disabled={false}
+ id="test-email-message"
+ onChange={[Function]}
+ required={true}
+ rows={5}
+ value="email_configuration.test.message_text"
+ />
+ </div>
+ <SubmitButton
+ disabled={false}
+ >
+ email_configuration.test.send
+ </SubmitButton>
+ </form>
+</div>
+`;
+
+exports[`should render correctly: sending 1`] = `
+<div
+ className="settings-definition"
+>
+ <div
+ className="settings-definition-left"
+ >
+ <h3
+ className="settings-definition-name"
+ >
+ email_configuration.test.title
+ </h3>
+ </div>
+ <form
+ className="settings-definition-right"
+ onSubmit={[Function]}
+ >
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="test-email-to"
+ >
+ email_configuration.test.to_address
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ className="settings-large-input"
+ disabled={true}
+ id="test-email-to"
+ onChange={[Function]}
+ required={true}
+ type="email"
+ value="luke@skywalker.biz"
+ />
+ </div>
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="test-email-subject"
+ >
+ email_configuration.test.subject
+ </label>
+ <input
+ className="settings-large-input"
+ disabled={true}
+ id="test-email-subject"
+ onChange={[Function]}
+ type="text"
+ value="email_configuration.test.subject"
+ />
+ </div>
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="test-email-message"
+ >
+ email_configuration.test.message
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <textarea
+ className="settings-large-input"
+ disabled={true}
+ id="test-email-message"
+ onChange={[Function]}
+ required={true}
+ rows={5}
+ value="email_configuration.test.message_text"
+ />
+ </div>
+ <SubmitButton
+ disabled={true}
+ >
+ email_configuration.test.send
+ </SubmitButton>
+ <DeferredSpinner
+ className="spacer-left"
+ />
+ </form>
+</div>
+`;
+
+exports[`should render correctly: success 1`] = `
+<div
+ className="settings-definition"
+>
+ <div
+ className="settings-definition-left"
+ >
+ <h3
+ className="settings-definition-name"
+ >
+ email_configuration.test.title
+ </h3>
+ </div>
+ <form
+ className="settings-definition-right"
+ onSubmit={[Function]}
+ >
+ <div
+ className="form-field"
+ >
+ <Alert
+ variant="success"
+ >
+ email_configuration.test.email_was_sent_to_x.email@example.com
+ </Alert>
+ </div>
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="test-email-to"
+ >
+ email_configuration.test.to_address
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ className="settings-large-input"
+ disabled={false}
+ id="test-email-to"
+ onChange={[Function]}
+ required={true}
+ type="email"
+ value="luke@skywalker.biz"
/>
</div>
<div