From c93b90cc54cc44975ba04971c73fc7ec159d88b1 Mon Sep 17 00:00:00 2001 From: Martin Konecny Date: Sat, 26 Jan 2013 20:05:31 -0500 Subject: [PATCH 1/7] prepare for improvements to way pypo communicates with LS --- python_apps/pypo/pypofetch.py | 47 ++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/python_apps/pypo/pypofetch.py b/python_apps/pypo/pypofetch.py index 1448c65da..03c79cfc6 100644 --- a/python_apps/pypo/pypofetch.py +++ b/python_apps/pypo/pypofetch.py @@ -143,6 +143,24 @@ class PypoFetch(Thread): finally: lock.release() + @staticmethod + def telnet_send(logger, lock, commands): + try: + lock.acquire() + + tn = telnetlib.Telnet(LS_HOST, LS_PORT) + for i in commands: + logger.info(i) + tn.write(i) + + tn.write('exit\n') + tn.read_all() + except Exception, e: + logger.error(str(e)) + finally: + lock.release() + + @staticmethod def switch_source(logger, lock, sourcename, status): logger.debug('Switching source: %s to "%s" status', sourcename, status) @@ -159,17 +177,7 @@ class PypoFetch(Thread): else: command += "stop\n" - try: - lock.acquire() - - tn = telnetlib.Telnet(LS_HOST, LS_PORT) - tn.write(command) - tn.write('exit\n') - tn.read_all() - except Exception, e: - logger.error(str(e)) - finally: - lock.release() + PypoFetch.telnet_send(logger, lock, [command]) """ grabs some information that are needed to be set on bootstrap time @@ -184,9 +192,19 @@ class PypoFetch(Thread): self.logger.debug('info:%s', info) for k, v in info['switch_status'].iteritems(): self.switch_source(self.logger, self.telnet_lock, k, v) - self.update_liquidsoap_stream_format(info['stream_label']) - self.update_liquidsoap_station_name(info['station_name']) - self.update_liquidsoap_transition_fade(info['transition_fade']) + #self.update_liquidsoap_stream_format(info['stream_label']) + #self.update_liquidsoap_station_name(info['station_name']) + #self.update_liquidsoap_transition_fade(info['transition_fade']) + + stream_format = info['stream_label'] + station_name = info['station_name'] + fade = info['transition_fade'] + + commands = [] + commands.append(('vars.stream_metadata_type %s\n' % stream_format).encode('utf-8')) + commands.append(('vars.station_name %s\n' % station_name).encode('utf-8')) + commands.append(('vars.default_dj_fade %s\n' % fade).encode('utf-8')) + PypoFetch.telnet_send(self.logger, self.telnet_lock, commands) def restart_liquidsoap(self): @@ -356,6 +374,7 @@ class PypoFetch(Thread): if(status == "true"): self.api_client.notify_liquidsoap_status("OK", stream_id, str(fake_time)) + def update_liquidsoap_stream_format(self, stream_format): # Push stream metadata to liquidsoap # TODO: THIS LIQUIDSOAP STUFF NEEDS TO BE MOVED TO PYPO-PUSH!!! From b389e440019426f5cce94910ca4e5cfb2f578442 Mon Sep 17 00:00:00 2001 From: Martin Konecny Date: Sun, 27 Jan 2013 15:00:56 -0500 Subject: [PATCH 2/7] take liquidsoap by the horns if it misbehaves. --- python_apps/pypo/airtime-liquidsoap-init-d | 6 +++--- .../pypo/liquidsoap_scripts/liquidsoap_prepare_terminate.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python_apps/pypo/airtime-liquidsoap-init-d b/python_apps/pypo/airtime-liquidsoap-init-d index 4180d5c67..7096bc59c 100755 --- a/python_apps/pypo/airtime-liquidsoap-init-d +++ b/python_apps/pypo/airtime-liquidsoap-init-d @@ -28,10 +28,10 @@ start () { stop () { monit unmonitor airtime-liquidsoap >/dev/null 2>&1 - /usr/lib/airtime/airtime_virtualenv/bin/python /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py - + #send term signal after 10 seconds + timeout 10 /usr/lib/airtime/airtime_virtualenv/bin/python /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py # Send TERM after 5 seconds, wait at most 30 seconds. - start-stop-daemon --stop --oknodo --retry 5 --quiet --pidfile $PIDFILE + start-stop-daemon --stop --oknodo --retry=TERM/10/KILL/5 --quiet --pidfile $PIDFILE rm -f $PIDFILE } diff --git a/python_apps/pypo/liquidsoap_scripts/liquidsoap_prepare_terminate.py b/python_apps/pypo/liquidsoap_scripts/liquidsoap_prepare_terminate.py index e1dac82b6..2f632d9c7 100644 --- a/python_apps/pypo/liquidsoap_scripts/liquidsoap_prepare_terminate.py +++ b/python_apps/pypo/liquidsoap_scripts/liquidsoap_prepare_terminate.py @@ -6,14 +6,14 @@ try: config = ConfigObj('/etc/airtime/pypo.cfg') LS_HOST = config['ls_host'] LS_PORT = config['ls_port'] - + tn = telnetlib.Telnet(LS_HOST, LS_PORT) tn.write("master_harbor.stop\n") tn.write("live_dj_harbor.stop\n") tn.write('exit\n') tn.read_all() - + except Exception, e: print('Error loading config file: %s', e) sys.exit() - \ No newline at end of file + From d7358338f0355cda0ba44e8bbf5d2f5258865cd8 Mon Sep 17 00:00:00 2001 From: Martin Konecny Date: Mon, 28 Jan 2013 17:00:16 -0500 Subject: [PATCH 3/7] improved logging in pypo fetch --- python_apps/pypo/pypofetch.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/python_apps/pypo/pypofetch.py b/python_apps/pypo/pypofetch.py index 1448c65da..9a94a4103 100644 --- a/python_apps/pypo/pypofetch.py +++ b/python_apps/pypo/pypofetch.py @@ -135,6 +135,7 @@ class PypoFetch(Thread): try: lock.acquire() tn = telnetlib.Telnet(LS_HOST, LS_PORT) + self.logger.info(command) tn.write(command) tn.write('exit\n') tn.read_all() @@ -330,8 +331,13 @@ class PypoFetch(Thread): # updated. current_time = time.time() boot_up_time_command = "vars.bootup_time " + str(current_time) + "\n" + self.logger.info(boot_up_time_command) tn.write(boot_up_time_command) - tn.write("streams.connection_status\n") + + connection_status = "streams.connection_status\n" + self.logger.info(connection_status) + tn.write(connection_status) + tn.write('exit\n') output = tn.read_all() From 9d8a9faca872b7697437da0811b7664694840c7e Mon Sep 17 00:00:00 2001 From: Martin Konecny Date: Mon, 28 Jan 2013 17:00:35 -0500 Subject: [PATCH 4/7] make code formatting easier on eyes --- .../pypo/liquidsoap_scripts/ls_script.liq | 79 ++++++++++++++++--- 1 file changed, 66 insertions(+), 13 deletions(-) diff --git a/python_apps/pypo/liquidsoap_scripts/ls_script.liq b/python_apps/pypo/liquidsoap_scripts/ls_script.liq index cd01ad453..489d494a3 100644 --- a/python_apps/pypo/liquidsoap_scripts/ls_script.liq +++ b/python_apps/pypo/liquidsoap_scripts/ls_script.liq @@ -195,28 +195,81 @@ def check_dj_client(user,password) = hd == "True" end -def append_dj_inputs(master_harbor_input_port, master_harbor_input_mount_point, dj_harbor_input_port, dj_harbor_input_mount_point, s) = - if master_harbor_input_port != 0 and master_harbor_input_mount_point != "" and dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then - master_dj = mksafe(audio_to_stereo(input.harbor(id="master_harbor", master_harbor_input_mount_point, port=master_harbor_input_port, auth=check_master_dj_client, - max=40., on_connect=master_dj_connect, on_disconnect=master_dj_disconnect))) - dj_live = mksafe(audio_to_stereo(input.harbor(id="live_dj_harbor", dj_harbor_input_mount_point, port=dj_harbor_input_port, auth=check_dj_client, - max=40., on_connect=live_dj_connect, on_disconnect=live_dj_disconnect))) +def append_dj_inputs(master_harbor_input_port, + master_harbor_input_mount_point, + dj_harbor_input_port, + dj_harbor_input_mount_point, + s) = + if master_harbor_input_port != 0 + and master_harbor_input_mount_point != "" + and dj_harbor_input_port != 0 + and dj_harbor_input_mount_point != "" then + + master_dj = mksafe( + audio_to_stereo( + input.harbor(id="master_harbor", + master_harbor_input_mount_point, + port=master_harbor_input_port, + auth=check_master_dj_client, + max=40., + on_connect=master_dj_connect, + on_disconnect=master_dj_disconnect))) + + dj_live = mksafe( + audio_to_stereo( + input.harbor(id="live_dj_harbor", + dj_harbor_input_mount_point, + port=dj_harbor_input_port, + auth=check_dj_client, + max=40., + on_connect=live_dj_connect, + on_disconnect=live_dj_disconnect))) ignore(output.dummy(master_dj, fallible=true)) ignore(output.dummy(dj_live, fallible=true)) - switch(id="master_dj_switch", track_sensitive=false, transitions=[transition, transition, transition], [({!master_dj_enabled},master_dj), ({!live_dj_enabled},dj_live), ({true}, s)]) + + switch(id="master_dj_switch", + track_sensitive=false, + transitions=[transition, transition, transition], + [({!master_dj_enabled},master_dj), + ({!live_dj_enabled},dj_live), + ({true}, s)]) + elsif master_harbor_input_port != 0 and master_harbor_input_mount_point != "" then - master_dj = mksafe(audio_to_stereo(input.harbor(id="master_harbor", master_harbor_input_mount_point, port=master_harbor_input_port, auth=check_master_dj_client, - max=40., on_connect=master_dj_connect, on_disconnect=master_dj_disconnect))) + master_dj = mksafe( + audio_to_stereo( + input.harbor(id="master_harbor", + master_harbor_input_mount_point, + port=master_harbor_input_port, + auth=check_master_dj_client, + max=40., + on_connect=master_dj_connect, + on_disconnect=master_dj_disconnect))) + ignore(output.dummy(master_dj, fallible=true)) - switch(id="master_dj_switch", track_sensitive=false, transitions=[transition, transition], [({!master_dj_enabled},master_dj), ({true}, s)]) + switch(id="master_dj_switch", + track_sensitive=false, + transitions=[transition, transition], + [({!master_dj_enabled},master_dj), ({true}, s)]) + elsif dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then - dj_live = mksafe(audio_to_stereo(input.harbor(id="live_dj_harbor", dj_harbor_input_mount_point, port=dj_harbor_input_port, auth=check_dj_client, - max=40., on_connect=live_dj_connect, on_disconnect=live_dj_disconnect))) + dj_live = mksafe( + audio_to_stereo( + input.harbor(id="live_dj_harbor", + dj_harbor_input_mount_point, + port=dj_harbor_input_port, + auth=check_dj_client, + max=40., + on_connect=live_dj_connect, + on_disconnect=live_dj_disconnect))) ignore(output.dummy(dj_live, fallible=true)) - switch(id="live_dj_switch", track_sensitive=false, transitions=[transition, transition], [({!live_dj_enabled},dj_live), ({true}, s)]) + + switch(id="live_dj_switch", + track_sensitive=false, + transitions=[transition, transition], + [({!live_dj_enabled},dj_live), ({true}, s)]) else s end From db4e6bb94afd6d362254ba570014f085c7ec3589 Mon Sep 17 00:00:00 2001 From: drigato Date: Tue, 29 Jan 2013 10:29:29 -0500 Subject: [PATCH 5/7] CC-4889: API client URL request is not wrapping in try/catch -fixed --- python_apps/api_clients/api_client.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index 517870e45..b28a4ca5a 100644 --- a/python_apps/api_clients/api_client.py +++ b/python_apps/api_clients/api_client.py @@ -73,17 +73,26 @@ class ApcUrl(object): else: return self.base_url class ApiRequest(object): - def __init__(self, name, url): + def __init__(self, name, url, logger=None): self.name = name self.url = url self.__req = None + if logger is None: self.logger = logging + else: self.logger = logger def __call__(self,_post_data=None, **kwargs): # TODO : get rid of god damn urllib and replace everything with # grequests or requests at least final_url = self.url.params(**kwargs).url() if _post_data is not None: _post_data = urllib.urlencode(_post_data) - req = urllib2.Request(final_url, _post_data) - response = urllib2.urlopen(req).read() + try: + req = urllib2.Request(final_url, _post_data) + response = urllib2.urlopen(req).read() + except Exception, e: + self.logger.error('Exception: %s', e) + import traceback + top = traceback.format_exc() + self.logger.error("traceback: %s", top) + response = "" # Ghetto hack for now because we don't the content type we are getting # (Pointless to look at mime since it's not being set correctly always) try: return json.loads(response) From 28c01760dde01dabd84d079d6675fd46f3fd8dcf Mon Sep 17 00:00:00 2001 From: Martin Konecny Date: Tue, 29 Jan 2013 12:17:05 -0500 Subject: [PATCH 6/7] be more gentle to Liquidsoap when sending lots of commands --- python_apps/pypo/pypofetch.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/python_apps/pypo/pypofetch.py b/python_apps/pypo/pypofetch.py index 03c79cfc6..ea602581c 100644 --- a/python_apps/pypo/pypofetch.py +++ b/python_apps/pypo/pypofetch.py @@ -179,6 +179,25 @@ class PypoFetch(Thread): PypoFetch.telnet_send(logger, lock, [command]) + + #TODO: Merge this with switch_source + def switch_source_temp(self, sourcename, status): + self.logger.debug('Switching source: %s to "%s" status', sourcename, status) + command = "streams." + if sourcename == "master_dj": + command += "master_dj_" + elif sourcename == "live_dj": + command += "live_dj_" + elif sourcename == "scheduled_play": + command += "scheduled_play_" + + if status == "on": + command += "start\n" + else: + command += "stop\n" + + return command + """ grabs some information that are needed to be set on bootstrap time and configures them @@ -190,17 +209,14 @@ class PypoFetch(Thread): self.logger.error('Unable to get bootstrap info.. Exiting pypo...') else: self.logger.debug('info:%s', info) + commands = [] for k, v in info['switch_status'].iteritems(): - self.switch_source(self.logger, self.telnet_lock, k, v) - #self.update_liquidsoap_stream_format(info['stream_label']) - #self.update_liquidsoap_station_name(info['station_name']) - #self.update_liquidsoap_transition_fade(info['transition_fade']) + commands.append(self.switch_source_temp(k, v)) stream_format = info['stream_label'] station_name = info['station_name'] fade = info['transition_fade'] - commands = [] commands.append(('vars.stream_metadata_type %s\n' % stream_format).encode('utf-8')) commands.append(('vars.station_name %s\n' % station_name).encode('utf-8')) commands.append(('vars.default_dj_fade %s\n' % fade).encode('utf-8')) From b15c4569ebe90949fd55da5e1a7db5eea5ce1b41 Mon Sep 17 00:00:00 2001 From: Martin Konecny Date: Tue, 29 Jan 2013 15:17:29 -0500 Subject: [PATCH 7/7] CC-4894: Need to filter output for potential XSS exploits -fixed few areas --- .../application/controllers/LibraryController.php | 9 +++++++++ airtime_mvc/application/controllers/UserController.php | 2 +- airtime_mvc/application/layouts/scripts/layout.phtml | 2 +- airtime_mvc/application/models/ShowBuilder.php | 2 +- airtime_mvc/application/models/User.php | 2 ++ .../application/views/scripts/form/edit-user.phtml | 4 ++-- .../views/scripts/form/preferences_watched_dirs.phtml | 4 ++-- .../application/views/scripts/playlist/playlist.phtml | 2 +- .../public/js/airtime/preferences/streamsetting.js | 2 +- 9 files changed, 20 insertions(+), 9 deletions(-) diff --git a/airtime_mvc/application/controllers/LibraryController.php b/airtime_mvc/application/controllers/LibraryController.php index 2b38349dd..1e3ac996a 100644 --- a/airtime_mvc/application/controllers/LibraryController.php +++ b/airtime_mvc/application/controllers/LibraryController.php @@ -385,6 +385,15 @@ class LibraryController extends Zend_Controller_Action //TODO move this to the datatables row callback. foreach ($r["aaData"] as &$data) { + foreach ($data as $k => &$v) { + if ($k != "image" && $k != "checkbox") { + $v = htmlspecialchars($v); + } + } + //TODO: Replace the above foreach loop with the line below when ticket + //CC-4896 is completed. + //$data = array_map('htmlspecialchars', $data); + if ($data['ftype'] == 'audioclip') { $file = Application_Model_StoredFile::Recall($data['id']); $scid = $file->getSoundCloudId(); diff --git a/airtime_mvc/application/controllers/UserController.php b/airtime_mvc/application/controllers/UserController.php index 395156f97..3faa1477f 100644 --- a/airtime_mvc/application/controllers/UserController.php +++ b/airtime_mvc/application/controllers/UserController.php @@ -115,7 +115,7 @@ class UserController extends Zend_Controller_Action $post = $this->getRequest()->getPost(); $users = Application_Model_User::getUsersDataTablesInfo($post); - die(json_encode($users)); + $this->_helper->json->sendJson($users); } public function getUserDataAction() diff --git a/airtime_mvc/application/layouts/scripts/layout.phtml b/airtime_mvc/application/layouts/scripts/layout.phtml index 29d04c0d6..dedda7c88 100644 --- a/airtime_mvc/application/layouts/scripts/layout.phtml +++ b/airtime_mvc/application/layouts/scripts/layout.phtml @@ -24,7 +24,7 @@ diff --git a/airtime_mvc/application/models/ShowBuilder.php b/airtime_mvc/application/models/ShowBuilder.php index a1ef7c588..72a5f6ab0 100644 --- a/airtime_mvc/application/models/ShowBuilder.php +++ b/airtime_mvc/application/models/ShowBuilder.php @@ -227,7 +227,7 @@ class Application_Model_ShowBuilder $row["endDate"] = $showEndDT->format("Y-m-d"); $row["endTime"] = $showEndDT->format("H:i"); $row["duration"] = floatval($showEndDT->format("U.u")) - floatval($showStartDT->format("U.u")); - $row["title"] = $p_item["show_name"]; + $row["title"] = htmlspecialchars($p_item["show_name"]); $row["instance"] = intval($p_item["si_id"]); $row["image"] = ''; diff --git a/airtime_mvc/application/models/User.php b/airtime_mvc/application/models/User.php index 63b82820a..97c9ca3ad 100644 --- a/airtime_mvc/application/models/User.php +++ b/airtime_mvc/application/models/User.php @@ -335,6 +335,8 @@ class Application_Model_User } else { $record['delete'] = ""; } + + $record = array_map('htmlspecialchars', $record); } return $res; diff --git a/airtime_mvc/application/views/scripts/form/edit-user.phtml b/airtime_mvc/application/views/scripts/form/edit-user.phtml index cd4b70bd9..79a0081fc 100644 --- a/airtime_mvc/application/views/scripts/form/edit-user.phtml +++ b/airtime_mvc/application/views/scripts/form/edit-user.phtml @@ -1,4 +1,4 @@ -

currentUser) ?>

+

escape($this->currentUser)) ?>

@@ -160,4 +160,4 @@
-
\ No newline at end of file + diff --git a/airtime_mvc/application/views/scripts/form/preferences_watched_dirs.phtml b/airtime_mvc/application/views/scripts/form/preferences_watched_dirs.phtml index 4889892dd..ad8e77797 100644 --- a/airtime_mvc/application/views/scripts/form/preferences_watched_dirs.phtml +++ b/airtime_mvc/application/views/scripts/form/preferences_watched_dirs.phtml @@ -11,7 +11,7 @@ element->getElement('storageFolder')->hasErrors()) : ?>
    element->getElement('storageFolder')->getMessages() as $error): ?> -
  • +
  • escape($error); ?>
@@ -29,7 +29,7 @@ element->getElement('watchedFolder')->hasErrors()) : ?>
    element->getElement('watchedFolder')->getMessages() as $error): ?> -
  • +
  • escape($error); ?>
diff --git a/airtime_mvc/application/views/scripts/playlist/playlist.phtml b/airtime_mvc/application/views/scripts/playlist/playlist.phtml index f8496d926..a516f2746 100644 --- a/airtime_mvc/application/views/scripts/playlist/playlist.phtml +++ b/airtime_mvc/application/views/scripts/playlist/playlist.phtml @@ -39,7 +39,7 @@ if (isset($this->obj)) { diff --git a/airtime_mvc/public/js/airtime/preferences/streamsetting.js b/airtime_mvc/public/js/airtime/preferences/streamsetting.js index 54bb986ca..6e76b693c 100644 --- a/airtime_mvc/public/js/airtime/preferences/streamsetting.js +++ b/airtime_mvc/public/js/airtime/preferences/streamsetting.js @@ -28,7 +28,7 @@ function rebuildStreamURL(ele){ }else{ streamurl = "http://"+host+":"+port+"/" } - div.find("#stream_url").html(streamurl) + div.find("#stream_url").text(streamurl) } function restrictOggBitrate(ele, on){ var div = ele.closest("div")