Skip to content

Commit 6fa04fd

Browse files
update
1 parent 9de70cb commit 6fa04fd

File tree

6 files changed

+155
-15
lines changed

6 files changed

+155
-15
lines changed

web/app/Http/Controllers/Api/HostingSubscriptionsController.php

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Http\Controllers\Api;
44

5+
use App\Http\Controllers\Api\Request\HostingSubscriptionCreateRequest;
56
use App\Http\Controllers\ApiController;
67
use App\Models\Domain;
78
use App\Models\HostingSubscription;
@@ -24,21 +25,17 @@ public function index()
2425

2526
}
2627

27-
public function store(Request $request)
28+
public function store(HostingSubscriptionCreateRequest $request)
2829
{
29-
$request->validate([
30-
'customer_id' => 'required',
31-
'hosting_plan_id' => 'required',
32-
'domain' => 'required',
33-
]);
34-
3530
$hostingSubscription = new HostingSubscription();
3631
$hostingSubscription->customer_id = $request->customer_id;
3732
$hostingSubscription->hosting_plan_id = $request->hosting_plan_id;
3833
$hostingSubscription->domain = $request->domain;
34+
3935
// $hostingSubscription->username = $request->username;
4036
// $hostingSubscription->password = $request->password;
4137
// $hostingSubscription->description = $request->description;
38+
4239
$hostingSubscription->setup_date = Carbon::now();
4340
$hostingSubscription->save();
4441

web/app/Http/Controllers/Api/Request/CustomerCreateRequest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class CustomerCreateRequest extends AuthorizedApiRequest
1212
public function rules()
1313
{
1414
return [
15-
'name' => 'required',
15+
'name' => 'required|max:255',
1616
'email' => 'required|email|unique:customers,email',
1717
];
1818
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Api\Request;
4+
5+
class HostingSubscriptionCreateRequest extends AuthorizedApiRequest
6+
{
7+
/**
8+
* Get the validation rules that apply to the request.
9+
*
10+
* @return array
11+
*/
12+
public function rules()
13+
{
14+
return [
15+
'customer_id' => 'required|exists:customers,id',
16+
'hosting_plan_id' => 'required|exists:hosting_plans,id',
17+
'domain' => 'required|regex:/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i',
18+
];
19+
}
20+
}

web/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"zircote/swagger-php": "^4.8"
3434
},
3535
"require-dev": {
36-
"fakerphp/faker": "^1.9.1",
36+
"fakerphp/faker": "^1.23",
3737
"laravel/dusk": "^8.2",
3838
"laravel/pint": "^1.15",
3939
"laravel/sail": "^1.18",

web/composer.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/tests/Unit/SecurityTest.php

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
namespace tests\Unit;
4+
5+
use Faker\Factory;
6+
use Tests\Feature\Api\ActionTestCase;
7+
8+
class SecurityTest extends ActionTestCase
9+
{
10+
public function testSecurity()
11+
{
12+
$callHostingSubscriptionStoreResponse = $this->callApiAuthorizedRouteAction(
13+
'api.hosting-subscriptions.store',
14+
[
15+
'customer_id' => '34232432',
16+
'hosting_plan_id'=> '4443232',
17+
'domain' => 'broken-domain-name',
18+
]
19+
)->json();
20+
21+
$this->assertArrayHasKey('error', $callHostingSubscriptionStoreResponse);
22+
$this->assertArrayHasKey('message', $callHostingSubscriptionStoreResponse);
23+
$this->assertArrayHasKey('data', $callHostingSubscriptionStoreResponse);
24+
$this->assertArrayHasKey('domain', $callHostingSubscriptionStoreResponse['data']);
25+
$this->assertSame('The selected customer id is invalid.', $callHostingSubscriptionStoreResponse['message']);
26+
27+
$this->assertSame('The selected hosting plan id is invalid.', $callHostingSubscriptionStoreResponse['data']['hosting_plan_id'][0]);
28+
$this->assertSame('The domain field format is invalid.', $callHostingSubscriptionStoreResponse['data']['domain'][0]);
29+
30+
31+
// Create a customer
32+
$faker = Factory::create();
33+
$randomName = $faker->firstName() . ' ' . $faker->lastName();
34+
$randomEmail = $faker->email();
35+
$callCustomerStoreResponse = $this->callApiAuthorizedRouteAction(
36+
'api.customers.store',
37+
[
38+
'name' => $randomName,
39+
'email' => $randomEmail,
40+
]
41+
)->json();
42+
$this->assertArrayHasKey('status', $callCustomerStoreResponse);
43+
$this->assertTrue($callCustomerStoreResponse['status'] == 'ok');
44+
45+
$this->assertArrayHasKey('message', $callCustomerStoreResponse);
46+
$this->assertArrayHasKey('data', $callCustomerStoreResponse);
47+
$this->assertArrayHasKey('customer', $callCustomerStoreResponse['data']);
48+
$this->assertArrayHasKey('id', $callCustomerStoreResponse['data']['customer']);
49+
$this->assertIsInt($callCustomerStoreResponse['data']['customer']['id']);
50+
$customerId = $callCustomerStoreResponse['data']['customer']['id'];
51+
52+
// Create a hosting subscription
53+
$randId = rand(1000, 9999);
54+
$callHostingPlansResponse = $this->callApiAuthorizedRouteAction('api.hosting-plans.index')->json();
55+
$this->assertArrayHasKey('status', $callHostingPlansResponse);
56+
$this->assertTrue($callHostingPlansResponse['status'] == 'ok');
57+
$this->assertArrayHasKey('data', $callHostingPlansResponse);
58+
$this->assertArrayHasKey('hostingPlans', $callHostingPlansResponse['data']);
59+
$this->assertIsArray($callHostingPlansResponse['data']['hostingPlans']);
60+
$this->assertNotEmpty($callHostingPlansResponse['data']['hostingPlans']);
61+
$hostingPlanId = $callHostingPlansResponse['data']['hostingPlans'][0]['id'];
62+
$this->assertIsInt($hostingPlanId);
63+
64+
$hostingSubscriptionDomain = 'phyre-unit-test-'.$randId.'.com';
65+
$callHostingSubscriptionStoreResponse = $this->callApiAuthorizedRouteAction(
66+
'api.hosting-subscriptions.store',
67+
[
68+
'customer_id' => $customerId,
69+
'hosting_plan_id'=> $hostingPlanId,
70+
'domain' => $hostingSubscriptionDomain,
71+
]
72+
)->json();
73+
74+
$this->assertArrayHasKey('status', $callHostingSubscriptionStoreResponse);
75+
$this->assertTrue($callHostingSubscriptionStoreResponse['status'] == 'ok');
76+
77+
$hostingSubscription = $callHostingSubscriptionStoreResponse['data']['hostingSubscription'];
78+
79+
// Check user home dir permissions
80+
$userHomeDir = '/home/' . $hostingSubscription['system_username'];
81+
$this->assertDirectoryExists($userHomeDir);
82+
$getUserHomeDirPermission = substr(sprintf('%o', fileperms($userHomeDir)), -4);
83+
$this->assertSame('0775', $getUserHomeDirPermission);
84+
85+
// Check domain dir permissions
86+
$domainDir = '/home/' . $hostingSubscription['system_username'] . '/public_html';
87+
$this->assertDirectoryExists($domainDir);
88+
$getDomainDirPermission = substr(sprintf('%o', fileperms($domainDir)), -4);
89+
$this->assertSame('0775', $getDomainDirPermission);
90+
91+
// Check domain dir file permissions
92+
$domainDirFile = '/home/' . $hostingSubscription['system_username'] . '/public_html/index.php';
93+
$this->assertFileExists($domainDirFile);
94+
$getDomainDirFilePermission = substr(sprintf('%o', fileperms($domainDirFile)), -4);
95+
$this->assertSame('0775', $getDomainDirFilePermission);
96+
97+
// Create second hosting subscription
98+
$randId = rand(1000, 9999);
99+
$callHostingSubscriptionStoreResponse = $this->callApiAuthorizedRouteAction(
100+
'api.hosting-subscriptions.store',
101+
[
102+
'customer_id' => $customerId,
103+
'hosting_plan_id'=> $hostingPlanId,
104+
'domain' => 'phyre-unit-test-'.$randId.'.com',
105+
]
106+
)->json();
107+
$this->assertArrayHasKey('status', $callHostingSubscriptionStoreResponse);
108+
$this->assertTrue($callHostingSubscriptionStoreResponse['status'] == 'ok');
109+
$secondHostingSubscription = $callHostingSubscriptionStoreResponse['data']['hostingSubscription'];
110+
111+
// Try to open /home directory with linux user
112+
$output = shell_exec("sudo -H -u ".$hostingSubscription['system_username']." bash -c 'ls -la /home'");
113+
$this->assertSame($output, null);
114+
115+
// Try to open /home/$user with linux user
116+
$output = shell_exec("sudo -H -u ".$hostingSubscription['system_username']." bash -c 'ls -la /home/".$hostingSubscription['system_username']."'");
117+
$this->assertTrue(str_contains($output, 'public_html'));
118+
$this->assertTrue(str_contains($output, $hostingSubscription['system_username']));
119+
120+
121+
122+
}
123+
}

0 commit comments

Comments
 (0)