Dashboard / Auth & Encryption
--:--:--
Staging Live
3 Alerts
Total Users
50
Mock dataset · Mockaroo
2FA Enrolled
—
— of users protected
Encrypted Fields
6
AES-256-GCM · at rest
Pending 2FA
—
— setup incomplete
User Security Status
Live · Staging DB
| User | Role | 2FA | OAuth | Phone (enc.) | Last Login |
|---|
Activity Log
Live
Field Encryption
AES-256-GCM
2FA Adoption
TOTP · RFC 6238
Enrollment rate
—
MonTueWedThuFriSatSun
Active 2FA—
Pending setup—
Not enrolled—
OAuth Providers
PKCE
🔴
Google
Active
—
⬡
GitHub
Active
—
✉
Email
bcrypt×12
—
Security Alerts
3 Open
AES-256-GCM — Core Encryption Snippet
Python · PyCryptodome
Production-ready
from Crypto.Cipher import AES
import os, base64
# 256-bit key loaded from env / secret vault — never hardcoded
KEY = bytes.fromhex(os.environ["AES_MASTER_KEY"]) # 32-byte key
def encrypt_field(plaintext: str) -> str:
cipher = AES.new(KEY, AES.MODE_GCM)
ct, tag = cipher.encrypt_and_digest(plaintext.encode("utf-8"))
# Pack: nonce(16) + tag(16) + ciphertext
return base64.b64encode(cipher.nonce + tag + ct).decode()
def decrypt_field(token: str) -> str:
raw = base64.b64decode(token)
nonce, tag, ct = raw[:16], raw[16:32], raw[32:]
cipher = AES.new(KEY, AES.MODE_GCM, nonce=nonce)
return cipher.decrypt_and_verify(ct, tag).decode("utf-8")
import os, base64
# 256-bit key loaded from env / secret vault — never hardcoded
KEY = bytes.fromhex(os.environ["AES_MASTER_KEY"]) # 32-byte key
def encrypt_field(plaintext: str) -> str:
cipher = AES.new(KEY, AES.MODE_GCM)
ct, tag = cipher.encrypt_and_digest(plaintext.encode("utf-8"))
# Pack: nonce(16) + tag(16) + ciphertext
return base64.b64encode(cipher.nonce + tag + ct).decode()
def decrypt_field(token: str) -> str:
raw = base64.b64decode(token)
nonce, tag, ct = raw[:16], raw[16:32], raw[32:]
cipher = AES.new(KEY, AES.MODE_GCM, nonce=nonce)
return cipher.decrypt_and_verify(ct, tag).decode("utf-8")
All Users
50 total
🔍
| User | Role | 2FA | OAuth | Actions |
|---|
TOTP Simulator
Google Authenticator
Simulate 2FA verification. The demo code changes every 30 seconds like a real TOTP token.
Current TOTP Code
------
Expires in 30s
Enter the 6-digit code to verify:
2FA Status Overview
All 50 users
Overall enrollment
—
| User | 2FA Status | Action |
|---|
Google OAuth
Active
Client IDconfigured ✓
Redirect URIconfigured ✓
Scopeemail, profile
FlowCode + PKCE
Users—
GitHub OAuth
Active
Client IDconfigured ✓
Redirect URIconfigured ✓
Scoperead:user, user:email
FlowCode + PKCE
Users—
Email / Password
bcrypt × 12
Hash algobcrypt
Work factor12 rounds
Saltauto-generated
Reset flowJWT · 15 min TTL
Users—
OAuth Flow — Authorization Code + PKCE
RFC 7636
# Flask-Dance — Google OAuth 2.0 + PKCE (simplified)
from flask import Flask, redirect, url_for, session
from flask_dance.contrib.google import make_google_blueprint, google
import os
app = Flask(__name__)
app.secret_key = os.environ["FLASK_SECRET"]
bp = make_google_blueprint(
client_id=os.environ["GOOGLE_CLIENT_ID"],
client_secret=os.environ["GOOGLE_CLIENT_SECRET"],
scope=["openid", "email", "profile"],
)
app.register_blueprint(bp, url_prefix="/login")
@app.route("/dashboard")
def dashboard():
if not google.authorized: return redirect(url_for("google.login"))
resp = google.get("/oauth2/v2/userinfo")
user = resp.json() # { email, name, picture, ... }
return f"Welcome {user['name']}"
from flask import Flask, redirect, url_for, session
from flask_dance.contrib.google import make_google_blueprint, google
import os
app = Flask(__name__)
app.secret_key = os.environ["FLASK_SECRET"]
bp = make_google_blueprint(
client_id=os.environ["GOOGLE_CLIENT_ID"],
client_secret=os.environ["GOOGLE_CLIENT_SECRET"],
scope=["openid", "email", "profile"],
)
app.register_blueprint(bp, url_prefix="/login")
@app.route("/dashboard")
def dashboard():
if not google.authorized: return redirect(url_for("google.login"))
resp = google.get("/oauth2/v2/userinfo")
user = resp.json() # { email, name, picture, ... }
return f"Welcome {user['name']}"
Field Encryption Status
AES-256-GCM
Live Encrypt / Decrypt Demo
Browser simulation
— click Encrypt to see output —
—
⚠ Browser simulation using Web Crypto AES-GCM (identical algorithm). Production uses PyCryptodome on the server.
Complete AES-256-GCM Implementation
Python · Full module
"""aes_crypto.py — Internee.pk field-level AES-256-GCM encryption"""
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import os, base64, json
from functools import wraps
# ── Key management ──────────────────────────────────────────────
_KEY: bytes | None = None
def load_key() -> bytes:
global _KEY
if _KEY is None:
hex_key = os.environ.get("AES_MASTER_KEY")
if not hex_key: raise RuntimeError("AES_MASTER_KEY not set")
_KEY = bytes.fromhex(hex_key)
if len(_KEY) != 32: raise ValueError("Key must be 256-bit (32 bytes)")
return _KEY
# ── Core encrypt / decrypt ───────────────────────────────────────
def encrypt_field(plaintext: str) -> str:
"""Encrypt a string field → base64(nonce+tag+ciphertext)"""
key = load_key()
cipher = AES.new(key, AES.MODE_GCM)
ct, tag = cipher.encrypt_and_digest(plaintext.encode("utf-8"))
return base64.b64encode(cipher.nonce + tag + ct).decode()
def decrypt_field(token: str) -> str:
"""Decrypt a base64 token → original string. Raises on tamper."""
key = load_key()
raw = base64.b64decode(token)
nonce, tag, ct = raw[:16], raw[16:32], raw[32:]
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
return cipher.decrypt_and_verify(ct, tag).decode("utf-8")
# ── SQLAlchemy TypeDecorator (auto-encrypt columns) ──────────────
from sqlalchemy import TypeDecorator, Text
class EncryptedString(TypeDecorator):
"""Column type that transparently encrypts/decrypts values."""
impl = Text; cache_ok = True
def process_bind_param(self, value, dialect):
return encrypt_field(value) if value is not None else None
def process_result_value(self, value, dialect):
return decrypt_field(value) if value is not None else None
# ── Model usage ──────────────────────────────────────────────────
# class User(Base):
# phone = Column(EncryptedString) # auto-encrypts on save
# cnic = Column(EncryptedString) # auto-decrypts on read
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import os, base64, json
from functools import wraps
# ── Key management ──────────────────────────────────────────────
_KEY: bytes | None = None
def load_key() -> bytes:
global _KEY
if _KEY is None:
hex_key = os.environ.get("AES_MASTER_KEY")
if not hex_key: raise RuntimeError("AES_MASTER_KEY not set")
_KEY = bytes.fromhex(hex_key)
if len(_KEY) != 32: raise ValueError("Key must be 256-bit (32 bytes)")
return _KEY
# ── Core encrypt / decrypt ───────────────────────────────────────
def encrypt_field(plaintext: str) -> str:
"""Encrypt a string field → base64(nonce+tag+ciphertext)"""
key = load_key()
cipher = AES.new(key, AES.MODE_GCM)
ct, tag = cipher.encrypt_and_digest(plaintext.encode("utf-8"))
return base64.b64encode(cipher.nonce + tag + ct).decode()
def decrypt_field(token: str) -> str:
"""Decrypt a base64 token → original string. Raises on tamper."""
key = load_key()
raw = base64.b64decode(token)
nonce, tag, ct = raw[:16], raw[16:32], raw[32:]
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
return cipher.decrypt_and_verify(ct, tag).decode("utf-8")
# ── SQLAlchemy TypeDecorator (auto-encrypt columns) ──────────────
from sqlalchemy import TypeDecorator, Text
class EncryptedString(TypeDecorator):
"""Column type that transparently encrypts/decrypts values."""
impl = Text; cache_ok = True
def process_bind_param(self, value, dialect):
return encrypt_field(value) if value is not None else None
def process_result_value(self, value, dialect):
return decrypt_field(value) if value is not None else None
# ── Model usage ──────────────────────────────────────────────────
# class User(Base):
# phone = Column(EncryptedString) # auto-encrypts on save
# cnic = Column(EncryptedString) # auto-decrypts on read
Security Alerts
3 Open
Audit Log
Last 24h
🔍
Key Vault
4 active keys
Security Settings
Global config