Ejemplo n.º 1
0
    def update_or_create(self, ctx, abstract_transaction: AbstractTransaction, id: Optional[int] = None) -> Tuple[Transaction, bool]:
        if abstract_transaction.src == abstract_transaction.dst:
            raise ValidationError('the source and destination accounts must not be the same')
        if abstract_transaction.value is None:
            raise ValidationError('the value field should not be None')
        if abstract_transaction.value <= 0:
            raise IntMustBePositive('value')

        if Roles.TRESO_WRITE.value not in ctx.get(CTX_ROLES):
            abstract_transaction.pending_validation = True

        transaction, created = super().update_or_create(ctx, abstract_transaction, id=id)

        if created:
            LOG.info('cashbox_update', extra=log_extra(
                ctx,
                value_modifier=abstract_transaction.value,
                transaction=transaction,
            ))
            if transaction.cashbox == "to":
                self.cashbox_repository.update(ctx, value_modifier=transaction.value, transaction=transaction)
            elif transaction.cashbox == "from":
                self.cashbox_repository.update(ctx, value_modifier=-transaction.value, transaction=transaction)
                
        return transaction, created
Ejemplo n.º 2
0
    def wrapper(cls, ctx, *args, **kwargs):
        """
        Wrap http_api function.
        """
        class_name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', type(cls).__name__)
        class_name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', class_name).lower()

        log_kwargs = {}
        log_args = []
        for key, value in kwargs.items():
            if hasattr(adh6.entity, type(value).__name__):
                log_kwargs[key] = value.to_dict()
            else:
                log_kwargs[key] = value

        for arg in args:
            if hasattr(adh6.entity, type(arg).__name__):
                log_args.append(arg.to_dict())
            else:
                log_args.append(arg)

        log_kwargs["__args"] = log_args
        LOG.info(class_name + "_" + f.__name__ + "_called",
                    extra=log_extra(ctx, **log_kwargs))
        return f(cls, ctx, *args, **kwargs)
Ejemplo n.º 3
0
    def get_cashbox(self, ctx) -> Tuple[int, int]:
        fond, coffre = self.cashbox_repository.get(ctx)

        # Log action.
        LOG.info('cashbox_get', extra=log_extra(
            ctx
        ))
        return fond, coffre
Ejemplo n.º 4
0
    def is_healthy(self, ctx) -> bool:
        db_health = self.health_repository.ping(ctx)
        if not db_health:
            LOG.error("health_check_db_not_healthy", extra=log_extra(ctx))
            return False

        # TODO: add more health checks?

        LOG.info("health_check_success", extra=log_extra(ctx))
        return True
Ejemplo n.º 5
0
    def __init__(self):
        from flask import current_app
        self.config = current_app.config

        if 'ELK_HOSTS' not in self.config:
            return

        LOG.info('About to instantiate ElasticSearch')
        LOG.debug('ELK_HOSTS:' + str(self.config['ELK_HOSTS']))
        self.es = Elasticsearch(self.config['ELK_HOSTS'],
                                http_auth=(self.config['ELK_USER'],
                                           self.config['ELK_SECRET']))
Ejemplo n.º 6
0
    def wrapper(*args,**kwargs):
        """
        Wrap http_api function.
        """
        s = session_handler.session() if session_handler else db.session()

        if "token_info" not in connexion.context:
            LOG.warning('could_not_extract_token_info_kwargs')
            raise UnauthenticatedError("Not token informations")

        token_info = connexion.context["token_info"]
        testing = current_app.config["TESTING"]
        ctx = build_context(
            session=s,
            testing=testing,
            request_id=str(uuid.uuid4()),  # Generates an unique ID on this request so we can track it.
            url=request.url,
            admin=token_info.get("uid", ""),
            roles=token_info.get("scope", [])
        )
        kwargs["ctx"] = ctx
        try:
            result = f(*args, **kwargs)

            # It makes things clearer and less error-prone.
            if not isinstance(result, tuple) or len(result) <= 1:
                raise ValueError("Please always pass the result AND the HTTP code.")

            status_code = result[1]
            msg = result[0]
            if result[0] == NoContent:
                msg = None
            if status_code and (200 <= status_code <= 299 or status_code == 302):
                s.commit()
            else:
                LOG.info("rollback_sql_transaction_non_200_http_code",
                         extra=log_extra(ctx, code=status_code, message=msg))
                s.rollback()
            return result

        except Exception as e:
            LOG.error("rollback_sql_transaction_exception_caught",
                      extra=log_extra(ctx, exception=str(e), traceback=traceback.format_exc()))
            s.rollback()
            raise

        finally:
            # When running unit tests, we don't close the session so tests can actually perform some work on that
            # session.
            if not testing:
                s.close()
Ejemplo n.º 7
0
def apikey_auth(token: str, required_scopes):
    try:
        from hashlib import sha3_512
        api_key = api_key_repository.find(token_hash=sha3_512(token.encode("utf-8")).hexdigest())[0]
        if not api_key or not api_key.login:
            raise
        roles = [
            i.role for i in role_repository.find(
                method=AuthenticationMethod.API_KEY, 
                identifiers=[str(api_key.id) if api_key.id else ""]
            )[0]
        ]
        if len(set(roles)&set(required_scopes)) != len(required_scopes):
            raise Unauthorized('invalid api key')
    except Exception as e:
        LOG.info(e)
        raise Unauthorized('invalid api key')
    return {
        "uid": role_repository.user_id_from_username(login=api_key.login),
        "scope": roles
    }
Ejemplo n.º 8
0
    def create_subscription(self, ctx, member_id: int,
                            body: SubscriptionBody) -> Membership:
        """
        Core use case of ADH. Registers a membership.

        User story: As an admin, I can create a new membership record, so that a member can have internet access.
        :param ctx: context
        :param member_id: member_id
        :param membership: entity AbstractMembership

        :raise IntMustBePositiveException
        :raise NoPriceAssignedToThatDurationException
        :raise MemberNotFound
        :raise UnknownPaymentMethod
        """

        member = self.member_repository.get_by_id(ctx, member_id)
        if not member:
            raise MemberNotFoundError(member_id)

        latest_subscription = self.latest_subscription(ctx=ctx,
                                                       member_id=member_id)

        if latest_subscription and latest_subscription.status not in [
                MembershipStatus.COMPLETE.value,
                MembershipStatus.CANCELLED.value,
                MembershipStatus.ABORTED.value
        ]:
            raise MembershipAlreadyExist(latest_subscription.status)

        state = MembershipStatus.PENDING_RULES

        if state == MembershipStatus.PENDING_RULES:
            date_signed_minet = self.charter_repository.get(
                ctx, member_id=member_id, charter_id=1)
            if date_signed_minet is not None and date_signed_minet != "":
                LOG.debug(
                    "create_membership_record_switch_status_to_pending_payment_initial"
                )
                state = MembershipStatus.PENDING_PAYMENT_INITIAL

        if state == MembershipStatus.PENDING_PAYMENT_INITIAL:
            if body.duration is not None and body.duration != 0:
                if body.duration not in self.duration_price:
                    LOG.warning("create_membership_record_no_price_defined",
                                extra=log_extra(ctx, duration=body.duration))
                    raise NoPriceAssignedToThatDuration(body.duration)
                LOG.debug(
                    "create_membership_record_switch_status_to_pending_payment"
                )
                state = MembershipStatus.PENDING_PAYMENT

        if state == MembershipStatus.PENDING_PAYMENT:
            if body.account is not None and body.payment_method is not None:
                account = self.account_repository.get_by_id(ctx, body.account)
                if not account:
                    raise AccountNotFoundError(body.account)
                payment_method = self.payment_method_repository.get_by_id(
                    ctx, body.payment_method)
                if not payment_method:
                    raise PaymentMethodNotFoundError(body.payment_method)
                LOG.debug(
                    "create_membership_record_switch_status_to_pending_payment_validation"
                )
                state = MembershipStatus.PENDING_PAYMENT_VALIDATION

        try:
            membership_created = self.membership_repository.create(
                ctx, body, state)
        except UnknownPaymentMethod:
            LOG.warning("create_membership_record_unknown_payment_method",
                        extra=log_extra(ctx,
                                        payment_method=body.payment_method))
            raise

        LOG.info("create_membership_record",
                 extra=log_extra(ctx,
                                 membership_uuis=membership_created.uuid,
                                 membership_status=membership_created.status))

        return membership_created
Ejemplo n.º 9
0
    def get_logs(self,
                 ctx,
                 devices: List[Device],
                 limit=LOG_DEFAULT_LIMIT,
                 username=None,
                 dhcp: bool = False):
        """
        Get the logs related to the username and to the devices.
        :param ctx:  context
        :param username:  username
        :param devices:  MAC addresses of the devices
        :param limit: limit result
        :param dhcp: allow to query DHCP logs or not
        :return: logs
        """
        if ctx.get(CTX_TESTING
                   ):  # Do not actually query elasticsearch if testing...
            return [[1, "test_log"]]

        if not self.config['ELK_HOSTS']:
            raise LogFetchError('no elk host configured')

        # Prepare the elasticsearch query...
        if not dhcp:
            query = {
                "sort": {
                    '@timestamp': 'desc',  # Sort by time
                },
                "query": {
                    "bool": {
                        "filter": {
                            "match": {
                                "program": "radiusd"
                            }
                        },
                        "should":
                        [  # "should" in a "bool" query basically act as a "OR"
                            {
                                "match": {
                                    "radius_user": username
                                }
                            },  # Match every log mentioning this member
                            # rules to match MACs addresses are added in the next chunk of code
                        ],
                        "minimum_should_match":
                        1,
                    },
                },
                "_source":
                ["@timestamp", "message", "src_mac"
                 ],  # discard any other field than timestamp & message
                "size": limit,
                "from": 0,
            }
        else:
            query = {
                "sort": {
                    '@timestamp': 'desc',  # Sort by time
                },
                "query": {
                    "constant_score": {
                        "filter": {
                            "bool": {
                                "should": [],
                                "minimum_should_match": 1,
                            },
                        },
                    },
                },
                "_source": ["@timestamp", "message", "program", "src_mac"],
                # discard any other field than timestamp & message
                "size": limit,
                "from": 0,
            }

        # Add the macs to the "should"
        for d in devices:
            addr = d.mac
            variations = map(lambda x: {"match_phrase": {
                "src_mac": x
            }}, get_mac_variations(addr))

            if not dhcp:
                # noinspection PyTypeChecker
                query["query"]["bool"]["should"] += list(variations)
            else:
                # noinspection PyTypeChecker
                query["query"]["constant_score"]["filter"]["bool"][
                    "should"] += list(variations)

        LOG.info('About to query ElasticSearch')
        res = self.es.search(index="", body=query)['hits']['hits']

        if not dhcp:
            for r in res:
                #msg = re.sub('(?<=incorrect) \(.*(failed|incorrect)\)', '', r["_source"]["message"])
                #msg = re.sub('\(from client .* (cli |tunnel)', '', r["_source"]["message"])
                #msg = re.sub('\) ', '', msg)
                #msg = re.sub(' {0}P', ' P', msg)
                #r["_source"]["message"] = r["_source"]["message"]
                pass

        return list(
            map(
                lambda x: [
                    dateutil.parser.parse(x["_source"]["@timestamp"]), x[
                        "_source"]["message"]
                ], res))