Passed
Push — developer ( 56d998...bda5eb )
by Mariusz
25:30 queued 09:47
created

Tokens::generate()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
c 0
b 0
f 0
dl 0
loc 16
rs 9.8333
cc 3
nc 2
nop 4
1
<?php
2
/**
3
 * Tokens utils file.
4
 *
5
 * @package App
6
 *
7
 * @copyright YetiForce S.A.
8
 * @license   YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
9
 * @author    Mariusz Krzaczkowski <[email protected]>
10
 */
11
12
namespace App\Utils;
13
14
/**
15
 * Tokens utils class.
16
 */
17
class Tokens
18
{
19
	/** @var string Token table name. */
20
	const TABLE_NAME = 's_#__tokens';
21
22
	/** @var string Last generated token. */
23
	private static $lastToken;
24
25
	/**
26
	 * Generate token.
27
	 *
28
	 * @param string      $method         Method name
29
	 * @param array       $params
30
	 * @param string|null $expirationDate Date and time until which the token is valid
31
	 * @param bool        $oneTime
32
	 *
33
	 * @return string
34
	 */
35
	public static function generate(string $method, array $params, string $expirationDate = null, bool $oneTime = true): string
36
	{
37
		if (!\is_callable($method) && !class_exists($method)) {
38
			throw new \App\Exceptions\AppException("The method `$method` does not exist");
39
		}
40
		$uid = self::generateUid();
41
		\App\Db::getInstance('admin')->createCommand()->insert(self::TABLE_NAME, [
42
			'uid' => $uid,
43
			'method' => $method,
44
			'params' => \App\Json::encode($params),
45
			'created_by_user' => \App\User::getCurrentUserRealId(),
46
			'created_date' => date('Y-m-d H:i:s'),
47
			'expiration_date' => $expirationDate,
48
			'one_time_use' => (int) $oneTime,
49
		])->execute();
50
		return self::$lastToken = $uid;
51
	}
52
53
	/**
54
	 * Generate uid function.
55
	 *
56
	 * @return string
57
	 */
58
	private static function generateUid(): string
59
	{
60
		$uid = \App\Encryption::generatePassword(64);
61
		if (null !== self::get($uid)) {
62
			return self::generateUid();
63
		}
64
		return $uid;
65
	}
66
67
	/**
68
	 * Get token detail.
69
	 *
70
	 * @param string $uid
71
	 * @param bool   $remove
72
	 *
73
	 * @return array|null
74
	 */
75
	public static function get(string $uid, bool $remove = false): ?array
76
	{
77
		$row = (new \App\Db\Query())->from(self::TABLE_NAME)
78
			->where(['uid' => $uid])->one(\App\Db::getInstance('admin')) ?: null;
79
		if (!empty($row['expiration_date']) && strtotime($row['expiration_date']) < time()) {
80
			self::delete($uid);
81
			$row = null;
82
		}
83
		if ($row) {
84
			$row['params'] = \App\Json::decode($row['params']);
85
		}
86
		if ($remove || ($row && (bool) $row['one_time_use'])) {
87
			self::delete($uid);
88
		}
89
		return $row;
90
	}
91
92
	/**
93
	 * Delete token.
94
	 *
95
	 * @param string $uid
96
	 *
97
	 * @return void
98
	 */
99
	public static function delete(string $uid): void
100
	{
101
		\App\Db::getInstance('admin')->createCommand()->delete(self::TABLE_NAME, ['uid' => $uid])->execute();
102
	}
103
104
	/**
105
	 * Generate URL form token.
106
	 *
107
	 * @param string|null $token
108
	 * @param int|null    $serverId
109
	 *
110
	 * @return string
111
	 */
112
	public static function generateLink(?string $token = null, ?int $serverId = null): string
113
	{
114
		if (null === $token) {
115
			$token = self::$lastToken;
116
		}
117
		$url = \App\Config::main('site_URL');
118
		if (0 === $serverId) {
119
			if ($rows = \App\Integrations\Services::getByType('Token')) {
120
				$row = reset($rows);
121
				if ($row && $row['url']) {
122
					$url = $row['url'];
123
					if ('/' !== substr($url, -1)) {
124
						$url .= '/';
125
					}
126
				}
127
			}
128
		} elseif ($serverId && ($data = \App\Integrations\Services::getById($serverId)) && $data['url']) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $serverId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
129
			$url = $data['url'];
130
			if ('/' !== substr($url, -1)) {
131
				$url .= '/';
132
			}
133
		}
134
		return $url . 'webservice/Token/' . $token;
135
	}
136
137
	/**
138
	 * Link action mechanism for TextParser.
139
	 *
140
	 * @param array             $params
141
	 * @param \Api\Token\Action $self
142
	 *
143
	 * @return void
144
	 */
145
	public static function runWorkflow(array $params, \Api\Token\Action $self): void
0 ignored issues
show
Unused Code introduced by
The parameter $self 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

145
	public static function runWorkflow(array $params, /** @scrutinizer ignore-unused */ \Api\Token\Action $self): void

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...
146
	{
147
		if (empty($params['recordId'])) {
148
			throw new \Api\Core\Exception('No record ID', 1001);
149
		}
150
		if (empty($params['workflowId'])) {
151
			throw new \Api\Core\Exception('No workflow ID', 1002);
152
		}
153
		if (!\App\Record::isExists($params['recordId'], '', \App\Record::STATE_ACTIVE)) {
154
			throw new \Api\Core\Exception("The record {$params['recordId']} does not exist", 1003);
155
		}
156
		\Vtiger_Loader::includeOnce('~~modules/com_vtiger_workflow/include.php');
157
		$wfs = new \VTWorkflowManager();
158
		$workflow = $wfs->retrieve($params['workflowId']);
159
		if (empty($workflow)) {
160
			throw new \Api\Core\Exception("The workflow {$params['workflowId']} does not exist", 1004);
161
		}
162
		$recordModel = \Vtiger_Record_Model::getInstanceById($params['recordId']);
163
		if ($workflow->evaluate($recordModel)) {
164
			$workflow->performTasks($recordModel);
165
			if (!empty($params['messages'])) {
166
				echo $params['messages'];
167
			} elseif ($params['redirect']) {
168
				header('location: ' . $params['redirect']);
169
			}
170
		} else {
171
			throw new \Api\Core\Exception('ERR_TOKEN_NOT_EXECUTION_CONDITIONS', 1005);
172
		}
173
	}
174
}
175