Passed
Pull Request — master (#686)
by Vitor
04:21
created

Client   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 119
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 5
Bugs 2 Features 2
Metric Value
wmc 9
eloc 74
dl 0
loc 119
ccs 0
cts 79
cp 0
rs 10
c 5
b 2
f 2

5 Methods

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