-
Notifications
You must be signed in to change notification settings - Fork 1
/
Jitsi.php
198 lines (176 loc) · 4.87 KB
/
Jitsi.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<?php
/**
* JWT Token for jitsi backend
*
* @link http://www.egroupware.org
* @author Hadi Nategh <hn-At-egroupware.org>
* @package Status
* @copyright (c) 2020 by Hadi Nategh <hn-At-egroupware.org>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
namespace EGroupware\Status\Videoconference\Backends;
use EGroupware\Api;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use EGroupware\Api\Config;
class Jitsi implements Iface
{
/**
* JWT HEADER
*/
protected const HEADER = ['alg' => 'HS256', 'typ' => 'JWT'];
/**
* the audience (aud claim)
*/
protected const AUD = 'EGroupware';
/**
* uid number
*/
protected const UID = 1;
/**
* Expiration grace-time of token
*/
protected const EXP_GRACETIME = 3600;
/**
* Not before grace-time the token
*/
protected const NBF_GRACETIME = 3600;
/**
* @var object \Lcobucci\JWT\Token
*/
private $token;
/**
* contains jwt payload
* @var array
*/
private $payload;
/**
* @var mixed
*/
private $config;
private $extraParams = [
'config.startAudioOnly' => false
];
/**
* Constructor
*
* @param string $_room room-id
* @param array $_context values for keys 'name', 'email', 'avatar', 'account_id'
* @param int|null $_start start UTC timestamp, default now (gracetime of self::NBF_GRACETIME=1h is applied)
* @param int|null $_end expiration UTC timestamp, default now plus gracetime of self::EXP_GRACETIME=1h
*/
public function __construct($_room='', $_context=[], $_start=null, $_end=null)
{
$config = Config::read('status');
$this->config = $config['videoconference']['jitsi'];
$iat = time();
$nbf = max(($_start ?: $iat) - self::NBF_GRACETIME, $iat);
$exp = ($_end ?: $iat) + self::EXP_GRACETIME;
$signer = new Sha256();
$this->payload = [
'iss' => $this->config['jitsi_application_id'] ?: 'egroupware',
'aud' => self::AUD,
'sub' => str_replace('jitsi.egroupware.net', '', $this->config['jitsi_domain']) ?: 'meet.jit.si',
'room' => $_room ?: '*',
'secret' => $this->config['jitsi_application_secret']
];
// Prosody in Jitsi expects all values of user context to be type of string otherwise will throw an error
$context['user'] = array_map(static function($val){
return (string)$val;
}, (array)$_context['user']);
// Jitsi doesn't like more context params, we use these params in other backends though
unset($context['user']['cal_id'], $context['user']['title']);
try {
$this->token = (new Builder())
// Configures the issuer (iss claim)
->issuedBy($this->payload['iss'])
// Configure headers
->withHeader('alg', self::HEADER['alg'])
->withHeader('typ', self::HEADER['typ'])
// Configure the audience (aud claim)
->permittedFor($this->payload['aud'])
// Configure the domain (sub claim)
->relatedTo($this->payload['sub'])
// Configures the time that the token was issue (iat claim)
->issuedAt($iat)
// Configures the time that the token can be used (nbf claim)
->canOnlyBeUsedAfter($nbf)
// Configures the expiration time of the token (exp claim)
->expiresAt($exp)
// Configure room
->withClaim('room', $this->payload['room'])
// Set context
->withClaim('context', $context)
// Get token
->getToken($signer, new Key ($this->payload['secret']));
}
catch (\Exception $e)
{
error_log(__METHOD__."() failed to generate token:".$e->getMessage());
}
}
/**
* @return bool returns false if generated token is already expired otherwise false
*/
private function _isTokenExpired ()
{
return $this->token->isExpired();
}
/**
* Get Jitsi Meet JWT Token
* @return string \Lcobucci\JWT\Token
*/
private function _getToken ()
{
return $this->token->toString();
}
/**
* @param ?array $_context
* @return string
*/
public function getMeetingUrl (?array $_context=null)
{
$jwt = !empty($this->config['jitsi_application_id']) ? "?jwt=".$this->_getToken() : '';
return 'https://'.$this->payload['sub'].'/'.$this->payload['room'].$jwt.'#'.$this->_getExtraParams();
}
/**
* @param false $value
*/
public function setStartAudioOnly ($value = false)
{
$this->extraParams['config.startAudioOnly'] = $value;
}
private function _getExtraParams()
{
return http_build_query($this->extraParams,'#');
}
/**
* @return bool
*/
public function isMeetingValid()
{
return $this->_isTokenExpired();
}
/**
* Give a regex to recognize "our" urls
*/
public function getRegex()
{
return 'https://'.$this->payload['sub'].'/'.str_replace('/' , '', Api\Header\Http::host().'.*');
}
/**
* @param string $url
* @return mixed|string returns room id
*/
public static function fetchRoomFromUrl($url='')
{
$parts = [];
if ($url)
{
$parts = explode('?jwt=', $url);
if (is_array($parts)) $parts = explode('/', $parts[0]);
}
return is_array($parts) ? array_pop($parts) : "";
}
}