Completed
Pull Request — master (#20)
by Robbie
02:24
created
src/Extension/CwpControllerExtension.php 2 patches
Indentation   +190 added lines, -190 removed lines patch added patch discarded remove patch
@@ -18,194 +18,194 @@
 block discarded – undo
18 18
 class CwpControllerExtension extends Extension implements PermissionProvider
19 19
 {
20 20
 
21
-    /**
22
-     * Enables SSL redirections - disabling not recommended as it will prevent forcing SSL on admin panel.
23
-     *
24
-     * @config
25
-     * @var bool
26
-     */
27
-    private static $ssl_redirection_enabled = true;
28
-
29
-    /**
30
-     * Specify a domain to redirect the vulnerable areas to.
31
-     *
32
-     * If left as null, live instance will set this to <instance-id>.cwp.govt.nz via CWP_SECURE_DOMAIN in _config.php.
33
-     * This allows us to automatically protect vulnerable areas on live even if the frontend cert is not installed.
34
-     *
35
-     * Set to false to redirect to https protocol on current domain (e.g. if you have frontend cert).
36
-     *
37
-     * Set to a domain string (e.g. 'example.com') to force that domain.
38
-     *
39
-     * @config
40
-     * @var string
41
-     */
42
-    private static $ssl_redirection_force_domain = null;
43
-
44
-    /**
45
-     * Enables the BasicAuth protection on all test environments. Disable with caution - it will open up
46
-     * all your UAT and test environments to the world.
47
-     *
48
-     * @config
49
-     * @var bool
50
-     */
51
-    private static $test_basicauth_enabled = true;
52
-
53
-    /**
54
-     * Enables the BasicAuth protection on all live environments.
55
-     * Useful for securing sites prior to public launch.
56
-     *
57
-     * @config
58
-     * @var bool
59
-     */
60
-    private static $live_basicauth_enabled = false;
61
-
62
-    /**
63
-     * This executes the passed callback with subsite filter disabled,
64
-     * then enabled the filter again before returning the callback result
65
-     * (or throwing the exception the callback raised)
66
-     *
67
-     * @param  callback  $callback - The callback to execute
68
-     * @return mixed     The result of the callback
69
-     * @throws Exception Any exception the callback raised
70
-     */
71
-    protected function callWithSubsitesDisabled($callback)
72
-    {
73
-        $rv = null;
74
-
75
-        try {
76
-            if (class_exists(Subsite::class)) {
77
-                Subsite::disable_subsite_filter(true);
78
-            }
79
-
80
-            $rv = call_user_func($callback);
81
-        } catch (Exception $e) {
82
-            if (class_exists(Subsite::class)) {
83
-                Subsite::disable_subsite_filter(false);
84
-            }
85
-
86
-            throw $e;
87
-        }
88
-
89
-        if (class_exists(Subsite::class)) {
90
-            Subsite::disable_subsite_filter(false);
91
-        }
92
-
93
-        return $rv;
94
-    }
95
-
96
-    /**
97
-     * Trigger Basic Auth protection, except when there's a reason to bypass it
98
-     *  - The source IP address is in the comma-seperated string in the constant CWP_IP_BYPASS_BASICAUTH
99
-     *    (so Pingdom, etc, can access the site)
100
-     *  - There is an identifiable member, that member has the ACCESS_UAT_SERVER permission, and they're trying
101
-     *    to access a white-list of URLs (so people following a reset password link can reset their password)
102
-     */
103
-    protected function triggerBasicAuthProtection()
104
-    {
105
-        $allowWithoutAuth = false;
106
-
107
-        // Allow whitelisting IPs for bypassing the basic auth.
108
-        if (Environment::getEnv('CWP_IP_BYPASS_BASICAUTH')) {
109
-            $remote = $_SERVER['REMOTE_ADDR'];
110
-            $bypass = explode(',', Environment::getEnv('CWP_IP_BYPASS_BASICAUTH'));
111
-
112
-            if (in_array($remote, $bypass)) {
113
-                $allowWithoutAuth = true;
114
-            }
115
-        }
116
-
117
-        // First, see if we can get a member to act on, either from a changepassword token or the session
118
-        if (isset($_REQUEST['m']) && isset($_REQUEST['t'])) {
119
-            $member = Member::get()->filter('ID', (int) $_REQUEST['m'])->first();
120
-
121
-            if (!$member->validateAutoLoginToken($_REQUEST['t'])) {
122
-                $member = null;
123
-            }
124
-        } elseif ($this->owner->getRequest()->getSession()->get('AutoLoginHash')) {
125
-            $member = Member::member_from_autologinhash(
126
-                $this->owner->getRequest()->getSession()->get('AutoLoginHash')
127
-            );
128
-        } else {
129
-            $member = Security::getCurrentUser();
130
-        }
131
-
132
-        // Then, if they have the right permissions, check the allowed URLs
133
-        $existingMemberCanAccessUAT = $member && $this->callWithSubsitesDisabled(function () use ($member) {
134
-            return Permission::checkMember($member, 'ACCESS_UAT_SERVER');
135
-        });
136
-
137
-        if ($existingMemberCanAccessUAT) {
138
-            $allowed = array(
139
-                '/^Security\/changepassword/',
140
-                '/^Security\/ChangePasswordForm/'
141
-            );
142
-
143
-            $relativeURL = Director::makeRelative(Director::absoluteURL($_SERVER['REQUEST_URI']));
144
-
145
-            foreach ($allowed as $pattern) {
146
-                $allowWithoutAuth = $allowWithoutAuth || preg_match($pattern, $relativeURL);
147
-            }
148
-        }
149
-
150
-        // Finally if they weren't allowed to bypass Basic Auth, trigger it
151
-        if (!$allowWithoutAuth) {
152
-            $this->callWithSubsitesDisabled(function () {
153
-                BasicAuth::requireLogin(
154
-                    $this->owner->getRequest(),
155
-                    _t(__CLASS__ . '.LoginPrompt', "Please log in with your CMS credentials"),
156
-                    'ACCESS_UAT_SERVER',
157
-                    true
158
-                );
159
-            });
160
-        }
161
-    }
162
-
163
-    /**
164
-     * @return void
165
-     */
166
-    public function onBeforeInit()
167
-    {
168
-        // Grab global injectable service to allow testing.
169
-        $director = Injector::inst()->get(Director::class);
170
-
171
-        if (Config::inst()->get(__CLASS__, 'ssl_redirection_enabled')) {
172
-            // redirect some vulnerable areas to the secure domain
173
-            if (!$director::is_https()) {
174
-                $forceDomain = Config::inst()->get(__CLASS__, 'ssl_redirection_force_domain');
175
-
176
-                if ($forceDomain) {
177
-                    $director::forceSSL(['/^Security/', '/^api/'], $forceDomain);
178
-                } else {
179
-                    $director::forceSSL(['/^Security/', '/^api/']);
180
-                }
181
-            }
182
-        }
183
-
184
-        if (Config::inst()->get(__CLASS__, 'test_basicauth_enabled')) {
185
-            // Turn on Basic Auth in testing mode
186
-            if ($director::isTest()) {
187
-                $this->triggerBasicAuthProtection();
188
-            }
189
-        }
190
-
191
-        if (Config::inst()->get(__CLASS__, 'live_basicauth_enabled')) {
192
-            // Turn on Basic Auth in live mode
193
-            if ($director::isLive()) {
194
-                $this->triggerBasicAuthProtection();
195
-            }
196
-        }
197
-    }
198
-
199
-    /**
200
-     * @return array
201
-     */
202
-    public function providePermissions()
203
-    {
204
-        return [
205
-            'ACCESS_UAT_SERVER' => _t(
206
-                __CLASS__ . '.UatServerPermission',
207
-                'Allow users to use their accounts to access the UAT server'
208
-            )
209
-        ];
210
-    }
21
+	/**
22
+	 * Enables SSL redirections - disabling not recommended as it will prevent forcing SSL on admin panel.
23
+	 *
24
+	 * @config
25
+	 * @var bool
26
+	 */
27
+	private static $ssl_redirection_enabled = true;
28
+
29
+	/**
30
+	 * Specify a domain to redirect the vulnerable areas to.
31
+	 *
32
+	 * If left as null, live instance will set this to <instance-id>.cwp.govt.nz via CWP_SECURE_DOMAIN in _config.php.
33
+	 * This allows us to automatically protect vulnerable areas on live even if the frontend cert is not installed.
34
+	 *
35
+	 * Set to false to redirect to https protocol on current domain (e.g. if you have frontend cert).
36
+	 *
37
+	 * Set to a domain string (e.g. 'example.com') to force that domain.
38
+	 *
39
+	 * @config
40
+	 * @var string
41
+	 */
42
+	private static $ssl_redirection_force_domain = null;
43
+
44
+	/**
45
+	 * Enables the BasicAuth protection on all test environments. Disable with caution - it will open up
46
+	 * all your UAT and test environments to the world.
47
+	 *
48
+	 * @config
49
+	 * @var bool
50
+	 */
51
+	private static $test_basicauth_enabled = true;
52
+
53
+	/**
54
+	 * Enables the BasicAuth protection on all live environments.
55
+	 * Useful for securing sites prior to public launch.
56
+	 *
57
+	 * @config
58
+	 * @var bool
59
+	 */
60
+	private static $live_basicauth_enabled = false;
61
+
62
+	/**
63
+	 * This executes the passed callback with subsite filter disabled,
64
+	 * then enabled the filter again before returning the callback result
65
+	 * (or throwing the exception the callback raised)
66
+	 *
67
+	 * @param  callback  $callback - The callback to execute
68
+	 * @return mixed     The result of the callback
69
+	 * @throws Exception Any exception the callback raised
70
+	 */
71
+	protected function callWithSubsitesDisabled($callback)
72
+	{
73
+		$rv = null;
74
+
75
+		try {
76
+			if (class_exists(Subsite::class)) {
77
+				Subsite::disable_subsite_filter(true);
78
+			}
79
+
80
+			$rv = call_user_func($callback);
81
+		} catch (Exception $e) {
82
+			if (class_exists(Subsite::class)) {
83
+				Subsite::disable_subsite_filter(false);
84
+			}
85
+
86
+			throw $e;
87
+		}
88
+
89
+		if (class_exists(Subsite::class)) {
90
+			Subsite::disable_subsite_filter(false);
91
+		}
92
+
93
+		return $rv;
94
+	}
95
+
96
+	/**
97
+	 * Trigger Basic Auth protection, except when there's a reason to bypass it
98
+	 *  - The source IP address is in the comma-seperated string in the constant CWP_IP_BYPASS_BASICAUTH
99
+	 *    (so Pingdom, etc, can access the site)
100
+	 *  - There is an identifiable member, that member has the ACCESS_UAT_SERVER permission, and they're trying
101
+	 *    to access a white-list of URLs (so people following a reset password link can reset their password)
102
+	 */
103
+	protected function triggerBasicAuthProtection()
104
+	{
105
+		$allowWithoutAuth = false;
106
+
107
+		// Allow whitelisting IPs for bypassing the basic auth.
108
+		if (Environment::getEnv('CWP_IP_BYPASS_BASICAUTH')) {
109
+			$remote = $_SERVER['REMOTE_ADDR'];
110
+			$bypass = explode(',', Environment::getEnv('CWP_IP_BYPASS_BASICAUTH'));
111
+
112
+			if (in_array($remote, $bypass)) {
113
+				$allowWithoutAuth = true;
114
+			}
115
+		}
116
+
117
+		// First, see if we can get a member to act on, either from a changepassword token or the session
118
+		if (isset($_REQUEST['m']) && isset($_REQUEST['t'])) {
119
+			$member = Member::get()->filter('ID', (int) $_REQUEST['m'])->first();
120
+
121
+			if (!$member->validateAutoLoginToken($_REQUEST['t'])) {
122
+				$member = null;
123
+			}
124
+		} elseif ($this->owner->getRequest()->getSession()->get('AutoLoginHash')) {
125
+			$member = Member::member_from_autologinhash(
126
+				$this->owner->getRequest()->getSession()->get('AutoLoginHash')
127
+			);
128
+		} else {
129
+			$member = Security::getCurrentUser();
130
+		}
131
+
132
+		// Then, if they have the right permissions, check the allowed URLs
133
+		$existingMemberCanAccessUAT = $member && $this->callWithSubsitesDisabled(function () use ($member) {
134
+			return Permission::checkMember($member, 'ACCESS_UAT_SERVER');
135
+		});
136
+
137
+		if ($existingMemberCanAccessUAT) {
138
+			$allowed = array(
139
+				'/^Security\/changepassword/',
140
+				'/^Security\/ChangePasswordForm/'
141
+			);
142
+
143
+			$relativeURL = Director::makeRelative(Director::absoluteURL($_SERVER['REQUEST_URI']));
144
+
145
+			foreach ($allowed as $pattern) {
146
+				$allowWithoutAuth = $allowWithoutAuth || preg_match($pattern, $relativeURL);
147
+			}
148
+		}
149
+
150
+		// Finally if they weren't allowed to bypass Basic Auth, trigger it
151
+		if (!$allowWithoutAuth) {
152
+			$this->callWithSubsitesDisabled(function () {
153
+				BasicAuth::requireLogin(
154
+					$this->owner->getRequest(),
155
+					_t(__CLASS__ . '.LoginPrompt', "Please log in with your CMS credentials"),
156
+					'ACCESS_UAT_SERVER',
157
+					true
158
+				);
159
+			});
160
+		}
161
+	}
162
+
163
+	/**
164
+	 * @return void
165
+	 */
166
+	public function onBeforeInit()
167
+	{
168
+		// Grab global injectable service to allow testing.
169
+		$director = Injector::inst()->get(Director::class);
170
+
171
+		if (Config::inst()->get(__CLASS__, 'ssl_redirection_enabled')) {
172
+			// redirect some vulnerable areas to the secure domain
173
+			if (!$director::is_https()) {
174
+				$forceDomain = Config::inst()->get(__CLASS__, 'ssl_redirection_force_domain');
175
+
176
+				if ($forceDomain) {
177
+					$director::forceSSL(['/^Security/', '/^api/'], $forceDomain);
178
+				} else {
179
+					$director::forceSSL(['/^Security/', '/^api/']);
180
+				}
181
+			}
182
+		}
183
+
184
+		if (Config::inst()->get(__CLASS__, 'test_basicauth_enabled')) {
185
+			// Turn on Basic Auth in testing mode
186
+			if ($director::isTest()) {
187
+				$this->triggerBasicAuthProtection();
188
+			}
189
+		}
190
+
191
+		if (Config::inst()->get(__CLASS__, 'live_basicauth_enabled')) {
192
+			// Turn on Basic Auth in live mode
193
+			if ($director::isLive()) {
194
+				$this->triggerBasicAuthProtection();
195
+			}
196
+		}
197
+	}
198
+
199
+	/**
200
+	 * @return array
201
+	 */
202
+	public function providePermissions()
203
+	{
204
+		return [
205
+			'ACCESS_UAT_SERVER' => _t(
206
+				__CLASS__ . '.UatServerPermission',
207
+				'Allow users to use their accounts to access the UAT server'
208
+			)
209
+		];
210
+	}
211 211
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -116,7 +116,7 @@  discard block
 block discarded – undo
116 116
 
117 117
         // First, see if we can get a member to act on, either from a changepassword token or the session
118 118
         if (isset($_REQUEST['m']) && isset($_REQUEST['t'])) {
119
-            $member = Member::get()->filter('ID', (int) $_REQUEST['m'])->first();
119
+            $member = Member::get()->filter('ID', (int)$_REQUEST['m'])->first();
120 120
 
121 121
             if (!$member->validateAutoLoginToken($_REQUEST['t'])) {
122 122
                 $member = null;
@@ -130,7 +130,7 @@  discard block
 block discarded – undo
130 130
         }
131 131
 
132 132
         // Then, if they have the right permissions, check the allowed URLs
133
-        $existingMemberCanAccessUAT = $member && $this->callWithSubsitesDisabled(function () use ($member) {
133
+        $existingMemberCanAccessUAT = $member && $this->callWithSubsitesDisabled(function() use ($member) {
134 134
             return Permission::checkMember($member, 'ACCESS_UAT_SERVER');
135 135
         });
136 136
 
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
 
150 150
         // Finally if they weren't allowed to bypass Basic Auth, trigger it
151 151
         if (!$allowWithoutAuth) {
152
-            $this->callWithSubsitesDisabled(function () {
152
+            $this->callWithSubsitesDisabled(function() {
153 153
                 BasicAuth::requireLogin(
154 154
                     $this->owner->getRequest(),
155 155
                     _t(__CLASS__ . '.LoginPrompt', "Please log in with your CMS credentials"),
Please login to merge, or discard this patch.
src/Extension/CwpHtmlEditorConfig.php 1 patch
Indentation   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -7,20 +7,20 @@
 block discarded – undo
7 7
 class CwpHtmlEditorConfig extends DataExtension
8 8
 {
9 9
 
10
-    /**
11
-     * @return string
12
-     *
13
-     * Override the default HtmlEditorConfig from 'cms' to 'cwp' defined in cwp-core/_config.php
14
-     * However if the group has a custom editor configuration set, use that instead.
15
-     */
16
-    public function getHtmlEditorConfig()
17
-    {
18
-        $originalConfig = $this->owner->getField("HtmlEditorConfig");
10
+	/**
11
+	 * @return string
12
+	 *
13
+	 * Override the default HtmlEditorConfig from 'cms' to 'cwp' defined in cwp-core/_config.php
14
+	 * However if the group has a custom editor configuration set, use that instead.
15
+	 */
16
+	public function getHtmlEditorConfig()
17
+	{
18
+		$originalConfig = $this->owner->getField("HtmlEditorConfig");
19 19
 
20
-        if ($originalConfig) {
21
-            return $originalConfig;
22
-        }
20
+		if ($originalConfig) {
21
+			return $originalConfig;
22
+		}
23 23
 
24
-        return 'cwp';
25
-    }
24
+		return 'cwp';
25
+	}
26 26
 }
Please login to merge, or discard this patch.
src/Extension/LoginAttemptNotifications.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -53,12 +53,12 @@  discard block
 block discarded – undo
53 53
                 $failures = $meantimeLoginAttempts->filter(['Status' => 'Failure'])->count();
54 54
                 $IPs = array_unique($meantimeLoginAttempts->column('IP'));
55 55
 
56
-                if ($attempts == 1) {
56
+                if ($attempts==1) {
57 57
                     $statusString = $failures ? "a failed" : "a successful";
58 58
                     $message = "In the last $elapsed $statusString login attempt to your account was "
59 59
                         . "registered. The attempt was made from ${IPs[0]}. ";
60 60
                 } else {
61
-                    if ($failures == $attempts) {
61
+                    if ($failures==$attempts) {
62 62
                         $statusString = $failures ? "failed" : "successful";
63 63
                         $message = "In the last $elapsed $attempts $statusString login "
64 64
                             . "attempts to your account were registered. ";
@@ -85,7 +85,7 @@  discard block
 block discarded – undo
85 85
                 $date = $lastLoginAttempt->Created;
86 86
                 $message = "Last login attempt to your account was on $lastLoginAttempt->Created "
87 87
                     . "from $lastLoginAttempt->IP";
88
-                $message .= $lastLoginAttempt->Status == 'Failure' ? " and was successful." : "and has failed.";
88
+                $message .= $lastLoginAttempt->Status=='Failure' ? " and was successful." : "and has failed.";
89 89
             }
90 90
         }
91 91
 
Please login to merge, or discard this patch.
Indentation   +66 added lines, -66 removed lines patch added patch discarded remove patch
@@ -19,81 +19,81 @@
 block discarded – undo
19 19
 class LoginAttemptNotifications extends Extension
20 20
 {
21 21
 
22
-    /**
23
-     *
24
-     * @return mixed null
25
-     */
26
-    public function init()
27
-    {
22
+	/**
23
+	 *
24
+	 * @return mixed null
25
+	 */
26
+	public function init()
27
+	{
28 28
 
29
-        // Exclude default admin.
30
-        $member = Security::getCurrentUser();
31
-        if (!$member || !$member->ID) {
32
-            return;
33
-        }
29
+		// Exclude default admin.
30
+		$member = Security::getCurrentUser();
31
+		if (!$member || !$member->ID) {
32
+			return;
33
+		}
34 34
 
35
-        $message = null;
36
-        $session = $this->owner->getRequest()->getSession();
35
+		$message = null;
36
+		$session = $this->owner->getRequest()->getSession();
37 37
 
38
-        Requirements::javascript('cwp/cwp-core:javascript/LoginAttemptNotifications.js');
39
-        $sessionLastVisited = $session->get('LoginAttemptNotifications.SessionLastVisited');
40
-        if ($sessionLastVisited) {
41
-            // Session already in progress. Show all attempts since the session was last visited.
38
+		Requirements::javascript('cwp/cwp-core:javascript/LoginAttemptNotifications.js');
39
+		$sessionLastVisited = $session->get('LoginAttemptNotifications.SessionLastVisited');
40
+		if ($sessionLastVisited) {
41
+			// Session already in progress. Show all attempts since the session was last visited.
42 42
 
43
-            $meantimeLoginAttempts = LoginAttempt::get()->filter([
44
-                'MemberID' => $member->ID,
45
-                'Created:GreaterThan' => $sessionLastVisited
46
-            ]);
43
+			$meantimeLoginAttempts = LoginAttempt::get()->filter([
44
+				'MemberID' => $member->ID,
45
+				'Created:GreaterThan' => $sessionLastVisited
46
+			]);
47 47
 
48
-            $attempts = $meantimeLoginAttempts->count();
49
-            if ($attempts) {
50
-                $lastVisitedObj = DBDatetime::create();
51
-                $lastVisitedObj->setValue($sessionLastVisited);
52
-                $elapsed = $lastVisitedObj->TimeDiff();
53
-                $failures = $meantimeLoginAttempts->filter(['Status' => 'Failure'])->count();
54
-                $IPs = array_unique($meantimeLoginAttempts->column('IP'));
48
+			$attempts = $meantimeLoginAttempts->count();
49
+			if ($attempts) {
50
+				$lastVisitedObj = DBDatetime::create();
51
+				$lastVisitedObj->setValue($sessionLastVisited);
52
+				$elapsed = $lastVisitedObj->TimeDiff();
53
+				$failures = $meantimeLoginAttempts->filter(['Status' => 'Failure'])->count();
54
+				$IPs = array_unique($meantimeLoginAttempts->column('IP'));
55 55
 
56
-                if ($attempts == 1) {
57
-                    $statusString = $failures ? "a failed" : "a successful";
58
-                    $message = "In the last $elapsed $statusString login attempt to your account was "
59
-                        . "registered. The attempt was made from ${IPs[0]}. ";
60
-                } else {
61
-                    if ($failures == $attempts) {
62
-                        $statusString = $failures ? "failed" : "successful";
63
-                        $message = "In the last $elapsed $attempts $statusString login "
64
-                            . "attempts to your account were registered. ";
65
-                    } else {
66
-                        $message = "In the last $elapsed $attempts login attempts to your "
67
-                            . "account were registered, of which $failures failed. ";
68
-                    }
56
+				if ($attempts == 1) {
57
+					$statusString = $failures ? "a failed" : "a successful";
58
+					$message = "In the last $elapsed $statusString login attempt to your account was "
59
+						. "registered. The attempt was made from ${IPs[0]}. ";
60
+				} else {
61
+					if ($failures == $attempts) {
62
+						$statusString = $failures ? "failed" : "successful";
63
+						$message = "In the last $elapsed $attempts $statusString login "
64
+							. "attempts to your account were registered. ";
65
+					} else {
66
+						$message = "In the last $elapsed $attempts login attempts to your "
67
+							. "account were registered, of which $failures failed. ";
68
+					}
69 69
 
70
-                    $message .= "The attempts were from " . implode(', ', $IPs) . '. ';
70
+					$message .= "The attempts were from " . implode(', ', $IPs) . '. ';
71 71
 
72
-                    // TODO: add this call to action in a way that doesn't break out of the availabel space. Fix CSS?
73
-                    // $message .= "If you suspect somebody else might be trying to access
74
-                    //  . "your account, please contact support.";
75
-                }
76
-            }
77
-        } else {
78
-            // New session - show last login attempt.
79
-            // TODO: this currently does NOT surface to the frontend in any way.
80
-            $lastLoginAttempt = LoginAttempt::get()->filter([
81
-                        'MemberID' => $member->ID
82
-            ])->sort('Created DESC')->First();
72
+					// TODO: add this call to action in a way that doesn't break out of the availabel space. Fix CSS?
73
+					// $message .= "If you suspect somebody else might be trying to access
74
+					//  . "your account, please contact support.";
75
+				}
76
+			}
77
+		} else {
78
+			// New session - show last login attempt.
79
+			// TODO: this currently does NOT surface to the frontend in any way.
80
+			$lastLoginAttempt = LoginAttempt::get()->filter([
81
+						'MemberID' => $member->ID
82
+			])->sort('Created DESC')->First();
83 83
 
84
-            if ($lastLoginAttempt) {
85
-                $date = $lastLoginAttempt->Created;
86
-                $message = "Last login attempt to your account was on $lastLoginAttempt->Created "
87
-                    . "from $lastLoginAttempt->IP";
88
-                $message .= $lastLoginAttempt->Status == 'Failure' ? " and was successful." : "and has failed.";
89
-            }
90
-        }
84
+			if ($lastLoginAttempt) {
85
+				$date = $lastLoginAttempt->Created;
86
+				$message = "Last login attempt to your account was on $lastLoginAttempt->Created "
87
+					. "from $lastLoginAttempt->IP";
88
+				$message .= $lastLoginAttempt->Status == 'Failure' ? " and was successful." : "and has failed.";
89
+			}
90
+		}
91 91
 
92
-        $session->set(
93
-            'LoginAttemptNotifications.SessionLastVisited',
94
-            DBDatetime::now()->Format(DBDatetime::ISO_DATETIME)
95
-        );
92
+		$session->set(
93
+			'LoginAttemptNotifications.SessionLastVisited',
94
+			DBDatetime::now()->Format(DBDatetime::ISO_DATETIME)
95
+		);
96 96
 
97
-        $this->owner->getResponse()->addHeader('X-LoginAttemptNotifications', $message);
98
-    }
97
+		$this->owner->getResponse()->addHeader('X-LoginAttemptNotifications', $message);
98
+	}
99 99
 }
Please login to merge, or discard this patch.
src/Feed/CwpAtomFeed.php 1 patch
Indentation   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -18,57 +18,57 @@
 block discarded – undo
18 18
 
19 19
 class CwpAtomFeed extends RSSFeed
20 20
 {
21
-    public function __construct(
22
-        SS_List $entries,
23
-        $link,
24
-        $title,
25
-        $description = null,
26
-        $titleField = "Title",
27
-        $descriptionField = "Content",
28
-        $authorField = null,
29
-        $lastModified = null,
30
-        $etag = null
31
-    ) {
32
-        parent::__construct(
33
-            $entries,
34
-            $link,
35
-            $title,
36
-            $description,
37
-            $titleField,
38
-            $descriptionField,
39
-            $authorField,
40
-            $lastModified
41
-        );
21
+	public function __construct(
22
+		SS_List $entries,
23
+		$link,
24
+		$title,
25
+		$description = null,
26
+		$titleField = "Title",
27
+		$descriptionField = "Content",
28
+		$authorField = null,
29
+		$lastModified = null,
30
+		$etag = null
31
+	) {
32
+		parent::__construct(
33
+			$entries,
34
+			$link,
35
+			$title,
36
+			$description,
37
+			$titleField,
38
+			$descriptionField,
39
+			$authorField,
40
+			$lastModified
41
+		);
42 42
 
43
-        $this->setTemplate(__CLASS__);
44
-    }
43
+		$this->setTemplate(__CLASS__);
44
+	}
45 45
 
46
-    /**
47
-     * Include an link to the feed
48
-     *
49
-     * @param string $url URL of the feed
50
-     * @param string $title Title to show
51
-     */
52
-    public static function linkToFeed($url, $title = null)
53
-    {
54
-        $title = Convert::raw2xml($title);
55
-        Requirements::insertHeadTags(
56
-            '<link rel="alternate" type="application/atom+xml" title="' . $title .
57
-            '" href="' . $url . '" />'
58
-        );
59
-    }
46
+	/**
47
+	 * Include an link to the feed
48
+	 *
49
+	 * @param string $url URL of the feed
50
+	 * @param string $title Title to show
51
+	 */
52
+	public static function linkToFeed($url, $title = null)
53
+	{
54
+		$title = Convert::raw2xml($title);
55
+		Requirements::insertHeadTags(
56
+			'<link rel="alternate" type="application/atom+xml" title="' . $title .
57
+			'" href="' . $url . '" />'
58
+		);
59
+	}
60 60
 
61
-    /**
62
-     * Output the feed to the browser
63
-     *
64
-     * @return DBHTMLText
65
-     */
66
-    public function outputToBrowser()
67
-    {
68
-        $output = parent::outputToBrowser();
69
-        $response = Controller::curr()->getResponse();
70
-        $response->addHeader("Content-Type", "application/atom+xml");
61
+	/**
62
+	 * Output the feed to the browser
63
+	 *
64
+	 * @return DBHTMLText
65
+	 */
66
+	public function outputToBrowser()
67
+	{
68
+		$output = parent::outputToBrowser();
69
+		$response = Controller::curr()->getResponse();
70
+		$response->addHeader("Content-Type", "application/atom+xml");
71 71
 
72
-        return $output;
73
-    }
72
+		return $output;
73
+	}
74 74
 }
Please login to merge, or discard this patch.
src/Extension/RichLinksExtension.php 1 patch
Indentation   +44 added lines, -44 removed lines patch added patch discarded remove patch
@@ -16,48 +16,48 @@
 block discarded – undo
16 16
 class RichLinksExtension extends Extension
17 17
 {
18 18
 
19
-    /**
20
-     * @var array
21
-     */
22
-    private static $casting = [
23
-        'RichLinks' => 'HTMLText'
24
-    ];
25
-
26
-    /**
27
-     * @return string
28
-     */
29
-    public function RichLinks()
30
-    {
31
-        // Note:
32
-        // Assume we can use Regexes because the link will always be formatted
33
-        // in the same way coming from the CMS.
34
-
35
-        $content = $this->owner->value;
36
-
37
-        // Find all file links for processing.
38
-        preg_match_all('/<a.*href="\[file_link,id=([0-9]+)\].*".*>.*<\/a>/U', $content, $matches);
39
-
40
-        // Attach the file type and size to each of the links.
41
-        for ($i = 0; $i < count($matches[0]); $i++) {
42
-            $file = DataObject::get_by_id('File', $matches[1][$i]);
43
-            if ($file) {
44
-                $size = $file->getSize();
45
-                $ext = strtoupper($file->getExtension());
46
-                // Replace the closing </a> tag with the size span (and reattach the closing tag).
47
-                $newLink = substr($matches[0][$i], 0, strlen($matches[0][$i]) - 4)
48
-                    . "<span class='fileExt'> [$ext, $size]</span></a>";
49
-                $content = str_replace($matches[0][$i], $newLink, $content);
50
-            }
51
-        }
52
-
53
-        // Inject extra attributes into the external links.
54
-        $pattern = '/(<a.*)(href=\"https?:\/\/[^\"]*\"[^>]*>.*)(<\/a>)/iU';
55
-        $replacement = sprintf(
56
-            '$1class="external" rel="external" title="%s" $2<span class="nonvisual-indicator">(external link)</span>$3',
57
-            _t(__CLASS__ . '.OpenLinkTitle', 'Open external link')
58
-        );
59
-        $content = preg_replace($pattern, $replacement, $content, -1);
60
-
61
-        return $content;
62
-    }
19
+	/**
20
+	 * @var array
21
+	 */
22
+	private static $casting = [
23
+		'RichLinks' => 'HTMLText'
24
+	];
25
+
26
+	/**
27
+	 * @return string
28
+	 */
29
+	public function RichLinks()
30
+	{
31
+		// Note:
32
+		// Assume we can use Regexes because the link will always be formatted
33
+		// in the same way coming from the CMS.
34
+
35
+		$content = $this->owner->value;
36
+
37
+		// Find all file links for processing.
38
+		preg_match_all('/<a.*href="\[file_link,id=([0-9]+)\].*".*>.*<\/a>/U', $content, $matches);
39
+
40
+		// Attach the file type and size to each of the links.
41
+		for ($i = 0; $i < count($matches[0]); $i++) {
42
+			$file = DataObject::get_by_id('File', $matches[1][$i]);
43
+			if ($file) {
44
+				$size = $file->getSize();
45
+				$ext = strtoupper($file->getExtension());
46
+				// Replace the closing </a> tag with the size span (and reattach the closing tag).
47
+				$newLink = substr($matches[0][$i], 0, strlen($matches[0][$i]) - 4)
48
+					. "<span class='fileExt'> [$ext, $size]</span></a>";
49
+				$content = str_replace($matches[0][$i], $newLink, $content);
50
+			}
51
+		}
52
+
53
+		// Inject extra attributes into the external links.
54
+		$pattern = '/(<a.*)(href=\"https?:\/\/[^\"]*\"[^>]*>.*)(<\/a>)/iU';
55
+		$replacement = sprintf(
56
+			'$1class="external" rel="external" title="%s" $2<span class="nonvisual-indicator">(external link)</span>$3',
57
+			_t(__CLASS__ . '.OpenLinkTitle', 'Open external link')
58
+		);
59
+		$content = preg_replace($pattern, $replacement, $content, -1);
60
+
61
+		return $content;
62
+	}
63 63
 }
Please login to merge, or discard this patch.