This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | /* |
||||
6 | * Copyright (C) 2020-2025 Iain Cambridge |
||||
7 | * |
||||
8 | * This program is free software: you can redistribute it and/or modify |
||||
9 | * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by |
||||
10 | * the Free Software Foundation, either version 2.1 of the License, or |
||||
11 | * (at your option) any later version. |
||||
12 | * |
||||
13 | * This program is distributed in the hope that it will be useful, |
||||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
16 | * GNU Lesser General Public License for more details. |
||||
17 | * |
||||
18 | * You should have received a copy of the GNU General Public License |
||||
19 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
20 | */ |
||||
21 | |||||
22 | namespace Parthenon\DependencyInjection\Modules; |
||||
23 | |||||
24 | use Parthenon\Billing\Athena\CustomerTeamSection; |
||||
25 | use Parthenon\Billing\Athena\CustomerUserSection; |
||||
26 | use Parthenon\Billing\BillaBear\Webhook\ProcessorInterface; |
||||
27 | use Parthenon\Billing\CustomerProviderInterface; |
||||
28 | use Parthenon\Billing\Plan\CachedPlanManager; |
||||
29 | use Parthenon\Billing\Plan\CounterInterface; |
||||
30 | use Parthenon\Billing\Plan\PlanManager; |
||||
31 | use Parthenon\Billing\Plan\PlanManagerInterface; |
||||
32 | use Parthenon\Billing\Repository\CustomerRepositoryInterface; |
||||
33 | use Parthenon\Billing\TeamCustomerProvider; |
||||
34 | use Parthenon\Billing\UserCustomerProvider; |
||||
35 | use Parthenon\Billing\Webhook\HandlerInterface; |
||||
36 | use Parthenon\Common\Exception\ParameterNotSetException; |
||||
37 | use Parthenon\User\Repository\TeamRepositoryInterface; |
||||
38 | use Parthenon\User\Repository\UserRepositoryInterface; |
||||
39 | use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; |
||||
40 | use Symfony\Component\Config\Definition\Builder\NodeBuilder; |
||||
41 | use Symfony\Component\Config\Definition\Builder\NodeDefinition; |
||||
42 | use Symfony\Component\Config\Definition\Builder\TreeBuilder; |
||||
43 | use Symfony\Component\Config\FileLocator; |
||||
44 | use Symfony\Component\DependencyInjection\ContainerBuilder; |
||||
45 | use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; |
||||
46 | |||||
47 | class Billing implements ModuleConfigurationInterface |
||||
48 | { |
||||
49 | public function addConfig(NodeBuilder $nodeBuilder): void |
||||
50 | { |
||||
51 | $nodeBuilder->arrayNode('billing') |
||||
52 | ->children() |
||||
53 | ->booleanNode('enabled')->defaultFalse()->end() |
||||
54 | ?->scalarNode('customer_type')->defaultValue('team')->end() |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
55 | ?->scalarNode('plan_management')->defaultValue('config')->end() |
||||
56 | ?->arrayNode('billabear') |
||||
57 | ->children() |
||||
58 | ->booleanNode('enabled')->defaultFalse()->end() |
||||
59 | ->scalarNode('api_url')->end() |
||||
60 | ->scalarNode('api_key')->end() |
||||
61 | ->end() |
||||
62 | ->end() |
||||
63 | ?->arrayNode('payments') |
||||
64 | ->children() |
||||
65 | ->scalarNode('provider')->end() |
||||
66 | ?->booleanNode('pci_mode')->end() |
||||
67 | ?->scalarNode('return_url')->end() |
||||
68 | ?->scalarNode('cancel_url')->end() |
||||
69 | ?->arrayNode('adyen') |
||||
70 | ->children() |
||||
71 | ->scalarNode('api_key')->end() |
||||
72 | ?->scalarNode('merchant_account')->end() |
||||
73 | ?->booleanNode('test_mode')->end() |
||||
74 | ?->scalarNode('webhook_secret')->end() |
||||
75 | ?->scalarNode('prefix')->end() |
||||
76 | ?->scalarNode('cse_url')->end() |
||||
77 | ?->end() |
||||
78 | ->end() |
||||
79 | ?->arrayNode('stripe') |
||||
80 | ->children() |
||||
81 | ->scalarNode('private_api_key')->end() |
||||
82 | ->scalarNode('webhook_secret')->end() |
||||
83 | ?->scalarNode('public_api_key')->end() |
||||
84 | ?->scalarNode('product_id')->end() |
||||
85 | ?->arrayNode('payment_methods') |
||||
86 | ->scalarPrototype()->end() |
||||
87 | ?->end() |
||||
88 | ->end() |
||||
89 | ->end() |
||||
90 | ->end() |
||||
91 | ->end() |
||||
92 | ->end() |
||||
93 | ->fixXmlConfig('plans') |
||||
94 | ->append($this->getPlansNode()) |
||||
95 | ?->end(); |
||||
96 | } |
||||
97 | |||||
98 | public function handleDefaultParameters(ContainerBuilder $container): void |
||||
99 | { |
||||
100 | $container->setParameter('parthenon_billing_payments_obol_config', []); |
||||
101 | $container->setParameter('parthenon_billing_customer_type', 'team'); |
||||
102 | $container->setParameter('parthenon_billing_config_frontend_info', ''); |
||||
103 | $container->setParameter('parthenon_billing_config_webhook_secret', ''); |
||||
104 | $container->setParameter('parthenon_billing_plan_plans', []); |
||||
105 | $container->setParameter('parthenon_billing_product_id', null); |
||||
106 | $container->setParameter('parthenon_billing_billabear_enabled', false); |
||||
107 | $container->setParameter('parthenon_billing_billabear_api_url', false); |
||||
108 | $container->setParameter('parthenon_billing_billabear_api_key', false); |
||||
109 | } |
||||
110 | |||||
111 | public function handleConfiguration(array $config, ContainerBuilder $container): void |
||||
112 | { |
||||
113 | if (!isset($config['billing']) || !isset($config['billing']['enabled']) || false === $config['billing']['enabled']) { |
||||
114 | return; |
||||
115 | } |
||||
116 | |||||
117 | $container->registerForAutoconfiguration(CounterInterface::class)->addTag('parthenon.billing.plan.counter'); |
||||
118 | $container->registerForAutoconfiguration(HandlerInterface::class)->addTag('parthenon.billing.webhooks.handler'); |
||||
119 | $container->registerForAutoconfiguration(ProcessorInterface::class)->addTag('parthenon.billing.billabear.webhooks.handler'); |
||||
120 | |||||
121 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../../Resources/config')); |
||||
122 | $loader->load('services/billing.xml'); |
||||
123 | $loader->load('services/orm/billing.xml'); |
||||
124 | |||||
125 | $billingConfig = $config['billing']; |
||||
126 | $paymentsConfig = $billingConfig['payments']; |
||||
127 | |||||
128 | if ('team' === strtolower($billingConfig['customer_type'])) { |
||||
129 | $this->handleTeamCustomer($config, $container); |
||||
130 | } elseif ('user' === strtolower($billingConfig['customer_type'])) { |
||||
131 | $this->handleUserCustomer($config, $container); |
||||
132 | } |
||||
133 | |||||
134 | if (isset($billingConfig['billabear']) && $billingConfig['billabear']['enabled']) { |
||||
135 | $loader->load('services/billing/billabear.xml'); |
||||
136 | $container->setAlias(PlanManagerInterface::class, CachedPlanManager::class); |
||||
137 | $this->handleBillaBearConfig($billingConfig['billabear'], $container); |
||||
138 | $container->setParameter('parthenon_billing_enabled', false); |
||||
139 | } elseif ('athena' === strtolower($billingConfig['plan_management'])) { |
||||
140 | $container->setParameter('parthenon_billing_enabled', true); |
||||
141 | $loader->load('services/billing/athena_plans.xml'); |
||||
142 | $container->setAlias(PlanManagerInterface::class, CachedPlanManager::class); |
||||
143 | } else { |
||||
144 | $container->setParameter('parthenon_billing_enabled', true); |
||||
145 | $container->setAlias(PlanManagerInterface::class, PlanManager::class); |
||||
146 | } |
||||
147 | |||||
148 | $container->setParameter('parthenon_billing_plan_plans', $config['billing']['plan']); |
||||
149 | |||||
150 | $obolConfig = match ($paymentsConfig['provider']) { |
||||
151 | 'stripe' => $this->handleStripeConfig($paymentsConfig, $container), |
||||
152 | 'adyen' => $this->handleAdyen($paymentsConfig, $container), |
||||
153 | 'custom' => [], |
||||
154 | default => throw new ParameterNotSetException('billing.payments.provider must be valid'), |
||||
155 | }; |
||||
156 | |||||
157 | $container->setParameter('parthenon_billing_payments_obol_config', $obolConfig); |
||||
158 | $container->setParameter('parthenon_billing_plan_plans', $config['billing']['plan']); |
||||
159 | } |
||||
160 | |||||
161 | public function buildPricesNode() |
||||
162 | { |
||||
163 | $treeBuilder = new TreeBuilder('prices'); |
||||
164 | $node = $treeBuilder->getRootNode(); |
||||
165 | |||||
166 | $priceNode = $node->requiresAtLeastOneElement() |
||||
0 ignored issues
–
show
The method
requiresAtLeastOneElement() does not exist on Symfony\Component\Config...\Builder\NodeDefinition . It seems like you code against a sub-type of Symfony\Component\Config...\Builder\NodeDefinition such as Symfony\Component\Config...der\ArrayNodeDefinition .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
167 | ->useAttributeAsKey('payment_schedule') |
||||
168 | ->prototype('array'); |
||||
169 | assert($priceNode instanceof ArrayNodeDefinition); |
||||
170 | |||||
171 | $priceNode |
||||
172 | ->arrayPrototype() |
||||
173 | ->children() |
||||
174 | ->scalarNode('amount')->end() |
||||
175 | ->scalarNode('price_id')->end() |
||||
176 | ->booleanNode('public')->defaultTrue()->end() |
||||
177 | ->end() |
||||
178 | ->end() |
||||
179 | ->end(); |
||||
180 | |||||
181 | return $node; |
||||
182 | } |
||||
183 | |||||
184 | protected function handleTeamCustomer(array $config, ContainerBuilder $containerBuilder): void |
||||
0 ignored issues
–
show
The parameter
$config 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. ![]() |
|||||
185 | { |
||||
186 | $containerBuilder->setAlias(CustomerProviderInterface::class, TeamCustomerProvider::class); |
||||
187 | $containerBuilder->setAlias(CustomerRepositoryInterface::class, TeamRepositoryInterface::class); |
||||
188 | $containerBuilder->removeDefinition(CustomerUserSection::class); |
||||
189 | } |
||||
190 | |||||
191 | protected function handleUserCustomer(array $config, ContainerBuilder $containerBuilder): void |
||||
0 ignored issues
–
show
The parameter
$config 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. ![]() |
|||||
192 | { |
||||
193 | $containerBuilder->setAlias(CustomerProviderInterface::class, UserCustomerProvider::class); |
||||
194 | $containerBuilder->setAlias(CustomerRepositoryInterface::class, UserRepositoryInterface::class); |
||||
195 | $containerBuilder->removeDefinition(CustomerTeamSection::class); |
||||
196 | } |
||||
197 | |||||
198 | protected function handleBillaBearConfig(array $billabearConfig, ContainerBuilder $containerBuilder): void |
||||
199 | { |
||||
200 | if (true !== $billabearConfig['enabled']) { |
||||
201 | return; |
||||
202 | } |
||||
203 | |||||
204 | $containerBuilder->setParameter('parthenon_billing_billabear_enabled', true); |
||||
205 | $containerBuilder->setParameter('parthenon_billing_billabear_api_key', $billabearConfig['api_key']); |
||||
206 | $containerBuilder->setParameter('parthenon_billing_billabear_api_url', $billabearConfig['api_url']); |
||||
207 | } |
||||
208 | |||||
209 | protected function handleStripeConfig(array $paymentsConfig, ContainerBuilder $containerBuilder): array |
||||
210 | { |
||||
211 | if (!isset($paymentsConfig['stripe']['private_api_key'])) { |
||||
212 | throw new ParameterNotSetException('billing.payments.stripe.private_api_key must be set.'); |
||||
213 | } |
||||
214 | |||||
215 | $pciMode = false; |
||||
216 | |||||
217 | if (isset($paymentsConfig['pci_mode'])) { |
||||
218 | $pciMode = $paymentsConfig['pci_mode']; |
||||
219 | } |
||||
220 | |||||
221 | $config = [ |
||||
222 | 'provider' => 'stripe', |
||||
223 | 'api_key' => $paymentsConfig['stripe']['private_api_key'], |
||||
224 | 'pci_mode' => $pciMode, |
||||
225 | ]; |
||||
226 | |||||
227 | $containerBuilder->setParameter('parthenon_billing_product_id', $paymentsConfig['stripe']['product_id'] ?? null); |
||||
228 | $containerBuilder->setParameter('parthenon_billing_config_frontend_info', $paymentsConfig['stripe']['public_api_key']); |
||||
229 | $containerBuilder->setParameter('parthenon_billing_config_webhook_secret', $paymentsConfig['stripe']['webhook_secret'] ?? ''); |
||||
230 | |||||
231 | if (isset($paymentsConfig['stripe']['payment_methods'])) { |
||||
232 | $config['payment_methods'] = $paymentsConfig['stripe']['payment_methods']; |
||||
233 | } |
||||
234 | |||||
235 | if (isset($paymentsConfig['return_url'])) { |
||||
236 | $config['success_url'] = $paymentsConfig['return_url']; |
||||
237 | $config['cancel_url'] = $paymentsConfig['return_url']; |
||||
238 | } |
||||
239 | |||||
240 | if (isset($paymentsConfig['cancel_url'])) { |
||||
241 | $config['cancel_url'] = $paymentsConfig['cancel_url']; |
||||
242 | } |
||||
243 | |||||
244 | return $config; |
||||
245 | } |
||||
246 | |||||
247 | protected function handleAdyen(array $paymentsConfig, ContainerBuilder $containerBuilder): array |
||||
248 | { |
||||
249 | if (!isset($paymentsConfig['adyen']['api_key'])) { |
||||
250 | throw new ParameterNotSetException('billing.payments.adyen.api_key must be set.'); |
||||
251 | } |
||||
252 | if (!isset($paymentsConfig['adyen']['merchant_account'])) { |
||||
253 | throw new ParameterNotSetException('billing.payments.adyen.merchant_account must be set.'); |
||||
254 | } |
||||
255 | |||||
256 | $pciMode = false; |
||||
257 | if (isset($paymentsConfig['pci_mode'])) { |
||||
258 | $pciMode = $paymentsConfig['pci_mode']; |
||||
259 | } |
||||
260 | |||||
261 | $testMode = true; |
||||
262 | if (isset($paymentsConfig['adyen']['test_mode'])) { |
||||
263 | $testMode = $paymentsConfig['adyen']['test_mode']; |
||||
264 | } |
||||
265 | |||||
266 | $config = [ |
||||
267 | 'provider' => 'adyen', |
||||
268 | 'api_key' => $paymentsConfig['adyen']['api_key'], |
||||
269 | 'merchant_account' => $paymentsConfig['adyen']['merchant_account'], |
||||
270 | 'pci_mode' => $pciMode, |
||||
271 | 'test_mode' => $testMode, |
||||
272 | ]; |
||||
273 | |||||
274 | if ($paymentsConfig['adyen']['prefix']) { |
||||
275 | $config['prefix'] = $paymentsConfig['adyen']['prefix']; |
||||
276 | } |
||||
277 | |||||
278 | if (isset($paymentsConfig['return_url'])) { |
||||
279 | $config['return_url'] = $paymentsConfig['return_url']; |
||||
280 | } |
||||
281 | |||||
282 | $containerBuilder->setParameter('parthenon_billing_config_frontend_info', $paymentsConfig['adyen']['cse_url']); |
||||
283 | $containerBuilder->setParameter('parthenon_billing_config_webhook_secret', $paymentsConfig['adyen']['webhook_secret'] ?? ''); |
||||
284 | |||||
285 | return $config; |
||||
286 | } |
||||
287 | |||||
288 | private function getPlansNode(): NodeDefinition |
||||
289 | { |
||||
290 | $treeBuilder = new TreeBuilder('plan'); |
||||
291 | $node = $treeBuilder->getRootNode(); |
||||
292 | |||||
293 | /** @var ArrayNodeDefinition $planNode */ |
||||
294 | $planNode = $node |
||||
295 | ->requiresAtLeastOneElement() |
||||
296 | ->useAttributeAsKey('name') |
||||
297 | ->prototype('array'); |
||||
298 | |||||
299 | $planNode |
||||
300 | ->fixXmlConfig('limits') |
||||
301 | ->children() |
||||
302 | ->booleanNode('is_free')->defaultFalse()->end() |
||||
303 | ?->booleanNode('is_per_seat')->defaultFalse()->end() |
||||
0 ignored issues
–
show
The method
booleanNode() does not exist on Symfony\Component\Config...der\NodeParentInterface . It seems like you code against a sub-type of Symfony\Component\Config...der\NodeParentInterface such as Symfony\Component\Config...ion\Builder\NodeBuilder .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
304 | ?->booleanNode('public')->defaultTrue()->end() |
||||
305 | ?->booleanNode('has_trial')->defaultFalse()->end() |
||||
306 | ?->scalarNode('trial_length_days')->defaultValue(0)->end() |
||||
307 | ?->scalarNode('user_count')->end() |
||||
308 | ->arrayNode('features') |
||||
309 | ->scalarPrototype()->end() |
||||
310 | ->end() |
||||
311 | ->arrayNode('limit') |
||||
312 | ->useAttributeAsKey('name') |
||||
313 | ->prototype('array') |
||||
314 | ->children() |
||||
315 | ->integerNode('limit')->end() |
||||
316 | ->scalarNode('description')->end() |
||||
317 | ->end() |
||||
318 | ->end() |
||||
319 | ->end() |
||||
320 | ->append($this->buildPricesNode()) |
||||
321 | ->end(); |
||||
322 | |||||
323 | return $node; |
||||
324 | } |
||||
325 | } |
||||
326 |