Esempio n. 1
0
def _sanitize_response(response_value, block_type):
    if block_type == 'file-input':
        return response_value  # don't mess with this magic
    elif block_type == 'multi-select-input':
        return [sanitize.strip_html(entry) for entry in response_value]
    else:
        return sanitize.strip_html(response_value)
def map_schemas_to_schemablocks(*args):
    """Map schemas to schema blocks

    WARNING: Deletes existing schema blocks
    """
    state = args[0]
    try:
        RegistrationSchema = state.get_model('osf', 'registrationschema')
    except Exception:
        try:
            RegistrationSchema = state.get_model('osf', 'metaschema')
        except Exception:
            # Working outside a migration
            from osf.models import RegistrationSchema

    # Delete all existing schema blocks (avoid creating duplicates)
    unmap_schemablocks(*args)

    for rs in RegistrationSchema.objects.all():
        logger.info('Migrating schema {}, version {} to schema blocks.'.format(rs.schema.get('name'), rs.schema_version))
        for page in rs.schema['pages']:
            # Create page heading block
            create_schema_block(
                state,
                rs.id,
                'page-heading',
                display_text=strip_html(page.get('title', '')),
                help_text=strip_html(page.get('description', ''))
            )
            for question in page['questions']:
                create_schema_blocks_for_question(state, rs, question)
    def test_bulk_creates_children_and_sanitizes_html_logged_in_owner(
            self, app, user, project, url):
        title = '<em>Reasoning</em> <strong>Aboot Projects</strong>'
        description = 'A <script>alert("super reasonable")</script> child'

        res = app.post_json_api(url, {
            'data': [{
                'type': 'nodes',
                'attributes': {
                    'title': title,
                    'description': description,
                    'category': 'project',
                    'public': True
                }
            }]
        }, auth=user.auth, bulk=True)
        child_id = res.json['data'][0]['id']
        assert res.status_code == 201
        url = '/{}nodes/{}/'.format(API_BASE, child_id)

        res = app.get(url, auth=user.auth)
        assert res.json['data']['attributes']['title'] == strip_html(title)
        assert res.json['data']['attributes']['description'] == strip_html(
            description)
        assert res.json['data']['attributes']['category'] == 'project'

        project.reload()
        child_id = res.json['data']['id']
        assert child_id == project.nodes[0]._id
        assert AbstractNode.load(child_id).logs.latest(
        ).action == NodeLog.PROJECT_CREATED
Esempio n. 4
0
def new_node(category, title, user, description='', parent=None, campaign=None):
    """Create a new project or component.

    :param str category: Node category
    :param str title: Node title
    :param User user: User object
    :param str description: Node description
    :param Node project: Optional parent object
    :return Node: Created node

    """
    # We use apps.get_model rather than import .model.Node
    # because we want the concrete Node class, not AbstractNode
    Node = apps.get_model('osf.Node')
    category = category
    title = strip_html(title.strip())
    if description:
        description = strip_html(description.strip())

    node = Node(
        title=title,
        category=category,
        creator=user,
        description=description,
        parent=parent
    )

    node.save()

    if campaign:
        from framework.auth.campaigns import system_tag_for_campaign
        node.add_system_tag(system_tag_for_campaign(campaign))

    return node
Esempio n. 5
0
def new_node(category, title, user, description='', parent=None):
    """Create a new project or component.

    :param str category: Node category
    :param str title: Node title
    :param User user: User object
    :param str description: Node description
    :param Node project: Optional parent object
    :return Node: Created node

    """
    # We use apps.get_model rather than import .model.Node
    # because we want the concrete Node class, not AbstractNode
    Node = apps.get_model('osf.Node')
    category = category
    title = strip_html(title.strip())
    if description:
        description = strip_html(description.strip())

    node = Node(
        title=title,
        category=category,
        creator=user,
        description=description,
        parent=parent
    )

    node.save()

    return node
    def test_bulk_creates_children_and_sanitizes_html_logged_in_owner(
            self, app, user, project, url):
        title = '<em>Reasoning</em> <strong>Aboot Projects</strong>'
        description = 'A <script>alert("super reasonable")</script> child'

        res = app.post_json_api(url, {
            'data': [{
                'type': 'nodes',
                'attributes': {
                    'title': title,
                    'description': description,
                    'category': 'project',
                    'public': True
                }
            }]
        },
                                auth=user.auth,
                                bulk=True)
        child_id = res.json['data'][0]['id']
        assert res.status_code == 201
        url = '/{}nodes/{}/'.format(API_BASE, child_id)

        res = app.get(url, auth=user.auth)
        assert res.json['data']['attributes']['title'] == strip_html(title)
        assert res.json['data']['attributes']['description'] == strip_html(
            description)
        assert res.json['data']['attributes']['category'] == 'project'

        project.reload()
        child_id = res.json['data']['id']
        assert child_id == project.nodes[0]._id
        assert AbstractNode.load(
            child_id).logs.latest().action == NodeLog.PROJECT_CREATED
    def test_strip_html_on_non_strings_returns_original_value(self):
        assert_true(sanitize.strip_html(True))
        assert_false(sanitize.strip_html(False))

        assert_equal(sanitize.strip_html(12), 12)
        assert_equal(sanitize.strip_html(12.3), 12.3)

        dtime = timezone.now()
        assert_equal(sanitize.strip_html(dtime), dtime)
 def test_strip_html(self):
     assert_equal(
         sanitize.strip_html('<foo>bar</foo>'),
         'bar'
     )
     assert_equal(
         sanitize.strip_html(b'<foo>bar</foo>'),
         'bar'
     )
Esempio n. 9
0
def map_schema_to_schemablocks(rs, state=None):
    for page in rs.schema['pages']:
        # Create page heading block
        create_schema_block(state,
                            rs.id,
                            'page-heading',
                            display_text=strip_html(page.get('title', '')),
                            help_text=strip_html(page.get('description', '')))
        for question in page['questions']:
            create_schema_blocks_for_question(state, rs, question)
Esempio n. 10
0
def find_title_description_help_example(rs, question):
    """
    For mapping schemas to schema blocks:
    Schemas are inconsistent with regards to the information going into "title",
    "description", and "help" blocks.

    :returns tuple, title, description, help, example strings

    """
    title = question.get('title', '')
    description = strip_html(question.get('description', ''))
    help = strip_html(question.get('help', ''))
    example = strip_html(question.get('example', ''))

    schema_name = rs.schema.get('name', '')
    # Descriptions that contain any of these keywords
    # are turned into help text instead.
    help_text_keywords = [
        'please',
        'choose',
        'provide',
        'format',
        'describe',
        'who',
        'what',
        'when',
        'where',
        'use',
        'you',
        'your',
        'skip',
        'enter',
    ]

    if title:
        if schema_name in [
                'OSF Preregistration', 'Prereg Challenge',
                'Secondary Data Preregistration'
        ]:
            # These two schemas have clear "example" text in the "help" section
            example = help
            help = description
            description = ''
        else:
            for keyword in help_text_keywords:
                if keyword in description.lower():
                    help = description
                    description = ''
                    break
    else:
        # if no title, description text is moved to title.
        title = description
        description = ''

    return title, description, help, example
Esempio n. 11
0
def deserialize_contributors(node, user_dicts, auth, validate=False):
    """View helper that returns a list of User objects from a list of
    serialized users (dicts). The users in the list may be registered or
    unregistered users.

    e.g. ``[{'id': 'abc123', 'registered': True, 'fullname': ..},
            {'id': None, 'registered': False, 'fullname'...},
            {'id': '123ab', 'registered': False, 'fullname': ...}]

    If a dict represents an unregistered user without an ID, creates a new
    unregistered User record.

    :param Node node: The node to add contributors to
    :param list(dict) user_dicts: List of serialized users in the format above.
    :param Auth auth:
    :param bool validate: Whether to validate and sanitize fields (if necessary)
    """

    # Add the registered contributors
    contribs = []
    for contrib_dict in user_dicts:
        fullname = contrib_dict['fullname']
        visible = contrib_dict['visible']
        email = contrib_dict.get('email')

        if validate is True:
            # Validate and sanitize inputs as needed. Email will raise error if invalid.
            # TODO Edge case bug: validation and saving are performed in same loop, so all in list
            # up to the invalid entry will be saved. (communicate to the user what needs to be retried)
            fullname = sanitize.strip_html(fullname)
            if not fullname:
                raise ValidationError('Full name field cannot be empty')
            if email:
                validate_email(email)  # Will raise a ValidationError if email invalid

        if contrib_dict['id']:
            contributor = OSFUser.load(contrib_dict['id'])
        else:
            try:
                contributor = OSFUser.create_unregistered(
                    fullname=fullname,
                    email=email)
                contributor.save()
            except ValidationError:
                ## FIXME: This suppresses an exception if ID not found & new validation fails; get_user will return None
                contributor = get_user(email=email)

        # Add unclaimed record if necessary
        if not contributor.is_registered:
            contributor.add_unclaimed_record(node, referrer=auth.user,
                given_name=fullname,
                email=email)
            contributor.save()

        contribs.append({
            'user': contributor,
            'visible': visible,
            'permissions': expand_permissions(contrib_dict.get('permission'))
        })
    return contribs
Esempio n. 12
0
    def set_title(self, title, auth, save=False):
        """Set the title of this Node and log it.

        :param str title: The new title.
        :param auth: All the auth information including user, API key.
        """
        if not self.has_permission(auth.user, 'write'):
            raise PermissionsError(
                'Must have admin or write permissions to edit a preprint\'s title.'
            )

        # Called so validation does not have to wait until save.
        validate_title(title)

        original_title = self.title
        new_title = sanitize.strip_html(title)
        # Title hasn't changed after sanitzation, bail out
        if original_title == new_title:
            return False
        self.title = new_title
        self.add_log(
            action=PreprintLog.EDITED_TITLE,
            params={
                'preprint': self._id,
                'title_new': self.title,
                'title_original': original_title,
            },
            auth=auth,
            save=False,
        )
        if save:
            self.save()
        return None
Esempio n. 13
0
    def set_description(self, description, auth, save=False):
        """Set the description and log the event.

        :param str description: The new description
        :param auth: All the auth informtion including user, API key.
        :param bool save: Save self after updating.
        """
        if not self.has_permission(auth.user, 'write'):
            raise PermissionsError(
                'Must have admin or write permissions to edit a preprint\'s title.'
            )

        original = self.description
        new_description = sanitize.strip_html(description)
        if original == new_description:
            return False
        self.description = new_description
        self.add_log(
            action=PreprintLog.EDITED_DESCRIPTION,
            params={
                'preprint': self._id,
                'description_new': self.description,
                'description_original': original
            },
            auth=auth,
            save=False,
        )
        if save:
            self.save()
        return None
Esempio n. 14
0
    def set_description(self, description, auth, save=False):
        """Set the description and log the event.

        :param str description: The new description
        :param auth: All the auth informtion including user, API key.
        :param bool save: Save self after updating.
        """
        if not self.has_permission(auth.user, 'write'):
            raise PermissionsError('Must have admin or write permissions to edit a preprint\'s title.')

        original = self.description
        new_description = sanitize.strip_html(description)
        if original == new_description:
            return False
        self.description = new_description
        self.add_log(
            action=PreprintLog.EDITED_DESCRIPTION,
            params={
                'preprint': self._id,
                'description_new': self.description,
                'description_original': original
            },
            auth=auth,
            save=False,
        )
        if save:
            self.save()
        return None
Esempio n. 15
0
    def set_title(self, title, auth, save=False):
        """Set the title of this Node and log it.

        :param str title: The new title.
        :param auth: All the auth information including user, API key.
        """
        if not self.has_permission(auth.user, 'write'):
            raise PermissionsError('Must have admin or write permissions to edit a preprint\'s title.')

        # Called so validation does not have to wait until save.
        validate_title(title)

        original_title = self.title
        new_title = sanitize.strip_html(title)
        # Title hasn't changed after sanitzation, bail out
        if original_title == new_title:
            return False
        self.title = new_title
        self.add_log(
            action=PreprintLog.EDITED_TITLE,
            params={
                'preprint': self._id,
                'title_new': self.title,
                'title_original': original_title,
            },
            auth=auth,
            save=False,
        )
        if save:
            self.save()
        return None
Esempio n. 16
0
def deserialize_contributors(node, user_dicts, auth, validate=False):
    """View helper that returns a list of User objects from a list of
    serialized users (dicts). The users in the list may be registered or
    unregistered users.

    e.g. ``[{'id': 'abc123', 'registered': True, 'fullname': ..},
            {'id': None, 'registered': False, 'fullname'...},
            {'id': '123ab', 'registered': False, 'fullname': ...}]

    If a dict represents an unregistered user without an ID, creates a new
    unregistered User record.

    :param Node node: The node to add contributors to
    :param list(dict) user_dicts: List of serialized users in the format above.
    :param Auth auth:
    :param bool validate: Whether to validate and sanitize fields (if necessary)
    """

    # Add the registered contributors
    contribs = []
    for contrib_dict in user_dicts:
        fullname = contrib_dict['fullname']
        visible = contrib_dict['visible']
        email = contrib_dict.get('email')

        if validate is True:
            # Validate and sanitize inputs as needed. Email will raise error if invalid.
            # TODO Edge case bug: validation and saving are performed in same loop, so all in list
            # up to the invalid entry will be saved. (communicate to the user what needs to be retried)
            fullname = sanitize.strip_html(fullname)
            if not fullname:
                raise ValidationError('Full name field cannot be empty')
            if email:
                validate_email(email)  # Will raise a ValidationError if email invalid

        if contrib_dict['id']:
            contributor = OSFUser.load(contrib_dict['id'])
        else:
            try:
                contributor = OSFUser.create_unregistered(
                    fullname=fullname,
                    email=email)
                contributor.save()
            except ValidationError:
                ## FIXME: This suppresses an exception if ID not found & new validation fails; get_user will return None
                contributor = get_user(email=email)

        # Add unclaimed record if necessary
        if not contributor.is_registered:
            contributor.add_unclaimed_record(node, referrer=auth.user,
                given_name=fullname,
                email=email)
            contributor.save()

        contribs.append({
            'user': contributor,
            'visible': visible,
            'permissions': expand_permissions(contrib_dict.get('permission'))
        })
    return contribs
Esempio n. 17
0
def register_user(**kwargs):
    """
    Register new user account.
    HTTP Method: POST

    :param-json str email1:
    :param-json str email2:
    :param-json str password:
    :param-json str fullName:
    :param-json str campaign:

    :raises: HTTPError(http.BAD_REQUEST) if validation fails or user already exists
    """

    # Verify that email address match.
    # Note: Both `landing.mako` and `register.mako` already have this check on the form. Users can not submit the form
    # if emails do not match. However, this check should not be removed given we may use the raw api call directly.
    json_data = request.get_json()
    if str(json_data['email1']).lower() != str(json_data['email2']).lower():
        raise HTTPError(http.BAD_REQUEST,
                        data=dict(message_long='Email addresses must match.'))

    # Verify that captcha is valid
    if settings.RECAPTCHA_SITE_KEY and not validate_recaptcha(
            json_data.get('g-recaptcha-response'),
            remote_ip=request.remote_addr):
        raise HTTPError(http.BAD_REQUEST,
                        data=dict(message_long='Invalid Captcha'))

    try:
        full_name = request.json['fullName']
        full_name = strip_html(full_name)

        campaign = json_data.get('campaign')
        if campaign and campaign not in campaigns.get_campaigns():
            campaign = None

        user = framework_auth.register_unconfirmed(
            request.json['email1'],
            request.json['password'],
            full_name,
            campaign=campaign,
        )
        framework_auth.signals.user_registered.send(user)
    except (ValidationValueError, DuplicateEmailError):
        raise HTTPError(
            http.BAD_REQUEST,
            data=dict(message_long=language.ALREADY_REGISTERED.format(
                email=markupsafe.escape(request.json['email1']))))
    except ValidationError as e:
        raise HTTPError(http.BAD_REQUEST, data=dict(message_long=e.message))

    if settings.CONFIRM_REGISTRATIONS_BY_EMAIL:
        send_confirm_email(user, email=user.username)
        message = language.REGISTRATION_SUCCESS.format(email=user.username)
        return {'message': message}
    else:
        return {'message': 'You may now log in.'}
Esempio n. 18
0
def project_new_post(auth, **kwargs):
    user = auth.user

    data = request.get_json()
    title = strip_html(data.get('title'))
    title = title.strip()
    category = data.get('category', 'project')
    template = data.get('template')
    description = strip_html(data.get('description'))
    new_project = {}

    if template:
        original_node = AbstractNode.load(template)
        changes = {
            'title': title,
            'category': category,
            'template_node': original_node,
        }

        if description:
            changes['description'] = description

        project = original_node.use_as_template(
            auth=auth,
            changes={
                template: changes,
            }
        )

    else:
        try:
            project = new_node(category, title, user, description)
        except ValidationError as e:
            raise HTTPError(
                http.BAD_REQUEST,
                data=dict(message_long=e.message)
            )
        new_project = _view_project(project, auth)
    return {
        'projectUrl': project.url,
        'newNode': new_project['node'] if new_project else None
    }, http.CREATED
Esempio n. 19
0
def project_new_post(auth, **kwargs):
    user = auth.user

    data = request.get_json()
    title = strip_html(data.get('title'))
    title = title.strip()
    category = data.get('category', 'project')
    template = data.get('template')
    description = strip_html(data.get('description'))
    new_project = {}

    if template:
        original_node = AbstractNode.load(template)
        changes = {
            'title': title,
            'category': category,
            'template_node': original_node,
        }

        if description:
            changes['description'] = description

        project = original_node.use_as_template(
            auth=auth,
            changes={
                template: changes,
            }
        )

    else:
        try:
            project = new_node(category, title, user, description)
        except ValidationError as e:
            raise HTTPError(
                http.BAD_REQUEST,
                data=dict(message_long=e.message)
            )
        new_project = _view_project(project, auth)
    return {
        'projectUrl': project.url,
        'newNode': new_project['node'] if new_project else None
    }, http.CREATED
Esempio n. 20
0
    def test_field_content_is_sanitized_upon_submission(
            self, app, data_sample, user_one, url_token_list):
        bad_text = '<a href="http://sanitized.name">User_text</a>'
        cleaned_text = sanitize.strip_html(bad_text)

        payload = copy.deepcopy(data_sample)
        payload['data']['attributes']['name'] = bad_text

        res = app.post_json_api(url_token_list, payload, auth=user_one.auth)
        assert res.status_code == 201
        assert res.json['data']['attributes']['name'] == cleaned_text
Esempio n. 21
0
 def test_update_user_sanitizes_html_properly(
         self, app, user_one, url_user_one):
     """Post request should update resource, and any HTML in fields should be stripped"""
     bad_fullname = 'Malcolm <strong>X</strong>'
     bad_family_name = 'X <script>alert("is")</script> a cool name'
     res = app.patch_json_api(url_user_one, {
         'data': {
             'id': user_one._id,
             'type': 'users',
             'attributes': {
                 'full_name': bad_fullname,
                 'family_name': bad_family_name,
             }
         }
     }, auth=user_one.auth)
     assert res.status_code == 200
     assert res.json['data']['attributes']['full_name'] == strip_html(
         bad_fullname)
     assert res.json['data']['attributes']['family_name'] == strip_html(
         bad_family_name)
Esempio n. 22
0
    def test_field_content_is_sanitized_upon_submission(
            self, app, data_sample, user_one, url_token_list):
        bad_text = '<a href="http://sanitized.name">User_text</a>'
        cleaned_text = sanitize.strip_html(bad_text)

        payload = copy.deepcopy(data_sample)
        payload['data']['attributes']['name'] = bad_text

        res = app.post_json_api(url_token_list, payload, auth=user_one.auth)
        assert res.status_code == 201
        assert res.json['data']['attributes']['name'] == cleaned_text
Esempio n. 23
0
    def test_field_content_is_sanitized_upon_submission(
            self, app, user, url, sample_data):
        bad_text = '<a href=\'http://sanitized.name\'>User_text</a>'
        cleaned_text = sanitize.strip_html(bad_text)

        payload = copy.copy(sample_data)
        payload['data']['attributes']['name'] = bad_text
        payload['data']['attributes']['description'] = bad_text

        res = app.post_json_api(url, payload, auth=user.auth)
        assert res.status_code == 201
        assert res.json['data']['attributes']['name'] == cleaned_text
Esempio n. 24
0
    def test_field_content_is_sanitized_upon_submission(
            self, app, user, url, sample_data):
        bad_text = '<a href=\'http://sanitized.name\'>User_text</a>'
        cleaned_text = sanitize.strip_html(bad_text)

        payload = copy.copy(sample_data)
        payload['data']['attributes']['name'] = bad_text
        payload['data']['attributes']['description'] = bad_text

        res = app.post_json_api(url, payload, auth=user.auth)
        assert res.status_code == 201
        assert res.json['data']['attributes']['name'] == cleaned_text
Esempio n. 25
0
 def test_update_user_sanitizes_html_properly(self, app, user_one,
                                              url_user_one):
     """Post request should update resource, and any HTML in fields should be stripped"""
     bad_fullname = 'Malcolm <strong>X</strong>'
     bad_family_name = 'X <script>alert("is")</script> a cool name'
     res = app.patch_json_api(url_user_one, {
         'data': {
             'id': user_one._id,
             'type': 'users',
             'attributes': {
                 'full_name': bad_fullname,
                 'family_name': bad_family_name,
             }
         }
     },
                              auth=user_one.auth)
     assert res.status_code == 200
     assert res.json['data']['attributes']['full_name'] == strip_html(
         bad_fullname)
     assert res.json['data']['attributes']['family_name'] == strip_html(
         bad_family_name)
Esempio n. 26
0
def project_new_node(auth, node, **kwargs):
    form = NewNodeForm(request.form)
    user = auth.user
    if form.validate():
        try:
            new_component = new_node(
                title=strip_html(form.title.data),
                user=user,
                category=form.category.data,
                parent=node,
            )
        except ValidationError as e:
            raise HTTPError(http.BAD_REQUEST,
                            data=dict(message_long=e.message))
        redirect_url = node.url
        message = (
            'Your component was created successfully. You can keep working on the project page below, '
            'or go to the new <u><a href={component_url}>component</a></u>.'
        ).format(component_url=new_component.url)
        if form.inherit_contributors.data and node.has_permission(user, WRITE):
            for contributor in node.contributors:
                perm = CREATOR_PERMISSIONS if contributor._id == user._id else node.get_permissions(
                    contributor)
                if contributor._id == user._id and not contributor.is_registered:
                    new_component.add_unregistered_contributor(
                        fullname=contributor.fullname,
                        email=contributor.email,
                        permissions=perm,
                        auth=auth,
                        existing_user=contributor)
                else:
                    new_component.add_contributor(contributor,
                                                  permissions=perm,
                                                  auth=auth)

            new_component.save()
            redirect_url = new_component.url + 'contributors/'
            message = (
                'Your component was created successfully. You can edit the contributor permissions below, '
                'work on your <u><a href={component_url}>component</a></u> or return to the <u> '
                '<a href="{project_url}">project page</a></u>.').format(
                    component_url=new_component.url, project_url=node.url)
        status.push_status_message(message, kind='info', trust=True)

        return {
            'status': 'success',
        }, 201, None, redirect_url
    else:
        # TODO: This function doesn't seem to exist anymore?
        status.push_errors_to_status(form.errors)
    raise HTTPError(http.BAD_REQUEST, redirect_url=node.url)
Esempio n. 27
0
def map_schemas_to_schemablocks(*args):
    """Map schemas to schema blocks

    WARNING: Deletes existing schema blocks
    """
    state = args[0] if args else apps
    try:
        schema_model = state.get_model('osf', 'registrationschema')
    except LookupError:
        # Use MetaSchema model if migrating from a version before RegistrationSchema existed
        schema_model = state.get_model('osf', 'metaschema')

    try:
        RegistrationSchemaBlock = state.get_model('osf',
                                                  'registrationschemablock')
    except LookupError:
        return  # can't create SchemaBlocks if they don't exist

    for rs in schema_model.objects.all():
        if RegistrationSchemaBlock.objects.filter(schema_id=rs.id).exists():
            continue

        logger.info('Migrating schema {}, version {} to schema blocks.'.format(
            rs.name, rs.schema_version))
        if rs.schema.get('atomicSchema'):
            create_schema_blocks_for_atomic_schema(rs)
            continue

        for page in rs.schema['pages']:
            # Create page heading block
            create_schema_block(state,
                                rs.id,
                                'page-heading',
                                display_text=strip_html(page.get('title', '')),
                                help_text=strip_html(
                                    page.get('description', '')))
            for question in page['questions']:
                create_schema_blocks_for_question(state, rs, question)
Esempio n. 28
0
def new_private_link(name, user, nodes, anonymous):
    """Create a new private link.

    :param str name: private link name
    :param User user: User object
    :param list Node node: a list of node object
    :param bool anonymous: make link anonymous or not
    :return PrivateLink: Created private link

    """
    PrivateLink = apps.get_model('osf.PrivateLink')
    NodeLog = apps.get_model('osf.NodeLog')

    key = str(uuid.uuid4()).replace('-', '')
    if name:
        name = strip_html(name)
        if name is None or not name.strip():
            raise ValidationError('Invalid link name.')
    else:
        name = 'Shared project link'

    private_link = PrivateLink(
        key=key,
        name=name,
        creator=user,
        anonymous=anonymous
    )

    private_link.save()

    private_link.nodes.add(*nodes)

    auth = Auth(user)
    for node in nodes:
        log_dict = {
            'project': node.parent_id,
            'node': node._id,
            'user': user._id,
            'anonymous_link': anonymous,
        }

        node.add_log(
            NodeLog.VIEW_ONLY_LINK_ADDED,
            log_dict,
            auth=auth
        )

    private_link.save()

    return private_link
Esempio n. 29
0
def new_private_link(name, user, nodes, anonymous):
    """Create a new private link.

    :param str name: private link name
    :param User user: User object
    :param list Node node: a list of node object
    :param bool anonymous: make link anonymous or not
    :return PrivateLink: Created private link

    """
    PrivateLink = apps.get_model('osf.PrivateLink')
    NodeLog = apps.get_model('osf.NodeLog')

    key = str(uuid.uuid4()).replace('-', '')
    if name:
        name = strip_html(name)
        if name is None or not name.strip():
            raise ValidationError('Invalid link name.')
    else:
        name = 'Shared project link'

    private_link = PrivateLink(
        key=key,
        name=name,
        creator=user,
        anonymous=anonymous
    )

    private_link.save()

    private_link.nodes.add(*nodes)

    auth = Auth(user)
    for node in nodes:
        log_dict = {
            'project': node.parent_id,
            'node': node._id,
            'user': user._id,
            'anonymous_link': anonymous,
        }

        node.add_log(
            NodeLog.VIEW_ONLY_LINK_ADDED,
            log_dict,
            auth=auth
        )

    private_link.save()

    return private_link
Esempio n. 30
0
def project_new_node(auth, node, **kwargs):
    form = NewNodeForm(request.form)
    user = auth.user
    if form.validate():
        try:
            new_component = new_node(
                title=strip_html(form.title.data),
                user=user,
                category=form.category.data,
                parent=node,
            )
        except ValidationError as e:
            raise HTTPError(
                http.BAD_REQUEST,
                data=dict(message_long=e.message)
            )
        redirect_url = node.url
        message = (
            'Your component was created successfully. You can keep working on the project page below, '
            'or go to the new <u><a href={component_url}>component</a></u>.'
        ).format(component_url=new_component.url)
        if form.inherit_contributors.data and node.has_permission(user, WRITE):
            for contributor in node.contributors:
                perm = CREATOR_PERMISSIONS if contributor._id == user._id else node.get_permissions(contributor)
                if contributor._id == user._id and not contributor.is_registered:
                    new_component.add_unregistered_contributor(
                        fullname=contributor.fullname, email=contributor.email,
                        permissions=perm, auth=auth, existing_user=contributor
                    )
                else:
                    new_component.add_contributor(contributor, permissions=perm, auth=auth)

            new_component.save()
            redirect_url = new_component.url + 'contributors/'
            message = (
                'Your component was created successfully. You can edit the contributor permissions below, '
                'work on your <u><a href={component_url}>component</a></u> or return to the <u> '
                '<a href="{project_url}">project page</a></u>.'
            ).format(component_url=new_component.url, project_url=node.url)
        status.push_status_message(message, kind='info', trust=True)

        return {
            'status': 'success',
        }, 201, None, redirect_url
    else:
        # TODO: This function doesn't seem to exist anymore?
        status.push_errors_to_status(form.errors)
    raise HTTPError(http.BAD_REQUEST, redirect_url=node.url)
Esempio n. 31
0
def validate_title(value):
    """Validator for Node#title. Makes sure that the value exists and is not
    above 512 characters.
    """
    if value is None or not value.strip():
        raise ValidationError('Title cannot be blank.')

    value = sanitize.strip_html(value)

    if value is None or not value.strip():
        raise ValidationError('Invalid title.')

    if len(value) > 512:
        raise ValidationError('Title cannot exceed 512 characters.')

    return True
Esempio n. 32
0
def validate_title(value):
    """Validator for Node#title. Makes sure that the value exists and is not
    above 200 characters.
    """
    if value is None or not value.strip():
        raise ValidationValueError('Title cannot be blank.')

    value = strip_html(value)

    if value is None or not value.strip():
        raise ValidationValueError('Invalid title.')

    if len(value) > 200:
        raise ValidationValueError('Title cannot exceed 200 characters.')

    return True
Esempio n. 33
0
def project_private_link_edit(auth, **kwargs):
    name = request.json.get('value', '')
    try:
        validate_title(name)
    except ValidationError as e:
        message = 'Invalid link name.' if e.message == 'Invalid title.' else e.message
        raise HTTPError(http.BAD_REQUEST, data=dict(message_long=message))

    private_link_id = request.json.get('pk', '')
    private_link = PrivateLink.load(private_link_id)

    if private_link:
        new_name = strip_html(name)
        private_link.name = new_name
        private_link.save()
        return new_name
    else:
        raise HTTPError(http.BAD_REQUEST,
                        data=dict(message_long='View-only link not found.'))
Esempio n. 34
0
def invite_contributor_post(node, **kwargs):
    """API view for inviting an unregistered user. Performs validation, but does not actually invite the user.

    Expects JSON arguments with 'fullname' (required) and email (not required).
    """
    fullname = request.json.get('fullname').strip()
    email = request.json.get('email')
    # Validate and sanitize inputs as needed. Email will raise error if invalid.
    fullname = sanitize.strip_html(fullname)
    if email:
        email = email.lower().strip()
        try:
            validate_email(email)
        except ValidationError as e:
            return {'status': 400, 'message': e.message}, 400

    if not fullname:
        return {
            'status': 400,
            'message': 'Full name field cannot be empty'
        }, 400

    # Check if email is in the database
    user = get_user(email=email)
    if user:
        if user.is_registered:
            msg = 'User is already in database. Please go back and try your search again.'
            return {'status': 400, 'message': msg}, 400
        elif node.is_contributor(user):
            msg = 'User with this email address is already a contributor to this project.'
            return {'status': 400, 'message': msg}, 400
        elif not user.is_confirmed:
            serialized = profile_utils.serialize_unregistered(fullname, email)
        else:
            serialized = profile_utils.add_contributor_json(user)
            # use correct display name
            serialized['fullname'] = fullname
            serialized['email'] = email
    else:
        # Create a placeholder
        serialized = profile_utils.serialize_unregistered(fullname, email)
    return {'status': 'success', 'contributor': serialized}
Esempio n. 35
0
def invite_contributor_post(node, **kwargs):
    """API view for inviting an unregistered user. Performs validation, but does not actually invite the user.

    Expects JSON arguments with 'fullname' (required) and email (not required).
    """
    fullname = request.json.get('fullname').strip()
    email = request.json.get('email')
    # Validate and sanitize inputs as needed. Email will raise error if invalid.
    fullname = sanitize.strip_html(fullname)
    if email:
        email = email.lower().strip()
        try:
            validate_email(email)
        except ValidationError as e:
            return {'status': 400, 'message': e.message}, 400

    if not fullname:
        return {'status': 400, 'message': 'Full name field cannot be empty'}, 400

    # Check if email is in the database
    user = get_user(email=email)
    if user:
        if user.is_registered:
            msg = 'User is already in database. Please go back and try your search again.'
            return {'status': 400, 'message': msg}, 400
        elif node.is_contributor(user):
            msg = 'User with this email address is already a contributor to this project.'
            return {'status': 400, 'message': msg}, 400
        elif not user.is_confirmed:
            serialized = profile_utils.serialize_unregistered(fullname, email)
        else:
            serialized = profile_utils.add_contributor_json(user)
            # use correct display name
            serialized['fullname'] = fullname
            serialized['email'] = email
    else:
        # Create a placeholder
        serialized = profile_utils.serialize_unregistered(fullname, email)
    return {'status': 'success', 'contributor': serialized}
    def set_group_name(self, name, auth=None):
        """Set the name of the group.

        :param str new Name: The new osf group name
        :param auth: Auth object
        """
        self._require_manager_permission(auth)
        new_name = sanitize.strip_html(name)
        # Title hasn't changed after sanitzation, bail out
        if self.name == new_name:
            return False
        old_name = self.name
        self.name = new_name

        self.add_log(OSFGroupLog.EDITED_NAME,
                     params={
                         'group': self._id,
                         'name_original': old_name
                     },
                     auth=auth)
        self.update_search()
        for node in self.nodes:
            node.update_search()
Esempio n. 37
0
def project_private_link_edit(auth, **kwargs):
    name = request.json.get('value', '')
    try:
        validate_title(name)
    except ValidationError as e:
        message = 'Invalid link name.' if e.message == 'Invalid title.' else e.message
        raise HTTPError(
            http.BAD_REQUEST,
            data=dict(message_long=message)
        )

    private_link_id = request.json.get('pk', '')
    private_link = PrivateLink.load(private_link_id)

    if private_link:
        new_name = strip_html(name)
        private_link.name = new_name
        private_link.save()
        return new_name
    else:
        raise HTTPError(
            http.BAD_REQUEST,
            data=dict(message_long='View-only link not found.')
        )
Esempio n. 38
0
 def __call__(self, form, field):
     if not field.data == strip_html(field.data):
         raise ValidationError(self.message)
Esempio n. 39
0
def register_user(**kwargs):
    """
    Register new user account.
    HTTP Method: POST

    :param-json str email1:
    :param-json str email2:
    :param-json str password:
    :param-json str fullName:
    :param-json str campaign:

    :raises: HTTPError(http.BAD_REQUEST) if validation fails or user already exists
    """

    # Verify that email address match.
    # Note: Both `landing.mako` and `register.mako` already have this check on the form. Users can not submit the form
    # if emails do not match. However, this check should not be removed given we may use the raw api call directly.
    json_data = request.get_json()
    if str(json_data['email1']).lower() != str(json_data['email2']).lower():
        raise HTTPError(
            http.BAD_REQUEST,
            data=dict(message_long='Email addresses must match.')
        )

    # Verify that captcha is valid
    if settings.RECAPTCHA_SITE_KEY and not validate_recaptcha(json_data.get('g-recaptcha-response'), remote_ip=request.remote_addr):
        raise HTTPError(
            http.BAD_REQUEST,
            data=dict(message_long='Invalid Captcha')
        )

    try:
        full_name = request.json['fullName']
        full_name = strip_html(full_name)

        campaign = json_data.get('campaign')
        if campaign and campaign not in campaigns.get_campaigns():
            campaign = None

        accepted_terms_of_service = timezone.now() if json_data.get('acceptedTermsOfService') else None
        user = framework_auth.register_unconfirmed(
            request.json['email1'],
            request.json['password'],
            full_name,
            campaign=campaign,
            accepted_terms_of_service=accepted_terms_of_service
        )
        framework_auth.signals.user_registered.send(user)
    except (ValidationValueError, DuplicateEmailError):
        raise HTTPError(
            http.BAD_REQUEST,
            data=dict(
                message_long=language.ALREADY_REGISTERED.format(
                    email=markupsafe.escape(request.json['email1'])
                )
            )
        )
    except BlacklistedEmailError as e:
        raise HTTPError(
            http.BAD_REQUEST,
            data=dict(message_long=language.BLACKLISTED_EMAIL)
        )
    except ValidationError as e:
        raise HTTPError(
            http.BAD_REQUEST,
            data=dict(message_long=e.message)
        )

    if settings.CONFIRM_REGISTRATIONS_BY_EMAIL:
        send_confirm_email(user, email=user.username)
        message = language.REGISTRATION_SUCCESS.format(email=user.username)
        return {'message': message}
    else:
        return {'message': 'You may now log in.'}
Esempio n. 40
0
 def __call__(self, form, field):
     if not field.data == strip_html(field.data):
         raise ValidationError(self.message)
def get_custom_publish_text(connection):
    if connection is None:
        return ''
    return strip_html(connection.get_custom_publish_text(),
                      tags=['strong', 'li', 'ul'])
 def test_strip_html_sanitizes_collection_types_as_strings(self):
     assert_equal(sanitize.strip_html({'foo': '<b>bar</b>'}), "{'foo': 'bar'}")
     assert_equal(sanitize.strip_html(['<em>baz</em>']), "['baz']")
Esempio n. 43
0
def get_custom_publish_text(connection):
    if connection is None:
        return ''
    return strip_html(connection.get_custom_publish_text(), tags=['strong', 'li', 'ul'])