File size: 4,386 Bytes
4585d4c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
from collections import defaultdict
from typing import List, Dict, Tuple

from utils.helpers import generate_nonce, generate_entropy_layers

class OneRoundVerifier:
    """
    A simplified, one-round version of the 1P authentication system.
    Use this for quick challenges where a full multi-round authentication is not needed.
    """
    def __init__(self, secret: str, direction_mapping: Dict[str, str],
                 colors: List[str], direction_map: Dict[str, str], domains: Dict[str, str]):
        self.secret = secret
        self.direction_mapping = direction_mapping
        self.colors = colors
        self.direction_map = direction_map
        self.domains = domains
        self.nonce = None
        self.color_map = {}

    def generate_challenge(self) -> Tuple[str, str]:
        """
        Generates a one-round challenge grid.

        Returns:
            Tuple containing (grid_html, expected_direction_code)
        """
        self.nonce = generate_nonce()
        entropy = generate_entropy_layers(self.nonce, 1)[0]

        # Build combined alphabet from all domains
        alphabet = ""
        for domain_chars in self.domains.values():
            alphabet += domain_chars
        alphabet = ''.join(set(alphabet))  # Remove duplicates

        # Create rotated alphabet based on entropy
        offset = entropy % len(alphabet)
        rotated = alphabet[offset:] + alphabet[:offset]

        # Create color mapping
        self.color_map = {rotated[i]: self.colors[i % len(self.colors)] for i in range(len(rotated))}

        # Determine expected solution
        assigned_color = self.color_map.get(self.secret, None)
        if assigned_color is None:
            expected = "S"  # Skip if secret character not in grid
        else:
            direction = self.direction_mapping.get(assigned_color, "Skip")
            expected = self.direction_map[direction]

        # Generate the grid HTML
        grid_html = self._generate_grid_html()

        return grid_html, expected

    def _generate_grid_html(self) -> str:
        """Generate HTML for the challenge grid."""
        chars_by_color = defaultdict(list)
        for ch, color in self.color_map.items():
            chars_by_color[color].append(ch)

        grid_html = """
        <div style="border: 2px solid #333; padding: 15px; margin: 10px; background: #f8f9fa; border-radius: 8px;">
        <h4>🎯 One-Round Authentication</h4>
        <p><strong>Find your secret character and note its color!</strong></p>
        """

        color_hex_map = {"red": "#FF0000", "green": "#00AA00", "blue": "#0066FF", "yellow": "#FFD700"}

        for color in self.colors:
            chars = chars_by_color[color]
            if chars:
                grid_html += f'<div style="margin: 8px 0;"><strong style="color: {color_hex_map[color]};">{color.upper()}:</strong> '
                for char in chars:
                    grid_html += f'<span style="color: {color_hex_map[color]}; font-size: 18px; margin: 2px; padding: 4px; background: white; border-radius: 4px;">{char}</span> '
                grid_html += '</div>'

        grid_html += '</div>'
        return grid_html

    def verify_solution(self, user_input: str, expected: str) -> bool:
        """
        Verify if the user's solution matches the expected direction.

        Args:
            user_input: User's input direction code ("U", "D", "L", "R", "S")
            expected: Expected direction code

        Returns:
            True if the authentication is successful, False otherwise
        """
        return user_input == expected

def run_one_round_authentication(secret: str, direction_mapping: Dict[str, str],
                               colors: List[str], direction_map: Dict[str, str],
                               domains: Dict[str, str]) -> Tuple[str, str]:
    """
    Helper function to run a single round of authentication.

    Args:
        secret: The user's secret character
        direction_mapping: Mapping of colors to directions
        colors: List of available colors
        direction_map: Mapping of direction names to codes
        domains: Available character domains

    Returns:
        Tuple containing (grid_html, expected_direction_code)
    """
    verifier = OneRoundVerifier(secret, direction_mapping, colors, direction_map, domains)
    return verifier.generate_challenge()