Skip to content

Commit bc59b61

Browse files
committed
Fix. Remote Calls. Skip check if no sign of RC action provided in Request.
1 parent 4dbf269 commit bc59b61

File tree

2 files changed

+279
-4
lines changed

2 files changed

+279
-4
lines changed

lib/Cleantalk/ApbctWP/RemoteCalls.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ class RemoteCalls
3131
*/
3232
public static function check()
3333
{
34-
return Request::get('spbc_remote_call_token')
35-
? self::checkWithToken()
36-
: self::checkWithoutToken();
34+
//do not check token logic if no RC action sign found
35+
if ( Request::getString('spbc_remote_call_action') ) {
36+
return Request::getString('spbc_remote_call_token')
37+
? self::checkWithToken()
38+
: self::checkWithoutToken();
39+
}
40+
return false;
3741
}
3842

3943
public static function checkWithToken()
@@ -107,7 +111,7 @@ public static function perform()
107111
// Check Access key
108112
if (
109113
(self::checkToken($token)) ||
110-
(self::checkWithoutToken() && self::isAllowedWithoutToken($action))
114+
(self::isAllowedWithoutToken($action) && self::checkWithoutToken())
111115
) {
112116
// Flag to let plugin know that Remote Call is running.
113117
$apbct->rc_running = true;

tests/ApbctWP/TestRemoteCalls.php

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
<?php
2+
3+
use PHPUnit\Framework\TestCase;
4+
use Cleantalk\ApbctWP\RemoteCalls;
5+
6+
class TestRemoteCalls extends TestCase
7+
{
8+
private $apbct_backup;
9+
protected function setUp(): void
10+
{
11+
// Reset global after each test
12+
global $apbct;
13+
$this->apbct_backup = $apbct;
14+
$apbct = null;
15+
}
16+
17+
protected function tearDown(): void
18+
{
19+
// Reset global after each test
20+
global $apbct;
21+
$apbct = $this->apbct_backup;
22+
}
23+
24+
/** @test */
25+
public function checkReturnsFalseWhenNoActionProvided()
26+
{
27+
$_REQUEST = [];
28+
\Cleantalk\ApbctWP\Variables\Request::getInstance()->variables = $_REQUEST;
29+
$this->assertFalse(RemoteCalls::check());
30+
}
31+
32+
/** @test */
33+
public function checkCallsCheckWithTokenWhenTokenProvided()
34+
{
35+
$_REQUEST = [
36+
'spbc_remote_call_action' => 'antispam',
37+
'spbc_remote_call_token' => 'token',
38+
//any token is allowed on check() stage, containment will be checked on perform()
39+
'plugin_name' => 'antispam',
40+
];
41+
42+
\Cleantalk\ApbctWP\Variables\Request::getInstance()->variables = $_REQUEST;
43+
44+
// checkWithToken returns true
45+
$this->assertTrue(RemoteCalls::check());
46+
}
47+
48+
/** @test */
49+
public function checkCallsCheckWithoutTokenWhenNoTokenProvided()
50+
{
51+
global $apbct;
52+
53+
$_REQUEST = [
54+
'spbc_remote_call_action' => 'get_fresh_wpnonce', //allowed action
55+
'plugin_name' => 'antispam',
56+
];
57+
58+
\Cleantalk\ApbctWP\Variables\Request::getInstance()->variables = $_REQUEST;
59+
60+
$apbct = new stdClass();
61+
$apbct->key_is_ok = true;
62+
$apbct->api_key = null;
63+
$apbct->data = [];
64+
$apbct->data['moderate_ip'] = null;
65+
66+
// checkWithoutToken returns true
67+
$this->assertTrue(RemoteCalls::check());
68+
}
69+
70+
public function checkCallsCheckWithTokenWhenEmptyTokenProvided()
71+
{
72+
$_REQUEST = [
73+
'spbc_remote_call_action' => 'antispam',
74+
//any token is allowed on check() stage, containment will be checked on perform()
75+
'plugin_name' => 'antispam',
76+
];
77+
78+
\Cleantalk\ApbctWP\Variables\Request::getInstance()->variables = $_REQUEST;
79+
80+
// checkWithToken returns true
81+
$this->assertFalse(RemoteCalls::check());
82+
}
83+
84+
/** @test */
85+
public function checkCallsCheckWithoutTokenWhenActioNIsNotAllowed()
86+
{
87+
global $apbct;
88+
89+
$_REQUEST = [
90+
'spbc_remote_call_action' => 'debug', //rejected action
91+
'plugin_name' => 'antispam',
92+
];
93+
94+
\Cleantalk\ApbctWP\Variables\Request::getInstance()->variables = $_REQUEST;
95+
96+
$apbct = new stdClass();
97+
$apbct->key_is_ok = true;
98+
$apbct->api_key = null;
99+
$apbct->data = [];
100+
$apbct->data['moderate_ip'] = null;
101+
102+
// checkWithoutToken returns true
103+
$this->assertFalse(RemoteCalls::check());
104+
}
105+
106+
/** @test */
107+
public function itHidesSensitiveDataInFlatArray()
108+
{
109+
$input = [
110+
'apikey' => '1234567890',
111+
'user_token' => 'abcdef',
112+
'salt' => 'qwerty12345',
113+
'normal_key' => 'visible'
114+
];
115+
116+
$method = new ReflectionMethod(RemoteCalls::class, 'hideSensitiveData');
117+
$method->setAccessible(true);
118+
119+
$result = $method->invoke(null, $input);
120+
121+
$this->assertEquals('12******90', $result['apikey']);
122+
$this->assertEquals('ab**ef', $result['user_token']);
123+
$this->assertEquals('qw*******45', $result['salt']);
124+
$this->assertEquals('visible', $result['normal_key']);
125+
}
126+
127+
/** @test */
128+
public function itHidesSensitiveDataInNestedArray()
129+
{
130+
$input = [
131+
'level1' => [
132+
'level2' => [
133+
'apikey' => 'abcdefghij'
134+
]
135+
]
136+
];
137+
138+
$method = new ReflectionMethod(RemoteCalls::class, 'hideSensitiveData');
139+
$method->setAccessible(true);
140+
141+
$result = $method->invoke(null, $input);
142+
143+
$this->assertEquals(
144+
'ab******ij',
145+
$result['level1']['level2']['apikey']
146+
);
147+
}
148+
149+
/** @test */
150+
public function itMasksShortSensitiveValues()
151+
{
152+
$input = [
153+
'apikey' => '1234'
154+
];
155+
156+
$method = new ReflectionMethod(RemoteCalls::class, 'hideSensitiveData');
157+
$method->setAccessible(true);
158+
159+
$result = $method->invoke(null, $input);
160+
161+
$this->assertEquals('****', $result['apikey']);
162+
}
163+
164+
/** @test */
165+
public function itDoesNotModifyNonArrayInput()
166+
{
167+
$method = new ReflectionMethod(RemoteCalls::class, 'hideSensitiveData');
168+
$method->setAccessible(true);
169+
170+
$result = $method->invoke(null, 'string');
171+
172+
$this->assertEquals('string', $result);
173+
}
174+
175+
/** @test */
176+
public function itValidatesMd5Token()
177+
{
178+
global $apbct;
179+
180+
$apbct = new stdClass();
181+
$apbct->api_key = 'testKey';
182+
$apbct->data = [];
183+
184+
$validToken = strtolower(md5('testKey'));
185+
186+
$method = new ReflectionMethod(RemoteCalls::class, 'checkToken');
187+
$method->setAccessible(true);
188+
189+
$this->assertTrue($method->invoke(null, $validToken));
190+
}
191+
192+
/** @test */
193+
public function itValidatesSha256Token()
194+
{
195+
global $apbct;
196+
197+
$apbct = new stdClass();
198+
$apbct->api_key = 'testKey';
199+
$apbct->data = [];
200+
201+
$validToken = strtolower(hash('sha256', 'testKey'));
202+
203+
$method = new ReflectionMethod(RemoteCalls::class, 'checkToken');
204+
$method->setAccessible(true);
205+
206+
$this->assertTrue($method->invoke(null, $validToken));
207+
}
208+
209+
/** @test */
210+
public function itReturnsFalseForInvalidToken()
211+
{
212+
global $apbct;
213+
214+
$apbct = new stdClass();
215+
$apbct->api_key = 'testKey';
216+
$apbct->data = [];
217+
218+
$method = new ReflectionMethod(RemoteCalls::class, 'checkToken');
219+
$method->setAccessible(true);
220+
221+
$this->assertFalse($method->invoke(null, 'invalidToken'));
222+
}
223+
224+
/** @test */
225+
public function itReturnsFalseIfNoApiKeyProvided()
226+
{
227+
global $apbct;
228+
229+
$apbct = new stdClass();
230+
$apbct->api_key = null;
231+
$apbct->data = [];
232+
$apbct->data['moderate_ip'] = null;
233+
234+
$method = new ReflectionMethod(RemoteCalls::class, 'checkToken');
235+
$method->setAccessible(true);
236+
237+
$this->assertFalse($method->invoke(null, md5('anything')));
238+
}
239+
240+
/** @test */
241+
public function itMapsSettingTitlesCorrectly()
242+
{
243+
$settings = [
244+
'apikey' => '123',
245+
'forms__registrations_test' => 1,
246+
'unknown_key' => 'abc'
247+
];
248+
249+
$method = new ReflectionMethod(RemoteCalls::class, 'getSettings');
250+
$method->setAccessible(true);
251+
252+
$result = $method->invoke(null, $settings);
253+
254+
$this->assertArrayHasKey('apikey - Access key', $result);
255+
$this->assertArrayHasKey('forms__registrations_test - Registration Forms', $result);
256+
$this->assertEquals('123', $result['apikey - Access key']);
257+
$this->assertEquals(1, $result['forms__registrations_test - Registration Forms']);
258+
$this->assertEquals('abc', $result['unknown_key']);
259+
}
260+
261+
/** @test */
262+
public function itDetectsAllowedActionsWithoutToken()
263+
{
264+
$method = new ReflectionMethod(RemoteCalls::class, 'isAllowedWithoutToken');
265+
$method->setAccessible(true);
266+
267+
$this->assertTrue($method->invoke(null, 'get_fresh_wpnonce'));
268+
$this->assertTrue($method->invoke(null, 'post_api_key'));
269+
$this->assertFalse($method->invoke(null, 'update_license'));
270+
}
271+
}

0 commit comments

Comments
 (0)