Skip to content

Commit 61f501a

Browse files
committed
Fix file parser failing if multiple configuration values are present on same line; closes pterodactyl#2604
1 parent 8c8feff commit 61f501a

File tree

1 file changed

+68
-66
lines changed

1 file changed

+68
-66
lines changed

app/Services/Eggs/EggConfigurationService.php

Lines changed: 68 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,10 @@
55
use Illuminate\Support\Arr;
66
use Illuminate\Support\Str;
77
use Pterodactyl\Models\Server;
8-
use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
98
use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
109

1110
class EggConfigurationService
1211
{
13-
private const NOT_MATCHED = '__no_match';
14-
15-
/**
16-
* @var \Pterodactyl\Contracts\Repository\EggRepositoryInterface
17-
*/
18-
private $repository;
19-
2012
/**
2113
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
2214
*/
@@ -25,14 +17,10 @@ class EggConfigurationService
2517
/**
2618
* EggConfigurationService constructor.
2719
*
28-
* @param \Pterodactyl\Contracts\Repository\EggRepositoryInterface $repository
2920
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $configurationStructureService
3021
*/
31-
public function __construct(
32-
EggRepositoryInterface $repository,
33-
ServerConfigurationStructureService $configurationStructureService
34-
) {
35-
$this->repository = $repository;
22+
public function __construct(ServerConfigurationStructureService $configurationStructureService)
23+
{
3624
$this->configurationStructureService = $configurationStructureService;
3725
}
3826

@@ -41,8 +29,6 @@ public function __construct(
4129
*
4230
* @param \Pterodactyl\Models\Server $server
4331
* @return array
44-
*
45-
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
4632
*/
4733
public function handle(Server $server): array
4834
{
@@ -111,8 +97,6 @@ protected function convertStopToNewFormat(string $stop): array
11197
* @param \Pterodactyl\Models\Server $server
11298
* @param object $configs
11399
* @return array
114-
*
115-
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
116100
*/
117101
protected function replacePlaceholders(Server $server, object $configs)
118102
{
@@ -130,6 +114,7 @@ protected function replacePlaceholders(Server $server, object $configs)
130114
foreach ($configs as $file => $data) {
131115
$append = ['file' => $file, 'replace' => []];
132116

117+
/** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
133118
// I like to think I understand PHP pretty well, but if you don't pass $value
134119
// by reference here, you'll end up with a resursive array loop if the config
135120
// file has two replacements that reference the same item in the configuration
@@ -167,71 +152,93 @@ protected function replacePlaceholders(Server $server, object $configs)
167152
}
168153

169154
/**
155+
* Replaces the legacy modifies from eggs with their new counterpart. The legacy Daemon would
156+
* set SERVER_MEMORY, SERVER_IP, and SERVER_PORT with their respective values on the Daemon
157+
* side. Ensure that anything referencing those properly replaces them with the matching config
158+
* value.
159+
*
160+
* @param string $key
170161
* @param string $value
171-
* @param array $structure
172-
* @return string|null
162+
* @return string
173163
*/
174-
protected function matchAndReplaceKeys(string $value, array $structure): ?string
164+
protected function replaceLegacyModifiers(string $key, string $value): string
175165
{
176-
preg_match('/{{(?<key>.*)}}/', $value, $matches);
177-
178-
if (! $key = $matches['key'] ?? null) {
179-
return self::NOT_MATCHED;
180-
}
181-
182-
// Matched something in {{server.X}} format, now replace that with the actual
183-
// value from the server properties.
184-
//
185-
// The Daemon supports server.X, env.X, and config.X placeholders.
186-
if (! Str::startsWith($key, ['server.', 'env.', 'config.'])) {
187-
return self::NOT_MATCHED;
188-
}
189-
190-
// The legacy Daemon would set SERVER_MEMORY, SERVER_IP, and SERVER_PORT with their
191-
// respective values on the Daemon side. Ensure that anything referencing those properly
192-
// replaces them with the matching config value.
193166
switch ($key) {
194167
case 'config.docker.interface':
195-
$key = 'config.docker.network.interface';
168+
$replace = 'config.docker.network.interface';
196169
break;
197170
case 'server.build.env.SERVER_MEMORY':
198171
case 'env.SERVER_MEMORY':
199-
$key = 'server.build.memory';
172+
$replace = 'server.build.memory';
200173
break;
201174
case 'server.build.env.SERVER_IP':
202175
case 'env.SERVER_IP':
203-
$key = 'server.build.default.ip';
176+
$replace = 'server.build.default.ip';
204177
break;
205178
case 'server.build.env.SERVER_PORT':
206179
case 'env.SERVER_PORT':
207-
$key = 'server.build.default.port';
180+
$replace = 'server.build.default.port';
208181
break;
182+
// By default we don't need to change anything, only if we ended up matching a specific legacy item.
183+
default:
184+
$replace = $key;
209185
}
210186

211-
// We don't want to do anything with config keys since the Daemon will need to handle
212-
// that. For example, the Spigot egg uses "config.docker.interface" to identify the Docker
213-
// interface to proxy through, but the Panel would be unaware of that.
214-
if (Str::startsWith($key, 'config.')) {
215-
return preg_replace('/{{(.*)}}/', "{{{$key}}}", $value);
216-
}
187+
return str_replace("{{{$key}}}", "{{{$replace}}}", $value);
188+
}
217189

218-
// Replace anything starting with "server." with the value out of the server configuration
219-
// array that used to be created for the old daemon.
220-
if (Str::startsWith($key, 'server.')) {
190+
/**
191+
* @param mixed $value
192+
* @param array $structure
193+
* @return mixed|null
194+
*/
195+
protected function matchAndReplaceKeys($value, array $structure)
196+
{
197+
preg_match_all('/{{(?<key>[\w.-]*)}}/', $value, $matches);
198+
199+
foreach ($matches['key'] as $key) {
200+
// Matched something in {{server.X}} format, now replace that with the actual
201+
// value from the server properties.
202+
//
203+
// The Daemon supports server.X, env.X, and config.X placeholders.
204+
if (! Str::startsWith($key, ['server.', 'env.', 'config.'])) {
205+
continue;
206+
}
207+
208+
// Don't do a replacement on anything that is not a string, we don't want to unintentionally
209+
// modify the resulting output.
210+
if (! is_string($value)) {
211+
continue;
212+
}
213+
214+
$value = $this->replaceLegacyModifiers($key, $value);
215+
216+
// We don't want to do anything with config keys since the Daemon will need to handle
217+
// that. For example, the Spigot egg uses "config.docker.interface" to identify the Docker
218+
// interface to proxy through, but the Panel would be unaware of that.
219+
if (Str::startsWith($key, 'config.')) {
220+
continue;
221+
}
222+
223+
// Replace anything starting with "server." with the value out of the server configuration
224+
// array that used to be created for the old daemon.
225+
if (Str::startsWith($key, 'server.')) {
226+
$plucked = Arr::get($structure, preg_replace('/^server\./', '', $key), '');
227+
228+
$value = str_replace("{{{$key}}}", $plucked, $value);
229+
continue;
230+
}
231+
232+
// Finally, replace anything starting with env. with the expected environment
233+
// variable from the server configuration.
221234
$plucked = Arr::get(
222-
$structure, preg_replace('/^server\./', '', $key), ''
235+
$structure, preg_replace('/^env\./', 'build.env.', $key), ''
223236
);
224237

225-
return preg_replace('/{{(.*)}}/', $plucked, $value);
238+
$value = str_replace("{{{$key}}}", $plucked, $value);
226239
}
227240

228-
// Finally, replace anything starting with env. with the expected environment
229-
// variable from the server configuration.
230-
$plucked = Arr::get(
231-
$structure, preg_replace('/^env\./', 'build.env.', $key), ''
232-
);
233-
234-
return preg_replace('/{{(.*)}}/', $plucked, $value);
241+
return $value;
235242
}
236243

237244
/**
@@ -255,12 +262,7 @@ private function iterate(&$data, array $structure)
255262
continue;
256263
}
257264

258-
$response = $this->matchAndReplaceKeys($value, $structure);
259-
if ($response === self::NOT_MATCHED) {
260-
continue;
261-
}
262-
263-
$value = $response;
265+
$value = $this->matchAndReplaceKeys($value, $structure);
264266
}
265267
}
266268
}

0 commit comments

Comments
 (0)