From 82691922a05856e03a9c5cc791391be0d75cf67c Mon Sep 17 00:00:00 2001 From: skoenen Date: Fri, 19 Jul 2013 10:39:49 +0200 Subject: [PATCH 1/3] Hashing sensible information in `cookies`, `request_url` and `referer`. --- src/adhocracy/lib/importexport/transforms.py | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/adhocracy/lib/importexport/transforms.py b/src/adhocracy/lib/importexport/transforms.py index 372c257ed..c3180dbf3 100644 --- a/src/adhocracy/lib/importexport/transforms.py +++ b/src/adhocracy/lib/importexport/transforms.py @@ -1,6 +1,7 @@ import datetime import re +import hashlib from adhocracy.lib import votedetail from adhocracy import model @@ -439,12 +440,40 @@ class RequestLogTransform(_Transform): def __init__(self, options): super(RequestLogTransform, self).__init__(options) + self.hash_func = hashlib.sha1 def _export(self, obj): res = obj.to_dict() + res['access_time'] = encode_time(res['access_time']) + + # Hash the cookies + cookies = [] + for cookie in res['cookies'].split(";"): + cookie = cookie.strip() + label = cookie.split("=")[0] + value = cookie.split("=")[1] + if "login" in label: + token = self.hash_func(value[0:40]).hexdigest() + value = (token, value[40:]) + + cookies.append({"label": label, "value": value}) + + res['cookies'] = tuple(cookies) + + # Filter out welcome codes + res['request_url'] = self._url_filter(res['request_url']) + res['referer'] = self._url_filter(res['referer']) + return res + def _url_filter(self, url): + if url is not None: + url = re.sub(r'(.*/welcome/[^/]+/)([0-9a-f]+)(?=/|\?|$)', + lambda m: m.group(1) + self.hash_func(m.group(2)).hexdigest(), + url) + return url + class StaticPageTransform(_Transform): def __init__(self, options, backend=None): From aba1cc67ba6a7f14b7ce2e35612cd446bb1d4081 Mon Sep 17 00:00:00 2001 From: skoenen Date: Fri, 19 Jul 2013 13:13:07 +0200 Subject: [PATCH 2/3] Simplified cookie hashing and shorten welcome regex. @phihag --- src/adhocracy/lib/importexport/transforms.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/adhocracy/lib/importexport/transforms.py b/src/adhocracy/lib/importexport/transforms.py index c3180dbf3..1c02018a1 100644 --- a/src/adhocracy/lib/importexport/transforms.py +++ b/src/adhocracy/lib/importexport/transforms.py @@ -447,19 +447,10 @@ def _export(self, obj): res['access_time'] = encode_time(res['access_time']) - # Hash the cookies - cookies = [] - for cookie in res['cookies'].split(";"): - cookie = cookie.strip() - label = cookie.split("=")[0] - value = cookie.split("=")[1] - if "login" in label: - token = self.hash_func(value[0:40]).hexdigest() - value = (token, value[40:]) - - cookies.append({"label": label, "value": value}) - - res['cookies'] = tuple(cookies) + # Filter out session codes from adhocracy login cookie + res['cookies'] = re.sub(r'(adhocracy_login\=)("?[a-f0-9]{40})', + lambda m: m.group(1) + self.hash_func(m.group(2)).hexdigest(), + res['cookies']) # Filter out welcome codes res['request_url'] = self._url_filter(res['request_url']) @@ -469,7 +460,7 @@ def _export(self, obj): def _url_filter(self, url): if url is not None: - url = re.sub(r'(.*/welcome/[^/]+/)([0-9a-f]+)(?=/|\?|$)', + url = re.sub(r'(/welcome/[^/]+/)([0-9a-f]+)(?=/|\?|$)', lambda m: m.group(1) + self.hash_func(m.group(2)).hexdigest(), url) return url From f27c06cae164231a37e70b3807b0e64095a9920c Mon Sep 17 00:00:00 2001 From: skoenen Date: Fri, 27 Sep 2013 13:24:57 +0200 Subject: [PATCH 3/3] Added instrumentations, config for pyprol integration, and analyse sql file. --- calc_timing.sql | 16 + calc_timing_calls.sql | 17 + etc/adhocracy.pyprol.ini | 441 +++++++++++++++++++++ src/adhocracy/instrumentations/__init__.py | 2 + src/adhocracy/instrumentations/model.py | 25 ++ 5 files changed, 501 insertions(+) create mode 100644 calc_timing.sql create mode 100644 calc_timing_calls.sql create mode 100644 etc/adhocracy.pyprol.ini create mode 100644 src/adhocracy/instrumentations/__init__.py create mode 100644 src/adhocracy/instrumentations/model.py diff --git a/calc_timing.sql b/calc_timing.sql new file mode 100644 index 000000000..acf634a08 --- /dev/null +++ b/calc_timing.sql @@ -0,0 +1,16 @@ +select + t.measure_id, + t.measure_session, + t.measure_point, + t.call_count, + (t.time_function / t.call_count) as time_per_call, + t.recursive_call_count, + t.time_total, + t.time_function, + (t.time_total - t.time_function) as time_other, + t.code +from timings as t +order by + t.time_total desc, + t.time_function desc +limit 10; \ No newline at end of file diff --git a/calc_timing_calls.sql b/calc_timing_calls.sql new file mode 100644 index 000000000..5bbb89e09 --- /dev/null +++ b/calc_timing_calls.sql @@ -0,0 +1,17 @@ +select + tc.measure_id, + tc.measure_point, + tc.call_count, + (tc.time_function / tc.call_count) as time_per_call, + tc.recursive_call_count, + tc.time_total, + tc.time_function, + (tc.time_total - tc.time_function) as time_other, + tc.code +from timings_calls as tc +where tc.measure_id = 411 +order by + tc.time_total desc, + tc.time_function desc, + time_other desc +limit 5; diff --git a/etc/adhocracy.pyprol.ini b/etc/adhocracy.pyprol.ini new file mode 100644 index 000000000..17e1b1205 --- /dev/null +++ b/etc/adhocracy.pyprol.ini @@ -0,0 +1,441 @@ +# +# WARNING: Please make you changes in *.ini.in file and then run buildout to install it. +# + +############################################################## +# Generated adhocracy settings +############################################################## + +[DEFAULT] +debug = True + + +# Uncomment and replace with the address which should receive any error reports +email_to = +smtp_server = localhost +smtp_port = 8825 +error_email_from = mail@adhocracy.cc + +[server:main] +use = egg:Paste#http +host = 0.0.0.0 +port = 5001 +use_threadpool = False + +threadpool_workers = 20 + + +###################not themed adhocracy ################### + +[composite:main] +use = egg:Paste#urlmap +/ = default + +[pipeline:default] +pipeline = pyprol content + + +[filter:pyprol] +use = egg:pyprol +pyprol.storage = sqlite:///nobackup/koenen/adhocracy_buildout/var/perf/db +pyprol.instrumentations = adhocracy.instrumentations.model + + +###################Adhocracy conf ################### + +#WARNING changed name: #[app:main] + +[app:content] +use = egg:adhocracy +full_stack = true +static_files = true + +cache_dir = /nobackup/koenen/adhocracy_buildout/var/data +beaker.session.key = adhocracy_state + +beaker.session.secret = 0x4f65112ae94cafb2135031d8198aa9bda26fca79906a20ac2d7e7e48ecf857ffL +adhocracy.auth.secret = 0x4c26646ca5b72ba9a9022f8e280aa3e0796ecc54fa0c43ca9d0b9535944f7d3aL + +adhocracy.crypto.secret = 0xc04cd03c82e27356a66bf40318f9b4d56d6f1574a6bbdd687fe3997527bf4e06L + +# INSTALL: Use cookies instead of beaker(=file system) to store session values +# adhocracy.session.implementation = cookie + +# INSTALL: Use URLs like /i/meta/proposal/foo instead of +# http://meta.adhocracy.lan:5001/proposal/foo +# If this is set, make sure to comment out beaker.session.cookie_domain +# and session.domain below. +adhocracy.relative_urls = True + +# INSTALL: Insert your domain name here. Make sure to include the +# dot at the beginning of each domain to create wildcard cookies. +# Also make sure this is identical to the adhocracy.domains setting +# below. +# Should be commented out iff relative URLs are used. + + + +# If you'd like to fine-tune the individual locations of the cache data dirs +# for the Cache data, or the Session saves, un-comment the desired settings +# here: +beaker.cache.data_dir = /nobackup/koenen/adhocracy_buildout/var/data/cache +beaker.session.data_dir = /nobackup/koenen/adhocracy_buildout/var/data/sessions + +# INSTALL: Locate your Memcached server if installed. Otherwise comment this out. +memcached.server = 127.0.0.1:5005 + +# INSTALL: SQLAlchemy database URL +sqlalchemy.url = sqlite:////nobackup/koenen/adhocracy_buildout/var/development.db + +# INSTALL: Uncommenting this line will delete all locally saved data and drop +# the entire database. Please only use this if you have a backup ready. +# Yes, that's a magic string. +## adhocracy.setup.drop = KILL_EM_ALL +# + +adhocracy.solr.url = http://localhost:5007/solr + +# To avoid a race condition between main and background processes, delaying +# background process updates can be delayed (see issue #358). This option +# defines the delay in seconds (default: 1 second) + +# adhocracy.delay_update_queue_seconds = 1 + +# If debug is enabled, an web-based interactive debugger can be executed from +# the HTTP500 error page, if the following option is set to true. This option +# doesn't have any effect if debug is false. +adhocracy.interactive_debugging = true + +# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* +# Debug mode will enable the interactive debugging tool, allowing ANYONE to +# execute malicious code after an exception is raised. +#set debug = false + + +# INSTALL: Set up the Adhocracy domain name. This will be used to determine the +# active instance, e.g. "Test Instance" for test.adhocracy.lan. + + +adhocracy.domain = adhocracy.lan:5001 +adhocracy.protocol = http + + + +# INSTALL: Set a site name for all instances. This will be used as a part of +# the html , notification E-Mails etc. +adhocracy.site.name = HHU Normsetzung +adhocracy.language = de_DE + +# INSTALL: Server timezone +# adhocracy.timezone = Europe/Berlin + +# INSTALL: The site directory contains your site modifications of Adhocracy +# (e.g. logos, CSS, html pages). A skeleton site directory will be created +# by the "setup-app" paster command. +adhocracy.site.dir = /nobackup/koenen/adhocracy_buildout/var/site + +# INSTALL: Location of your custom client (overrides adhocracy defaults) +# adhocracy.client_location = /nobackup/koenen/adhocracy_buildout/src/adhocracy.YOUR_theme/ + +# INSTALL: A nice E-Mail address. +adhocracy.email.from = mail@adhocracy.cc + +# INSTALL: Allow users to use the above email as sender address in mass messages +allow_system_email_in_mass_messages = True + +# Show fallback icons in instance overview if no instance icon is defined +adhocracy.show_instance_fallback_icons = False + +# INSTALL: Twitter. Since there is currently no option to take it out of the UI, +# you will want to use Twitter. Create an OAuth application to allow users to +# link their profiles: https://twitter.com/oauth_clients +adhocracy.twitter.username = +adhocracy.twitter.key = +adhocracy.twitter.secret = +adhocracy.twitter.consumer_key = +adhocracy.twitter.consumer_secret = + +# INSTALL: Full path to a installation wide twitter profile which is used in +# follow-us link, e.g. http://twitter.com/liqd_de +adhocracy.twitter.profile_url = + +# INSTALL: bit.ly is used as a URL shortener. Since their API requires auth, you +# can either leave the defaults here and give certain usage statistics to the +# Adhocracy developers, or you can create an account at http://api.bit.ly +#adhocracy.bitly.login = +#adhocracy.bitly.key = + + +# Redis is used to build a task queue that will be processed by the +# `worker` process. +# Note: host has to be an IP address, not a hostname +adhocracy.redis.host = 127.0.0.1 +adhocracy.redis.port = 5006 +adhocracy.redis.queue = adhocracy.queue + +# Background processing can be disabled entirely +adhocracy.background_processing = true + +# INSTALL: If you want to use recaptcha uncomment these lines +#recaptcha.public_key = 6LcICcgSAAAAAKNYq9iM4lIpB_GSjYItF21wS4NS +#recaptcha.private_key = 6LcICcgSAAAAAEJL1zhVbX6N0TGb0zVXD_g2lXSo + +# TUNING: Memcache page fragments? +adhocracy.cache_tiles = True + +# adhocracy.instance = adhocracy + +# INSTALL: Add an HTTP header that identifies the server we're running on +#adhocracy.include_machine_name_in_header = True + +# INSTALL: Feedback instance settings. +# If feedback shall be used, users need to be member of the feedback instance. +# This can be achieved with the `adhocracy.instances.autojoin` option below. If +# the feedback instance is enabled later, existing users can be added to the +# feedback instance with the following command: +# +# `bin/adhocpy src/adhocracy/scripts/add_all_users_to_instances.py etc/adhocracy.ini feedback` + +adhocracy.use_feedback_instance = true +adhocracy.feedback_instance_key = feedback +adhocracy.feedback_instance_label = Feedback + +# INSTALL: Instances which new users automatically join. This can be a comma +# separated list of instances, or ALL. If feedback is enabled above, the +# corresponding instance key or ALL should be part of this list. +adhocracy.instances.autojoin = feedback + +# INSTALL: Read client IP addresses from X-Forwarded-For header. +adhocracy.behind_proxy = False + +# INSTALL: Store statistic information about requests in the database +#adhocracy.requestlog_active = True +# ... but don't log IP addresses ('dontlog', default) +# ... but set the last 8 / 80 bits to zero ('anonymize') +# -.. but log the full IP address ('none') +#adhocracy.requestlog_ipanonymization = anonymize + +# INSTALL: Redirect outgoing links so that we can see when a user leaves our site. +# adhocracy.track_outgoing_links = True + +# Statistics via Piwik +piwik.site = +piwik.id = + +# INSTALL: Allow select users to include HTML +# If this option is set to false, we only allow markdown input. +# If it is set, we make a best effort to filter unsafe HTML, but allow iframes +# and other complex constructs. +#adhocracy.allow_user_html = false + +# INSTALL: Allow registration +#adhocracy.allow_registration = true + +# Require emails from users (default: true) +# adhocracy.require_email = true + +# INSTALL: If registration is disabled above, and adhocracy.login_style is +# "alternate", notify this address on registration attempts. +# adhocracy.registration_support_email = + +# INSTALL: How can users login? +# Available options are openid, username+password, email+password, shibboleth +# Note that shibboleth needs additional configuration +#adhocracy.login_type = openid,username+password,email+password + +# Allow password change for shibboleth users (default: false) +# adhocracy.allow_shibboleth_password_change = false + +# Hide local login form (e.g. when using Shibboleth or OpenID primarily) +# The normal login can still be found under `/login?locallogin` +# adhocracy.hide_locallogin = true + +# INSTALL: Allow administrators to let users log in from an invitation email +# adhocracy.enable_welcome = True + +# INSTALL: Hide individual votes and only show aggregate results (EXPERIMENTAL) +# adhocracy.hide_individual_votes = true + +# INSTALL: Allow users to lock themselves out of adhocracy +# adhocracy.allow_self_deletion = true + +# In the case that no came_from parameter is set, users are redirected to the +# locations defined in the following settings. You can leave any of these +# commented out. If instance is given, the url of the given instance is used +# to build the URL, otherwise the current instance is used. + +# adhocracy.post_register_url = +# adhocracy.post_register_instance = +# adhocracy.post_login_url = /proposal +# adhocracy.post_login_instance = test + +# activate geo features + + + +# show tutorials +adhocracy.show_tutorials = True + +# hide instance list in main navigation +adhocracy.hide_instance_list_in_navigation = False + +# hide watchlist in main navigation and put it in user menu +adhocracy.put_watchlist_in_user_menu = False + +# useful in settings where users can create instances +adhocracy.show_instance_creators = False + +# show next milestones in instance overview +adhocracy.show_instance_overview_milestones = True + +# number of upcoming milestones to show in instance overview +adhocracy.number_instance_overview_milestones = 3 + +# show newest proposals in instance overview +# adhocracy.show_instance_overview_proposals_new = False + +# hide categories in facet navigation if no proposal is assigned to it +adhocracy.hide_empty_categories_in_facet_list = True + +# Show global stats (user/proposal/comment count) on frontpage +#adhocracy.show_stats_on_frontpage = true + +# number of newest proposals to show on frontpage (0 to hide the list) +adhocracy.startpage.proposals.list_length = 0 + +# Source for imprint, details etc. ("database" or "filesystem" (default)) +#adhocracy.staticpage_backend = database + +# Configure paths to static content which is inserted + +# Static content path for start page (default: index) +adhocracy.static_index_path = index + +# Static content path for login page (default: empty) +# adhocracy.static_login_path = login + +# Static content paths for shibboleth register page (default: empty) +# Ontop defines the area on top of the form and the title of the page. +# adhocracy.static_shibboleth_register_ontop_path = shibboleth_register_ontop +# Below defines the area below the form, the title is ignored. +# adhocracy.static_shibboleth_register_below_path = shibboleth_register + +# Ask the user for email and then password, instead of form + links +# adhocracy.login_style = alternate + +# Force randomized user names (default: false) +# adhocracy.force_randomized_user_names = true + +# Set display name in register dialog (default: false) +# adhocracy.set_display_name_on_register = true + +# Automatically set new permissions their default value. This should be +# set to false in restrictive environments. +# adhocracy.autoassign_permissions = true + +# Turn on badge-specific UI modifications +# adhocracy.enable_behavior = True + +# Show Facebook / Twitter / G+ buttons +# adhocracy.show_social_buttons = False + +## Performance options + +# Check whether feedback instance exists before rendering a feedback button +# adhocracy.feedback_check_instance = False + +# Load feedback categories for the feedback form +# adhocracy.feedback_use_categories = False + +# Optional user attributes +# adhocracy.user.optional_attributes = +# year_of_birth, int, Year of Birth +# foo, unicode, Foo +# adhocracy.user.optional_attributes.year_of_birth = +# 2001, 2222, 1111 +## adhocracy.user.optional_attributes.foo = + + +# Logging configuration +[loggers] +keys = root, adhocracy, sqlalchemy + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[logger_routes] +level = INFO +handlers = +qualname = routes.middleware +# "level = DEBUG" logs the route matched and routing variables. + +[logger_adhocracy] +level = DEBUG + +handlers = +qualname = adhocracy + +[logger_sqlalchemy] +level = WARN +handlers = console +qualname = sqlalchemy.engine + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s + +############################################################## +# Custom OVERRIDE adhocracy settings +############################################################## + +[app:content] +adhocracy.client_location = /nobackup/koenen/adhocracy_buildout/src/adhocracy.hhu_theme/ +adhocracy.comment_wording = True +adhocracy.enable_behavior = True +adhocracy.enable_gender = True +adhocracy.enable_votedetail = True +adhocracy.enable_welcome = True +adhocracy.feedback_check_instance = False +adhocracy.feedback_use_categories = False +adhocracy.hide_individual_votes = true +adhocracy.include_machine_name_in_header = True +adhocracy.instances.autojoin = ALL +adhocracy.login_style = alternate +adhocracy.login_type = email+password +adhocracy.monitor_browser_values = True +adhocracy.monitor_comment_behavior = True +adhocracy.monitor_external_links = True +adhocracy.monitor_page_performance = True +adhocracy.monitor_page_time_interval = 10000 +adhocracy.monitor_pager_clicks = True +adhocracy.post_login_instance = +adhocracy.post_login_url = / +adhocracy.post_register_instance = +adhocracy.post_register_url = +adhocracy.registration_support_email = normsetzung-support@cs.uni-duesseldorf.de +adhocracy.requestlog_active = True +adhocracy.requestlog_ipanonymization = none +adhocracy.self_deletion_allowed = false +adhocracy.session.implementation = cookie +adhocracy.show_abuse_button = False +adhocracy.show_instance_overview_events = False +adhocracy.show_instance_overview_proposals_all = True +adhocracy.show_instance_overview_proposals_new = False +adhocracy.show_instance_overview_stats = False +adhocracy.show_social_buttons = False +adhocracy.show_stats_on_frontpage = False +adhocracy.startpage.instances.list_length = -1 +adhocracy.staticpage_backend = database +adhocracy.track_outgoing_links = True diff --git a/src/adhocracy/instrumentations/__init__.py b/src/adhocracy/instrumentations/__init__.py new file mode 100644 index 000000000..833a0ba11 --- /dev/null +++ b/src/adhocracy/instrumentations/__init__.py @@ -0,0 +1,2 @@ +from . import model + diff --git a/src/adhocracy/instrumentations/model.py b/src/adhocracy/instrumentations/model.py new file mode 100644 index 000000000..48e2d77c5 --- /dev/null +++ b/src/adhocracy/instrumentations/model.py @@ -0,0 +1,25 @@ +import importlib + +from pyprol.measurement import measurement +from logging import getLogger + +log = getLogger(u'adhocracy.instrumentations.model') + +def inject(config): + try: + _adhocracy_model = importlib.import_module("adhocracy.model") + _before_commit = _adhocracy_model.before_commit + + def before_commit(session): + measure = measurement.enable(u"adhocracy.model.before_commit") + result = _before_commit(session) + measurement.disable(measure) + return result + + _adhocracy_model.before_commit = before_commit + log.info("injected into adhocracy.model.before_commit") + + except ImportError as e: + log.info("Could not import `adhocracy.model`") + log.debug(e) +