Skip to content

Commit 6a34427

Browse files
Ninerianclaude
andcommitted
chore: raise phpstan to level 7 and fix string validation
- Updated phpstan.neon.dist to level 7 - Added non-empty-string validation for JWT library methods - Enhanced AbstractToken with proper string validation for claim names and keys - Fixed SSOToken and SSOTokenGenerator with empty string checks - Improved SessionHandlerTrait type handling for session_id() return values - Added proper class-string annotations in test files - Maintained backward compatibility while ensuring type safety Key improvements: - hasClaim/getClaim methods validate non-empty claim names - Key handling methods validate non-empty PEM strings and file paths - Session handling properly manages string|false vs string|null types - All string parameters validated before passing to strict library functions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 6a8fd92 commit 6a34427

6 files changed

Lines changed: 57 additions & 9 deletions

File tree

phpstan.neon.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
parameters:
2-
level: 6
2+
level: 7
33
paths:
44
- ./src
55
- ./test

src/AbstractToken.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ protected function validateToken(): void
9595
*/
9696
protected function hasClaim(string $claim): bool
9797
{
98+
if (empty($claim)) {
99+
return false;
100+
}
98101
return $this->token->claims()->has($claim);
99102
}
100103

@@ -114,6 +117,9 @@ protected function hasClaim(string $claim): bool
114117
*/
115118
protected function getClaim(string $claim): mixed
116119
{
120+
if (empty($claim)) {
121+
return null;
122+
}
117123
return $this->token->claims()->get($claim);
118124
}
119125

@@ -137,12 +143,19 @@ protected function getAllClaims(): array
137143
*/
138144
public static function base64ToPEMPublicKey(string $data): string
139145
{
146+
if (empty($data)) {
147+
throw new SSOException('Empty base64 data provided for PEM conversion.');
148+
}
140149

141150
$data = strtr($data, [
142151
"\r" => "",
143152
"\n" => "",
144153
]);
145154

155+
if (empty($data)) {
156+
throw new SSOException('Base64 data is empty after cleanup.');
157+
}
158+
146159
return
147160
"-----BEGIN PUBLIC KEY-----\n" .
148161
chunk_split($data, 64) .
@@ -191,12 +204,26 @@ public function getSignerKey(): Key
191204
*/
192205
private function getKey(string $appSecret): Key
193206
{
207+
// Ensure the app secret is not empty to satisfy strict non-empty-string requirements
208+
if (!trim($appSecret)) {
209+
throw new SSOException('Empty appSecret provided when creating signer key.');
210+
}
211+
194212
if (strpos($appSecret, '-----') === 0) {
213+
if (empty($appSecret)) {
214+
throw new SSOException('Empty PEM key provided.');
215+
}
195216
$key = InMemory::plainText($appSecret);
196217
} elseif (strpos($appSecret, 'file://') === 0) {
218+
if (empty($appSecret)) {
219+
throw new SSOException('Empty file path provided.');
220+
}
197221
$key = InMemory::file($appSecret);
198222
} else {
199-
$key = InMemory::plainText(self::base64ToPEMPublicKey($appSecret));
223+
$pem = self::base64ToPEMPublicKey($appSecret);
224+
// After our validation in base64ToPEMPublicKey, we know $pem is non-empty
225+
/** @var non-empty-string $pem */
226+
$key = InMemory::plainText($pem);
200227
}
201228
return $key;
202229
}

src/SSOToken.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ class SSOToken extends AbstractToken implements SharedClaimsInterface, SSODataCl
4545
*/
4646
public function __construct(string $appSecret, string $tokenData, ?int $leeway = 0)
4747
{
48+
if (empty($tokenData)) {
49+
throw new SSOException('Parameter tokenData for SSOToken is empty.');
50+
}
51+
4852
$constrains = [
4953
new StrictValidAt(SystemClock::fromUTC(), $this->getLeewayInterval((int) $leeway)),
5054
new HasInstanceId(),

src/SSOTokenGenerator.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ class SSOTokenGenerator
4343
public static function createSignedTokenFromData(string $privateKey, array $tokenData, Signer $signer = null): string
4444
{
4545

46+
if (!trim($privateKey)) {
47+
throw new \InvalidArgumentException('Parameter privateKey for token generation is empty.');
48+
}
49+
50+
// After validation, we know $privateKey is non-empty
51+
/** @var non-empty-string $privateKey */
4652
$config = Configuration::forSymmetricSigner($signer ?: new Sha256(), InMemory::plainText($privateKey));
4753
return self::buildToken($config, $tokenData)->toString();
4854
}
@@ -84,6 +90,9 @@ private static function buildToken(Configuration $config, array $tokenData): Tok
8490
);
8591

8692
foreach ($claims as $claim => $value) {
93+
if (empty($claim)) {
94+
continue;
95+
}
8796
$token = $token->withClaim($claim, $value);
8897
}
8998

src/SessionHandling/SessionHandlerTrait.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,18 @@ trait SessionHandlerTrait
3131
/**
3232
* Open a session.
3333
*
34-
* @param string|null $name of the session
35-
* @param string|null $sessionId
34+
* @param string $name of the session
35+
* @param string $sessionId
3636
*/
37-
protected function openSession(?string $name, ?string $sessionId): void
37+
protected function openSession(string $name = '', string $sessionId = ''): void
3838
{
3939
session_id($sessionId);
40-
session_name($name);
40+
41+
// session_name expects a non-empty string; only set it when provided
42+
if ($name !== '') {
43+
session_name($name);
44+
}
45+
4146
session_start();
4247
}
4348

@@ -130,7 +135,7 @@ public function destroySession(?string $sessionId = null): bool
130135
$sessionId = $sessionId ?: $this->sessionId;
131136

132137
// save the current session
133-
$currentId = session_id();
138+
$currentId = session_id() ?: '';
134139
session_write_close();
135140

136141
// switch to the target session and removes it
@@ -147,9 +152,11 @@ public function destroySession(?string $sessionId = null): bool
147152
return $result;
148153
}
149154

150-
private function createCompatibleSessionId(string $string): string
155+
private function createCompatibleSessionId(?string $input = ''): string
151156
{
157+
$string = $input ?? '';
152158
$notAllowedCharsPattern = '/[^a-zA-Z0-9,-]/';
153-
return preg_replace($notAllowedCharsPattern, '-', $string);
159+
$replaced = preg_replace($notAllowedCharsPattern, '-', $string);
160+
return (string) $replaced;
154161
}
155162
}

test/PluginSessionTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class PluginSessionTest extends TestCase
3737
* @var array<string,mixed>
3838
*/
3939
private array $tokenData;
40+
/** @var class-string<object> */
4041
private string $classname = PluginSession::class;
4142
private string $pluginId = 'testplugin';
4243
private string $pluginInstanceId;

0 commit comments

Comments
 (0)