Passed
Pull Request — master (#778)
by
unknown
08:24
created

WhatsAppCloudApiConfigurationController::isAdmin()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 6
rs 10
cc 2
nc 2
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7
 * SPDX-License-Identifier: AGPL-3.0-or-later
8
 */
9
10
namespace OCA\TwoFactorGateway\Controller;
11
12
use OCA\TwoFactorGateway\Provider\Channel\WhatsApp\Drivers\CloudApiDriver;
13
use OCP\AppFramework\Controller;
14
use OCP\AppFramework\Http\Attribute\ApiRoute;
15
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
16
use OCP\AppFramework\Http\DataResponse;
17
use OCP\Http\Client\IClientService;
18
use OCP\IAppConfig;
19
use OCP\IGroupManager;
20
use OCP\IRequest;
21
use OCP\IUserSession;
22
use OCP\Security\ISecureRandom;
23
use OCP\Util;
24
use Psr\Log\LoggerInterface;
25
26
class WhatsAppCloudApiConfigurationController extends Controller {
27
	public function __construct(
28
		IRequest $request,
29
		private IAppConfig $appConfig,
30
		private IClientService $clientService,
31
		private LoggerInterface $logger,
32
		private ISecureRandom $secureRandom,
33
		private IUserSession $userSession,
34
		private IGroupManager $groupManager,
35
	) {
36
		parent::__construct('twofactor_gateway', $request);
37
	}
38
39
	/**
40
	 * Get current WhatsApp Cloud API configuration
41
	 *
42
	 * @return DataResponse
43
	 */
44
	#[ApiRoute(verb: 'GET', url: '/api/v1/whatsapp/configuration')]
45
	public function getConfiguration(): DataResponse {
46
		try {
47
			// Only admin can access
48
			if (!$this->isAdmin()) {
49
				return new DataResponse(['message' => 'Unauthorized'], 403);
50
			}
51
52
			$config = [
53
				'phone_number_id' => $this->appConfig->getValueString('twofactor_gateway', 'whatsapp_cloud_phone_number_id', ''),
54
				'phone_number_fb' => $this->appConfig->getValueString('twofactor_gateway', 'whatsapp_cloud_phone_number_fb', ''),
55
				'business_account_id' => $this->appConfig->getValueString('twofactor_gateway', 'whatsapp_cloud_business_account_id', ''),
56
				'api_key' => '', // Never send API key to frontend
57
				'api_endpoint' => $this->appConfig->getValueString('twofactor_gateway', 'whatsapp_cloud_api_endpoint', ''),
58
			];
59
60
			return new DataResponse($config, 200);
61
		} catch (\Exception $e) {
62
			$this->logger->error('Error retrieving WhatsApp configuration', ['exception' => $e]);
63
			return new DataResponse(['message' => 'Error retrieving configuration'], 500);
64
		}
65
	}
66
67
	/**
68
	 * Save WhatsApp Cloud API configuration
69
	 *
70
	 * @return DataResponse
71
	 */
72
	#[ApiRoute(verb: 'POST', url: '/api/v1/whatsapp/configuration')]
73
	public function saveConfiguration(
74
		string $phone_number_id = '',
75
		string $phone_number_fb = '',
76
		string $business_account_id = '',
77
		string $api_key = '',
78
		string $api_endpoint = '',
79
	): DataResponse {
80
		try {
81
			// Only admin can access
82
			if (!$this->isAdmin()) {
83
				return new DataResponse(['message' => 'Unauthorized'], 403);
84
			}
85
86
		// Validate required fields (api_key is optional - only save if provided)
87
		if (empty($phone_number_id) || empty($business_account_id)) {
88
			return new DataResponse([
89
				'message' => 'Phone Number ID and Business Account ID are required',
90
			], 400);
91
		}
92
93
		// Store configuration
94
		$this->appConfig->setValueString('twofactor_gateway', 'whatsapp_cloud_phone_number_id', $phone_number_id);
95
		$this->appConfig->setValueString('twofactor_gateway', 'whatsapp_cloud_phone_number_fb', $phone_number_fb);
96
		$this->appConfig->setValueString('twofactor_gateway', 'whatsapp_cloud_business_account_id', $business_account_id);
97
		if (!empty($api_key)) {
98
			$this->appConfig->setValueString('twofactor_gateway', 'whatsapp_cloud_api_key', $api_key);
99
		}
100
		$this->appConfig->setValueString('twofactor_gateway', 'whatsapp_cloud_api_endpoint', $api_endpoint ?: 'https://graph.facebook.com');
101
102
			$this->logger->info('WhatsApp Cloud API configuration saved');
103
104
			return new DataResponse(['message' => 'Configuration saved successfully'], 200);
105
		} catch (\Exception $e) {
106
			$this->logger->error('Error saving WhatsApp configuration', ['exception' => $e]);
107
			return new DataResponse(['message' => 'Error saving configuration'], 500);
108
		}
109
	}
110
111
	/**
112
	 * Test WhatsApp Cloud API connection
113
	 *
114
	 * @return DataResponse
115
	 */
116
	#[ApiRoute(verb: 'POST', url: '/api/v1/whatsapp/test')]
117
	public function testConfiguration(
118
		string $phone_number_id = '',
119
		string $phone_number_fb = '',
0 ignored issues
show
Unused Code introduced by
The parameter $phone_number_fb 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 ignore-unused  annotation

119
		/** @scrutinizer ignore-unused */ string $phone_number_fb = '',

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
120
		string $business_account_id = '',
121
		string $api_key = '',
122
		string $api_endpoint = '',
123
	): DataResponse {
124
		try {
125
			// Only admin can access
126
			if (!$this->isAdmin()) {
127
				return new DataResponse(['message' => 'Unauthorized'], 403);
128
			}
129
130
		// Validate required fields (api_key is optional - use stored key if not provided)
131
		if (empty($phone_number_id) || empty($business_account_id)) {
132
			return new DataResponse([
133
				'message' => 'Phone Number ID and Business Account ID are required',
134
			], 400);
135
		}
136
137
		// Use provided api_key or fall back to stored key
138
		if (empty($api_key)) {
139
			$api_key = $this->appConfig->getValueString('twofactor_gateway', 'whatsapp_cloud_api_key', '');
140
		}
141
142
		if (empty($api_key)) {
143
			return new DataResponse([
144
				'message' => 'API Key is required',
145
			], 400);
146
		}
147
148
		$endpoint = $api_endpoint ?: 'https://graph.facebook.com';
149
		$client = $this->clientService->newClient();
150
151
		// Test the connection by getting phone number information
152
		$url = sprintf('%s/v14.0/%s', rtrim($endpoint, '/'), $phone_number_id);
153
154
			try {
155
				$response = $client->get($url, [
156
					'headers' => [
157
						'Authorization' => "Bearer $api_key",
158
					],
159
				]);
160
161
				if ($response->getStatusCode() === 200) {
162
					$this->logger->info('WhatsApp Cloud API connection test successful');
163
					return new DataResponse(['message' => 'Connection test successful'], 200);
164
				}
165
166
				return new DataResponse([
167
					'message' => 'Connection test failed with status ' . $response->getStatusCode(),
168
				], 400);
169
			} catch (\Exception $e) {
170
				$this->logger->error('WhatsApp Cloud API connection test failed', ['exception' => $e]);
171
				return new DataResponse([
172
					'message' => 'Connection test failed: ' . $e->getMessage(),
173
				], 400);
174
			}
175
		} catch (\Exception $e) {
176
			$this->logger->error('Error testing WhatsApp configuration', ['exception' => $e]);
177
			return new DataResponse(['message' => 'Error testing configuration'], 500);
178
		}
179
	}
180
181
	/**
182
	 * Get WhatsApp webhook credentials
183
	 *
184
	 * @return DataResponse
185
	 */
186
	#[ApiRoute(verb: 'GET', url: '/api/v1/whatsapp/webhook-credentials')]
187
	public function getWebhookCredentials(): DataResponse {
188
		try {
189
			// Only admin can access
190
			if (!$this->isAdmin()) {
191
				return new DataResponse(['message' => 'Unauthorized'], 403);
192
			}
193
194
			// Generate verification token if not exists
195
			$token = $this->appConfig->getValueString('twofactor_gateway', 'whatsapp_cloud_verify_token', '');
196
			if (empty($token)) {
197
				$token = $this->secureRandom->generate(32, 'abcdefghijklmnopqrstuvwxyz0123456789');
198
				$this->appConfig->setValueString('twofactor_gateway', 'whatsapp_cloud_verify_token', $token);
199
			}
200
201
			// Build webhook URL
202
			$baseUrl = \OC::$server->getConfig()->getSystemValue('overwrite.cli.url') ?: \OC::$server->getConfig()->getSystemValue('url');
203
			$webhookUrl = rtrim($baseUrl, '/') . '/ocs/v2.php/apps/twofactor_gateway/api/v1/webhooks/whatsapp';
204
205
			return new DataResponse([
206
				'webhook_url' => $webhookUrl,
207
				'verify_token' => $token,
208
			], 200);
209
		} catch (\Exception $e) {
210
			$this->logger->error('Error retrieving WhatsApp webhook credentials', ['exception' => $e]);
211
			return new DataResponse(['message' => 'Error retrieving webhook credentials'], 500);
212
		}
213
	}
214
215
	/**
216
	 * Check if current user is admin
217
	 */
218
	private function isAdmin(): bool {
219
		$user = $this->userSession->getUser();
220
		if ($user === null) {
221
			return false;
222
		}
223
		return $this->groupManager->isAdmin($user->getUID());
224
	}
225
}
226