Skip to content

Commit 752608b

Browse files
committed
Harden trait contracts and constant refs across API auth and routing
1 parent edafb6f commit 752608b

9 files changed

Lines changed: 96 additions & 34 deletions

File tree

src/base/types/traits/Api/ApiTrait.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ protected function saveBulk()
105105
{
106106
$tablemap = $this->getTableMap();
107107
$this->bulkSavedCount = 0;
108+
$databaseName = $this->resolveTableMapDatabaseName($tablemap);
108109
foreach ($this->list as &$model) {
109-
$con = Propel::getWriteConnection($tablemap::DATABASE_NAME);
110+
$con = Propel::getWriteConnection($databaseName);
110111
try {
111112
$model->save($con);
112113
$con->commit();
@@ -280,4 +281,12 @@ protected function resolveReturnFields(string $returnFields): array
280281
}
281282
return $select;
282283
}
284+
285+
protected function resolveTableMapDatabaseName(TableMap $tableMap): string
286+
{
287+
if (defined(get_class($tableMap) . '::DATABASE_NAME')) {
288+
return constant(get_class($tableMap) . '::DATABASE_NAME');
289+
}
290+
return Config::getParam('database.name', 'default');
291+
}
283292
}

src/base/types/traits/Api/Crud/ApiListTrait.php

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,18 @@ trait ApiListTrait
1313
{
1414
use MutationTrait;
1515

16-
const API_COMBO_FIELD = '__combo';
17-
const API_ORDER_FIELD = '__order';
18-
const API_PAGE_FIELD = '__page';
19-
const API_LIMIT_FIELD = '__limit';
16+
/**
17+
* Contract: provided by ApiTrait.
18+
*/
19+
abstract protected function prepareQuery();
20+
21+
/**
22+
* Contract: provided by ApiTrait.
23+
*
24+
* @param ModelCriteria $query
25+
* @return mixed
26+
*/
27+
abstract protected function checkReturnFields(ModelCriteria &$query);
2028

2129
/**
2230
* @var array
@@ -41,7 +49,7 @@ protected function hydrateOrders()
4149
if (count($this->query)) {
4250
Logger::log(static::class . ' gathering query string', LOG_DEBUG);
4351
foreach ($this->query as $key => $value) {
44-
if ($key === self::API_ORDER_FIELD) {
52+
if ($key === $this->apiOrderField()) {
4553
$orders = json_decode($value, true);
4654
foreach ($orders as $field => $direction) {
4755
$this->order->addOrder($field, $direction);
@@ -57,8 +65,8 @@ protected function hydrateOrders()
5765
protected function extractPagination()
5866
{
5967
Logger::log(static::class . ' extract pagination start', LOG_DEBUG);
60-
$page = array_key_exists(self::API_PAGE_FIELD, $this->query) ? $this->query[self::API_PAGE_FIELD] : 1;
61-
$limit = array_key_exists(self::API_LIMIT_FIELD, $this->query) ? $this->query[self::API_LIMIT_FIELD] : 100;
68+
$page = array_key_exists($this->apiPageField(), $this->query) ? $this->query[$this->apiPageField()] : 1;
69+
$limit = array_key_exists($this->apiLimitField(), $this->query) ? $this->query[$this->apiLimitField()] : 100;
6270
Logger::log(static::class . ' extract pagination end', LOG_DEBUG);
6371
return array($page, (int)$limit);
6472
}
@@ -100,7 +108,7 @@ protected function addFilters(ModelCriteria &$query)
100108
if (!empty($this->query)) {
101109
$tableMap = $this->getTableMap();
102110
foreach ($this->query as $field => $value) {
103-
if (self::API_COMBO_FIELD === $field) {
111+
if ($this->apiComboField() === $field) {
104112
ApiHelper::composerComboField($tableMap, $query, $this->extraColumns, $value);
105113
} elseif (!preg_match('/^__/', $field)) {
106114
ApiHelper::addModelField($tableMap, $query, $field, $value);
@@ -129,4 +137,24 @@ protected function paginate()
129137
}
130138
}
131139

140+
private function apiComboField(): string
141+
{
142+
return '__combo';
143+
}
144+
145+
private function apiOrderField(): string
146+
{
147+
return '__order';
148+
}
149+
150+
private function apiPageField(): string
151+
{
152+
return '__page';
153+
}
154+
155+
private function apiLimitField(): string
156+
{
157+
return '__limit';
158+
}
159+
132160
}

src/base/types/traits/Api/DocumentorHelperTrait.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
namespace PSFS\base\types\traits\Api;
44

55
use Exception;
6+
use Propel\Runtime\ActiveRecord\ActiveRecordInterface;
67
use Propel\Runtime\Map\ColumnMap;
78
use PSFS\base\Logger;
89
use PSFS\base\Router;
10+
use PSFS\base\dto\Dto;
911
use PSFS\base\types\helpers\AnnotationHelper;
1012
use PSFS\base\types\helpers\ApiHelper;
1113
use PSFS\base\types\helpers\DocumentorHelper;
@@ -18,6 +20,11 @@
1820
*/
1921
trait DocumentorHelperTrait
2022
{
23+
/**
24+
* Contract: provided by SwaggerDtoComposerTrait.
25+
*/
26+
abstract protected function checkDtoAttributes(array $dto, array $modelDto, string $dtoName): array;
27+
2128
public static $nativeMethods = [
2229
'modelList', // Api list
2330
'get', // Api get
@@ -61,7 +68,7 @@ protected function extractApi(?string $comments = '', ?ReflectionClass $reflecto
6168
*/
6269
protected function checkDeprecated($comments = '')
6370
{
64-
return false != preg_match('/@deprecated\n/i', $comments);
71+
return preg_match('/@deprecated\n/i', $comments) === 1;
6572
}
6673

6774
/**
@@ -115,7 +122,7 @@ protected function extractDtoProperties($class)
115122
{
116123
$properties = [];
117124
$reflector = new ReflectionClass($class);
118-
if ($reflector->isSubclassOf(self::DTO_INTERFACE)) {
125+
if ($reflector->isSubclassOf(Dto::class)) {
119126
$properties = array_merge($properties, InjectorHelper::extractVariables($reflector));
120127
}
121128

@@ -193,7 +200,7 @@ protected function extractModelFields($namespace)
193200
try {
194201
$reflector = new ReflectionClass($namespace);
195202
// Checks if reflector is a subclass of propel ActiveRecords
196-
if (null !== $reflector && $reflector->isSubclassOf(self::MODEL_INTERFACE)) {
203+
if (null !== $reflector && $reflector->isSubclassOf(ActiveRecordInterface::class)) {
197204
$tableMap = $namespace::TABLE_MAP;
198205
$tableMap = $tableMap::getTableMap();
199206

@@ -212,7 +219,7 @@ protected function extractModelFields($namespace)
212219
}
213220
$payload[ApiHelper::getColumnMapName($field)] = $info;
214221
}
215-
} elseif (null !== $reflector && $reflector->isSubclassOf(self::DTO_INTERFACE)) {
222+
} elseif (null !== $reflector && $reflector->isSubclassOf(Dto::class)) {
216223
$payload = $this->extractDtoProperties($namespace);
217224
}
218225
} catch (Exception $e) {

src/base/types/traits/Helper/AuthCryptoTrait.php

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

33
namespace PSFS\base\types\traits\Helper;
44

5+
use PSFS\base\types\helpers\AuthHelper;
6+
57
trait AuthCryptoTrait
68
{
79
private static function isPasswordHash(string $hash): bool
@@ -12,7 +14,7 @@ private static function isPasswordHash(string $hash): bool
1214

1315
private static function secureEncrypt(string $data, string $key): false|string
1416
{
15-
$ivLen = openssl_cipher_iv_length(self::CRYPTO_CIPHER);
17+
$ivLen = openssl_cipher_iv_length(AuthHelper::CRYPTO_CIPHER);
1618
if (false === $ivLen || $ivLen < 1) {
1719
return false;
1820
}
@@ -24,13 +26,13 @@ private static function secureEncrypt(string $data, string $key): false|string
2426
$tag = '';
2527
$encrypted = openssl_encrypt(
2628
$data,
27-
self::CRYPTO_CIPHER,
29+
AuthHelper::CRYPTO_CIPHER,
2830
hash('sha256', $key, true),
2931
OPENSSL_RAW_DATA,
3032
$iv,
3133
$tag,
3234
'',
33-
self::CRYPTO_TAG_LENGTH
35+
AuthHelper::CRYPTO_TAG_LENGTH
3436
);
3537
if (false === $encrypted) {
3638
return false;
@@ -66,7 +68,7 @@ private static function secureDecrypt(string $payload, string $key): false|strin
6668

6769
$decrypted = openssl_decrypt(
6870
$encrypted,
69-
self::CRYPTO_CIPHER,
71+
AuthHelper::CRYPTO_CIPHER,
7072
hash('sha256', $key, true),
7173
OPENSSL_RAW_DATA,
7274
$iv,

src/base/types/traits/Helper/AuthFlowTrait.php

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

55
use Firebase\JWT\JWT;
66
use PSFS\base\Request;
7+
use PSFS\base\types\helpers\AuthHelper;
78
use Throwable;
89

910
trait AuthFlowTrait
@@ -73,13 +74,13 @@ private static function validateAdminHash(?string $user, ?string $pass, array $p
7374

7475
private static function extractCredentialsFromCookie(string $authCookie): array
7576
{
76-
$secret = self::decrypt($authCookie, self::SESSION_TOKEN);
77+
$secret = self::decrypt($authCookie, AuthHelper::SESSION_TOKEN);
7778
if (is_string($secret) && str_contains($secret, ':')) {
7879
[$user, $pass] = explode(':', $secret, 2);
7980
return self::authTuple($user, $pass);
8081
}
8182
// Legacy fallback: old cookies/tests may still use ADMIN_ID_TOKEN.
82-
$legacySecret = self::decrypt($authCookie, self::ADMIN_ID_TOKEN);
83+
$legacySecret = self::decrypt($authCookie, AuthHelper::ADMIN_ID_TOKEN);
8384
if (is_string($legacySecret) && str_contains($legacySecret, ':')) {
8485
self::logLegacyFallbackUsage('cookie_key_admin_token');
8586
[$user, $pass] = explode(':', $legacySecret, 2);

src/base/types/traits/Helper/I18nLocaleTrait.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PSFS\base\Request;
66
use PSFS\base\Security;
77
use PSFS\base\config\Config;
8+
use PSFS\base\types\helpers\I18nHelper;
89
use PSFS\base\types\helpers\ServerHelper;
910

1011
trait I18nLocaleTrait
@@ -27,8 +28,8 @@ public static function extractLocale(string $default = null): string
2728
$locale = Request::header('X-API-LANG', $default);
2829
if (empty($locale)) {
2930
$session = Security::getInstance();
30-
$sessionLocale = $session->getSessionKey(self::PSFS_SESSION_LOCALE_KEY);
31-
$sessionLanguage = $session->getSessionKey(self::PSFS_SESSION_LANGUAGE_KEY);
31+
$sessionLocale = $session->getSessionKey(I18nHelper::PSFS_SESSION_LOCALE_KEY);
32+
$sessionLanguage = $session->getSessionKey(I18nHelper::PSFS_SESSION_LANGUAGE_KEY);
3233
if (!empty($sessionLanguage) && (empty($sessionLocale) || stripos(
3334
(string)$sessionLocale,
3435
(string)$sessionLanguage . '_'
@@ -53,7 +54,7 @@ public static function extractLocale(string $default = null): string
5354
if (!in_array($locale, array_merge($defaultLocales, self::$langs), true)) {
5455
$locale = Config::getParam('default.language', $default);
5556
}
56-
return $locale;
57+
return is_string($locale) ? $locale : (string)Config::getParam('default.language', 'en_US');
5758
}
5859

5960
private static function normalizeLocale(string $locale): string

src/base/types/traits/Router/RouterCacheFlowTrait.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212

1313
trait RouterCacheFlowTrait
1414
{
15+
/**
16+
* Contract: provided by ModulesTrait.
17+
*/
18+
abstract protected function calculateRoutingFingerprint(): string;
19+
1520
/**
1621
* @param array $action
1722
* @param array $params
@@ -173,18 +178,23 @@ private function isRoutingMetaFresh(): bool
173178

174179
private function loadRoutingMeta(): array
175180
{
176-
$metaPath = CONFIG_DIR . DIRECTORY_SEPARATOR . self::ROUTING_META_FILE;
181+
$metaPath = CONFIG_DIR . DIRECTORY_SEPARATOR . $this->routingMetaFileName();
177182
$meta = $this->cache->getDataFromFile($metaPath, Cache::JSON, true);
178183
return is_array($meta) ? $meta : [];
179184
}
180185

181186
private function storeRoutingMeta(): void
182187
{
183-
$metaPath = CONFIG_DIR . DIRECTORY_SEPARATOR . self::ROUTING_META_FILE;
188+
$metaPath = CONFIG_DIR . DIRECTORY_SEPARATOR . $this->routingMetaFileName();
184189
$payload = [
185190
'fingerprint' => $this->calculateRoutingFingerprint(),
186191
'updated_at' => date('c'),
187192
];
188193
$this->cache->storeData($metaPath, $payload, Cache::JSON, true);
189194
}
195+
196+
private function routingMetaFileName(): string
197+
{
198+
return 'routes.meta.json';
199+
}
190200
}

src/base/types/traits/Security/FlashesTrait.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace PSFS\base\types\traits\Security;
44

5+
use PSFS\base\Security;
6+
57
/**
68
* @package PSFS\base\types\traits\Security
79
*/
@@ -14,7 +16,7 @@ trait FlashesTrait
1416
*/
1517
public function getFlashes()
1618
{
17-
$flashes = $this->getSessionKey(self::FLASH_MESSAGE_TOKEN);
19+
$flashes = $this->getSessionKey(Security::FLASH_MESSAGE_TOKEN);
1820

1921
return (null !== $flashes) ? $flashes : array();
2022
}
@@ -24,7 +26,7 @@ public function getFlashes()
2426
*/
2527
public function clearFlashes()
2628
{
27-
$this->setSessionKey(self::FLASH_MESSAGE_TOKEN, null);
29+
$this->setSessionKey(Security::FLASH_MESSAGE_TOKEN, null);
2830

2931
return $this;
3032
}
@@ -41,7 +43,7 @@ public function setFlash($key, $data = null)
4143
$flashes = [];
4244
}
4345
$flashes[$key] = $data;
44-
$this->setSessionKey(self::FLASH_MESSAGE_TOKEN, $flashes);
46+
$this->setSessionKey(Security::FLASH_MESSAGE_TOKEN, $flashes);
4547
}
4648

4749
/**

src/runtime/swoole/SwoolePidManager.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ public static function isRunning(int $pid): bool
2323
return false;
2424
}
2525
if (function_exists('posix_kill')) {
26-
return @posix_kill($pid, 0);
26+
return posix_kill($pid, 0);
2727
}
28-
$result = @exec('kill -0 ' . (int)$pid . ' 2>/dev/null', $output, $code);
28+
$result = exec('kill -0 ' . (int)$pid . ' 2>/dev/null', $output, $code);
2929
return $result !== false && $code === 0;
3030
}
3131

@@ -36,7 +36,9 @@ public static function readRunningPid(string $pidFile): ?int
3636
return null;
3737
}
3838
if (!self::isRunning($pid)) {
39-
@unlink($pidFile);
39+
if (is_file($pidFile) && unlink($pidFile) === false) {
40+
// Keep stale pid file if unable to remove.
41+
}
4042
return null;
4143
}
4244
return $pid;
@@ -45,16 +47,16 @@ public static function readRunningPid(string $pidFile): ?int
4547
public static function writePid(string $pidFile, int $pid): void
4648
{
4749
$dir = dirname($pidFile);
48-
if (!is_dir($dir)) {
49-
@mkdir($dir, 0775, true);
50+
if (!is_dir($dir) && mkdir($dir, 0775, true) === false && !is_dir($dir)) {
51+
return;
5052
}
5153
file_put_contents($pidFile, (string)$pid);
5254
}
5355

5456
public static function removePid(string $pidFile): void
5557
{
56-
if (is_file($pidFile)) {
57-
@unlink($pidFile);
58+
if (is_file($pidFile) && unlink($pidFile) === false) {
59+
// Ignore remove failures to keep shutdown flow non-fatal.
5860
}
5961
}
6062
}

0 commit comments

Comments
 (0)