Skip to content

Commit db655f8

Browse files
authored
Merge pull request #327 from opentok/feature/e-2-e-support
Add end-to-end encryption when creating session.
2 parents c85f458 + 811cc98 commit db655f8

File tree

4 files changed

+150
-13
lines changed

4 files changed

+150
-13
lines changed

src/OpenTok/OpenTok.php

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace OpenTok;
44

5-
use OpenTok\Layout;
65
use OpenTok\Util\Client;
76
use OpenTok\Util\Validators;
87
use OpenTok\Exception\InvalidArgumentException;
@@ -166,6 +165,10 @@ public function generateToken($sessionId, $options = array())
166165
* (either automatically or not), you must set the <code>mediaMode</code> key to
167166
* <code>MediaMode::ROUTED</code>.</li>
168167
*
168+
* <li><code>'e2ee'</code> (Boolean) &mdash; Whether to enable
169+
* <a href="https://tokbox.com/developer/guides/end-to-end-encryption">end-to-end encryption</a>
170+
* for a routed session.</li>
171+
*
169172
* <li><code>'location'</code> (String) &mdash; An IP address that the OpenTok servers
170173
* will use to situate the session in its global network. If you do not set a location hint,
171174
* the OpenTok servers will be based on the first client connecting to the session.</li>
@@ -212,26 +215,41 @@ public function createSession($options = array())
212215
{
213216
if (
214217
array_key_exists('archiveMode', $options) &&
215-
$options['archiveMode'] != ArchiveMode::MANUAL
218+
$options['archiveMode'] !== ArchiveMode::MANUAL
216219
) {
217220
if (
218221
array_key_exists('mediaMode', $options) &&
219-
$options['mediaMode'] != MediaMode::ROUTED
222+
$options['mediaMode'] !== MediaMode::ROUTED
220223
) {
221224
throw new InvalidArgumentException('A session must be routed to be archived.');
222225
} else {
223226
$options['mediaMode'] = MediaMode::ROUTED;
224227
}
225228
}
226229

230+
if (array_key_exists('e2ee', $options) && $options['e2ee']) {
231+
232+
if (array_key_exists('mediaMode', $options) && $options['mediaMode'] !== MediaMode::ROUTED) {
233+
throw new InvalidArgumentException('MediaMode must be routed in order to enable E2EE');
234+
}
235+
236+
if (array_key_exists('archiveMode', $options) && $options['archiveMode'] === ArchiveMode::ALWAYS) {
237+
throw new InvalidArgumentException('ArchiveMode cannot be set to always when using E2EE');
238+
}
239+
240+
$options['e2ee'] = 'true';
241+
}
242+
227243
// unpack optional arguments (merging with default values) into named variables
228244
$defaults = array(
229245
'mediaMode' => MediaMode::RELAYED,
230246
'archiveMode' => ArchiveMode::MANUAL,
231-
'location' => null
247+
'location' => null,
248+
'e2ee' => 'false',
232249
);
250+
233251
$options = array_merge($defaults, array_intersect_key($options, $defaults));
234-
list($mediaMode, $archiveMode, $location) = array_values($options);
252+
list($mediaMode, $archiveMode, $location, $e2ee) = array_values($options);
235253

236254
// validate arguments
237255
Validators::validateMediaMode($mediaMode);
@@ -251,7 +269,8 @@ public function createSession($options = array())
251269
return new Session($this, (string)$sessionId, array(
252270
'location' => $location,
253271
'mediaMode' => $mediaMode,
254-
'archiveMode' => $archiveMode
272+
'archiveMode' => $archiveMode,
273+
'e2ee' => $e2ee
255274
));
256275
}
257276

src/OpenTok/Session.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,25 @@ class Session
3232
* @internal
3333
*/
3434
protected $opentok;
35+
/**
36+
* @internal
37+
*/
38+
protected $e2ee;
3539

3640
/**
3741
* @internal
3842
*/
3943
public function __construct($opentok, $sessionId, $properties = array())
4044
{
41-
// unpack arguments
42-
$defaults = array('mediaMode' => MediaMode::ROUTED, 'archiveMode' => ArchiveMode::MANUAL, 'location' => null);
45+
$defaults = [
46+
'mediaMode' => MediaMode::ROUTED,
47+
'archiveMode' => ArchiveMode::MANUAL,
48+
'location' => null,
49+
'e2ee' => false
50+
];
51+
4352
$properties = array_merge($defaults, array_intersect_key($properties, $defaults));
44-
list($mediaMode, $archiveMode, $location) = array_values($properties);
53+
list($mediaMode, $archiveMode, $location, $e2ee) = array_values($properties);
4554

4655
Validators::validateOpenTok($opentok);
4756
Validators::validateSessionId($sessionId);
@@ -54,6 +63,7 @@ public function __construct($opentok, $sessionId, $properties = array())
5463
$this->location = $location;
5564
$this->mediaMode = $mediaMode;
5665
$this->archiveMode = $archiveMode;
66+
$this->e2ee = $e2ee;
5767
}
5868

5969
/**
@@ -148,4 +158,15 @@ public function generateToken($options = array())
148158
{
149159
return $this->opentok->generateToken($this->sessionId, $options);
150160
}
161+
162+
/**
163+
* Whether <a href="https://tokbox.com/developer/guides/end-to-end-encryption">end-to-end encryption</a>
164+
* is set for the session.
165+
*
166+
* @return bool
167+
*/
168+
public function getE2EE(): bool
169+
{
170+
return (bool)$this->e2ee;
171+
}
151172
}

tests/OpenTokTest/OpenTokTest.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PHPUnit\Framework\TestCase;
1919
use GuzzleHttp\Handler\MockHandler;
2020
use OpenTok\Exception\InvalidArgumentException;
21+
use OpenTok\Session;
2122

2223
define('OPENTOK_DEBUG', true);
2324

@@ -218,6 +219,9 @@ public function testCreatesDefaultSession()
218219
$p2p_preference = $this->getPostField($request, 'p2p.preference');
219220
$this->assertEquals('enabled', $p2p_preference);
220221

222+
$e2ee = $this->getPostField($request, 'e2ee');
223+
$this->assertEquals('false', $e2ee);
224+
221225
$this->assertInstanceOf('OpenTok\Session', $session);
222226
// NOTE: this is an actual sessionId from the recorded response, this doesn't correspond to
223227
// the API Key and API Secret used to create the session.
@@ -227,6 +231,89 @@ public function testCreatesDefaultSession()
227231
);
228232
}
229233

234+
public function testCreatesE2EESession(): void
235+
{
236+
// Arrange
237+
$this->setupOTWithMocks([[
238+
'code' => 200,
239+
'headers' => [
240+
'Content-Type' => 'text/xml'
241+
],
242+
'path' => 'session/create/relayed'
243+
]]);
244+
245+
$session = $this->opentok->createSession(['e2ee' => true]);
246+
247+
$this->assertCount(1, $this->historyContainer);
248+
249+
$request = $this->historyContainer[0]['request'];
250+
$this->assertEquals('POST', strtoupper($request->getMethod()));
251+
$this->assertEquals('/session/create', $request->getUri()->getPath());
252+
$this->assertEquals('api.opentok.com', $request->getUri()->getHost());
253+
$this->assertEquals('https', $request->getUri()->getScheme());
254+
255+
$authString = $request->getHeaderLine('X-OPENTOK-AUTH');
256+
$this->assertEquals(true, TestHelpers::validateOpenTokAuthHeader($this->API_KEY, $this->API_SECRET, $authString));
257+
258+
$userAgent = $request->getHeaderLine('User-Agent');
259+
$this->assertNotEmpty($userAgent);
260+
$this->assertStringStartsWith('OpenTok-PHP-SDK/4.12.0', $userAgent);
261+
262+
$p2p_preference = $this->getPostField($request, 'p2p.preference');
263+
$this->assertEquals('enabled', $p2p_preference);
264+
265+
$e2ee = $this->getPostField($request, 'e2ee');
266+
$this->assertEquals('true', $e2ee);
267+
268+
$this->assertInstanceOf(Session::class, $session);
269+
$this->assertEquals(
270+
'2_MX4xNzAxMjYzMX4xMjcuMC4wLjF-V2VkIEZlYiAyNiAxODo1NzoyNCBQU1QgMjAxNH4wLjU0MDU4ODc0fg',
271+
$session->getSessionId()
272+
);
273+
}
274+
275+
public function testCannotStartE2EESessionWithWrongMediaMode(): void
276+
{
277+
$this->expectException(InvalidArgumentException::class);
278+
$this->expectErrorMessage('MediaMode must be routed in order to enable E2EE');
279+
280+
$this->setupOTWithMocks([[
281+
'code' => 200,
282+
'headers' => [
283+
'Content-Type' => 'text/xml'
284+
],
285+
'path' => 'session/create/relayed'
286+
]]);
287+
288+
$session = $this->opentok->createSession(
289+
[
290+
'mediaMode' => MediaMode::RELAYED,
291+
'e2ee' => true
292+
]
293+
);
294+
}
295+
296+
public function testCannotStartE2EESessionWithWrongArchiveMode(): void
297+
{
298+
$this->expectException(InvalidArgumentException::class);
299+
$this->expectErrorMessage('ArchiveMode cannot be set to always when using E2EE');
300+
301+
$this->setupOTWithMocks([[
302+
'code' => 200,
303+
'headers' => [
304+
'Content-Type' => 'text/xml'
305+
],
306+
'path' => 'session/create/relayed'
307+
]]);
308+
309+
$session = $this->opentok->createSession(
310+
[
311+
'archiveMode' => ArchiveMode::ALWAYS,
312+
'e2ee' => true
313+
]
314+
);
315+
}
316+
230317
private function getPostField($request, $targetKey)
231318
{
232319
$params = array_map(function ($item) {

tests/OpenTokTest/SessionTest.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@
22

33
namespace OpenTokTest;
44

5-
use GuzzleHttp\Handler\MockHandler;
6-
use GuzzleHttp\HandlerStack;
7-
use GuzzleHttp\Middleware;
85
use OpenTok\OpenTok;
96
use OpenTok\Session;
107
use OpenTok\MediaMode;
118
use OpenTok\ArchiveMode;
12-
use OpenTok\Util\Client;
139
use PHPUnit\Framework\TestCase;
1410

1511
class SessionTest extends TestCase
@@ -122,6 +118,20 @@ public function badParameterProvider()
122118
);
123119
}
124120

121+
public function testInitialzationWithoutE2ee()
122+
{
123+
$sessionId = 'SESSIONID';
124+
$session = new Session($this->opentok, $sessionId);
125+
$this->assertEquals(false, $session->getE2EE());
126+
}
127+
128+
public function testInitialzationWithE2ee()
129+
{
130+
$sessionId = 'SESSIONID';
131+
$session = new Session($this->opentok, $sessionId, ['e2ee' => true]);
132+
$this->assertEquals(true, $session->getE2EE());
133+
}
134+
125135
public function testInitializationWithExtraneousParams()
126136
{
127137
$sessionId = 'SESSIONID';

0 commit comments

Comments
 (0)