# HG changeset patch # User om # Date 1385989325 -3600 # Node ID 65432e6c60427e415bd34d3c60c215007e7703b8 # Parent 446a7ba983099c5eb004becfdb2c870a8cf98eaa initial deployment and project layout commit diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/Readme.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/Readme.md Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,151 @@ +# How To OpenSecurity Demo + +## Installation + +1. Copy the OpenSecurity parent Folder as-is to "C:\Program Files" + +2. Inside this folder you find: + + OpenSecurity/ + ├── client ............... OpenSecurity client code + ├── cygwin ............... A cygwin subsystem used inside OpenSecurity + ├── gfx .................. OpenSecurity images and icons used + ├── install .............. Necessary 3rd party installment + └── server ............... OpenSecuirty server code + +3. Switch into the "install" folder. There you have: + + OpenSecurity/ + └── install/ + ├── OpenSecurity.reg + ├── PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x32.exe + ├── PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x64.exe + ├── python-2.7.6.amd64.msi + ├── python-2.7.6.msi + ├── VirtualBox-4.3.4-91027-Win.exe + └── web.py-0.37 + + Please install the software via double-click: + + * python-2.7.6.msi on 32-Bit + _or_ + python-2.7.6.amd64.msi on 64-Bit + + * PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x32.exe on 32-Bit + _or_ + PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x64.exe on 64-Bit + + * VirtualBox-4.3.4-91027-Win.exe + + If you didn't change any settings you'll have a Win32 Python + installation at C:\Python27 right now. This is important for + the next step. + + 1. Open up a cmd box --> Start / Execute / "cmd" + 2. Switch into the OpenSecurity folder where the web.py resides: + + C:> cd C:\Program Files\OpenSecurity\install\web.py-0.37 + + 3. Install web.py by calling the setup.py with the "install" command + from within a python shell: + + C:\Program Files\OpenSecurity\install\web.py-0.37> C:\Python27\python.exe setup.py install + running install + running build + running build_py + creating build + creating build\lib + creating build\lib\web + copying web\application.py -> build\lib\web + copying web\browser.py -> build\lib\web + copying web\db.py -> build\lib\web + copying web\debugerror.py -> build\lib\web + copying web\form.py -> build\lib\web + ... + +4. Finally update your registry by double-clicking the OpenSecurity.reg file. + +5. To make changes in effect (automatically starting the OpenSecurity client and server daemons) you should restrat the machine. + +NOTE: + Windows will pop up an UAC dialog for X11, OpenSecurity Client Daemon and OpenSecuirty Server Daemon + + +## VirtualBox VM Images + +For the current setup to work you need at least a single Virtual Machine: + +1. Create a Virtual Machine for Debian Linux + --> The machine should be named 'Debian 7' + --> There must be a user called 'user' + +2. Have a Debian 7 (or 7.2) network installation ready and install a fresh new Debian system, with a user called 'user'. + +3. Create 2 (!) Network Interfaces for your Virtual Machine + a) The first will be set to "NAT" --> this will be eth0 + b) The second will be set to "Host-Only Adapter" --> this will be eth1 + +4. Power up the Virtual Machine and set the network interface configuration (/etc/network/interfaces) to: + + auto lo + iface lo + + auto eth0 + allow-hotplug eth0 + iface eth0 inet dhcp + + auto eth1 + iface eth1 inet static + address 192.168.56.101 + netmask 255.255.255.0 + gateway 192.168.56.1 + +5. Create a passwordless SSH connection from within Cygwin into the VM: + + a) ensure the VM is started and you have a user login called 'user'. + b) start a cygwin shell by double-clicking "C:\Program Files\OpenSecurity\cygwin\Cygwin.vbs" + c) generate a ssh-key + + $ ssh-keygen + + --> do not set passphrases, leave all to default + d) copy the public key to the virtual machine + + $ scp ~/.ssh/id_rsa.pub user@192.168.56.101: + + e) add the public key to the list of authorized keys: + + - login into the virtual machine + - open up a terminal + + $ mkdir ~/.ssh &> /dev/null + $ cat id_rsa.pub >> ~/.ssh/authorized_keys + + f) test the passwordless connection by open the cyginw command prompt on the Windows Host again: + + $ ssh user@192.168.56.101 + + --> this should now give you a login shell on the virtual machine without a password request. + + (you can now safely delete the id_rsa.pub file in your virtual machine's home) + + +## Demonstration + +* Start the Virtual Machine + --> You do not have to log in. Just start the machine. If the X11-Login Screen appears, all is done. + +* Start the opensecurity-client by calling + + NOTE: you may omit this step if you double-clicked the OpenSecuirty.reg file previously. + + C:> C:\ + C:> cd "C:\Program Files\OpenSecurity\client" + C:\Program Files\OpenSecurity\client> start "opensecurity_client_restful_server.py 8090" + + +* Open Up a browser and type: + + "http://127.0.0.1:8090" + + HAVE FUN! =D diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/client/about.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/client/about.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,126 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# about-dialog +# +# tell the user about the project +# +# 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 os + +from PyQt4 import QtCore +from PyQt4 import QtGui + +# local +from environment import Environment + +# ------------------------------------------------------------ +# vars + + +ABOUT_TEXT = """ + + + +
+

+ +

+

OpenSecurity

+

+

+

+Blah ...
+ +

+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 +

+ + + + +"""; + + +# ------------------------------------------------------------ +# code + + +class About(QtGui.QDialog): + + """Show some about stuff.""" + + def __init__(self, parent = None, flags = QtCore.Qt.WindowFlags(0)): + + # super call and widget init + super(About, self).__init__(parent, flags) + + # setup image search path + QtCore.QDir.setSearchPaths("image", QtCore.QStringList(os.path.join(Environment('opensecurity').data_path, '..', 'gfx'))); + + self.setWindowTitle('About OpenSecuirty ...') + self.setup_ui() + + + def setup_ui(self): + + """Create the widgets.""" + + lyMain = QtGui.QVBoxLayout(self) + lyMain.setContentsMargins(8, 8, 8, 8) + + lbAbout = QtGui.QLabel() + lbAbout.setStyleSheet("QWidget { background: white; color: black; };") + lbAbout.setText(ABOUT_TEXT) + lbAbout.setContentsMargins(12, 12, 12, 12) + + scAbout = QtGui.QScrollArea() + scAbout.setWidget(lbAbout) + scAbout.viewport().setStyleSheet("QWidget { background: white; color: black; };") + lyMain.addWidget(scAbout) + + # buttons + lyButton = QtGui.QHBoxLayout() + lyMain.addLayout(lyButton) + + lyButton.addStretch(1) + btnOk = QtGui.QPushButton('&Ok', self) + btnOk.setMinimumWidth(100) + lyButton.addWidget(btnOk) + + # connectors + btnOk.clicked.connect(self.accept) + + # reduce to the max + self.setMinimumSize(400, 200) + self.resize(lyMain.minimumSize()) + diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/client/credentials.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/client/credentials.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,160 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# credentials-dialog +# +# ask the user credentials +# +# 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 Credentials(QtGui.QDialog): + + """Ask the user for credentials.""" + + def __init__(self, text, parent = None, flags = QtCore.Qt.WindowFlags(0)): + + super(Credentials, self).__init__(parent, flags) + self.setWindowTitle('OpenSecuirty Credentials Request') + self.setup_ui() + + # 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 + self.lbText.setText(text) + + + def clicked_about(self): + """clicked the about button""" + dlgAbout = About() + dlgAbout.exec_() + + + def clicked_cancel(self): + """clicked the cancel button""" + self.reject() + + + def clicked_ok(self): + """clicked the ok button""" + sys.stdout.write('{ ') + sys.stdout.write('\'user\': \'') + sys.stdout.write(self.edUser.text()) + sys.stdout.write('\', ') + sys.stdout.write('\'password\': \'') + sys.stdout.write(self.edPassword.text()) + sys.stdout.write('\' ') + sys.stdout.write('}\n') + self.accept() + + + def setup_ui(self): + + """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.QGridLayout() + lyContent.addLayout(lyText) + self.lbText = QtGui.QLabel() + lyText.addWidget(self.lbText, 0, 0, 1, 2) + + lbUser = QtGui.QLabel('&User:') + lyText.addWidget(lbUser, 1, 0) + self.edUser = QtGui.QLineEdit() + lyText.addWidget(self.edUser, 1, 1) + lbUser.setBuddy(self.edUser) + + lbPassword = QtGui.QLabel('&Password:') + lyText.addWidget(lbPassword, 2, 0) + self.edPassword = QtGui.QLineEdit() + self.edPassword.setEchoMode(QtGui.QLineEdit.Password) + lyText.addWidget(self.edPassword, 2, 1) + lbPassword.setBuddy(self.edPassword) + + lyText.addWidget(QtGui.QWidget(), 3, 0, 1, 2) + lyText.setColumnStretch(1, 1) + lyText.setRowStretch(3, 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) + btnCancel = QtGui.QPushButton('&Cancel', self) + btnCancel.setMinimumWidth(100) + lyButton.addWidget(btnCancel) + btnAbout = QtGui.QPushButton('&About', self) + btnAbout.setMinimumWidth(100) + lyButton.addWidget(btnAbout) + + button_width = max(btnOk.width(), btnCancel.width(), btnAbout.width()) + btnOk.setMinimumWidth(button_width) + btnCancel.setMinimumWidth(button_width) + btnAbout.setMinimumWidth(button_width) + + # reduce to the max + self.resize(lyMain.minimumSize()) + + # connectors + btnOk.clicked.connect(self.clicked_ok) + btnCancel.clicked.connect(self.clicked_cancel) + btnAbout.clicked.connect(self.clicked_about) diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/client/cygwin.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/client/cygwin.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,105 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# cygwin command +# +# executes a cygwin command inside the opensecurity project +# +# 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 os +import subprocess +import sys + +# local +from environment import Environment + + +# ------------------------------------------------------------ +# code + + +class Cygwin(object): + + """Some nifty methods working with Cygwin""" + + def __call__(self, command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE): + """make an instance of this object act as a function""" + return self.execute(command, stdin, stdout, stderr) + + + @staticmethod + def root(): + """get the path to our local cygwin installment""" + return os.path.join(Environment('OpenSecurity').prefix_path, '..', 'cygwin') + + + def execute(self, command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE): + """execute a cygwin shell command + + command is list of arguments like ['/bin/ls', '-al', '-h'] + + a Popen object is returned""" + command_path = Cygwin.root() + os.sep.join(command[0].split('/')) + command = [command_path] + command[1:] + + return subprocess.Popen(command, shell = False, stdin = stdin, stdout = stdout, stderr = stderr) + + + @staticmethod + def is_X11_running(): + """check if we can connect to a X11 running instance""" + p = Cygwin()(['/bin/bash', '-c', 'DISPLAY=:0 /usr/bin/xset -q']) + stdout, stderr = p.communicate() + return p.returncode == 0 + + + @staticmethod + def start_X11(): + """start X11 in the background (if not already running) on DISPLAY=:0""" + + # do not start if already running + if Cygwin.is_X11_running(): + return + + # launch X11 (forget output and return immediately) + p = Cygwin()(['/bin/bash', '--login', '-i', '-c', ' X :0 -multiwindow'], stdin = None, stdout = None, stderr = None) + + +# start +if __name__ == "__main__": + + # execute what is given on the command line + c = Cygwin() + p = c(sys.argv[1:]) + + # wait until the process finished and grab the output + stdout, stderr = p.communicate() + print('=== call result on stdout: ===\n' + stdout) + print('=== call result on stderr: ===\n' + stderr) + diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/client/environment.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/client/environment.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,103 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# environment.py +# +# pick some current environment infos +# +# 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 os +import os.path +import sys + + +# ------------------------------------------------------------ +# code + + +class Environment(object): + + """Hold some nifty environment stuff in a dedicated class.""" + + def __init__(self, application = None): + + # if we ain't got a path to start from, all is valid/lost + if len(sys.path[0]) == 0: + self._prefix_path = '' + self._data_path = '' + return + + # the prefix path + # + # - on Linux: this is ../../ to the current executable + # e.g. "/usr/bin/myprogram" --> "/usr" + # + # - on Windows (inkl. Cygwin): this is the installation folder + # e.g. "C:/Program Files/MyProgram/myprogam" --> "C:/Program Files/MyProgram" + # + if sys.platform == 'linux2': + self._prefix_path = os.path.split(sys.path[0])[0] + elif sys.platform == 'win32' or sys.platform == 'cygwin': + self._prefix_path = sys.path[0] + + # the data path where all data files are stored + if sys.platform == 'linux2': + if not application is None: + self._data_path = os.path.join(self._prefix_path, os.path.join('share', application)) + else: + self._data_path = os.path.join(self._prefix_path, 'share') + elif sys.platform == 'win32' or sys.platform == 'cygwin': + self._data_path = self._prefix_path + + + def data_path_get(self): + """dat_path get""" + return self._data_path + + data_path = property(data_path_get) + + + def prefix_path_get(self): + """prefix_path get""" + return self._prefix_path + + prefix_path = property(prefix_path_get) + +# test method +def test(): + + """Test: class Environment""" + e = Environment('My Application') + print('prefix_path: "{0}"'.format(e.prefix_path)) + print(' data_path: "{0}"'.format(e.data_path)) + + +# test the module +if __name__ == '__main__': + test() diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/client/launch.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/client/launch.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,287 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# opensecurity-launcher +# +# launches an application inside a VM +# +# 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 argparse +import os +import subprocess +import sys + +from PyQt4 import QtCore +from PyQt4 import QtGui + +# local +from about import About +from cygwin import Cygwin +from environment import Environment +import opensecurity_server + + +# ------------------------------------------------------------ +# code + + +class Chooser(QtGui.QDialog, object): + + """Ask the user what to launch.""" + + def __init__(self, parent = None, flags = QtCore.Qt.WindowFlags(0)): + + super(Chooser, self).__init__(parent, flags) + self.setWindowTitle('OpenSecuirty Launch Application') + self.setup_ui() + + # known vms and applications + self._apps, self_vms = [], [] + + # 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) + + # refresh vm and command input + self.refresh() + + + def app_get(self): + """The application of the user.""" + a = str(self._cbApplication.currentText()) + for app in self._apps: + if a == app['name']: + return app['command'] + return a + + app = property(app_get) + + + def clicked_about(self): + """clicked the about button""" + dlgAbout = About() + dlgAbout.exec_() + + + def clicked_cancel(self): + """clicked the cancel button""" + self.reject() + + + def clicked_ok(self): + """clicked the ok button""" + self.accept() + + + def refresh(self): + """load the known vms and commands and adjust input fields""" + + self._apps = opensecurity_server.query_apps() + self._vms = opensecurity_server.query_vms() + + # add the VMs we know + self._cbApplication.clear() + for app in self._apps: + self._cbApplication.addItem(app['name']) + + # add the commands we know + self._cbVM.clear() + for vm in self._vms: + self._cbVM.addItem(vm['name']) + + + def setup_ui(self): + """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) + + # launch ... + lyLaunch = QtGui.QGridLayout() + lyContent.addLayout(lyLaunch) + lbTitle = QtGui.QLabel('Specify details for application to launch.') + lyLaunch.addWidget(lbTitle, 0, 0, 1, 2) + + lbVM = QtGui.QLabel('&VM-ID:') + lyLaunch.addWidget(lbVM, 1, 0) + self._cbVM = QtGui.QComboBox() + self._cbVM.setEditable(True) + self._cbVM.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically) + lyLaunch.addWidget(self._cbVM, 1, 1) + lbVM.setBuddy(self._cbVM) + + lbApplication = QtGui.QLabel('&Application:') + lyLaunch.addWidget(lbApplication, 2, 0) + self._cbApplication = QtGui.QComboBox() + self._cbApplication.setEditable(True) + self._cbApplication.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically) + lyLaunch.addWidget(self._cbApplication, 2, 1) + lbApplication.setBuddy(self._cbApplication) + + lyLaunch.addWidget(QtGui.QWidget(), 3, 0, 1, 2) + lyLaunch.setColumnStretch(1, 1) + lyLaunch.setRowStretch(3, 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) + btnCancel = QtGui.QPushButton('&Cancel', self) + btnCancel.setMinimumWidth(100) + lyButton.addWidget(btnCancel) + btnAbout = QtGui.QPushButton('&About', self) + btnAbout.setMinimumWidth(100) + lyButton.addWidget(btnAbout) + + button_width = max(btnOk.width(), btnCancel.width(), btnAbout.width()) + btnOk.setMinimumWidth(button_width) + btnCancel.setMinimumWidth(button_width) + btnAbout.setMinimumWidth(button_width) + + # reduce to the max + self.resize(lyMain.minimumSize()) + + # connectors + btnOk.clicked.connect(self.clicked_ok) + btnCancel.clicked.connect(self.clicked_cancel) + btnAbout.clicked.connect(self.clicked_about) + + + def user_get(self): + """The user of the vm of choice.""" + v = str(self._cbVM.currentText()) + for vm in self._vms: + if v == vm['name']: + return vm['user'] + return v + + user = property(user_get) + + + def vm_get(self): + """The vm of choice.""" + v = str(self._cbVM.currentText()) + for vm in self._vms: + if v == vm['name']: + return vm['ip'] + return v + + vm = property(vm_get) + + +def ask_user(): + """ask the user for VM and app to start""" + + # launch Qt + app = QtGui.QApplication(sys.argv) + + # prebuild the pixmap cache: fetch all jpg, png and jpeg images and load them + image_path = os.path.join(Environment("OpenSecurity").data_path, '..', 'gfx') + for file in os.listdir(image_path): + if file.lower().rpartition('.')[2] in ('jpg', 'png', 'jpeg'): + QtGui.QPixmapCache.insert(file.lower().rpartition('.')[0], QtGui.QPixmap(os.path.join(image_path, file))) + + # we should have now our application icon + app.setWindowIcon(QtGui.QIcon(QtGui.QPixmapCache.find('opensecurity_icon_64'))) + + # pop up the dialog + dlg = Chooser() + dlg.show() + app.exec_() + + if dlg.result() == QtGui.QDialog.Accepted: + return dlg.user, dlg.vm, dlg.app + + return '', '', '' + + +def main(): + """entry point""" + + # parse command line + parser = argparse.ArgumentParser(description = 'OpenSecurity Launcher: run application in VM') + parser.add_argument('user', metavar='USER', help='USER on Virtual Machine', nargs='?', type=str, default='') + parser.add_argument('ip', metavar='IP', help='IP of Virtual Machine', nargs='?', type=str, default='') + parser.add_argument('command', metavar='COMMAND', help='Full path of command and arguments to start inside VM', nargs='?', type=str, default='') + args = parser.parse_args() + + # we must have at least all or none set + set_user = args.user != '' + set_ip = args.ip != '' + set_command = args.command != '' + set_ALL = set_user and set_ip and set_command + set_NONE = (not set_user) and (not set_ip) and (not set_command) + if (not set_ALL) and (not set_NONE): + sys.stderr.write("Please specify user, ip and command or none.\n") + sys.stderr.write("Type '--help' for help.\n") + sys.exit(1) + + # check if we need to ask the user + if set_NONE: + args.user, args.ip, args.command = ask_user() + + # still no IP? --> no chance, over and out! + if args.ip == '': + sys.exit(0) + + # ensure we have our X11 running + Cygwin.start_X11() + + # the SSH command + user_at_guest = args.user + '@' + args.ip + ssh = 'DISPLAY=:0 /usr/bin/ssh -Y ' + user_at_guest + ' ' + args.command + print(ssh) + + # off we go! + Cygwin()(['/bin/bash', '--login', '-i', '-c', ssh], None, None, None) + + +# start +if __name__ == "__main__": + main() + diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/client/opensecurity_client_restful_server.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/client/opensecurity_client_restful_server.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,215 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# opensecurity_client_restful_server +# +# the OpenSecurity client RESTful server +# +# 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 os +import os.path +import subprocess +import sys +import web + +# local +from environment import Environment +import opensecurity_server + + +# ------------------------------------------------------------ +# const + + +__version__ = "0.1" + + +"""All the URLs we know mapping to class handler""" +opensecurity_urls = ( + '/application', 'os_application', + '/credentials', 'os_credentials', + '/password', 'os_password', + '/', 'os_root' +) + + +# ------------------------------------------------------------ +# code + + +class os_application: + """OpenSecurity '/application' handler. + + This is called on GET /application?vm=VM-ID&app=APP-ID + This tries to access the vm identified with the label VM-ID + and launched the application identified APP-ID + """ + + def GET(self): + + # pick the arguments + args = web.input() + + # we _need_ a vm + if not "vm" in args: + raise web.badrequest() + + # we _need_ a app + if not "app" in args: + raise web.badrequest() + + apps = opensecurity_server.query_apps() + vms = opensecurity_server.query_vms() + + # check if we do have valid vm + v = [v for v in vms if v['name'] == args.vm] + if len(v) == 0: + raise web.notfound('vm not found') + v = v[0] + + # check if we do have a valid app + a = [a for a in apps if a['name'] == args.app] + if len(a) == 0: + raise web.notfound('app not found') + a = a[0] + + # invoke launch with + res = "starting: launch " + v['user'] + " " + v['ip'] + " " + a['command'] + + launch_image = os.path.join(sys.path[0], 'launch.py') + process_command = [sys.executable, launch_image, v['user'], v['ip'], a['command']] + process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE) + result = process.communicate()[0] + if process.returncode != 0: + return 'Launch of application aborted.' + + return result + + +class os_credentials: + """OpenSecurity '/credentials' handler. + + This is called on GET /credentials?text=TEXT. + Ideally this should pop up a user dialog to insert his + credentials based the given TEXT. + """ + + def GET(self): + + # pick the arguments + args = web.input() + + # we _need_ a device id + if not "text" in args: + raise web.badrequest() + + # 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] + process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE) + result = process.communicate()[0] + if process.returncode != 0: + return 'Credentials request has been aborted.' + + return result + + +class os_password: + """OpenSecurity '/password' handler. + + This is called on GET /password?text=TEXT. + Ideally this should pop up a user dialog to insert his + password based device name. + """ + + def GET(self): + + # pick the arguments + args = web.input() + + # we _need_ a device id + if not "text" in args: + raise web.badrequest() + + # 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] + 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 + + +class os_root: + """OpenSecurity '/' handler""" + + def GET(self): + + res = "OpenSecurity-Client RESTFul Server { \"version\": \"%s\" }" % __version__ + + # add some sample links + res = res + """ + +USAGE EXAMPLES: + +Request a password: + (copy paste this into your browser's address field after the host:port) + + /password?text=Give+me+a+password+for+device+%22My+USB+Drive%22+(ID%3A+32090-AAA-X0) + + (eg.: http://127.0.0.1:8090/password?text=Give+me+a+password+for+device+%22My+USB+Drive%22+(ID%3A+32090-AAA-X0)) + NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window. + + +Request a combination of user and password: + (copy paste this into your browser's address field after the host:port) + + /credentials?text=Tell+the+NSA+which+credentials+to+use+in+order+to+avoid+hacking+noise+on+wire. + + (eg.: http://127.0.0.1:8090/credentials?text=Tell+the+NSA+which+credentials+to+use+in+order+to+avoid+hacking+noise+on+wire.) + NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window. + + +Start a Browser: + (copy paste this into your browser's address field after the host:port) + + /application?vm=Debian+7&app=Browser + + (e.g. http://127.0.0.1:8090/application?vm=Debian+7&app=Browser) + """ + + return res + + +# start +if __name__ == "__main__": + server = web.application(opensecurity_urls, globals()) + server.run() diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/client/opensecurity_dialog.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/client/opensecurity_dialog.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,93 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# opensecurity-dialog +# +# an opensecurity dialog +# +# 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 argparse +import os +import sys + +from PyQt4 import QtCore +from PyQt4 import QtGui + +# local +from credentials import Credentials +from environment import Environment +from password import Password + + +# ------------------------------------------------------------ +# code + + +def main(): + + # parse command line + parser = argparse.ArgumentParser(description = 'OpenSecurity Dialog.') + parser.add_argument('mode', metavar='MODE', help='dialog mode: \'password\' or \'credentials\'') + parser.add_argument('text', metavar='TEXT', help='text to show') + args = parser.parse_args() + + app = QtGui.QApplication(sys.argv) + + # prebuild the pixmap cache: fetch all jpg, png and jpeg images and load them + data_path = Environment("OpenSecurity").data_path + image_path = os.path.join(data_path, '..', 'gfx') + for file in os.listdir(image_path): + if file.lower().rpartition('.')[2] in ('jpg', 'png', 'jpeg'): + QtGui.QPixmapCache.insert(file.lower().rpartition('.')[0], QtGui.QPixmap(os.path.join(image_path, file))) + + # we should have now our application icon + app.setWindowIcon(QtGui.QIcon(QtGui.QPixmapCache.find('opensecurity_icon_64'))) + + if args.mode == 'password': + dlg = Password(args.text) + + if args.mode == 'credentials': + dlg = Credentials(args.text) + + # pop up the dialog + dlg.show() + app.exec_() + + # give proper result code + if dlg.result() == QtGui.QDialog.Accepted: + res = 0 + else: + res = 1 + sys.exit(res) + + +# start +if __name__ == "__main__": + main() + diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/client/opensecurity_server.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/client/opensecurity_server.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,71 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# opensecurity-server +# +# talk to the opensecurity server +# +# 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. +# ------------------------------------------------------------ + +# ------------------------------------------------------------ +# import + +from pprint import PrettyPrinter + + +# ------------------------------------------------------------ +# code + +def query_apps(): + """get the list of known apps""" + + # TODO: REPLACE THIS HARDCODED STUFF WITH REAL CODE TO THE OS SERVER + apps = [ + { 'vm': 'Debian 7', 'name': 'Browser', 'command': '/usr/bin/iceweasel'}, + { 'vm': 'Debian 7', 'name': 'VLC', 'command': '/usr/bin/vlc'} + ] + + return apps + + +def query_vms(): + """get the list of registered vms, their ip and the prefered user""" + + # TODO: REPLACE THIS HARDCODED STUFF WITH REAL CODE TO THE OS SERVER + vms = [ + { 'user': 'user', 'name': 'Debian 7', 'ip': '192.168.56.101'}, + { 'user': 'user', 'name': 'Anit-Virus VM', 'ip': '192.168.56.101'} + ] + + return vms + + +# start +if __name__ == "__main__": + print("known apps: ") + PrettyPrinter().pprint(query_apps()) + print("known vms: ") + PrettyPrinter().pprint(query_vms()) + + diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/client/opensecurity_tray.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/client/opensecurity_tray.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,131 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# opensecurity-dialog +# +# an opensecurity dialog +# +# 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 argparse +import os +import subprocess +import sys + +from PyQt4 import QtCore +from PyQt4 import QtGui + +# local +from about import About +from environment import Environment + + +# ------------------------------------------------------------ +# code + + +class OpenSecurityTrayIcon(QtGui.QSystemTrayIcon): + + """This is the OpenSecuirty Tray Icon""" + + def __init__(self, icon, parent=None): + + super(OpenSecurityTrayIcon, self).__init__(icon, parent) + self.setup_ui() + + + def clicked_about(self): + """clicked about""" + dlgAbout = About() + dlgAbout.exec_() + + + def clicked_exit(self): + """clicked exit""" + sys.exit(0) + + + def clicked_launch_application(self): + """clicked the launch an application""" + dlg_launch_image = os.path.join(sys.path[0], 'launch.pyw') + process_command = [sys.executable, dlg_launch_image] + print(process_command) + process = subprocess.Popen(process_command, shell = False) + process.communicate() + + + def clicked_refresh(self): + """clicked refresh""" + self.setup_ui() + + + def setup_ui(self): + """create the user interface + As for the system tray this is 'just' the context menu. + """ + + # define the tray icon menu + menu = QtGui.QMenu(self.parent()) + self.setContextMenu(menu) + + # add known apps + + # add standard menu items + cAcLaunch = menu.addAction(QtGui.QIcon(QtGui.QPixmapCache.find('opensecurity_icon_64')), 'Lauch Application') + menu.addSeparator() + cAcRefresh = menu.addAction('Refresh') + cAcAbout = menu.addAction("About") + cAcExit = menu.addAction("Exit") + + cAcLaunch.triggered.connect(self.clicked_launch_application) + cAcRefresh.triggered.connect(self.clicked_refresh) + cAcAbout.triggered.connect(self.clicked_about) + cAcExit.triggered.connect(self.clicked_exit) + + +def main(): + + app = QtGui.QApplication(sys.argv) + + # prebuild the pixmap cache: fetch all jpg, png and jpeg images and load them + image_path = os.path.join(Environment("OpenSecurity").data_path, '..', 'gfx') + for file in os.listdir(image_path): + if file.lower().rpartition('.')[2] in ('jpg', 'png', 'jpeg'): + QtGui.QPixmapCache.insert(file.lower().rpartition('.')[0], QtGui.QPixmap(os.path.join(image_path, file))) + + w = QtGui.QWidget() + trayIcon = OpenSecurityTrayIcon(QtGui.QIcon(QtGui.QPixmapCache.find('opensecurity_icon_64')), w) + + trayIcon.show() + sys.exit(app.exec_()) + + +# start +if __name__ == "__main__": + main() + diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/client/password.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/client/password.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,150 @@ +#!/bin/env python +# -*- coding: utf-8 -*- + +# ------------------------------------------------------------ +# password-dialog +# +# ask the user a password +# +# 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 Password(QtGui.QDialog): + + """Ask the user for a password.""" + + def __init__(self, text, parent = None, flags = QtCore.Qt.WindowFlags(0)): + + # super call and widget init + super(Password, self).__init__(parent, flags) + self.setWindowTitle('OpenSecuirty Password Request') + self.setup_ui() + + # 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 + self.lbText.setText(text) + + + def clicked_about(self): + """clicked the about button""" + dlgAbout = About() + dlgAbout.exec_() + + + def clicked_cancel(self): + """clicked the cancel button""" + self.reject() + + + def clicked_ok(self): + """clicked the ok button""" + sys.stdout.write('{ ') + sys.stdout.write('\'password\': \'') + sys.stdout.write(self.edPassword.text()) + sys.stdout.write('\' ') + sys.stdout.write('}\n') + self.accept() + + + def setup_ui(self): + + """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) + self.lbText = QtGui.QLabel() + lyText.addWidget(self.lbText) + lyPassword = QtGui.QHBoxLayout() + lyText.addLayout(lyPassword) + lbPassword = QtGui.QLabel('&Password:') + lyPassword.addWidget(lbPassword) + self.edPassword = QtGui.QLineEdit() + self.edPassword.setEchoMode(QtGui.QLineEdit.Password) + lyPassword.addWidget(self.edPassword) + lbPassword.setBuddy(self.edPassword) + 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) + btnCancel = QtGui.QPushButton('&Cancel', self) + btnCancel.setMinimumWidth(100) + lyButton.addWidget(btnCancel) + btnAbout = QtGui.QPushButton('&About', self) + btnAbout.setMinimumWidth(100) + lyButton.addWidget(btnAbout) + + button_width = max(btnOk.width(), btnCancel.width(), btnAbout.width()) + btnOk.setMinimumWidth(button_width) + btnCancel.setMinimumWidth(button_width) + btnAbout.setMinimumWidth(button_width) + + # reduce to the max + self.resize(lyMain.minimumSize()) + + # connectors + btnOk.clicked.connect(self.clicked_ok) + btnCancel.clicked.connect(self.clicked_cancel) + btnAbout.clicked.connect(self.clicked_about) diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/cygwin/Cygwin.vbs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/cygwin/Cygwin.vbs Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,50 @@ +Option Explicit + +' ------------------------------------------------------------ +' start a cygwin shell +' +' 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 starts a cygwin shell within a relocatable cygwin +' folder but without a DOS shell window prior. The idea is +' to do it like in this BAT snippet below: +' +' @echo off +' SET INSTALL_DRIVE=%~d0 +' SET INSTALL_FOLDER=%~p0 +' SET CYGWIN_BIN="%INSTALL_DRIVE%%INSTALL_FOLDER%bin" +' SET CYGWIN_BASH="%INSTALL_DRIVE%%INSTALL_FOLDER%bin\bash" +' %INSTALL_DRIVE% +' chdir "%CYGWIN_BIN%" +' start mintty.exe %CYGWIN_BASH% --login -i +' +' ------------------------------------------------------------ + +' setup the basic objects +Dim cFSO +Dim cShell +Set cShell = CreateObject("WScript.Shell") +Set cFSO = CreateObject("Scripting.FileSystemObject") + +' parse script location and cd into folder +Dim sPath +sPath = Wscript.ScriptFullName +sPath = cFSO.GetAbsolutePathName(sPath) +sPath = cFSO.GetParentFolderName(sPath) +cShell.CurrentDirectory = sPath + +' locations of mintty and bash +Dim sMinTTYPath +Dim sBashPath +sMinTTYPath = """" & sPath & "\bin\mintty" & """" +sBashPath = """" & sPath & "\bin\bash" & """" + +' start a cygwin shell +cShell.Run sMinTTYPath & " " & sBashPath & " --login -i", 1, false diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/cygwin/content.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/cygwin/content.txt Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,10 @@ +Content of Opensecurity/cygwin +============================== + +This folder contains a complete Cygwin - 32 Bit with at least these packages installed: + + - bash + - coreutils + - openssh + - xinit + - genisofs diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/cygwin/setup-x86.exe Binary file OpenSecurity/cygwin/setup-x86.exe has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/cygwin64/Cygwin.vbs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/cygwin64/Cygwin.vbs Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,50 @@ +Option Explicit + +' ------------------------------------------------------------ +' start a cygwin shell +' +' 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 starts a cygwin shell within a relocatable cygwin +' folder but without a DOS shell window prior. The idea is +' to do it like in this BAT snippet below: +' +' @echo off +' SET INSTALL_DRIVE=%~d0 +' SET INSTALL_FOLDER=%~p0 +' SET CYGWIN_BIN="%INSTALL_DRIVE%%INSTALL_FOLDER%bin" +' SET CYGWIN_BASH="%INSTALL_DRIVE%%INSTALL_FOLDER%bin\bash" +' %INSTALL_DRIVE% +' chdir "%CYGWIN_BIN%" +' start mintty.exe %CYGWIN_BASH% --login -i +' +' ------------------------------------------------------------ + +' setup the basic objects +Dim cFSO +Dim cShell +Set cShell = CreateObject("WScript.Shell") +Set cFSO = CreateObject("Scripting.FileSystemObject") + +' parse script location and cd into folder +Dim sPath +sPath = Wscript.ScriptFullName +sPath = cFSO.GetAbsolutePathName(sPath) +sPath = cFSO.GetParentFolderName(sPath) +cShell.CurrentDirectory = sPath + +' locations of mintty and bash +Dim sMinTTYPath +Dim sBashPath +sMinTTYPath = """" & sPath & "\bin\mintty" & """" +sBashPath = """" & sPath & "\bin\bash" & """" + +' start a cygwin shell +cShell.Run sMinTTYPath & " " & sBashPath & " --login -i", 1, false diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/cygwin64/content.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/cygwin64/content.txt Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,10 @@ +Content of Opensecurity/cygwin +============================== + +This folder contains a complete Cygwin - 64 Bit with at least these packages installed: + + - bash + - coreutils + - openssh + - xinit + - genisofs diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/cygwin64/setup-x86_64.exe Binary file OpenSecurity/cygwin64/setup-x86_64.exe has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/ait_logo.jpg Binary file OpenSecurity/gfx/ait_logo.jpg has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/ait_logo_no_claim.png Binary file OpenSecurity/gfx/ait_logo_no_claim.png has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/bmvit_logo.jpg Binary file OpenSecurity/gfx/bmvit_logo.jpg has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/ffg_logo.jpg Binary file OpenSecurity/gfx/ffg_logo.jpg has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/ikarus_logo.jpg Binary file OpenSecurity/gfx/ikarus_logo.jpg has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/kiras_logo.jpg Binary file OpenSecurity/gfx/kiras_logo.jpg has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/linz_logo.jpg Binary file OpenSecurity/gfx/linz_logo.jpg has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/liqua_logo.jpg Binary file OpenSecurity/gfx/liqua_logo.jpg has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/opensecurity.ico Binary file OpenSecurity/gfx/opensecurity.ico has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/opensecurity_icon_64.png Binary file OpenSecurity/gfx/opensecurity_icon_64.png has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/opensecurity_logo.jpg Binary file OpenSecurity/gfx/opensecurity_logo.jpg has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/gfx/x-net_logo.jpg Binary file OpenSecurity/gfx/x-net_logo.jpg has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/OpenSecurity.reg Binary file OpenSecurity/install/OpenSecurity.reg has changed diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/content.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/content.txt Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,15 @@ +Content of Opensecurity/install +============================== + +Additonally to the files already present in this folder, we need: + +- PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x32.exe +- PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x64.exe + (--> http://www.riverbankcomputing.com/software/pyqt/download) + +- python-2.7.6.amd64.msi +- python-2.7.6.msi + (--> http://www.python.org/download) + +- VirtualBox-4.3.4-91027-Win.exe + (--> https://virtualbox.org/wiki/Downloads) diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/PKG-INFO --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/PKG-INFO Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,10 @@ +Metadata-Version: 1.0 +Name: web.py +Version: 0.37 +Summary: web.py: makes web apps +Home-page: http://webpy.org/ +Author: Anand Chitipothu +Author-email: anandology@gmail.com +License: Public domain +Description: Think about the ideal way to write a web app. Write the code to make it happen. +Platform: any diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/__init__.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,33 @@ +#!/usr/bin/env python +"""web.py: makes web apps (http://webpy.org)""" + +from __future__ import generators + +__version__ = "0.37" +__author__ = [ + "Aaron Swartz ", + "Anand Chitipothu " +] +__license__ = "public domain" +__contributors__ = "see http://webpy.org/changes" + +import utils, db, net, wsgi, http, webapi, httpserver, debugerror +import template, form + +import session + +from utils import * +from db import * +from net import * +from wsgi import * +from http import * +from webapi import * +from httpserver import * +from debugerror import * +from application import * +from browser import * +try: + import webopenid as openid +except ImportError: + pass # requires openid module + diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/application.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/application.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,687 @@ +""" +Web application +(from web.py) +""" +import webapi as web +import webapi, wsgi, utils +import debugerror +import httpserver + +from utils import lstrips, safeunicode +import sys + +import urllib +import traceback +import itertools +import os +import types +from exceptions import SystemExit + +try: + import wsgiref.handlers +except ImportError: + pass # don't break people with old Pythons + +__all__ = [ + "application", "auto_application", + "subdir_application", "subdomain_application", + "loadhook", "unloadhook", + "autodelegate" +] + +class application: + """ + Application to delegate requests based on path. + + >>> urls = ("/hello", "hello") + >>> app = application(urls, globals()) + >>> class hello: + ... def GET(self): return "hello" + >>> + >>> app.request("/hello").data + 'hello' + """ + def __init__(self, mapping=(), fvars={}, autoreload=None): + if autoreload is None: + autoreload = web.config.get('debug', False) + self.init_mapping(mapping) + self.fvars = fvars + self.processors = [] + + self.add_processor(loadhook(self._load)) + self.add_processor(unloadhook(self._unload)) + + if autoreload: + def main_module_name(): + mod = sys.modules['__main__'] + file = getattr(mod, '__file__', None) # make sure this works even from python interpreter + return file and os.path.splitext(os.path.basename(file))[0] + + def modname(fvars): + """find name of the module name from fvars.""" + file, name = fvars.get('__file__'), fvars.get('__name__') + if file is None or name is None: + return None + + if name == '__main__': + # Since the __main__ module can't be reloaded, the module has + # to be imported using its file name. + name = main_module_name() + return name + + mapping_name = utils.dictfind(fvars, mapping) + module_name = modname(fvars) + + def reload_mapping(): + """loadhook to reload mapping and fvars.""" + mod = __import__(module_name, None, None, ['']) + mapping = getattr(mod, mapping_name, None) + if mapping: + self.fvars = mod.__dict__ + self.init_mapping(mapping) + + self.add_processor(loadhook(Reloader())) + if mapping_name and module_name: + self.add_processor(loadhook(reload_mapping)) + + # load __main__ module usings its filename, so that it can be reloaded. + if main_module_name() and '__main__' in sys.argv: + try: + __import__(main_module_name()) + except ImportError: + pass + + def _load(self): + web.ctx.app_stack.append(self) + + def _unload(self): + web.ctx.app_stack = web.ctx.app_stack[:-1] + + if web.ctx.app_stack: + # this is a sub-application, revert ctx to earlier state. + oldctx = web.ctx.get('_oldctx') + if oldctx: + web.ctx.home = oldctx.home + web.ctx.homepath = oldctx.homepath + web.ctx.path = oldctx.path + web.ctx.fullpath = oldctx.fullpath + + def _cleanup(self): + # Threads can be recycled by WSGI servers. + # Clearing up all thread-local state to avoid interefereing with subsequent requests. + utils.ThreadedDict.clear_all() + + def init_mapping(self, mapping): + self.mapping = list(utils.group(mapping, 2)) + + def add_mapping(self, pattern, classname): + self.mapping.append((pattern, classname)) + + def add_processor(self, processor): + """ + Adds a processor to the application. + + >>> urls = ("/(.*)", "echo") + >>> app = application(urls, globals()) + >>> class echo: + ... def GET(self, name): return name + ... + >>> + >>> def hello(handler): return "hello, " + handler() + ... + >>> app.add_processor(hello) + >>> app.request("/web.py").data + 'hello, web.py' + """ + self.processors.append(processor) + + def request(self, localpart='/', method='GET', data=None, + host="0.0.0.0:8080", headers=None, https=False, **kw): + """Makes request to this application for the specified path and method. + Response will be a storage object with data, status and headers. + + >>> urls = ("/hello", "hello") + >>> app = application(urls, globals()) + >>> class hello: + ... def GET(self): + ... web.header('Content-Type', 'text/plain') + ... return "hello" + ... + >>> response = app.request("/hello") + >>> response.data + 'hello' + >>> response.status + '200 OK' + >>> response.headers['Content-Type'] + 'text/plain' + + To use https, use https=True. + + >>> urls = ("/redirect", "redirect") + >>> app = application(urls, globals()) + >>> class redirect: + ... def GET(self): raise web.seeother("/foo") + ... + >>> response = app.request("/redirect") + >>> response.headers['Location'] + 'http://0.0.0.0:8080/foo' + >>> response = app.request("/redirect", https=True) + >>> response.headers['Location'] + 'https://0.0.0.0:8080/foo' + + The headers argument specifies HTTP headers as a mapping object + such as a dict. + + >>> urls = ('/ua', 'uaprinter') + >>> class uaprinter: + ... def GET(self): + ... return 'your user-agent is ' + web.ctx.env['HTTP_USER_AGENT'] + ... + >>> app = application(urls, globals()) + >>> app.request('/ua', headers = { + ... 'User-Agent': 'a small jumping bean/1.0 (compatible)' + ... }).data + 'your user-agent is a small jumping bean/1.0 (compatible)' + + """ + path, maybe_query = urllib.splitquery(localpart) + query = maybe_query or "" + + if 'env' in kw: + env = kw['env'] + else: + env = {} + env = dict(env, HTTP_HOST=host, REQUEST_METHOD=method, PATH_INFO=path, QUERY_STRING=query, HTTPS=str(https)) + headers = headers or {} + + for k, v in headers.items(): + env['HTTP_' + k.upper().replace('-', '_')] = v + + if 'HTTP_CONTENT_LENGTH' in env: + env['CONTENT_LENGTH'] = env.pop('HTTP_CONTENT_LENGTH') + + if 'HTTP_CONTENT_TYPE' in env: + env['CONTENT_TYPE'] = env.pop('HTTP_CONTENT_TYPE') + + if method not in ["HEAD", "GET"]: + data = data or '' + import StringIO + if isinstance(data, dict): + q = urllib.urlencode(data) + else: + q = data + env['wsgi.input'] = StringIO.StringIO(q) + if not env.get('CONTENT_TYPE', '').lower().startswith('multipart/') and 'CONTENT_LENGTH' not in env: + env['CONTENT_LENGTH'] = len(q) + response = web.storage() + def start_response(status, headers): + response.status = status + response.headers = dict(headers) + response.header_items = headers + response.data = "".join(self.wsgifunc()(env, start_response)) + return response + + def browser(self): + import browser + return browser.AppBrowser(self) + + def handle(self): + fn, args = self._match(self.mapping, web.ctx.path) + return self._delegate(fn, self.fvars, args) + + def handle_with_processors(self): + def process(processors): + try: + if processors: + p, processors = processors[0], processors[1:] + return p(lambda: process(processors)) + else: + return self.handle() + except web.HTTPError: + raise + except (KeyboardInterrupt, SystemExit): + raise + except: + print >> web.debug, traceback.format_exc() + raise self.internalerror() + + # processors must be applied in the resvere order. (??) + return process(self.processors) + + def wsgifunc(self, *middleware): + """Returns a WSGI-compatible function for this application.""" + def peep(iterator): + """Peeps into an iterator by doing an iteration + and returns an equivalent iterator. + """ + # wsgi requires the headers first + # so we need to do an iteration + # and save the result for later + try: + firstchunk = iterator.next() + except StopIteration: + firstchunk = '' + + return itertools.chain([firstchunk], iterator) + + def is_generator(x): return x and hasattr(x, 'next') + + def wsgi(env, start_resp): + # clear threadlocal to avoid inteference of previous requests + self._cleanup() + + self.load(env) + try: + # allow uppercase methods only + if web.ctx.method.upper() != web.ctx.method: + raise web.nomethod() + + result = self.handle_with_processors() + if is_generator(result): + result = peep(result) + else: + result = [result] + except web.HTTPError, e: + result = [e.data] + + result = web.safestr(iter(result)) + + status, headers = web.ctx.status, web.ctx.headers + start_resp(status, headers) + + def cleanup(): + self._cleanup() + yield '' # force this function to be a generator + + return itertools.chain(result, cleanup()) + + for m in middleware: + wsgi = m(wsgi) + + return wsgi + + def run(self, *middleware): + """ + Starts handling requests. If called in a CGI or FastCGI context, it will follow + that protocol. If called from the command line, it will start an HTTP + server on the port named in the first command line argument, or, if there + is no argument, on port 8080. + + `middleware` is a list of WSGI middleware which is applied to the resulting WSGI + function. + """ + return wsgi.runwsgi(self.wsgifunc(*middleware)) + + def stop(self): + """Stops the http server started by run. + """ + if httpserver.server: + httpserver.server.stop() + httpserver.server = None + + def cgirun(self, *middleware): + """ + Return a CGI handler. This is mostly useful with Google App Engine. + There you can just do: + + main = app.cgirun() + """ + wsgiapp = self.wsgifunc(*middleware) + + try: + from google.appengine.ext.webapp.util import run_wsgi_app + return run_wsgi_app(wsgiapp) + except ImportError: + # we're not running from within Google App Engine + return wsgiref.handlers.CGIHandler().run(wsgiapp) + + def load(self, env): + """Initializes ctx using env.""" + ctx = web.ctx + ctx.clear() + ctx.status = '200 OK' + ctx.headers = [] + ctx.output = '' + ctx.environ = ctx.env = env + ctx.host = env.get('HTTP_HOST') + + if env.get('wsgi.url_scheme') in ['http', 'https']: + ctx.protocol = env['wsgi.url_scheme'] + elif env.get('HTTPS', '').lower() in ['on', 'true', '1']: + ctx.protocol = 'https' + else: + ctx.protocol = 'http' + ctx.homedomain = ctx.protocol + '://' + env.get('HTTP_HOST', '[unknown]') + ctx.homepath = os.environ.get('REAL_SCRIPT_NAME', env.get('SCRIPT_NAME', '')) + ctx.home = ctx.homedomain + ctx.homepath + #@@ home is changed when the request is handled to a sub-application. + #@@ but the real home is required for doing absolute redirects. + ctx.realhome = ctx.home + ctx.ip = env.get('REMOTE_ADDR') + ctx.method = env.get('REQUEST_METHOD') + ctx.path = env.get('PATH_INFO') + # http://trac.lighttpd.net/trac/ticket/406 requires: + if env.get('SERVER_SOFTWARE', '').startswith('lighttpd/'): + ctx.path = lstrips(env.get('REQUEST_URI').split('?')[0], ctx.homepath) + # Apache and CherryPy webservers unquote the url but lighttpd doesn't. + # unquote explicitly for lighttpd to make ctx.path uniform across all servers. + ctx.path = urllib.unquote(ctx.path) + + if env.get('QUERY_STRING'): + ctx.query = '?' + env.get('QUERY_STRING', '') + else: + ctx.query = '' + + ctx.fullpath = ctx.path + ctx.query + + for k, v in ctx.iteritems(): + # convert all string values to unicode values and replace + # malformed data with a suitable replacement marker. + if isinstance(v, str): + ctx[k] = v.decode('utf-8', 'replace') + + # status must always be str + ctx.status = '200 OK' + + ctx.app_stack = [] + + def _delegate(self, f, fvars, args=[]): + def handle_class(cls): + meth = web.ctx.method + if meth == 'HEAD' and not hasattr(cls, meth): + meth = 'GET' + if not hasattr(cls, meth): + raise web.nomethod(cls) + tocall = getattr(cls(), meth) + return tocall(*args) + + def is_class(o): return isinstance(o, (types.ClassType, type)) + + if f is None: + raise web.notfound() + elif isinstance(f, application): + return f.handle_with_processors() + elif is_class(f): + return handle_class(f) + elif isinstance(f, basestring): + if f.startswith('redirect '): + url = f.split(' ', 1)[1] + if web.ctx.method == "GET": + x = web.ctx.env.get('QUERY_STRING', '') + if x: + url += '?' + x + raise web.redirect(url) + elif '.' in f: + mod, cls = f.rsplit('.', 1) + mod = __import__(mod, None, None, ['']) + cls = getattr(mod, cls) + else: + cls = fvars[f] + return handle_class(cls) + elif hasattr(f, '__call__'): + return f() + else: + return web.notfound() + + def _match(self, mapping, value): + for pat, what in mapping: + if isinstance(what, application): + if value.startswith(pat): + f = lambda: self._delegate_sub_application(pat, what) + return f, None + else: + continue + elif isinstance(what, basestring): + what, result = utils.re_subm('^' + pat + '$', what, value) + else: + result = utils.re_compile('^' + pat + '$').match(value) + + if result: # it's a match + return what, [x for x in result.groups()] + return None, None + + def _delegate_sub_application(self, dir, app): + """Deletes request to sub application `app` rooted at the directory `dir`. + The home, homepath, path and fullpath values in web.ctx are updated to mimic request + to the subapp and are restored after it is handled. + + @@Any issues with when used with yield? + """ + web.ctx._oldctx = web.storage(web.ctx) + web.ctx.home += dir + web.ctx.homepath += dir + web.ctx.path = web.ctx.path[len(dir):] + web.ctx.fullpath = web.ctx.fullpath[len(dir):] + return app.handle_with_processors() + + def get_parent_app(self): + if self in web.ctx.app_stack: + index = web.ctx.app_stack.index(self) + if index > 0: + return web.ctx.app_stack[index-1] + + def notfound(self): + """Returns HTTPError with '404 not found' message""" + parent = self.get_parent_app() + if parent: + return parent.notfound() + else: + return web._NotFound() + + def internalerror(self): + """Returns HTTPError with '500 internal error' message""" + parent = self.get_parent_app() + if parent: + return parent.internalerror() + elif web.config.get('debug'): + import debugerror + return debugerror.debugerror() + else: + return web._InternalError() + +class auto_application(application): + """Application similar to `application` but urls are constructed + automatiacally using metaclass. + + >>> app = auto_application() + >>> class hello(app.page): + ... def GET(self): return "hello, world" + ... + >>> class foo(app.page): + ... path = '/foo/.*' + ... def GET(self): return "foo" + >>> app.request("/hello").data + 'hello, world' + >>> app.request('/foo/bar').data + 'foo' + """ + def __init__(self): + application.__init__(self) + + class metapage(type): + def __init__(klass, name, bases, attrs): + type.__init__(klass, name, bases, attrs) + path = attrs.get('path', '/' + name) + + # path can be specified as None to ignore that class + # typically required to create a abstract base class. + if path is not None: + self.add_mapping(path, klass) + + class page: + path = None + __metaclass__ = metapage + + self.page = page + +# The application class already has the required functionality of subdir_application +subdir_application = application + +class subdomain_application(application): + """ + Application to delegate requests based on the host. + + >>> urls = ("/hello", "hello") + >>> app = application(urls, globals()) + >>> class hello: + ... def GET(self): return "hello" + >>> + >>> mapping = (r"hello\.example\.com", app) + >>> app2 = subdomain_application(mapping) + >>> app2.request("/hello", host="hello.example.com").data + 'hello' + >>> response = app2.request("/hello", host="something.example.com") + >>> response.status + '404 Not Found' + >>> response.data + 'not found' + """ + def handle(self): + host = web.ctx.host.split(':')[0] #strip port + fn, args = self._match(self.mapping, host) + return self._delegate(fn, self.fvars, args) + + def _match(self, mapping, value): + for pat, what in mapping: + if isinstance(what, basestring): + what, result = utils.re_subm('^' + pat + '$', what, value) + else: + result = utils.re_compile('^' + pat + '$').match(value) + + if result: # it's a match + return what, [x for x in result.groups()] + return None, None + +def loadhook(h): + """ + Converts a load hook into an application processor. + + >>> app = auto_application() + >>> def f(): "something done before handling request" + ... + >>> app.add_processor(loadhook(f)) + """ + def processor(handler): + h() + return handler() + + return processor + +def unloadhook(h): + """ + Converts an unload hook into an application processor. + + >>> app = auto_application() + >>> def f(): "something done after handling request" + ... + >>> app.add_processor(unloadhook(f)) + """ + def processor(handler): + try: + result = handler() + is_generator = result and hasattr(result, 'next') + except: + # run the hook even when handler raises some exception + h() + raise + + if is_generator: + return wrap(result) + else: + h() + return result + + def wrap(result): + def next(): + try: + return result.next() + except: + # call the hook at the and of iterator + h() + raise + + result = iter(result) + while True: + yield next() + + return processor + +def autodelegate(prefix=''): + """ + Returns a method that takes one argument and calls the method named prefix+arg, + calling `notfound()` if there isn't one. Example: + + urls = ('/prefs/(.*)', 'prefs') + + class prefs: + GET = autodelegate('GET_') + def GET_password(self): pass + def GET_privacy(self): pass + + `GET_password` would get called for `/prefs/password` while `GET_privacy` for + `GET_privacy` gets called for `/prefs/privacy`. + + If a user visits `/prefs/password/change` then `GET_password(self, '/change')` + is called. + """ + def internal(self, arg): + if '/' in arg: + first, rest = arg.split('/', 1) + func = prefix + first + args = ['/' + rest] + else: + func = prefix + arg + args = [] + + if hasattr(self, func): + try: + return getattr(self, func)(*args) + except TypeError: + raise web.notfound() + else: + raise web.notfound() + return internal + +class Reloader: + """Checks to see if any loaded modules have changed on disk and, + if so, reloads them. + """ + + """File suffix of compiled modules.""" + if sys.platform.startswith('java'): + SUFFIX = '$py.class' + else: + SUFFIX = '.pyc' + + def __init__(self): + self.mtimes = {} + + def __call__(self): + for mod in sys.modules.values(): + self.check(mod) + + def check(self, mod): + # jython registers java packages as modules but they either + # don't have a __file__ attribute or its value is None + if not (mod and hasattr(mod, '__file__') and mod.__file__): + return + + try: + mtime = os.stat(mod.__file__).st_mtime + except (OSError, IOError): + return + if mod.__file__.endswith(self.__class__.SUFFIX) and os.path.exists(mod.__file__[:-1]): + mtime = max(os.stat(mod.__file__[:-1]).st_mtime, mtime) + + if mod not in self.mtimes: + self.mtimes[mod] = mtime + elif self.mtimes[mod] < mtime: + try: + reload(mod) + self.mtimes[mod] = mtime + except ImportError: + pass + +if __name__ == "__main__": + import doctest + doctest.testmod() diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/browser.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/browser.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,236 @@ +"""Browser to test web applications. +(from web.py) +""" +from utils import re_compile +from net import htmlunquote + +import httplib, urllib, urllib2 +import copy +from StringIO import StringIO + +DEBUG = False + +__all__ = [ + "BrowserError", + "Browser", "AppBrowser", + "AppHandler" +] + +class BrowserError(Exception): + pass + +class Browser: + def __init__(self): + import cookielib + self.cookiejar = cookielib.CookieJar() + self._cookie_processor = urllib2.HTTPCookieProcessor(self.cookiejar) + self.form = None + + self.url = "http://0.0.0.0:8080/" + self.path = "/" + + self.status = None + self.data = None + self._response = None + self._forms = None + + def reset(self): + """Clears all cookies and history.""" + self.cookiejar.clear() + + def build_opener(self): + """Builds the opener using urllib2.build_opener. + Subclasses can override this function to prodive custom openers. + """ + return urllib2.build_opener() + + def do_request(self, req): + if DEBUG: + print 'requesting', req.get_method(), req.get_full_url() + opener = self.build_opener() + opener.add_handler(self._cookie_processor) + try: + self._response = opener.open(req) + except urllib2.HTTPError, e: + self._response = e + + self.url = self._response.geturl() + self.path = urllib2.Request(self.url).get_selector() + self.data = self._response.read() + self.status = self._response.code + self._forms = None + self.form = None + return self.get_response() + + def open(self, url, data=None, headers={}): + """Opens the specified url.""" + url = urllib.basejoin(self.url, url) + req = urllib2.Request(url, data, headers) + return self.do_request(req) + + def show(self): + """Opens the current page in real web browser.""" + f = open('page.html', 'w') + f.write(self.data) + f.close() + + import webbrowser, os + url = 'file://' + os.path.abspath('page.html') + webbrowser.open(url) + + def get_response(self): + """Returns a copy of the current response.""" + return urllib.addinfourl(StringIO(self.data), self._response.info(), self._response.geturl()) + + def get_soup(self): + """Returns beautiful soup of the current document.""" + import BeautifulSoup + return BeautifulSoup.BeautifulSoup(self.data) + + def get_text(self, e=None): + """Returns content of e or the current document as plain text.""" + e = e or self.get_soup() + return ''.join([htmlunquote(c) for c in e.recursiveChildGenerator() if isinstance(c, unicode)]) + + def _get_links(self): + soup = self.get_soup() + return [a for a in soup.findAll(name='a')] + + def get_links(self, text=None, text_regex=None, url=None, url_regex=None, predicate=None): + """Returns all links in the document.""" + return self._filter_links(self._get_links(), + text=text, text_regex=text_regex, url=url, url_regex=url_regex, predicate=predicate) + + def follow_link(self, link=None, text=None, text_regex=None, url=None, url_regex=None, predicate=None): + if link is None: + links = self._filter_links(self.get_links(), + text=text, text_regex=text_regex, url=url, url_regex=url_regex, predicate=predicate) + link = links and links[0] + + if link: + return self.open(link['href']) + else: + raise BrowserError("No link found") + + def find_link(self, text=None, text_regex=None, url=None, url_regex=None, predicate=None): + links = self._filter_links(self.get_links(), + text=text, text_regex=text_regex, url=url, url_regex=url_regex, predicate=predicate) + return links and links[0] or None + + def _filter_links(self, links, + text=None, text_regex=None, + url=None, url_regex=None, + predicate=None): + predicates = [] + if text is not None: + predicates.append(lambda link: link.string == text) + if text_regex is not None: + predicates.append(lambda link: re_compile(text_regex).search(link.string or '')) + if url is not None: + predicates.append(lambda link: link.get('href') == url) + if url_regex is not None: + predicates.append(lambda link: re_compile(url_regex).search(link.get('href', ''))) + if predicate: + predicate.append(predicate) + + def f(link): + for p in predicates: + if not p(link): + return False + return True + + return [link for link in links if f(link)] + + def get_forms(self): + """Returns all forms in the current document. + The returned form objects implement the ClientForm.HTMLForm interface. + """ + if self._forms is None: + import ClientForm + self._forms = ClientForm.ParseResponse(self.get_response(), backwards_compat=False) + return self._forms + + def select_form(self, name=None, predicate=None, index=0): + """Selects the specified form.""" + forms = self.get_forms() + + if name is not None: + forms = [f for f in forms if f.name == name] + if predicate: + forms = [f for f in forms if predicate(f)] + + if forms: + self.form = forms[index] + return self.form + else: + raise BrowserError("No form selected.") + + def submit(self, **kw): + """submits the currently selected form.""" + if self.form is None: + raise BrowserError("No form selected.") + req = self.form.click(**kw) + return self.do_request(req) + + def __getitem__(self, key): + return self.form[key] + + def __setitem__(self, key, value): + self.form[key] = value + +class AppBrowser(Browser): + """Browser interface to test web.py apps. + + b = AppBrowser(app) + b.open('/') + b.follow_link(text='Login') + + b.select_form(name='login') + b['username'] = 'joe' + b['password'] = 'secret' + b.submit() + + assert b.path == '/' + assert 'Welcome joe' in b.get_text() + """ + def __init__(self, app): + Browser.__init__(self) + self.app = app + + def build_opener(self): + return urllib2.build_opener(AppHandler(self.app)) + +class AppHandler(urllib2.HTTPHandler): + """urllib2 handler to handle requests using web.py application.""" + handler_order = 100 + + def __init__(self, app): + self.app = app + + def http_open(self, req): + result = self.app.request( + localpart=req.get_selector(), + method=req.get_method(), + host=req.get_host(), + data=req.get_data(), + headers=dict(req.header_items()), + https=req.get_type() == "https" + ) + return self._make_response(result, req.get_full_url()) + + def https_open(self, req): + return self.http_open(req) + + try: + https_request = urllib2.HTTPHandler.do_request_ + except AttributeError: + # for python 2.3 + pass + + def _make_response(self, result, url): + data = "\r\n".join(["%s: %s" % (k, v) for k, v in result.header_items]) + headers = httplib.HTTPMessage(StringIO(data)) + response = urllib.addinfourl(StringIO(result.data), headers, url) + code, msg = result.status.split(None, 1) + response.code, response.msg = int(code), msg + return response diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/contrib/template.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/contrib/template.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,131 @@ +""" +Interface to various templating engines. +""" +import os.path + +__all__ = [ + "render_cheetah", "render_genshi", "render_mako", + "cache", +] + +class render_cheetah: + """Rendering interface to Cheetah Templates. + + Example: + + render = render_cheetah('templates') + render.hello(name="cheetah") + """ + def __init__(self, path): + # give error if Chetah is not installed + from Cheetah.Template import Template + self.path = path + + def __getattr__(self, name): + from Cheetah.Template import Template + path = os.path.join(self.path, name + ".html") + + def template(**kw): + t = Template(file=path, searchList=[kw]) + return t.respond() + + return template + +class render_genshi: + """Rendering interface genshi templates. + Example: + + for xml/html templates. + + render = render_genshi(['templates/']) + render.hello(name='genshi') + + For text templates: + + render = render_genshi(['templates/'], type='text') + render.hello(name='genshi') + """ + + def __init__(self, *a, **kwargs): + from genshi.template import TemplateLoader + + self._type = kwargs.pop('type', None) + self._loader = TemplateLoader(*a, **kwargs) + + def __getattr__(self, name): + # Assuming all templates are html + path = name + ".html" + + if self._type == "text": + from genshi.template import TextTemplate + cls = TextTemplate + type = "text" + else: + cls = None + type = None + + t = self._loader.load(path, cls=cls) + def template(**kw): + stream = t.generate(**kw) + if type: + return stream.render(type) + else: + return stream.render() + return template + +class render_jinja: + """Rendering interface to Jinja2 Templates + + Example: + + render= render_jinja('templates') + render.hello(name='jinja2') + """ + def __init__(self, *a, **kwargs): + extensions = kwargs.pop('extensions', []) + globals = kwargs.pop('globals', {}) + + from jinja2 import Environment,FileSystemLoader + self._lookup = Environment(loader=FileSystemLoader(*a, **kwargs), extensions=extensions) + self._lookup.globals.update(globals) + + def __getattr__(self, name): + # Assuming all templates end with .html + path = name + '.html' + t = self._lookup.get_template(path) + return t.render + +class render_mako: + """Rendering interface to Mako Templates. + + Example: + + render = render_mako(directories=['templates']) + render.hello(name="mako") + """ + def __init__(self, *a, **kwargs): + from mako.lookup import TemplateLookup + self._lookup = TemplateLookup(*a, **kwargs) + + def __getattr__(self, name): + # Assuming all templates are html + path = name + ".html" + t = self._lookup.get_template(path) + return t.render + +class cache: + """Cache for any rendering interface. + + Example: + + render = cache(render_cheetah("templates/")) + render.hello(name='cache') + """ + def __init__(self, render): + self._render = render + self._cache = {} + + def __getattr__(self, name): + if name not in self._cache: + self._cache[name] = getattr(self._render, name) + return self._cache[name] diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/db.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/db.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,1237 @@ +""" +Database API +(part of web.py) +""" + +__all__ = [ + "UnknownParamstyle", "UnknownDB", "TransactionError", + "sqllist", "sqlors", "reparam", "sqlquote", + "SQLQuery", "SQLParam", "sqlparam", + "SQLLiteral", "sqlliteral", + "database", 'DB', +] + +import time +try: + import datetime +except ImportError: + datetime = None + +try: set +except NameError: + from sets import Set as set + +from utils import threadeddict, storage, iters, iterbetter, safestr, safeunicode + +try: + # db module can work independent of web.py + from webapi import debug, config +except: + import sys + debug = sys.stderr + config = storage() + +class UnknownDB(Exception): + """raised for unsupported dbms""" + pass + +class _ItplError(ValueError): + def __init__(self, text, pos): + ValueError.__init__(self) + self.text = text + self.pos = pos + def __str__(self): + return "unfinished expression in %s at char %d" % ( + repr(self.text), self.pos) + +class TransactionError(Exception): pass + +class UnknownParamstyle(Exception): + """ + raised for unsupported db paramstyles + + (currently supported: qmark, numeric, format, pyformat) + """ + pass + +class SQLParam(object): + """ + Parameter in SQLQuery. + + >>> q = SQLQuery(["SELECT * FROM test WHERE name=", SQLParam("joe")]) + >>> q + + >>> q.query() + 'SELECT * FROM test WHERE name=%s' + >>> q.values() + ['joe'] + """ + __slots__ = ["value"] + + def __init__(self, value): + self.value = value + + def get_marker(self, paramstyle='pyformat'): + if paramstyle == 'qmark': + return '?' + elif paramstyle == 'numeric': + return ':1' + elif paramstyle is None or paramstyle in ['format', 'pyformat']: + return '%s' + raise UnknownParamstyle, paramstyle + + def sqlquery(self): + return SQLQuery([self]) + + def __add__(self, other): + return self.sqlquery() + other + + def __radd__(self, other): + return other + self.sqlquery() + + def __str__(self): + return str(self.value) + + def __repr__(self): + return '' % repr(self.value) + +sqlparam = SQLParam + +class SQLQuery(object): + """ + You can pass this sort of thing as a clause in any db function. + Otherwise, you can pass a dictionary to the keyword argument `vars` + and the function will call reparam for you. + + Internally, consists of `items`, which is a list of strings and + SQLParams, which get concatenated to produce the actual query. + """ + __slots__ = ["items"] + + # tested in sqlquote's docstring + def __init__(self, items=None): + r"""Creates a new SQLQuery. + + >>> SQLQuery("x") + + >>> q = SQLQuery(['SELECT * FROM ', 'test', ' WHERE x=', SQLParam(1)]) + >>> q + + >>> q.query(), q.values() + ('SELECT * FROM test WHERE x=%s', [1]) + >>> SQLQuery(SQLParam(1)) + + """ + if items is None: + self.items = [] + elif isinstance(items, list): + self.items = items + elif isinstance(items, SQLParam): + self.items = [items] + elif isinstance(items, SQLQuery): + self.items = list(items.items) + else: + self.items = [items] + + # Take care of SQLLiterals + for i, item in enumerate(self.items): + if isinstance(item, SQLParam) and isinstance(item.value, SQLLiteral): + self.items[i] = item.value.v + + def append(self, value): + self.items.append(value) + + def __add__(self, other): + if isinstance(other, basestring): + items = [other] + elif isinstance(other, SQLQuery): + items = other.items + else: + return NotImplemented + return SQLQuery(self.items + items) + + def __radd__(self, other): + if isinstance(other, basestring): + items = [other] + else: + return NotImplemented + + return SQLQuery(items + self.items) + + def __iadd__(self, other): + if isinstance(other, (basestring, SQLParam)): + self.items.append(other) + elif isinstance(other, SQLQuery): + self.items.extend(other.items) + else: + return NotImplemented + return self + + def __len__(self): + return len(self.query()) + + def query(self, paramstyle=None): + """ + Returns the query part of the sql query. + >>> q = SQLQuery(["SELECT * FROM test WHERE name=", SQLParam('joe')]) + >>> q.query() + 'SELECT * FROM test WHERE name=%s' + >>> q.query(paramstyle='qmark') + 'SELECT * FROM test WHERE name=?' + """ + s = [] + for x in self.items: + if isinstance(x, SQLParam): + x = x.get_marker(paramstyle) + s.append(safestr(x)) + else: + x = safestr(x) + # automatically escape % characters in the query + # For backward compatability, ignore escaping when the query looks already escaped + if paramstyle in ['format', 'pyformat']: + if '%' in x and '%%' not in x: + x = x.replace('%', '%%') + s.append(x) + return "".join(s) + + def values(self): + """ + Returns the values of the parameters used in the sql query. + >>> q = SQLQuery(["SELECT * FROM test WHERE name=", SQLParam('joe')]) + >>> q.values() + ['joe'] + """ + return [i.value for i in self.items if isinstance(i, SQLParam)] + + def join(items, sep=' ', prefix=None, suffix=None, target=None): + """ + Joins multiple queries. + + >>> SQLQuery.join(['a', 'b'], ', ') + + + Optinally, prefix and suffix arguments can be provided. + + >>> SQLQuery.join(['a', 'b'], ', ', prefix='(', suffix=')') + + + If target argument is provided, the items are appended to target instead of creating a new SQLQuery. + """ + if target is None: + target = SQLQuery() + + target_items = target.items + + if prefix: + target_items.append(prefix) + + for i, item in enumerate(items): + if i != 0: + target_items.append(sep) + if isinstance(item, SQLQuery): + target_items.extend(item.items) + else: + target_items.append(item) + + if suffix: + target_items.append(suffix) + return target + + join = staticmethod(join) + + def _str(self): + try: + return self.query() % tuple([sqlify(x) for x in self.values()]) + except (ValueError, TypeError): + return self.query() + + def __str__(self): + return safestr(self._str()) + + def __unicode__(self): + return safeunicode(self._str()) + + def __repr__(self): + return '' % repr(str(self)) + +class SQLLiteral: + """ + Protects a string from `sqlquote`. + + >>> sqlquote('NOW()') + + >>> sqlquote(SQLLiteral('NOW()')) + + """ + def __init__(self, v): + self.v = v + + def __repr__(self): + return self.v + +sqlliteral = SQLLiteral + +def _sqllist(values): + """ + >>> _sqllist([1, 2, 3]) + + """ + items = [] + items.append('(') + for i, v in enumerate(values): + if i != 0: + items.append(', ') + items.append(sqlparam(v)) + items.append(')') + return SQLQuery(items) + +def reparam(string_, dictionary): + """ + Takes a string and a dictionary and interpolates the string + using values from the dictionary. Returns an `SQLQuery` for the result. + + >>> reparam("s = $s", dict(s=True)) + + >>> reparam("s IN $s", dict(s=[1, 2])) + + """ + dictionary = dictionary.copy() # eval mucks with it + vals = [] + result = [] + for live, chunk in _interpolate(string_): + if live: + v = eval(chunk, dictionary) + result.append(sqlquote(v)) + else: + result.append(chunk) + return SQLQuery.join(result, '') + +def sqlify(obj): + """ + converts `obj` to its proper SQL version + + >>> sqlify(None) + 'NULL' + >>> sqlify(True) + "'t'" + >>> sqlify(3) + '3' + """ + # because `1 == True and hash(1) == hash(True)` + # we have to do this the hard way... + + if obj is None: + return 'NULL' + elif obj is True: + return "'t'" + elif obj is False: + return "'f'" + elif datetime and isinstance(obj, datetime.datetime): + return repr(obj.isoformat()) + else: + if isinstance(obj, unicode): obj = obj.encode('utf8') + return repr(obj) + +def sqllist(lst): + """ + Converts the arguments for use in something like a WHERE clause. + + >>> sqllist(['a', 'b']) + 'a, b' + >>> sqllist('a') + 'a' + >>> sqllist(u'abc') + u'abc' + """ + if isinstance(lst, basestring): + return lst + else: + return ', '.join(lst) + +def sqlors(left, lst): + """ + `left is a SQL clause like `tablename.arg = ` + and `lst` is a list of values. Returns a reparam-style + pair featuring the SQL that ORs together the clause + for each item in the lst. + + >>> sqlors('foo = ', []) + + >>> sqlors('foo = ', [1]) + + >>> sqlors('foo = ', 1) + + >>> sqlors('foo = ', [1,2,3]) + + """ + if isinstance(lst, iters): + lst = list(lst) + ln = len(lst) + if ln == 0: + return SQLQuery("1=2") + if ln == 1: + lst = lst[0] + + if isinstance(lst, iters): + return SQLQuery(['('] + + sum([[left, sqlparam(x), ' OR '] for x in lst], []) + + ['1=2)'] + ) + else: + return left + sqlparam(lst) + +def sqlwhere(dictionary, grouping=' AND '): + """ + Converts a `dictionary` to an SQL WHERE clause `SQLQuery`. + + >>> sqlwhere({'cust_id': 2, 'order_id':3}) + + >>> sqlwhere({'cust_id': 2, 'order_id':3}, grouping=', ') + + >>> sqlwhere({'a': 'a', 'b': 'b'}).query() + 'a = %s AND b = %s' + """ + return SQLQuery.join([k + ' = ' + sqlparam(v) for k, v in dictionary.items()], grouping) + +def sqlquote(a): + """ + Ensures `a` is quoted properly for use in a SQL query. + + >>> 'WHERE x = ' + sqlquote(True) + ' AND y = ' + sqlquote(3) + + >>> 'WHERE x = ' + sqlquote(True) + ' AND y IN ' + sqlquote([2, 3]) + + """ + if isinstance(a, list): + return _sqllist(a) + else: + return sqlparam(a).sqlquery() + +class Transaction: + """Database transaction.""" + def __init__(self, ctx): + self.ctx = ctx + self.transaction_count = transaction_count = len(ctx.transactions) + + class transaction_engine: + """Transaction Engine used in top level transactions.""" + def do_transact(self): + ctx.commit(unload=False) + + def do_commit(self): + ctx.commit() + + def do_rollback(self): + ctx.rollback() + + class subtransaction_engine: + """Transaction Engine used in sub transactions.""" + def query(self, q): + db_cursor = ctx.db.cursor() + ctx.db_execute(db_cursor, SQLQuery(q % transaction_count)) + + def do_transact(self): + self.query('SAVEPOINT webpy_sp_%s') + + def do_commit(self): + self.query('RELEASE SAVEPOINT webpy_sp_%s') + + def do_rollback(self): + self.query('ROLLBACK TO SAVEPOINT webpy_sp_%s') + + class dummy_engine: + """Transaction Engine used instead of subtransaction_engine + when sub transactions are not supported.""" + do_transact = do_commit = do_rollback = lambda self: None + + if self.transaction_count: + # nested transactions are not supported in some databases + if self.ctx.get('ignore_nested_transactions'): + self.engine = dummy_engine() + else: + self.engine = subtransaction_engine() + else: + self.engine = transaction_engine() + + self.engine.do_transact() + self.ctx.transactions.append(self) + + def __enter__(self): + return self + + def __exit__(self, exctype, excvalue, traceback): + if exctype is not None: + self.rollback() + else: + self.commit() + + def commit(self): + if len(self.ctx.transactions) > self.transaction_count: + self.engine.do_commit() + self.ctx.transactions = self.ctx.transactions[:self.transaction_count] + + def rollback(self): + if len(self.ctx.transactions) > self.transaction_count: + self.engine.do_rollback() + self.ctx.transactions = self.ctx.transactions[:self.transaction_count] + +class DB: + """Database""" + def __init__(self, db_module, keywords): + """Creates a database. + """ + # some DB implementaions take optional paramater `driver` to use a specific driver modue + # but it should not be passed to connect + keywords.pop('driver', None) + + self.db_module = db_module + self.keywords = keywords + + self._ctx = threadeddict() + # flag to enable/disable printing queries + self.printing = config.get('debug_sql', config.get('debug', False)) + self.supports_multiple_insert = False + + try: + import DBUtils + # enable pooling if DBUtils module is available. + self.has_pooling = True + except ImportError: + self.has_pooling = False + + # Pooling can be disabled by passing pooling=False in the keywords. + self.has_pooling = self.keywords.pop('pooling', True) and self.has_pooling + + def _getctx(self): + if not self._ctx.get('db'): + self._load_context(self._ctx) + return self._ctx + ctx = property(_getctx) + + def _load_context(self, ctx): + ctx.dbq_count = 0 + ctx.transactions = [] # stack of transactions + + if self.has_pooling: + ctx.db = self._connect_with_pooling(self.keywords) + else: + ctx.db = self._connect(self.keywords) + ctx.db_execute = self._db_execute + + if not hasattr(ctx.db, 'commit'): + ctx.db.commit = lambda: None + + if not hasattr(ctx.db, 'rollback'): + ctx.db.rollback = lambda: None + + def commit(unload=True): + # do db commit and release the connection if pooling is enabled. + ctx.db.commit() + if unload and self.has_pooling: + self._unload_context(self._ctx) + + def rollback(): + # do db rollback and release the connection if pooling is enabled. + ctx.db.rollback() + if self.has_pooling: + self._unload_context(self._ctx) + + ctx.commit = commit + ctx.rollback = rollback + + def _unload_context(self, ctx): + del ctx.db + + def _connect(self, keywords): + return self.db_module.connect(**keywords) + + def _connect_with_pooling(self, keywords): + def get_pooled_db(): + from DBUtils import PooledDB + + # In DBUtils 0.9.3, `dbapi` argument is renamed as `creator` + # see Bug#122112 + + if PooledDB.__version__.split('.') < '0.9.3'.split('.'): + return PooledDB.PooledDB(dbapi=self.db_module, **keywords) + else: + return PooledDB.PooledDB(creator=self.db_module, **keywords) + + if getattr(self, '_pooleddb', None) is None: + self._pooleddb = get_pooled_db() + + return self._pooleddb.connection() + + def _db_cursor(self): + return self.ctx.db.cursor() + + def _param_marker(self): + """Returns parameter marker based on paramstyle attribute if this database.""" + style = getattr(self, 'paramstyle', 'pyformat') + + if style == 'qmark': + return '?' + elif style == 'numeric': + return ':1' + elif style in ['format', 'pyformat']: + return '%s' + raise UnknownParamstyle, style + + def _db_execute(self, cur, sql_query): + """executes an sql query""" + self.ctx.dbq_count += 1 + + try: + a = time.time() + query, params = self._process_query(sql_query) + out = cur.execute(query, params) + b = time.time() + except: + if self.printing: + print >> debug, 'ERR:', str(sql_query) + if self.ctx.transactions: + self.ctx.transactions[-1].rollback() + else: + self.ctx.rollback() + raise + + if self.printing: + print >> debug, '%s (%s): %s' % (round(b-a, 2), self.ctx.dbq_count, str(sql_query)) + return out + + def _process_query(self, sql_query): + """Takes the SQLQuery object and returns query string and parameters. + """ + paramstyle = getattr(self, 'paramstyle', 'pyformat') + query = sql_query.query(paramstyle) + params = sql_query.values() + return query, params + + def _where(self, where, vars): + if isinstance(where, (int, long)): + where = "id = " + sqlparam(where) + #@@@ for backward-compatibility + elif isinstance(where, (list, tuple)) and len(where) == 2: + where = SQLQuery(where[0], where[1]) + elif isinstance(where, SQLQuery): + pass + else: + where = reparam(where, vars) + return where + + def query(self, sql_query, vars=None, processed=False, _test=False): + """ + Execute SQL query `sql_query` using dictionary `vars` to interpolate it. + If `processed=True`, `vars` is a `reparam`-style list to use + instead of interpolating. + + >>> db = DB(None, {}) + >>> db.query("SELECT * FROM foo", _test=True) + + >>> db.query("SELECT * FROM foo WHERE x = $x", vars=dict(x='f'), _test=True) + + >>> db.query("SELECT * FROM foo WHERE x = " + sqlquote('f'), _test=True) + + """ + if vars is None: vars = {} + + if not processed and not isinstance(sql_query, SQLQuery): + sql_query = reparam(sql_query, vars) + + if _test: return sql_query + + db_cursor = self._db_cursor() + self._db_execute(db_cursor, sql_query) + + if db_cursor.description: + names = [x[0] for x in db_cursor.description] + def iterwrapper(): + row = db_cursor.fetchone() + while row: + yield storage(dict(zip(names, row))) + row = db_cursor.fetchone() + out = iterbetter(iterwrapper()) + out.__len__ = lambda: int(db_cursor.rowcount) + out.list = lambda: [storage(dict(zip(names, x))) \ + for x in db_cursor.fetchall()] + else: + out = db_cursor.rowcount + + if not self.ctx.transactions: + self.ctx.commit() + return out + + def select(self, tables, vars=None, what='*', where=None, order=None, group=None, + limit=None, offset=None, _test=False): + """ + Selects `what` from `tables` with clauses `where`, `order`, + `group`, `limit`, and `offset`. Uses vars to interpolate. + Otherwise, each clause can be a SQLQuery. + + >>> db = DB(None, {}) + >>> db.select('foo', _test=True) + + >>> db.select(['foo', 'bar'], where="foo.bar_id = bar.id", limit=5, _test=True) + + """ + if vars is None: vars = {} + sql_clauses = self.sql_clauses(what, tables, where, group, order, limit, offset) + clauses = [self.gen_clause(sql, val, vars) for sql, val in sql_clauses if val is not None] + qout = SQLQuery.join(clauses) + if _test: return qout + return self.query(qout, processed=True) + + def where(self, table, what='*', order=None, group=None, limit=None, + offset=None, _test=False, **kwargs): + """ + Selects from `table` where keys are equal to values in `kwargs`. + + >>> db = DB(None, {}) + >>> db.where('foo', bar_id=3, _test=True) + + >>> db.where('foo', source=2, crust='dewey', _test=True) + + >>> db.where('foo', _test=True) + + """ + where_clauses = [] + for k, v in kwargs.iteritems(): + where_clauses.append(k + ' = ' + sqlquote(v)) + + if where_clauses: + where = SQLQuery.join(where_clauses, " AND ") + else: + where = None + + return self.select(table, what=what, order=order, + group=group, limit=limit, offset=offset, _test=_test, + where=where) + + def sql_clauses(self, what, tables, where, group, order, limit, offset): + return ( + ('SELECT', what), + ('FROM', sqllist(tables)), + ('WHERE', where), + ('GROUP BY', group), + ('ORDER BY', order), + ('LIMIT', limit), + ('OFFSET', offset)) + + def gen_clause(self, sql, val, vars): + if isinstance(val, (int, long)): + if sql == 'WHERE': + nout = 'id = ' + sqlquote(val) + else: + nout = SQLQuery(val) + #@@@ + elif isinstance(val, (list, tuple)) and len(val) == 2: + nout = SQLQuery(val[0], val[1]) # backwards-compatibility + elif isinstance(val, SQLQuery): + nout = val + else: + nout = reparam(val, vars) + + def xjoin(a, b): + if a and b: return a + ' ' + b + else: return a or b + + return xjoin(sql, nout) + + def insert(self, tablename, seqname=None, _test=False, **values): + """ + Inserts `values` into `tablename`. Returns current sequence ID. + Set `seqname` to the ID if it's not the default, or to `False` + if there isn't one. + + >>> db = DB(None, {}) + >>> q = db.insert('foo', name='bob', age=2, created=SQLLiteral('NOW()'), _test=True) + >>> q + + >>> q.query() + 'INSERT INTO foo (age, name, created) VALUES (%s, %s, NOW())' + >>> q.values() + [2, 'bob'] + """ + def q(x): return "(" + x + ")" + + if values: + _keys = SQLQuery.join(values.keys(), ', ') + _values = SQLQuery.join([sqlparam(v) for v in values.values()], ', ') + sql_query = "INSERT INTO %s " % tablename + q(_keys) + ' VALUES ' + q(_values) + else: + sql_query = SQLQuery(self._get_insert_default_values_query(tablename)) + + if _test: return sql_query + + db_cursor = self._db_cursor() + if seqname is not False: + sql_query = self._process_insert_query(sql_query, tablename, seqname) + + if isinstance(sql_query, tuple): + # for some databases, a separate query has to be made to find + # the id of the inserted row. + q1, q2 = sql_query + self._db_execute(db_cursor, q1) + self._db_execute(db_cursor, q2) + else: + self._db_execute(db_cursor, sql_query) + + try: + out = db_cursor.fetchone()[0] + except Exception: + out = None + + if not self.ctx.transactions: + self.ctx.commit() + return out + + def _get_insert_default_values_query(self, table): + return "INSERT INTO %s DEFAULT VALUES" % table + + def multiple_insert(self, tablename, values, seqname=None, _test=False): + """ + Inserts multiple rows into `tablename`. The `values` must be a list of dictioanries, + one for each row to be inserted, each with the same set of keys. + Returns the list of ids of the inserted rows. + Set `seqname` to the ID if it's not the default, or to `False` + if there isn't one. + + >>> db = DB(None, {}) + >>> db.supports_multiple_insert = True + >>> values = [{"name": "foo", "email": "foo@example.com"}, {"name": "bar", "email": "bar@example.com"}] + >>> db.multiple_insert('person', values=values, _test=True) + + """ + if not values: + return [] + + if not self.supports_multiple_insert: + out = [self.insert(tablename, seqname=seqname, _test=_test, **v) for v in values] + if seqname is False: + return None + else: + return out + + keys = values[0].keys() + #@@ make sure all keys are valid + + # make sure all rows have same keys. + for v in values: + if v.keys() != keys: + raise ValueError, 'Bad data' + + sql_query = SQLQuery('INSERT INTO %s (%s) VALUES ' % (tablename, ', '.join(keys))) + + for i, row in enumerate(values): + if i != 0: + sql_query.append(", ") + SQLQuery.join([SQLParam(row[k]) for k in keys], sep=", ", target=sql_query, prefix="(", suffix=")") + + if _test: return sql_query + + db_cursor = self._db_cursor() + if seqname is not False: + sql_query = self._process_insert_query(sql_query, tablename, seqname) + + if isinstance(sql_query, tuple): + # for some databases, a separate query has to be made to find + # the id of the inserted row. + q1, q2 = sql_query + self._db_execute(db_cursor, q1) + self._db_execute(db_cursor, q2) + else: + self._db_execute(db_cursor, sql_query) + + try: + out = db_cursor.fetchone()[0] + out = range(out-len(values)+1, out+1) + except Exception: + out = None + + if not self.ctx.transactions: + self.ctx.commit() + return out + + + def update(self, tables, where, vars=None, _test=False, **values): + """ + Update `tables` with clause `where` (interpolated using `vars`) + and setting `values`. + + >>> db = DB(None, {}) + >>> name = 'Joseph' + >>> q = db.update('foo', where='name = $name', name='bob', age=2, + ... created=SQLLiteral('NOW()'), vars=locals(), _test=True) + >>> q + + >>> q.query() + 'UPDATE foo SET age = %s, name = %s, created = NOW() WHERE name = %s' + >>> q.values() + [2, 'bob', 'Joseph'] + """ + if vars is None: vars = {} + where = self._where(where, vars) + + query = ( + "UPDATE " + sqllist(tables) + + " SET " + sqlwhere(values, ', ') + + " WHERE " + where) + + if _test: return query + + db_cursor = self._db_cursor() + self._db_execute(db_cursor, query) + if not self.ctx.transactions: + self.ctx.commit() + return db_cursor.rowcount + + def delete(self, table, where, using=None, vars=None, _test=False): + """ + Deletes from `table` with clauses `where` and `using`. + + >>> db = DB(None, {}) + >>> name = 'Joe' + >>> db.delete('foo', where='name = $name', vars=locals(), _test=True) + + """ + if vars is None: vars = {} + where = self._where(where, vars) + + q = 'DELETE FROM ' + table + if using: q += ' USING ' + sqllist(using) + if where: q += ' WHERE ' + where + + if _test: return q + + db_cursor = self._db_cursor() + self._db_execute(db_cursor, q) + if not self.ctx.transactions: + self.ctx.commit() + return db_cursor.rowcount + + def _process_insert_query(self, query, tablename, seqname): + return query + + def transaction(self): + """Start a transaction.""" + return Transaction(self.ctx) + +class PostgresDB(DB): + """Postgres driver.""" + def __init__(self, **keywords): + if 'pw' in keywords: + keywords['password'] = keywords.pop('pw') + + db_module = import_driver(["psycopg2", "psycopg", "pgdb"], preferred=keywords.pop('driver', None)) + if db_module.__name__ == "psycopg2": + import psycopg2.extensions + psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) + + # if db is not provided postgres driver will take it from PGDATABASE environment variable + if 'db' in keywords: + keywords['database'] = keywords.pop('db') + + self.dbname = "postgres" + self.paramstyle = db_module.paramstyle + DB.__init__(self, db_module, keywords) + self.supports_multiple_insert = True + self._sequences = None + + def _process_insert_query(self, query, tablename, seqname): + if seqname is None: + # when seqname is not provided guess the seqname and make sure it exists + seqname = tablename + "_id_seq" + if seqname not in self._get_all_sequences(): + seqname = None + + if seqname: + query += "; SELECT currval('%s')" % seqname + + return query + + def _get_all_sequences(self): + """Query postgres to find names of all sequences used in this database.""" + if self._sequences is None: + q = "SELECT c.relname FROM pg_class c WHERE c.relkind = 'S'" + self._sequences = set([c.relname for c in self.query(q)]) + return self._sequences + + def _connect(self, keywords): + conn = DB._connect(self, keywords) + try: + conn.set_client_encoding('UTF8') + except AttributeError: + # fallback for pgdb driver + conn.cursor().execute("set client_encoding to 'UTF-8'") + return conn + + def _connect_with_pooling(self, keywords): + conn = DB._connect_with_pooling(self, keywords) + conn._con._con.set_client_encoding('UTF8') + return conn + +class MySQLDB(DB): + def __init__(self, **keywords): + import MySQLdb as db + if 'pw' in keywords: + keywords['passwd'] = keywords['pw'] + del keywords['pw'] + + if 'charset' not in keywords: + keywords['charset'] = 'utf8' + elif keywords['charset'] is None: + del keywords['charset'] + + self.paramstyle = db.paramstyle = 'pyformat' # it's both, like psycopg + self.dbname = "mysql" + DB.__init__(self, db, keywords) + self.supports_multiple_insert = True + + def _process_insert_query(self, query, tablename, seqname): + return query, SQLQuery('SELECT last_insert_id();') + + def _get_insert_default_values_query(self, table): + return "INSERT INTO %s () VALUES()" % table + +def import_driver(drivers, preferred=None): + """Import the first available driver or preferred driver. + """ + if preferred: + drivers = [preferred] + + for d in drivers: + try: + return __import__(d, None, None, ['x']) + except ImportError: + pass + raise ImportError("Unable to import " + " or ".join(drivers)) + +class SqliteDB(DB): + def __init__(self, **keywords): + db = import_driver(["sqlite3", "pysqlite2.dbapi2", "sqlite"], preferred=keywords.pop('driver', None)) + + if db.__name__ in ["sqlite3", "pysqlite2.dbapi2"]: + db.paramstyle = 'qmark' + + # sqlite driver doesn't create datatime objects for timestamp columns unless `detect_types` option is passed. + # It seems to be supported in sqlite3 and pysqlite2 drivers, not surte about sqlite. + keywords.setdefault('detect_types', db.PARSE_DECLTYPES) + + self.paramstyle = db.paramstyle + keywords['database'] = keywords.pop('db') + keywords['pooling'] = False # sqlite don't allows connections to be shared by threads + self.dbname = "sqlite" + DB.__init__(self, db, keywords) + + def _process_insert_query(self, query, tablename, seqname): + return query, SQLQuery('SELECT last_insert_rowid();') + + def query(self, *a, **kw): + out = DB.query(self, *a, **kw) + if isinstance(out, iterbetter): + del out.__len__ + return out + +class FirebirdDB(DB): + """Firebird Database. + """ + def __init__(self, **keywords): + try: + import kinterbasdb as db + except Exception: + db = None + pass + if 'pw' in keywords: + keywords['passwd'] = keywords['pw'] + del keywords['pw'] + keywords['database'] = keywords['db'] + del keywords['db'] + DB.__init__(self, db, keywords) + + def delete(self, table, where=None, using=None, vars=None, _test=False): + # firebird doesn't support using clause + using=None + return DB.delete(self, table, where, using, vars, _test) + + def sql_clauses(self, what, tables, where, group, order, limit, offset): + return ( + ('SELECT', ''), + ('FIRST', limit), + ('SKIP', offset), + ('', what), + ('FROM', sqllist(tables)), + ('WHERE', where), + ('GROUP BY', group), + ('ORDER BY', order) + ) + +class MSSQLDB(DB): + def __init__(self, **keywords): + import pymssql as db + if 'pw' in keywords: + keywords['password'] = keywords.pop('pw') + keywords['database'] = keywords.pop('db') + self.dbname = "mssql" + DB.__init__(self, db, keywords) + + def _process_query(self, sql_query): + """Takes the SQLQuery object and returns query string and parameters. + """ + # MSSQLDB expects params to be a tuple. + # Overwriting the default implementation to convert params to tuple. + paramstyle = getattr(self, 'paramstyle', 'pyformat') + query = sql_query.query(paramstyle) + params = sql_query.values() + return query, tuple(params) + + def sql_clauses(self, what, tables, where, group, order, limit, offset): + return ( + ('SELECT', what), + ('TOP', limit), + ('FROM', sqllist(tables)), + ('WHERE', where), + ('GROUP BY', group), + ('ORDER BY', order), + ('OFFSET', offset)) + + def _test(self): + """Test LIMIT. + + Fake presence of pymssql module for running tests. + >>> import sys + >>> sys.modules['pymssql'] = sys.modules['sys'] + + MSSQL has TOP clause instead of LIMIT clause. + >>> db = MSSQLDB(db='test', user='joe', pw='secret') + >>> db.select('foo', limit=4, _test=True) + + """ + pass + +class OracleDB(DB): + def __init__(self, **keywords): + import cx_Oracle as db + if 'pw' in keywords: + keywords['password'] = keywords.pop('pw') + + #@@ TODO: use db.makedsn if host, port is specified + keywords['dsn'] = keywords.pop('db') + self.dbname = 'oracle' + db.paramstyle = 'numeric' + self.paramstyle = db.paramstyle + + # oracle doesn't support pooling + keywords.pop('pooling', None) + DB.__init__(self, db, keywords) + + def _process_insert_query(self, query, tablename, seqname): + if seqname is None: + # It is not possible to get seq name from table name in Oracle + return query + else: + return query + "; SELECT %s.currval FROM dual" % seqname + +_databases = {} +def database(dburl=None, **params): + """Creates appropriate database using params. + + Pooling will be enabled if DBUtils module is available. + Pooling can be disabled by passing pooling=False in params. + """ + dbn = params.pop('dbn') + if dbn in _databases: + return _databases[dbn](**params) + else: + raise UnknownDB, dbn + +def register_database(name, clazz): + """ + Register a database. + + >>> class LegacyDB(DB): + ... def __init__(self, **params): + ... pass + ... + >>> register_database('legacy', LegacyDB) + >>> db = database(dbn='legacy', db='test', user='joe', passwd='secret') + """ + _databases[name] = clazz + +register_database('mysql', MySQLDB) +register_database('postgres', PostgresDB) +register_database('sqlite', SqliteDB) +register_database('firebird', FirebirdDB) +register_database('mssql', MSSQLDB) +register_database('oracle', OracleDB) + +def _interpolate(format): + """ + Takes a format string and returns a list of 2-tuples of the form + (boolean, string) where boolean says whether string should be evaled + or not. + + from (public domain, Ka-Ping Yee) + """ + from tokenize import tokenprog + + def matchorfail(text, pos): + match = tokenprog.match(text, pos) + if match is None: + raise _ItplError(text, pos) + return match, match.end() + + namechars = "abcdefghijklmnopqrstuvwxyz" \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; + chunks = [] + pos = 0 + + while 1: + dollar = format.find("$", pos) + if dollar < 0: + break + nextchar = format[dollar + 1] + + if nextchar == "{": + chunks.append((0, format[pos:dollar])) + pos, level = dollar + 2, 1 + while level: + match, pos = matchorfail(format, pos) + tstart, tend = match.regs[3] + token = format[tstart:tend] + if token == "{": + level = level + 1 + elif token == "}": + level = level - 1 + chunks.append((1, format[dollar + 2:pos - 1])) + + elif nextchar in namechars: + chunks.append((0, format[pos:dollar])) + match, pos = matchorfail(format, dollar + 1) + while pos < len(format): + if format[pos] == "." and \ + pos + 1 < len(format) and format[pos + 1] in namechars: + match, pos = matchorfail(format, pos + 1) + elif format[pos] in "([": + pos, level = pos + 1, 1 + while level: + match, pos = matchorfail(format, pos) + tstart, tend = match.regs[3] + token = format[tstart:tend] + if token[0] in "([": + level = level + 1 + elif token[0] in ")]": + level = level - 1 + else: + break + chunks.append((1, format[dollar + 1:pos])) + else: + chunks.append((0, format[pos:dollar + 1])) + pos = dollar + 1 + (nextchar == "$") + + if pos < len(format): + chunks.append((0, format[pos:])) + return chunks + +if __name__ == "__main__": + import doctest + doctest.testmod() diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/debugerror.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/debugerror.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,354 @@ +""" +pretty debug errors +(part of web.py) + +portions adapted from Django +Copyright (c) 2005, the Lawrence Journal-World +Used under the modified BSD license: +http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 +""" + +__all__ = ["debugerror", "djangoerror", "emailerrors"] + +import sys, urlparse, pprint, traceback +from template import Template +from net import websafe +from utils import sendmail, safestr +import webapi as web + +import os, os.path +whereami = os.path.join(os.getcwd(), __file__) +whereami = os.path.sep.join(whereami.split(os.path.sep)[:-1]) +djangoerror_t = """\ +$def with (exception_type, exception_value, frames) + + + + + + $exception_type at $ctx.path + + + + + +$def dicttable (d, kls='req', id=None): + $ items = d and d.items() or [] + $items.sort() + $:dicttable_items(items, kls, id) + +$def dicttable_items(items, kls='req', id=None): + $if items: + + + $for k, v in items: + + +
VariableValue
$k
$prettify(v)
+ $else: +

No data.

+ +
+

$exception_type at $ctx.path

+

$exception_value

+ + + + + + +
Python$frames[0].filename in $frames[0].function, line $frames[0].lineno
Web$ctx.method $ctx.home$ctx.path
+
+
+

Traceback (innermost first)

+
    +$for frame in frames: +
  • + $frame.filename in $frame.function + $if frame.context_line is not None: +
    + $if frame.pre_context: +
      + $for line in frame.pre_context: +
    1. $line
    2. +
    +
    1. $frame.context_line ...
    + $if frame.post_context: +
      + $for line in frame.post_context: +
    1. $line
    2. +
    +
    + + $if frame.vars: +
    + Local vars + $# $inspect.formatargvalues(*inspect.getargvalues(frame['tb'].tb_frame)) +
    + $:dicttable(frame.vars, kls='vars', id=('v' + str(frame.id))) +
  • +
+
+ +
+$if ctx.output or ctx.headers: +

Response so far

+

HEADERS

+ $:dicttable_items(ctx.headers) + +

BODY

+

+ $ctx.output +

+ +

Request information

+ +

INPUT

+$:dicttable(web.input(_unicode=False)) + + +$:dicttable(web.cookies()) + +

META

+$ newctx = [(k, v) for (k, v) in ctx.iteritems() if not k.startswith('_') and not isinstance(v, dict)] +$:dicttable(dict(newctx)) + +

ENVIRONMENT

+$:dicttable(ctx.env) +
+ +
+

+ You're seeing this error because you have web.config.debug + set to True. Set that to False if you don't want to see this. +

+
+ + + +""" + +djangoerror_r = None + +def djangoerror(): + def _get_lines_from_file(filename, lineno, context_lines): + """ + Returns context_lines before and after lineno from file. + Returns (pre_context_lineno, pre_context, context_line, post_context). + """ + try: + source = open(filename).readlines() + lower_bound = max(0, lineno - context_lines) + upper_bound = lineno + context_lines + + pre_context = \ + [line.strip('\n') for line in source[lower_bound:lineno]] + context_line = source[lineno].strip('\n') + post_context = \ + [line.strip('\n') for line in source[lineno + 1:upper_bound]] + + return lower_bound, pre_context, context_line, post_context + except (OSError, IOError, IndexError): + return None, [], None, [] + + exception_type, exception_value, tback = sys.exc_info() + frames = [] + while tback is not None: + filename = tback.tb_frame.f_code.co_filename + function = tback.tb_frame.f_code.co_name + lineno = tback.tb_lineno - 1 + + # hack to get correct line number for templates + lineno += tback.tb_frame.f_locals.get("__lineoffset__", 0) + + pre_context_lineno, pre_context, context_line, post_context = \ + _get_lines_from_file(filename, lineno, 7) + + if '__hidetraceback__' not in tback.tb_frame.f_locals: + frames.append(web.storage({ + 'tback': tback, + 'filename': filename, + 'function': function, + 'lineno': lineno, + 'vars': tback.tb_frame.f_locals, + 'id': id(tback), + 'pre_context': pre_context, + 'context_line': context_line, + 'post_context': post_context, + 'pre_context_lineno': pre_context_lineno, + })) + tback = tback.tb_next + frames.reverse() + urljoin = urlparse.urljoin + def prettify(x): + try: + out = pprint.pformat(x) + except Exception, e: + out = '[could not display: <' + e.__class__.__name__ + \ + ': '+str(e)+'>]' + return out + + global djangoerror_r + if djangoerror_r is None: + djangoerror_r = Template(djangoerror_t, filename=__file__, filter=websafe) + + t = djangoerror_r + globals = {'ctx': web.ctx, 'web':web, 'dict':dict, 'str':str, 'prettify': prettify} + t.t.func_globals.update(globals) + return t(exception_type, exception_value, frames) + +def debugerror(): + """ + A replacement for `internalerror` that presents a nice page with lots + of debug information for the programmer. + + (Based on the beautiful 500 page from [Django](http://djangoproject.com/), + designed by [Wilson Miner](http://wilsonminer.com/).) + """ + return web._InternalError(djangoerror()) + +def emailerrors(to_address, olderror, from_address=None): + """ + Wraps the old `internalerror` handler (pass as `olderror`) to + additionally email all errors to `to_address`, to aid in + debugging production websites. + + Emails contain a normal text traceback as well as an + attachment containing the nice `debugerror` page. + """ + from_address = from_address or to_address + + def emailerrors_internal(): + error = olderror() + tb = sys.exc_info() + error_name = tb[0] + error_value = tb[1] + tb_txt = ''.join(traceback.format_exception(*tb)) + path = web.ctx.path + request = web.ctx.method + ' ' + web.ctx.home + web.ctx.fullpath + + message = "\n%s\n\n%s\n\n" % (request, tb_txt) + + sendmail( + "your buggy site <%s>" % from_address, + "the bugfixer <%s>" % to_address, + "bug: %(error_name)s: %(error_value)s (%(path)s)" % locals(), + message, + attachments=[ + dict(filename="bug.html", content=safestr(djangoerror())) + ], + ) + return error + + return emailerrors_internal + +if __name__ == "__main__": + urls = ( + '/', 'index' + ) + from application import application + app = application(urls, globals()) + app.internalerror = debugerror + + class index: + def GET(self): + thisdoesnotexist + + app.run() diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/form.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/form.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,410 @@ +""" +HTML forms +(part of web.py) +""" + +import copy, re +import webapi as web +import utils, net + +def attrget(obj, attr, value=None): + try: + if hasattr(obj, 'has_key') and obj.has_key(attr): + return obj[attr] + except TypeError: + # Handle the case where has_key takes different number of arguments. + # This is the case with Model objects on appengine. See #134 + pass + if hasattr(obj, attr): + return getattr(obj, attr) + return value + +class Form(object): + r""" + HTML form. + + >>> f = Form(Textbox("x")) + >>> f.render() + u'\n \n
' + """ + def __init__(self, *inputs, **kw): + self.inputs = inputs + self.valid = True + self.note = None + self.validators = kw.pop('validators', []) + + def __call__(self, x=None): + o = copy.deepcopy(self) + if x: o.validates(x) + return o + + def render(self): + out = '' + out += self.rendernote(self.note) + out += '\n' + + for i in self.inputs: + html = utils.safeunicode(i.pre) + i.render() + self.rendernote(i.note) + utils.safeunicode(i.post) + if i.is_hidden(): + out += ' \n' % (html) + else: + out += ' \n' % (i.id, net.websafe(i.description), html) + out += "
%s
%s
" + return out + + def render_css(self): + out = [] + out.append(self.rendernote(self.note)) + for i in self.inputs: + if not i.is_hidden(): + out.append('' % (i.id, net.websafe(i.description))) + out.append(i.pre) + out.append(i.render()) + out.append(self.rendernote(i.note)) + out.append(i.post) + out.append('\n') + return ''.join(out) + + def rendernote(self, note): + if note: return '%s' % net.websafe(note) + else: return "" + + def validates(self, source=None, _validate=True, **kw): + source = source or kw or web.input() + out = True + for i in self.inputs: + v = attrget(source, i.name) + if _validate: + out = i.validate(v) and out + else: + i.set_value(v) + if _validate: + out = out and self._validate(source) + self.valid = out + return out + + def _validate(self, value): + self.value = value + for v in self.validators: + if not v.valid(value): + self.note = v.msg + return False + return True + + def fill(self, source=None, **kw): + return self.validates(source, _validate=False, **kw) + + def __getitem__(self, i): + for x in self.inputs: + if x.name == i: return x + raise KeyError, i + + def __getattr__(self, name): + # don't interfere with deepcopy + inputs = self.__dict__.get('inputs') or [] + for x in inputs: + if x.name == name: return x + raise AttributeError, name + + def get(self, i, default=None): + try: + return self[i] + except KeyError: + return default + + def _get_d(self): #@@ should really be form.attr, no? + return utils.storage([(i.name, i.get_value()) for i in self.inputs]) + d = property(_get_d) + +class Input(object): + def __init__(self, name, *validators, **attrs): + self.name = name + self.validators = validators + self.attrs = attrs = AttributeList(attrs) + + self.description = attrs.pop('description', name) + self.value = attrs.pop('value', None) + self.pre = attrs.pop('pre', "") + self.post = attrs.pop('post', "") + self.note = None + + self.id = attrs.setdefault('id', self.get_default_id()) + + if 'class_' in attrs: + attrs['class'] = attrs['class_'] + del attrs['class_'] + + def is_hidden(self): + return False + + def get_type(self): + raise NotImplementedError + + def get_default_id(self): + return self.name + + def validate(self, value): + self.set_value(value) + + for v in self.validators: + if not v.valid(value): + self.note = v.msg + return False + return True + + def set_value(self, value): + self.value = value + + def get_value(self): + return self.value + + def render(self): + attrs = self.attrs.copy() + attrs['type'] = self.get_type() + if self.value is not None: + attrs['value'] = self.value + attrs['name'] = self.name + return '' % attrs + + def rendernote(self, note): + if note: return '%s' % net.websafe(note) + else: return "" + + def addatts(self): + # add leading space for backward-compatibility + return " " + str(self.attrs) + +class AttributeList(dict): + """List of atributes of input. + + >>> a = AttributeList(type='text', name='x', value=20) + >>> a + + """ + def copy(self): + return AttributeList(self) + + def __str__(self): + return " ".join(['%s="%s"' % (k, net.websafe(v)) for k, v in self.items()]) + + def __repr__(self): + return '' % repr(str(self)) + +class Textbox(Input): + """Textbox input. + + >>> Textbox(name='foo', value='bar').render() + u'' + >>> Textbox(name='foo', value=0).render() + u'' + """ + def get_type(self): + return 'text' + +class Password(Input): + """Password input. + + >>> Password(name='password', value='secret').render() + u'' + """ + + def get_type(self): + return 'password' + +class Textarea(Input): + """Textarea input. + + >>> Textarea(name='foo', value='bar').render() + u'' + """ + def render(self): + attrs = self.attrs.copy() + attrs['name'] = self.name + value = net.websafe(self.value or '') + return '' % (attrs, value) + +class Dropdown(Input): + r"""Dropdown/select input. + + >>> Dropdown(name='foo', args=['a', 'b', 'c'], value='b').render() + u'\n' + >>> Dropdown(name='foo', args=[('a', 'aa'), ('b', 'bb'), ('c', 'cc')], value='b').render() + u'\n' + """ + def __init__(self, name, args, *validators, **attrs): + self.args = args + super(Dropdown, self).__init__(name, *validators, **attrs) + + def render(self): + attrs = self.attrs.copy() + attrs['name'] = self.name + + x = '\n' + return x + + def _render_option(self, arg, indent=' '): + if isinstance(arg, (tuple, list)): + value, desc= arg + else: + value, desc = arg, arg + + if self.value == value or (isinstance(self.value, list) and value in self.value): + select_p = ' selected="selected"' + else: + select_p = '' + return indent + '%s\n' % (select_p, net.websafe(value), net.websafe(desc)) + + +class GroupedDropdown(Dropdown): + r"""Grouped Dropdown/select input. + + >>> GroupedDropdown(name='car_type', args=(('Swedish Cars', ('Volvo', 'Saab')), ('German Cars', ('Mercedes', 'Audi'))), value='Audi').render() + u'\n' + >>> GroupedDropdown(name='car_type', args=(('Swedish Cars', (('v', 'Volvo'), ('s', 'Saab'))), ('German Cars', (('m', 'Mercedes'), ('a', 'Audi')))), value='a').render() + u'\n' + + """ + def __init__(self, name, args, *validators, **attrs): + self.args = args + super(Dropdown, self).__init__(name, *validators, **attrs) + + def render(self): + attrs = self.attrs.copy() + attrs['name'] = self.name + + x = '\n' + return x + +class Radio(Input): + def __init__(self, name, args, *validators, **attrs): + self.args = args + super(Radio, self).__init__(name, *validators, **attrs) + + def render(self): + x = '' + for arg in self.args: + if isinstance(arg, (tuple, list)): + value, desc= arg + else: + value, desc = arg, arg + attrs = self.attrs.copy() + attrs['name'] = self.name + attrs['type'] = 'radio' + attrs['value'] = value + if self.value == value: + attrs['checked'] = 'checked' + x += ' %s' % (attrs, net.websafe(desc)) + x += '' + return x + +class Checkbox(Input): + """Checkbox input. + + >>> Checkbox('foo', value='bar', checked=True).render() + u'' + >>> Checkbox('foo', value='bar').render() + u'' + >>> c = Checkbox('foo', value='bar') + >>> c.validate('on') + True + >>> c.render() + u'' + """ + def __init__(self, name, *validators, **attrs): + self.checked = attrs.pop('checked', False) + Input.__init__(self, name, *validators, **attrs) + + def get_default_id(self): + value = utils.safestr(self.value or "") + return self.name + '_' + value.replace(' ', '_') + + def render(self): + attrs = self.attrs.copy() + attrs['type'] = 'checkbox' + attrs['name'] = self.name + attrs['value'] = self.value + + if self.checked: + attrs['checked'] = 'checked' + return '' % attrs + + def set_value(self, value): + self.checked = bool(value) + + def get_value(self): + return self.checked + +class Button(Input): + """HTML Button. + + >>> Button("save").render() + u'' + >>> Button("action", value="save", html="Save Changes").render() + u'' + """ + def __init__(self, name, *validators, **attrs): + super(Button, self).__init__(name, *validators, **attrs) + self.description = "" + + def render(self): + attrs = self.attrs.copy() + attrs['name'] = self.name + if self.value is not None: + attrs['value'] = self.value + html = attrs.pop('html', None) or net.websafe(self.name) + return '' % (attrs, html) + +class Hidden(Input): + """Hidden Input. + + >>> Hidden(name='foo', value='bar').render() + u'' + """ + def is_hidden(self): + return True + + def get_type(self): + return 'hidden' + +class File(Input): + """File input. + + >>> File(name='f').render() + u'' + """ + def get_type(self): + return 'file' + +class Validator: + def __deepcopy__(self, memo): return copy.copy(self) + def __init__(self, msg, test, jstest=None): utils.autoassign(self, locals()) + def valid(self, value): + try: return self.test(value) + except: return False + +notnull = Validator("Required", bool) + +class regexp(Validator): + def __init__(self, rexp, msg): + self.rexp = re.compile(rexp) + self.msg = msg + + def valid(self, value): + return bool(self.rexp.match(value)) + +if __name__ == "__main__": + import doctest + doctest.testmod() diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/http.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/http.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,150 @@ +""" +HTTP Utilities +(from web.py) +""" + +__all__ = [ + "expires", "lastmodified", + "prefixurl", "modified", + "changequery", "url", + "profiler", +] + +import sys, os, threading, urllib, urlparse +try: import datetime +except ImportError: pass +import net, utils, webapi as web + +def prefixurl(base=''): + """ + Sorry, this function is really difficult to explain. + Maybe some other time. + """ + url = web.ctx.path.lstrip('/') + for i in xrange(url.count('/')): + base += '../' + if not base: + base = './' + return base + +def expires(delta): + """ + Outputs an `Expires` header for `delta` from now. + `delta` is a `timedelta` object or a number of seconds. + """ + if isinstance(delta, (int, long)): + delta = datetime.timedelta(seconds=delta) + date_obj = datetime.datetime.utcnow() + delta + web.header('Expires', net.httpdate(date_obj)) + +def lastmodified(date_obj): + """Outputs a `Last-Modified` header for `datetime`.""" + web.header('Last-Modified', net.httpdate(date_obj)) + +def modified(date=None, etag=None): + """ + Checks to see if the page has been modified since the version in the + requester's cache. + + When you publish pages, you can include `Last-Modified` and `ETag` + with the date the page was last modified and an opaque token for + the particular version, respectively. When readers reload the page, + the browser sends along the modification date and etag value for + the version it has in its cache. If the page hasn't changed, + the server can just return `304 Not Modified` and not have to + send the whole page again. + + This function takes the last-modified date `date` and the ETag `etag` + and checks the headers to see if they match. If they do, it returns + `True`, or otherwise it raises NotModified error. It also sets + `Last-Modified` and `ETag` output headers. + """ + try: + from __builtin__ import set + except ImportError: + # for python 2.3 + from sets import Set as set + + n = set([x.strip('" ') for x in web.ctx.env.get('HTTP_IF_NONE_MATCH', '').split(',')]) + m = net.parsehttpdate(web.ctx.env.get('HTTP_IF_MODIFIED_SINCE', '').split(';')[0]) + validate = False + if etag: + if '*' in n or etag in n: + validate = True + if date and m: + # we subtract a second because + # HTTP dates don't have sub-second precision + if date-datetime.timedelta(seconds=1) <= m: + validate = True + + if date: lastmodified(date) + if etag: web.header('ETag', '"' + etag + '"') + if validate: + raise web.notmodified() + else: + return True + +def urlencode(query, doseq=0): + """ + Same as urllib.urlencode, but supports unicode strings. + + >>> urlencode({'text':'foo bar'}) + 'text=foo+bar' + >>> urlencode({'x': [1, 2]}, doseq=True) + 'x=1&x=2' + """ + def convert(value, doseq=False): + if doseq and isinstance(value, list): + return [convert(v) for v in value] + else: + return utils.safestr(value) + + query = dict([(k, convert(v, doseq)) for k, v in query.items()]) + return urllib.urlencode(query, doseq=doseq) + +def changequery(query=None, **kw): + """ + Imagine you're at `/foo?a=1&b=2`. Then `changequery(a=3)` will return + `/foo?a=3&b=2` -- the same URL but with the arguments you requested + changed. + """ + if query is None: + query = web.rawinput(method='get') + for k, v in kw.iteritems(): + if v is None: + query.pop(k, None) + else: + query[k] = v + out = web.ctx.path + if query: + out += '?' + urlencode(query, doseq=True) + return out + +def url(path=None, doseq=False, **kw): + """ + Makes url by concatenating web.ctx.homepath and path and the + query string created using the arguments. + """ + if path is None: + path = web.ctx.path + if path.startswith("/"): + out = web.ctx.homepath + path + else: + out = path + + if kw: + out += '?' + urlencode(kw, doseq=doseq) + + return out + +def profiler(app): + """Outputs basic profiling information at the bottom of each response.""" + from utils import profile + def profile_internal(e, o): + out, result = profile(app)(e, o) + return list(out) + ['
' + net.websafe(result) + '
'] + return profile_internal + +if __name__ == "__main__": + import doctest + doctest.testmod() diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/httpserver.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/httpserver.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,319 @@ +__all__ = ["runsimple"] + +import sys, os +from SimpleHTTPServer import SimpleHTTPRequestHandler +import urllib +import posixpath + +import webapi as web +import net +import utils + +def runbasic(func, server_address=("0.0.0.0", 8080)): + """ + Runs a simple HTTP server hosting WSGI app `func`. The directory `static/` + is hosted statically. + + Based on [WsgiServer][ws] from [Colin Stewart][cs]. + + [ws]: http://www.owlfish.com/software/wsgiutils/documentation/wsgi-server-api.html + [cs]: http://www.owlfish.com/ + """ + # Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/) + # Modified somewhat for simplicity + # Used under the modified BSD license: + # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 + + import SimpleHTTPServer, SocketServer, BaseHTTPServer, urlparse + import socket, errno + import traceback + + class WSGIHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + def run_wsgi_app(self): + protocol, host, path, parameters, query, fragment = \ + urlparse.urlparse('http://dummyhost%s' % self.path) + + # we only use path, query + env = {'wsgi.version': (1, 0) + ,'wsgi.url_scheme': 'http' + ,'wsgi.input': self.rfile + ,'wsgi.errors': sys.stderr + ,'wsgi.multithread': 1 + ,'wsgi.multiprocess': 0 + ,'wsgi.run_once': 0 + ,'REQUEST_METHOD': self.command + ,'REQUEST_URI': self.path + ,'PATH_INFO': path + ,'QUERY_STRING': query + ,'CONTENT_TYPE': self.headers.get('Content-Type', '') + ,'CONTENT_LENGTH': self.headers.get('Content-Length', '') + ,'REMOTE_ADDR': self.client_address[0] + ,'SERVER_NAME': self.server.server_address[0] + ,'SERVER_PORT': str(self.server.server_address[1]) + ,'SERVER_PROTOCOL': self.request_version + } + + for http_header, http_value in self.headers.items(): + env ['HTTP_%s' % http_header.replace('-', '_').upper()] = \ + http_value + + # Setup the state + self.wsgi_sent_headers = 0 + self.wsgi_headers = [] + + try: + # We have there environment, now invoke the application + result = self.server.app(env, self.wsgi_start_response) + try: + try: + for data in result: + if data: + self.wsgi_write_data(data) + finally: + if hasattr(result, 'close'): + result.close() + except socket.error, socket_err: + # Catch common network errors and suppress them + if (socket_err.args[0] in \ + (errno.ECONNABORTED, errno.EPIPE)): + return + except socket.timeout, socket_timeout: + return + except: + print >> web.debug, traceback.format_exc(), + + if (not self.wsgi_sent_headers): + # We must write out something! + self.wsgi_write_data(" ") + return + + do_POST = run_wsgi_app + do_PUT = run_wsgi_app + do_DELETE = run_wsgi_app + + def do_GET(self): + if self.path.startswith('/static/'): + SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) + else: + self.run_wsgi_app() + + def wsgi_start_response(self, response_status, response_headers, + exc_info=None): + if (self.wsgi_sent_headers): + raise Exception \ + ("Headers already sent and start_response called again!") + # Should really take a copy to avoid changes in the application.... + self.wsgi_headers = (response_status, response_headers) + return self.wsgi_write_data + + def wsgi_write_data(self, data): + if (not self.wsgi_sent_headers): + status, headers = self.wsgi_headers + # Need to send header prior to data + status_code = status[:status.find(' ')] + status_msg = status[status.find(' ') + 1:] + self.send_response(int(status_code), status_msg) + for header, value in headers: + self.send_header(header, value) + self.end_headers() + self.wsgi_sent_headers = 1 + # Send the data + self.wfile.write(data) + + class WSGIServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): + def __init__(self, func, server_address): + BaseHTTPServer.HTTPServer.__init__(self, + server_address, + WSGIHandler) + self.app = func + self.serverShuttingDown = 0 + + print "http://%s:%d/" % server_address + WSGIServer(func, server_address).serve_forever() + +# The WSGIServer instance. +# Made global so that it can be stopped in embedded mode. +server = None + +def runsimple(func, server_address=("0.0.0.0", 8080)): + """ + Runs [CherryPy][cp] WSGI server hosting WSGI app `func`. + The directory `static/` is hosted statically. + + [cp]: http://www.cherrypy.org + """ + global server + func = StaticMiddleware(func) + func = LogMiddleware(func) + + server = WSGIServer(server_address, func) + + if server.ssl_adapter: + print "https://%s:%d/" % server_address + else: + print "http://%s:%d/" % server_address + + try: + server.start() + except (KeyboardInterrupt, SystemExit): + server.stop() + server = None + +def WSGIServer(server_address, wsgi_app): + """Creates CherryPy WSGI server listening at `server_address` to serve `wsgi_app`. + This function can be overwritten to customize the webserver or use a different webserver. + """ + import wsgiserver + + # Default values of wsgiserver.ssl_adapters uses cherrypy.wsgiserver + # prefix. Overwriting it make it work with web.wsgiserver. + wsgiserver.ssl_adapters = { + 'builtin': 'web.wsgiserver.ssl_builtin.BuiltinSSLAdapter', + 'pyopenssl': 'web.wsgiserver.ssl_pyopenssl.pyOpenSSLAdapter', + } + + server = wsgiserver.CherryPyWSGIServer(server_address, wsgi_app, server_name="localhost") + + def create_ssl_adapter(cert, key): + # wsgiserver tries to import submodules as cherrypy.wsgiserver.foo. + # That doesn't work as not it is web.wsgiserver. + # Patching sys.modules temporarily to make it work. + import types + cherrypy = types.ModuleType('cherrypy') + cherrypy.wsgiserver = wsgiserver + sys.modules['cherrypy'] = cherrypy + sys.modules['cherrypy.wsgiserver'] = wsgiserver + + from wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter + adapter = pyOpenSSLAdapter(cert, key) + + # We are done with our work. Cleanup the patches. + del sys.modules['cherrypy'] + del sys.modules['cherrypy.wsgiserver'] + + return adapter + + # SSL backward compatibility + if (server.ssl_adapter is None and + getattr(server, 'ssl_certificate', None) and + getattr(server, 'ssl_private_key', None)): + server.ssl_adapter = create_ssl_adapter(server.ssl_certificate, server.ssl_private_key) + + server.nodelay = not sys.platform.startswith('java') # TCP_NODELAY isn't supported on the JVM + return server + +class StaticApp(SimpleHTTPRequestHandler): + """WSGI application for serving static files.""" + def __init__(self, environ, start_response): + self.headers = [] + self.environ = environ + self.start_response = start_response + + def send_response(self, status, msg=""): + self.status = str(status) + " " + msg + + def send_header(self, name, value): + self.headers.append((name, value)) + + def end_headers(self): + pass + + def log_message(*a): pass + + def __iter__(self): + environ = self.environ + + self.path = environ.get('PATH_INFO', '') + self.client_address = environ.get('REMOTE_ADDR','-'), \ + environ.get('REMOTE_PORT','-') + self.command = environ.get('REQUEST_METHOD', '-') + + from cStringIO import StringIO + self.wfile = StringIO() # for capturing error + + try: + path = self.translate_path(self.path) + etag = '"%s"' % os.path.getmtime(path) + client_etag = environ.get('HTTP_IF_NONE_MATCH') + self.send_header('ETag', etag) + if etag == client_etag: + self.send_response(304, "Not Modified") + self.start_response(self.status, self.headers) + raise StopIteration + except OSError: + pass # Probably a 404 + + f = self.send_head() + self.start_response(self.status, self.headers) + + if f: + block_size = 16 * 1024 + while True: + buf = f.read(block_size) + if not buf: + break + yield buf + f.close() + else: + value = self.wfile.getvalue() + yield value + +class StaticMiddleware: + """WSGI middleware for serving static files.""" + def __init__(self, app, prefix='/static/'): + self.app = app + self.prefix = prefix + + def __call__(self, environ, start_response): + path = environ.get('PATH_INFO', '') + path = self.normpath(path) + + if path.startswith(self.prefix): + return StaticApp(environ, start_response) + else: + return self.app(environ, start_response) + + def normpath(self, path): + path2 = posixpath.normpath(urllib.unquote(path)) + if path.endswith("/"): + path2 += "/" + return path2 + + +class LogMiddleware: + """WSGI middleware for logging the status.""" + def __init__(self, app): + self.app = app + self.format = '%s - - [%s] "%s %s %s" - %s' + + from BaseHTTPServer import BaseHTTPRequestHandler + import StringIO + f = StringIO.StringIO() + + class FakeSocket: + def makefile(self, *a): + return f + + # take log_date_time_string method from BaseHTTPRequestHandler + self.log_date_time_string = BaseHTTPRequestHandler(FakeSocket(), None, None).log_date_time_string + + def __call__(self, environ, start_response): + def xstart_response(status, response_headers, *args): + out = start_response(status, response_headers, *args) + self.log(status, environ) + return out + + return self.app(environ, xstart_response) + + def log(self, status, environ): + outfile = environ.get('wsgi.errors', web.debug) + req = environ.get('PATH_INFO', '_') + protocol = environ.get('ACTUAL_SERVER_PROTOCOL', '-') + method = environ.get('REQUEST_METHOD', '-') + host = "%s:%s" % (environ.get('REMOTE_ADDR','-'), + environ.get('REMOTE_PORT','-')) + + time = self.log_date_time_string() + + msg = self.format % (host, time, protocol, method, req, status) + print >> outfile, utils.safestr(msg) diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/net.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/net.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,193 @@ +""" +Network Utilities +(from web.py) +""" + +__all__ = [ + "validipaddr", "validipport", "validip", "validaddr", + "urlquote", + "httpdate", "parsehttpdate", + "htmlquote", "htmlunquote", "websafe", +] + +import urllib, time +try: import datetime +except ImportError: pass + +def validipaddr(address): + """ + Returns True if `address` is a valid IPv4 address. + + >>> validipaddr('192.168.1.1') + True + >>> validipaddr('192.168.1.800') + False + >>> validipaddr('192.168.1') + False + """ + try: + octets = address.split('.') + if len(octets) != 4: + return False + for x in octets: + if not (0 <= int(x) <= 255): + return False + except ValueError: + return False + return True + +def validipport(port): + """ + Returns True if `port` is a valid IPv4 port. + + >>> validipport('9000') + True + >>> validipport('foo') + False + >>> validipport('1000000') + False + """ + try: + if not (0 <= int(port) <= 65535): + return False + except ValueError: + return False + return True + +def validip(ip, defaultaddr="0.0.0.0", defaultport=8080): + """Returns `(ip_address, port)` from string `ip_addr_port`""" + addr = defaultaddr + port = defaultport + + ip = ip.split(":", 1) + if len(ip) == 1: + if not ip[0]: + pass + elif validipaddr(ip[0]): + addr = ip[0] + elif validipport(ip[0]): + port = int(ip[0]) + else: + raise ValueError, ':'.join(ip) + ' is not a valid IP address/port' + elif len(ip) == 2: + addr, port = ip + if not validipaddr(addr) and validipport(port): + raise ValueError, ':'.join(ip) + ' is not a valid IP address/port' + port = int(port) + else: + raise ValueError, ':'.join(ip) + ' is not a valid IP address/port' + return (addr, port) + +def validaddr(string_): + """ + Returns either (ip_address, port) or "/path/to/socket" from string_ + + >>> validaddr('/path/to/socket') + '/path/to/socket' + >>> validaddr('8000') + ('0.0.0.0', 8000) + >>> validaddr('127.0.0.1') + ('127.0.0.1', 8080) + >>> validaddr('127.0.0.1:8000') + ('127.0.0.1', 8000) + >>> validaddr('fff') + Traceback (most recent call last): + ... + ValueError: fff is not a valid IP address/port + """ + if '/' in string_: + return string_ + else: + return validip(string_) + +def urlquote(val): + """ + Quotes a string for use in a URL. + + >>> urlquote('://?f=1&j=1') + '%3A//%3Ff%3D1%26j%3D1' + >>> urlquote(None) + '' + >>> urlquote(u'\u203d') + '%E2%80%BD' + """ + if val is None: return '' + if not isinstance(val, unicode): val = str(val) + else: val = val.encode('utf-8') + return urllib.quote(val) + +def httpdate(date_obj): + """ + Formats a datetime object for use in HTTP headers. + + >>> import datetime + >>> httpdate(datetime.datetime(1970, 1, 1, 1, 1, 1)) + 'Thu, 01 Jan 1970 01:01:01 GMT' + """ + return date_obj.strftime("%a, %d %b %Y %H:%M:%S GMT") + +def parsehttpdate(string_): + """ + Parses an HTTP date into a datetime object. + + >>> parsehttpdate('Thu, 01 Jan 1970 01:01:01 GMT') + datetime.datetime(1970, 1, 1, 1, 1, 1) + """ + try: + t = time.strptime(string_, "%a, %d %b %Y %H:%M:%S %Z") + except ValueError: + return None + return datetime.datetime(*t[:6]) + +def htmlquote(text): + r""" + Encodes `text` for raw use in HTML. + + >>> htmlquote(u"<'&\">") + u'<'&">' + """ + text = text.replace(u"&", u"&") # Must be done first! + text = text.replace(u"<", u"<") + text = text.replace(u">", u">") + text = text.replace(u"'", u"'") + text = text.replace(u'"', u""") + return text + +def htmlunquote(text): + r""" + Decodes `text` that's HTML quoted. + + >>> htmlunquote(u'<'&">') + u'<\'&">' + """ + text = text.replace(u""", u'"') + text = text.replace(u"'", u"'") + text = text.replace(u">", u">") + text = text.replace(u"<", u"<") + text = text.replace(u"&", u"&") # Must be done last! + return text + +def websafe(val): + r"""Converts `val` so that it is safe for use in Unicode HTML. + + >>> websafe("<'&\">") + u'<'&">' + >>> websafe(None) + u'' + >>> websafe(u'\u203d') + u'\u203d' + >>> websafe('\xe2\x80\xbd') + u'\u203d' + """ + if val is None: + return u'' + elif isinstance(val, str): + val = val.decode('utf-8') + elif not isinstance(val, unicode): + val = unicode(val) + + return htmlquote(val) + +if __name__ == "__main__": + import doctest + doctest.testmod() diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/python23.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/python23.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,46 @@ +"""Python 2.3 compatabilty""" +import threading + +class threadlocal(object): + """Implementation of threading.local for python2.3. + """ + def __getattribute__(self, name): + if name == "__dict__": + return threadlocal._getd(self) + else: + try: + return object.__getattribute__(self, name) + except AttributeError: + try: + return self.__dict__[name] + except KeyError: + raise AttributeError, name + + def __setattr__(self, name, value): + self.__dict__[name] = value + + def __delattr__(self, name): + try: + del self.__dict__[name] + except KeyError: + raise AttributeError, name + + def _getd(self): + t = threading.currentThread() + if not hasattr(t, '_d'): + # using __dict__ of thread as thread local storage + t._d = {} + + _id = id(self) + # there could be multiple instances of threadlocal. + # use id(self) as key + if _id not in t._d: + t._d[_id] = {} + return t._d[_id] + +if __name__ == '__main__': + d = threadlocal() + d.x = 1 + print d.__dict__ + print d.x + \ No newline at end of file diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/session.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/session.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,358 @@ +""" +Session Management +(from web.py) +""" + +import os, time, datetime, random, base64 +import os.path +from copy import deepcopy +try: + import cPickle as pickle +except ImportError: + import pickle +try: + import hashlib + sha1 = hashlib.sha1 +except ImportError: + import sha + sha1 = sha.new + +import utils +import webapi as web + +__all__ = [ + 'Session', 'SessionExpired', + 'Store', 'DiskStore', 'DBStore', +] + +web.config.session_parameters = utils.storage({ + 'cookie_name': 'webpy_session_id', + 'cookie_domain': None, + 'cookie_path' : None, + 'timeout': 86400, #24 * 60 * 60, # 24 hours in seconds + 'ignore_expiry': True, + 'ignore_change_ip': True, + 'secret_key': 'fLjUfxqXtfNoIldA0A0J', + 'expired_message': 'Session expired', + 'httponly': True, + 'secure': False +}) + +class SessionExpired(web.HTTPError): + def __init__(self, message): + web.HTTPError.__init__(self, '200 OK', {}, data=message) + +class Session(object): + """Session management for web.py + """ + __slots__ = [ + "store", "_initializer", "_last_cleanup_time", "_config", "_data", + "__getitem__", "__setitem__", "__delitem__" + ] + + def __init__(self, app, store, initializer=None): + self.store = store + self._initializer = initializer + self._last_cleanup_time = 0 + self._config = utils.storage(web.config.session_parameters) + self._data = utils.threadeddict() + + self.__getitem__ = self._data.__getitem__ + self.__setitem__ = self._data.__setitem__ + self.__delitem__ = self._data.__delitem__ + + if app: + app.add_processor(self._processor) + + def __contains__(self, name): + return name in self._data + + def __getattr__(self, name): + return getattr(self._data, name) + + def __setattr__(self, name, value): + if name in self.__slots__: + object.__setattr__(self, name, value) + else: + setattr(self._data, name, value) + + def __delattr__(self, name): + delattr(self._data, name) + + def _processor(self, handler): + """Application processor to setup session for every request""" + self._cleanup() + self._load() + + try: + return handler() + finally: + self._save() + + def _load(self): + """Load the session from the store, by the id from cookie""" + cookie_name = self._config.cookie_name + cookie_domain = self._config.cookie_domain + cookie_path = self._config.cookie_path + httponly = self._config.httponly + self.session_id = web.cookies().get(cookie_name) + + # protection against session_id tampering + if self.session_id and not self._valid_session_id(self.session_id): + self.session_id = None + + self._check_expiry() + if self.session_id: + d = self.store[self.session_id] + self.update(d) + self._validate_ip() + + if not self.session_id: + self.session_id = self._generate_session_id() + + if self._initializer: + if isinstance(self._initializer, dict): + self.update(deepcopy(self._initializer)) + elif hasattr(self._initializer, '__call__'): + self._initializer() + + self.ip = web.ctx.ip + + def _check_expiry(self): + # check for expiry + if self.session_id and self.session_id not in self.store: + if self._config.ignore_expiry: + self.session_id = None + else: + return self.expired() + + def _validate_ip(self): + # check for change of IP + if self.session_id and self.get('ip', None) != web.ctx.ip: + if not self._config.ignore_change_ip: + return self.expired() + + def _save(self): + if not self.get('_killed'): + self._setcookie(self.session_id) + self.store[self.session_id] = dict(self._data) + else: + self._setcookie(self.session_id, expires=-1) + + def _setcookie(self, session_id, expires='', **kw): + cookie_name = self._config.cookie_name + cookie_domain = self._config.cookie_domain + cookie_path = self._config.cookie_path + httponly = self._config.httponly + secure = self._config.secure + web.setcookie(cookie_name, session_id, expires=expires, domain=cookie_domain, httponly=httponly, secure=secure, path=cookie_path) + + def _generate_session_id(self): + """Generate a random id for session""" + + while True: + rand = os.urandom(16) + now = time.time() + secret_key = self._config.secret_key + session_id = sha1("%s%s%s%s" %(rand, now, utils.safestr(web.ctx.ip), secret_key)) + session_id = session_id.hexdigest() + if session_id not in self.store: + break + return session_id + + def _valid_session_id(self, session_id): + rx = utils.re_compile('^[0-9a-fA-F]+$') + return rx.match(session_id) + + def _cleanup(self): + """Cleanup the stored sessions""" + current_time = time.time() + timeout = self._config.timeout + if current_time - self._last_cleanup_time > timeout: + self.store.cleanup(timeout) + self._last_cleanup_time = current_time + + def expired(self): + """Called when an expired session is atime""" + self._killed = True + self._save() + raise SessionExpired(self._config.expired_message) + + def kill(self): + """Kill the session, make it no longer available""" + del self.store[self.session_id] + self._killed = True + +class Store: + """Base class for session stores""" + + def __contains__(self, key): + raise NotImplementedError + + def __getitem__(self, key): + raise NotImplementedError + + def __setitem__(self, key, value): + raise NotImplementedError + + def cleanup(self, timeout): + """removes all the expired sessions""" + raise NotImplementedError + + def encode(self, session_dict): + """encodes session dict as a string""" + pickled = pickle.dumps(session_dict) + return base64.encodestring(pickled) + + def decode(self, session_data): + """decodes the data to get back the session dict """ + pickled = base64.decodestring(session_data) + return pickle.loads(pickled) + +class DiskStore(Store): + """ + Store for saving a session on disk. + + >>> import tempfile + >>> root = tempfile.mkdtemp() + >>> s = DiskStore(root) + >>> s['a'] = 'foo' + >>> s['a'] + 'foo' + >>> time.sleep(0.01) + >>> s.cleanup(0.01) + >>> s['a'] + Traceback (most recent call last): + ... + KeyError: 'a' + """ + def __init__(self, root): + # if the storage root doesn't exists, create it. + if not os.path.exists(root): + os.makedirs( + os.path.abspath(root) + ) + self.root = root + + def _get_path(self, key): + if os.path.sep in key: + raise ValueError, "Bad key: %s" % repr(key) + return os.path.join(self.root, key) + + def __contains__(self, key): + path = self._get_path(key) + return os.path.exists(path) + + def __getitem__(self, key): + path = self._get_path(key) + if os.path.exists(path): + pickled = open(path).read() + return self.decode(pickled) + else: + raise KeyError, key + + def __setitem__(self, key, value): + path = self._get_path(key) + pickled = self.encode(value) + try: + f = open(path, 'w') + try: + f.write(pickled) + finally: + f.close() + except IOError: + pass + + def __delitem__(self, key): + path = self._get_path(key) + if os.path.exists(path): + os.remove(path) + + def cleanup(self, timeout): + now = time.time() + for f in os.listdir(self.root): + path = self._get_path(f) + atime = os.stat(path).st_atime + if now - atime > timeout : + os.remove(path) + +class DBStore(Store): + """Store for saving a session in database + Needs a table with the following columns: + + session_id CHAR(128) UNIQUE NOT NULL, + atime DATETIME NOT NULL default current_timestamp, + data TEXT + """ + def __init__(self, db, table_name): + self.db = db + self.table = table_name + + def __contains__(self, key): + data = self.db.select(self.table, where="session_id=$key", vars=locals()) + return bool(list(data)) + + def __getitem__(self, key): + now = datetime.datetime.now() + try: + s = self.db.select(self.table, where="session_id=$key", vars=locals())[0] + self.db.update(self.table, where="session_id=$key", atime=now, vars=locals()) + except IndexError: + raise KeyError + else: + return self.decode(s.data) + + def __setitem__(self, key, value): + pickled = self.encode(value) + now = datetime.datetime.now() + if key in self: + self.db.update(self.table, where="session_id=$key", data=pickled, vars=locals()) + else: + self.db.insert(self.table, False, session_id=key, data=pickled ) + + def __delitem__(self, key): + self.db.delete(self.table, where="session_id=$key", vars=locals()) + + def cleanup(self, timeout): + timeout = datetime.timedelta(timeout/(24.0*60*60)) #timedelta takes numdays as arg + last_allowed_time = datetime.datetime.now() - timeout + self.db.delete(self.table, where="$last_allowed_time > atime", vars=locals()) + +class ShelfStore: + """Store for saving session using `shelve` module. + + import shelve + store = ShelfStore(shelve.open('session.shelf')) + + XXX: is shelve thread-safe? + """ + def __init__(self, shelf): + self.shelf = shelf + + def __contains__(self, key): + return key in self.shelf + + def __getitem__(self, key): + atime, v = self.shelf[key] + self[key] = v # update atime + return v + + def __setitem__(self, key, value): + self.shelf[key] = time.time(), value + + def __delitem__(self, key): + try: + del self.shelf[key] + except KeyError: + pass + + def cleanup(self, timeout): + now = time.time() + for k in self.shelf.keys(): + atime, v = self.shelf[k] + if now - atime > timeout : + del self[k] + +if __name__ == '__main__' : + import doctest + doctest.testmod() diff -r 446a7ba98309 -r 65432e6c6042 OpenSecurity/install/web.py-0.37/build/lib/web/template.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OpenSecurity/install/web.py-0.37/build/lib/web/template.py Mon Dec 02 14:02:05 2013 +0100 @@ -0,0 +1,1515 @@ +""" +simple, elegant templating +(part of web.py) + +Template design: + +Template string is split into tokens and the tokens are combined into nodes. +Parse tree is a nodelist. TextNode and ExpressionNode are simple nodes and +for-loop, if-loop etc are block nodes, which contain multiple child nodes. + +Each node can emit some python string. python string emitted by the +root node is validated for safeeval and executed using python in the given environment. + +Enough care is taken to make sure the generated code and the template has line to line match, +so that the error messages can point to exact line number in template. (It doesn't work in some cases still.) + +Grammar: + + template -> defwith sections + defwith -> '$def with (' arguments ')' | '' + sections -> section* + section -> block | assignment | line + + assignment -> '$ ' + line -> (text|expr)* + text -> + expr -> '$' pyexpr | '$(' pyexpr ')' | '${' pyexpr '}' + pyexpr -> +""" + +__all__ = [ + "Template", + "Render", "render", "frender", + "ParseError", "SecurityError", + "test" +] + +import tokenize +import os +import sys +import glob +import re +from UserDict import DictMixin +import warnings + +from utils import storage, safeunicode, safestr, re_compile +from webapi import config +from net import websafe + +def splitline(text): + r""" + Splits the given text at newline. + + >>> splitline('foo\nbar') + ('foo\n', 'bar') + >>> splitline('foo') + ('foo', '') + >>> splitline('') + ('', '') + """ + index = text.find('\n') + 1 + if index: + return text[:index], text[index:] + else: + return text, '' + +class Parser: + """Parser Base. + """ + def __init__(self): + self.statement_nodes = STATEMENT_NODES + self.keywords = KEYWORDS + + def parse(self, text, name="