# -*- coding: utf-8 -*- # Copyright (C) 2010-2016 RhodeCode GmbH # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License, version 3 # (only), as published by the Free Software Foundation. # # 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 Affero General Public License # along with this program. If not, see . # # This program is dual-licensed. If you wish to learn more about the # AppEnlight Enterprise Edition, including its added features, Support # services, and proprietary license terms, please see # https://rhodecode.com/licenses/ import hashlib import os from pyramid.i18n import TranslationStringFactory from pyramid import threadlocal _ = TranslationStringFactory('pyramid') from appenlight import security from appenlight.lib import helpers, generate_random_string from appenlight.models.services.config import ConfigService def gen_urls(request): urls = { 'baseUrl': request.route_url('/'), 'applicationsNoId': request.route_url('applications_no_id'), 'applications': request.route_url('applications', resource_id='REPLACE_ID').replace('REPLACE_ID',':resourceId'), 'applicationsProperty': request.route_url('applications_property',key='REPLACE_KEY', resource_id='REPLACE_ID').replace('REPLACE_ID',':resourceId').replace('REPLACE_KEY',':key'), 'configsNoId': request.route_url('admin_configs'), 'configs': request.route_url('admin_config', key='REPLACE_KEY', section='REPLACE_SECTION').replace('REPLACE_SECTION',':section').replace('REPLACE_KEY',':key'), 'docs': 'http://getappenlight.com/page/api/main.html', 'eventsNoId': request.route_url('events_no_id'), 'events': request.route_url('events', event_id='REPLACE_ID').replace('REPLACE_ID',':eventId'), 'eventsProperty': request.route_url('events_property',key='REPLACE_KEY', event_id='REPLACE_ID').replace('REPLACE_ID',':eventId').replace('REPLACE_KEY',':key'), 'groupsNoId': request.route_url('groups_no_id'), 'groups': request.route_url('groups', group_id='REPLACE_ID').replace('REPLACE_ID',':groupId'), 'groupsProperty': request.route_url('groups_property',key='REPLACE_KEY', group_id='REPLACE_ID').replace('REPLACE_ID',':groupId').replace('REPLACE_KEY',':key'), 'logsNoId': request.route_url('logs_no_id'), 'integrationAction': request.route_url('integrations_id',action='REPLACE_ACT', resource_id='REPLACE_RID', integration='REPLACE_IID').replace('REPLACE_RID',':resourceId').replace('REPLACE_ACT',':action').replace('REPLACE_IID',':integration'), 'usersNoId': request.route_url('users_no_id'), 'users': request.route_url('users', user_id='REPLACE_ID').replace('REPLACE_ID',':userId'), 'usersProperty': request.route_url('users_property',key='REPLACE_KEY', user_id='REPLACE_ID').replace('REPLACE_ID',':userId').replace('REPLACE_KEY',':key'), 'userSelf': request.route_url('users_self'), 'userSelfProperty': request.route_url('users_self_property',key='REPLACE_KEY').replace('REPLACE_KEY',':key'), 'reports': request.route_url('reports'), 'reportGroup': request.route_url('report_groups', group_id='REPLACE_RID').replace('REPLACE_RID',':groupId'), 'reportGroupProperty': request.route_url('report_groups_property', key='REPLACE_KEY', group_id='REPLACE_GID').replace('REPLACE_KEY',':key').replace('REPLACE_GID',':groupId'), 'pluginConfigsNoId': request.route_url('plugin_configs', plugin_name='REPLACE_TYPE').replace('REPLACE_TYPE',':plugin_name'), 'pluginConfigs': request.route_url('plugin_config', id='REPLACE_ID', plugin_name='REPLACE_TYPE').replace('REPLACE_ID',':id').replace('REPLACE_TYPE',':plugin_name'), 'resourceProperty': request.route_url('resources_property',key='REPLACE_KEY', resource_id='REPLACE_ID').replace('REPLACE_ID',':resourceId').replace('REPLACE_KEY',':key'), 'slowReports': request.route_url('slow_reports'), 'sectionView': request.route_url('section_view', section='REPLACE_S', view='REPLACE_V').replace('REPLACE_S',':section').replace('REPLACE_V',':view'), 'otherRoutes': { 'register': request.route_url('register') , 'lostPassword': request.route_url('lost_password') , 'lostPasswordGenerate': request.route_url('lost_password_generate') }, 'social_auth': { 'google':request.route_url('social_auth', provider='google'), 'twitter':request.route_url('social_auth', provider='twitter'), 'bitbucket':request.route_url('social_auth', provider='bitbucket'), 'github':request.route_url('social_auth', provider='github'), }, "plugins":{}, "adminAction": request.route_url('admin', action="REPLACE_ACT").replace('REPLACE_ACT',':action') } return urls def new_request(event): environ = event.request.environ event.request.response.headers['X-Frame-Options'] = 'SAMEORIGIN' event.request.response.headers['X-XSS-Protection'] = '1; mode=block' # can this be enabled on non https deployments? # event.request.response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubdomains;' # do not send XSRF token with /api calls if not event.request.path.startswith('/api'): if environ['wsgi.url_scheme'] == 'https': event.request.response.set_cookie( 'XSRF-TOKEN', event.request.session.get_csrf_token(), secure=True) else: event.request.response.set_cookie( 'XSRF-TOKEN', event.request.session.get_csrf_token()) if event.request.user: event.request.response.headers[ 'x-appenlight-uid'] = '%s' % event.request.user.id def add_renderer_globals(event): request = event.get("request") or threadlocal.get_current_request() renderer_globals = event renderer_globals["h"] = helpers renderer_globals["js_hash"] = request.registry.js_hash renderer_globals["css_hash"] = request.registry.css_hash renderer_globals['_'] = _ renderer_globals['security'] = security renderer_globals['flash_msgs'] = [] renderer_globals['js_plugins'] = [] renderer_globals['top_nav'] = { 'menu_dashboards_items': [], 'menu_reports_items': [], 'menu_logs_items': [], 'menu_settings_items': [], 'menu_admin_items': [], } if 'jinja' in event['renderer_info'].type: renderer_globals['url_list'] = gen_urls(request) # add footer html and some other global vars to renderer for module, config in request.registry.appenlight_plugins.items(): if config['url_gen']: urls = config['url_gen'](request) renderer_globals['url_list']['plugins'][module] = urls if config['javascript']: renderer_globals['js_plugins'].append( ({'name':module, 'config':config['javascript']})) for nav_key in renderer_globals['top_nav'].keys(): if nav_key in config['top_nav'] and config['top_nav'][nav_key]: renderer_globals['top_nav'][nav_key].append( config['top_nav'][nav_key]) if request.has_permission('root_administration', security.RootFactory(request)): renderer_globals['top_nav']['menu_admin_items'].append( {'sref': 'admin', 'label': 'Admin Settings'} ) footer_config = ConfigService.by_key_and_section( 'template_footer_html', 'global', default_value='') renderer_globals['template_footer_html'] = footer_config.value try: renderer_globals['root_administrator'] = request.has_permission( 'root_administration', security.RootFactory(request)) except AttributeError: renderer_globals['root_administrator'] = False renderer_globals['_mail_url'] = request.registry.settings['_mail_url'] if not request: return # do not sens flash headers with /api calls if not request.path.startswith('/api'): flash_msgs = helpers.get_type_formatted_flash(request) renderer_globals['flash_msgs'] = flash_msgs request.add_flash_to_headers() def application_created(app): webassets_dir = app.app.registry.settings.get('webassets.dir') js_hash = generate_random_string() css_hash = generate_random_string() if webassets_dir: js_hasher = hashlib.md5() css_hasher = hashlib.md5() for root, dirs, files in os.walk(webassets_dir): for name in files: filename = os.path.join(root, name) if name.endswith('css'): with open(filename, 'r', encoding='utf8', errors='replace') as f: for line in f: css_hasher.update(line.encode('utf8')) elif name.endswith('js'): with open(filename, 'r', encoding='utf8', errors='replace') as f: for line in f: js_hasher.update(line.encode('utf8')) js_hash = js_hasher.hexdigest() css_hash = css_hasher.hexdigest() app.app.registry.js_hash = js_hash app.app.registry.css_hash = css_hash