File size: 5,565 Bytes
edec17e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b1b77d5
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
"""

Flare – Fernet şifreleme yardımcıları

- encrypt(): düz string → "enc:<blob>"

- decrypt(): enc:<blob> → düz string (veya enc: yoksa aynen döner)

Anahtar: FLARE_TOKEN_KEY (32-bayt, base64, URL-safe)



CLI Kullanımı:

  python encryption_utils.py enc "şifrelenecek metin" [--key KEY]

  python encryption_utils.py dec "enc:..." [--key KEY]

"""

import os
import sys
import argparse
from typing import Optional
from cryptography.fernet import Fernet, InvalidToken

try:
    from .logger import log_error, log_warning
except ImportError:
    # Fallback to simple print
    def log_error(msg, error=None):
        print(f"ERROR: {msg}", file=sys.stderr)
        if error:
            print(f"Details: {error}", file=sys.stderr)
    
    def log_warning(msg):
        print(f"WARNING: {msg}", file=sys.stderr)

_ENV_KEY = "FLARE_TOKEN_KEY"

def _get_key() -> Fernet:
    """Get encryption key with better error messages"""
    # Direkt environment variable kullan
    key = os.getenv(_ENV_KEY)
    
    # .env dosyasından yüklemeyi dene
    if not key:
        try:
            from dotenv import load_dotenv
            load_dotenv()
            key = os.getenv(_ENV_KEY)
        except ImportError:
            pass
    
    if not key:
        error_msg = (
            f"{_ENV_KEY} ortam değişkeni tanımlanmadı. "
            f"Lütfen 32-byte base64 key oluşturun: python generate_key.py"
        )
        log_error(error_msg)
        raise RuntimeError(error_msg)
    
    # Key formatını kontrol et
    try:
        return Fernet(key.encode())
    except Exception as e:
        error_msg = (
            f"{_ENV_KEY} geçersiz format. "
            f"32-byte base64 URL-safe key olmalı. "
            f"Yeni key için: python generate_key.py"
        )
        log_error(error_msg, error=str(e))
        raise RuntimeError(error_msg)

def encrypt(plain: str, key: Optional[str] = None) -> str:
    """düz string → enc:..."""
    if not plain:
        log_warning("Empty string passed to encrypt")
        return ""
    
    try:
        if key:
            f = Fernet(key.encode())
        else:
            f = _get_key()
        
        encrypted = f.encrypt(plain.encode()).decode()
        return "enc:" + encrypted
    except Exception as e:
        log_error("Encryption failed", error=str(e))
        raise

def decrypt(value: Optional[str], key: Optional[str] = None) -> Optional[str]:
    """enc:... ise çözer, değilse aynen döndürür"""
    if value is None or not isinstance(value, str):
        return value
    
    if not value.startswith("enc:"):
        return value
    
    token = value.split("enc:", 1)[1]
    
    try:
        if key:
            f = Fernet(key.encode())
        else:
            f = _get_key()
        
        decrypted = f.decrypt(token.encode()).decode()
        return decrypted
    except InvalidToken:
        error_msg = (
            "Şifre çözme başarısız. Muhtemel sebepler:\n"
            "1. FLARE_TOKEN_KEY değişti\n"
            "2. Şifreli veri bozuldu\n"
            "3. Farklı bir key ile şifrelendi"
        )
        log_error(error_msg)
        raise RuntimeError(error_msg)
    except Exception as e:
        log_error("Decryption error", error=str(e))
        raise

def generate_key() -> str:
    """Generate a new Fernet encryption key"""
    return Fernet.generate_key().decode()

def main():
    """CLI entry point"""
    parser = argparse.ArgumentParser(
        description="Fernet encryption/decryption utility",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""

Examples:

  # Generate a new key

  python encryption_utils.py keygen

  

  # Save generated key to .env file

  python encryption_utils.py keygen >> .env

  # Then edit .env to add: FLARE_TOKEN_KEY=<generated-key>

  

  # Encrypt with environment key

  python encryption_utils.py enc "secret message"

  

  # Encrypt with custom key

  python encryption_utils.py enc "secret message" --key "your-32-byte-base64-key"

  

  # Decrypt

  python encryption_utils.py dec "enc:gAAAAABh..."

  

  # Decrypt with custom key

  python encryption_utils.py dec "enc:gAAAAABh..." --key "your-32-byte-base64-key"

        """
    )
    
    parser.add_argument(
        "command",
        choices=["enc", "dec", "keygen"],
        help="Command to execute: 'enc' for encrypt, 'dec' for decrypt, 'keygen' to generate new key"
    )
    
    parser.add_argument(
        "text",
        nargs="?",
        help="Text to encrypt or decrypt (not needed for keygen)"
    )
    
    parser.add_argument(
        "--key",
        help="Optional Fernet key (32-byte base64). If not provided, uses FLARE_TOKEN_KEY env var"
    )
    
    args = parser.parse_args()
    
    try:
        if args.command == "keygen":
            key = generate_key()
            print(key)
        elif args.command == "enc":
            if not args.text:
                parser.error("Text is required for encryption")
            result = encrypt(args.text, args.key)
            print(result)
        else:  # dec
            if not args.text:
                parser.error("Text is required for decryption")
            result = decrypt(args.text, args.key)
            print(result)
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()