1 | <?php |
||||
2 | |||||
3 | namespace MadWizard\WebAuthn\Builder; |
||||
4 | |||||
5 | use Closure; |
||||
6 | use GuzzleHttp\Client; |
||||
7 | use MadWizard\WebAuthn\Attestation\AttestationType; |
||||
8 | use MadWizard\WebAuthn\Attestation\Registry\AttestationFormatRegistry; |
||||
9 | use MadWizard\WebAuthn\Attestation\Registry\AttestationFormatRegistryInterface; |
||||
10 | use MadWizard\WebAuthn\Attestation\TrustAnchor\TrustPathValidator; |
||||
11 | use MadWizard\WebAuthn\Attestation\TrustAnchor\TrustPathValidatorInterface; |
||||
12 | use MadWizard\WebAuthn\Attestation\Verifier; |
||||
13 | use MadWizard\WebAuthn\Cache\CacheProviderInterface; |
||||
14 | use MadWizard\WebAuthn\Cache\FileCacheProvider; |
||||
15 | use MadWizard\WebAuthn\Config\RelyingParty; |
||||
16 | use MadWizard\WebAuthn\Config\RelyingPartyInterface; |
||||
17 | use MadWizard\WebAuthn\Credential\CredentialStoreInterface; |
||||
18 | use MadWizard\WebAuthn\Exception\ConfigurationException; |
||||
19 | use MadWizard\WebAuthn\Exception\UnsupportedException; |
||||
20 | use MadWizard\WebAuthn\Extension\AppId\AppIdExtension; |
||||
21 | use MadWizard\WebAuthn\Extension\ExtensionInterface; |
||||
22 | use MadWizard\WebAuthn\Extension\ExtensionRegistry; |
||||
23 | use MadWizard\WebAuthn\Extension\ExtensionRegistryInterface; |
||||
24 | use MadWizard\WebAuthn\Metadata\MetadataResolver; |
||||
25 | use MadWizard\WebAuthn\Metadata\MetadataResolverInterface; |
||||
26 | use MadWizard\WebAuthn\Metadata\NullMetadataResolver; |
||||
27 | use MadWizard\WebAuthn\Metadata\Provider\FileProvider; |
||||
28 | use MadWizard\WebAuthn\Metadata\Provider\MetadataServiceProvider; |
||||
29 | use MadWizard\WebAuthn\Metadata\Source\BundledSource; |
||||
30 | use MadWizard\WebAuthn\Metadata\Source\MetadataServiceSource; |
||||
31 | use MadWizard\WebAuthn\Metadata\Source\MetadataSourceInterface; |
||||
32 | use MadWizard\WebAuthn\Metadata\Source\StatementDirectorySource; |
||||
33 | use MadWizard\WebAuthn\Pki\CertificateStatusResolverInterface; |
||||
34 | use MadWizard\WebAuthn\Pki\ChainValidator; |
||||
35 | use MadWizard\WebAuthn\Pki\ChainValidatorInterface; |
||||
36 | use MadWizard\WebAuthn\Pki\CrlCertificateStatusResolver; |
||||
37 | use MadWizard\WebAuthn\Pki\NullCertificateStatusResolver; |
||||
38 | use MadWizard\WebAuthn\Policy\Policy; |
||||
39 | use MadWizard\WebAuthn\Policy\PolicyInterface; |
||||
40 | use MadWizard\WebAuthn\Policy\Trust\TrustDecisionManager; |
||||
41 | use MadWizard\WebAuthn\Policy\Trust\TrustDecisionManagerInterface; |
||||
42 | use MadWizard\WebAuthn\Policy\Trust\Voter; |
||||
43 | use MadWizard\WebAuthn\Remote\CachingClientFactory; |
||||
44 | use MadWizard\WebAuthn\Remote\Downloader; |
||||
45 | use MadWizard\WebAuthn\Remote\DownloaderInterface; |
||||
46 | use MadWizard\WebAuthn\Server\ServerInterface; |
||||
47 | use MadWizard\WebAuthn\Server\WebAuthnServer; |
||||
48 | use Psr\Log\LoggerAwareInterface; |
||||
49 | use Psr\Log\LoggerInterface; |
||||
50 | use Psr\Log\NullLogger; |
||||
51 | |||||
52 | final class ServerBuilder |
||||
53 | { |
||||
54 | /** |
||||
55 | * @var RelyingParty|null |
||||
56 | */ |
||||
57 | private $rp; |
||||
58 | |||||
59 | /** |
||||
60 | * @var CredentialStoreInterface|null |
||||
61 | */ |
||||
62 | private $store; |
||||
63 | |||||
64 | /** |
||||
65 | * @var string|null; |
||||
66 | */ |
||||
67 | private $cacheDir; |
||||
68 | |||||
69 | /** |
||||
70 | * @var callable|PolicyCallbackInterface|null |
||||
71 | */ |
||||
72 | private $policyCallback; |
||||
73 | |||||
74 | /** |
||||
75 | * @var MetadataSourceInterface[] |
||||
76 | */ |
||||
77 | private $metadataSources = []; |
||||
78 | |||||
79 | /** |
||||
80 | * @var LoggerInterface|null |
||||
81 | */ |
||||
82 | private $logger; |
||||
83 | |||||
84 | /** |
||||
85 | * @var bool |
||||
86 | */ |
||||
87 | private $allowNoneAttestation = true; |
||||
88 | |||||
89 | /** |
||||
90 | * @var bool |
||||
91 | */ |
||||
92 | private $allowSelfAttestation = true; |
||||
93 | |||||
94 | /** |
||||
95 | * @var bool |
||||
96 | */ |
||||
97 | private $trustWithoutMetadata = true; |
||||
98 | |||||
99 | /** |
||||
100 | * @var bool |
||||
101 | */ |
||||
102 | private $validateUsingMetadata = true; |
||||
103 | |||||
104 | /** |
||||
105 | * @var bool |
||||
106 | */ |
||||
107 | private $strictSupportedFormats = false; |
||||
108 | |||||
109 | /** |
||||
110 | * @var string[] |
||||
111 | */ |
||||
112 | private $enabledExtensions = []; |
||||
113 | |||||
114 | /** |
||||
115 | * @var ExtensionInterface[] |
||||
116 | */ |
||||
117 | private $customExtensions = []; |
||||
118 | |||||
119 | /** |
||||
120 | * @var bool |
||||
121 | */ |
||||
122 | private $enableCrl = false; |
||||
123 | |||||
124 | /** |
||||
125 | * @var bool |
||||
126 | */ |
||||
127 | private $crlSilentFailure = true; |
||||
128 | |||||
129 | private const SUPPORTED_EXTENSIONS = [ |
||||
130 | 'appid' => AppIdExtension::class, |
||||
131 | ]; |
||||
132 | |||||
133 | 19 | public function __construct() |
|||
134 | { |
||||
135 | 19 | } |
|||
136 | |||||
137 | 19 | public function setRelyingParty(RelyingParty $rp): self |
|||
138 | { |
||||
139 | 19 | $this->rp = $rp; |
|||
140 | 19 | return $this; |
|||
141 | } |
||||
142 | |||||
143 | 19 | public function setCredentialStore(CredentialStoreInterface $store): self |
|||
144 | { |
||||
145 | 19 | $this->store = $store; |
|||
146 | 19 | return $this; |
|||
147 | } |
||||
148 | |||||
149 | public function setCacheDirectory(string $directory): self |
||||
150 | { |
||||
151 | $this->cacheDir = $directory; |
||||
152 | return $this; |
||||
153 | } |
||||
154 | |||||
155 | public function useSystemTempCache(string $subDirectory = 'webauthn-server-cache'): self |
||||
156 | { |
||||
157 | $this->cacheDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $subDirectory; |
||||
158 | return $this; |
||||
159 | } |
||||
160 | |||||
161 | /** |
||||
162 | * @param callable|PolicyCallbackInterface $policyCallback |
||||
163 | * |
||||
164 | * @return $this |
||||
165 | */ |
||||
166 | public function configurePolicy(callable $policyCallback): self |
||||
167 | { |
||||
168 | $this->policyCallback = $policyCallback; |
||||
169 | return $this; |
||||
170 | } |
||||
171 | |||||
172 | /** |
||||
173 | * @return $this |
||||
174 | */ |
||||
175 | public function allowNoneAttestation(bool $allow): self |
||||
176 | { |
||||
177 | $this->allowNoneAttestation = $allow; |
||||
178 | return $this; |
||||
179 | } |
||||
180 | |||||
181 | /** |
||||
182 | * @return $this |
||||
183 | */ |
||||
184 | public function strictSupportedFormats(bool $strict): self |
||||
185 | { |
||||
186 | $this->strictSupportedFormats = $strict; |
||||
187 | return $this; |
||||
188 | } |
||||
189 | |||||
190 | /** |
||||
191 | * @return $this |
||||
192 | */ |
||||
193 | public function validateUsingMetadata(bool $use): self |
||||
194 | { |
||||
195 | $this->validateUsingMetadata = $use; |
||||
196 | return $this; |
||||
197 | } |
||||
198 | |||||
199 | /** |
||||
200 | * @return $this |
||||
201 | * @experimental |
||||
202 | */ |
||||
203 | public function enableCrl(bool $enable, bool $silentFailure = true): self |
||||
204 | { |
||||
205 | if ($enable && !class_exists(\phpseclib3\File\X509::class)) { |
||||
206 | throw new UnsupportedException('CRL support requires phpseclib v3. Use composer require phpseclib/phpseclib ^3.0'); |
||||
207 | } |
||||
208 | $this->enableCrl = $enable; |
||||
209 | $this->crlSilentFailure = $silentFailure; |
||||
210 | return $this; |
||||
211 | } |
||||
212 | |||||
213 | /** |
||||
214 | * @return $this |
||||
215 | */ |
||||
216 | public function allowSelfAttestation(bool $allow): self |
||||
217 | { |
||||
218 | $this->allowSelfAttestation = $allow; |
||||
219 | return $this; |
||||
220 | } |
||||
221 | |||||
222 | /** |
||||
223 | * @return $this |
||||
224 | */ |
||||
225 | public function trustWithoutMetadata(bool $trust): self |
||||
226 | { |
||||
227 | $this->trustWithoutMetadata = $trust; |
||||
228 | return $this; |
||||
229 | } |
||||
230 | |||||
231 | /** |
||||
232 | * @return $this |
||||
233 | */ |
||||
234 | public function enableExtensions(string ...$extensions): self |
||||
235 | { |
||||
236 | foreach ($extensions as $ext) { |
||||
237 | if (!isset(self::SUPPORTED_EXTENSIONS[$ext])) { |
||||
238 | throw new ConfigurationException(sprintf('Extension %s is not supported.', $ext)); |
||||
239 | } |
||||
240 | } |
||||
241 | $this->enabledExtensions = array_merge($this->enabledExtensions, $extensions); |
||||
242 | return $this; |
||||
243 | } |
||||
244 | |||||
245 | /** |
||||
246 | * @return $this |
||||
247 | */ |
||||
248 | public function addCustomExtension(ExtensionInterface $extension): self |
||||
249 | { |
||||
250 | $this->customExtensions[] = $extension; |
||||
251 | return $this; |
||||
252 | } |
||||
253 | |||||
254 | /** |
||||
255 | * @return $this |
||||
256 | */ |
||||
257 | public function setLogger(LoggerInterface $logger): self |
||||
258 | { |
||||
259 | $this->logger = $logger; |
||||
260 | return $this; |
||||
261 | } |
||||
262 | |||||
263 | private function assignLogger(LoggerAwareInterface $service): void |
||||
264 | { |
||||
265 | if ($this->logger !== null) { |
||||
266 | $service->setLogger($this->logger); |
||||
267 | } |
||||
268 | } |
||||
269 | |||||
270 | 19 | public function build(): ServerInterface |
|||
271 | { |
||||
272 | 19 | $c = $this->setupContainer(); |
|||
273 | |||||
274 | 19 | return $c[ServerInterface::class]; |
|||
275 | } |
||||
276 | |||||
277 | 19 | private function setupContainer(): ServiceContainer |
|||
278 | { |
||||
279 | 19 | $c = new ServiceContainer(); |
|||
280 | |||||
281 | 19 | $this->setupConfiguredServices($c); |
|||
282 | 19 | $this->setupFormats($c); |
|||
283 | 19 | $this->setupTrustDecisionManager($c); |
|||
284 | 19 | $this->setupExtensions($c); |
|||
285 | |||||
286 | $c[TrustPathValidatorInterface::class] = static function (ServiceContainer $c): TrustPathValidatorInterface { |
||||
287 | 19 | return new TrustPathValidator($c[ChainValidatorInterface::class]); |
|||
288 | }; |
||||
289 | |||||
290 | 19 | if ($this->enableCrl) { |
|||
291 | $this->setupCache($c); |
||||
292 | $this->setupDownloader($c); |
||||
293 | $c[CertificateStatusResolverInterface::class] = function (ServiceContainer $c): CertificateStatusResolverInterface { |
||||
294 | return new CrlCertificateStatusResolver($c[DownloaderInterface::class], $c[CacheProviderInterface::class], $this->crlSilentFailure); |
||||
295 | }; |
||||
296 | } else { |
||||
297 | $c[CertificateStatusResolverInterface::class] = static function (): CertificateStatusResolverInterface { |
||||
298 | 19 | return new NullCertificateStatusResolver(); |
|||
299 | }; |
||||
300 | } |
||||
301 | |||||
302 | $c[ChainValidatorInterface::class] = function (ServiceContainer $c): ChainValidatorInterface { |
||||
303 | 19 | return new ChainValidator($c[CertificateStatusResolverInterface::class]); |
|||
304 | }; |
||||
305 | |||||
306 | 19 | $c[PolicyInterface::class] = Closure::fromCallable([$this, 'createPolicy']); |
|||
307 | 19 | $c[MetadataResolverInterface::class] = Closure::fromCallable([$this, 'createMetadataResolver']); |
|||
308 | 19 | $c[ServerInterface::class] = Closure::fromCallable([$this, 'createServer']); |
|||
309 | |||||
310 | 19 | return $c; |
|||
311 | } |
||||
312 | |||||
313 | private function setupDownloader(ServiceContainer $c): void |
||||
314 | { |
||||
315 | $this->setupCache($c); |
||||
316 | if (isset($c[DownloaderInterface::class])) { |
||||
317 | return; |
||||
318 | } |
||||
319 | $c[DownloaderInterface::class] = static function (ServiceContainer $c): DownloaderInterface { |
||||
320 | return new Downloader($c[Client::class]); |
||||
321 | }; |
||||
322 | $c[Client::class] = static function (ServiceContainer $c): Client { |
||||
323 | $factory = new CachingClientFactory($c[CacheProviderInterface::class]); |
||||
324 | return $factory->createClient(); |
||||
325 | }; |
||||
326 | } |
||||
327 | |||||
328 | private function setupCache(ServiceContainer $c): void |
||||
329 | { |
||||
330 | if (isset($c[CacheProviderInterface::class])) { |
||||
331 | return; |
||||
332 | } |
||||
333 | |||||
334 | $cacheDir = $this->cacheDir; |
||||
335 | if ($cacheDir === null) { |
||||
336 | throw new ConfigurationException('No cache directory configured. Use useCacheDirectory or useSystemTempCache.'); |
||||
337 | } |
||||
338 | $c[CacheProviderInterface::class] = static function (ServiceContainer $c) use ($cacheDir): CacheProviderInterface { |
||||
0 ignored issues
–
show
|
|||||
339 | return new FileCacheProvider($cacheDir); |
||||
340 | }; |
||||
341 | } |
||||
342 | |||||
343 | 19 | private function setupConfiguredServices(ServiceContainer $c): void |
|||
344 | { |
||||
345 | 19 | if ($this->rp === null) { |
|||
346 | throw new ConfigurationException('Relying party not configured. Use setRelyingParty.'); |
||||
347 | } |
||||
348 | |||||
349 | $c[RelyingPartyInterface::class] = function (): RelyingPartyInterface { return $this->rp; }; |
||||
0 ignored issues
–
show
|
|||||
350 | |||||
351 | 19 | if ($this->store === null) { |
|||
352 | throw new ConfigurationException('Credential store not configured. Use setCredentialStore.'); |
||||
353 | } |
||||
354 | |||||
355 | $c[CredentialStoreInterface::class] = function (): CredentialStoreInterface { return $this->store; }; |
||||
0 ignored issues
–
show
|
|||||
356 | $c[LoggerInterface::class] = function (): LoggerInterface { return $this->logger ?? new NullLogger(); }; |
||||
357 | 19 | } |
|||
358 | |||||
359 | 19 | private function createPolicy(ServiceContainer $c): PolicyInterface |
|||
0 ignored issues
–
show
The parameter
$c is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
360 | { |
||||
361 | 19 | $policy = new Policy(); |
|||
362 | |||||
363 | 19 | if ($this->policyCallback !== null) { |
|||
364 | ($this->policyCallback)($policy); |
||||
365 | } |
||||
366 | |||||
367 | 19 | return $policy; |
|||
368 | } |
||||
369 | |||||
370 | 19 | private function createServer(ServiceContainer $c): ServerInterface |
|||
371 | { |
||||
372 | 19 | return new WebAuthnServer( |
|||
373 | 19 | $c[RelyingPartyInterface::class], |
|||
374 | 19 | $c[PolicyInterface::class], |
|||
375 | 19 | $c[CredentialStoreInterface::class], |
|||
376 | 19 | $c[AttestationFormatRegistryInterface::class], |
|||
377 | 19 | $c[MetadataResolverInterface::class], |
|||
378 | 19 | $c[TrustDecisionManagerInterface::class], |
|||
379 | 19 | $c[ExtensionRegistryInterface::class]); |
|||
380 | } |
||||
381 | |||||
382 | public function addMetadataSource(MetadataSourceInterface $metadataSource): self |
||||
383 | { |
||||
384 | $this->metadataSources[] = $metadataSource; |
||||
385 | return $this; |
||||
386 | } |
||||
387 | |||||
388 | public function addBundledMetadataSource(array $sets = ['@all']): self |
||||
389 | { |
||||
390 | $this->metadataSources[] = new BundledSource($sets); |
||||
391 | return $this; |
||||
392 | } |
||||
393 | |||||
394 | 19 | private function createMetadataResolver(ServiceContainer $c): MetadataResolverInterface |
|||
395 | { |
||||
396 | 19 | if (count($this->metadataSources) === 0) { |
|||
397 | 19 | return new NullMetadataResolver(); |
|||
398 | } |
||||
399 | return new MetadataResolver($this->createMetadataProviders($c)); |
||||
400 | } |
||||
401 | |||||
402 | 19 | private function setupTrustDecisionManager(ServiceContainer $c): void |
|||
403 | { |
||||
404 | $c[TrustDecisionManagerInterface::class] = function (ServiceContainer $c): TrustDecisionManagerInterface { |
||||
405 | 19 | $tdm = new TrustDecisionManager(); |
|||
406 | |||||
407 | 19 | if ($this->allowNoneAttestation) { |
|||
408 | 19 | $tdm->addVoter(new Voter\TrustAttestationTypeVoter(AttestationType::NONE)); |
|||
409 | } |
||||
410 | 19 | if ($this->allowSelfAttestation) { |
|||
411 | 19 | $tdm->addVoter(new Voter\TrustAttestationTypeVoter(AttestationType::SELF)); |
|||
412 | } |
||||
413 | 19 | if ($this->trustWithoutMetadata) { |
|||
414 | 19 | $tdm->addVoter(new Voter\AllowEmptyMetadataVoter()); |
|||
415 | } |
||||
416 | 19 | if ($this->validateUsingMetadata) { |
|||
417 | 19 | $tdm->addVoter(new Voter\SupportedAttestationTypeVoter()); |
|||
418 | 19 | $tdm->addVoter(new Voter\UndesiredStatusReportVoter()); |
|||
419 | 19 | $tdm->addVoter(new Voter\TrustChainVoter($c[TrustPathValidatorInterface::class])); |
|||
420 | } |
||||
421 | 19 | return $tdm; |
|||
422 | }; |
||||
423 | 19 | } |
|||
424 | |||||
425 | private function createMetadataProviders(ServiceContainer $c): array |
||||
426 | { |
||||
427 | $providers = []; |
||||
428 | foreach ($this->metadataSources as $source) { |
||||
429 | // TODO: More elegant solution than if/else |
||||
430 | if ($source instanceof StatementDirectorySource) { |
||||
431 | $providers[] = new FileProvider($source); |
||||
432 | } elseif ($source instanceof MetadataServiceSource) { |
||||
433 | $this->setupDownloader($c); |
||||
434 | $providers[] = new MetadataServiceProvider($source, $c[DownloaderInterface::class], $c[CacheProviderInterface::class], $c[ChainValidatorInterface::class]); |
||||
435 | } elseif ($source instanceof BundledSource) { |
||||
436 | $providers = array_merge( |
||||
437 | $providers, |
||||
438 | $source->createProviders() |
||||
439 | ); |
||||
440 | } else { |
||||
441 | throw new UnsupportedException(sprintf('No provider available for metadata source of type %s.', get_class($source))); |
||||
442 | } |
||||
443 | } |
||||
444 | |||||
445 | foreach ($providers as $provider) { |
||||
446 | if ($provider instanceof LoggerAwareInterface) { |
||||
447 | $this->assignLogger($provider); |
||||
448 | } |
||||
449 | } |
||||
450 | return $providers; |
||||
451 | } |
||||
452 | |||||
453 | 19 | private function setupFormats(ServiceContainer $c): void |
|||
454 | { |
||||
455 | $c[Verifier\PackedAttestationVerifier::class] = static function (): Verifier\PackedAttestationVerifier { |
||||
456 | 19 | return new Verifier\PackedAttestationVerifier(); |
|||
457 | }; |
||||
458 | $c[Verifier\FidoU2fAttestationVerifier::class] = static function (): Verifier\FidoU2fAttestationVerifier { |
||||
459 | 19 | return new Verifier\FidoU2fAttestationVerifier(); |
|||
460 | }; |
||||
461 | $c[Verifier\NoneAttestationVerifier::class] = static function (): Verifier\NoneAttestationVerifier { |
||||
462 | 19 | return new Verifier\NoneAttestationVerifier(); |
|||
463 | }; |
||||
464 | $c[Verifier\TpmAttestationVerifier::class] = static function (): Verifier\TpmAttestationVerifier { |
||||
465 | 19 | return new Verifier\TpmAttestationVerifier(); |
|||
466 | }; |
||||
467 | $c[Verifier\AndroidSafetyNetAttestationVerifier::class] = static function (): Verifier\AndroidSafetyNetAttestationVerifier { |
||||
468 | 19 | return new Verifier\AndroidSafetyNetAttestationVerifier(); |
|||
469 | }; |
||||
470 | $c[Verifier\AndroidKeyAttestationVerifier::class] = static function (): Verifier\AndroidKeyAttestationVerifier { |
||||
471 | 19 | return new Verifier\AndroidKeyAttestationVerifier(); |
|||
472 | }; |
||||
473 | $c[Verifier\AppleAttestationVerifier::class] = static function (): Verifier\AppleAttestationVerifier { |
||||
474 | 19 | return new Verifier\AppleAttestationVerifier(); |
|||
475 | }; |
||||
476 | |||||
477 | $c[AttestationFormatRegistryInterface::class] = function (ServiceContainer $c): AttestationFormatRegistryInterface { |
||||
478 | 19 | $registry = new AttestationFormatRegistry(); |
|||
479 | |||||
480 | 19 | $registry->strictSupportedFormats($this->strictSupportedFormats); |
|||
481 | |||||
482 | 19 | $registry->addFormat($c[Verifier\PackedAttestationVerifier::class]->getSupportedFormat()); |
|||
483 | 19 | $registry->addFormat($c[Verifier\FidoU2fAttestationVerifier::class]->getSupportedFormat()); |
|||
484 | 19 | $registry->addFormat($c[Verifier\NoneAttestationVerifier::class]->getSupportedFormat()); |
|||
485 | 19 | $registry->addFormat($c[Verifier\TpmAttestationVerifier::class]->getSupportedFormat()); |
|||
486 | 19 | $registry->addFormat($c[Verifier\AndroidSafetyNetAttestationVerifier::class]->getSupportedFormat()); |
|||
487 | 19 | $registry->addFormat($c[Verifier\AndroidKeyAttestationVerifier::class]->getSupportedFormat()); |
|||
488 | 19 | $registry->addFormat($c[Verifier\AppleAttestationVerifier::class]->getSupportedFormat()); |
|||
489 | |||||
490 | 19 | return $registry; |
|||
491 | }; |
||||
492 | 19 | } |
|||
493 | |||||
494 | 19 | private function setupExtensions(ServiceContainer $c): void |
|||
495 | { |
||||
496 | $c[AppIdExtension::class] = static function (ServiceContainer $c): AppIdExtension { |
||||
0 ignored issues
–
show
The parameter
$c is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
497 | return new AppIdExtension(); |
||||
498 | }; |
||||
499 | $c[ExtensionRegistryInterface::class] = function (ServiceContainer $c): ExtensionRegistryInterface { |
||||
500 | 19 | $registry = new ExtensionRegistry(); |
|||
501 | 19 | foreach (array_unique($this->enabledExtensions) as $ext) { |
|||
502 | $registry->addExtension($c[self::SUPPORTED_EXTENSIONS[$ext]]); |
||||
503 | } |
||||
504 | 19 | foreach ($this->customExtensions as $ext) { |
|||
505 | $registry->addExtension($ext); |
||||
506 | } |
||||
507 | 19 | return $registry; |
|||
508 | }; |
||||
509 | 19 | } |
|||
510 | } |
||||
511 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.