PluginProbe
VdoCipher: Secure Video Player and Hosting / trunk
VdoCipher: Secure Video Player and Hosting vtrunk
trunk 1.10 1.11 1.12 1.13 1.14 1.15 1.17 1.18 1.19 1.20 1.21 1.22 1.23 1.24 1.25 1.26 1.27 1.28 1.29 1.3 1.30 1.4 1.5 1.6 All 28 releases
vdocipher / vdocipher.php

vdocipher.php in VdoCipher: Secure Video Player and Hosting trunk, at vdocipher.php

560 lines 18.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: VdoCipher
4 * Plugin URI: https://www.vdocipher.com
5 * Description: Secured video hosting for WordPress
6 * Version: 1.30
7 * Author: VdoCipher
8 * Author URI: https://www.vdocipher.com
9 * License: GPL2
10 */
11
12 if (__FILE__ == $_SERVER['SCRIPT_FILENAME']) {
13 header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');
14 exit(
15 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<html lang='en'><head>\r\n<title>404 Not Found</title>\r\n".
16 "</head><body>\r\n<h1>Not Found</h1>\r\n<p>The requested URL " . $_SERVER['SCRIPT_NAME'] . " was not found on ".
17 "this server.</p>\r\n</body></html>"
18 );
19 }
20
21 if (!defined('VDOCIPHER_PLUGIN_VERSION')) {
22 define('VDOCIPHER_PLUGIN_VERSION', '1.30');
23 }
24
25 if (!defined('VDOCIPHER_PLAYER_VERSION')) {
26 define('VDOCIPHER_PLAYER_VERSION', 'v2');
27 }
28
29 if (!defined('VDOCIPHER_DEFAULT_THEME')) {
30 define('VDOCIPHER_DEFAULT_THEME', '');
31 }
32
33 function vdo_plugin_check_version()
34 {
35 // This applies only for installs 1.24 and below
36 if (!get_option('vdo_plugin_version')) {
37 if (preg_match('/^1\.[0123456]\.[0-9]{1,2}$/', get_option('vdo_embed_version'))) {
38 update_option('vdo_embed_version', VDOCIPHER_PLAYER_VERSION);
39 }
40 if (preg_match('/^1\.[01234]\.[0-9]{1,2}$/', get_option('vdo_embed_version'))) {
41 update_option('vdo_default_height', 'auto');
42 }
43 update_option('vdo_plugin_version', VDOCIPHER_PLUGIN_VERSION);
44 return ;
45 }
46 // This applies for all new installations after 1.25
47 if (VDOCIPHER_PLUGIN_VERSION !== get_option('vdo_plugin_version')) {
48 if (preg_match('/^1\.[0-9]{1,2}\.[0-9]{1,2}$/', get_option('vdo_embed_version'))) {
49 update_option('vdo_embed_version', VDOCIPHER_PLAYER_VERSION);
50 }
51 update_option('vdo_plugin_version', VDOCIPHER_PLUGIN_VERSION);
52 }
53 }
54
55 add_action('plugins_loaded', 'vdo_plugin_check_version');
56
57 // Function called to get OTP, starts
58 function vdo_otp($video, $otp_post_array = array())
59 {
60 $client_key = get_option('vdo_client_key');
61 if (empty($client_key)) {
62 return (object)['message' => 'Plugin not configured. API Key missing.'];
63 } elseif (strlen($client_key) !== 64) {
64 return (object)["message" => "Invalid API Key."];
65 }
66 $url = "https://dev.vdocipher.com/api/videos/$video/otp";
67 $pluginVersion = VDOCIPHER_PLUGIN_VERSION;
68 $phpVersion = phpversion();
69 $headers = array(
70 'Authorization' => 'Apisecret '.$client_key,
71 'Content-Type' => 'application/json',
72 'Accept' => 'application/json',
73 'vdo-sdk' => "VdoWP/$pluginVersion PHP/$phpVersion" // for backward compatibility
74 );
75 $otp_post_json = json_encode($otp_post_array);
76 $response = wp_remote_post(
77 $url,
78 array(
79 'method' => 'POST',
80 'headers' => $headers,
81 'body' => $otp_post_json
82 )
83 );
84 if (is_wp_error($response)) {
85 $error_message = $response->get_error_message();
86 if (false !== stripos($error_message, 'Operation timed out')) {
87 $error_message = 'Operation timed out. Check your firewall at web host or try after sometime.';
88 } elseif (false !== stripos($error_message, 'Could not resolve host')) {
89 $error_message = 'DNS Connectivity issue. Check firewall at web host.';
90 }
91 return (object)["message" => $error_message];
92 }
93
94 $responseCode = $response['response']['code'];
95 if ($responseCode === 404) {
96 return (object)["message" => "Video ID not found"];
97 } elseif ($responseCode === 403) {
98 return (object)["message" => "API key does not have OTP creator permission"];
99 } elseif ($responseCode === 401) {
100 return (object)["message" => "Incorrect API key"];
101 } elseif ($responseCode === 400) {
102 return (object)["message" => "Invalid configuration"];
103 } elseif ($responseCode >= 500) {
104 return (object)["message" => "Service unavailable. Please try after sometime."];
105 } else {
106 return json_decode($response['body']);
107 }
108 }
109 // Function called to get OTP, ends
110
111 /**
112 * Generate player code for V2
113 *
114 * @param string $url iframe URL
115 * @param string $styleAttr style attribute
116 * @param string $speedOptions comma separated float for playback speed
117 *
118 * @return string
119 */
120 function buildPlayerV2($url, $styleAttr, $speedOptions)
121 {
122 $url = esc_url($url);
123 $styleAttr = esc_attr($styleAttr);
124 $uniq = 'u' . rand();
125 $output = <<<END
126 <script src="https://player.vdocipher.com/v2/api.js"></script>
127 <iframe
128 src="$url"
129 id="$uniq"
130 style="$styleAttr"
131 allow="encrypted-media"
132 allowfullscreen
133 ></iframe>
134 <script>
135 (function() {
136 const iframe = document.querySelector('#$uniq');
137 const player = VdoPlayer.getInstance(iframe);
138 const isAutoHeight = () => iframe.style.height === 'auto' && iframe.style.width.endsWith('px');
139 const setAspectRatio = (ratio) => {
140 iframe.style.maxHeight = '100vh';
141 if (CSS.supports('aspect-ratio', 1)) {
142 iframe.style.aspectRatio = ratio;
143 } else {
144 const offsetWidth = iframe.offsetWidth;
145 iframe.style.height = Math.round(offsetWidth / ratio) + 'px';
146 }
147 }
148 if (isAutoHeight()) {
149 if (iframe.src.includes('litemode')) {
150 setAspectRatio(16/9);
151 }
152 player.video.addEventListener('loadstart', async () => {
153 const aspectRatio = (await player.api.getMetaData()).aspectRatio;
154 setAspectRatio(aspectRatio);
155 });
156 }
157 })();
158 </script>
159 END;
160 $speedPattern = '/^\d.\d{1,2}(,\d.\d{1,2})+$/';
161
162 if ($speedOptions !== false && preg_match($speedPattern, $speedOptions)) {
163 $speedOptions = esc_js($speedOptions);
164 $output .= <<<END
165 <script>
166 (function() {
167 const iframe = document.querySelector('#$uniq')
168 const player = VdoPlayer.getInstance(iframe);
169 player.video.addEventListener('loadstart', async () => {
170 player.api.updatePlayerConfig({playbackSpeedOptions: [$speedOptions]});
171 });
172 })();
173 </script>
174 END;
175 }
176 return $output;
177 }
178
179
180 /**
181 * Process watermark, to insert WordPress variables, ip, date
182 *
183 * @param string $inputWatermark watermark entered in options
184 *
185 * @return string json string with variables replaced
186 */
187 function processWatermark($inputWatermark)
188 {
189 $current_user = wp_get_current_user();
190 $vdo_annotate_code = get_option('vdo_annotate_code');
191 $vdo_annotate_code = apply_filters('vdocipher_annotate_preprocess', $vdo_annotate_code);
192 if (is_user_logged_in()) {
193 $vdo_annotate_code = str_replace('{name}', esc_js($current_user->display_name), $vdo_annotate_code);
194 $vdo_annotate_code = str_replace('{email}', esc_js($current_user->user_email), $vdo_annotate_code);
195 $vdo_annotate_code = str_replace('{username}', esc_js($current_user->user_login), $vdo_annotate_code);
196 $vdo_annotate_code = str_replace('{id}', esc_js($current_user->ID), $vdo_annotate_code);
197 }
198 $vdo_annotate_code = str_replace('{ip}', $_SERVER['REMOTE_ADDR'], $vdo_annotate_code);
199 $vdo_annotate_code = preg_replace_callback('/{date\.([^}]+)}/', "eval_date", $vdo_annotate_code);
200
201 return apply_filters('vdocipher_annotate_postprocess', $vdo_annotate_code);
202 }
203
204 function buildPlayerV1Speed($speedOptions)
205 {
206 $speedOptions = esc_js($speedOptions);
207 return <<<END
208 <script>
209 (function () {
210 var originalReadyFunction = window.onVdoCipherAPIReady;
211 // private API; do not use anywhere else; might change without notice
212 var index = vdo.d.length - 1;
213 window.onVdoCipherAPIReady = () => {
214 if (originalReadyFunction) originalReadyFunction();
215 var v_ = vdo.getObjects()[index];
216 v_.addEventListener('load', () => {
217 v_.availablePlaybackRates = [$speedOptions]
218 });
219 }
220 })()
221 </script>
222 END;
223 }
224
225 /**
226 * Generate player code for V1
227 *
228 * @param string $OTP otp
229 * @param string $playbackInfo playbackInfo
230 * @param string $styleAttr string for inline styles
231 * @param string $vdo_player_theme optional theme id applicable to player v1
232 *
233 * @return string string html for embed code
234 */
235 function buildPlayerV1($OTP, $playbackInfo, $styleAttr, $vdo_player_theme)
236 {
237 $styleAttr = esc_attr($styleAttr);
238 $OTP = esc_attr($OTP);
239 $playbackInfo = esc_attr($playbackInfo);
240 $vdo_player_theme = esc_attr($vdo_player_theme);
241 return <<<END
242 <div id='vdo$OTP' style='$styleAttr' ></div>
243 <script>(function(v,i,d,e,o){v[o]=v[o]||{}; v[o].add = v[o].add || function V(a){
244 (v[o].d=v[o].d||[]).push(a);};
245 if(!v[o].l) { v[o].l=1*new Date(); a=i.createElement(d), m=i.getElementsByTagName(d)[0];
246 a.async=1; a.src=e; m.parentNode.insertBefore(a,m);}
247 })(window,document,'script','https://d1z78r8i505acl.cloudfront.net/playerAssets/1.6.10/vdo.js','vdo');
248 vdo.add({
249 otp: '$OTP',
250 playbackInfo: '$playbackInfo',
251 theme: '$vdo_player_theme',
252 plugins: [{
253 name: 'keyboard',
254 options: {
255 preset: 'default',
256 bindings: {
257 'Left' : (player) => player.seek(player.currentTime - 15),
258 'Right' : (player) => player.seek(player.currentTime + 15),
259 },
260 }
261 }],
262 container: document.querySelector('#vdo$OTP'),
263 })
264 </script>
265 END;
266 }
267
268 // VdoCipher Shortcode starts
269 function vdo_shortcode($atts)
270 {
271 $vdo_args = shortcode_atts(
272 array(
273 'width' => get_option('vdo_default_width'),
274 'height' => get_option('vdo_default_height'),
275 'id' => 'id',
276 'no_annotate' => false,
277 'vdo_theme' => false,
278 'autoplay' => false,
279 'loop' => false,
280 'controls' => 'on',
281 'cc_language' => false,
282 'litemode' => false,
283 ),
284 $atts
285 );
286 $width = $vdo_args['width'];
287 $height = $vdo_args['height'];
288 $id = $vdo_args['id'];
289 $no_annotate = $vdo_args['no_annotate'];
290 $vdo_theme = $vdo_args['vdo_theme'];
291
292 if (!preg_match('/.*px$/', $width)) {
293 $width = $width."px";
294 }
295 if (!preg_match('/.*px$/', $height)) {
296 if ($height != 'auto') {
297 $height = $height."px";
298 }
299 }
300 if (!$atts['id']) {
301 return "Required argument id for embedded video not found.";
302 } else {
303 $video = $id;
304 }
305
306 // Initialize $otp_post_array, to be sent as part of OTP request, as for time-to-live 300
307 $otp_post_array = array("ttl" => 300);
308 if (!function_exists("eval_date")) {
309 function eval_date($matches)
310 {
311 return current_time($matches[1]);
312 }
313 }
314 if (get_option('vdo_annotate_code') != "") {
315 // Add annotate code to $otp_post_array, which will be
316 // converted to Json and then sent as POST body to API endpoint
317 if (!$no_annotate) {
318 $otp_post_array["annotate"] = processWatermark(get_option('vdo_annotate_code'));
319 }
320 }
321 $userId = get_current_user_id();
322 if (get_option('vdo_send_user_id_in_api') && $userId !== 0) {
323 $otp_post_array["userId"] = $userId;
324 }
325 // OTP is requested via vdo_otp function
326 $OTP_Response = vdo_otp($video, $otp_post_array);
327
328 // https://www.php.net/manual/en/function.isset.php#86313
329 $message = (isset($OTP_Response->message)) ? $OTP_Response->message : null;
330 $OTP = (isset($OTP_Response->otp)) ? $OTP_Response->otp : null;
331 $playbackInfo = (isset($OTP_Response->playbackInfo)) ? $OTP_Response->playbackInfo : null;
332
333 if (is_null($OTP)) {
334 return "<div id='vdo$OTP'><strong>VdoCipher Error: $message</strong></div>";
335 }
336
337 // Video Embed version is retrieved from options table or from shortcode attribute
338 $vdo_embed_version_str = get_option('vdo_embed_version');
339
340 // Video Player theme, update and as shortcode attribute
341 if (!$vdo_theme) {
342 $vdo_player_theme = get_option('vdo_player_theme');
343 } else {
344 $vdo_player_theme = $vdo_theme;
345 }
346 if (strpos($vdo_player_theme, 'v1/') === 0 || strlen($vdo_player_theme) === 32) {
347 $vdo_embed_version_str = '1.6.10';
348 } elseif (strlen($vdo_player_theme) === 16) {
349 $vdo_embed_version_str = 'v2';
350 }
351 $speedOptions = esc_attr(get_option('vdo_player_speed'));
352
353 $styleAttr = "height:$height;width:$width;max-width:100%;border:0;display: block;";
354
355 // Old Embed Code
356 if ($vdo_embed_version_str === '1.6.10') {
357 //Old embed code
358 $output = buildPlayerV1($OTP, $playbackInfo, $styleAttr, $vdo_player_theme);
359
360 $speedPattern = '/^\d.\d{1,2}(,\d.\d{1,2})+$/';
361
362 if ($speedOptions !== false && preg_match($speedPattern, $speedOptions)) {
363 $output .= buildPlayerV1Speed($speedOptions);
364 }
365 } elseif ($vdo_embed_version_str === 'v2') {
366 $url = "https://player.vdocipher.com/v2/?otp=$OTP&playbackInfo=$playbackInfo";
367 if (strlen($vdo_player_theme) === 16) {
368 $url .= "&player=$vdo_player_theme";
369 }
370 if ($vdo_args['autoplay']) {
371 $url .= "&autoplay=true";
372 }
373 if ($vdo_args['loop']) {
374 $url .= "&loop=true";
375 }
376 if (in_array($vdo_args['controls'], ['off', 'native'])) {
377 $url .= "&controls=" . $vdo_args['controls'];
378 }
379 if ($vdo_args['cc_language']) {
380 $url .= "&ccLanguage=" . $vdo_args['cc_language'];
381 }
382 if ($vdo_args['litemode'] === 'true') {
383 $url .= "&litemode=true";
384 }
385 $output = buildPlayerV2($url, $styleAttr, $speedOptions);
386
387 } else {
388 $output = 'Invalid player selection: ' . $vdo_embed_version_str;
389 }
390 return $output;
391 }
392
393 add_shortcode('vdo', 'vdo_shortcode');
394 // VdoCipher Shortcode ends
395
396 // adding the Settings link, starts
397 $plugin = plugin_basename(__FILE__);
398 add_filter("plugin_action_links_$plugin", 'vdo_settings_link');
399
400 function vdo_settings_link($links)
401 {
402 $settings_link = '<a href="options-general.php?page=vdocipher">Settings</a>';
403 array_unshift($links, $settings_link);
404 return $links;
405 }
406 // adding the Settings link, ends
407
408 // add the menu item and register settings (3 functions), starts
409 if (is_admin()) { // admin actions
410 add_action('admin_init', 'register_vdo_settings');
411 add_action('admin_menu', 'vdo_menu');
412 }
413
414 function vdo_menu()
415 {
416 if (get_option('vdo_show_plugin_in_sidebar') === "") {
417 add_options_page(
418 'VdoCipher Options',
419 'VdoCipher',
420 'manage_options',
421 'vdocipher',
422 'vdo_options'
423 );
424 } else {
425 add_menu_page(
426 'VdoCipher Options',
427 'VdoCipher',
428 'manage_options',
429 'vdocipher',
430 'vdo_options',
431 plugin_dir_url(__FILE__).'images/logo.png'
432 );
433 }
434 }
435
436 function vdo_options()
437 {
438 if (!get_option('vdo_default_height')) {
439 update_option('vdo_default_height', 'auto');
440 }
441 if (!get_option('vdo_default_width')) {
442 update_option('vdo_default_width', '1280');
443 }
444 if (!current_user_can('manage_options')) {
445 wp_die(__('You do not have sufficient permissions to access this page.'));
446 }
447 include('include/options.php');
448 return "";
449 }
450
451 function register_vdo_settings()
452 {
453 // whitelist options
454 register_setting('vdo_option-group', 'vdo_client_key');
455 register_setting('vdo_option-group', 'vdo_default_height');
456 register_setting('vdo_option-group', 'vdo_default_width');
457 register_setting('vdo_option-group', 'vdo_annotate_code');
458 register_setting('vdo_option-group', 'vdo_embed_version');
459 register_setting('vdo_option-group', 'vdo_player_theme');
460 register_setting('vdo_option-group', 'vdo_plugin_version');
461 register_setting('vdo_option-group', 'vdo_player_speed');
462 register_setting('vdo_option-group', 'vdo_show_plugin_in_sidebar');
463 register_setting('vdo_option-group', 'vdo_send_user_id_in_api');
464 }
465 // add the menu item and register settings (3 functions), ends
466
467 // Activation Hook starts
468 function vdo_activate()
469 {
470 add_option('vdo_default_height', 'auto');
471 add_option('vdo_default_width', 1280);
472 add_option('vdo_embed_version', VDOCIPHER_PLAYER_VERSION);
473 add_option('vdo_player_theme', VDOCIPHER_DEFAULT_THEME);
474 add_option('vdo_show_plugin_in_sidebar', 'true');
475 }
476 register_activation_hook(__FILE__, 'vdo_activate');
477
478 // Registering and specifying Gutenberg block
479 function vdo_register_block()
480 {
481 if (!function_exists('register_block_type')) {
482 return ;
483 }
484 wp_register_script(
485 'vdo-block-script',
486 plugins_url('/include/block/dist/blocks.build.js', __FILE__),
487 array('wp-blocks', 'wp-element', 'wp-editor', 'wp-i18n')
488 );
489 wp_register_style(
490 'vdo-block-editor-style',
491 plugins_url('/include/block/dist/blocks.editor.build.css', __FILE__),
492 array('wp-edit-blocks')
493 );
494 register_block_type(
495 'vdo/block',
496 array(
497 'editor_script' => 'vdo-block-script',
498 'editor_style' => 'vdo-block-editor-style',
499 'attributes' => array(
500 'id' => array(
501 'type' => 'string',
502 ),
503 'width' => array(
504 'type' => 'string',
505 'default' => get_option('vdo_default_width')
506 ),
507 'height' => array(
508 'type' => 'string',
509 'default' => get_option('vdo_default_height')
510 ),
511 'vdo_theme' => array(
512 'type' => 'string',
513 'default' => get_option('vdo_player_theme')
514 ),
515 'vdo_version' => array(
516 'type' => 'string',
517 'default' => get_option('vdo_embed_version')
518 ),
519 ),
520 'render_callback' => 'vdo_shortcode'
521 )
522 );
523 }
524
525 add_action('init', 'vdo_register_block');
526
527 // Deactivation Hook starts
528 function vdo_uninstall()
529 {
530 delete_option('vdo_client_key');
531 delete_option('vdo_default_width');
532 delete_option('vdo_default_height');
533 delete_option('vdo_annotate_code');
534 delete_option('vdo_embed_version');
535 delete_option('vdo_player_theme');
536 delete_option('vdo_plugin_version');
537 delete_option('vdo_player_speed');
538 delete_option('vdo_show_plugin_in_sidebar');
539 delete_option('vdo_send_user_id_in_api');
540 }
541 register_uninstall_hook(__FILE__, 'vdo_uninstall');
542
543 // Admin notice to configure plugin for new installs, starts
544 function vdo_admin_notice()
545 {
546 if ((!get_option('vdo_client_key') || strlen(get_option('vdo_client_key')) != 64)
547 && basename($_SERVER['PHP_SELF']) == "plugins.php"
548 ) {
549 ?>
550 <div class="error">
551 <p>
552 The VdoCipher plugin is not ready.
553 <a href="options-general.php?page=vdocipher">Click here to configure</a>
554 </p>
555 </div>
556 <?php
557 }
558 }
559 add_action('admin_notices', 'vdo_admin_notice');
560