Passed
Pull Request — master (#671)
by Vitor
04:29
created

Client::cliConfigure()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 38
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 3
Bugs 2 Features 2
Metric Value
eloc 26
c 3
b 2
f 2
dl 0
loc 38
ccs 0
cts 26
cp 0
rs 9.504
cc 2
nc 2
nop 2
crap 6
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\AppInfo\Application;
13
use OCA\TwoFactorGateway\Exception\MessageTransmissionException;
14
use OCA\TwoFactorGateway\Provider\Channel\Telegram\Provider\AProvider;
15
use OCP\Files\IAppData;
16
use OCP\Files\NotFoundException;
17
use OCP\IConfig;
18
use OCP\IL10N;
19
use Psr\Log\LoggerInterface;
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 getBotToken()
27
 * @method static setBotToken(string $botToken)
28
 * @method string getApiId()
29
 * @method static setApiId(string $apiId)
30
 * @method string getApiHash()
31
 * @method static setApiHash(string $apiHash)
32
 */
33
class Client extends AProvider {
34
	public const SCHEMA = [
35
		'id' => 'telegram_client',
36
		'name' => 'Telegram Client API',
37
		'allow_markdown' => true,
38
		'instructions' => <<<HTML
39
			<p>Enter your Telegram number or username to receive your verification code below.</p>
40
			HTML,
41
		'fields' => [
42
			['field' => 'api_id', 'prompt' => 'Please enter your Telegram api_id:'],
43
			['field' => 'api_hash', 'prompt' => 'Please enter your Telegram api_hash:'],
44
		],
45
	];
46
	public function __construct(
47
		private LoggerInterface $logger,
48
		private IL10N $l10n,
49
		private IAppData $appData,
50
		private IConfig $config,
51
	) {
52
	}
53
54
	#[\Override]
55
	public function send(string $identifier, string $message, array $extra = []): void {
56
		$this->logger->debug("sending telegram message to $identifier, message: $message");
57
58
		$sessionFile = $this->getSessionDirectory();
59
60
		putenv('TELEGRAM_API_ID=' . $this->getApiId());
61
		putenv('TELEGRAM_API_HASH=' . $this->getApiHash());
62
63
		$path = realpath(__DIR__ . '/ClientCli/Cli.php');
64
		$cmd = 'php ' . escapeshellarg($path) . ' '
65
			. 'telegram:send-message '
66
			. '--session-directory ' . escapeshellarg($sessionFile)
67
			. ' --to ' . escapeshellarg($identifier)
68
			. ' --message ' . escapeshellarg($message);
69
70
		exec($cmd, $output, $returnVar);
71
72
		if ($returnVar !== 0) {
73
			$this->logger->error('Error sending Telegram message', ['output' => $output, 'returnVar' => $returnVar]);
74
			throw new MessageTransmissionException();
75
		}
76
77
		$this->logger->debug("telegram message to chat $identifier sent");
78
	}
79
80
	#[\Override]
81
	public function cliConfigure(InputInterface $input, OutputInterface $output): int {
82
		if (PHP_VERSION_ID < 80200) {
83
			$output->writeln('The Telegram Client API provider requires PHP 8.2 or higher.');
84
			return 1;
85
		}
86
87
		$telegramApiQuestion = new Question('Please enter your api_id (get one at https://my.telegram.org/apps): ');
88
		$helper = new QuestionHelper();
89
		$apiId = $helper->ask($input, $output, $telegramApiQuestion);
90
		$apiHashQuestion = new Question('Please enter your api_hash (get one at https://my.telegram.org/apps): ');
91
		$apiHash = $helper->ask($input, $output, $apiHashQuestion);
92
93
		$this->setApiId($apiId);
94
		$this->setApiHash($apiHash);
95
96
		putenv('TELEGRAM_API_ID=' . $apiId);
97
		putenv('TELEGRAM_API_HASH=' . $apiHash);
98
99
		$sessionFile = $this->getSessionDirectory();
100
101
		$path = realpath(__DIR__ . '/ClientCli/Cli.php');
102
		$cmd = 'php ' . escapeshellarg($path) . ' telegram:login --session-directory ' . escapeshellarg($sessionFile);
103
104
		// This is only to create the client session files.
105
		// The login will be made afterwards.
106
		exec($cmd);
107
108
		$user = posix_getpwuid(posix_getuid());
109
110
		$output->writeln('<info>Run the following command to start the Telegram login process:</info>');
111
		$output->writeln('');
112
		$output->writeln("<comment>$cmd</comment>");
113
		$output->writeln('');
114
		$output->writeln('Make sure that the user to run the command is the same as the web server user: <info>' . $user['name'] . '</info>.');
115
		$output->writeln('');
116
		$output->writeln('Follow the instructions in the command output.');
117
		return 0;
118
	}
119
120
	private function getSessionDirectory(): string {
121
122
		try {
123
			$folder = $this->appData->newFolder('session.madeline');
124
		} catch (NotFoundException) {
125
			$folder = $this->appData->getFolder('session.madeline');
126
		}
127
128
		$instanceId = $this->config->getSystemValueString('instanceid');
129
		$appDataFolder = 'appdata_' . $instanceId;
130
		$dataDirectory = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data');
131
		$fullPath = $dataDirectory . '/' . $appDataFolder . '/' . Application::APP_ID . '/session.madeline';
132
133
		if (is_dir($fullPath) === false) {
134
			$reflection = new \ReflectionClass($folder);
135
			$reflectionProperty = $reflection->getProperty('folder');
136
			$reflectionProperty->setAccessible(true);
137
			$folder = $reflectionProperty->getValue($folder);
138
			$fullPath = $folder->getInternalPath();
139
		}
140
		return $fullPath;
141
	}
142
}
143