# -*- coding: utf-8 -*- # Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import wtforms import formencode import re import pyramid.threadlocal import datetime import appenlight.lib.helpers as h from ziggurat_foundations.models.services.user import UserService from ziggurat_foundations.models.services.group import GroupService from appenlight.models import DBSession from appenlight.models.alert_channel import AlertChannel from appenlight.models.integrations import IntegrationException from appenlight.models.integrations.campfire import CampfireIntegration from appenlight.models.integrations.bitbucket import BitbucketIntegration from appenlight.models.integrations.github import GithubIntegration from appenlight.models.integrations.flowdock import FlowdockIntegration from appenlight.models.integrations.hipchat import HipchatIntegration from appenlight.models.integrations.jira import JiraClient from appenlight.models.integrations.slack import SlackIntegration from appenlight.lib.ext_json import json from wtforms.ext.csrf.form import SecureForm from wtforms.compat import iteritems from collections import defaultdict _ = str strip_filter = lambda x: x.strip() if x else None uppercase_filter = lambda x: x.upper() if x else None FALSE_VALUES = ('false', '', False, None) class CSRFException(Exception): pass class ReactorForm(SecureForm): def __init__(self, formdata=None, obj=None, prefix='', csrf_context=None, **kwargs): super(ReactorForm, self).__init__(formdata=formdata, obj=obj, prefix=prefix, csrf_context=csrf_context, **kwargs) self._csrf_context = csrf_context def generate_csrf_token(self, csrf_context): return csrf_context.session.get_csrf_token() def validate_csrf_token(self, field): request = self._csrf_context or pyramid.threadlocal.get_current_request() is_from_auth_token = 'auth:auth_token' in request.effective_principals if is_from_auth_token: return True if field.data != field.current_token: # try to save the day by using token from angular if request.headers.get('X-XSRF-TOKEN') != field.current_token: raise CSRFException('Invalid CSRF token') @property def errors_dict(self): r_dict = defaultdict(list) for k, errors in self.errors.items(): r_dict[k].extend([str(e) for e in errors]) return r_dict @property def errors_json(self): return json.dumps(self.errors_dict) def populate_obj(self, obj, ignore_none=False): """ Populates the attributes of the passed `obj` with data from the form's fields. :note: This is a destructive operation; Any attribute with the same name as a field will be overridden. Use with caution. """ if ignore_none: for name, field in iteritems(self._fields): if field.data is not None: field.populate_obj(obj, name) else: for name, field in iteritems(self._fields): field.populate_obj(obj, name) css_classes = {} ignore_labels = {} class SignInForm(ReactorForm): came_from = wtforms.HiddenField() sign_in_user_name = wtforms.StringField(_('User Name')) sign_in_user_password = wtforms.PasswordField(_('Password')) ignore_labels = ['submit'] css_classes = {'submit': 'btn btn-primary'} html_attrs = {'sign_in_user_name': {'placeholder': 'Your login'}, 'sign_in_user_password': { 'placeholder': 'Your password'}} from wtforms.widgets import html_params, HTMLString def select_multi_checkbox(field, ul_class='set', **kwargs): """Render a multi-checkbox widget""" kwargs.setdefault('type', 'checkbox') field_id = kwargs.pop('id', field.id) html = ['') return HTMLString(''.join(html)) def button_widget(field, button_cls='ButtonField btn btn-default', **kwargs): """Render a button widget""" kwargs.setdefault('type', 'button') field_id = kwargs.pop('id', field.id) kwargs.setdefault('value', field.label.text) html = ['' % (html_params(id=field_id, class_=button_cls), kwargs['value'],)] return HTMLString(''.join(html)) def clean_whitespace(value): if value: return value.strip() return value def found_username_validator(form, field): user = UserService.by_user_name(field.data) # sets user to recover in email validator form.field_user = user if not user: raise wtforms.ValidationError('This username does not exist') def found_username_email_validator(form, field): user = UserService.by_email(field.data) if not user: raise wtforms.ValidationError('Email is incorrect') def unique_username_validator(form, field): user = UserService.by_user_name(field.data) if user: raise wtforms.ValidationError('This username already exists in system') def unique_groupname_validator(form, field): group = GroupService.by_group_name(field.data) mod_group = getattr(form, '_modified_group', None) if group and (not mod_group or mod_group.id != group.id): raise wtforms.ValidationError( 'This group name already exists in system') def unique_email_validator(form, field): user = UserService.by_email(field.data) if user: raise wtforms.ValidationError('This email already exists in system') def email_validator(form, field): validator = formencode.validators.Email() try: validator.to_python(field.data) except formencode.Invalid as e: raise wtforms.ValidationError(e) def unique_alert_email_validator(form, field): q = DBSession.query(AlertChannel) q = q.filter(AlertChannel.channel_name == 'email') q = q.filter(AlertChannel.channel_value == field.data) email = q.first() if email: raise wtforms.ValidationError( 'This email already exists in alert system') def blocked_email_validator(form, field): blocked_emails = [ 'goood-mail.org', 'shoeonlineblog.com', 'louboutinemart.com', 'guccibagshere.com', 'nikeshoesoutletforsale.com' ] data = field.data or '' domain = data.split('@')[-1] if domain in blocked_emails: raise wtforms.ValidationError('Don\'t spam') def old_password_validator(form, field): if not UserService.check_password(field.user, field.data or ''): raise wtforms.ValidationError('You need to enter correct password') class UserRegisterForm(ReactorForm): user_name = wtforms.StringField( _('User Name'), filters=[strip_filter], validators=[ wtforms.validators.Length(min=2, max=30), wtforms.validators.Regexp( re.compile(r'^[\.\w-]+$', re.UNICODE), message="Invalid characters used"), unique_username_validator, wtforms.validators.DataRequired() ]) user_password = wtforms.PasswordField(_('User Password'), filters=[strip_filter], validators=[ wtforms.validators.Length(min=4), wtforms.validators.DataRequired() ]) email = wtforms.StringField(_('Email Address'), filters=[strip_filter], validators=[email_validator, unique_email_validator, blocked_email_validator, wtforms.validators.DataRequired()]) first_name = wtforms.HiddenField(_('First Name')) last_name = wtforms.HiddenField(_('Last Name')) ignore_labels = ['submit'] css_classes = {'submit': 'btn btn-primary'} html_attrs = {'user_name': {'placeholder': 'Your login'}, 'user_password': {'placeholder': 'Your password'}, 'email': {'placeholder': 'Your email'}} class UserCreateForm(UserRegisterForm): status = wtforms.BooleanField('User status', false_values=FALSE_VALUES) class UserUpdateForm(UserCreateForm): user_name = None user_password = wtforms.PasswordField(_('User Password'), filters=[strip_filter], validators=[ wtforms.validators.Length(min=4), wtforms.validators.Optional() ]) email = wtforms.StringField(_('Email Address'), filters=[strip_filter], validators=[email_validator, wtforms.validators.DataRequired()]) class LostPasswordForm(ReactorForm): email = wtforms.StringField(_('Email Address'), filters=[strip_filter], validators=[email_validator, found_username_email_validator, wtforms.validators.DataRequired()]) submit = wtforms.SubmitField(_('Reset password')) ignore_labels = ['submit'] css_classes = {'submit': 'btn btn-primary'} class ChangePasswordForm(ReactorForm): old_password = wtforms.PasswordField( 'Old Password', filters=[strip_filter], validators=[old_password_validator, wtforms.validators.DataRequired()]) new_password = wtforms.PasswordField( 'New Password', filters=[strip_filter], validators=[wtforms.validators.Length(min=4), wtforms.validators.DataRequired()]) new_password_confirm = wtforms.PasswordField( 'Confirm Password', filters=[strip_filter], validators=[wtforms.validators.EqualTo('new_password'), wtforms.validators.DataRequired()]) submit = wtforms.SubmitField('Change Password') ignore_labels = ['submit'] css_classes = {'submit': 'btn btn-primary'} class CheckPasswordForm(ReactorForm): password = wtforms.PasswordField( 'Password', filters=[strip_filter], validators=[old_password_validator, wtforms.validators.DataRequired()]) class NewPasswordForm(ReactorForm): new_password = wtforms.PasswordField( 'New Password', filters=[strip_filter], validators=[wtforms.validators.Length(min=4), wtforms.validators.DataRequired()]) new_password_confirm = wtforms.PasswordField( 'Confirm Password', filters=[strip_filter], validators=[wtforms.validators.EqualTo('new_password'), wtforms.validators.DataRequired()]) submit = wtforms.SubmitField('Set Password') ignore_labels = ['submit'] css_classes = {'submit': 'btn btn-primary'} class CORSTextAreaField(wtforms.StringField): """ This field represents an HTML ``