Completed
Push — master ( ea0713...bd13d1 )
by Vitor
15s
created

Client   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 110
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 5
Bugs 2 Features 2
Metric Value
wmc 8
eloc 70
c 5
b 2
f 2
dl 0
loc 110
ccs 0
cts 61
cp 0
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A send() 0 24 2
A getSessionDirectory() 0 21 3
A cliConfigure() 0 40 2
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 full phone number including country code (e.g. +491751234567) as identifier or your Telegram user name preceded by an `@` (e.g. `@myusername`).</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) . ' '
103
			. 'telegram:login '
104
			. '--session-directory ' . escapeshellarg($sessionFile);
105
106
		// This is only to create the client session files.
107
		// The login will be made afterwards.
108
		exec($cmd);
109
110
		$user = posix_getpwuid(posix_getuid());
111
112
		$output->writeln('<info>Run the following command to start the Telegram login process:</info>');
113
		$output->writeln('');
114
		$output->writeln("<comment>$cmd</comment>");
115
		$output->writeln('');
116
		$output->writeln('Make sure that the user to run the command is the same as the web server user: <info>' . $user['name'] . '</info>.');
117
		$output->writeln('');
118
		$output->writeln('Follow the instructions in the command output.');
119
		return 0;
120
	}
121
122
	private function getSessionDirectory(): string {
123
124
		try {
125
			$folder = $this->appData->newFolder('session.madeline');
126
		} catch (NotFoundException) {
127
			$folder = $this->appData->getFolder('session.madeline');
128
		}
129
130
		$instanceId = $this->config->getSystemValueString('instanceid');
131
		$appDataFolder = 'appdata_' . $instanceId;
132
		$dataDirectory = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data');
133
		$fullPath = $dataDirectory . '/' . $appDataFolder . '/' . Application::APP_ID . '/session.madeline';
134
135
		if (is_dir($fullPath) === false) {
136
			$reflection = new \ReflectionClass($folder);
137
			$reflectionProperty = $reflection->getProperty('folder');
138
			$reflectionProperty->setAccessible(true);
139
			$folder = $reflectionProperty->getValue($folder);
140
			$fullPath = $folder->getInternalPath();
141
		}
142
		return $fullPath;
143
	}
144
}
145