From d9f2283c60d94f821fbbbc5e62ec0517ad441b1b Mon Sep 17 00:00:00 2001 From: Pantelis Roditis Date: Sat, 30 Nov 2024 03:42:13 +0200 Subject: [PATCH 1/5] bump the versions for the assets --- frontend/assets/MaterialAsset.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/assets/MaterialAsset.php b/frontend/assets/MaterialAsset.php index 33ffa2371..d00d3c995 100644 --- a/frontend/assets/MaterialAsset.php +++ b/frontend/assets/MaterialAsset.php @@ -32,15 +32,15 @@ class MaterialAsset extends AssetBundle public $css = [ ['//fonts.googleapis.com/css?family=Roboto:300,400,500,700|Roboto+Slab:400,700|Material+Icons|Roboto+Mono|Orbitron&display=swap', 'async' => 'async', 'crossorigin' => "anonymous"], - ['css/all.min.css?v=0.20.3', 'defer' => 'defer'], - 'css/material-dashboard.css?v=0.20.0', - 'css/material.css?v=0.22.0', + ['css/all.min.css?v=1.0.0', 'defer' => 'defer'], + 'css/material-dashboard.css?v=1.0.0', + 'css/material.css?v=1.0.0', ]; public $js = [ - '/js/core/popper.min.js?v=0.20.0', - '/js/core/bootstrap-material-design.min.js?v=0.20.0', - '/js/plugins/perfect-scrollbar.jquery.min.js?v=0.20.0', + '/js/core/popper.min.js?v=1.0.0', + '/js/core/bootstrap-material-design.min.js?v=1.0.0', + '/js/plugins/perfect-scrollbar.jquery.min.js?v=1.0.0', // ["js/plugins/bootstrap-autocomplete.min.js", 'defer' => 'defer'], /* Plugin for the momentJs */ ['/js/plugins/moment.min.js', 'defer' => 'defer'], @@ -67,8 +67,8 @@ class MaterialAsset extends AssetBundle // 'https://maps.googleapis.com/maps/api/js?key=YOUR_KEY_HERE', /******/ //'/js/cookieconsent.min.js', // Move this to only the pages needing it. - '/js/material-dashboard.js?v=0.24.0', - ['/js/libechoctf.js?v=0.24.0', 'defer' => 'defer'], + '/js/material-dashboard.js?v=1.0.0', + ['/js/libechoctf.js?v=1.0.0', 'defer' => 'defer'], ]; public $depends = [ From e85a09df68bcbd26f9f2e773d2f49064015279d7 Mon Sep 17 00:00:00 2001 From: Pantelis Roditis Date: Sat, 30 Nov 2024 03:42:39 +0200 Subject: [PATCH 2/5] add id to the ip tag --- .../material/modules/target/views/default/_target_card.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/themes/material/modules/target/views/default/_target_card.php b/frontend/themes/material/modules/target/views/default/_target_card.php index 9b6e53d14..284e2b9c8 100644 --- a/frontend/themes/material/modules/target/views/default/_target_card.php +++ b/frontend/themes/material/modules/target/views/default/_target_card.php @@ -21,7 +21,10 @@ else $display_ip=Html::a($target_ip,$target_ip,["class"=>'copy-to-clipboard text-danger text-bold','swal-data'=>"Copied to clipboard",'data-toggle'=>'tooltip','title'=>\Yii::t('app',"The IP of your private instance. Click to copy IP to clipboard.")]); } - +if($target_ip=='0.0.0.0') +{ + $this->registerJs("targetUpdates({$target->id});", \yii\web\View::POS_READY); +} $subtitleARR=[$target->category,ucfirst($target->getDifficultyText($target->average_rating)),boolval($target->rootable) ? "Rootable" : "Non rootable",$target->timer===false ? null:'Timed']; $subtitle=implode(", ",array_filter($subtitleARR)); Card::begin([ @@ -31,7 +34,7 @@ 'icon'=>sprintf('', $target->logo), 'color'=>'target', 'subtitle'=>$subtitle, - 'title'=>sprintf('%s / %s', $target->name, $display_ip), + 'title'=>sprintf('%s / %s', $target->name, $display_ip), 'footer'=>sprintf('
%s
%s', $target->purpose, TargetCardActions::widget(['model'=>$target,'identity'=>$identity]) ), ]); echo "

", $target->total_treasures, ": Flag".($target->total_treasures > 1 ? 's' : '')." "; From 9d0514fe3b89c813228115a35bb3736bb4f6d879 Mon Sep 17 00:00:00 2001 From: Pantelis Roditis Date: Sat, 30 Nov 2024 03:43:04 +0200 Subject: [PATCH 3/5] add ip action --- .../target/controllers/DefaultController.php | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/frontend/modules/target/controllers/DefaultController.php b/frontend/modules/target/controllers/DefaultController.php index e575162ff..963c96e8b 100644 --- a/frontend/modules/target/controllers/DefaultController.php +++ b/frontend/modules/target/controllers/DefaultController.php @@ -46,16 +46,16 @@ public function behaviors() return ArrayHelper::merge(parent::behaviors(), [ 'access' => [ 'class' => AccessControl::class, - 'only' => ['index', 'view', 'claim', 'spin', 'spawn', 'shut', 'versus', 'badge', 'search'], + 'only' => ['index', 'view', 'claim', 'spin', 'spawn', 'shut', 'versus', 'badge', 'search','ip'], 'rules' => [ 'eventStartEnd' => [ - 'actions' => ['index', 'view', 'claim', 'spin', 'spawn', 'shut', 'versus', 'search'], + 'actions' => ['index', 'view', 'claim', 'spin', 'spawn', 'shut', 'versus', 'search','ip'], ], 'teamsAccess' => [ - 'actions' => ['index', 'claim', 'spin', 'spawn', 'shut', 'versus', 'search'], + 'actions' => ['index', 'claim', 'spin', 'spawn', 'shut', 'versus', 'search','ip'], ], 'disabledRoute' => [ - 'actions' => ['badge', 'view', 'index', 'claim', 'spin', 'spawn', 'shut', 'versus', 'search'], + 'actions' => ['badge', 'view', 'index', 'claim', 'spin', 'spawn', 'shut', 'versus', 'search', 'ip'], ], [ 'actions' => ['spawn', 'shut', 'spin'], @@ -110,7 +110,7 @@ public function behaviors() 'verbs' => ['post'], ], [ - 'actions' => ['index','search'], + 'actions' => ['index','search','ip'], 'allow' => true, 'roles' => ['@'] ], @@ -124,7 +124,7 @@ public function behaviors() }, ], [ - 'actions' => ['view', 'versus', 'badge'], + 'actions' => ['view', 'versus', 'badge','ip'], 'allow' => true, 'roles' => ['@'] ], @@ -140,7 +140,7 @@ public function behaviors() ], [ 'class' => 'yii\filters\AjaxFilter', - 'only' => ['claim', 'search'], + 'only' => ['claim', 'search','ip'], ], ]); } @@ -221,7 +221,7 @@ public function actionIndex() } /** - * Lists all Credits models. + * Returns target models matching $q. * @return mixed */ public function actionSearch($q) @@ -248,6 +248,32 @@ public function actionSearch($q) return []; } + /** + * Lists all Credits models. + * @return mixed + */ + + public function actionIp($id) + { + Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + if (($target = \app\modules\target\models\Target::find()->where(['t.id' => $id])->forView(\Yii::$app->user->id)->cache(true)->one()) === null) { + throw new NotFoundHttpException(\Yii::t('app', 'The requested target does not exist.')); + } + $obj=new \stdClass; + if (Yii::$app->user->identity->instance) + { + $obj->ip = long2ip(Yii::$app->user->identity->instance->ip); + $obj->instance=true; + } + else if(($target->on_ondemand===false) || ($target->on_ondemand && $target->ondemand_state==1)) + { + $obj->ip = long2ip($target->ip); + } + else + $obj->ip=long2ip(0); + + return $obj; + } /** * Renders a Target model details view * @return string From 40a77842d6b7cf4401c25d53634a4dd3fa8f1814 Mon Sep 17 00:00:00 2001 From: Pantelis Roditis Date: Sat, 30 Nov 2024 03:43:31 +0200 Subject: [PATCH 4/5] add javascript code to update the target ip --- frontend/web/js/libechoctf.js | 361 ++++++++++++++++++++-------------- 1 file changed, 208 insertions(+), 153 deletions(-) diff --git a/frontend/web/js/libechoctf.js b/frontend/web/js/libechoctf.js index 2eb8f8c97..b07f1d9f7 100644 --- a/frontend/web/js/libechoctf.js +++ b/frontend/web/js/libechoctf.js @@ -1,21 +1,20 @@ // Extend with ifexists for checking existing elements $.fn.extend({ 'ifexists': function (callback) { - if (this.length > 0) { - return callback($(this)); - } + if (this.length > 0) { + return callback($(this)); + } } }); /* Dummy escapeHtml implementation */ -function escapeHtml(unsafe) -{ - return unsafe - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); +function escapeHtml(unsafe) { + return unsafe + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); } // @@ -26,15 +25,14 @@ function isFileImage(file) { } /* Calculate luminanace */ -function luminanace(r, g, b) -{ - var a = [r, g, b].map(function (v) { - v /= 255; - return v <= 0.03928 - ? v / 12.92 - : Math.pow( (v + 0.055) / 1.055, 2.4 ); - }); - return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722; +function luminanace(r, g, b) { + var a = [r, g, b].map(function (v) { + v /= 255; + return v <= 0.03928 + ? v / 12.92 + : Math.pow((v + 0.055) / 1.055, 2.4); + }); + return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722; } /** * Override the default yii confirm dialog. This function is @@ -45,21 +43,18 @@ function luminanace(r, g, b) * @param string cancelCallback callback triggered when cancelled */ yii.confirm = function (message, okCallback, cancelCallback) { - var title='Are you sure?'; - var swType='warning'; - var showCancelButton=true; - if($(this).attr('data-title') !== 'undefined' && $(this).attr('data-title')!== false && $(this).attr('data-title') !== undefined) - { - title=$(this).attr('data-title')+'?'; + var title = 'Are you sure?'; + var swType = 'warning'; + var showCancelButton = true; + if ($(this).attr('data-title') !== 'undefined' && $(this).attr('data-title') !== false && $(this).attr('data-title') !== undefined) { + title = $(this).attr('data-title') + '?'; } - if($(this).attr('data-swType') !== 'undefined' && $(this).attr('data-swType')!== false && $(this).attr('data-swType') !== undefined) - { - swType=$(this).attr('data-swType'); + if ($(this).attr('data-swType') !== 'undefined' && $(this).attr('data-swType') !== false && $(this).attr('data-swType') !== undefined) { + swType = $(this).attr('data-swType'); } - if($(this).attr('data-showCancelButton') !== 'undefined' && $(this).attr('data-showCancelButton')!== false && $(this).attr('data-showCancelButton') !== undefined && $(this).attr('data-showCancelButton') == 'false' ) - { - showCancelButton=false; + if ($(this).attr('data-showCancelButton') !== 'undefined' && $(this).attr('data-showCancelButton') !== false && $(this).attr('data-showCancelButton') !== undefined && $(this).attr('data-showCancelButton') == 'false') { + showCancelButton = false; } swal({ @@ -80,46 +75,67 @@ yii.confirm = function (message, okCallback, cancelCallback) { * contrast([255, 255, 255], [255, 255, 0]); // 1.074 for yellow */ function contrast(rgb1, rgb2) { - return (luminanace(rgb1[0], rgb1[1], rgb1[2]) + 0.05) - / (luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05); + return (luminanace(rgb1[0], rgb1[1], rgb1[2]) + 0.05) + / (luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05); } -function showTime(){ +function showTime() { - var date = new Date(); - var h = date.getUTCHours(); // 0 - 23 - var m = date.getUTCMinutes(); // 0 - 59 - var s = date.getUTCSeconds(); // 0 - 59 - var session=""; - h = (h < 10) ? "0" + h : h; - m = (m < 10) ? "0" + m : m; - s = (s < 10) ? "0" + s : s; - session = (h < 12) ? "AM" : ""; + var date = new Date(); + var h = date.getUTCHours(); // 0 - 23 + var m = date.getUTCMinutes(); // 0 - 59 + var s = date.getUTCSeconds(); // 0 - 59 + var session = ""; + h = (h < 10) ? "0" + h : h; + m = (m < 10) ? "0" + m : m; + s = (s < 10) ? "0" + s : s; + session = (h < 12) ? "AM" : ""; - var time = h + ":" + m; - document.getElementById("time").innerText = time; - document.getElementById("time").textContent = time; + var time = h + ":" + m; + document.getElementById("time").innerText = time; + document.getElementById("time").textContent = time; - setTimeout(showTime, 1000); + setTimeout(showTime, 1000); } -jQuery( document ).ready(function() { +$(document).on('click', '.copy-to-clipboard', function (e) { + //$(".copy-to-clipboard").click(function (e) { + e.preventDefault(); + e.stopPropagation(); + + const el = document.createElement('textarea'); + el.value = $(this).attr('href'); + el.setAttribute('readonly', ''); + el.style.position = 'absolute'; + el.style.left = '-9999px'; + document.body.appendChild(el); + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); + if ($(this).parent('.dropdown-menu') && $(this).parent('.dropdown-menu').selectpicker) + $(this).parent('.dropdown-menu').selectpicker('toggle'); + if ($(this).attr('swal-data')) + return Swal.fire({ title: $(this).attr('swal-data'), closeOnClickOutside: false, }); + + return false; +}); + +jQuery(document).ready(function () { $(".card-nav-tabs .nav-tabs .nav-item:nth-of-type(1) .nav-link").addClass('active'); $(".tab-content .tab-pane:nth-of-type(1)").addClass('active'); $(".markdown img").addClass("img-fluid"); - $('.markdown a').attr('target','_blank'); - $('#claim-flag').on('pjax:success', function(event) { - window.location.reload(); + $('.markdown a').attr('target', '_blank'); + $('#claim-flag').on('pjax:success', function (event) { + window.location.reload(); }); - if(document.getElementById('signupform-password')) - { - const capscheck=document.getElementById("signupform-password"); - capscheck.addEventListener( 'keydown', function( event ) { - var caps = event.getModifierState && event.getModifierState( 'CapsLock' ); - if(caps) + if (document.getElementById('signupform-password')) { + const capscheck = document.getElementById("signupform-password"); + capscheck.addEventListener('keydown', function (event) { + var caps = event.getModifierState && event.getModifierState('CapsLock'); + if (caps) $('#form-signup').yiiActiveForm('updateAttribute', 'signupform-password', ['Caps Lock is on!']); else $('#form-signup').yiiActiveForm('updateAttribute', 'signupform-password', ''); @@ -127,126 +143,168 @@ jQuery( document ).ready(function() { }); } - $(".copy-to-clipboard").click(function(e){ - e.preventDefault(); - e.stopPropagation(); - - const el = document.createElement('textarea'); - el.value = $(this).attr('href'); - el.setAttribute('readonly', ''); - el.style.position = 'absolute'; - el.style.left = '-9999px'; - document.body.appendChild(el); - el.select(); - document.execCommand('copy'); - document.body.removeChild(el); - if($(this).parent('.dropdown-menu') && $(this).parent('.dropdown-menu').selectpicker) - $(this).parent('.dropdown-menu').selectpicker('toggle'); - if($(this).attr('swal-data')) - return Swal.fire({ title: $(this).attr('swal-data'),closeOnClickOutside: false,}); - - return false; - }) - - if(document.getElementById('writeup-content')) - { - const textarea=document.getElementById("writeup-content"); + if (document.getElementById('writeup-content')) { + const textarea = document.getElementById("writeup-content"); var converter = new showdown.Converter({ - omitExtraWLInCodeBlocks: true, - headerLevelStart: 2, - parseImgDimensions: true, - ghCodeBlocks: true, - simplifiedAutoLink: true, - tables: true, - tasklists: true, - simpleLineBreaks: true, - openLinksInNewWindow: true, - emoji: true, - splitAdjacentBlockquotes: true, - }); + omitExtraWLInCodeBlocks: true, + headerLevelStart: 2, + parseImgDimensions: true, + ghCodeBlocks: true, + simplifiedAutoLink: true, + tables: true, + tasklists: true, + simpleLineBreaks: true, + openLinksInNewWindow: true, + emoji: true, + splitAdjacentBlockquotes: true, + }); converter.setFlavor('github'); - document.getElementById("markdown-preview").innerHTML=converter.makeHtml(textarea.value); - textarea.addEventListener( 'keyup', function( event ) { - var text = textarea.value, - html = converter.makeHtml(text); - document.getElementById("markdown-preview").innerHTML=html; + document.getElementById("markdown-preview").innerHTML = converter.makeHtml(textarea.value); + textarea.addEventListener('keyup', function (event) { + var text = textarea.value, + html = converter.makeHtml(text); + document.getElementById("markdown-preview").innerHTML = html; }); } //showTime(); }); -$('#Notifications, #Hints').on('hide.bs.dropdown', function() { - const curId=$(this).attr('id') +$('#Notifications, #Hints').on('hide.bs.dropdown', function () { + const curId = $(this).attr('id') clearDropdownCounters(curId) }) -function clearDropdownCounters(curId){ -// on close remove the pill - $('#'+curId+'>a>span').remove(); +function clearDropdownCounters(curId) { + // on close remove the pill + $('#' + curId + '>a>span').remove(); // remove the text-primary - const el = document.querySelector('#'+curId+'>a>i'); + const el = document.querySelector('#' + curId + '>a>i'); el.classList.remove("text-primary"); } var notifTimeout; -var intervalTimeout=5000 +var targetTimeout; +var intervalTimeout = 5000; -function apiNotifications(){ - notifTimeout=setInterval(function () { +function targetUpdates(id) { + var targetEl = document.getElementById("target_id"); + targetTimeout = setInterval(function () { var request = new XMLHttpRequest(); - request.open("GET", "/api/notification"); + request.open("GET", `/target/${id}/ip`); request.setRequestHeader('X-Requested-With', 'XMLHttpRequest') request.send(); - request.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) { - jsonObj=JSON.parse(this.responseText)['items']; - for(i=0;i0) clearDropdownCounters('Notifications') + else { + if (jsonObj.ip == '0.0.0.0') { + el = document.createElement("b"); + el.setAttribute("data-toggle", "tooltip"); + el.setAttribute("title", "The IP will be visible once the system is powered up."); + el.innerHTML = jsonObj.ip; + $(targetEl.children[0]).tooltip('dispose'); + targetEl.innerHTML = ''; + targetEl.appendChild(el); + } + else { + el = document.createElement("a"); + el.innerHTML = jsonObj.ip; + el.href = jsonObj.ip; + el.className = "copy-to-clipboard text-dark text-bold"; + el.setAttribute("swal-data", "Copied to clipboard"); + el.setAttribute("data-toggle", "tooltip"); + el.setAttribute("title", "The IP of the target. Click to copy IP to clipboard."); + $(targetEl.children[0]).tooltip('dispose'); + targetEl.innerHTML = ''; + targetEl.appendChild(el); + } + } + } } } }, intervalTimeout); } -$(document).ready(function(){ - var x = setInterval(function() { +function apiNotifications() { + notifTimeout = setInterval(function () { + var request = new XMLHttpRequest(); + request.open("GET", "/api/notification"); + request.setRequestHeader('X-Requested-With', 'XMLHttpRequest') + request.send(); + + request.onreadystatechange = function () { + if (this.readyState == 4 && this.status == 200) { + jsonObj = JSON.parse(this.responseText)['items']; + for (i = 0; i < jsonObj.length; i++) { + const record = jsonObj[i]; + if (record.category.startsWith('swal')) { + if (!swal.isVisible()) { + swal.fire({ title: record.title, html: record.body, type: record.category.replace('swal:', ''), showConfirmButton: true, closeOnClickOutside: false }); + } + } + else { + $.notify({ + id: "notifw" + record.id, + message: record.title, + icon: "done" + }, { + timer: "4000", + type: record.category, + }) + } + } + if (jsonObj.length > 0) clearDropdownCounters('Notifications') + } + } + }, intervalTimeout); +} + +$(document).ready(function () { + $('body').tooltip({ + selector: '[data-toggle="tooltip"]', + }); + + var x = setInterval(function () { if (typeof countDownDate === 'undefined') return; // Get today's date and time // var now = new Date(); // Find the distance between now and the count down date - if(countDownDate===0) - { + if (countDownDate === 0) { clearInterval(x); return; } var timeNow = Date.now(); var distance = countDownDate - timeNow; - element=document.getElementById("event_countdown"); + element = document.getElementById("event_countdown"); msg = "The competition ends in: " - if(countDownStart>0 && countDownStart>timeNow) - { + if (countDownStart > 0 && countDownStart > timeNow) { distance = countDownStart - timeNow; msg = "The competition starts in: "; } @@ -261,36 +319,33 @@ $(document).ready(function(){ // If the count down is finished, write some text if (distance < 0) { clearInterval(x); - if(typeof(element)!='undefined' && element != null) + if (typeof (element) != 'undefined' && element != null) element.innerHTML = 'The competition is finished'; } - else - { - if(element) - { + else { + if (element) { //console.log(`${countDownStart} ${timeNow} ${distance}`); - if(days>0) - element.innerHTML = msg+ days + "d " + hours + "h " + minutes + "m " + seconds + "s"; - else if(hours>0) - element.innerHTML = msg+ hours + "h " + minutes + "m " + seconds + "s"; - else if(minutes>0) - element.innerHTML = msg+ minutes + "m " + seconds + "s"; - else if(seconds>0) + if (days > 0) + element.innerHTML = msg + days + "d " + hours + "h " + minutes + "m " + seconds + "s"; + else if (hours > 0) + element.innerHTML = msg + hours + "h " + minutes + "m " + seconds + "s"; + else if (minutes > 0) + element.innerHTML = msg + minutes + "m " + seconds + "s"; + else if (seconds > 0) element.innerHTML = msg + seconds + "seconds"; } } }, 1000); - $('#Notifications, #Hints').ifexists(function(elem) { - document.addEventListener('visibilitychange', function(e) { + $('#Notifications, #Hints').ifexists(function (elem) { + document.addEventListener('visibilitychange', function (e) { if (document.visibilityState === 'hidden') { clearTimeout(notifTimeout); } - else - { + else { clearTimeout(notifTimeout); // clear any existing ones - $('#Notifications, #Hints').ifexists(function(elem) { apiNotifications(); }) + $('#Notifications, #Hints').ifexists(function (elem) { apiNotifications(); }) } }); apiNotifications(); From 0b9fdeea6ce34c90fbb59173bc72361365b491e6 Mon Sep 17 00:00:00 2001 From: Pantelis Roditis Date: Sat, 30 Nov 2024 13:54:52 +0200 Subject: [PATCH 5/5] dont cache this query --- frontend/modules/target/controllers/DefaultController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/modules/target/controllers/DefaultController.php b/frontend/modules/target/controllers/DefaultController.php index 963c96e8b..9df69c6d4 100644 --- a/frontend/modules/target/controllers/DefaultController.php +++ b/frontend/modules/target/controllers/DefaultController.php @@ -256,7 +256,7 @@ public function actionSearch($q) public function actionIp($id) { Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; - if (($target = \app\modules\target\models\Target::find()->where(['t.id' => $id])->forView(\Yii::$app->user->id)->cache(true)->one()) === null) { + if (($target = \app\modules\target\models\Target::find()->where(['t.id' => $id])->forView(\Yii::$app->user->id)->one()) === null) { throw new NotFoundHttpException(\Yii::t('app', 'The requested target does not exist.')); } $obj=new \stdClass;