Esempio n. 1
0
    def post(self, namespace_name, repo_name, trigger_uuid):
        """
        List the subdirectories available for the specified build trigger and source.
        """
        trigger = get_trigger(trigger_uuid)

        user_permission = UserAdminPermission(trigger.connected_user.username)
        if user_permission.can():
            new_config_dict = request.get_json()
            handler = BuildTriggerHandler.get_handler(trigger, new_config_dict)

            try:
                subdirs = handler.list_build_subdirs()
                context_map = {}
                for file in subdirs:
                    context_map = handler.get_parent_directory_mappings(file, context_map)

                return {
                    "dockerfile_paths": ["/" + subdir for subdir in subdirs],
                    "contextMap": context_map,
                    "status": "success",
                }
            except EmptyRepositoryException as exc:
                return {
                    "status": "success",
                    "contextMap": {},
                    "dockerfile_paths": [],
                }
            except TriggerException as exc:
                return {
                    "status": "error",
                    "message": exc.message,
                }
        else:
            raise Unauthorized()
Esempio n. 2
0
    def get(self, namespace_name, repo_name, trigger_uuid):
        """ List the build sources for the trigger configuration thus far. """
        trigger = get_trigger(trigger_uuid)

        user_permission = UserAdminPermission(trigger.connected_user.username)
        if user_permission.can():
            handler = BuildTriggerHandler.get_handler(trigger)

            try:
                return {"namespaces": handler.list_build_source_namespaces()}
            except TriggerException as rre:
                raise InvalidRequest(rre.message)
        else:
            raise Unauthorized()
Esempio n. 3
0
def update_user(username):
    permission = UserAdminPermission(username)
    if permission.can():
        update_request = request.get_json()

        if "password" in update_request:
            logger.debug("Updating user password")
            model.user.change_password(get_authenticated_user(),
                                       update_request["password"])

        return jsonify({
            "username": get_authenticated_user().username,
            "email": get_authenticated_user().email,
        })

    abort(403)
Esempio n. 4
0
def update_user(username):
    permission = UserAdminPermission(username)
    if permission.can():
        update_request = request.get_json()

        if 'password' in update_request:
            logger.debug('Updating user password')
            model.user.change_password(get_authenticated_user(),
                                       update_request['password'])

        return jsonify({
            'username': get_authenticated_user().username,
            'email': get_authenticated_user().email,
        })

    abort(403)
Esempio n. 5
0
    def post(self, namespace_name, repo_name, trigger_uuid):
        """
        List the build sources for the trigger configuration thus far.
        """
        namespace = request.get_json().get("namespace")
        if namespace is None:
            raise InvalidRequest()

        trigger = get_trigger(trigger_uuid)

        user_permission = UserAdminPermission(trigger.connected_user.username)
        if user_permission.can():
            handler = BuildTriggerHandler.get_handler(trigger)

            try:
                return {"sources": handler.list_build_sources_for_namespace(namespace)}
            except TriggerException as rre:
                raise InvalidRequest(str(rre)) from rre
        else:
            raise Unauthorized()
Esempio n. 6
0
    def get(self, prefix, parsed_args):
        """
        Get a list of entities that match the specified prefix.
        """

        # Ensure we don't have any unicode characters in the search, as it breaks the search. Nothing
        # being searched can have unicode in it anyway, so this is a safe operation.
        prefix = prefix.encode("unidecode", "ignore").replace(" ", "").lower()

        teams = []
        org_data = []

        namespace_name = parsed_args["namespace"]
        robot_namespace = None
        organization = None

        try:
            organization = model.organization.get_organization(namespace_name)

            # namespace name was an org
            permission = OrganizationMemberPermission(namespace_name)
            if permission.can():
                robot_namespace = namespace_name

                if parsed_args["includeTeams"]:
                    teams = model.team.get_matching_teams(prefix, organization)

                if (parsed_args["includeOrgs"]
                        and AdministerOrganizationPermission(namespace_name)
                        and namespace_name.startswith(prefix)):
                    org_data = [{
                        "name":
                        namespace_name,
                        "kind":
                        "org",
                        "is_org_member":
                        True,
                        "avatar":
                        avatar.get_data_for_org(organization),
                    }]

        except model.organization.InvalidOrganizationException:
            # namespace name was a user
            user = get_authenticated_user()
            if user and user.username == namespace_name:
                # Check if there is admin user permissions (login only)
                admin_permission = UserAdminPermission(user.username)
                if admin_permission.can():
                    robot_namespace = namespace_name

        # Lookup users in the database for the prefix query.
        users = model.user.get_matching_users(
            prefix,
            robot_namespace,
            organization,
            limit=10,
            exact_matches_only=not features.PARTIAL_USER_AUTOCOMPLETE,
        )

        # Lookup users via the user system for the prefix query. We'll filter out any users that
        # already exist in the database.
        external_users, federated_id, _ = authentication.query_users(prefix,
                                                                     limit=10)
        filtered_external_users = []
        if external_users and federated_id is not None:
            users = list(users)
            user_ids = [user.id for user in users]

            # Filter the users if any are already found via the database. We do so by looking up all
            # the found users in the federated user system.
            federated_query = model.user.get_federated_logins(
                user_ids, federated_id)
            found = {result.service_ident for result in federated_query}
            filtered_external_users = [
                user for user in external_users if not user.username in found
            ]

        def entity_team_view(team):
            result = {
                "name": team.name,
                "kind": "team",
                "is_org_member": True,
                "avatar": avatar.get_data_for_team(team),
            }
            return result

        def user_view(user):
            user_json = {
                "name": user.username,
                "kind": "user",
                "is_robot": user.robot,
                "avatar": avatar.get_data_for_user(user),
            }

            if organization is not None:
                user_json["is_org_member"] = user.robot or user.is_org_member

            return user_json

        def external_view(user):
            result = {
                "name": user.username,
                "kind": "external",
                "title": user.email or "",
                "avatar": avatar.get_data_for_external_user(user),
            }
            return result

        team_data = [entity_team_view(team) for team in teams]
        user_data = [user_view(user) for user in users]
        external_data = [
            external_view(user) for user in filtered_external_users
        ]

        return {"results": team_data + user_data + org_data + external_data}
Esempio n. 7
0
    def post(self, namespace_name, repo_name, trigger_uuid):
        """
        Activate the specified build trigger.
        """
        trigger = get_trigger(trigger_uuid)
        handler = BuildTriggerHandler.get_handler(trigger)
        if handler.is_active():
            raise InvalidRequest("Trigger config is not sufficient for activation.")

        user_permission = UserAdminPermission(trigger.connected_user.username)
        if user_permission.can():
            # Update the pull robot (if any).
            pull_robot_name = request.get_json().get("pull_robot", None)
            if pull_robot_name:
                try:
                    pull_robot = model.user.lookup_robot(pull_robot_name)
                except model.InvalidRobotException:
                    raise NotFound()

                # Make sure the user has administer permissions for the robot's namespace.
                (robot_namespace, _) = parse_robot_username(pull_robot_name)
                if not AdministerOrganizationPermission(robot_namespace).can():
                    raise Unauthorized()

                # Make sure the namespace matches that of the trigger.
                if robot_namespace != namespace_name:
                    raise Unauthorized()

                # Set the pull robot.
                trigger.pull_robot = pull_robot

            # Update the config.
            new_config_dict = request.get_json()["config"]

            write_token_name = "Build Trigger: %s" % trigger.service.name
            write_token = model.token.create_delegate_token(
                namespace_name, repo_name, write_token_name, "write"
            )

            try:
                path = url_for("webhooks.build_trigger_webhook", trigger_uuid=trigger.uuid)
                authed_url = _prepare_webhook_url(
                    app.config["PREFERRED_URL_SCHEME"],
                    "$token",
                    write_token.get_code(),
                    app.config["SERVER_HOSTNAME"],
                    path,
                )

                handler = BuildTriggerHandler.get_handler(trigger, new_config_dict)
                final_config, private_config = handler.activate(authed_url)

                if "private_key" in private_config:
                    trigger.secure_private_key = DecryptedValue(private_config["private_key"])

            except TriggerException as exc:
                write_token.delete_instance()
                raise request_error(message=exc.message)

            # Save the updated config.
            update_build_trigger(trigger, final_config, write_token=write_token)

            # Log the trigger setup.
            repo = model.repository.get_repository(namespace_name, repo_name)
            log_action(
                "setup_repo_trigger",
                namespace_name,
                {
                    "repo": repo_name,
                    "namespace": namespace_name,
                    "trigger_id": trigger.uuid,
                    "service": trigger.service.name,
                    "pull_robot": trigger.pull_robot.username if trigger.pull_robot else None,
                    "config": final_config,
                },
                repo=repo,
            )

            return trigger_view(trigger, can_admin=True)
        else:
            raise Unauthorized()
Esempio n. 8
0
def user_view(user, previous_username=None):
    def org_view(o, user_admin=True):
        admin_org = AdministerOrganizationPermission(o.username)
        org_response = {
            "name": o.username,
            "avatar": avatar.get_data_for_org(o),
            "can_create_repo": CreateRepositoryPermission(o.username).can(),
            "public": o.username in app.config.get("PUBLIC_NAMESPACES", []),
        }

        if user_admin:
            org_response.update(
                {
                    "is_org_admin": admin_org.can(),
                    "preferred_namespace": not (o.stripe_id is None),
                }
            )

        return org_response

    # Retrieve the organizations for the user.
    organizations = {
        o.username: o for o in model.organization.get_user_organizations(user.username)
    }

    # Add any public namespaces.
    public_namespaces = app.config.get("PUBLIC_NAMESPACES", [])
    if public_namespaces:
        organizations.update({ns: model.user.get_namespace_user(ns) for ns in public_namespaces})

    def login_view(login):
        try:
            metadata = json.loads(login.metadata_json)
        except:
            metadata = {}

        return {
            "service": login.service.name,
            "service_identifier": login.service_ident,
            "metadata": metadata,
        }

    logins = model.user.list_federated_logins(user)

    user_response = {
        "anonymous": False,
        "username": user.username,
        "avatar": avatar.get_data_for_user(user),
    }

    user_admin = UserAdminPermission(previous_username if previous_username else user.username)
    if user_admin.can():
        user_response.update(
            {
                "can_create_repo": True,
                "is_me": True,
                "verified": user.verified,
                "email": user.email,
                "logins": [login_view(login) for login in logins],
                "invoice_email": user.invoice_email,
                "invoice_email_address": user.invoice_email_address,
                "preferred_namespace": not (user.stripe_id is None),
                "tag_expiration_s": user.removed_tag_expiration_s,
                "prompts": model.user.get_user_prompts(user),
                "company": user.company,
                "family_name": user.family_name,
                "given_name": user.given_name,
                "location": user.location,
                "is_free_account": user.stripe_id is None,
                "has_password_set": authentication.has_password_set(user.username),
            }
        )

        if features.QUOTA_MANAGEMENT:
            quotas = model.namespacequota.get_namespace_quota_list(user.username)
            user_response["quotas"] = [quota_view(quota) for quota in quotas] if quotas else []
            user_response["quota_report"] = model.namespacequota.get_quota_for_view(user.username)

    user_view_perm = UserReadPermission(user.username)
    if user_view_perm.can():
        user_response.update(
            {
                "organizations": [
                    org_view(o, user_admin=user_admin.can()) for o in list(organizations.values())
                ],
            }
        )

    if features.SUPER_USERS and SuperUserPermission().can():
        user_response.update(
            {
                "super_user": user
                and user == get_authenticated_user()
                and SuperUserPermission().can()
            }
        )

    return user_response
Esempio n. 9
0
  def post(self, namespace_name, repo_name, trigger_uuid):
    """ Activate the specified build trigger. """
    trigger = get_trigger(trigger_uuid)
    handler = BuildTriggerHandler.get_handler(trigger)
    if handler.is_active():
      raise InvalidRequest('Trigger config is not sufficient for activation.')

    user_permission = UserAdminPermission(trigger.connected_user.username)
    if user_permission.can():
      # Update the pull robot (if any).
      pull_robot_name = request.get_json().get('pull_robot', None)
      if pull_robot_name:
        try:
          pull_robot = model.user.lookup_robot(pull_robot_name)
        except model.InvalidRobotException:
          raise NotFound()

        # Make sure the user has administer permissions for the robot's namespace.
        (robot_namespace, _) = parse_robot_username(pull_robot_name)
        if not AdministerOrganizationPermission(robot_namespace).can():
          raise Unauthorized()

        # Make sure the namespace matches that of the trigger.
        if robot_namespace != namespace_name:
          raise Unauthorized()

        # Set the pull robot.
        trigger.pull_robot = pull_robot

      # Update the config.
      new_config_dict = request.get_json()['config']

      write_token_name = 'Build Trigger: %s' % trigger.service.name
      write_token = model.token.create_delegate_token(namespace_name, repo_name, write_token_name,
                                                      'write')

      try:
        path = url_for('webhooks.build_trigger_webhook', trigger_uuid=trigger.uuid)
        authed_url = _prepare_webhook_url(app.config['PREFERRED_URL_SCHEME'],
                                          '$token', write_token.get_code(),
                                          app.config['SERVER_HOSTNAME'], path)

        handler = BuildTriggerHandler.get_handler(trigger, new_config_dict)
        final_config, private_config = handler.activate(authed_url)

        if 'private_key' in private_config:
          trigger.secure_private_key = DecryptedValue(private_config['private_key'])

          # TODO(remove-unenc): Remove legacy field.
          if ActiveDataMigration.has_flag(ERTMigrationFlags.WRITE_OLD_FIELDS):
            trigger.private_key = private_config['private_key']

      except TriggerException as exc:
        write_token.delete_instance()
        raise request_error(message=exc.message)

      # Save the updated config.
      update_build_trigger(trigger, final_config, write_token=write_token)

      # Log the trigger setup.
      repo = model.repository.get_repository(namespace_name, repo_name)
      log_action('setup_repo_trigger', namespace_name,
                 {'repo': repo_name, 'namespace': namespace_name,
                  'trigger_id': trigger.uuid, 'service': trigger.service.name,
                  'pull_robot': trigger.pull_robot.username if trigger.pull_robot else None,
                  'config': final_config},
                 repo=repo)

      return trigger_view(trigger, can_admin=True)
    else:
      raise Unauthorized()
Esempio n. 10
0
def user_view(user, previous_username=None):
    def org_view(o, user_admin=True):
        admin_org = AdministerOrganizationPermission(o.username)
        org_response = {
            'name': o.username,
            'avatar': avatar.get_data_for_org(o),
            'can_create_repo': CreateRepositoryPermission(o.username).can(),
            'public': o.username in app.config.get('PUBLIC_NAMESPACES', []),
        }

        if user_admin:
            org_response.update({
                'is_org_admin':
                admin_org.can(),
                'preferred_namespace':
                not (o.stripe_id is None),
            })

        return org_response

    # Retrieve the organizations for the user.
    organizations = {
        o.username: o
        for o in model.organization.get_user_organizations(user.username)
    }

    # Add any public namespaces.
    public_namespaces = app.config.get('PUBLIC_NAMESPACES', [])
    if public_namespaces:
        organizations.update({
            ns: model.user.get_namespace_user(ns)
            for ns in public_namespaces
        })

    def login_view(login):
        try:
            metadata = json.loads(login.metadata_json)
        except:
            metadata = {}

        return {
            'service': login.service.name,
            'service_identifier': login.service_ident,
            'metadata': metadata
        }

    logins = model.user.list_federated_logins(user)

    user_response = {
        'anonymous': False,
        'username': user.username,
        'avatar': avatar.get_data_for_user(user),
    }

    user_admin = UserAdminPermission(
        previous_username if previous_username else user.username)
    if user_admin.can():
        user_response.update({
            'can_create_repo':
            True,
            'is_me':
            True,
            'verified':
            user.verified,
            'email':
            user.email,
            'logins': [login_view(login) for login in logins],
            'invoice_email':
            user.invoice_email,
            'invoice_email_address':
            user.invoice_email_address,
            'preferred_namespace':
            not (user.stripe_id is None),
            'tag_expiration_s':
            user.removed_tag_expiration_s,
            'prompts':
            model.user.get_user_prompts(user),
            'company':
            user.company,
            'family_name':
            user.family_name,
            'given_name':
            user.given_name,
            'location':
            user.location,
            'is_free_account':
            user.stripe_id is None,
            'has_password_set':
            authentication.has_password_set(user.username),
        })

        analytics_metadata = user_analytics.get_user_analytics_metadata(user)

        # This is a sync call, but goes through the async wrapper interface and
        # returns a Future. By calling with timeout 0 immediately after the method
        # call, we ensure that if it ever accidentally becomes async it will raise
        # a TimeoutError.
        user_response.update(analytics_metadata.result(timeout=0))

    user_view_perm = UserReadPermission(user.username)
    if user_view_perm.can():
        user_response.update({
            'organizations': [
                org_view(o, user_admin=user_admin.can())
                for o in organizations.values()
            ],
        })

    if features.SUPER_USERS and SuperUserPermission().can():
        user_response.update({
            'super_user':
            user and user == get_authenticated_user()
            and SuperUserPermission().can()
        })

    return user_response