diff --git a/.env.example b/.env.example index 4899e60..033f2d7 100644 --- a/.env.example +++ b/.env.example @@ -5,4 +5,5 @@ TIME_ZONE=Asia/Ho_Chi_Minh NTP_SERVER=pool.ntp.org DOWNLOAD_INVERVAL=300 DATA_PATH=/var/www/app/data/ -#CUSTOM_SCRIPT_192_168_1_10=http://url/custom_download_script_for_your_camera.sh \ No newline at end of file +#CUSTOM_SCRIPT_192_168_1_10=http://url/custom_download_script_for_your_camera.sh +HOTLINK_SECRET=hellowordmyseret diff --git a/Dockerfile b/Dockerfile index b83d04e..0c5c9e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,11 +33,28 @@ RUN apk --update add wget \ mkdir -p /var/log/supervisor && \ rm /etc/nginx/nginx.conf +WORKDIR /var/www/app +ADD ./webui/composer.json ./webui/composer.lock ./ +RUN composer install +ADD ./webui/scripts/package.json ./webui/scripts/yarn.lock ./scripts/ +RUN npm install -g yarn && cd /var/www/app/scripts/ && yarn install +ADD ./webui/scripts/main.js ./webui/scripts/player.js ./scripts/ +ADD ./webui/index.php ./ +ADD ./webui/libs ./libs +ADD ./webui/templates ./templates + + +RUN mkdir -p /opt/yidownload/ +WORKDIR /opt/yidownload/ +ADD ./cronjob/yiantcopy.sh ./ +ADD ./config/start.sh ./ +RUN chmod 755 /opt/yidownload/*.sh + +RUN mkdir -p /var/www/app/data + ADD ./config/nginx/nginx.conf /etc/nginx/nginx.conf ADD ./config/supervisord/supervisord.conf /etc/supervisord.conf -ADD ./config/start.sh /start.sh - # tweak php-fpm config RUN sed -i -e "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g" /etc/php5/php.ini && \ sed -i -e "s/upload_max_filesize\s*=\s*2M/upload_max_filesize = 500M/g" /etc/php5/php.ini && \ @@ -60,28 +77,12 @@ RUN sed -i -e "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g" /etc/php5/php.ini rm -Rf /etc/nginx/conf.d/* && \ rm -Rf /etc/nginx/sites-available/default && \ mkdir -p /etc/nginx/ssl/ && \ - chmod 755 /start.sh && \ find /etc/php5/conf.d/ -name "*.ini" -exec sed -i -re 's/^(\s*)#(.*)/\1;\2/g' {} \; - ADD ./config/nginx/site-default.conf /etc/nginx/sites-enabled/default.conf -RUN mkdir -p /var/www/app/tmp/ && chmod 777 /var/www/app/tmp/ -WORKDIR /var/www/app -ADD ./webui/composer.json ./webui/composer.lock ./ -RUN composer install -ADD ./webui/scripts ./scripts -RUN cd /var/www/app/scripts/ && npm install -ADD ./webui/index.php ./ -ADD ./webui/libs ./libs -ADD ./webui/templates ./templates +RUN mkdir -p /var/www/app/tmp/ && chmod 777 /var/www/app/tmp/ -RUN mkdir -p /opt/yidownload/ -WORKDIR /opt/yidownload/ -ADD ./cronjob/yiantcopy.sh ./ -ADD ./config/start.sh ./ -RUN chmod 755 /opt/yidownload/*.sh -RUN mkdir -p /var/www/app/data VOLUME /var/www/app/data # Expose Ports diff --git a/config/nginx/site-default.conf b/config/nginx/site-default.conf index f02a409..3d7d98d 100644 --- a/config/nginx/site-default.conf +++ b/config/nginx/site-default.conf @@ -8,7 +8,7 @@ server { index index.php; - add_header X-Frame-Options "SAMEORIGIN"; + add_header X-Frame-Options "ALLOW-FROM http://hassio.phuonglm.net/"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; @@ -35,7 +35,6 @@ server { internal; } - location / { # First attempt to serve request as file, then # as directory, then fall back to front-end controller @@ -43,6 +42,19 @@ server { try_files $uri $uri/ /index.php$is_args$args; } + location /data { + secure_link $arg_md5,$arg_expires; + secure_link_md5 "$secure_link_expires$uri "; + + if ($secure_link = "") { + return 403; + } + + if ($secure_link = "0") { + return 410; + } + root /var/www/app; + } location ~ ^/.+\.php { root /var/www/app; @@ -97,4 +109,4 @@ server { # Don't log robots.txt or favicon.ico files location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { allow all; access_log off; log_not_found off; } -} \ No newline at end of file +} diff --git a/config/start.sh b/config/start.sh index 560eac2..4720afa 100644 --- a/config/start.sh +++ b/config/start.sh @@ -7,6 +7,7 @@ echo -e "Host *\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config # Tweak nginx to match the workers to cpu's procs=$(cat /proc/cpuinfo |grep processor | wc -l) sed -i -e "s/worker_processes 5/worker_processes $procs/" /etc/nginx/nginx.conf +sed -i -e "s//$HOTLINK_SECRET/" /etc/nginx/sites-enabled/default.conf # If an htpasswd file is provided, download and configure nginx @@ -23,7 +24,7 @@ printenv | grep -v affinity:container | xargs -I{} echo {} | awk 'BEGIN { FS = " if [ -f /var/www/app/phing ]; then cd /var/www/app /var/www/app/phing ${STAGE} -fi +fi chown -R nginx:nginx /var/www/app diff --git a/webui/libs/utils.php b/webui/libs/utils.php index 74c636d..2013d8f 100644 --- a/webui/libs/utils.php +++ b/webui/libs/utils.php @@ -1,6 +1,9 @@ = DateTime::createFromFormat('Y\Ym\Md\DH\H',$start->format('Y\Ym\Md\DH\H')) && DateTime::createFromFormat('Y\Ym\Md\DH\H',$file) <= DateTime::createFromFormat('Y\Ym\Md\DH\H',$end->format('Y\Ym\Md\DH\H'))){ array_push($dirList, $file); @@ -150,7 +153,7 @@ function getData(){ $hostsname = explode(" ", getenv('CAMERAS')); foreach ($hostsname as $hostname) { $timeLine = new TimeLine($hostname.'/'); - $records = $timeLine->getRange($startDate, + $records = $timeLine->getRange($startDate, $endDate); foreach ($records as $record) { array_push($data->rows, array('c' => array( @@ -163,7 +166,17 @@ function getData(){ echo json_encode($data); }; +function path_hash($path, $expires, $secret){ + $expires = time() + $expires; + $md5 = md5("$expires$path $secret", true); + $md5 = base64_encode($md5); + $md5 = strtr($md5, '+/', '-_'); + $md5 = str_replace('=', '', $md5); + return $path . '?md5=' . $md5 . '&expires=' . $expires; +} + function getPlaylist(){ + $base = $_GET['base']; $start = new DateTime(); $start->setTimestamp( intval($_GET['start']/1000)); @@ -172,19 +185,20 @@ function getPlaylist(){ $end->setTimestamp(intval($_GET['end']/1000)); $playlist = Utils::getRecordList($base, $start, $end); - $protocol = explode("/",$_SERVER['SERVER_PROTOCOL']); - $protocol = strtolower(array_shift($protocol)); - + $protocol = "http"; + if(isset($_SERVER['HTTP_X_FORWARDED_SCHEME'])){ + $protocol = $_SERVER['HTTP_X_FORWARDED_SCHEME']; + } if ($_GET['type'] == 'm3u'){ header("content-type: audio/x-mpegurl"); echo "#EXTM3U \r\n"; foreach ($playlist as $media) { - echo $protocol."://".$_SERVER['HTTP_HOST'] . '/data/' . $base . '/' . $media . "\r\n"; + echo $protocol."://".$_SERVER['HTTP_HOST'] . path_hash('/data/' . $base . '/' . $media, $GLOBALS['HOTLINK_TTL'], $GLOBALS['HOTLINK_SECRET']) . "\r\n"; } } elseif ($_GET['type'] == 'json') { $result = array(); foreach ($playlist as $media) { - $fullUrl = $protocol."://".$_SERVER['HTTP_HOST'] . '/data/'. $base . '/' . $media; + $fullUrl = $protocol."://".$_SERVER['HTTP_HOST'] . path_hash('/data/' . $base . '/' . $media, $GLOBALS['HOTLINK_TTL'], $GLOBALS['HOTLINK_SECRET']); array_push($result, $fullUrl); } echo json_encode($result); @@ -210,11 +224,11 @@ function deletePlaylist(){ } $module = ""; -if ($_GET['a'] == 'getData'){ +if (isset($_GET['a']) && $_GET['a'] == 'getData'){ getData(); -} elseif ($_GET['a'] == 'getPlaylist') { +} elseif (isset($_GET['a']) && $_GET['a'] == 'getPlaylist') { getPlaylist(); -} elseif ($_GET['a'] == 'deletePlaylist') { +} elseif (isset($_GET['a']) && $_GET['a'] == 'deletePlaylist') { deletePlaylist(); } else { $module = "index"; diff --git a/webui/scripts/main.js b/webui/scripts/main.js index 28ebc83..508bfa7 100644 --- a/webui/scripts/main.js +++ b/webui/scripts/main.js @@ -74,7 +74,7 @@ $(document).ready(function(){ }); function getDateFromMedia(url){ - return moment(url.substring(44,65),"YYYY[Y]MM[M]DD[D]HH[H]/mm[M]ss[S]"); + return moment(url.match(/^.*\.mp4/)[0].slice(-25).substring(0,21),"YYYY[Y]MM[M]DD[D]HH[H]/mm[M]ss[S]"); } function drawChart() { @@ -145,11 +145,10 @@ function drawChart() { $("#cameraVideo").data("base", base); - - - - $('#myModal').bind('keydown', function(e){ + $('#myModal').bind('keydown',function(e){ var keycode = e.keyCode; + var myPlayer = videojs('cameraVideo'); + if (keycode == 39) { var item = myPlayer.playlist.next(); if(item){ @@ -165,7 +164,7 @@ function drawChart() { } }); - $('#video_container').swipe({ + $('#video_container video').swipe({ swipe:function(event, direction, distance, duration, fingerCount, fingerData) { if (direction === 'left') { var item = myPlayer.playlist.next(); @@ -178,6 +177,7 @@ function drawChart() { $('#pushModalLabel').html(getDateFromMedia(videojs('cameraVideo').currentSource().src).format("D/M HH:mm")); } } + return true; }, doubleTab: function(event, target){ myPlayer.requestFullscreen(); @@ -185,7 +185,7 @@ function drawChart() { } }); - $('#video_container').bind('dblclick', function() { myPlayer.requestFullscreen(); }); + $('#video_container video').bind('dblclick', function() { myPlayer.requestFullscreen(); }); myPlayer.playlist(playlist, 0); myPlayer.playlist.autoadvance(0); @@ -199,4 +199,3 @@ function drawChart() { } - diff --git a/webui/scripts/package.json b/webui/scripts/package.json index c7ef0d6..2991644 100644 --- a/webui/scripts/package.json +++ b/webui/scripts/package.json @@ -9,12 +9,12 @@ "bootstrap-datepicker": "1.8.0", "bootstrap4-fs-modal": "^0.1.5", "font-awesome": "^4.7.0", - "jquery": "^3.3.1", + "jquery": "^3.5.0", "jquery-touchswipe": "^1.6.19", "moment": "2.22.2", "popper.js": "^1.14.3", - "video.js": "6.2.0", - "videojs-playlist": "^4.2.0" + "video.js": "7.4.1", + "videojs-playlist": "^4.3.0" }, "devDependencies": {}, "scripts": { diff --git a/webui/scripts/yarn.lock b/webui/scripts/yarn.lock index e2f2b14..e6cdeea 100644 --- a/webui/scripts/yarn.lock +++ b/webui/scripts/yarn.lock @@ -28,13 +28,6 @@ aes-decrypter@3.0.0: global "^4.3.2" pkcs7 "^1.0.2" -babel-runtime@^6.9.2: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - bootstrap-autohidingnavbar@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/bootstrap-autohidingnavbar/-/bootstrap-autohidingnavbar-4.0.0.tgz#10a2853e62e7ef98f09b46ba4ca181e04ad4850a" @@ -59,18 +52,10 @@ commander@^2.9.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" -core-js@^2.4.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.2.tgz#267988d7268323b349e20b4588211655f0e83944" - dom-walk@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" -es5-shim@^4.5.1: - version "4.5.12" - resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.5.12.tgz#508c13dda1c87dd3df1b50e69e7b96b82149b649" - font-awesome@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" @@ -104,9 +89,9 @@ jquery-touchswipe@^1.6.19: version "1.6.19" resolved "https://registry.yarnpkg.com/jquery-touchswipe/-/jquery-touchswipe-1.6.19.tgz#dfd5ddaec0b78212dd500d29707129b9c7fd6cd4" -"jquery@>=1.7.1 <4.0.0", jquery@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" +"jquery@>=1.7.1 <4.0.0", jquery@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.0.tgz#9980b97d9e4194611c36530e7dc46a58d7340fc9" m3u8-parser@4.2.0: version "4.2.0" @@ -152,10 +137,6 @@ process@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - regenerator-runtime@^0.12.0: version "0.12.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" @@ -184,20 +165,7 @@ url-toolkit@^2.1.1, url-toolkit@^2.1.3: version "2.1.6" resolved "https://registry.yarnpkg.com/url-toolkit/-/url-toolkit-2.1.6.tgz#6d03246499e519aad224c44044a4ae20544154f2" -video.js@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/video.js/-/video.js-6.2.0.tgz#2d35db30eb734270096c8dd541d35d790529c705" - dependencies: - babel-runtime "^6.9.2" - global "4.3.2" - safe-json-parse "4.0.0" - tsml "1.0.1" - videojs-font "2.0.0" - videojs-ie8 "1.1.2" - videojs-vtt.js "0.12.4" - xhr "2.4.0" - -"video.js@^6 || ^7", "video.js@^6.8.0 || ^7.0.0": +video.js@7.4.1, "video.js@^6 || ^7", "video.js@^6.8.0 || ^7.0.0": version "7.4.1" resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.4.1.tgz#41349d3b0ca40fa281c6f906381a0a41b75bd04e" dependencies: @@ -210,33 +178,17 @@ video.js@6.2.0: videojs-vtt.js "0.14.1" xhr "2.4.0" -videojs-font@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-2.0.0.tgz#af7461ef9d4b95e0334bffb78b2f2ff0364a9034" - videojs-font@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-3.1.0.tgz#ac33be9b517fe19299f61cccd2b3c7d75a1c6960" -videojs-ie8@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/videojs-ie8/-/videojs-ie8-1.1.2.tgz#a23d3d8608ad7192b69c6077fc4eb848998d35d9" - dependencies: - es5-shim "^4.5.1" - -videojs-playlist@^4.2.0: +videojs-playlist@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/videojs-playlist/-/videojs-playlist-4.3.0.tgz#67736a48f30575c84841512e50be38900be2ce4d" dependencies: global "^4.3.2" video.js "^6 || ^7" -videojs-vtt.js@0.12.4: - version "0.12.4" - resolved "https://registry.yarnpkg.com/videojs-vtt.js/-/videojs-vtt.js-0.12.4.tgz#38f2499e31efb3fa93590ddad4cb663275a4b161" - dependencies: - global "^4.3.1" - videojs-vtt.js@0.14.1: version "0.14.1" resolved "https://registry.yarnpkg.com/videojs-vtt.js/-/videojs-vtt.js-0.14.1.tgz#da583eb1fc9c81c826a9432b706040e8dea49911" diff --git a/webui/templates/index.tpl b/webui/templates/index.tpl index 094786f..b6dc266 100644 --- a/webui/templates/index.tpl +++ b/webui/templates/index.tpl @@ -1,5 +1,5 @@ - + {$doc_title} @@ -21,14 +21,11 @@ - - - - +