Bot::send()   A
last analyzed

Complexity

Conditions 5
Paths 20

Size

Total Lines 40
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 29
c 2
b 0
f 1
dl 0
loc 40
ccs 0
cts 31
cp 0
rs 9.1448
cc 5
nc 20
nop 3
crap 30
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * SPDX-FileCopyrightText: 2024 Christoph Wurst <[email protected]>
7
 * SPDX-License-Identifier: AGPL-3.0-or-later
8
 */
9
10
namespace OCA\TwoFactorGateway\Provider\Channel\Telegram\Provider\Drivers;
11
12
use OCA\TwoFactorGateway\Exception\MessageTransmissionException;
13
use OCA\TwoFactorGateway\Provider\Channel\Telegram\Provider\AProvider;
14
use OCA\TwoFactorGateway\Provider\FieldDefinition;
15
use OCA\TwoFactorGateway\Provider\Settings;
16
use OCP\Http\Client\IClientService;
17
use OCP\IL10N;
18
use Psr\Log\LoggerInterface;
19
use RuntimeException;
20
use Symfony\Component\Console\Helper\QuestionHelper;
21
use Symfony\Component\Console\Input\InputInterface;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Component\Console\Question\Question;
24
25
/**
26
 * @method string getToken()
27
 * @method static setToken(string $token)
28
 */
29
class Bot extends AProvider {
30
	private const TELEGRAM_API_URL = 'https://api.telegram.org/bot';
31
32 1
	public function __construct(
33
		private LoggerInterface $logger,
34
		private IL10N $l10n,
35
		private IClientService $clientService,
36
	) {
37 1
	}
38
39 1
	public function createSettings() {
40 1
		return new Settings(
41 1
			id: 'telegram_bot',
42 1
			name: 'Telegram Bot',
43 1
			allowMarkdown: true,
44 1
			instructions: <<<HTML
45
				<p>In order to receive authentication codes via Telegram, you first
46
				have to start a new chat with the bot set up by your admin.</p>
47
				<p>Secondly, you have to obtain your Telegram ID via the
48
				<a href="https://telegram.me/getmyid_bot" target="_blank" rel="noreferrer noopener">ID Bot</a>.</p>
49
				<p>Enter this ID to receive your verification code below.</p>
50 1
				HTML,
51 1
			fields: [
52 1
				new FieldDefinition(
53 1
					field: 'token',
54 1
					prompt: 'Please enter your Telegram bot token:',
55 1
				),
56 1
			]
57 1
		);
58
	}
59
60
	#[\Override]
61
	public function send(string $identifier, string $message, array $extra = []): void {
62
		if (empty($message)) {
63
			$message = $this->l10n->t('`%s` is your Nextcloud verification code.', [$extra['code']]);
64
		}
65
		$this->logger->debug("sending telegram message to $identifier, message: $message");
66
		$token = $this->getToken();
67
		$this->logger->debug("telegram bot token: $token");
68
69
		$url = self::TELEGRAM_API_URL . $token . '/sendMessage';
70
		$params = [
71
			'chat_id' => $identifier,
72
			'text' => $message,
73
			'parse_mode' => 'markdown',
74
		];
75
76
		$this->logger->debug("sending telegram message to $identifier");
77
		try {
78
			$client = $this->clientService->newClient();
79
			$response = $client->post($url, [
80
				'json' => $params,
81
				'timeout' => 10,
82
			]);
83
84
			$body = $response->getBody();
85
			$data = json_decode($body, true);
0 ignored issues
show
Bug introduced by
It seems like $body can also be of type null and resource; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

85
			$data = json_decode(/** @scrutinizer ignore-type */ $body, true);
Loading history...
86
87
			if (!isset($data['ok']) || $data['ok'] !== true) {
88
				$errorDescription = $data['description'] ?? 'Unknown error';
89
				$this->logger->error('Telegram API error: ' . $errorDescription);
90
				throw new MessageTransmissionException('Telegram API error: ' . $errorDescription);
91
			}
92
93
			$this->logger->debug("telegram message to chat $identifier sent");
94
		} catch (RuntimeException $e) {
95
			$this->logger->error('Failed to send Telegram message', [
96
				'exception' => $e,
97
				'chat_id' => $identifier,
98
			]);
99
			throw new MessageTransmissionException('Failed to send Telegram message: ' . $e->getMessage(), 0, $e);
100
		}
101
	}
102
103
	#[\Override]
104
	public function cliConfigure(InputInterface $input, OutputInterface $output): int {
105
		$helper = new QuestionHelper();
106
		$settings = $this->getSettings();
107
		$tokenQuestion = new Question($settings->fields[0]->prompt . ' ');
108
		$token = $helper->ask($input, $output, $tokenQuestion);
109
		$this->setToken($token);
110
		$output->writeln("Using $token.");
111
		return 0;
112
	}
113
}
114