# HG changeset patch # User om # Date 1386596681 -3600 # Node ID 3f564e1673bb5a88e0c9b93cd85024c4d45e5689 # Parent a4c4b0f64b3f7a2809dd1ad2b94a55a3a0d67695 added notifcation and password callback url diff -r a4c4b0f64b3f -r 3f564e1673bb OpenSecurity/bin/credentials.py --- a/OpenSecurity/bin/credentials.py Mon Dec 09 11:52:43 2013 +0100 +++ b/OpenSecurity/bin/credentials.py Mon Dec 09 14:44:41 2013 +0100 @@ -107,7 +107,7 @@ # text ... lyText = QtGui.QGridLayout() - lyContent.addLayout(lyText) + lyContent.addLayout(lyText, 1) self.lbText = QtGui.QLabel() lyText.addWidget(self.lbText, 0, 0, 1, 2) diff -r a4c4b0f64b3f -r 3f564e1673bb OpenSecurity/bin/notification.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/bin/notification.py Mon Dec 09 14:44:41 2013 +0100 @@ -0,0 +1,151 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# notification-dialog +# +# show the user an opensecurity specific message box +# +# Autor: Oliver Maurhart, +# +# Copyright (C) 2013 AIT Austrian Institute of Technology +# AIT Austrian Institute of Technology GmbH +# Donau-City-Strasse 1 | 1220 Vienna | Austria +# http://www.ait.ac.at +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation version 2. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# ------------------------------------------------------------ + + +# ------------------------------------------------------------ +# imports + +import sys + +from PyQt4 import QtCore +from PyQt4 import QtGui + +# local +from about import About + + +# ------------------------------------------------------------ +# code + +class Notification(QtGui.QDialog): + + """Show the user an OpenSecurity specific notification.""" + + TYPES = ['information', 'warning', 'critical'] + + def __init__(self, msgtype, text, parent = None, flags = QtCore.Qt.WindowFlags(0)): + + # super call and widget init + super(Notification, self).__init__(parent, flags) + self.setWindowTitle('OpenSecuirty Notification') + self.setup_ui(msgtype) + + # positionate ourself central + screen = QtGui.QDesktopWidget().screenGeometry() + self.resize(self.geometry().width() * 1.25, self.geometry().height()) + size = self.geometry() + self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2) + + # fix up text + if msgtype in Notification.TYPES: + + typetext = { + 'information': 'OpenSecurity information', + 'warning': 'OpenSecurity warning', + 'critical': 'OpenSecurity critical error' + } + self.lbMsgType.setText(typetext[msgtype]) + + captiontext = { + 'information': 'OpenSecurity: Information', + 'warning': 'OpenSecurity: Warning', + 'critical': 'OpenSecurity: Critical' + } + self.setWindowTitle(captiontext[msgtype]) + + else: + raise ValueError('unknown msgtype') + + self.lbText.setText(text) + + + def clicked_about(self): + """clicked the about button""" + dlgAbout = About() + dlgAbout.exec_() + + + def clicked_ok(self): + """clicked the ok button""" + self.accept() + + + def setup_ui(self, msgtype): + + """Create the widgets.""" + + lyMain = QtGui.QVBoxLayout(self) + lyMain.setContentsMargins(8, 8, 8, 8) + + # content area: left pixmap, right text + lyContent = QtGui.QHBoxLayout() + lyMain.addLayout(lyContent) + + # pixmap + lbPix = QtGui.QLabel() + lbPix.setPixmap(QtGui.QPixmapCache.find('opensecurity_icon_64')) + lyContent.addWidget(lbPix, 0, QtCore.Qt.Alignment(QtCore.Qt.AlignTop + QtCore.Qt.AlignHCenter)) + lyContent.addSpacing(16) + + # text ... + lyText = QtGui.QVBoxLayout() + lyContent.addLayout(lyText, 1) + + self.lbMsgType = QtGui.QLabel() + lyText.addWidget(self.lbMsgType) + self.lbText = QtGui.QLabel() + lyText.addWidget(self.lbText) + lyText.addStretch(1) + + lyMain.addStretch(1) + + # buttons + lyButton = QtGui.QHBoxLayout() + lyMain.addLayout(lyButton) + + lyButton.addStretch(1) + btnOk = QtGui.QPushButton('&Ok', self) + btnOk.setDefault(True) + btnOk.setMinimumWidth(100) + lyButton.addWidget(btnOk) + btnAbout = QtGui.QPushButton('&About', self) + btnAbout.setMinimumWidth(100) + lyButton.addWidget(btnAbout) + + button_width = max(btnOk.width(), btnAbout.width()) + btnOk.setMinimumWidth(button_width) + btnAbout.setMinimumWidth(button_width) + + # reduce to the max + self.resize(lyMain.minimumSize()) + + # connectors + btnOk.clicked.connect(self.clicked_ok) + btnAbout.clicked.connect(self.clicked_about) diff -r a4c4b0f64b3f -r 3f564e1673bb OpenSecurity/bin/opensecurity_client_restful_server.py --- a/OpenSecurity/bin/opensecurity_client_restful_server.py Mon Dec 09 11:52:43 2013 +0100 +++ b/OpenSecurity/bin/opensecurity_client_restful_server.py Mon Dec 09 14:44:41 2013 +0100 @@ -36,10 +36,13 @@ import os.path import subprocess import sys +import urllib +import urllib2 import web # local from environment import Environment +from notification import Notification import opensecurity_server @@ -54,6 +57,7 @@ opensecurity_urls = ( '/application', 'os_application', '/credentials', 'os_credentials', + '/notification', 'os_notification', '/password', 'os_password', '/', 'os_root' ) @@ -78,11 +82,11 @@ # we _need_ a vm if not "vm" in args: - raise web.badrequest() + raise web.badrequest('no vm given') # we _need_ a app if not "app" in args: - raise web.badrequest() + raise web.badrequest('no app given') apps = opensecurity_server.query_apps() vms = opensecurity_server.query_vms() @@ -125,13 +129,13 @@ # pick the arguments args = web.input() - # we _need_ a device id + # we _need_ a text if not "text" in args: - raise web.badrequest() + raise web.badrequest('no text given') # invoke the user dialog as a subprocess - dlg_credentials_image = os.path.join(sys.path[0], 'opensecurity_dialog.py') - process_command = [sys.executable, dlg_credentials_image, 'credentials', args.text] + dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py') + process_command = [sys.executable, dlg_image, 'credentials', args.text] process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE) result = process.communicate()[0] if process.returncode != 0: @@ -140,6 +144,36 @@ return result +class os_notification: + """OpenSecurity '/notification' handler. + + This is called on GET /notification?msgtype=TYPE&text=TEXT. + This will pop up an OpenSecurity notifcation window + """ + + def GET(self): + + # pick the arguments + args = web.input() + + # we _need_ a type + if not "msgtype" in args: + raise web.badrequest('no msgtype given') + + if not args.msgtype in Notification.TYPES: + raise web.badrequest('Unknown value for msgtype') + + # we _need_ a text + if not "text" in args: + raise web.badrequest('no text given') + + # invoke the user dialog as a subprocess + dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py') + process_command = [sys.executable, dlg_image, 'notification-' + args.msgtype, args.text] + process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE) + return "Ok" + + class os_password: """OpenSecurity '/password' handler. @@ -153,19 +187,45 @@ # pick the arguments args = web.input() - # we _need_ a device id + # we _need_ a text if not "text" in args: - raise web.badrequest() + raise web.badrequest('no text given') + # remember remote ip + remote_ip = web.ctx.environ['REMOTE_ADDR'] + # invoke the user dialog as a subprocess - dlg_credentials_image = os.path.join(sys.path[0], 'opensecurity_dialog.py') - process_command = [sys.executable, dlg_credentials_image, 'password', args.text] + dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py') + process_command = [sys.executable, dlg_image, 'password', args.text] process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE) result = process.communicate()[0] if process.returncode != 0: return 'password request has been aborted.' - return result + # all ok, tell send request back appropriate destination + + # the returned value of the dialog is a jason object like + # "{ 'password': 'THE_PASSWORD' }" + # so we _could_ call eval(...) on this. + # + # However, anyone malicious enough _could_ encode a certain + # "password" making some nasty things within that eval code. :( + # + # So this is plain old-school string hacking then ... + try: + password = result.split(':')[1].split("'")[1] + except: + raise web.internalerror('error in password parsing') + + url_addr = 'http://' + remote_ip + ':58080/password' + url_data = urllib.urlencode({ 'password': password}) + req = urllib2.Request(url = url_addr + '?' + url_data) + try: + res = urllib2.urlopen(req) + except: + raise web.internalerror('failed to contact: ' + url_addr) + + return 'password told' class os_root: diff -r a4c4b0f64b3f -r 3f564e1673bb OpenSecurity/bin/opensecurity_dialog.py --- a/OpenSecurity/bin/opensecurity_dialog.py Mon Dec 09 11:52:43 2013 +0100 +++ b/OpenSecurity/bin/opensecurity_dialog.py Mon Dec 09 14:44:41 2013 +0100 @@ -42,6 +42,7 @@ # local from credentials import Credentials from environment import Environment +from notification import Notification from password import Password @@ -53,7 +54,7 @@ # parse command line parser = argparse.ArgumentParser(description = 'OpenSecurity Dialog.') - parser.add_argument('mode', metavar='MODE', help='dialog mode: \'password\' or \'credentials\'') + parser.add_argument('mode', metavar='MODE', help='dialog mode: \'password\', \'credentials\', \'notification-information\', \'notification-warning\' or \'notification-critical\'') parser.add_argument('text', metavar='TEXT', help='text to show') args = parser.parse_args() @@ -75,6 +76,18 @@ if args.mode == 'credentials': dlg = Credentials(args.text) + if args.mode == 'notification-information': + dlg = Notification('information', args.text) + + if args.mode == 'notification-warning': + dlg = Notification('warning', args.text) + + if args.mode == 'notification-critical': + dlg = Notification('critical', args.text) + + if not 'dlg' in locals(): + raise ValueError('unknown mode. type --help for help') + # pop up the dialog dlg.show() app.exec_() diff -r a4c4b0f64b3f -r 3f564e1673bb OpenSecurity/bin/password.py --- a/OpenSecurity/bin/password.py Mon Dec 09 11:52:43 2013 +0100 +++ b/OpenSecurity/bin/password.py Mon Dec 09 14:44:41 2013 +0100 @@ -105,7 +105,7 @@ # text ... lyText = QtGui.QVBoxLayout() - lyContent.addLayout(lyText) + lyContent.addLayout(lyText, 1) self.lbText = QtGui.QLabel() lyText.addWidget(self.lbText) lyPassword = QtGui.QHBoxLayout() diff -r a4c4b0f64b3f -r 3f564e1673bb OpenSecurity/test/get-notification.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/test/get-notification.bat Mon Dec 09 14:44:41 2013 +0100 @@ -0,0 +1,4 @@ +@echo off +..\cygwin\bin\curl --get --data-urlencode "msgtype=information" --data-urlencode "text=Alle Daten wurden vernichtet." http://127.0.0.1:8090/notification +..\cygwin\bin\curl --get --data-urlencode "msgtype=warning" --data-urlencode "text=Christkind in PDF entdeckt." http://127.0.0.1:8090/notification +..\cygwin\bin\curl --get --data-urlencode "msgtype=critical" --data-urlencode "text=Influenza.Win7 im Bootsektor." http://127.0.0.1:8090/notification