├── .github ├── CODEOWNERS └── workflows │ └── secrets-scanning.yml ├── .gitleaksignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── app ├── board.php ├── boctf.php ├── bootstrap.php ├── conf │ ├── .htaccess │ └── conf.php ├── dashboard │ ├── dashjson.php │ ├── index.php │ ├── js │ │ ├── security_dashboard.js │ │ └── ss │ │ │ ├── ss.js │ │ │ ├── ss_communication_ajax.js │ │ │ ├── ss_dom_css.js │ │ │ ├── ss_utility_serialize.js │ │ │ └── ss_utility_url.js │ ├── styles.css │ └── templates │ │ ├── .htaccess │ │ └── dashboard.html ├── dashjson.php ├── index.php ├── js │ ├── security.js │ ├── security_dashboard.js │ ├── sendmsg.js │ └── ss │ │ ├── ss.js │ │ ├── ss_communication_ajax.js │ │ ├── ss_dom_css.js │ │ ├── ss_utility_serialize.js │ │ └── ss_utility_url.js ├── json.php ├── lib │ ├── .htaccess │ ├── Auth.php │ ├── DB.php │ ├── Game.php │ └── Team.php ├── scripts │ ├── .htaccess │ ├── game.pem │ └── normalizer.php ├── sendmessage.php ├── styles.css ├── templates │ ├── .htaccess │ ├── board.html │ ├── boctf.html │ ├── dashboard.html │ └── index.html └── websock │ ├── .gitignore │ ├── .htaccess │ ├── app │ └── server.js │ ├── logs.sh │ ├── old │ ├── run_server.sh │ ├── server.php │ ├── websocket.admin.php │ ├── websocket.client.php │ ├── websocket.exceptions.php │ ├── websocket.framing.php │ ├── websocket.functions.php │ ├── websocket.message.php │ ├── websocket.resources.php │ ├── websocket.server.php │ └── websocket.users.php │ ├── package.json │ ├── start_websockets.sh │ └── stop_websockets.sh ├── catalog-info.yaml ├── composer.json ├── composer.lock ├── composer.phar ├── docker-compose.yml ├── docker ├── nginx │ ├── Dockerfile │ └── default.conf └── php │ └── Dockerfile ├── screenshots ├── backoffice.png ├── public dashboard.png └── team dashboard.png ├── sql ├── .htaccess └── schema.sql └── vendor ├── autoload.php ├── composer ├── ClassLoader.php ├── LICENSE ├── autoload_classmap.php ├── autoload_namespaces.php ├── autoload_psr4.php ├── autoload_real.php ├── autoload_static.php └── installed.json └── textalk └── websocket ├── .coveralls.yml ├── .gitignore ├── .travis.yml ├── Makefile ├── README.md ├── composer.json ├── composer.lock ├── examples ├── echoserver.php └── send.php ├── lib ├── BadOpcodeException.php ├── BadUriException.php ├── Base.php ├── Client.php ├── ConnectionException.php ├── Exception.php └── Server.php ├── phpunit.xml.dist └── tests └── unit └── ClientTest.php /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @tmendo -------------------------------------------------------------------------------- /.github/workflows/secrets-scanning.yml: -------------------------------------------------------------------------------- 1 | name: Detect Secrets 2 | on: 3 | pull_request: 4 | push: 5 | workflow_dispatch: 6 | jobs: 7 | secrets-scan: 8 | uses: probely/snyk-prodsec/.github/workflows/secrets-scanning.yml@main 9 | with: 10 | channel: probely-alerts 11 | secrets: 12 | SLACK_BOT_TOKEN: ${{ secrets.SLACK_SECRET }} 13 | GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} 14 | -------------------------------------------------------------------------------- /.gitleaksignore: -------------------------------------------------------------------------------- 1 | 7cb3c9f95e5057ec0e5ddbffbc7ac3ffb5b48369:app/scripts/ssl.key:private-key:1 2 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/gitleaks/gitleaks 3 | rev: v8.24.2 4 | hooks: 5 | - id: gitleaks 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pixels Camp Security CTF Dashboard 2 | 3 | This is the repo for the Pixels Camp Security CTF Dashboard, which includes 4 | 5 | * a public dashboard 6 | * a private team area to submit answers/follow progress 7 | * a backoffice for the organization 8 | 9 | Public dashboard: 10 | ![Public dashboard](https://github.com/Probely/CTF-Game/blob/master/screenshots/public%20dashboard.png) 11 | 12 | Private team area: 13 | ![Private team area](https://github.com/Probely/CTF-Game/blob/master/screenshots/team%20dashboard.png) 14 | 15 | Organization backoffice: 16 | ![Organization backoffice](https://github.com/Probely/CTF-Game/blob/master/screenshots/backoffice.png) 17 | 18 | Main features of the dashboard 19 | 20 | * start/stop the CTF 21 | * pause the counter (adds minutes) 22 | * anouncements system to teams 23 | * logs of correct answer submissions (in the backoffice) 24 | * logs of submissions (through syslog) 25 | 26 | 27 | ## Setup 28 | 29 | Each team gets a token to login in their private area. Set them up at the ```teams``` table, [here](https://github.com/Probely/CTF-Game/blob/master/sql/schema.sql). Don't reuse the tokens or else teams from previous CTFs could login as an opponent team. 30 | 31 | Run ```docker-compose up```. This makes the dashboard available at localhost:8050 32 | 33 | The private team area is at [localhost:8050](http://localhost:8050). You can login with one of the tokens from the ```teams``` table. 34 | 35 | The backoffice will be running [here](http://localhost:8050/boctf.php). You should (really!) protect this URL with some basic auth, or some other kind of ACL. 36 | -------------------------------------------------------------------------------- /app/board.php: -------------------------------------------------------------------------------- 1 | board($conf['qa']); 22 | $hints = $game->getHints(); 23 | $secs2end = $game->endTS() - time(); 24 | //$time2end = gmdate("H:i:s", $secs2end); 25 | 26 | $atleastoneopen = false; 27 | foreach ($board as $cat => $que) { 28 | if (in_array('', $que)) { 29 | $atleastoneopen = true; 30 | } 31 | if (array_search('open', $que)) { 32 | $opencat = $cat; 33 | $openq = array_search('open', $que); 34 | } 35 | } 36 | 37 | //echo "
";var_dump($atleastoneopen);var_dump($board); 38 | 39 | // Submitting an answer 40 | if (isset($_POST['answer']) && $secs2end>0) { 41 | $category = $_POST['category']; 42 | $question = $_POST['question']; 43 | // Checking if the question is open 44 | if ($board[$category][$question] == 'open' || 45 | $board[$category][$question] == 'lead' 46 | ) { 47 | 48 | $answer = strtolower(trim($_POST['answer'])); 49 | $answer = preg_replace("/\r|\n/", "", $answer); 50 | 51 | $isCorrectAnswer = $answer === strtolower($conf['qa'][$category][$question]['a']); 52 | 53 | openlog('CTF', LOG_ODELAY, LOG_DAEMON); 54 | syslog(LOG_CRIT, "Dashboard [Team: ".$team->id()."|".$team->ip()."|".$category."|".$question."|Correct: ".($isCorrectAnswer?'true':'false')."] - ".$answer); 55 | 56 | // Validating the answer 57 | if ($isCorrectAnswer) { 58 | $team->answer($category, $question); 59 | $notification = true; 60 | $notificationmsg = 'Hurray! That is the correct answer!'; 61 | 62 | if ($atleastoneopen) { 63 | $notificationmsg = $notificationmsg . ' Pick another question from the list to carry on.'; 64 | if ($game->resetLeadQuestion($category, $question)) { 65 | // non error 66 | } 67 | } 68 | $game->reloadGameInfo(); 69 | } else { 70 | $error = true; 71 | $errormsg = 'Wrong answer. Try again :('; 72 | } 73 | } 74 | } else if (isset($_GET['newleadcat']) && isset($_GET['newleadq']) 75 | && $game->isSelectLeadMode() && $secs2end>0 76 | ) { // Selected a new lead question 77 | // Checking if the question is not opened 78 | if (empty($board[$_GET['newleadcat']][$_GET['newleadq']])) { 79 | if ($game->setNewLeadQuestion($_GET['newleadcat'], $_GET['newleadq'])) { 80 | // non error 81 | $category = $_GET['newleadcat']; 82 | $question = $_GET['newleadq']; 83 | } 84 | $game->reloadGameInfo(); 85 | } 86 | } else { // Loading a question 87 | // Check if the question is open. If not, return lead question 88 | if (isset($_GET['cat']) && isset($_GET['q']) && $board[$_GET['cat']][$_GET['q']] == 'open') { 89 | $category = $_GET['cat']; 90 | $question = $_GET['q']; 91 | } else { 92 | $category = $game->leadCat(); 93 | $question = $game->leadPoints(); 94 | //echo "

"; var_dump($category,$question, $opencat, $openq); 95 | if ((isset($board[$category][$question]) && $board[$category][$question] == 'answered')) { 96 | if (!isset($opencat) && !isset($openq)) { 97 | $allanswered = true; 98 | } else { 99 | $category = $opencat; 100 | $question = $openq; 101 | } 102 | } 103 | } 104 | 105 | } 106 | 107 | // We need to retrieve the info again because of answered questions or new lead questions 108 | $board = $team->board($conf['qa']); 109 | 110 | // Select current question 111 | if (!empty($category) && !empty($question) 112 | && ($board[$category][$question] == 'open' || $board[$category][$question] == 'lead') 113 | ) { 114 | $board[$category][$question] = ($board[$category][$question] == 'lead') ? 'lead current' : 'current'; 115 | } 116 | 117 | // Make the leaderboard 118 | $leaderboard = $game->leaderBoard(); 119 | 120 | // Selecting a new lead question? 121 | if ($game->isSelectLeadMode()) { 122 | $board = $team->boardSelectLead($board); 123 | $notification = true; 124 | $notificationmsg = 'Open a new question below!'; 125 | $msg = 'You should open a new question from the board on the left!'; 126 | } 127 | 128 | // Board Template 129 | require 'templates/board.html'; 130 | 131 | /* 132 | echo "

















"; 133 | echo "

















"; print_r($board);
134 | echo "


\n\n\n\n\n\n". $game->json($board); 135 | echo "



"; print_r($game->db->normalizer($conf['qa'])); 136 | */ 137 | -------------------------------------------------------------------------------- /app/boctf.php: -------------------------------------------------------------------------------- 1 | startGame($conf); 12 | } else if (isset($_POST['end'])) { 13 | $db->endGame(); 14 | } else if (isset($_POST['pause']) && isset($_POST['text'])) { 15 | $db->pauseGame(intval($_POST['text'])); 16 | } elseif (isset($_POST['addhint']) && isset($_POST['text'])) { 17 | $db->addNewHint(trim($_POST['text'])); 18 | } 19 | 20 | // Redirect page to avoid multiple submits on refresh 21 | if (!empty($_POST)) { 22 | // Force clients to reload 23 | $game->forceClientRefresh(); 24 | 25 | header('Location:'.$_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING']); 26 | die(); 27 | } 28 | 29 | $board = $game->dashboard($conf['qa']); 30 | $secs2end = $game->endTS() - time(); 31 | 32 | // Make the leaderboard 33 | $leaderboard = $game->dashleaderBoard(); 34 | 35 | // Board Template 36 | require 'templates/boctf.html'; 37 | 38 | /* 39 | echo "















"; 40 | echo "

















"; print_r($board);print_r($leaderboard);
41 | echo "


\n\n\n\n\n\n". $game->dashjson($board); 42 | */ 43 | -------------------------------------------------------------------------------- /app/bootstrap.php: -------------------------------------------------------------------------------- 1 | Those guys at Nameless Corporation take everybody for fools, yet they believe nobody would ever target them. Nobody smart anyhow, from what I\'ve seen so far. 29 |

30 | They have a microservice lying around with data from relevant employees. Maybe I can gather some information from it and do a bit of social engineering... 31 |

32 | The service is listening at http://w100-329074e6b126304d.ctf.rules and I\'ve already mapped a few key methods. Also, I duped some helpdesk drone into resetting an account with my own password. Help me put these people to shame! 33 |

34 | GET /token (basic auth, returns a temporary access token)
35 | GET /users (returns all employees in the rolodex, as JSON)
36 | GET /users/1 (returns data for employee #1, in JSON, based on access rights)
37 | PUT /users/1 (replaces employee #1\'s data with the JSON in the request body) 38 |

39 | Requests to /users require a X-API-Token header or token= query string parameter. 40 |

41 | The credentials for /token are the same ones used for the CTF with an username matching the team number (e.g. use "team1" as the username for team #1, etc.).

'; 42 | $conf['qa']['Web Hacking'][100]['a'] = 'xxxxxxx'; 43 | $conf['qa']['Web Hacking'][200]['q'] = ' Question 200 '; 44 | $conf['qa']['Web Hacking'][200]['a'] = ' Answer 200'; 45 | $conf['qa']['Web Hacking'][300]['q'] = ' Question 300'; 46 | $conf['qa']['Web Hacking'][300]['a'] = ' Answer 300'; 47 | $conf['qa']['Web Hacking'][400]['q'] = ' Question 400'; 48 | $conf['qa']['Web Hacking'][400]['a'] = ' Answer 400'; 49 | 50 | 51 | $conf['qa']['Forensics'][100]['q'] = ' Question 100 '; 52 | $conf['qa']['Forensics'][100]['a'] = ' Answer 100'; 53 | $conf['qa']['Forensics'][200]['q'] = ' Question 200 '; 54 | $conf['qa']['Forensics'][200]['a'] = ' Answer 200'; 55 | $conf['qa']['Forensics'][300]['q'] = ' Question 300 '; 56 | $conf['qa']['Forensics'][300]['a'] = ' Answer 300'; 57 | $conf['qa']['Forensics'][400]['q'] = ' Question 400'; 58 | $conf['qa']['Forensics'][400]['a'] = ' Answer 400'; 59 | 60 | $conf['qa']['Pwnable'][100]['q'] = ' Question 100 '; 61 | $conf['qa']['Pwnable'][100]['a'] = ' Answer 100'; 62 | $conf['qa']['Pwnable'][200]['q'] = ' Question 200 '; 63 | $conf['qa']['Pwnable'][200]['a'] = ' Answer 200'; 64 | $conf['qa']['Pwnable'][300]['q'] = ' Question 300 '; 65 | $conf['qa']['Pwnable'][300]['a'] = ' Answer 300'; 66 | $conf['qa']['Pwnable'][400]['q'] = ' Question 400'; 67 | $conf['qa']['Pwnable'][400]['a'] = ' Answer 400'; 68 | 69 | $conf['qa']['Trivia'][100]['q'] = ' Question 100 '; 70 | $conf['qa']['Trivia'][100]['a'] = ' Answer 100'; 71 | $conf['qa']['Trivia'][200]['q'] = ' Question 200 '; 72 | $conf['qa']['Trivia'][200]['a'] = ' Answer 200'; 73 | $conf['qa']['Trivia'][300]['q'] = ' Question 300 '; 74 | $conf['qa']['Trivia'][300]['a'] = ' Answer 300'; 75 | $conf['qa']['Trivia'][400]['q'] = ' Question 400'; 76 | $conf['qa']['Trivia'][400]['a'] = ' Answer 400'; 77 | 78 | -------------------------------------------------------------------------------- /app/dashboard/dashjson.php: -------------------------------------------------------------------------------- 1 | dashboard($conf['qa']); 10 | $secs2end = $game->endTS() - time(); 11 | 12 | echo $game->dashjson($board); 13 | -------------------------------------------------------------------------------- /app/dashboard/index.php: -------------------------------------------------------------------------------- 1 | dashboard($conf['qa']); 9 | $secs2end = $game->endTS() - time(); 10 | 11 | // Make the leaderboard 12 | $leaderboard = $game->dashleaderBoard(); 13 | 14 | // Board Template 15 | require 'templates/dashboard.html'; 16 | 17 | /* 18 | echo "

















"; 19 | echo "

















"; print_r($board);print_r($leaderboard);
20 | echo "


\n\n\n\n\n\n". $game->dashjson($board); 21 | */ 22 | -------------------------------------------------------------------------------- /app/dashboard/js/security_dashboard.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | window.PixelsCampSecurityContestDashboard = function() 4 | { 5 | this.init(); 6 | } 7 | 8 | 9 | window.PixelsCampSecurityContestDashboard.prototype = { 10 | 11 | init: function() 12 | { 13 | this._debug = false; 14 | 15 | this.ajax = false; 16 | 17 | this.counterWSConnect = 0; 18 | 19 | this.timeToEnd = 0; 20 | this.timeElm = null; 21 | 22 | this._countDown(); 23 | 24 | this._processInfo(); 25 | 26 | this._runProcessInfoTimer(); 27 | 28 | }, 29 | 30 | _runProcessInfoTimer: function() 31 | { 32 | var setInt = setInterval(function(){ 33 | location.reload(); 34 | //this._processInfo(); 35 | }.bindObj(this), (1000 * 15)); // intervalo de update 36 | }, 37 | 38 | _countDown: function() 39 | { 40 | this.timeElm = document.getElementById('timer'); 41 | if(this.timeElm != null) { 42 | var toEnd = this.timeElm.getAttribute('time'); 43 | toEnd = parseInt(toEnd, 10); 44 | 45 | this.timeToEnd = toEnd; 46 | 47 | setInterval(function() { 48 | this._goingDown(); 49 | }.bindObj(this), 1000); 50 | 51 | if(this._debug) { 52 | console.log(toEnd); 53 | } 54 | } 55 | }, 56 | 57 | _blinkIt: function() 58 | { 59 | this.setIntBlink = setInterval(function(){ 60 | if(SAPO.Dom.Css.getStyle(this.timeElm, 'opacity') == '0.5') { 61 | SAPO.Dom.Css.setOpacity(this.timeElm, '1'); 62 | //this.timeElm.style.visibility = 'visible'; 63 | } else { 64 | SAPO.Dom.Css.setOpacity(this.timeElm, '0.5'); 65 | //this.timeElm.style.visibility = 'hidden'; 66 | } 67 | }.bindObj(this), 500); 68 | }, 69 | 70 | _goingDown: function() 71 | { 72 | this.timeToEnd--; 73 | 74 | if(this.timeToEnd <= 0) { 75 | this.timeToEnd = 0; 76 | this.timeElm.style.color = 'red'; 77 | } 78 | 79 | if(this.timeToEnd <= 61 && this.timeElm.style.color != 'red') { 80 | setTimeout(function() { 81 | this.timeElm.style.color = 'red'; 82 | }.bindObj(this), 1000); 83 | } 84 | 85 | var hours = false; 86 | var minutes = false; 87 | var seconds = false; 88 | 89 | var hours = Math.floor(this.timeToEnd / (60 * 60)); 90 | 91 | var divisor_for_minutes = this.timeToEnd % (60 * 60); 92 | var minutes = Math.floor(divisor_for_minutes / 60); 93 | 94 | var divisor_for_seconds = divisor_for_minutes % 60; 95 | var seconds = Math.ceil(divisor_for_seconds); 96 | 97 | hours = (hours < 10) ? '0'+hours : hours; 98 | minutes = (minutes < 10) ? '0'+minutes : minutes; 99 | seconds = (seconds < 10) ? '0'+seconds : seconds; 100 | 101 | this.timeElm.innerHTML = ' '+hours+':'+minutes+':'+seconds+' '; 102 | 103 | if(this.timeToEnd <= 0) { 104 | var elmToRemove = document.getElementById('current_question'); 105 | if(elmToRemove != null) { 106 | elmToRemove.parentNode.removeChild(elmToRemove); 107 | } 108 | } 109 | }, 110 | 111 | 112 | _addPageEvents: function() 113 | { 114 | return; 115 | }, 116 | 117 | _getUpdatedInfo: function() 118 | { 119 | if(this.ajax) { 120 | this.ajax.transport.abort(); 121 | this.ajax = false; 122 | } 123 | var opt = { 124 | method: 'GET', 125 | onSuccess: this._updateMatrix.bindObj(this) 126 | }; 127 | 128 | this.ajax = new SAPO.Communication.Ajax('dashjson.php', opt); 129 | }, 130 | 131 | _updateMatrix: function(obj) 132 | { 133 | var res = eval('['+obj.responseText+']'); 134 | if(res.length > 0) { 135 | res = res[0]; 136 | 137 | if(typeof(res.board) != 'undefined' && typeof(res.leaderboard) != 'undefined') { 138 | this._processMatrixInfo(res.board); 139 | this._processScoreInfo(res.leaderboard); 140 | this._processTimeInfo(res.time); 141 | } 142 | if(this._debug) { 143 | console.log(res); 144 | } 145 | } 146 | this.ajax = false; 147 | }, 148 | 149 | _processInfo: function(data) 150 | { 151 | this._getUpdatedInfo(); 152 | }, 153 | 154 | _processMatrixInfo: function(data) 155 | { 156 | //return false; 157 | if(typeof(data) == 'object') { 158 | var curKey = false; 159 | var curClass = false; 160 | var aCurTeams = false; 161 | for(var i in data) { 162 | for(var j in data[i]) { 163 | curKey = i+'_'+j; 164 | curKey = curKey.toLowerCase(); 165 | curKey = curKey.replace(/\ /g, ''); 166 | 167 | curClass = data[i][j]['class']; 168 | aCurTeams = data[i][j]['teams']; 169 | 170 | var elm = document.getElementById(curKey); 171 | if(elm) { 172 | 173 | switch(curClass) { 174 | case 'open': 175 | elm.className = 'open'; 176 | var str = '

'+j+'

'; 177 | if(aCurTeams.length > 0) { 178 | str += '

Teams Completed:

    '; 179 | for(var k=0, tK = aCurTeams.length; k < tK; k++) { 180 | str += '
  • '+aCurTeams[k]+'
  • '; 181 | } 182 | str += '
'; 183 | } 184 | elm.innerHTML = str; 185 | break; 186 | 187 | case 'closed': 188 | elm.className = 'closed'; 189 | elm.str += j; 190 | break; 191 | 192 | case 'lead': 193 | elm.className = 'lead'; 194 | elm.innerHTML = '

'+j+'

Lead Question

'; 195 | break; 196 | } 197 | } 198 | } 199 | } 200 | } 201 | }, 202 | 203 | _processScoreInfo: function(data) 204 | { 205 | var elmList = document.getElementById('leaderboard_list'); 206 | 207 | if(elmList == null) { 208 | return; 209 | } 210 | 211 | elmList.innerHTML = ''; 212 | 213 | if(data.length > 0) { 214 | var cur = false; 215 | for(var i=0, total=data.length; i < total; i++) { 216 | cur = data[i]; 217 | var li = document.createElement('li'); 218 | if(typeof(cur.me) != 'undefined' && cur.me === true) { 219 | li.className = 'you'; 220 | } 221 | if(cur.team == null) { 222 | li.innerHTML = ' ('+cur.points+')'; 223 | } else { 224 | li.innerHTML = cur.team+' ('+cur.points+')'; 225 | } 226 | 227 | elmList.appendChild(li); 228 | } 229 | } 230 | 231 | }, 232 | 233 | _processTimeInfo: function(data) 234 | { 235 | this.timeToEnd = data; 236 | //this.timeToEnd = 10; 237 | if(this._debug) { 238 | console.log('by ajax -> '+data); 239 | } 240 | }, 241 | 242 | _processOtherStuff: function(data) 243 | { 244 | return; 245 | if(data) { 246 | document.getElementById('out3').innerHTML = '
'+data+'
'; 247 | } 248 | }, 249 | 250 | 251 | debug: function(){} 252 | 253 | }; 254 | 255 | 256 | -------------------------------------------------------------------------------- /app/dashboard/js/ss/ss.js: -------------------------------------------------------------------------------- 1 | 2 | if(typeof SAPO==='undefined'){window.SAPO={};}else{window.SAPO=window.SAPO;} 3 | SAPO.namespace=function(ns){if(!ns||!ns.length){return null;} 4 | var levels=ns.split(".");var nsobj=SAPO;for(var i=(levels[0]==="SAPO")?1:0;i1){for(var i=0,elements=[],length=arguments.length;i0?window.escape(document.referrer):false:false;},detectBrowser:function() 34 | {var sAgent=navigator.userAgent;this.userAgent=sAgent;sAgent=sAgent.toLowerCase();if((new RegExp("applewebkit\/")).test(sAgent)){if((new RegExp("chrome\/")).test(sAgent)){this.CHROME=true;this.model='chrome';this.version=sAgent.replace(new RegExp("(.*)chrome\/([^\\s]+)(.*)"),"$2");this.cssPrefix='-webkit-';this.domPrefix='Webkit';}else{this.SAFARI=true;this.model='safari';this.version=sAgent.replace(new RegExp("(.*)applewebkit\/([^\\s]+)(.*)"),"$2");this.cssPrefix='-webkit-';this.domPrefix='Webkit';}}else if((new RegExp("opera")).test(sAgent)){this.OPERA=true;this.model='opera';this.version=sAgent.replace(new RegExp("(.*)opera.([^\\s$]+)(.*)"),"$2");this.cssPrefix='-o-';this.domPrefix='O';}else if((new RegExp("konqueror")).test(sAgent)){this.KONQUEROR=true;this.model='konqueror';this.version=sAgent.replace(new RegExp("(.*)konqueror\/([^;]+);(.*)"),"$2");this.cssPrefix='-khtml-';this.domPrefix='Khtml';}else if(/(msie|trident)/i.test(sAgent)){this.IE=true;this.model='ie';if(/rv:((?:\d|\.)+)/.test(sAgent)){this.version=sAgent.match(/rv:((?:\d|\.)+)/)[1];} 35 | else{this.version=sAgent.replace(/(.*)\smsie\s([^;]+);(.*)/,"$2");} 36 | this.cssPrefix='-ms-';this.domPrefix='ms';}else if((new RegExp("gecko")).test(sAgent)){this.GECKO=true;var re=new RegExp("(camino|chimera|epiphany|minefield|firefox|firebird|phoenix|galeon|iceweasel|k\\-meleon|seamonkey|netscape|songbird|sylera)");if(re.test(sAgent)){this.model=sAgent.match(re)[1];this.version=sAgent.replace(new RegExp("(.*)"+this.model+"\/([^;\\s$]+)(.*)"),"$2");this.cssPrefix='-moz-';this.domPrefix='Moz';}else{this.model='mozilla';var reVersion=new RegExp("(.*)rv:([^)]+)(.*)");if(reVersion.test(sAgent)){this.version=sAgent.replace(reVersion,"$2");} 37 | this.cssPrefix='-moz-';this.domPrefix='Moz';}}},debug:function() 38 | {var str="known browsers: (ie, gecko, opera, safari, konqueror) \n";str+=[this.IE,this.GECKO,this.OPERA,this.SAFARI,this.KONQUEROR]+"\n";str+="model -> "+this.model+"\n";str+="version -> "+this.version+"\n";str+="\n";str+="original UA -> "+this.userAgent;alert(str);}};SAPO.Browser.init();} 39 | SAPO.logReferer=function(classURL){var thisOptions=SAPO.extendObj({s:'js.sapo.pt',swakt:'59a97a5f-0924-3720-a62e-0c44d9ea4f16',pg:false,swasection:false,swasubsection:'',dc:'',ref:false,etype:'libsapojs-view',swav:'1',swauv:'1',bcs:'1',bsr:'1',bul:'1',bje:'1',bfl:'1',debug:false},arguments[1]||{});if(typeof classURL!=='undefined'&&classURL!==null){if(!thisOptions.pg){thisOptions.pg=classURL;} 40 | if(!thisOptions.swasection){thisOptions.swasection=classURL;} 41 | if(!thisOptions.ref){thisOptions.ref=location.href;} 42 | var waURI='http://wa.sl.pt/wa.gif?';var waURISSL='https://wa.sl.pt/wa.gif?';var aQuery=['pg='+encodeURIComponent(thisOptions.pg),'swasection='+encodeURIComponent(thisOptions.swasection),'swasubsection='+encodeURIComponent(thisOptions.swasubsection),'dc='+encodeURIComponent(thisOptions.dc),'s='+thisOptions.s,'ref='+encodeURIComponent(thisOptions.ref),'swakt='+thisOptions.swakt,'etype='+encodeURIComponent(thisOptions.etype),'swav='+encodeURIComponent(thisOptions.swav),'swauv='+encodeURIComponent(thisOptions.swauv),'bcs='+encodeURIComponent(thisOptions.bcs),'bsr='+encodeURIComponent(thisOptions.bsr),'bul='+encodeURIComponent(thisOptions.bul),'bje='+encodeURIComponent(thisOptions.bje),'bfl='+encodeURIComponent(thisOptions.bfl),''];var waLogURI=((location.protocol==='https:')?waURISSL:waURI);var img=new Image();img.src=waLogURI+aQuery.join('&');}};SAPO._require=function(uri,callBack) 43 | {if(typeof uri!=='string'){return;} 44 | var script=document.createElement('script');script.type='text/javascript';var aHead=document.getElementsByTagName('HEAD');if(aHead.length>0){aHead[0].appendChild(script);} 45 | if(document.addEventListener){script.onload=function(e){if(typeof callBack!=='undefined'){callBack();}};}else{script.onreadystatechange=function(e){if(this.readyState==='loaded'){if(typeof callBack!=='undefined'){callBack();}}};} 46 | script.src=uri;};SAPO.require=function(reqArray,callBack) 47 | {var objectsToCheck=[];var uriToAdd=[];var _isSAPOObject=function(param){if(typeof param==='string'){if(/^SAPO\./.test(param)){return true;}} 48 | return false;};var _isObjectUri=function(param){if(typeof param==='object'&¶m.constructor===Object){if(typeof param.uri==='string'){return true;}} 49 | return false;};var _isObjectArray=function(param){if(typeof param==='object'&¶m.constructor===Array){return true;} 50 | return false;};var _parseSAPOObject=function(param){var aSAPO=param.split('.');var sapoURI=aSAPO.join('/');return'http://js.sapo.pt/'+sapoURI+'/';};var _parseObjectUri=function(param){return param.uri;};var _objectExists=function(objStr,ver){if(typeof objStr!=='undefined'){var aStrObj=objStr.split('.');var objParent=window;for(var k=0,aStrObjLength=aStrObj.length;k1){SAPO._require(uriToAdd[0],requestRecursive);uriToAdd.splice(0,1);}else if(uriToAdd.length===1){if(typeof callBack!=='undefined'){SAPO._require(uriToAdd[0],callBack);}else{SAPO._require(uriToAdd[0]);} 54 | uriToAdd.splice(0,1);}else if(uriToAdd.length===0){if(typeof callBack!=='undefined'){callBack();}}};if(typeof reqArray!=='undefined'){var cur=false;var curURI=false;if(typeof reqArray==='string'){if(_isSAPOObject(reqArray)){if(!_objectExists(reqArray)){uriToAdd.push(_parseSAPOObject(reqArray));}}else{uriToAdd.push(reqArray);}}else{for(var i=0,reqArrayLength=reqArray.length;i0){if(_isSAPOObject(cur[0])){if(!_objectExists(cur[0])){if(cur.length===2){uriToAdd.push(_parseSAPOObject(cur[0])+cur[1]+'/');}else{uriToAdd.push(_parseSAPOObject(cur[0]));}}}}}else{if(typeof cur==='string'){uriToAdd.push(cur);}else{if(_isObjectUri(cur)){if(typeof cur.check==='string'){if(typeof cur.version==='string'){if(!_objectExists(cur.check,cur.version)){uriToAdd.push(_parseObjectUri(cur));}}else{if(!_objectExists(cur.check)){uriToAdd.push(_parseObjectUri(cur));}}}else{uriToAdd.push(_parseObjectUri(cur));}}}}}} 55 | if(arguments.length===3){if(typeof arguments[2]==='boolean'){if(arguments[2]===true){for(var l=0,uriToAddLength=uriToAdd.length;l-1){this.url=this.url+'&'+params;}else{this.url=this.url+'?'+params;}}},getHeader:function(name) 15 | {try{return this.transport.getResponseHeader(name);}catch(e){return null;}},getResponse:function(){var t=this.transport,r={headerJSON:null,responseJSON:null,getHeader:this.getHeader,request:this,transport:t};r.readyState=t.readyState;r.responseText=t.responseText;r.responseXML=t.responseXML;r.status=t.status;r.statusText=t.statusText;return r;},runStateChange:function() 16 | {var responseJSON,responseContent,response;try{var curStatus=this.transport.status||0;}catch(e){var curStatus=0;} 17 | if(this.transport.readyState==4){if(this.stoTimeout){clearTimeout(this.stoTimeout);} 18 | responseContent=this.transport.responseText;response=this.getResponse();var headerContentType=this.getHeader('Content-Type');if(headerContentType==null){headerContentType='';} 19 | if((this.options.evalJS&&headerContentType.indexOf("application/json")>=0)||this.options.evalJS==='force'){try{responseJSON=this.evalJSON(responseContent,this.sanitizeJSON);if(responseJSON){responseContent=response.responseJSON=responseJSON;}}catch(e){this._dispatchException(e);}} 20 | var xjson=this.getHeader("X-JSON");if(xjson&&this.options.evalJS){try{responseJSON=this.evalJSON(xjson,this.sanitizeJSON);responseContent=response.headerJSON=responseJSON;}catch(e){this._dispatchException(e);}} 21 | if(this.transport.responseXML!==null&&response.responseJSON===null&&this.transport.responseXML.xml!==""){responseContent=this.transport.responseXML;} 22 | if(curStatus>=200&&curStatus<300){if(this.options.onSuccess){this.options.onSuccess(response,responseContent);}}else{if(this.options.onFailure){this.options.onFailure(response,responseContent);}} 23 | if(typeof(this.options['on'+curStatus])!='undefined'){this.options['on'+curStatus](response,responseContent);} 24 | if(this.options.onComplete){this.options.onComplete(response,responseContent);}}},_dispatchException:function(e){if(typeof this.options.onException==="function"){this.options.onException(e);}else{throw e;}},request:function(url) 25 | {if(this.transport){if(this.options.method=='get'){this.setParams();} 26 | if(this.options.method=='get'){this.transport.open("GET",this.url,this.options.asynchronous);}else{this.transport.open("POST",this.url,this.options.asynchronous);} 27 | this.setHeaders();if(this.options.onCreate){this.options.onCreate(this.transport);} 28 | if(this.options.timeout&&!isNaN(this.options.timeout)){this.stoTimeout=setTimeout(function(){if(this.options.onTimeout){this.transport.abort();this.options.onTimeout();}}.bindObj(this),(this.options.timeout*1000));} 29 | if(this.options.asynchronous){this.transport.onreadystatechange=function(){this.runStateChange();}.bindObj(this);} 30 | if(this.options.method=='get'){this.transport.send(null);}else{var params;if(this.options.postBody){params=this.options.postBody;}else{if(typeof this.options.parameters==="string"){params=this.options.parameters;}else if(typeof this.options.parameters==="object"){params=this.paramsObjToStr(this.options.parameters);}} 31 | this.transport.send(params);} 32 | if(!this.options.asynchronous){this.runStateChange();}}},isJSON:function(str) 33 | {if(str.length===0||typeof str!=="string"){return false;} 34 | str=str.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"/g,'');return(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);},evalJSON:function(strJSON,sanitize) 35 | {if(!sanitize||this.isJSON(strJSON)){try{if(typeof(JSON)!=="undefined"&&typeof(JSON.parse)!=='undefined'){return JSON.parse(strJSON);} 36 | return eval('('+strJSON+')');}catch(e){throw new Error('ERROR: Bad JSON string...');}} 37 | return false;},debug:function(){}};SAPO.Communication.Ajax.load=function(url,callback){return new SAPO.Communication.Ajax(url,{method:'get',onSuccess:function(response){callback(response.responseText);}});}; -------------------------------------------------------------------------------- /app/dashboard/js/ss/ss_utility_serialize.js: -------------------------------------------------------------------------------- 1 | 2 | SAPO.namespace('Utility');SAPO.Utility.Serialize={_convertToUnicode:true,_toUnicode:function(theString) 3 | {if(!this._convertToUnicode){var _m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};if(/["\\\x00-\x1f]/.test(theString)){theString=theString.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=_m[b];if(c){return c;} 4 | c=b.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);});} 5 | return theString;}else{var unicodeString='';var inInt=false;var theUnicode=false;var i=0;var charCount=0;var total=theString.length;while(i=32&&inInt<=126)||inInt==8||inInt==9||inInt==10||inInt==12||inInt==13||inInt==32||inInt==34||inInt==47||inInt==58||inInt==92){if(inInt==34||inInt==92||inInt==47){theUnicode='\\'+theString.charAt(i);}else if(inInt==8){theUnicode='\\b';}else if(inInt==9){theUnicode='\\t';}else if(inInt==10){theUnicode='\\n';}else if(inInt==12){theUnicode='\\f';}else if(inInt==13){theUnicode='\\r';}else{theUnicode=theString.charAt(i);}}else{if(this._convertToUnicode){theUnicode=theString.charCodeAt(i).toString(16)+''.toUpperCase();while(theUnicode.length<4){theUnicode='0'+theUnicode;} 6 | theUnicode='\\u'+theUnicode;}else{theUnicode=theString.charAt(i);}} 7 | unicodeString+=theUnicode;i++;} 8 | return unicodeString;}},_serialize:function(param) 9 | {var formated='';if(typeof(param)=='object'&¶m!==null){if(param.constructor==Array){formated='['+this._removeLastComma(this._format(param))+']';}else if(param.constructor==Object){formated='{'+this._removeLastComma(this._format(param))+'}';} 10 | return formated;}else{return param;}},_format:function(param) 11 | {var formated='';var tmpValue=false;var hasKey=false;if(typeof(param)=='object'&¶m!==null&¶m.constructor==Object){hasKey=true;} 12 | for(var key in param){if(param.hasOwnProperty(key)){tmpValue=param[key];if(tmpValue===null){if(hasKey){formated+='"'+key+'": null,';}else{formated+='null,';}}else if(typeof(tmpValue)=='string'){if(hasKey){formated+='"'+key+'": "'+this._toUnicode(tmpValue)+'",';}else{formated+='"'+this._toUnicode(tmpValue)+'",';}}else if(typeof(tmpValue)=='number'){if(hasKey){formated+='"'+key+'": '+tmpValue+',';}else{formated+=''+tmpValue+',';}}else if(tmpValue===true||tmpValue===false){if(hasKey){formated+='"'+key+'": '+(tmpValue?'true':'false')+',';}else{formated+=''+(tmpValue?'true':'false')+',';}}else if(typeof(tmpValue)=='object'&&tmpValue!==null&&tmpValue.constructor==Array){if(hasKey){formated+='"'+key+'": ['+this._removeLastComma(this._format(tmpValue))+'],';}else{formated+='['+this._removeLastComma(this._format(tmpValue))+'],';}}else if(typeof(tmpValue)=='object'&&tmpValue!==null&&tmpValue.constructor==Object){if(hasKey){formated+='"'+key+'": {'+this._removeLastComma(this._format(tmpValue))+'},';}else{formated+='{'+this._removeLastComma(this._format(tmpValue))+'},';}}}} 13 | return formated;},_removeLastComma:function(string) 14 | {var len=string.length;if(string.substring((len-1),len)==','){return string.substring(0,(len-1));} 15 | return string;},get:function(jsObject,convertToUnicode) 16 | {if(typeof(convertToUnicode)!='undefined'){if(convertToUnicode===false){this._convertToUnicode=false;}else{this._convertToUnicode=true;}} 17 | if(!this._convertToUnicode&&typeof JSON!=="undefined"){return JSON.stringify(jsObject);} 18 | return this._serialize(jsObject);},debug:function(param){}}; -------------------------------------------------------------------------------- /app/dashboard/js/ss/ss_utility_url.js: -------------------------------------------------------------------------------- 1 | 2 | SAPO.namespace('Utility');SAPO.Utility.Url={_keyStr:'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',getUrl:function() 3 | {var url=false;url=location.href;return url;},getQueryString:function(string) 4 | {if(string&&typeof(string)!='undefined'){var url=string;}else{var url=this.getUrl();} 5 | var aParams={};if(url.match(/\?(.+)/i)){var queryStr=url.replace(/^(.*)\?([^\#]+)(\#(.*))?/g,"$2");if(queryStr.length>0){var aQueryStr=queryStr.split(/[;&]/);for(var i=0;i0){var aAnchorStr=anchorStr.split(/[;&]/);for(var i=0;i0){return aScripts[(aScripts.length-1)];}else{return false;}}else{var curScript=false;var re=new RegExp(""+match+"","i");for(var i=0,total=aScripts.length;i>2;enc2=((chr1&3)<<4)|(chr2>>4);enc3=((chr2&15)<<2)|(chr3>>6);enc4=chr3&63;if(isNaN(chr2)){enc3=enc4=64;}else if(isNaN(chr3)){enc4=64;} 26 | output=output+ 27 | this._keyStr.charAt(enc1)+this._keyStr.charAt(enc2)+ 28 | this._keyStr.charAt(enc3)+this._keyStr.charAt(enc4);} 29 | return output;},base64Decode:function(string) 30 | {if(!SAPO.Utility.String||typeof(SAPO.Utility.String)=='undefined'){throw"SAPO.Utility.Url.base64Decode depends of SAPO.Utility.String, which has not been referred.";return false;} 31 | var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;var input=string.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(i>4);chr2=((enc2&15)<<4)|(enc3>>2);chr3=((enc3&3)<<6)|enc4;output=output+String.fromCharCode(chr1);if(enc3!=64){output=output+String.fromCharCode(chr2);} 32 | if(enc4!=64){output=output+String.fromCharCode(chr3);}} 33 | output=SAPO.Utility.String.utf8Decode(output);return output;}}; -------------------------------------------------------------------------------- /app/dashboard/templates/.htaccess: -------------------------------------------------------------------------------- 1 | order deny,allow 2 | deny from all 3 | -------------------------------------------------------------------------------- /app/dashjson.php: -------------------------------------------------------------------------------- 1 | dashboard($conf['qa']); 10 | $secs2end = $game->endTS() - time(); 11 | 12 | echo $game->dashjson($board); 13 | -------------------------------------------------------------------------------- /app/index.php: -------------------------------------------------------------------------------- 1 | login($_POST['login']); 25 | if ($loggedin) { // auth successful 26 | session_regenerate_id(); // prevent session fixation 27 | header("Location: board.php"); 28 | exit(0); 29 | } else { 30 | $failedlogin = true; 31 | } 32 | 33 | } 34 | 35 | // Login Template 36 | require 'templates/index.html'; 37 | -------------------------------------------------------------------------------- /app/js/security_dashboard.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | window.PixelsCampSecurityContestDashboard = function() 5 | { 6 | this.init(); 7 | } 8 | 9 | 10 | window.PixelsCampSecurityContestDashboard.prototype = { 11 | 12 | init: function() 13 | { 14 | this._debug = false; 15 | 16 | this.ajax = false; 17 | 18 | this.counterWSConnect = 0; 19 | 20 | this.timeToEnd = 0; 21 | this.timeElm = null; 22 | 23 | this._countDown(); 24 | 25 | this._processInfo(); 26 | 27 | this._runProcessInfoTimer(); 28 | 29 | }, 30 | 31 | _runProcessInfoTimer: function() 32 | { 33 | 34 | var setInt = setInterval(function(){ 35 | this._processInfo(); 36 | }.bindObj(this), (1000 * 5)); // intervalo de update 37 | }, 38 | 39 | _countDown: function() 40 | { 41 | this.timeElm = document.getElementById('timer'); 42 | if(this.timeElm != null) { 43 | var toEnd = this.timeElm.getAttribute('time'); 44 | toEnd = parseInt(toEnd, 10); 45 | 46 | this.timeToEnd = toEnd; 47 | 48 | setInterval(function() { 49 | this._goingDown(); 50 | }.bindObj(this), 1000); 51 | 52 | if(this._debug) { 53 | console.log(toEnd); 54 | } 55 | } 56 | }, 57 | 58 | _blinkIt: function() 59 | { 60 | this.setIntBlink = setInterval(function(){ 61 | if(SAPO.Dom.Css.getStyle(this.timeElm, 'opacity') == '0.5') { 62 | SAPO.Dom.Css.setOpacity(this.timeElm, '1'); 63 | //this.timeElm.style.visibility = 'visible'; 64 | } else { 65 | SAPO.Dom.Css.setOpacity(this.timeElm, '0.5'); 66 | //this.timeElm.style.visibility = 'hidden'; 67 | } 68 | }.bindObj(this), 500); 69 | }, 70 | 71 | _goingDown: function() 72 | { 73 | this.timeToEnd--; 74 | 75 | if(this.timeToEnd <= 0) { 76 | this.timeToEnd = 0; 77 | this.timeElm.style.color = 'red'; 78 | } 79 | 80 | if(this.timeToEnd <= 61 && this.timeElm.style.color != 'red') { 81 | setTimeout(function() { 82 | this.timeElm.style.color = 'red'; 83 | }.bindObj(this), 1000); 84 | } 85 | 86 | var hours = false; 87 | var minutes = false; 88 | var seconds = false; 89 | 90 | var hours = Math.floor(this.timeToEnd / (60 * 60)); 91 | 92 | var divisor_for_minutes = this.timeToEnd % (60 * 60); 93 | var minutes = Math.floor(divisor_for_minutes / 60); 94 | 95 | var divisor_for_seconds = divisor_for_minutes % 60; 96 | var seconds = Math.ceil(divisor_for_seconds); 97 | 98 | hours = (hours < 10) ? '0'+hours : hours; 99 | minutes = (minutes < 10) ? '0'+minutes : minutes; 100 | seconds = (seconds < 10) ? '0'+seconds : seconds; 101 | 102 | this.timeElm.innerHTML = ' '+hours+':'+minutes+':'+seconds+' '; 103 | 104 | if(this.timeToEnd <= 0) { 105 | var elmToRemove = document.getElementById('current_question'); 106 | if(elmToRemove != null) { 107 | elmToRemove.parentNode.removeChild(elmToRemove); 108 | } 109 | } 110 | }, 111 | 112 | 113 | _addPageEvents: function() 114 | { 115 | return; 116 | }, 117 | 118 | _getUpdatedInfo: function() 119 | { 120 | if(this.ajax) { 121 | this.ajax.transport.abort(); 122 | this.ajax = false; 123 | } 124 | var opt = { 125 | method: 'GET', 126 | onSuccess: this._updateMatrix.bindObj(this) 127 | }; 128 | 129 | this.ajax = new SAPO.Communication.Ajax('dashjson.php', opt); 130 | }, 131 | 132 | _updateMatrix: function(obj) 133 | { 134 | var res = eval('['+obj.responseText+']'); 135 | if(res.length > 0) { 136 | res = res[0]; 137 | 138 | if(typeof(res.board) != 'undefined' && typeof(res.leaderboard) != 'undefined') { 139 | this._processMatrixInfo(res.board); 140 | this._processScoreInfo(res.leaderboard); 141 | this._processTimeInfo(res.time); 142 | } 143 | if(this._debug) { 144 | console.log(res); 145 | } 146 | } 147 | this.ajax = false; 148 | }, 149 | 150 | _processInfo: function(data) 151 | { 152 | this._getUpdatedInfo(); 153 | }, 154 | 155 | _processMatrixInfo: function(data) 156 | { 157 | //return false; 158 | if(typeof(data) == 'object') { 159 | var curKey = false; 160 | var curClass = false; 161 | var aCurTeams = false; 162 | for(var i in data) { 163 | for(var j in data[i]) { 164 | curKey = i+'_'+j; 165 | curKey = curKey.toLowerCase(); 166 | curKey = curKey.replace(/\ /g, ''); 167 | 168 | curClass = data[i][j]['class']; 169 | aCurTeams = data[i][j]['teams']; 170 | 171 | var elm = document.getElementById(curKey); 172 | if(elm) { 173 | 174 | switch(curClass) { 175 | case 'open': 176 | elm.className = 'open'; 177 | var str = '

'+j+'

'; 178 | if(aCurTeams.length > 0) { 179 | str += '

Teams Completed:

    '; 180 | for(var k=0, tK = aCurTeams.length; k < tK; k++) { 181 | str += '
  • '+aCurTeams[k]+'
  • '; 182 | } 183 | str += '
'; 184 | } 185 | elm.innerHTML = str; 186 | break; 187 | 188 | case 'closed': 189 | elm.className = 'closed'; 190 | elm.str += j; 191 | break; 192 | 193 | case 'lead': 194 | elm.className = 'lead'; 195 | elm.innerHTML = '

'+j+'

Lead Question

'; 196 | break; 197 | } 198 | } 199 | } 200 | } 201 | } 202 | }, 203 | 204 | _processScoreInfo: function(data) 205 | { 206 | var elmList = document.getElementById('leaderboard_list'); 207 | 208 | if(elmList == null) { 209 | return; 210 | } 211 | 212 | elmList.innerHTML = ''; 213 | 214 | if(data.length > 0) { 215 | var cur = false; 216 | for(var i=0, total=data.length; i < total; i++) { 217 | cur = data[i]; 218 | var li = document.createElement('li'); 219 | if(typeof(cur.me) != 'undefined' && cur.me === true) { 220 | li.className = 'you'; 221 | } 222 | if(cur.team == null) { 223 | li.innerHTML = ' ('+cur.points+')'; 224 | } else { 225 | li.innerHTML = cur.team+' ('+cur.points+')'; 226 | } 227 | 228 | elmList.appendChild(li); 229 | } 230 | } 231 | 232 | }, 233 | 234 | _processTimeInfo: function(data) 235 | { 236 | this.timeToEnd = data; 237 | //this.timeToEnd = 10; 238 | if(this._debug) { 239 | console.log('by ajax -> '+data); 240 | } 241 | }, 242 | 243 | _processOtherStuff: function(data) 244 | { 245 | return; 246 | if(data) { 247 | document.getElementById('out3').innerHTML = '
'+data+'
'; 248 | } 249 | }, 250 | 251 | 252 | debug: function(){} 253 | 254 | }; 255 | 256 | 257 | -------------------------------------------------------------------------------- /app/js/sendmsg.js: -------------------------------------------------------------------------------- 1 | //var host = 'wss://game.sec.codebits.eu:12345/echo'; 2 | var host = 'wss://game-ctf.pixels.camp/ws'; 3 | var socket = false; 4 | 5 | function startWebsockets() { 6 | if(("WebSocket" in window)) { 7 | socket = new WebSocket(host); 8 | } /*else if(("MozWebSocket" in window)) { 9 | socket = new MozWebSocket(host); 10 | }*/ else { 11 | alert('your browser does not support websockets... choose another on :]'); 12 | } 13 | 14 | if(!socket) { 15 | alert('error'); 16 | } 17 | 18 | socket.onopen = function() { 19 | console.log('connected'); 20 | _runPing(); 21 | }; 22 | socket.onmessage = function(m) { console.log('message received'); }; 23 | socket.onclose = function() { 24 | console.log('closed'); 25 | setTimeout(function() { 26 | console.log('Reconnecting...'); 27 | startWebsockets(); 28 | }, 3000); 29 | }; 30 | } 31 | startWebsockets(); 32 | 33 | function _runPing() { 34 | socket.send('ping'); 35 | setTimeout(function() { 36 | _runPing(); 37 | }, 30000); 38 | } 39 | 40 | function sendMessage(event) { 41 | 42 | if(event.preventDefault) { 43 | event.preventDefault(); 44 | } 45 | if(window.attachEvent) { 46 | event.returnValue = false; 47 | } 48 | if(event.cancel !== null) { 49 | event.cancel = true; 50 | } 51 | 52 | var elm = document.getElementById('text_message'); 53 | if(elm == null) { 54 | return false; 55 | } 56 | 57 | var msgToSend = elm.value; 58 | 59 | var oObj = { 60 | sekjdfSAEwelnfsdWT: msgToSend 61 | }; 62 | 63 | //var str = SAPO.Utility.Serialize.get(oObj); 64 | var str = JSON.stringify(oObj); 65 | 66 | //alert('will send: '+str); 67 | 68 | socket.send(str); 69 | 70 | return false; 71 | } 72 | -------------------------------------------------------------------------------- /app/js/ss/ss.js: -------------------------------------------------------------------------------- 1 | 2 | if(typeof SAPO==='undefined'){window.SAPO={};}else{window.SAPO=window.SAPO;} 3 | SAPO.namespace=function(ns){if(!ns||!ns.length){return null;} 4 | var levels=ns.split(".");var nsobj=SAPO;for(var i=(levels[0]==="SAPO")?1:0;i1){for(var i=0,elements=[],length=arguments.length;i0?window.escape(document.referrer):false:false;},detectBrowser:function() 34 | {var sAgent=navigator.userAgent;this.userAgent=sAgent;sAgent=sAgent.toLowerCase();if((new RegExp("applewebkit\/")).test(sAgent)){if((new RegExp("chrome\/")).test(sAgent)){this.CHROME=true;this.model='chrome';this.version=sAgent.replace(new RegExp("(.*)chrome\/([^\\s]+)(.*)"),"$2");this.cssPrefix='-webkit-';this.domPrefix='Webkit';}else{this.SAFARI=true;this.model='safari';this.version=sAgent.replace(new RegExp("(.*)applewebkit\/([^\\s]+)(.*)"),"$2");this.cssPrefix='-webkit-';this.domPrefix='Webkit';}}else if((new RegExp("opera")).test(sAgent)){this.OPERA=true;this.model='opera';this.version=sAgent.replace(new RegExp("(.*)opera.([^\\s$]+)(.*)"),"$2");this.cssPrefix='-o-';this.domPrefix='O';}else if((new RegExp("konqueror")).test(sAgent)){this.KONQUEROR=true;this.model='konqueror';this.version=sAgent.replace(new RegExp("(.*)konqueror\/([^;]+);(.*)"),"$2");this.cssPrefix='-khtml-';this.domPrefix='Khtml';}else if(/(msie|trident)/i.test(sAgent)){this.IE=true;this.model='ie';if(/rv:((?:\d|\.)+)/.test(sAgent)){this.version=sAgent.match(/rv:((?:\d|\.)+)/)[1];} 35 | else{this.version=sAgent.replace(/(.*)\smsie\s([^;]+);(.*)/,"$2");} 36 | this.cssPrefix='-ms-';this.domPrefix='ms';}else if((new RegExp("gecko")).test(sAgent)){this.GECKO=true;var re=new RegExp("(camino|chimera|epiphany|minefield|firefox|firebird|phoenix|galeon|iceweasel|k\\-meleon|seamonkey|netscape|songbird|sylera)");if(re.test(sAgent)){this.model=sAgent.match(re)[1];this.version=sAgent.replace(new RegExp("(.*)"+this.model+"\/([^;\\s$]+)(.*)"),"$2");this.cssPrefix='-moz-';this.domPrefix='Moz';}else{this.model='mozilla';var reVersion=new RegExp("(.*)rv:([^)]+)(.*)");if(reVersion.test(sAgent)){this.version=sAgent.replace(reVersion,"$2");} 37 | this.cssPrefix='-moz-';this.domPrefix='Moz';}}},debug:function() 38 | {var str="known browsers: (ie, gecko, opera, safari, konqueror) \n";str+=[this.IE,this.GECKO,this.OPERA,this.SAFARI,this.KONQUEROR]+"\n";str+="model -> "+this.model+"\n";str+="version -> "+this.version+"\n";str+="\n";str+="original UA -> "+this.userAgent;alert(str);}};SAPO.Browser.init();} 39 | SAPO.logReferer=function(classURL){var thisOptions=SAPO.extendObj({s:'js.sapo.pt',swakt:'59a97a5f-0924-3720-a62e-0c44d9ea4f16',pg:false,swasection:false,swasubsection:'',dc:'',ref:false,etype:'libsapojs-view',swav:'1',swauv:'1',bcs:'1',bsr:'1',bul:'1',bje:'1',bfl:'1',debug:false},arguments[1]||{});if(typeof classURL!=='undefined'&&classURL!==null){if(!thisOptions.pg){thisOptions.pg=classURL;} 40 | if(!thisOptions.swasection){thisOptions.swasection=classURL;} 41 | if(!thisOptions.ref){thisOptions.ref=location.href;} 42 | var waURI='http://wa.sl.pt/wa.gif?';var waURISSL='https://wa.sl.pt/wa.gif?';var aQuery=['pg='+encodeURIComponent(thisOptions.pg),'swasection='+encodeURIComponent(thisOptions.swasection),'swasubsection='+encodeURIComponent(thisOptions.swasubsection),'dc='+encodeURIComponent(thisOptions.dc),'s='+thisOptions.s,'ref='+encodeURIComponent(thisOptions.ref),'swakt='+thisOptions.swakt,'etype='+encodeURIComponent(thisOptions.etype),'swav='+encodeURIComponent(thisOptions.swav),'swauv='+encodeURIComponent(thisOptions.swauv),'bcs='+encodeURIComponent(thisOptions.bcs),'bsr='+encodeURIComponent(thisOptions.bsr),'bul='+encodeURIComponent(thisOptions.bul),'bje='+encodeURIComponent(thisOptions.bje),'bfl='+encodeURIComponent(thisOptions.bfl),''];var waLogURI=((location.protocol==='https:')?waURISSL:waURI);var img=new Image();img.src=waLogURI+aQuery.join('&');}};SAPO._require=function(uri,callBack) 43 | {if(typeof uri!=='string'){return;} 44 | var script=document.createElement('script');script.type='text/javascript';var aHead=document.getElementsByTagName('HEAD');if(aHead.length>0){aHead[0].appendChild(script);} 45 | if(document.addEventListener){script.onload=function(e){if(typeof callBack!=='undefined'){callBack();}};}else{script.onreadystatechange=function(e){if(this.readyState==='loaded'){if(typeof callBack!=='undefined'){callBack();}}};} 46 | script.src=uri;};SAPO.require=function(reqArray,callBack) 47 | {var objectsToCheck=[];var uriToAdd=[];var _isSAPOObject=function(param){if(typeof param==='string'){if(/^SAPO\./.test(param)){return true;}} 48 | return false;};var _isObjectUri=function(param){if(typeof param==='object'&¶m.constructor===Object){if(typeof param.uri==='string'){return true;}} 49 | return false;};var _isObjectArray=function(param){if(typeof param==='object'&¶m.constructor===Array){return true;} 50 | return false;};var _parseSAPOObject=function(param){var aSAPO=param.split('.');var sapoURI=aSAPO.join('/');return'http://js.sapo.pt/'+sapoURI+'/';};var _parseObjectUri=function(param){return param.uri;};var _objectExists=function(objStr,ver){if(typeof objStr!=='undefined'){var aStrObj=objStr.split('.');var objParent=window;for(var k=0,aStrObjLength=aStrObj.length;k1){SAPO._require(uriToAdd[0],requestRecursive);uriToAdd.splice(0,1);}else if(uriToAdd.length===1){if(typeof callBack!=='undefined'){SAPO._require(uriToAdd[0],callBack);}else{SAPO._require(uriToAdd[0]);} 54 | uriToAdd.splice(0,1);}else if(uriToAdd.length===0){if(typeof callBack!=='undefined'){callBack();}}};if(typeof reqArray!=='undefined'){var cur=false;var curURI=false;if(typeof reqArray==='string'){if(_isSAPOObject(reqArray)){if(!_objectExists(reqArray)){uriToAdd.push(_parseSAPOObject(reqArray));}}else{uriToAdd.push(reqArray);}}else{for(var i=0,reqArrayLength=reqArray.length;i0){if(_isSAPOObject(cur[0])){if(!_objectExists(cur[0])){if(cur.length===2){uriToAdd.push(_parseSAPOObject(cur[0])+cur[1]+'/');}else{uriToAdd.push(_parseSAPOObject(cur[0]));}}}}}else{if(typeof cur==='string'){uriToAdd.push(cur);}else{if(_isObjectUri(cur)){if(typeof cur.check==='string'){if(typeof cur.version==='string'){if(!_objectExists(cur.check,cur.version)){uriToAdd.push(_parseObjectUri(cur));}}else{if(!_objectExists(cur.check)){uriToAdd.push(_parseObjectUri(cur));}}}else{uriToAdd.push(_parseObjectUri(cur));}}}}}} 55 | if(arguments.length===3){if(typeof arguments[2]==='boolean'){if(arguments[2]===true){for(var l=0,uriToAddLength=uriToAdd.length;l-1){this.url=this.url+'&'+params;}else{this.url=this.url+'?'+params;}}},getHeader:function(name) 15 | {try{return this.transport.getResponseHeader(name);}catch(e){return null;}},getResponse:function(){var t=this.transport,r={headerJSON:null,responseJSON:null,getHeader:this.getHeader,request:this,transport:t};r.readyState=t.readyState;r.responseText=t.responseText;r.responseXML=t.responseXML;r.status=t.status;r.statusText=t.statusText;return r;},runStateChange:function() 16 | {var responseJSON,responseContent,response;try{var curStatus=this.transport.status||0;}catch(e){var curStatus=0;} 17 | if(this.transport.readyState==4){if(this.stoTimeout){clearTimeout(this.stoTimeout);} 18 | responseContent=this.transport.responseText;response=this.getResponse();var headerContentType=this.getHeader('Content-Type');if(headerContentType==null){headerContentType='';} 19 | if((this.options.evalJS&&headerContentType.indexOf("application/json")>=0)||this.options.evalJS==='force'){try{responseJSON=this.evalJSON(responseContent,this.sanitizeJSON);if(responseJSON){responseContent=response.responseJSON=responseJSON;}}catch(e){this._dispatchException(e);}} 20 | var xjson=this.getHeader("X-JSON");if(xjson&&this.options.evalJS){try{responseJSON=this.evalJSON(xjson,this.sanitizeJSON);responseContent=response.headerJSON=responseJSON;}catch(e){this._dispatchException(e);}} 21 | if(this.transport.responseXML!==null&&response.responseJSON===null&&this.transport.responseXML.xml!==""){responseContent=this.transport.responseXML;} 22 | if(curStatus>=200&&curStatus<300){if(this.options.onSuccess){this.options.onSuccess(response,responseContent);}}else{if(this.options.onFailure){this.options.onFailure(response,responseContent);}} 23 | if(typeof(this.options['on'+curStatus])!='undefined'){this.options['on'+curStatus](response,responseContent);} 24 | if(this.options.onComplete){this.options.onComplete(response,responseContent);}}},_dispatchException:function(e){if(typeof this.options.onException==="function"){this.options.onException(e);}else{throw e;}},request:function(url) 25 | {if(this.transport){if(this.options.method=='get'){this.setParams();} 26 | if(this.options.method=='get'){this.transport.open("GET",this.url,this.options.asynchronous);}else{this.transport.open("POST",this.url,this.options.asynchronous);} 27 | this.setHeaders();if(this.options.onCreate){this.options.onCreate(this.transport);} 28 | if(this.options.timeout&&!isNaN(this.options.timeout)){this.stoTimeout=setTimeout(function(){if(this.options.onTimeout){this.transport.abort();this.options.onTimeout();}}.bindObj(this),(this.options.timeout*1000));} 29 | if(this.options.asynchronous){this.transport.onreadystatechange=function(){this.runStateChange();}.bindObj(this);} 30 | if(this.options.method=='get'){this.transport.send(null);}else{var params;if(this.options.postBody){params=this.options.postBody;}else{if(typeof this.options.parameters==="string"){params=this.options.parameters;}else if(typeof this.options.parameters==="object"){params=this.paramsObjToStr(this.options.parameters);}} 31 | this.transport.send(params);} 32 | if(!this.options.asynchronous){this.runStateChange();}}},isJSON:function(str) 33 | {if(str.length===0||typeof str!=="string"){return false;} 34 | str=str.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"/g,'');return(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);},evalJSON:function(strJSON,sanitize) 35 | {if(!sanitize||this.isJSON(strJSON)){try{if(typeof(JSON)!=="undefined"&&typeof(JSON.parse)!=='undefined'){return JSON.parse(strJSON);} 36 | return eval('('+strJSON+')');}catch(e){throw new Error('ERROR: Bad JSON string...');}} 37 | return false;},debug:function(){}};SAPO.Communication.Ajax.load=function(url,callback){return new SAPO.Communication.Ajax(url,{method:'get',onSuccess:function(response){callback(response.responseText);}});}; -------------------------------------------------------------------------------- /app/js/ss/ss_dom_css.js: -------------------------------------------------------------------------------- 1 | 2 | (function(window,undefined){'use strict';SAPO.namespace('Dom');if(SAPO.Dom.Css){return;} 3 | var ua=navigator.userAgent.toLowerCase();var isNativeAndroidBrowser=ua.indexOf('android')!==-1&&ua.indexOf('chrome')===-1&&ua.indexOf('safari')!==-1;var isNode=(typeof Node==='object')?function(o){return o instanceof Node;}:function(o){return o&&typeof o==='object'&&typeof o.nodeType==='number'&&typeof o.nodeName==='string';};SAPO.Dom.Css={addRemoveClassName:function(elm,className,addRemState){if(addRemState){return SAPO.Dom.Css.addClassName(elm,className);} 4 | SAPO.Dom.Css.removeClassName(elm,className);},addClassName:function(elm,className){elm=s$(elm);if(elm&&className){if(typeof elm.classList!=="undefined"){elm.classList.add(className);} 5 | else if(!this.hasClassName(elm,className)){elm.className+=(elm.className?' ':'')+className;}}},removeClassName:function(elm,className){elm=s$(elm);if(elm&&className){if(typeof elm.classList!=="undefined"){elm.classList.remove(className);}else{if(typeof elm.className==="undefined"){return false;} 6 | var elmClassName=elm.className,re=new RegExp("(^|\\s+)"+className+"(\\s+|$)");elmClassName=elmClassName.replace(re,' ');elmClassName=elmClassName.replace(/^\s+/,'').replace(/\s+$/,'');elm.className=elmClassName;}}},setClassName:function(elm,className,add){if(add){SAPO.Dom.Css.addClassName(elm,className);} 7 | else{SAPO.Dom.Css.removeClassName(elm,className);}},hasClassName:function(elm,className){elm=s$(elm);if(elm&&className){if(typeof elm.classList!=="undefined"){return elm.classList.contains(className);} 8 | else{if(typeof elm.className==="undefined"){return false;} 9 | var elmClassName=elm.className;if(typeof elmClassName.length==="undefined"){return false;} 10 | if(elmClassName.length>0){if(elmClassName===className){return true;} 11 | else{var re=new RegExp("(^|\\s)"+className+"(\\s|$)");if(re.test(elmClassName)){return true;}}}}} 12 | return false;},blinkClass:function(element,className,timeout,negate){element=s$(element);SAPO.Dom.Css.setClassName(element,className,!negate);setTimeout(function(){SAPO.Dom.Css.setClassName(element,className,negate);},Number(timeout)|100);},toggleClassName:function(elm,className,forceAdd){if(elm&&className){if(typeof elm.classList!=="undefined"){elm=s$(elm);if(elm!==null){elm.classList.toggle(className);} 13 | return true;}} 14 | if(typeof forceAdd!=='undefined'){if(forceAdd===true){this.addClassName(elm,className);} 15 | else if(forceAdd===false){this.removeClassName(elm,className);}}else{if(this.hasClassName(elm,className)){this.removeClassName(elm,className);} 16 | else{this.addClassName(elm,className);}}},setOpacity:function(elm,value){elm=s$(elm);if(elm!==null){var val=1;if(!isNaN(Number(value))){if(value<=0){val=0;} 17 | else if(value<=1){val=value;} 18 | else if(value<=100){val=value/100;} 19 | else{val=1;}} 20 | if(typeof elm.style.opacity!=='undefined'){elm.style.opacity=val;} 21 | else{elm.style.filter="alpha(opacity:"+(val*100|0)+")";}}},_camelCase:function(str){return str?str.replace(/-(\w)/g,function(_,$1){return $1.toUpperCase();}):str;},getStyle:function(elm,style){elm=s$(elm);if(elm!==null){style=style==='float'?'cssFloat':SAPO.Dom.Css._camelCase(style);var value=elm.style[style];if(window.getComputedStyle&&(!value||value==='auto')){var css=getComputedStyle(elm,null);value=css?css[style]:null;} 22 | else if(!value&&elm.currentStyle){value=elm.currentStyle[style];if(value==='auto'&&(style==='width'||style==='height')){value=elm["offset"+style.charAt(0).toUpperCase()+style.slice(1)]+"px";}} 23 | if(style==='opacity'){return value?parseFloat(value,10):1.0;} 24 | else if(style==='borderTopWidth'||style==='borderBottomWidth'||style==='borderRightWidth'||style==='borderLeftWidth'){if(value==='thin'){return'1px';} 25 | else if(value==='medium'){return'3px';} 26 | else if(value==='thick'){return'5px';}} 27 | return value==='auto'?null:value;}},setStyle:function(elm,style){elm=s$(elm);if(elm!==null){if(typeof style==='string'){elm.style.cssText+='; '+style;if(style.indexOf('opacity')!==-1){this.setOpacity(elm,style.match(/opacity:\s*(\d?\.?\d*)/)[1]);}} 28 | else{for(var prop in style){if(style.hasOwnProperty(prop)){if(prop==='opacity'){this.setOpacity(elm,style[prop]);} 29 | else{if(prop==='float'||prop==='cssFloat'){if(typeof elm.style.styleFloat==='undefined'){elm.style.cssFloat=style[prop];} 30 | else{elm.style.styleFloat=style[prop];}}else{elm.style[prop]=style[prop];}}}}}}},show:function(elm,forceDisplayProperty){elm=s$(elm);if(elm!==null){elm.style.display=(forceDisplayProperty)?forceDisplayProperty:'';}},hide:function(elm){elm=s$(elm);if(elm!==null){elm.style.display='none';}},showHide:function(elm,show){elm=s$(elm);if(elm){elm.style.display=show?'':'none';}},toggle:function(elm,forceShow){elm=s$(elm);if(elm!==null){if(typeof forceShow!=='undefined'){if(forceShow===true){this.show(elm);}else{this.hide(elm);}} 31 | else{if(elm.style.display==='none'){this.show(elm);} 32 | else{this.hide(elm);}}}},_getRefTag:function(head){if(head.firstElementChild){return head.firstElementChild;} 33 | for(var child=head.firstChild;child;child=child.nextSibling){if(child.nodeType===1){return child;}} 34 | return null;},appendStyleTag:function(selector,style,options){options=SAPO.extendObj({type:'text/css',force:false},options||{});var styles=document.getElementsByTagName("style"),oldStyle=false,setStyle=true,i,l;for(i=0,l=styles.length;i=0){setStyle=false;}} 35 | if(setStyle){var defStyle=document.createElement("style"),head=document.getElementsByTagName("head")[0],refTag=false,styleStr='';defStyle.type=options.type;styleStr+=selector+" {";styleStr+=style;styleStr+="} ";if(typeof defStyle.styleSheet!=="undefined"){defStyle.styleSheet.cssText=styleStr;}else{defStyle.appendChild(document.createTextNode(styleStr));} 36 | if(options.force){head.appendChild(defStyle);}else{refTag=this._getRefTag(head);if(refTag){head.insertBefore(defStyle,refTag);}}}},appendStylesheet:function(path,options){options=SAPO.extendObj({media:'screen',type:'text/css',force:false},options||{});var refTag,style=document.createElement("link"),head=document.getElementsByTagName("head")[0];style.media=options.media;style.type=options.type;style.href=path;style.rel="Stylesheet";if(options.force){head.appendChild(style);} 37 | else{refTag=this._getRefTag(head);if(refTag){head.insertBefore(style,refTag);}}},_loadingCSSFiles:{},_loadedCSSFiles:{},appendStylesheetCb:function(url,callback){if(!url){return callback(url);} 38 | if(SAPO.Dom.Css._loadedCSSFiles[url]){return callback(url);} 39 | var cbs=SAPO.Dom.Css._loadingCSSFiles[url];if(cbs){return cbs.push(callback);} 40 | SAPO.Dom.Css._loadingCSSFiles[url]=[callback];var linkEl=document.createElement('link');linkEl.type='text/css';linkEl.rel='stylesheet';linkEl.href=url;var headEl=document.getElementsByTagName('head')[0];headEl.appendChild(linkEl);var innerCb=function(frameEl){var url=this;SAPO.Dom.Css._loadedCSSFiles[url]=true;var callbacks=SAPO.Dom.Css._loadingCSSFiles[url];for(var i=0,f=callbacks.length;imaxVal){continue;} 76 | el.style.fontSize=val+'px';}}};})(window); -------------------------------------------------------------------------------- /app/js/ss/ss_utility_serialize.js: -------------------------------------------------------------------------------- 1 | 2 | SAPO.namespace('Utility');SAPO.Utility.Serialize={_convertToUnicode:true,_toUnicode:function(theString) 3 | {if(!this._convertToUnicode){var _m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};if(/["\\\x00-\x1f]/.test(theString)){theString=theString.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=_m[b];if(c){return c;} 4 | c=b.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);});} 5 | return theString;}else{var unicodeString='';var inInt=false;var theUnicode=false;var i=0;var charCount=0;var total=theString.length;while(i=32&&inInt<=126)||inInt==8||inInt==9||inInt==10||inInt==12||inInt==13||inInt==32||inInt==34||inInt==47||inInt==58||inInt==92){if(inInt==34||inInt==92||inInt==47){theUnicode='\\'+theString.charAt(i);}else if(inInt==8){theUnicode='\\b';}else if(inInt==9){theUnicode='\\t';}else if(inInt==10){theUnicode='\\n';}else if(inInt==12){theUnicode='\\f';}else if(inInt==13){theUnicode='\\r';}else{theUnicode=theString.charAt(i);}}else{if(this._convertToUnicode){theUnicode=theString.charCodeAt(i).toString(16)+''.toUpperCase();while(theUnicode.length<4){theUnicode='0'+theUnicode;} 6 | theUnicode='\\u'+theUnicode;}else{theUnicode=theString.charAt(i);}} 7 | unicodeString+=theUnicode;i++;} 8 | return unicodeString;}},_serialize:function(param) 9 | {var formated='';if(typeof(param)=='object'&¶m!==null){if(param.constructor==Array){formated='['+this._removeLastComma(this._format(param))+']';}else if(param.constructor==Object){formated='{'+this._removeLastComma(this._format(param))+'}';} 10 | return formated;}else{return param;}},_format:function(param) 11 | {var formated='';var tmpValue=false;var hasKey=false;if(typeof(param)=='object'&¶m!==null&¶m.constructor==Object){hasKey=true;} 12 | for(var key in param){if(param.hasOwnProperty(key)){tmpValue=param[key];if(tmpValue===null){if(hasKey){formated+='"'+key+'": null,';}else{formated+='null,';}}else if(typeof(tmpValue)=='string'){if(hasKey){formated+='"'+key+'": "'+this._toUnicode(tmpValue)+'",';}else{formated+='"'+this._toUnicode(tmpValue)+'",';}}else if(typeof(tmpValue)=='number'){if(hasKey){formated+='"'+key+'": '+tmpValue+',';}else{formated+=''+tmpValue+',';}}else if(tmpValue===true||tmpValue===false){if(hasKey){formated+='"'+key+'": '+(tmpValue?'true':'false')+',';}else{formated+=''+(tmpValue?'true':'false')+',';}}else if(typeof(tmpValue)=='object'&&tmpValue!==null&&tmpValue.constructor==Array){if(hasKey){formated+='"'+key+'": ['+this._removeLastComma(this._format(tmpValue))+'],';}else{formated+='['+this._removeLastComma(this._format(tmpValue))+'],';}}else if(typeof(tmpValue)=='object'&&tmpValue!==null&&tmpValue.constructor==Object){if(hasKey){formated+='"'+key+'": {'+this._removeLastComma(this._format(tmpValue))+'},';}else{formated+='{'+this._removeLastComma(this._format(tmpValue))+'},';}}}} 13 | return formated;},_removeLastComma:function(string) 14 | {var len=string.length;if(string.substring((len-1),len)==','){return string.substring(0,(len-1));} 15 | return string;},get:function(jsObject,convertToUnicode) 16 | {if(typeof(convertToUnicode)!='undefined'){if(convertToUnicode===false){this._convertToUnicode=false;}else{this._convertToUnicode=true;}} 17 | if(!this._convertToUnicode&&typeof JSON!=="undefined"){return JSON.stringify(jsObject);} 18 | return this._serialize(jsObject);},debug:function(param){}}; -------------------------------------------------------------------------------- /app/js/ss/ss_utility_url.js: -------------------------------------------------------------------------------- 1 | 2 | SAPO.namespace('Utility');SAPO.Utility.Url={_keyStr:'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',getUrl:function() 3 | {var url=false;url=location.href;return url;},getQueryString:function(string) 4 | {if(string&&typeof(string)!='undefined'){var url=string;}else{var url=this.getUrl();} 5 | var aParams={};if(url.match(/\?(.+)/i)){var queryStr=url.replace(/^(.*)\?([^\#]+)(\#(.*))?/g,"$2");if(queryStr.length>0){var aQueryStr=queryStr.split(/[;&]/);for(var i=0;i0){var aAnchorStr=anchorStr.split(/[;&]/);for(var i=0;i0){return aScripts[(aScripts.length-1)];}else{return false;}}else{var curScript=false;var re=new RegExp(""+match+"","i");for(var i=0,total=aScripts.length;i>2;enc2=((chr1&3)<<4)|(chr2>>4);enc3=((chr2&15)<<2)|(chr3>>6);enc4=chr3&63;if(isNaN(chr2)){enc3=enc4=64;}else if(isNaN(chr3)){enc4=64;} 26 | output=output+ 27 | this._keyStr.charAt(enc1)+this._keyStr.charAt(enc2)+ 28 | this._keyStr.charAt(enc3)+this._keyStr.charAt(enc4);} 29 | return output;},base64Decode:function(string) 30 | {if(!SAPO.Utility.String||typeof(SAPO.Utility.String)=='undefined'){throw"SAPO.Utility.Url.base64Decode depends of SAPO.Utility.String, which has not been referred.";return false;} 31 | var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;var input=string.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(i>4);chr2=((enc2&15)<<4)|(enc3>>2);chr3=((enc3&3)<<6)|enc4;output=output+String.fromCharCode(chr1);if(enc3!=64){output=output+String.fromCharCode(chr2);} 32 | if(enc4!=64){output=output+String.fromCharCode(chr3);}} 33 | output=SAPO.Utility.String.utf8Decode(output);return output;}}; -------------------------------------------------------------------------------- /app/json.php: -------------------------------------------------------------------------------- 1 | true)); 8 | exit(0); 9 | } 10 | 11 | $db = new DB($conf['db']); 12 | $game = new Game($db); 13 | $team = new Team($game); 14 | $board = $team->board($conf['qa']); 15 | 16 | $allanswered = false; 17 | $atleastoneopen = false; 18 | foreach ($board as $cat => $que) { 19 | if (in_array('', $que)) { 20 | $atleastoneopen = true; 21 | } 22 | if (array_search('open', $que)) { 23 | $opencat = $cat; 24 | $openq = array_search('open', $que); 25 | } 26 | } 27 | 28 | // Check if the question is open. If not, return lead question 29 | if (isset($_GET['cat']) && isset($_GET['q']) && $board[$_GET['cat']][$_GET['q']] == 'open') { 30 | $category = $_GET['cat']; 31 | $question = $_GET['q']; 32 | } else { 33 | $category = $game->leadCat(); 34 | $question = $game->leadPoints(); 35 | //echo "

"; var_dump($category,$question, $opencat, $openq); 36 | if ((isset($board[$category][$question]) && $board[$category][$question] == 'answered')) { 37 | if (!isset($opencat) && !isset($openq)) { 38 | $allanswered = true; 39 | } else { 40 | $category = $opencat; 41 | $question = $openq; 42 | } 43 | } 44 | } 45 | 46 | if (!empty($category) && !empty($question) 47 | && ($board[$category][$question] == 'open' || $board[$category][$question] == 'lead') 48 | ) { 49 | $board[$category][$question] = ($board[$category][$question] == 'lead') ? 'lead current' : 'current'; 50 | } 51 | 52 | if ($game->isSelectLeadMode()) { 53 | $board = $team->boardSelectLead($board); 54 | } 55 | 56 | $board['selectmode'] = $game->isSelectLeadMode(); 57 | $board['allanswered'] = $allanswered; 58 | 59 | $secs2end = $game->endTS() - time(); 60 | if ($secs2end<=0) { 61 | $board['allanswered'] = true; 62 | } 63 | 64 | echo $game->json($board); 65 | -------------------------------------------------------------------------------- /app/lib/.htaccess: -------------------------------------------------------------------------------- 1 | order deny,allow 2 | deny from all 3 | -------------------------------------------------------------------------------- /app/lib/Auth.php: -------------------------------------------------------------------------------- 1 | db = $db; 14 | if (isset($_SESSION['teamid']) && isset($_SESSION['team'])) { 15 | $this->teamid = $_SESSION['teamid']; 16 | $this->team = $_SESSION['team']; 17 | $this->authip = $_SESSION['authip']; 18 | } 19 | } 20 | 21 | public function login($key) 22 | { 23 | $team = $this->db->getAuth($key); 24 | if (!$team) { 25 | return false; 26 | } 27 | $this->team = $team['team']; 28 | $this->teamid = $team['id']; 29 | $this->authip = $_SERVER['REMOTE_ADDR']; 30 | $_SESSION['authip'] = $this->authip; 31 | $_SESSION['teamid'] = $this->teamid; 32 | $_SESSION['team'] = $this->team; 33 | return true; 34 | } 35 | 36 | public static function check() 37 | { 38 | //echo "


";print_r($_SESSION);print_r($_COOKIE);
39 |         return (isset($_SESSION['teamid']) && isset($_SESSION['team']) &&
40 |                     isset($_SESSION['authip']) && $_SESSION['authip'] == $_SERVER['REMOTE_ADDR']);
41 |     }
42 | 
43 |     public static function ip_check()
44 |     {
45 |         global $conf;
46 | 
47 |         $ip='';
48 |         // Use cloudflare ip first (XXX: WARNING This should be removed if not using cloudflare!)
49 |         if (array_key_exists('HTTP_CF_CONNECTING_IP', $_SERVER)) {
50 |             $ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
51 |         } else { // Otherwise, remote addr
52 |             $ip = $_SERVER['REMOTE_ADDR'];
53 |         }
54 | 
55 |         foreach($conf['whitelist'] as $ipregexp) {
56 |             if(preg_match($ipregexp, $ip) == 1) {
57 |                 return true;
58 |             }
59 |         }
60 | 
61 |         return false;
62 |     }
63 | 
64 |     public function getTeamId()
65 |     {
66 |         return $this->teamid;
67 |     }
68 | 
69 |     public function getTeam()
70 |     {
71 |         return $this->team;
72 |     }
73 | }
74 | 


--------------------------------------------------------------------------------
/app/lib/Game.php:
--------------------------------------------------------------------------------
  1 | db = $db;
 23 |         $this->teamid = isset($_SESSION['teamid']) ? $_SESSION['teamid'] : null;
 24 |         $this->team = isset($_SESSION['team']) ? $_SESSION['team'] : null;
 25 | 
 26 |         $this->reloadGameInfo();
 27 |     }
 28 | 
 29 |     public function leadCat()
 30 |     {
 31 |         return $this->leadcat;
 32 |     }
 33 | 
 34 |     public function leadPoints()
 35 |     {
 36 |         return $this->leadpoints;
 37 |     }
 38 | 
 39 |     public function endTS()
 40 |     {
 41 |         return $this->end;
 42 |     }
 43 | 
 44 |     public function isSelectLeadMode()
 45 |     {
 46 |         return ($this->teamid == $this->yellowshirt && empty($this->leadcat) && empty($this->leadpoints));
 47 |     }
 48 | 
 49 |     public function leaderBoard()
 50 |     {
 51 |         $this->leaderboard = (is_array($this->leaderboard) ? $this->leaderboard : $this->db->getLeaderBoard($this->teamid));
 52 |         return $this->leaderboard;
 53 |     }
 54 | 
 55 |     public function dashleaderBoard()
 56 |     {
 57 |          $this->dashleaderboard = (is_array($this->leaderboard) ? $this->leaderboard : $this->db->getLeaderBoard($this->yellowshirt));
 58 |          return $this->dashleaderboard;
 59 |     }
 60 | 
 61 |     // Game Dashboard
 62 |     public function json($board)
 63 |     {
 64 |         $secs2end = $this->endTS() - time();
 65 |         return json_encode(array(
 66 |             'board' => $board,
 67 |             'leaderboard' => $this->leaderBoard(),
 68 |             'time' => $secs2end,
 69 |             'hints' => $this->_hints
 70 |         ));
 71 |     }
 72 | 
 73 |     // Public Dashboard
 74 |     public function dashjson($board)
 75 |     {
 76 |         $secs2end = $this->endTS() - time();
 77 |         return json_encode(array(
 78 |             'board' => $board,
 79 |             'leaderboard' => $this->dashleaderBoard(),
 80 |             'time' => $secs2end,
 81 |             'hints' => $this->_hints
 82 |         ));
 83 |     }
 84 | 
 85 |     public function electNewLeadQuestion()
 86 |     {
 87 |         // check lowest point questions and rand
 88 |         // getOpenQuestions(), new array w/1st element cat=>points, sort array by value
 89 |     }
 90 | 
 91 |     public function resetLeadQuestion($postcat, $postquestion)
 92 |     {
 93 |         $response = $this->db->resetLeadQuestion($this->teamid, $postcat, $postquestion);
 94 |         $this->forceClientRefresh();
 95 |         return $response;
 96 |     }
 97 | 
 98 |     public function setNewLeadQuestion($leadcat, $leadquestion)
 99 |     {
100 |         $response = $this->db->setNewLeadQuestion($this->teamid, $leadcat, $leadquestion);
101 |         $this->forceClientRefresh();
102 |         return $response;
103 |     }
104 | 
105 |     public function reloadGameInfo()
106 |     {
107 |         $gameinfo = $this->db->getGameInfo();
108 |         $this->leadcat = $gameinfo['leadcat'];
109 |         $this->leadpoints = $gameinfo['leadpoints'];
110 |         $this->end = $gameinfo['end'];
111 |         $this->yellowshirt = $gameinfo['yellowshirt'];
112 |         $this->lastleadreset = $gameinfo['lastleadreset'];
113 |         $this->_hints = $gameinfo['hints'];
114 |     }
115 | 
116 |     public function getHints()
117 |     {
118 |         return $this->_hints;
119 |     }
120 | 
121 |     public function dashboard($questions)
122 |     {
123 |         $board = array();
124 |         $stat = $this->db->getDashboard($this->leadCat(), $this->leadPoints());
125 |         foreach ($questions as $cat => $q) {
126 |             foreach ($q as $points => $qa) {
127 |                 $board[$cat][$points]['class'] = (isset($stat[$cat][$points]['class'])) ? $stat[$cat][$points]['class'] : 'closed';
128 |                 $board[$cat][$points]['teams'] = (isset($stat[$cat][$points]['teams'])) ? $stat[$cat][$points]['teams'] : '';
129 |             }
130 |         }
131 |         return $board;
132 |     }
133 | 
134 |     public function closedQuestions()
135 |     {
136 |         $q = $this->db->getClosedQuestions();
137 |         return $q;
138 |     }
139 | 
140 |     // Force clients to reload
141 |     public function forceClientRefresh()
142 |     {
143 |         global $conf;
144 | 
145 |         try {
146 |             // Connect to websocket
147 |             $client = new Client($conf['websocket']);
148 |             // Send empty message
149 |             $client->send(json_encode(array($conf['websocket-key'] => NULL)));
150 |         } catch (Exception $e) {
151 |             return false;
152 |         }
153 |         return true;
154 |     }
155 | }
156 | 


--------------------------------------------------------------------------------
/app/lib/Team.php:
--------------------------------------------------------------------------------
 1 | game = $game;
15 |         $this->db = $this->game->db;
16 |         $this->teamid = $_SESSION['teamid'];
17 |         $this->team = $_SESSION['team'];
18 |     }
19 | 
20 |     public function name()
21 |     {
22 |         return $this->team;
23 |     }
24 | 
25 |     public function id()
26 |     {
27 |         return $this->teamid;
28 |     }
29 |     public function points()
30 |     {
31 |         return (isset($this->points) ? $this->points : $this->db->getTeamPoints($this->teamid));
32 |     }
33 | 
34 |     public function board($questions)
35 |     {
36 |         $board = array();
37 |         $stat = $this->db->getTeamStatusQuestions($this->teamid, $this->game->leadCat(), $this->game->leadPoints());
38 |         foreach ($questions as $cat => $q) {
39 |             foreach ($q as $points => $qa) {
40 |                 $board[$cat][$points] = (isset($stat[$cat][$points])) ? $stat[$cat][$points] : '';
41 |             }
42 |         }
43 |         return $board;
44 |     }
45 | 
46 |     public function boardSelectLead($questions)
47 |     {
48 |         $board = array();
49 |         foreach ($questions as $cat => $q) {
50 |             foreach ($q as $points => $qa) {
51 |                 if (empty($questions[$cat][$points])) {
52 |                     $board[$cat][$points] = 'select_lead';
53 |                 } else if ($questions[$cat][$points] == 'open') {
54 |                     $board[$cat][$points] = 'openstatic';
55 |                 } else {
56 |                     $board[$cat][$points] = $questions[$cat][$points];
57 |                 }
58 |             }
59 |         }
60 |         return $board;
61 |     }
62 | 
63 |     public function answer($cat, $question)
64 |     {
65 |         return $this->db->insertAnswer($this->teamid, $cat, $question);
66 |     }
67 | 
68 |     public function ip()
69 |     {
70 |         $ipaddress = $_SERVER['REMOTE_ADDR'];
71 |         if (isset($_SERVER['HTTP_CLIENT_IP'])) {
72 |             $ipaddress .= ",".$_SERVER['HTTP_CLIENT_IP'];
73 |         } else if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
74 |             $ipaddress .= ",".$_SERVER['HTTP_X_FORWARDED_FOR'];
75 |         } else if(isset($_SERVER['HTTP_X_FORWARDED'])) {
76 |             $ipaddress .= ",".$_SERVER['HTTP_X_FORWARDED'];
77 |         } else if(isset($_SERVER['HTTP_FORWARDED_FOR'])) {
78 |             $ipaddress .= ",".$_SERVER['HTTP_FORWARDED_FOR'];
79 |         } else if(isset($_SERVER['HTTP_FORWARDED'])) {
80 |             $ipaddress .= ",".$_SERVER['HTTP_FORWARDED'];
81 |         } else if(isset($_SERVER['REMOTE_ADDR'])) {
82 |             $ipaddress .= ",".$_SERVER['REMOTE_ADDR'];
83 |         }
84 | 
85 |         return $ipaddress;
86 |     }
87 | 
88 | 
89 | }
90 | 


--------------------------------------------------------------------------------
/app/scripts/.htaccess:
--------------------------------------------------------------------------------
1 | order deny,allow
2 | deny from all
3 | 


--------------------------------------------------------------------------------
/app/scripts/game.pem:
--------------------------------------------------------------------------------
 1 | -----BEGIN CERTIFICATE-----
 2 | MIIHJTCCBg2gAwIBAgIDBKAgMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
 3 | TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
 4 | YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
 5 | MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTExMTA0MTkzNzIx
 6 | WhcNMTIxMTA0MTU1ODIwWjBoMSAwHgYDVQQNExc1NTY0MTEtNm8zdnhKTXhaNlYy
 7 | RjBWaDEdMBsGA1UEAxMUZ2FtZS5zZWMuY29kZWJpdHMuZXUxJTAjBgkqhkiG9w0B
 8 | CQEWFmhvc3RtYXN0ZXJAY29kZWJpdHMuZXUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
 9 | DwAwggEKAoIBAQCzFnL7kyg55vF+e2efNCCvvA44vv5mzlHygI7eqnTPT1PrAtPp
10 | /v28m/ue9dK69MxmZ6wbQQd4mxE/1Roz8IkUW0nIppdA+AhQoMNtMHNVGzbQe7Xi
11 | ame1fu1WPwlxpyHMDSawUXs37K/eP6hAJUAqbjdDamjHBpzI90KEZ9nlpZhoP3Ue
12 | /PfY5hBEggyZiZHGtKHO3y3c2M62zkYeiissAVOJnVnU9RrtfQgfzIk97IfmXGGr
13 | dk0VJrViQn8aAtMgMETwcfF8HeEcN81BpAY/92icSArQBqjFYGdqQp0O8ikjcMCk
14 | l1zXNdHal5TYawSKLRNbnkZNZ0zAVb4uNwxnAgMBAAGjggOxMIIDrTAJBgNVHRME
15 | AjAAMAsGA1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQU
16 | lZjcaV5hUFuPsH8B9RoIdRl/MnMwHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xk
17 | Lu8OLEUwLAYDVR0RBCUwI4IUZ2FtZS5zZWMuY29kZWJpdHMuZXWCC2NvZGViaXRz
18 | LmV1MIICIQYDVR0gBIICGDCCAhQwggIQBgsrBgEEAYG1NwECAjCCAf8wLgYIKwYB
19 | BQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYB
20 | BQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYw
21 | gfcGCCsGAQUFBwICMIHqMCcWIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9y
22 | aXR5MAMCAQEagb5UaGlzIGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgYWNjb3JkaW5n
23 | IHRvIHRoZSBDbGFzcyAxIFZhbGlkYXRpb24gcmVxdWlyZW1lbnRzIG9mIHRoZSBT
24 | dGFydENvbSBDQSBwb2xpY3ksIHJlbGlhbmNlIG9ubHkgZm9yIHRoZSBpbnRlbmRl
25 | ZCBwdXJwb3NlIGluIGNvbXBsaWFuY2Ugb2YgdGhlIHJlbHlpbmcgcGFydHkgb2Js
26 | aWdhdGlvbnMuMIGcBggrBgEFBQcCAjCBjzAnFiBTdGFydENvbSBDZXJ0aWZpY2F0
27 | aW9uIEF1dGhvcml0eTADAgECGmRMaWFiaWxpdHkgYW5kIHdhcnJhbnRpZXMgYXJl
28 | IGxpbWl0ZWQhIFNlZSBzZWN0aW9uICJMZWdhbCBhbmQgTGltaXRhdGlvbnMiIG9m
29 | IHRoZSBTdGFydENvbSBDQSBwb2xpY3kuMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6
30 | Ly9jcmwuc3RhcnRzc2wuY29tL2NydDEtY3JsLmNybDCBjgYIKwYBBQUHAQEEgYEw
31 | fzA5BggrBgEFBQcwAYYtaHR0cDovL29jc3Auc3RhcnRzc2wuY29tL3N1Yi9jbGFz
32 | czEvc2VydmVyL2NhMEIGCCsGAQUFBzAChjZodHRwOi8vYWlhLnN0YXJ0c3NsLmNv
33 | bS9jZXJ0cy9zdWIuY2xhc3MxLnNlcnZlci5jYS5jcnQwIwYDVR0SBBwwGoYYaHR0
34 | cDovL3d3dy5zdGFydHNzbC5jb20vMA0GCSqGSIb3DQEBBQUAA4IBAQBCNlLbjOXD
35 | 0MIa1hiqxRDs3OTTJysmO9pb8ORHrcWqJZuHypb2zrgFZQreTXCmtrizwwk7wHAT
36 | h1PNxmaMDZ5FsSuZDoyOF8LOA8Am8+VmDT1iwU+GSiMU/THWXEC8gva0ecCeK6yJ
37 | uJ8ugoF4BddiXqh/IKWc+NI7PoJ3rnR2m9i1eKx3jXMdiXTPQyIInenoEP9dpQih
38 | L3bXyU8rq8kRdrgmDyL9HBZbL+P11piTX/VlkLkv4iHnnglOoFxPEGGZahEvMJz+
39 | XdRE1camHNmg/XK7DKn69du3X7xYheHA3sUHJIbA7YnmaCP6hvPulKL5N1UUwDan
40 | fDpyMYpyxZuT
41 | -----END CERTIFICATE-----
42 | 


--------------------------------------------------------------------------------
/app/scripts/normalizer.php:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/php -q
 2 | normalizer($conf['qa']);
 9 | print_r($lead);
10 | 


--------------------------------------------------------------------------------
/app/sendmessage.php:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 | 
 5 | 
 6 | 
 7 | 
46 | 
47 | 
48 | 
49 | 
50 | 

Send Message

51 |
52 |
53 | Send a message to all users:
54 |
55 | 56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /app/templates/.htaccess: -------------------------------------------------------------------------------- 1 | order deny,allow 2 | deny from all 3 | -------------------------------------------------------------------------------- /app/templates/board.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Scoreboard 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

Team: name() ." (Team ". $team->id() . ")"; ?>

17 |
18 | 19 |
20 |

Your Score: points(); ?>

21 |
22 | 23 |
24 |          25 |
26 | 27 | 28 |
29 |

30 |
31 | 32 | 33 | 34 |
35 |

36 |
37 | 38 | 39 |
40 | $q) { ?> 41 | 42 |
43 |

44 |
    45 | $status) { 48 | $id = preg_replace("/\s/", "", strtolower($cat)) . "_" . $points; 49 | if ($status == 'open' || $status == 'openstatic' || $status == 'lead' || $status == 'lead current') { 50 | if ($game->isSelectLeadMode()) { 51 | echo "\t\t\t\t\t
  • $points
  • \n"; 52 | } else { 53 | echo "\t\t\t\t\t
  • $points
  • \n"; 54 | } 55 | } else if ($status == 'select_lead' && $game->isSelectLeadMode()){ 56 | echo "\t\t\t\t\t
  • $points
  • \n"; 57 | } else { 58 | echo "\t\t\t\t\t
  • $points
  • \n"; 59 | } 60 | } 61 | ?> 62 |
63 |
64 | 65 | 66 | 67 |
68 | 69 |
70 |
    71 |
  •   = Lead Question
  • 72 |
  •   = Open
  • 73 |
  •   = Answered
  • 74 |
75 |
76 |
77 | 78 |
style="display: none" > 79 |

Messages:

80 |
81 | 0) { 83 | foreach ($hints as $hint) { 84 | echo "

${hint['timestamp']}${hint['hint']}

\n"; 85 | } 86 | } 87 | ?> 88 |
89 |
90 | 91 |
92 | 93 | 94 | 95 | 96 | 97 | 129 | 130 | 131 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /app/templates/boctf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Scoreboard 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |

Security Contest BO

19 |
20 | 21 |
22 |          23 |
24 | 25 |
26 |
27 |

28 |

29 |
30 |
31 |

      

32 |

33 |

34 |
35 |
36 |
37 |
38 |
39 |

40 |

41 |
42 |
43 |
44 | 45 | 46 |
47 | 48 | 49 | 50 | listAllAnswers() as $k => $answer) { 52 | echo ""; 53 | } 54 | ?> 55 | 56 |
CategoryQuestionPointsTeamIDAnswer TS
".$answer['cat']."".$answer['question']."". $answer['points'] . "" . $answer['teamid'] . "" . $answer['answeredts'] . "
57 |
58 | 59 |
60 | 61 | 62 | 63 | closedQuestions() as $k => $answer) { 65 | echo ""; 66 | } 67 | ?> 68 | 69 |
CategoryQuestionTeamIDAnswer TS
".$answer['cat']."".$answer['question']. "" . $answer['teamid'] . "" . $answer['answeredts'] . "
70 |
71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /app/templates/dashboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Scoreboard 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

Security Contest Scoreboard

17 |
18 | 19 |
20 |          21 |
22 | 23 |
24 | 25 | $q) { ?> 26 | 27 |
28 |

29 |
    30 | $status) { 33 | $id = preg_replace("/\s/", "", strtolower($cat)) . "_" . $points; 34 | if ($status['class'] == 'open') { 35 | echo "\t\t\t\t\t
  • $points

    Teams Completed:

      "; 36 | foreach ($status['teams'] as $k=>$teamid) { 37 | echo "
    • $teamid
    • "; 38 | } 39 | echo "
  • \n"; 40 | } else if ($status['class'] == 'lead') { 41 | echo "\t\t\t\t\t
  • $points

    Lead Question

  • \n"; 42 | } else { 43 | echo "\t\t\t\t\t
  • $points

  • \n"; 44 | } 45 | } 46 | ?> 47 |
48 |
49 | 50 |
51 |
    52 |
  •   = Lead Question
  • 53 |
  •   = Open
  • 54 |
55 |
56 |
57 | 58 |
59 | 60 | 77 | 78 |
79 | Updated every 5 seconds 80 |
81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Scoreboard 7 | 8 | 9 | 10 | 11 |
12 |

Invalid Login!

13 |
14 | 15 |
16 |
17 | 18 |

19 | 20 |
21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/websock/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /app/websock/.htaccess: -------------------------------------------------------------------------------- 1 | order deny,allow 2 | deny from all 3 | -------------------------------------------------------------------------------- /app/websock/app/server.js: -------------------------------------------------------------------------------- 1 | 2 | var config = { 3 | port: 31310 4 | }; 5 | var WebSocketServer = require('ws').Server; 6 | 7 | var wss = new WebSocketServer({port: config.port}, function(a) { 8 | console.log('Running on port ' + config.port); 9 | }); 10 | 11 | 12 | 13 | wss.on('connection', function connection(ws) { 14 | 15 | ws.on('message', function(message) { 16 | console.log('NEW MESSAGE', message); 17 | try { 18 | var aMsg = JSON.parse(message); 19 | } catch(ex) { 20 | var aMsg = message; 21 | } 22 | var isObj = false; 23 | var adminMessage; 24 | if(typeof(aMsg) !== 'object') { 25 | return; 26 | } 27 | if(typeof(aMsg) === 'object' && 'sekjdfSAEwelnfsdWT' in aMsg) { 28 | adminMessage = aMsg.sekjdfSAEwelnfsdWT; 29 | } 30 | 31 | var objToSend = {reload: true}; 32 | if(adminMessage) { 33 | objToSend.msg = adminMessage; 34 | } 35 | wss.clients.forEach(function(wsCli) { 36 | if(wsCli.readyState === wsCli.OPEN) { 37 | wsCli.send(JSON.stringify(objToSend)); 38 | } 39 | }); 40 | //console.log('received: ', aMsg); 41 | }); 42 | 43 | ws.on('close', function(ws) { 44 | console.log('User left server... Users online: ' + wss.clients.length); 45 | }); 46 | //ws.send({msg: 'Hello user :) '); 47 | 48 | console.log('NEw user connected... Total users: '+ wss.clients.length); 49 | }); 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/websock/logs.sh: -------------------------------------------------------------------------------- 1 | ./node_modules/pm2/bin/pm2 logs 2 | -------------------------------------------------------------------------------- /app/websock/old/run_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | php -q server.php 4 | 5 | -------------------------------------------------------------------------------- /app/websock/old/server.php: -------------------------------------------------------------------------------- 1 | php demo.php 5 | require_once("websocket.server.php"); 6 | 7 | /** 8 | * This demo resource handler will respond to all messages sent to /echo/ on the socketserver below 9 | * 10 | * All this handler does is echoing the responds to the user 11 | * @author Chris 12 | * 13 | */ 14 | class DemoEchoHandler extends WebSocketResourceHandler{ 15 | public function onMessage(IWebSocketUser $user, IWebSocketMessage $msg){ 16 | $this->say("[ECHO] {$msg->getData()}"); 17 | 18 | $received = $msg->getData(); 19 | 20 | $aRec = json_decode($received); 21 | 22 | $this->say("[DEBUG_MSG] ".print_r($aRec, true).""); 23 | 24 | if(is_object($aRec) && isset($aRec->sekjdfSAEwelnfsdWT)) { 25 | $adminMessage = (string) $aRec->sekjdfSAEwelnfsdWT; 26 | } else { 27 | $adminMessage = false; 28 | } 29 | 30 | foreach($this->users as $userr) { 31 | if(!empty($adminMessage)) { 32 | $this->send($userr, json_encode(array('reload' => true, 'msg' => $adminMessage))); 33 | } else { 34 | $this->send($userr, json_encode(array('reload' => true))); 35 | } 36 | } 37 | } 38 | 39 | public function onAdminMessage(IWebSocketUser $user, stdClass $obj){ 40 | $this->say("[DEMO] Admin TEST received!"); 41 | 42 | $frame = WebSocketFrame::create(WebSocketOpcode::PongFrame); 43 | $this->server->sendFrame($user, $frame); 44 | } 45 | } 46 | 47 | /** 48 | * Demo socket server. Implements the basic eventlisteners and attaches a resource handler for /echo/ urls. 49 | * 50 | * 51 | * @author Chris 52 | * 53 | */ 54 | class DemoSocketServer extends WebSocketServer{ 55 | protected $debug = true; 56 | 57 | public function getAdminKey(){ 58 | return "superdupersecretkey"; 59 | } 60 | 61 | public function __construct($address, $port){ 62 | parent::__construct($address, $port); 63 | 64 | $this->addResourceHandler("echo", new DemoEchoHandler()); 65 | } 66 | protected function onConnect(IWebSocketUser $user){ 67 | $this->say("[DEMO] {$user->getId()} connected"); 68 | } 69 | 70 | public function onMessage($user, IWebSocketMessage $msg){ 71 | $this->say("[DEMO] {$user->getId()} says '{$msg->getData()}'"); 72 | } 73 | 74 | protected function onDisconnect(IWebSocketUser $user){ 75 | $this->say("[DEMO] {$user->getId()} disconnected"); 76 | } 77 | 78 | protected function onAdminTest(IWebSocketUser $user){ 79 | $this->say("[DEMO] Admin TEST received!"); 80 | 81 | $frame = WebSocketFrame::create(WebSocketOpcode::PongFrame); 82 | $this->sendFrame($user, $frame); 83 | } 84 | } 85 | 86 | // Start server 87 | //$server = new DemoSocketServer(0,12345); 88 | $server = new DemoSocketServer('0.0.0.0',54321); 89 | $server->run(); 90 | -------------------------------------------------------------------------------- /app/websock/old/websocket.admin.php: -------------------------------------------------------------------------------- 1 | adminKey = $adminKey; 11 | 12 | $this->addHeader("Admin-Key", $adminKey); 13 | } 14 | 15 | 16 | public function sendMessage(WebSocketAdminMessage $msg){ 17 | $wsmsg = WebSocketMessage::create(json_encode($msg)); 18 | 19 | parent::sendMessage($wsmsg); 20 | } 21 | } 22 | 23 | /** 24 | * Helper class to send Admin Messages to the WebSocketServer 25 | * 26 | * Makes the server execute onAdminXXXX() events 27 | * 28 | * @author Chris 29 | * 30 | */ 31 | class WebSocketAdminMessage extends stdClass{ 32 | public $task = null; 33 | 34 | private function __construct(){ 35 | 36 | } 37 | 38 | /** 39 | * Create a message that will be send to the instance of the WebSocketServer 40 | * 41 | * @param string $task 42 | * @return WebSocketAdminMessage 43 | */ 44 | public static function create($task){ 45 | $o = new self(); 46 | $o->task = $task; 47 | 48 | return $o; 49 | } 50 | } -------------------------------------------------------------------------------- /app/websock/old/websocket.client.php: -------------------------------------------------------------------------------- 1 | url = $url; 22 | 23 | if(in_array($parts['scheme'], array('ws')) === false) 24 | throw new WebSocketInvalidUrlScheme(); 25 | 26 | $this->host = $parts['host']; 27 | $this->port = $parts['port']; 28 | 29 | $this->origin = 'http://'.$this->host; 30 | 31 | if(isset($parts['path'])) 32 | $this->requestUri = $parts['path']; 33 | else $this->requestUri = "/"; 34 | 35 | if(isset($parts['query'])) 36 | $this->requestUri .= "?".$parts['query']; 37 | 38 | $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 39 | $this->setTimeOut(1); 40 | 41 | $this->buildHeaderArray(); 42 | } 43 | 44 | public function setTimeOut($seconds){ 45 | socket_set_option($this->socket,SOL_SOCKET, SO_RCVTIMEO, array("sec" => $seconds, "usec" => 0)); 46 | socket_set_option($this->socket,SOL_SOCKET, SO_SNDTIMEO, array("sec" => $seconds, "usec" => 0)); 47 | } 48 | 49 | /** 50 | * TODO: Proper header generation! 51 | * TODO: Check server response! 52 | */ 53 | public function open(){ 54 | socket_connect($this->socket, $this->host, $this->port); 55 | 56 | $buffer = $this->serializeHeaders(); 57 | 58 | socket_write($this->socket, $buffer, strlen($buffer)); 59 | 60 | // wait for response 61 | $buffer = socket_read($this->socket, 2048,PHP_BINARY_READ); 62 | $headers = WebSocketFunctions::parseHeaders($buffer); 63 | 64 | if($headers['Sec-Websocket-Accept'] != WebSocketFunctions::calcHybiResponse($this->handshakeChallenge)){ 65 | return false; 66 | } 67 | 68 | return true; 69 | } 70 | 71 | private function serializeHeaders(){ 72 | $str = ''; 73 | 74 | foreach($this->headers as $k => $v){ 75 | $str .= $k." ".$v."\r\n"; 76 | } 77 | 78 | return $str; 79 | } 80 | 81 | public function addHeader($key, $value){ 82 | $this->headers[$key.":"] = $value; 83 | } 84 | 85 | protected function buildHeaderArray(){ 86 | $this->handshakeChallenge = WebSocketFunctions::randHybiKey(); 87 | 88 | $this->headers = array( 89 | "GET" => "{$this->url} HTTP/1.1", 90 | "Connection:" => "Upgrade", 91 | "Host:" => "{$this->host}:{$this->port}", 92 | "Sec-WebSocket-Key:" => "{$this->handshakeChallenge}", 93 | "Sec-WebSocket-Origin:" => "{$this->origin}", 94 | "Sec-WebSocket-Version:" => 8, 95 | "Upgrade:" => "websocket" 96 | ); 97 | 98 | return $headers; 99 | } 100 | 101 | public function send($string){ 102 | $msg = WebSocketMessage::create($string); 103 | 104 | $this->sendMessage($msg); 105 | } 106 | 107 | public function sendMessage(IWebSocketMessage $msg){ 108 | // Sent all fragments 109 | foreach($msg->getFrames() as $frame){ 110 | $this->sendFrame($frame); 111 | } 112 | } 113 | 114 | public function sendFrame(IWebSocketFrame $frame){ 115 | $msg = $frame->encode(); 116 | socket_write($this->socket, $msg,strlen($msg)); 117 | } 118 | 119 | public function readFrame(){ 120 | $data = socket_read($this->socket,2048,PHP_BINARY_READ); 121 | 122 | if($data === false) 123 | return null; 124 | 125 | return WebSocketFrame::decode($data); 126 | } 127 | 128 | public function readMessage(){ 129 | $frame = $this->readFrame(); 130 | 131 | if($frame != null) 132 | $msg = WebSocketMessage::fromFrame($frame); 133 | else return null; 134 | 135 | while($msg->isFinalised() == false){ 136 | $frame = $this->readFrame(); 137 | 138 | if($frame != null) 139 | $msg->takeFrame($this->readFrame()); 140 | else return null; 141 | } 142 | 143 | return $msg; 144 | } 145 | 146 | public function close(){ 147 | socket_close($this->socket); 148 | } 149 | 150 | } -------------------------------------------------------------------------------- /app/websock/old/websocket.exceptions.php: -------------------------------------------------------------------------------- 1 | user = $user; 32 | } 33 | } 34 | 35 | class WebSocketInvalidKeyException extends Exception{ 36 | public function __construct($key1, $key2, $l8b){ 37 | parent::__construct("Client sent an invalid opening handshake!"); 38 | fwrite(STDERR, "Key 1: \t$key1\nKey 2: \t$key2\nL8b: \t$l8b"); 39 | } 40 | } -------------------------------------------------------------------------------- /app/websock/old/websocket.framing.php: -------------------------------------------------------------------------------- 1 | FIN = true; 103 | $o->payloadData = $data; 104 | $o->payloadLength = $data != null ? strlen($data) : 0; 105 | $o->setType($type); 106 | 107 | 108 | return $o; 109 | } 110 | 111 | public function isMasked(){ 112 | return $this->mask == 1; 113 | } 114 | 115 | protected function setType($type){ 116 | $this->opcode = $type; 117 | 118 | if($type == WebSocketOpcode::CloseFrame) 119 | $this->mask = 1; 120 | } 121 | 122 | protected static function IsBitSet($byte, $pos) 123 | { 124 | return ($byte & pow(2,$pos)) > 0 ? 1 : 0; 125 | } 126 | 127 | protected static function rotMask($data, $key){ 128 | $res = ''; 129 | for($i = 0; $i < strlen($data); $i++){ 130 | $j = $i % 4; 131 | 132 | $res .= chr(ord($data[$i]) ^ ord($key[$j])); 133 | } 134 | 135 | return $res; 136 | } 137 | 138 | public function getType(){ 139 | return $this->opcode; 140 | } 141 | 142 | public function encode(){ 143 | $this->payloadLength = strlen($this->payloadData); 144 | 145 | 146 | $firstByte = $this->opcode; 147 | 148 | $firstByte += 149 | $this->FIN * 128 150 | + $this->RSV1 * 64 151 | + $this->RSV2 * 32 152 | + $this->RSV3 * 16; 153 | 154 | $encoded = chr($firstByte); 155 | 156 | if($this->payloadLength <= 125){ 157 | $secondByte = $this->payloadLength; 158 | $secondByte += $this->mask * 128; 159 | 160 | $encoded .= chr($secondByte); 161 | } else if($this->payloadLength <= 255*255 - 1){ 162 | $secondByte = 126; 163 | $secondByte += $this->mask * 128; 164 | 165 | $encoded .= chr($secondByte).pack("n", $this->payloadLength); 166 | } else { 167 | // TODO: max length is now 32 bits instead of 64 !!!!! 168 | $secondByte = 127; 169 | $secondByte += $this->mask * 128; 170 | 171 | $encoded .= chr($secondByte); 172 | $encoded .= pack("N",0); 173 | $encoded .= pack("N",$this->payloadLength); 174 | } 175 | 176 | $key = 0; 177 | if($this->mask){ 178 | $key = pack("N", rand(0, pow(255,4) - 1)); 179 | $encoded .= $key; 180 | 181 | } 182 | 183 | if($this->payloadData) 184 | $encoded .= ($this->mask == 1) ? $this->rotMask($this->payloadData,$key) : $this->payloadData; 185 | 186 | return $encoded; 187 | } 188 | 189 | public static function decode($raw){ 190 | $frame = new self(); 191 | 192 | // Read the first two bytes, then chop them off 193 | list($firstByte, $secondByte) = substr($raw,0,2); 194 | $raw = substr($raw,2); 195 | 196 | $firstByte = ord($firstByte); 197 | $secondByte = ord($secondByte); 198 | 199 | $frame->FIN = self::IsBitSet($firstByte, 7); 200 | $frame->RSV1 = self::IsBitSet($firstByte, 6); 201 | $frame->RSV2 = self::IsBitSet($firstByte, 5); 202 | $frame->RSV3 = self::IsBitSet($firstByte, 4); 203 | 204 | $frame->mask = self::IsBitSet($secondByte, 7); 205 | 206 | $frame->opcode = ($firstByte & 0x0F); 207 | 208 | $len = $secondByte & ~128; 209 | 210 | 211 | if($len <= 125) 212 | $frame->payloadLength = $len; 213 | elseif($len == 126){ 214 | list($frame->payloadLength) = unpack("nfirst", $raw); 215 | $raw = substr($raw,2); 216 | } elseif($len = 127) { 217 | list($frame->payloadLength) = unpack("nfirst", $raw); 218 | $raw = substr($raw,4); 219 | } 220 | 221 | if($frame->mask){ 222 | $frame->maskingKey = substr($raw,0,4); 223 | $raw = substr($raw,4); 224 | } 225 | 226 | if(strlen($raw) != $frame->payloadLength) 227 | throw new WebSocketFrameSizeMismatch($frame); 228 | 229 | if($frame->mask) 230 | $frame->payloadData = self::rotMask($raw, $frame->maskingKey); 231 | else $frame->payloadData = $raw; 232 | 233 | return $frame; 234 | } 235 | 236 | public function isFinal(){ 237 | return $this->FIN == 1; 238 | } 239 | 240 | public function getData(){ 241 | return $this->payloadData; 242 | } 243 | } 244 | 245 | class WebSocketFrame76 implements IWebSocketFrame{ 246 | public $payloadData = ''; 247 | protected $opcode = WebSocketOpcode::TextFrame; 248 | 249 | public static function create($type, $data = null){ 250 | $o = new self(); 251 | 252 | $o->payloadData = $data; 253 | 254 | return $o; 255 | } 256 | 257 | public function encode(){ 258 | return chr(0).$this->payloadData.chr(255); 259 | } 260 | 261 | public function getData(){ 262 | return $this->payloadData; 263 | } 264 | 265 | public function getType(){ 266 | return $this->opcode; 267 | } 268 | 269 | public static function decode($str){ 270 | $o = new self(); 271 | $o->payloadData = substr($str, 1, strlen($str) - 2); 272 | 273 | return $o; 274 | } 275 | 276 | } -------------------------------------------------------------------------------- /app/websock/old/websocket.functions.php: -------------------------------------------------------------------------------- 1 | setData($data); 65 | return $o; 66 | } 67 | 68 | public function getFrames(){ 69 | $arr = array(); 70 | 71 | $arr[] = $this->frame; 72 | 73 | return $arr; 74 | } 75 | 76 | public function setData($data){ 77 | $this->data = $data; 78 | $this->frame = WebSocketFrame76::create(WebSocketOpcode::TextFrame, $data); 79 | } 80 | public function getData(){ 81 | return $this->frame->getData(); 82 | } 83 | 84 | public function isFinalised(){ 85 | return true; 86 | } 87 | 88 | /** 89 | * Creates a new WebSocketMessage76 from a IWebSocketFrame 90 | * @param IWebSocketFrame $frame 91 | * 92 | * @return WebSocketMessage76 Message composed of the frame provided 93 | */ 94 | public static function fromFrame(IWebSocketFrame $frame){ 95 | $o = new self(); 96 | $o->frame = $frame; 97 | 98 | return $o; 99 | } 100 | } 101 | 102 | /** 103 | * WebSocketMessage compatible with the latest draft. 104 | * Should be updated to keep up with the latest changes. 105 | * 106 | * @author Chris 107 | * 108 | */ 109 | class WebSocketMessage implements IWebSocketMessage{ 110 | /** 111 | * 112 | * Enter description here ... 113 | * @var WebSocketFrame[]; 114 | */ 115 | protected $frames = array(); 116 | protected $data = ''; 117 | 118 | public function setData($data){ 119 | $this->data = $data; 120 | 121 | $this->createFrames(); 122 | } 123 | 124 | public static function create($data){ 125 | $o = new self(); 126 | 127 | $o->setData($data); 128 | return $o; 129 | } 130 | 131 | public function getData(){ 132 | if($this->isFinalised() == false) 133 | throw new WebSocketMessageNotFinalised($this); 134 | 135 | $data = ''; 136 | 137 | foreach($this->frames as $frame){ 138 | $data .= $frame->getData(); 139 | } 140 | 141 | return $data; 142 | } 143 | 144 | 145 | public static function fromFrame(IWebSocketFrame $frame){ 146 | $o = new self(); 147 | $o->takeFrame($frame); 148 | 149 | return $o; 150 | } 151 | 152 | protected function createFrames(){ 153 | $this->frames = array(WebSocketFrame::create(WebSocketOpcode::TextFrame, $this->data)); 154 | } 155 | 156 | public function getFrames(){ 157 | return $this->frames; 158 | } 159 | 160 | public function isFinalised(){ 161 | if(count($this->frames) == 0) 162 | return false; 163 | 164 | return $this->frames[count($this->frames)-1]->isFinal(); 165 | } 166 | 167 | /** 168 | * Append a frame to the message 169 | * @param unknown_type $frame 170 | */ 171 | public function takeFrame(WebSocketFrame $frame){ 172 | $this->frames[] = $frame; 173 | } 174 | } -------------------------------------------------------------------------------- /app/websock/old/websocket.resources.php: -------------------------------------------------------------------------------- 1 | users = new SplObjectStorage(); 32 | } 33 | 34 | public function addUser(IWebSocketUser $user){ 35 | $this->users->attach($user); 36 | } 37 | 38 | public function removeUser(IWebSocketUser $user){ 39 | $this->users->detach($user); 40 | } 41 | 42 | public function setServer(WebSocketServer $server){ 43 | $this->server = $server; 44 | } 45 | 46 | public function say($msg =''){ 47 | return $this->server->say($msg); 48 | } 49 | 50 | public function send(IWebSocketUser $client, $str){ 51 | return $this->server->send($client, $str); 52 | } 53 | 54 | public function onMessage(IWebSocketUser $user, IWebSocketMessage $msg){} 55 | public function onAdminMessage(IWebSocketUser $user, stdClass $msg){} 56 | 57 | //abstract public function onMessage(WebSocketUser $user, IWebSocketMessage $msg); 58 | 59 | public function getUsers(){ 60 | return $this->users; 61 | } 62 | } -------------------------------------------------------------------------------- /app/websock/old/websocket.users.php: -------------------------------------------------------------------------------- 1 | socket = $socket; 66 | 67 | $address = ''; 68 | if(socket_getpeername($socket, &$address) === false) 69 | throw new Exception(); 70 | 71 | $this->ip = $address; 72 | $this->id = uniqid("u-"); 73 | 74 | $this->_server = $server; 75 | 76 | $this->lastTime = time(); 77 | } 78 | 79 | public function getId(){ 80 | return $this->id; 81 | } 82 | 83 | public function getHeaders(){ 84 | return $this->headers; 85 | } 86 | 87 | public function setHeaders($headers){ 88 | $this->headers = $headers; 89 | 90 | if(array_key_exists('Cookie', $this->headers) && is_array($this->headers['Cookie'])) { 91 | $this->cookie = array(); 92 | } else { 93 | if(array_key_exists("Cookie", $this->headers)){ 94 | $this->_cookies = WebSocketFunctions::cookie_parse($this->headers['Cookie']); 95 | }else $this->_cookies = array(); 96 | } 97 | 98 | $this->isAdmin = array_key_exists('Admin-Key', $this->headers) 99 | && $this->headers['Admin-Key'] == $this->getServerInstance()->getAdminKey(); 100 | 101 | // Incorrect admin-key 102 | if($this->isAdmin == false && array_key_exists('Admin-Key', $this->headers)) 103 | throw new WebSocketNotAuthorizedException($this); 104 | 105 | } 106 | 107 | public function createMessage($data){ 108 | if($this->protocol == WebSocketProtocolVersions::HIXIE_76) 109 | return WebSocketMessage76::create($data); 110 | else return WebSocketMessage::create($data); 111 | } 112 | 113 | public function hasHandshaked(){ 114 | return $this->handshaked; 115 | } 116 | 117 | public function setHandshaked(){ 118 | $this->handshaked = true; 119 | } 120 | 121 | public function getProtocolVersion(){ 122 | return $this->protocol; 123 | } 124 | 125 | public function getCookies(){ 126 | return $this->_cookies; 127 | } 128 | 129 | public function setProtocolVersion($version){ 130 | $this->protocol = $version; 131 | } 132 | 133 | public function getResource(){ 134 | return $this->resource; 135 | } 136 | 137 | public function setResource($resource){ 138 | $this->resource = $resource; 139 | } 140 | 141 | public function isAdmin(){ 142 | return $this->isAdmin; 143 | } 144 | 145 | public function getLastMessage(){ 146 | return $this->message; 147 | } 148 | 149 | public function getSocket(){ 150 | return $this->socket; 151 | } 152 | 153 | public function addMessage(IWebSocketMessage $msg){ 154 | $this->message = $msg; 155 | $this->lastTime = time(); 156 | } 157 | 158 | public function getLastMessageTime(){ 159 | return $this->lastTime; 160 | } 161 | 162 | public function getServerInstance(){ 163 | return $this->_server; 164 | } 165 | 166 | public function getIp(){ 167 | return $this->ip; 168 | } 169 | } -------------------------------------------------------------------------------- /app/websock/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ctfwsserver", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Claudio Gamboa ", 10 | "license": "ISC", 11 | "dependencies": { 12 | "mysql": "^2.11.1", 13 | "pm2": "^2.0.18", 14 | "ws": "^1.1.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/websock/start_websockets.sh: -------------------------------------------------------------------------------- 1 | ./node_modules/pm2/bin/pm2 start app/server.js 2 | -------------------------------------------------------------------------------- /app/websock/stop_websockets.sh: -------------------------------------------------------------------------------- 1 | ./node_modules/pm2/bin/pm2 stop app/server.js 2 | -------------------------------------------------------------------------------- /catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: CTF-Game 5 | spec: 6 | type: intentionally-vulnerable 7 | lifecycle: "-" 8 | owner: "-" -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "textalk/websocket": "1.0.*" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "f84ba71c3da1165dc6d66094d0028157", 8 | "content-hash": "bd455206e2cff444eabd9923726c6543", 9 | "packages": [ 10 | { 11 | "name": "textalk/websocket", 12 | "version": "1.0.3", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/Textalk/websocket-php.git", 16 | "reference": "ba2e5f9ef7cf24d536d1c864ae74b2a9599b86eb" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/Textalk/websocket-php/zipball/ba2e5f9ef7cf24d536d1c864ae74b2a9599b86eb", 21 | "reference": "ba2e5f9ef7cf24d536d1c864ae74b2a9599b86eb", 22 | "shasum": "" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "4.1.*", 26 | "phpunit/phpunit-selenium": "1.3.3", 27 | "satooshi/php-coveralls": "dev-master" 28 | }, 29 | "type": "library", 30 | "autoload": { 31 | "psr-4": { 32 | "WebSocket\\": "lib" 33 | } 34 | }, 35 | "notification-url": "https://packagist.org/downloads/", 36 | "license": [ 37 | "MIT" 38 | ], 39 | "authors": [ 40 | { 41 | "name": "Fredrik Liljegren", 42 | "email": "fredrik.liljegren@textalk.se" 43 | } 44 | ], 45 | "description": "WebSocket client and server", 46 | "time": "2015-04-11 05:45:54" 47 | } 48 | ], 49 | "packages-dev": [], 50 | "aliases": [], 51 | "minimum-stability": "stable", 52 | "stability-flags": [], 53 | "prefer-stable": false, 54 | "prefer-lowest": false, 55 | "platform": [], 56 | "platform-dev": [] 57 | } 58 | -------------------------------------------------------------------------------- /composer.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Probely/CTF-Game/1759dfbfe7f6d0dd974a9f709f1ab1ab08161bbe/composer.phar -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | nginx: 4 | build: docker/nginx 5 | ports: 6 | - "8050:80" 7 | links: 8 | - php 9 | volumes: 10 | - .:/var/www/ctf 11 | php: 12 | build: docker/php 13 | ports: 14 | - "9000" 15 | links: 16 | - mysql 17 | environment: 18 | DB_HOST: mysql 19 | volumes: 20 | - .:/var/www/ctf 21 | mysql: 22 | image: mysql 23 | ports: 24 | - "3306" 25 | environment: 26 | MYSQL_ROOT_PASSWORD: hellyeah 27 | volumes: 28 | - ./sql:/docker-entrypoint-initdb.d 29 | -------------------------------------------------------------------------------- /docker/nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:latest 2 | COPY ./default.conf /etc/nginx/conf.d/ -------------------------------------------------------------------------------- /docker/nginx/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | 4 | root /var/www/ctf/app; 5 | 6 | location / { 7 | try_files $uri /index.php$is_args$args; 8 | } 9 | 10 | location ~ ^/.+\.php(/|$) { 11 | fastcgi_pass php:9000; 12 | include fastcgi_params; 13 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docker/php/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7-fpm 2 | RUN docker-php-ext-install pdo pdo_mysql -------------------------------------------------------------------------------- /screenshots/backoffice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Probely/CTF-Game/1759dfbfe7f6d0dd974a9f709f1ab1ab08161bbe/screenshots/backoffice.png -------------------------------------------------------------------------------- /screenshots/public dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Probely/CTF-Game/1759dfbfe7f6d0dd974a9f709f1ab1ab08161bbe/screenshots/public dashboard.png -------------------------------------------------------------------------------- /screenshots/team dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Probely/CTF-Game/1759dfbfe7f6d0dd974a9f709f1ab1ab08161bbe/screenshots/team dashboard.png -------------------------------------------------------------------------------- /sql/.htaccess: -------------------------------------------------------------------------------- 1 | order deny,allow 2 | deny from all 3 | -------------------------------------------------------------------------------- /sql/schema.sql: -------------------------------------------------------------------------------- 1 | -- MySQL dump 10.13 Distrib 5.1.57, for apple-darwin10.8.0 (i386) 2 | -- 3 | -- Host: localhost Database: codebits 4 | -- ------------------------------------------------------ 5 | -- Server version 5.1.53 6 | 7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 10 | /*!40101 SET NAMES utf8 */; 11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 12 | /*!40103 SET TIME_ZONE='+00:00' */; 13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 17 | 18 | CREATE DATABASE IF NOT EXISTS CTF; 19 | USE CTF; 20 | 21 | -- 22 | -- Table structure for table `answers` 23 | -- 24 | 25 | DROP TABLE IF EXISTS `answers`; 26 | /*!40101 SET @saved_cs_client = @@character_set_client */; 27 | /*!40101 SET character_set_client = utf8 */; 28 | CREATE TABLE `answers` ( 29 | `teamid` int(11) NOT NULL, 30 | `cat` varchar(20) NOT NULL, 31 | `question` int(11) NOT NULL, 32 | `points` int(11) DEFAULT NULL, 33 | `answeredts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 34 | PRIMARY KEY (`teamid`,`cat`,`question`), 35 | KEY `teamid` (`teamid`) 36 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 37 | /*!40101 SET character_set_client = @saved_cs_client */; 38 | 39 | -- 40 | -- Dumping data for table `answers` 41 | -- 42 | 43 | LOCK TABLES `answers` WRITE; 44 | /*!40000 ALTER TABLE `answers` DISABLE KEYS */; 45 | #INSERT INTO `answers` VALUES (1,'Trivia',100,90,'2011-10-31 17:23:50'),(1,'Trivia',200,200,'2011-10-31 17:23:50'),(1,'Trivia',400,400,'2011-10-31 17:23:50'),(2,'Forensics',300,300,'2011-10-31 17:23:40'),(2,'Trivia',100,100,'2011-10-31 17:23:50'),(2,'Trivia',300,300,'2011-10-31 17:23:50'),(2,'Web Hacking',100,100,'2011-10-31 17:24:29'),(2,'Web Hacking',200,180,'2011-11-02 14:45:43'),(3,'Trivia',100,80,'2011-11-02 14:45:43'),(3,'Trivia',200,160,'2011-11-02 14:45:43'),(4,'Trivia',100,80,'2011-11-02 14:45:43'),(4,'Web Hacking',200,200,'2011-11-02 14:45:43'),(5,'Trivia',100,80,'2011-11-02 14:45:43'); 46 | 47 | insert into answers values (5,'Trivia',100,100,now()); insert into answers values (5,'Trivia',200,100,now());insert into answers values (5,'Trivia',300,100,now()); insert into answers values (5,'Trivia',400,100,now()); 48 | insert into answers values (5,'Pwnable',100,100,now()); insert into answers values (5,'Pwnable',200,100,now());insert into answers values (5,'Pwnable',300,100,now());insert into answers values (5,'Pwnable',400,100,now()); 49 | insert into answers values (5,'Forensics',100,100,now()); insert into answers values (5,'Forensics',200,100,now());insert into answers values (5,'Forensics',300,100,now());insert into answers values (5,'Forensics',400,100,now()); 50 | insert into answers values (5,'Web Hacking',100,100,now());insert into answers values (5,'Web Hacking',200,100,now()); insert into answers values (5,'Web Hacking',300,100,now()); insert into answers values (5,'Web Hacking',400,100,now()); 51 | 52 | /*!40000 ALTER TABLE `answers` ENABLE KEYS */; 53 | UNLOCK TABLES; 54 | 55 | -- 56 | -- Table structure for table `game` 57 | -- 58 | 59 | DROP TABLE IF EXISTS `game`; 60 | /*!40101 SET @saved_cs_client = @@character_set_client */; 61 | /*!40101 SET character_set_client = utf8 */; 62 | CREATE TABLE `game` ( 63 | `leadcat` varchar(20), 64 | `leadpoints` int(11), 65 | `yellowshirt` int(11) DEFAULT NULL, 66 | `lastleadreset` timestamp NULL DEFAULT NULL, 67 | `end` timestamp NULL DEFAULT NULL, 68 | PRIMARY KEY (`leadcat`, `leadpoints`), 69 | KEY `yellowshirt` (`yellowshirt`), 70 | CONSTRAINT `yellowshirt` FOREIGN KEY (`yellowshirt`) REFERENCES `teams` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION 71 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 72 | /*!40101 SET character_set_client = @saved_cs_client */; 73 | 74 | -- 75 | -- Dumping data for table `game` 76 | -- 77 | 78 | LOCK TABLES `game` WRITE; 79 | /*!40000 ALTER TABLE `game` DISABLE KEYS */; 80 | INSERT INTO `game` (leadcat,leadpoints,end) VALUES ('Trivia',100,from_unixtime(unix_timestamp(now())+10800)); 81 | /*!40000 ALTER TABLE `game` ENABLE KEYS */; 82 | UNLOCK TABLES; 83 | 84 | -- 85 | -- Table structure for table `teams` 86 | -- 87 | 88 | DROP TABLE IF EXISTS `teams`; 89 | /*!40101 SET @saved_cs_client = @@character_set_client */; 90 | /*!40101 SET character_set_client = utf8 */; 91 | CREATE TABLE `teams` ( 92 | `id` int(11) NOT NULL, 93 | `team` varchar(80) DEFAULT NULL, 94 | `tkey` varchar(80) DEFAULT NULL, 95 | PRIMARY KEY (`id`), 96 | UNIQUE KEY `tkey_UNIQUE` (`tkey`) 97 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 98 | /*!40101 SET character_set_client = @saved_cs_client */; 99 | 100 | DROP TABLE IF EXISTS `hints`; 101 | /*!40101 SET @saved_cs_client = @@character_set_client */; 102 | /*!40101 SET character_set_client = utf8 */; 103 | CREATE TABLE `hints` ( 104 | `id` int(11) NOT NULL AUTO_INCREMENT, 105 | `hint` TEXT NOT NULL, 106 | `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 107 | PRIMARY KEY (`id`) 108 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 109 | /*!40101 SET character_set_client = @saved_cs_client */; 110 | 111 | -- 112 | -- Dumping data for table `teams` 113 | -- 114 | 115 | LOCK TABLES `teams` WRITE; 116 | /*!40000 ALTER TABLE `teams` DISABLE KEYS */; 117 | INSERT INTO `teams` VALUES (1,'Team1',sha1('5bd7b888f1327e07ecfcbed64a7ba4154bbe08bc')), 118 | (2,'team2',sha1('da1caf48a41f09b76df6e6692f03573508925364')), 119 | (3,'Team3',sha1('6e91a41941be135959c97a26ad43cbc6c8a68364')), 120 | (4,'team4',sha1('92e1b5d17c3b6ad12b6a711d70a077a3d32d27c9')), 121 | (5,'Team5',sha1('7849f1efc1578926a42a91198d872a47b6614adf')), 122 | (6,'team6',sha1('b8a49af1f5801d6943f271887511cac890cceaca')), 123 | (7,'Team7',sha1('caf47b50a973d1dcec68095021111caef0b8a680')), 124 | (8,'team8',sha1('b87611d1ab526a72f015417131faf618dcead012')), 125 | (9,'Team9',sha1('7fe046eb111dd620d9fc9b1b11cd0d6d0c35fb61')), 126 | (10,'team10',sha1('a31f110ac892c1c4fad24f5cc7131e58b3311396')); 127 | /*!40000 ALTER TABLE `teams` ENABLE KEYS */; 128 | UNLOCK TABLES; 129 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 130 | 131 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 132 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 133 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 134 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 135 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 136 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 137 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 138 | 139 | CREATE USER 'pixels'@'localhost' IDENTIFIED BY 'xxxxxxxxxxx'; 140 | GRANT SELECT,INSERT,UPDATE,DELETE ON CTF.* TO 'pixels'@'localhost'; 141 | 142 | 143 | -- Dump completed on 2011-11-02 15:06:05 144 | -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | array($vendorDir . '/textalk/websocket/lib'), 10 | ); 11 | -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | = 50600 && !defined('HHVM_VERSION'); 27 | if ($useStaticLoader) { 28 | require_once __DIR__ . '/autoload_static.php'; 29 | 30 | call_user_func(\Composer\Autoload\ComposerStaticInitebb8a408ed842a32cbacb538793056a2::getInitializer($loader)); 31 | } else { 32 | $map = require __DIR__ . '/autoload_namespaces.php'; 33 | foreach ($map as $namespace => $path) { 34 | $loader->set($namespace, $path); 35 | } 36 | 37 | $map = require __DIR__ . '/autoload_psr4.php'; 38 | foreach ($map as $namespace => $path) { 39 | $loader->setPsr4($namespace, $path); 40 | } 41 | 42 | $classMap = require __DIR__ . '/autoload_classmap.php'; 43 | if ($classMap) { 44 | $loader->addClassMap($classMap); 45 | } 46 | } 47 | 48 | $loader->register(true); 49 | 50 | return $loader; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | 11 | array ( 12 | 'WebSocket\\' => 10, 13 | ), 14 | ); 15 | 16 | public static $prefixDirsPsr4 = array ( 17 | 'WebSocket\\' => 18 | array ( 19 | 0 => __DIR__ . '/..' . '/textalk/websocket/lib', 20 | ), 21 | ); 22 | 23 | public static function getInitializer(ClassLoader $loader) 24 | { 25 | return \Closure::bind(function () use ($loader) { 26 | $loader->prefixLengthsPsr4 = ComposerStaticInitebb8a408ed842a32cbacb538793056a2::$prefixLengthsPsr4; 27 | $loader->prefixDirsPsr4 = ComposerStaticInitebb8a408ed842a32cbacb538793056a2::$prefixDirsPsr4; 28 | 29 | }, null, ClassLoader::class); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "textalk/websocket", 4 | "version": "1.0.3", 5 | "version_normalized": "1.0.3.0", 6 | "source": { 7 | "type": "git", 8 | "url": "https://github.com/Textalk/websocket-php.git", 9 | "reference": "ba2e5f9ef7cf24d536d1c864ae74b2a9599b86eb" 10 | }, 11 | "dist": { 12 | "type": "zip", 13 | "url": "https://api.github.com/repos/Textalk/websocket-php/zipball/ba2e5f9ef7cf24d536d1c864ae74b2a9599b86eb", 14 | "reference": "ba2e5f9ef7cf24d536d1c864ae74b2a9599b86eb", 15 | "shasum": "" 16 | }, 17 | "require-dev": { 18 | "phpunit/phpunit": "4.1.*", 19 | "phpunit/phpunit-selenium": "1.3.3", 20 | "satooshi/php-coveralls": "dev-master" 21 | }, 22 | "time": "2015-04-11 05:45:54", 23 | "type": "library", 24 | "installation-source": "dist", 25 | "autoload": { 26 | "psr-4": { 27 | "WebSocket\\": "lib" 28 | } 29 | }, 30 | "notification-url": "https://packagist.org/downloads/", 31 | "license": [ 32 | "MIT" 33 | ], 34 | "authors": [ 35 | { 36 | "name": "Fredrik Liljegren", 37 | "email": "fredrik.liljegren@textalk.se" 38 | } 39 | ], 40 | "description": "WebSocket client and server" 41 | } 42 | ] 43 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | src_dir: lib 3 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /vendor/ 3 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.5 5 | - 5.4 6 | - 5.3 7 | 8 | before_script: 9 | - curl -s http://getcomposer.org/installer | php 10 | - php composer.phar install --dev --no-interaction 11 | 12 | script: 13 | - mkdir -p build/logs 14 | - ./vendor/bin/phpunit 15 | 16 | after_script: 17 | - php vendor/bin/coveralls -v 18 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/Makefile: -------------------------------------------------------------------------------- 1 | install: composer.phar 2 | ./composer.phar install 3 | 4 | update: 5 | ./composer.phar update 6 | 7 | test: vendor/bin/phpunit build 8 | ./vendor/bin/phpunit --strict 9 | 10 | composer.phar: 11 | curl -s http://getcomposer.org/installer | php 12 | 13 | vendor/bin/phpunit: install 14 | 15 | build: 16 | mkdir build 17 | 18 | clean: 19 | rm composer.phar 20 | rm -r vendor 21 | rm -r build 22 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/README.md: -------------------------------------------------------------------------------- 1 | Websocket Client for PHP 2 | ======================== 3 | 4 | [![Build Status](https://travis-ci.org/Textalk/websocket-php.png)](https://travis-ci.org/Textalk/websocket-php) 5 | [![Coverage Status](https://coveralls.io/repos/Textalk/websocket-php/badge.png)](https://coveralls.io/r/Textalk/websocket-php) 6 | 7 | This package mainly contains a WebSocket client for PHP. 8 | 9 | I made it because the state of other WebSocket clients I could found was either very poor 10 | (sometimes failing on large frames) or had huge dependencies (React…). 11 | 12 | The Client should be good. If it isn't, tell me! 13 | 14 | The Server there because much of the code would be identical in writing a server, and because it is 15 | used for the tests. To be really useful though, there should be a Connection-class returned from a 16 | new Connection, and the Server-class only handling the handshake. Then you could hold a full array 17 | of Connections and check them periodically for new data, send something to them all or fork off a 18 | process handling one connection. But, I have no use for that right now. (Actually, I would 19 | suggest a language with better asynchronous handling than PHP for that.) 20 | 21 | Installing 22 | ---------- 23 | 24 | Preferred way to install is with [Composer](https://getcomposer.org/). 25 | 26 | Just add 27 | 28 | "require": { 29 | "textalk/websocket": "1.0.*" 30 | } 31 | 32 | in your projects composer.json. 33 | 34 | Client usage: 35 | ------------- 36 | ```php 37 | require('vendor/autoload.php'); 38 | 39 | use WebSocket\Client; 40 | 41 | $client = new Client("ws://echo.websocket.org/"); 42 | $client->send("Hello WebSocket.org!"); 43 | 44 | echo $client->receive(); // Will output 'Hello WebSocket.org!' 45 | ``` 46 | 47 | Developer install 48 | ----------------- 49 | 50 | Development depends on php, php-curl and php-xdebug. 51 | 52 | ```bash 53 | # Will get composer, install dependencies and run tests 54 | make test 55 | ``` 56 | 57 | Changelog 58 | --------- 59 | 60 | 1.0.0 61 | 62 | * Release as production ready. 63 | * Adding option to set/override headers. 64 | * Supporting basic authentication from user:pass in URL. 65 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "textalk/websocket", 3 | "description": "WebSocket client and server", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Fredrik Liljegren", 8 | "email": "fredrik.liljegren@textalk.se" 9 | } 10 | ], 11 | "autoload": { 12 | "psr-4": {"WebSocket\\": "lib"} 13 | }, 14 | "require-dev": { 15 | "phpunit/phpunit": "4.1.*", 16 | "phpunit/phpunit-selenium": "1.3.3", 17 | "satooshi/php-coveralls": "dev-master" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/examples/echoserver.php: -------------------------------------------------------------------------------- 1 | 200)); 15 | 16 | echo $server->getPort(), "\n"; 17 | 18 | while ($connection = $server->accept()) { 19 | $test_id = $server->getPath(); 20 | $test_id = substr($test_id, 1); 21 | 22 | xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); 23 | PHPUnit_Extensions_SeleniumCommon_ExitHandler::init(); 24 | 25 | try { 26 | while(1) { 27 | $message = $server->receive(); 28 | echo "Received $message\n\n"; 29 | 30 | if ($message === 'exit') { 31 | echo microtime(true), " Client told me to quit. Bye bye.\n"; 32 | echo microtime(true), " Close response: ", $server->close(), "\n"; 33 | echo microtime(true), " Close status: ", $server->getCloseStatus(), "\n"; 34 | save_coverage_data($test_id); 35 | exit; 36 | } 37 | 38 | if ($message === 'Dump headers') { 39 | $server->send(implode("\r\n", $server->getRequest())); 40 | } 41 | elseif ($auth = $server->getHeader('Authorization')) { 42 | $server->send("$auth - $message", 'text', false); 43 | } 44 | else { 45 | $server->send($message, 'text', false); 46 | } 47 | } 48 | } 49 | catch (WebSocket\ConnectionException $e) { 50 | echo "\n", microtime(true), " Client died: $e\n"; 51 | save_coverage_data($test_id); 52 | } 53 | } 54 | 55 | exit; 56 | 57 | 58 | function save_coverage_data($test_id) { 59 | $data = xdebug_get_code_coverage(); 60 | xdebug_stop_code_coverage(); 61 | 62 | if (!is_dir($GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'])) { 63 | mkdir($GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'], 0777, true); 64 | } 65 | $file = $GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'] . '/' . $test_id 66 | . '.' . md5(uniqid(rand(), true)); 67 | 68 | echo "Saving coverage data to $file...\n"; 69 | file_put_contents($file, serialize($data)); 70 | } 71 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/examples/send.php: -------------------------------------------------------------------------------- 1 | send($argv[2]); 10 | 11 | echo $client->receive(); 12 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/lib/BadOpcodeException.php: -------------------------------------------------------------------------------- 1 | 1, 11 | 'binary' => 2, 12 | 'close' => 8, 13 | 'ping' => 9, 14 | 'pong' => 10, 15 | ); 16 | 17 | public function getLastOpcode() { return $this->last_opcode; } 18 | public function getCloseStatus() { return $this->close_status; } 19 | public function isConnected() { return $this->is_connected; } 20 | 21 | public function setTimeout($timeout) { 22 | $this->options['timeout'] = $timeout; 23 | 24 | if ($this->socket && get_resource_type($this->socket) === 'stream') { 25 | stream_set_timeout($this->socket, $timeout); 26 | } 27 | } 28 | 29 | public function send($payload, $opcode = 'text', $masked = true) { 30 | if (!$this->is_connected) $this->connect(); /// @todo This is a client function, fixme! 31 | 32 | if (!in_array($opcode, array_keys(self::$opcodes))) { 33 | throw new BadOpcodeException("Bad opcode '$opcode'. Try 'text' or 'binary'."); 34 | } 35 | 36 | // Binary string for header. 37 | $frame_head_binstr = ''; 38 | 39 | 40 | // Write FIN, final fragment bit. 41 | $final = true; /// @todo Support HUGE payloads. 42 | $frame_head_binstr .= $final ? '1' : '0'; 43 | 44 | // RSV 1, 2, & 3 false and unused. 45 | $frame_head_binstr .= '000'; 46 | 47 | // Opcode rest of the byte. 48 | $frame_head_binstr .= sprintf('%04b', self::$opcodes[$opcode]); 49 | 50 | // Use masking? 51 | $frame_head_binstr .= $masked ? '1' : '0'; 52 | 53 | // 7 bits of payload length... 54 | $payload_length = strlen($payload); 55 | if ($payload_length > 65535) { 56 | $frame_head_binstr .= decbin(127); 57 | $frame_head_binstr .= sprintf('%064b', $payload_length); 58 | } 59 | elseif ($payload_length > 125) { 60 | $frame_head_binstr .= decbin(126); 61 | $frame_head_binstr .= sprintf('%016b', $payload_length); 62 | } 63 | else { 64 | $frame_head_binstr .= sprintf('%07b', $payload_length); 65 | } 66 | 67 | $frame = ''; 68 | 69 | // Write frame head to frame. 70 | foreach (str_split($frame_head_binstr, 8) as $binstr) $frame .= chr(bindec($binstr)); 71 | 72 | // Handle masking 73 | if ($masked) { 74 | // generate a random mask: 75 | $mask = ''; 76 | for ($i = 0; $i < 4; $i++) $mask .= chr(rand(0, 255)); 77 | $frame .= $mask; 78 | } 79 | 80 | // Append payload to frame: 81 | for ($i = 0; $i < $payload_length; $i++) { 82 | $frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i]; 83 | } 84 | 85 | $this->write($frame); 86 | } 87 | 88 | public function receive() { 89 | if (!$this->is_connected) $this->connect(); /// @todo This is a client function, fixme! 90 | 91 | // Just read the main fragment information first. 92 | $data = $this->read(2); 93 | 94 | // Is this the final fragment? // Bit 0 in byte 0 95 | /// @todo Handle huge payloads with multiple fragments. 96 | $final = (boolean) (ord($data[0]) & 1 << 7); 97 | 98 | // Should be unused, and must be false… // Bits 1, 2, & 3 99 | $rsv1 = (boolean) (ord($data[0]) & 1 << 6); 100 | $rsv2 = (boolean) (ord($data[0]) & 1 << 5); 101 | $rsv3 = (boolean) (ord($data[0]) & 1 << 4); 102 | 103 | // Parse opcode 104 | $opcode_int = ord($data[0]) & 31; // Bits 4-7 105 | $opcode_ints = array_flip(self::$opcodes); 106 | if (!array_key_exists($opcode_int, $opcode_ints)) { 107 | throw new ConnectionException("Bad opcode in websocket frame: $opcode_int"); 108 | } 109 | $opcode = $opcode_ints[$opcode_int]; 110 | $this->last_opcode = $opcode; 111 | 112 | // Masking? 113 | $mask = (boolean) (ord($data[1]) >> 7); // Bit 0 in byte 1 114 | 115 | $payload = ""; 116 | 117 | // Payload length 118 | $payload_length = (integer) ord($data[1]) & 127; // Bits 1-7 in byte 1 119 | if ($payload_length > 125) { 120 | if ($payload_length === 126) $data = $this->read(2); // 126: Payload is a 16-bit unsigned int 121 | else $data = $this->read(8); // 127: Payload is a 64-bit unsigned int 122 | $payload_length = bindec(self::sprintB($data)); 123 | } 124 | 125 | // Get masking key. 126 | if ($mask) $masking_key = $this->read(4); 127 | 128 | // Get the actual payload, if any (might not be for e.g. close frames. 129 | if ($payload_length > 0) { 130 | $data = $this->read($payload_length); 131 | 132 | if ($mask) { 133 | // Unmask payload. 134 | $payload = ''; 135 | for ($i = 0; $i < $payload_length; $i++) $payload .= ($data[$i] ^ $masking_key[$i % 4]); 136 | } 137 | else $payload = $data; 138 | } 139 | 140 | if ($opcode === 'close') { 141 | // Get the close status. 142 | if ($payload_length >= 2) { 143 | $status_bin = $payload[0] . $payload[1]; 144 | $status = bindec(sprintf("%08b%08b", ord($payload[0]), ord($payload[1]))); 145 | $this->close_status = $status; 146 | $payload = substr($payload, 2); 147 | } 148 | 149 | if ($this->is_closing) $this->is_closing = false; // A close response, all done. 150 | else $this->send($status_bin . 'Close acknowledged: ' . $status, 'close', true); // Respond. 151 | 152 | // And close the socket. 153 | fclose($this->socket); 154 | $this->is_connected = false; 155 | } 156 | 157 | return $payload; 158 | } 159 | 160 | /** 161 | * Tell the socket to close. 162 | * 163 | * @param integer $status http://tools.ietf.org/html/rfc6455#section-7.4 164 | * @param string $message A closing message, max 125 bytes. 165 | */ 166 | public function close($status = 1000, $message = 'ttfn') { 167 | $status_binstr = sprintf('%016b', $status); 168 | $status_str = ''; 169 | foreach (str_split($status_binstr, 8) as $binstr) $status_str .= chr(bindec($binstr)); 170 | $this->send($status_str . $message, 'close', true); 171 | 172 | $this->is_closing = true; 173 | $response = $this->receive(); // Receiving a close frame will close the socket now. 174 | 175 | return $response; 176 | } 177 | 178 | protected function write($data) { 179 | $written = fwrite($this->socket, $data); 180 | 181 | if ($written < strlen($data)) { 182 | throw new ConnectionException( 183 | "Could only write $written out of " . strlen($data) . " bytes." 184 | ); 185 | } 186 | } 187 | 188 | protected function read($length) { 189 | $data = ''; 190 | while (strlen($data) < $length) { 191 | $buffer = fread($this->socket, $length - strlen($data)); 192 | if ($buffer === false) { 193 | $metadata = stream_get_meta_data($this->socket); 194 | throw new ConnectionException( 195 | 'Broken frame, read ' . strlen($payload_data) . ' of stated ' 196 | . $payload_length . ' bytes. Stream state: ' 197 | . json_encode($metadata) 198 | ); 199 | } 200 | if ($buffer === '') { 201 | $metadata = stream_get_meta_data($this->socket); 202 | throw new ConnectionException( 203 | 'Empty read; connection dead? Stream state: ' . json_encode($metadata) 204 | ); 205 | } 206 | $data .= $buffer; 207 | } 208 | return $data; 209 | } 210 | 211 | 212 | /** 213 | * Helper to convert a binary to a string of '0' and '1'. 214 | */ 215 | protected static function sprintB($string) { 216 | $return = ''; 217 | for ($i = 0; $i < strlen($string); $i++) $return .= sprintf("%08b", ord($string[$i])); 218 | return $return; 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/lib/Client.php: -------------------------------------------------------------------------------- 1 | options = $options; 17 | 18 | if (!array_key_exists('timeout', $this->options)) $this->options['timeout'] = 5; 19 | 20 | $this->socket_uri = $uri; 21 | } 22 | 23 | public function __destruct() { 24 | if ($this->socket) { 25 | if (get_resource_type($this->socket) === 'stream') fclose($this->socket); 26 | $this->socket = null; 27 | } 28 | } 29 | 30 | /** 31 | * Perform WebSocket handshake 32 | */ 33 | protected function connect() { 34 | $url_parts = parse_url($this->socket_uri); 35 | $scheme = $url_parts['scheme']; 36 | $host = $url_parts['host']; 37 | $user = isset($url_parts['user']) ? $url_parts['user'] : ''; 38 | $pass = isset($url_parts['pass']) ? $url_parts['pass'] : ''; 39 | $port = isset($url_parts['port']) ? $url_parts['port'] : ($scheme === 'wss' ? 443 : 80); 40 | $path = isset($url_parts['path']) ? $url_parts['path'] : '/'; 41 | $query = isset($url_parts['query']) ? $url_parts['query'] : ''; 42 | $fragment = isset($url_parts['fragment']) ? $url_parts['fragment'] : ''; 43 | 44 | $path_with_query = $path; 45 | if (!empty($query)) $path_with_query .= '?' . $query; 46 | if (!empty($fragment)) $path_with_query .= '#' . $fragment; 47 | 48 | if (!in_array($scheme, array('ws', 'wss'))) { 49 | throw new BadUriException( 50 | "Url should have scheme ws or wss, not '$scheme' from URI '$this->socket_uri' ." 51 | ); 52 | } 53 | 54 | $host_uri = ($scheme === 'wss' ? 'ssl' : 'tcp') . '://' . $host; 55 | 56 | // Open the socket. @ is there to supress warning that we will catch in check below instead. 57 | $this->socket = @fsockopen($host_uri, $port, $errno, $errstr, $this->options['timeout']); 58 | 59 | if ($this->socket === false) { 60 | throw new ConnectionException( 61 | "Could not open socket to \"$host:$port\": $errstr ($errno)." 62 | ); 63 | } 64 | 65 | // Set timeout on the stream as well. 66 | stream_set_timeout($this->socket, $this->options['timeout']); 67 | 68 | // Generate the WebSocket key. 69 | $key = self::generateKey(); 70 | 71 | // Default headers (using lowercase for simpler array_merge below). 72 | $headers = array( 73 | 'host' => $host . ":" . $port, 74 | 'user-agent' => 'websocket-client-php', 75 | 'connection' => 'Upgrade', 76 | 'upgrade' => 'websocket', 77 | 'sec-websocket-key' => $key, 78 | 'sec-websocket-version' => '13', 79 | ); 80 | 81 | // Handle basic authentication. 82 | if ($user || $pass) { 83 | $headers['authorization'] = 'Basic ' . base64_encode($user . ':' . $pass) . "\r\n"; 84 | } 85 | 86 | // Deprecated way of adding origin (use headers instead). 87 | if (isset($this->options['origin'])) $headers['origin'] = $this->options['origin']; 88 | 89 | // Add and override with headers from options. 90 | if (isset($this->options['headers'])) { 91 | $headers = array_merge($headers, array_change_key_case($this->options['headers'])); 92 | } 93 | 94 | $header = 95 | "GET " . $path_with_query . " HTTP/1.1\r\n" 96 | . implode( 97 | "\r\n", array_map( 98 | function($key, $value) { return "$key: $value"; }, array_keys($headers), $headers 99 | ) 100 | ) 101 | . "\r\n\r\n"; 102 | 103 | // Send headers. 104 | $this->write($header); 105 | 106 | // Get server response. 107 | $response = ''; 108 | do { 109 | $buffer = stream_get_line($this->socket, 1024, "\r\n"); 110 | $response .= $buffer . "\n"; 111 | $metadata = stream_get_meta_data($this->socket); 112 | } while (!feof($this->socket) && $metadata['unread_bytes'] > 0); 113 | 114 | /// @todo Handle version switching 115 | 116 | // Validate response. 117 | if (!preg_match('#Sec-WebSocket-Accept:\s(.*)$#mUi', $response, $matches)) { 118 | $address = $scheme . '://' . $host . $path_with_query; 119 | throw new ConnectionException( 120 | "Connection to '{$address}' failed: Server sent invalid upgrade response:\n" 121 | . $response 122 | ); 123 | } 124 | 125 | $keyAccept = trim($matches[1]); 126 | $expectedResonse 127 | = base64_encode(pack('H*', sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); 128 | 129 | if ($keyAccept !== $expectedResonse) { 130 | throw new ConnectionException('Server sent bad upgrade response.'); 131 | } 132 | 133 | $this->is_connected = true; 134 | } 135 | 136 | /** 137 | * Generate a random string for WebSocket key. 138 | * @return string Random string 139 | */ 140 | protected static function generateKey() { 141 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"$&/()=[]{}0123456789'; 142 | $key = ''; 143 | $chars_length = strlen($chars); 144 | for ($i = 0; $i < 16; $i++) $key .= $chars[mt_rand(0, $chars_length-1)]; 145 | return base64_encode($key); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/lib/ConnectionException.php: -------------------------------------------------------------------------------- 1 | port = isset($options['port']) ? $options['port'] : 8000; 19 | $this->options = $options; 20 | 21 | do { 22 | $this->listening = @stream_socket_server("tcp://0.0.0.0:$this->port", $errno, $errstr); 23 | } while ($this->listening === false && $this->port++ < 10000); 24 | 25 | if (!$this->listening) { 26 | throw new ConnectionException("Could not open listening socket."); 27 | } 28 | } 29 | 30 | public function getPort() { return $this->port; } 31 | public function getPath() { return $this->request_path; } 32 | public function getRequest() { return $this->request; } 33 | 34 | public function getHeader($header) { 35 | foreach ($this->request as $row) { 36 | if (stripos($row, $header) !== false) { 37 | list($headername, $headervalue) = explode(":", $row); 38 | return trim($headervalue); 39 | } 40 | } 41 | return null; 42 | } 43 | 44 | public function accept() { 45 | $this->socket = stream_socket_accept($this->listening); 46 | 47 | if (array_key_exists('timeout', $this->options)) { 48 | stream_set_timeout($this->socket, $this->options['timeout']); 49 | } 50 | 51 | $this->performHandshake(); 52 | 53 | return $this->socket; 54 | } 55 | 56 | protected function performHandshake() { 57 | $request = ''; 58 | do { 59 | $buffer = stream_get_line($this->socket, 1024, "\r\n"); 60 | $request .= $buffer . "\n"; 61 | $metadata = stream_get_meta_data($this->socket); 62 | } while (!feof($this->socket) && $metadata['unread_bytes'] > 0); 63 | 64 | if (!preg_match('/GET (.*) HTTP\//mUi', $request, $matches)) { 65 | throw new ConnectionException("No GET in request:\n" . $request); 66 | } 67 | $get_uri = trim($matches[1]); 68 | $uri_parts = parse_url($get_uri); 69 | 70 | $this->request = explode("\n", $request); 71 | $this->request_path = $uri_parts['path']; 72 | /// @todo Get query and fragment as well. 73 | 74 | if (!preg_match('#Sec-WebSocket-Key:\s(.*)$#mUi', $request, $matches)) { 75 | throw new ConnectionException("Client had no Key in upgrade request:\n" . $request); 76 | } 77 | 78 | $key = trim($matches[1]); 79 | 80 | /// @todo Validate key length and base 64... 81 | $response_key = base64_encode(pack('H*', sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); 82 | 83 | $header = "HTTP/1.1 101 Switching Protocols\r\n" 84 | . "Upgrade: websocket\r\n" 85 | . "Connection: Upgrade\r\n" 86 | . "Sec-WebSocket-Accept: $response_key\r\n" 87 | . "\r\n"; 88 | 89 | $this->write($header); 90 | $this->is_connected = true; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 7 | cacheTokens="false" 8 | colors="true" 9 | convertErrorsToExceptions="true" 10 | convertNoticesToExceptions="true" 11 | convertWarningsToExceptions="true" 12 | forceCoversAnnotation="false" 13 | mapTestClassNameToCoveredClassName="false" 14 | processIsolation="false" 15 | stopOnError="true" 16 | stopOnFailure="true" 17 | stopOnIncomplete="false" 18 | stopOnSkipped="false" 19 | strict="true" 20 | verbose="true"> 21 | 22 | 23 | tests/unit 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | lib/Server.php 35 | 36 | 37 | 38 | lib/Server.php 39 | 40 | lib/ 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /vendor/textalk/websocket/tests/unit/ClientTest.php: -------------------------------------------------------------------------------- 1 | %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile)); 14 | 15 | usleep(500000); 16 | self::$port = trim(file_get_contents($outputfile)); 17 | 18 | echo "Server started with port: ", self::$port, "\n"; 19 | } 20 | 21 | public static function tearDownAfterClass() { 22 | $ws = new Client('ws://localhost:' . self::$port); 23 | $ws->send('exit'); 24 | } 25 | 26 | public function setup() { 27 | // Setup server side coverage catching 28 | $this->test_id = rand(); 29 | } 30 | 31 | protected function getCodeCoverage() { 32 | $files = glob(dirname(dirname(dirname(__FILE__))) . '/build/tmp/' . $this->test_id . '.*'); 33 | 34 | if (count($files) > 1) { 35 | echo "We have more than one coverage file...\n"; 36 | } 37 | 38 | foreach ($files as $file) { 39 | $buffer = file_get_contents($file); 40 | $coverage_data = unserialize($buffer); 41 | } 42 | 43 | if (!isset($coverage_data)) return array(); 44 | 45 | return $coverage_data; 46 | } 47 | 48 | public function run(PHPUnit_Framework_TestResult $result = NULL) { 49 | if ($result === NULL) { 50 | $result = $this->createResult(); 51 | } 52 | 53 | $this->collectCodeCoverageInformation = $result->getCollectCodeCoverageInformation(); 54 | 55 | parent::run($result); 56 | 57 | if ($this->collectCodeCoverageInformation) { 58 | $result->getCodeCoverage()->append( 59 | $this->getCodeCoverage(), $this 60 | ); 61 | } 62 | 63 | return $result; 64 | } 65 | 66 | public function testInstantiation() { 67 | $ws = new Client('ws://localhost:' . self::$port . '/' . $this->test_id); 68 | 69 | $this->assertInstanceOf('WebSocket\Client', $ws); 70 | } 71 | 72 | /** 73 | * @dataProvider dataLengthProvider 74 | */ 75 | public function testEcho($data_length) { 76 | $ws = new Client('ws://localhost:' . self::$port . '/' . $this->test_id); 77 | 78 | $greeting = ''; 79 | for ($i = 0; $i < $data_length; $i++) $greeting .= 'o'; 80 | 81 | $ws->send($greeting); 82 | $response = $ws->receive(); 83 | 84 | $this->assertEquals($greeting, $response); 85 | } 86 | 87 | public function testBasicAuth() { 88 | $user = 'JohnDoe'; 89 | $pass = 'eoDnhoJ'; 90 | 91 | $ws = new Client("ws://$user:$pass@localhost:" . self::$port . '/' . $this->test_id); 92 | 93 | $greeting = 'Howdy'; 94 | $ws->send($greeting); 95 | $response = $ws->receive(); 96 | 97 | // Echo server will prefix basic authed requests. 98 | $this->assertEquals("Basic Sm9obkRvZTplb0RuaG9K - $greeting", $response); 99 | } 100 | 101 | public function dataLengthProvider() { 102 | return array( 103 | array(8), 104 | array(126), 105 | array(127), 106 | array(128), 107 | array(65000), 108 | array(66000), 109 | ); 110 | } 111 | 112 | public function testOrgEchoTwice() { 113 | $ws = new Client('ws://localhost:' . self::$port . '/' . $this->test_id); 114 | 115 | for ($i = 0; $i < 2; $i++) { 116 | $greeting = 'Hello WebSockets ' . $i; 117 | $ws->send($greeting); 118 | $response = $ws->receive(); 119 | $this->assertEquals($greeting, $response); 120 | } 121 | } 122 | 123 | public function testClose() { 124 | // Start a NEW dedicated server for this test 125 | $cmd = 'php examples/echoserver.php'; 126 | $outputfile = 'build/serveroutput_close.txt'; 127 | $pidfile = 'build/server_close.pid'; 128 | exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile)); 129 | 130 | usleep(500000); 131 | $port = trim(file_get_contents($outputfile)); 132 | 133 | $ws = new Client('ws://localhost:' . $port . '/' . $this->test_id); 134 | $ws->send('exit'); 135 | $response = $ws->receive(); 136 | 137 | $this->assertEquals('ttfn', $response); 138 | $this->assertEquals(1000, $ws->getCloseStatus()); 139 | $this->assertFalse($ws->isConnected()); 140 | } 141 | 142 | /** 143 | * @expectedException WebSocket\BadUriException 144 | * @expectedExceptionMessage Url should have scheme ws or wss 145 | */ 146 | public function testBadUrl() { 147 | $ws = new Client('http://echo.websocket.org'); 148 | $ws->send('foo'); 149 | } 150 | 151 | /** 152 | * @expectedException WebSocket\ConnectionException 153 | */ 154 | public function testNonWSSite() { 155 | $ws = new Client('ws://example.org'); 156 | $ws->send('foo'); 157 | } 158 | 159 | public function testSslUrl() { 160 | $ws = new Client('wss://echo.websocket.org'); 161 | 162 | $greeting = 'Hello WebSockets'; 163 | $ws->send($greeting); 164 | $response = $ws->receive(); 165 | $this->assertEquals($greeting, $response); 166 | } 167 | 168 | public function testSslUrlMasked() { 169 | $ws = new Client('wss://echo.websocket.org'); 170 | 171 | $greeting = 'Hello WebSockets'; 172 | $ws->send($greeting, 'text', true); 173 | $response = $ws->receive(); 174 | $this->assertEquals($greeting, $response); 175 | } 176 | 177 | public function testMaskedEcho() { 178 | $ws = new Client('ws://localhost:' . self::$port . '/' . $this->test_id); 179 | 180 | $greeting = 'Hello WebSockets'; 181 | $ws->send($greeting, 'text', true); 182 | $response = $ws->receive(); 183 | $this->assertEquals($greeting, $response); 184 | } 185 | 186 | /** 187 | * @dataProvider timeoutProvider 188 | */ 189 | public function testTimeout($timeout) { 190 | try { 191 | $ws = new Client('ws://example.org:1111', array('timeout' => $timeout)); 192 | $start_time = microtime(true); 193 | $ws->send('foo'); 194 | } 195 | catch (WebSocket\ConnectionException $e) { 196 | $this->assertLessThan($timeout + 0.2, microtime(true) - $start_time); 197 | $this->assertGreaterThan($timeout - 0.2, microtime(true) - $start_time); 198 | } 199 | 200 | if (!isset($e)) $this->fail('Should have timed out and thrown a ConnectionException'); 201 | } 202 | 203 | public function timeoutProvider() { 204 | return array( 205 | array(1), 206 | array(2), 207 | ); 208 | } 209 | 210 | public function testChangeTimeout() { 211 | $timeout = 1; 212 | 213 | try { 214 | $ws = new Client('ws://example.org:1111', array('timeout' => 5)); 215 | $ws->setTimeout($timeout); 216 | $start_time = microtime(true); 217 | $ws->send('foo'); 218 | } 219 | catch (WebSocket\ConnectionException $e) { 220 | $this->assertLessThan($timeout + 0.2, microtime(true) - $start_time); 221 | $this->assertGreaterThan($timeout - 0.2, microtime(true) - $start_time); 222 | } 223 | 224 | if (!isset($e)) $this->fail('Should have timed out and thrown a ConnectionException'); 225 | } 226 | 227 | public function testDefaultHeaders() { 228 | $ws = new Client('ws://localhost:' . self::$port . '/' . $this->test_id); 229 | 230 | $ws->send('Dump headers'); 231 | 232 | $this->assertRegExp( 233 | "/GET \/$this->test_id HTTP\/1.1\r\n" 234 | . "host: localhost:".self::$port."\r\n" 235 | . "user-agent: websocket-client-php\r\n" 236 | . "connection: Upgrade\r\n" 237 | . "upgrade: websocket\r\n" 238 | . "sec-websocket-key: .*\r\n" 239 | . "sec-websocket-version: 13\r\n/", 240 | $ws->receive() 241 | ); 242 | } 243 | 244 | public function testUserAgentOverride() { 245 | $ws = new Client( 246 | 'ws://localhost:' . self::$port . '/' . $this->test_id, 247 | array('headers' => array('User-Agent' => 'Deep thought')) 248 | ); 249 | 250 | $ws->send('Dump headers'); 251 | 252 | $this->assertRegExp( 253 | "/GET \/$this->test_id HTTP\/1.1\r\n" 254 | . "host: localhost:".self::$port."\r\n" 255 | . "user-agent: Deep thought\r\n" 256 | . "connection: Upgrade\r\n" 257 | . "upgrade: websocket\r\n" 258 | . "sec-websocket-key: .*\r\n" 259 | . "sec-websocket-version: 13\r\n/", 260 | $ws->receive() 261 | ); 262 | } 263 | 264 | public function testAddingHeaders() { 265 | $ws = new Client( 266 | 'ws://localhost:' . self::$port . '/' . $this->test_id, 267 | array('headers' => array('X-Cooler-Than-Beeblebrox' => 'Slartibartfast')) 268 | ); 269 | 270 | $ws->send('Dump headers'); 271 | 272 | $this->assertRegExp( 273 | "/GET \/$this->test_id HTTP\/1.1\r\n" 274 | . "host: localhost:".self::$port."\r\n" 275 | . "user-agent: websocket-client-php\r\n" 276 | . "connection: Upgrade\r\n" 277 | . "upgrade: websocket\r\n" 278 | . "sec-websocket-key: .*\r\n" 279 | . "sec-websocket-version: 13\r\n" 280 | . "x-cooler-than-beeblebrox: Slartibartfast\r\n/", 281 | $ws->receive() 282 | ); 283 | } 284 | 285 | /** 286 | * @expectedException WebSocket\BadOpcodeException 287 | * @expectedExceptionMessage Bad opcode 'bad_opcode' 288 | */ 289 | public function testSendBadOpcode() { 290 | $ws = new Client('ws://localhost:' . self::$port); 291 | $ws->send('foo', 'bad_opcode'); 292 | } 293 | } 294 | --------------------------------------------------------------------------------