This is an automated email from the ASF dual-hosted git repository. solomax pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/openmeetings.git
The following commit(s) were added to refs/heads/master by this push: new 06f4030 [OPENMEETINGS-2365] NoSleep.js is added 06f4030 is described below commit 06f40309b7f5a034c830ebdd9edc01dff81342b4 Author: Maxim Solodovnik <solomax...@gmail.com> AuthorDate: Fri Jun 12 14:08:31 2020 +0700 [OPENMEETINGS-2365] NoSleep.js is added --- .../db/dao/basic/ConfigurationDao.java | 4 +- .../installation/ImportInitvalues.java | 12 +- .../src/main/assembly/components/templates.xml | 1 + .../openmeetings/util/OpenmeetingsVariables.java | 6 +- openmeetings-web/pom.xml | 3 + .../org/apache/openmeetings/web/room/NoSleep.js | 240 +++++++++++++++++++++ .../org/apache/openmeetings/web/room/raw-room.js | 15 +- pom.xml | 3 +- 8 files changed, 271 insertions(+), 13 deletions(-) diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java index 575f59e..7be84df 100644 --- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java +++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java @@ -592,8 +592,8 @@ public class ConfigurationDao implements IDataProviderDao<Configuration> { setCspFontSrc(getString(CONFIG_CSP_FONT, DEFAULT_CSP_FONT)); setCspFrameSrc(getString(CONFIG_CSP_FRAME, SELF.getValue())); - setCspImageSrc(getString(CONFIG_CSP_IMAGE, DEFAULT_CSP_IMAGE)); - setCspMediaSrc(getString(CONFIG_CSP_MEDIA, SELF.getValue())); + setCspImageSrc(getString(CONFIG_CSP_IMAGE, DEFAULT_CSP_DATA)); + setCspMediaSrc(getString(CONFIG_CSP_MEDIA, DEFAULT_CSP_DATA)); setCspScriptSrc(getString(CONFIG_CSP_SCRIPT, STRICT_DYNAMIC.getValue())); setCspStyleSrc(getString(CONFIG_CSP_STYLE, DEFAULT_CSP_STYLE)); if (Application.exists()) { diff --git a/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java b/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java index b564ea4..dcef308 100644 --- a/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java +++ b/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java @@ -31,13 +31,13 @@ import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CALENDAR import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CAM_FPS; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CHAT_SEND_ON_ENTER; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CRYPT; +import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CSP_ENABLED; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CSP_FONT; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CSP_FRAME; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CSP_IMAGE; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CSP_MEDIA; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CSP_SCRIPT; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CSP_STYLE; -import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CSP_ENABLED; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DASHBOARD_RSS_FEED1; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DASHBOARD_RSS_FEED2; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DASHBOARD_SHOW_CHAT; @@ -101,8 +101,8 @@ import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_TIM import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_TLS; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_USER; import static org.apache.openmeetings.util.OpenmeetingsVariables.DEFAULT_APP_NAME; +import static org.apache.openmeetings.util.OpenmeetingsVariables.DEFAULT_CSP_DATA; import static org.apache.openmeetings.util.OpenmeetingsVariables.DEFAULT_CSP_FONT; -import static org.apache.openmeetings.util.OpenmeetingsVariables.DEFAULT_CSP_IMAGE; import static org.apache.openmeetings.util.OpenmeetingsVariables.DEFAULT_CSP_STYLE; import static org.apache.openmeetings.util.OpenmeetingsVariables.DEFAULT_MAX_UPLOAD_SIZE; import static org.apache.openmeetings.util.OpenmeetingsVariables.DEFAULT_MINUTES_REMINDER_SEND; @@ -374,10 +374,10 @@ public class ImportInitvalues { + cspMore, DEFAULT_CSP_FONT), VER_5_0_0); addCfg(list, CONFIG_CSP_FRAME, SELF.getValue(), Configuration.Type.STRING, String.format("Value for 'frame-src' directive of 'Content-Security-Policy' header (default: %s)" + cspMore, SELF), VER_5_0_0); - addCfg(list, CONFIG_CSP_IMAGE, DEFAULT_CSP_IMAGE, Configuration.Type.STRING, String.format("Value for 'image-src' directive of 'Content-Security-Policy' header (default: %s)" - + cspMore, DEFAULT_CSP_IMAGE), VER_5_0_0); - addCfg(list, CONFIG_CSP_MEDIA, SELF.getValue(), Configuration.Type.STRING, String.format("Value for 'media-src' directive of 'Content-Security-Policy' header (default: %s)" - + cspMore, SELF), VER_5_0_0); + addCfg(list, CONFIG_CSP_IMAGE, DEFAULT_CSP_DATA, Configuration.Type.STRING, String.format("Value for 'image-src' directive of 'Content-Security-Policy' header (default: %s)" + + cspMore, DEFAULT_CSP_DATA), VER_5_0_0); + addCfg(list, CONFIG_CSP_MEDIA, DEFAULT_CSP_DATA, Configuration.Type.STRING, String.format("Value for 'media-src' directive of 'Content-Security-Policy' header (default: %s)" + + cspMore, DEFAULT_CSP_DATA), VER_5_0_0); addCfg(list, CONFIG_CSP_SCRIPT, STRICT_DYNAMIC.getValue(), Configuration.Type.STRING, String.format("Value for 'script-src' directive of 'Content-Security-Policy' header (default: %s)" + cspMore, STRICT_DYNAMIC), VER_5_0_0); addCfg(list, CONFIG_CSP_STYLE, DEFAULT_CSP_STYLE, Configuration.Type.STRING, String.format("Value for 'style-src' directive of 'Content-Security-Policy' header (default: %s)" diff --git a/openmeetings-server/src/main/assembly/components/templates.xml b/openmeetings-server/src/main/assembly/components/templates.xml index 5d3f7e6..68adfa8 100644 --- a/openmeetings-server/src/main/assembly/components/templates.xml +++ b/openmeetings-server/src/main/assembly/components/templates.xml @@ -39,6 +39,7 @@ <exclude>**/fileinput.css</exclude> <exclude>**/adapter-latest.js</exclude> <exclude>**/kurento-utils.js</exclude> + <exclude>**/NoSleep.js</exclude> <exclude>**/network.js</exclude> </excludes> </fileSet> diff --git a/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java b/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java index 91187d9..31467bf 100644 --- a/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java +++ b/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java @@ -119,7 +119,7 @@ public class OpenmeetingsVariables { public static final String DEFAULT_SIP_CONTEXT = "rooms"; public static final String DEFAULT_CSP_FONT = "https://fonts.gstatic.com"; public static final String DEFAULT_CSP_STYLE = "https://fonts.googleapis.com/css"; - public static final String DEFAULT_CSP_IMAGE = "data:"; + public static final String DEFAULT_CSP_DATA = SELF.getValue() + ",data:"; private static String cryptClassName = null; private static String wicketApplicationName = null; @@ -154,8 +154,8 @@ public class OpenmeetingsVariables { private static boolean myRoomsEnabled = true; private static String cspFontSrc = DEFAULT_CSP_FONT; private static String cspFrameSrc = SELF.getValue(); - private static String cspImageSrc = DEFAULT_CSP_IMAGE; - private static String cspMediaSrc = SELF.getValue(); + private static String cspImageSrc = DEFAULT_CSP_DATA; + private static String cspMediaSrc = DEFAULT_CSP_DATA; private static String cspScriptSrc = STRICT_DYNAMIC.getValue(); private static String cspStyleSrc = DEFAULT_CSP_STYLE; private static String smtpServer; diff --git a/openmeetings-web/pom.xml b/openmeetings-web/pom.xml index 755d1f1..7268839 100644 --- a/openmeetings-web/pom.xml +++ b/openmeetings-web/pom.xml @@ -201,6 +201,7 @@ <charset>UTF-8</charset> <jsSourceDir>../java/org/apache/openmeetings/web/room</jsSourceDir> <jsSourceFiles> + <jsSourceFile>NoSleep.js</jsSourceFile> <jsSourceFile>raw-video.js</jsSourceFile> <jsSourceFile>raw-video-manager.js</jsSourceFile> <jsSourceFile>raw-sharer.js</jsSourceFile> @@ -281,6 +282,7 @@ **/fileinput.css, **/adapter-latest.js, **/kurento-utils.js, + **/NoSleep.js, **/network.js </packagingExcludes> <warSourceExcludes> @@ -292,6 +294,7 @@ **/fileinput.css, **/adapter-latest.js, **/kurento-utils.js, + **/NoSleep.js, **/network.js </warSourceExcludes> <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors> diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/NoSleep.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/NoSleep.js new file mode 100644 index 0000000..60e6761 --- /dev/null +++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/NoSleep.js @@ -0,0 +1,240 @@ +/*! NoSleep.js v0.11.0 - git.io/vfn01 - Rich Tibbett - MIT license */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["NoSleep"] = factory(); + else + root["NoSleep"] = factory(); +})(window, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) [...] + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var _require = __webpack_require__(1), + webm = _require.webm, + mp4 = _require.mp4; + +// Detect iOS browsers < version 10 + + +var oldIOS = typeof navigator !== "undefined" && parseFloat(("" + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ""])[1]).replace("undefined", "3_2").replace("_", ".").replace("_", "")) < 10 && !window.MSStream; + +// Detect native Wake Lock API support +var nativeWakeLock = "wakeLock" in navigator; + +var NoSleep = function () { + function NoSleep() { + var _this = this; + + _classCallCheck(this, NoSleep); + + if (nativeWakeLock) { + this._wakeLock = null; + var handleVisibilityChange = function handleVisibilityChange() { + if (_this._wakeLock !== null && document.visibilityState === "visible") { + _this.enable(); + } + }; + document.addEventListener("visibilitychange", handleVisibilityChange); + document.addEventListener("fullscreenchange", handleVisibilityChange); + } else if (oldIOS) { + this.noSleepTimer = null; + } else { + // Set up no sleep video element + this.noSleepVideo = document.createElement("video"); + + this.noSleepVideo.setAttribute("title", "No Sleep"); + this.noSleepVideo.setAttribute("playsinline", ""); + + this._addSourceToVideo(this.noSleepVideo, "webm", webm); + this._addSourceToVideo(this.noSleepVideo, "mp4", mp4); + + this.noSleepVideo.addEventListener("loadedmetadata", function () { + if (_this.noSleepVideo.duration <= 1) { + // webm source + _this.noSleepVideo.setAttribute("loop", ""); + } else { + // mp4 source + _this.noSleepVideo.addEventListener("timeupdate", function () { + if (_this.noSleepVideo.currentTime > 0.5) { + _this.noSleepVideo.currentTime = Math.random(); + } + }); + } + }); + } + } + + _createClass(NoSleep, [{ + key: "_addSourceToVideo", + value: function _addSourceToVideo(element, type, dataURI) { + var source = document.createElement("source"); + source.src = dataURI; + source.type = "video/" + type; + element.appendChild(source); + } + }, { + key: "enable", + value: function enable() { + var _this2 = this; + + if (nativeWakeLock) { + navigator.wakeLock.request("screen").then(function (wakeLock) { + _this2._wakeLock = wakeLock; + console.log("Wake Lock active."); + _this2._wakeLock.addEventListener("release", function () { + // ToDo: Potentially emit an event for the page to observe since + // Wake Lock releases happen when page visibility changes. + // (https://web.dev/wakelock/#wake-lock-lifecycle) + console.log("Wake Lock released."); + }); + }).catch(function (err) { + console.error(err.name + ", " + err.message); + }); + } else if (oldIOS) { + this.disable(); + console.warn("\n NoSleep enabled for older iOS devices. This can interrupt\n active or long-running network requests from completing successfully.\n See https://github.com/richtr/NoSleep.js/issues/15 for more details.\n "); + this.noSleepTimer = window.setInterval(function () { + if (!document.hidden) { + window.location.href = window.location.href.split("#")[0]; + window.setTimeout(window.stop, 0); + } + }, 15000); + } else { + this.noSleepVideo.play(); + } + } + }, { + key: "disable", + value: function disable() { + if (nativeWakeLock) { + this._wakeLock.release(); + this._wakeLock = null; + } else if (oldIOS) { + if (this.noSleepTimer) { + console.warn("\n NoSleep now disabled for older iOS devices.\n "); + window.clearInterval(this.noSleepTimer); + this.noSleepTimer = null; + } + } else { + this.noSleepVideo.pause(); + } + } + }]); + + return NoSleep; +}(); + +module.exports = NoSleep; + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = { + webm: "data:video/webm;base64,GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA=", + mp4: "data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem [...] +}; + +/***/ }) +/******/ ]); +}); \ No newline at end of file diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js index 75572e3..6e5297f 100644 --- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js +++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js @@ -1,7 +1,7 @@ /* Licensed under the Apache License, Version 2.0 (the "License") http://www.apache.org/licenses/LICENSE-2.0 */ var Room = (function() { const self = {}, sbSide = Settings.isRtl ? 'right' : 'left'; - let options, menuHeight, sb, dock, activities; + let options, menuHeight, sb, dock, activities, noSleep; function _init(_options) { options = _options; @@ -158,6 +158,18 @@ var Room = (function() { $(window).on('keydown.openmeetings', _preventKeydown); $(window).on('keyup.openmeetings', _keyHandler); $(document).click(_mouseHandler); + _addNoSleep(); + } + function _addNoSleep() { + _removeNoSleep(); + noSleep = new NoSleep(); + noSleep.enable(); + } + function _removeNoSleep() { + if (noSleep) { + noSleep.disable(); + noSleep = null; + } } function _unload() { $('body').removeClass('no-header'); @@ -179,6 +191,7 @@ var Room = (function() { $(document).off('click', _mouseHandler); sb = undefined; Sharer.close(); + _removeNoSleep(); } function _showClipboard(txt) { const dlg = $('#clipboard-dialog'); diff --git a/pom.xml b/pom.xml index 22fd08d..a4dacdb 100644 --- a/pom.xml +++ b/pom.xml @@ -118,7 +118,7 @@ <quartz.version>2.3.2</quartz.version> <kurento.version>6.13.1</kurento.version> <!-- Exclude all generated code --> - <sonar.exclusions>file:**/generated-sources/**, file:**/jquery-ui.css, file:**/fabric.js, file:**/cssemoticons.js, file:**/adapter-latest.js, file:**/kurento-utils.js, file:**/fileinput*.js, file:**/MathJax.js, file:**/network.js</sonar.exclusions> + <sonar.exclusions>file:**/generated-sources/**, file:**/jquery-ui.css, file:**/fabric.js, file:**/cssemoticons.js, file:**/adapter-latest.js, file:**/kurento-utils.js, file:**/NoSleep.js, file:**/fileinput*.js, file:**/MathJax.js, file:**/network.js</sonar.exclusions> <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin> <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis> <sonar.junit.reportPaths>target/surefire-reports</sonar.junit.reportPaths> @@ -991,6 +991,7 @@ <pattern>Licensed under the MIT license</pattern> <pattern>MIT/GPL2 Licensed</pattern> <pattern>licensed under the MIT and GPL</pattern> + <pattern>MIT license</pattern> </patterns> </license> <license implementation="org.apache.rat.analysis.license.SimplePatternBasedLicense">