<commit_before>from django.utils import timezone
from django.db.models import Max
from django.core.exceptions import ValidationError

from breach.analyzer import decide_next_world_state
from breach.backtracking_analyzer import decide_next_backtracking_world_state
from breach.models import Target, Round, SampleSet
from breach.sniffer import Sniffer

import string
import requests
import logging
import random


logger = logging.getLogger(__name__)

CALIBRATION_STEP = 0.1
CALIBRATION_SAMPLESET_WINDOW_CHECK = 3


class MaxReflectionLengthError(Exception):
    '''Custom exception to handle cases when maxreflectionlength
    is not sufficient for the attack to continue.'''
    pass


class Strategy(object):
    def __init__(self, victim):
        self._victim = victim

        sniffer_params = {
            'snifferendpoint': self._victim.snifferendpoint,
            'sourceip': self._victim.sourceip,
            'host': self._victim.target.host,
            'interface': self._victim.interface,
            'port': self._victim.target.port,
            'calibration_wait': self._victim.calibration_wait
        }
        self.sniffer = Sniffer(sniffer_params)

        # Extract maximum round index for the current victim.
        current_round_index = Round.objects.filter(victim=self._victim).aggregate(Max('index'))['index__max']

        if not current_round_index:
            current_round_index = 1
            self._analyzed = True
            try:
                self._begin_attack()
            except MaxReflectionLengthError:
                # If the initial round or samplesets cannot be created, end the analysis
                return

        self._choose_next_round(self._victim.target.method, current_round_index)

        self._analyzed = False

    def _choose_next_round(self, method, current_round_index):
        # Choose next round to analyze, based on the execution method.
        if method == Target.BACKTRACKING:
            max_accumulated_prob = Round.objects.filter(
                victim=self._victim,
                completed=None
            ).aggregate(Max('accumulated_probability'))

            # Check if more than one objects have the same accumulated
            # probability.
            if isinstance(max_accumulated_prob, list):
                max_value = max_accumulated_prob[0]['accumulated_probability__max']
                self._round = Round.objects.get(
                    victim=self._victim,
                    completed=None,
                    accumulated_probability=max_value)[0]
            else:
                max_value = max_accumulated_prob['accumulated_probability__max']
                self._round = Round.objects.get(
                    victim=self._victim,
                    completed=None,
                    accumulated_probability=max_value)

            if not self._round.started:
                self._round.started = timezone.now()
                self._round.save()
        else:
            self._round = Round.objects.filter(
                victim=self._victim,
                index=current_round_index
            )[0]

    def get_decrypted_secret(self):
        return self._round.knownsecret

    def _build_candidates_divide_conquer(self, state):
        candidate_alphabet_cardinality = len(state['knownalphabet']) / 2

        bottom_half = state['knownalphabet'][:candidate_alphabet_cardinality]
        top_half = state['knownalphabet'][candidate_alphabet_cardinality:]

        return [bottom_half, top_half]

    def _build_candidates_serial(self, state):
        return state['knownalphabet']

    def _build_candidates(self, state):
        '''Given a state of the world, produce a list of candidate alphabets.'''
        methods = {
            Target.SERIAL: self._build_candidates_serial,<commit_msg>Simplify next round pick for backtracking<commit_after>from django.utils import timezone
from django.db.models import Max
from django.core.exceptions import ValidationError

from breach.analyzer import decide_next_world_state
from breach.backtracking_analyzer import decide_next_backtracking_world_state
from breach.models import Target, Round, SampleSet
from breach.sniffer import Sniffer

import string
import requests
import logging
import random


logger = logging.getLogger(__name__)

CALIBRATION_STEP = 0.1
CALIBRATION_SAMPLESET_WINDOW_CHECK = 3


class MaxReflectionLengthError(Exception):
    '''Custom exception to handle cases when maxreflectionlength
    is not sufficient for the attack to continue.'''
    pass


class Strategy(object):
    def __init__(self, victim):
        self._victim = victim

        sniffer_params = {
            'snifferendpoint': self._victim.snifferendpoint,
            'sourceip': self._victim.sourceip,
            'host': self._victim.target.host,
            'interface': self._victim.interface,
            'port': self._victim.target.port,
            'calibration_wait': self._victim.calibration_wait
        }
        self.sniffer = Sniffer(sniffer_params)

        # Extract maximum round index for the current victim.
        current_round_index = Round.objects.filter(victim=self._victim).aggregate(Max('index'))['index__max']

        if not current_round_index:
            current_round_index = 1
            self._analyzed = True
            try:
                self._begin_attack()
            except MaxReflectionLengthError:
                # If the initial round or samplesets cannot be created, end the analysis
                return

        self._choose_next_round(self._victim.target.method, current_round_index)

        self._analyzed = False

    def _choose_next_round(self, method, current_round_index):
        # Choose next round to analyze, based on the execution method.
        if method == Target.BACKTRACKING:
            candidate_rounds = Round.objects.filter(
                victim=self._victim,
                completed=None
            ).order_by('-accumulated_probability')
            self._round = candidate_rounds[0]

            self._round.started = timezone.now()
            self._round.save()
        else:
            self._round = Round.objects.filter(
                victim=self._victim,
                index=current_round_index
            )[0]

    def get_decrypted_secret(self):
        return self._round.knownsecret

    def _build_candidates_divide_conquer(self, state):
        candidate_alphabet_cardinality = len(state['knownalphabet']) / 2

        bottom_half = state['knownalphabet'][:candidate_alphabet_cardinality]
        top_half = state['knownalphabet'][candidate_alphabet_cardinality:]

        return [bottom_half, top_half]

    def _build_candidates_serial(self, state):
        return state['knownalphabet']

    def _build_candidates(self, state):
        '''Given a state of the world, produce a list of candidate alphabets.'''
        methods = {
            Target.SERIAL: self._build_candidates_serial,
{'fraction_non_alphanumeric': 0.07571613646178206, 'fraction_numerical': 0.002159205412408234, 'mean_word_length': 2.564905079527963, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5293621', 'n_tokens_mistral': 1963, 'n_tokens_neox': 1826, 'n_words': 426}