Docs: Channel Lock & PIN Protection feature design
- Created comprehensive design document (docs/CHANNEL_LOCK_DESIGN.md) - Complete UX flows with PIN setup, unlock, and auto-lock modes - Technical implementation details with code examples - Security architecture (PBKDF2, brute force protection) - Database schema changes and migration plan - Testing strategy and implementation checklist - Added to ROADMAP.md as Phase 3, Item #1 (HIGH PRIORITY) - Target: October 2025 implementation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
f440042204
commit
7806bb2392
46
ROADMAP.md
46
ROADMAP.md
@ -101,11 +101,43 @@ This roadmap outlines the development priorities and strategic direction for Lit
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Phase 3: Feature Enhancements (Q1 2026 - January-March)
|
||||
## 🚀 Phase 3: Feature Enhancements (Q4 2025 - Q1 2026)
|
||||
|
||||
### Security & Privacy Features
|
||||
|
||||
#### 1. 🔒 TeleBot Channel Lock & PIN Protection [HIGH PRIORITY]
|
||||
- **Status**: 📋 Documented - Ready for Implementation
|
||||
- **Priority**: HIGH - Privacy & Security Enhancement
|
||||
- **Location**: `docs/CHANNEL_LOCK_DESIGN.md`
|
||||
- **Description**: Complete channel lock system with 4-digit PIN protection
|
||||
- **Features**:
|
||||
- Single security gate protecting all bot functionality
|
||||
- 4-digit PIN with PBKDF2 hashing (100,000 iterations)
|
||||
- Auto-lock modes (Manual, On Main Menu, Inactivity, On Exit, Always)
|
||||
- Brute force protection (3 attempts → 5 min lockout)
|
||||
- Screenshot-safe locked state (no data visible)
|
||||
- Backward compatible (Guest mode for users without PIN)
|
||||
- **Benefits**:
|
||||
- ✅ Enterprise-grade privacy protection
|
||||
- ✅ Shared device safety
|
||||
- ✅ Mobile banking UX pattern
|
||||
- ✅ GDPR compliance enhancement
|
||||
- ✅ Zero data loss (preserved during lock)
|
||||
- **Implementation Estimate**: 2-3 hours core + 1-2 hours UX polish
|
||||
- **Timeline**: October 2025
|
||||
- **Success Metrics**:
|
||||
- 60% user adoption within 30 days
|
||||
- < 0.1% lockout rate
|
||||
- > 90% user satisfaction
|
||||
- **Future Enhancements**:
|
||||
- Biometric unlock (Telegram WebApp API)
|
||||
- 2FA/TOTP support
|
||||
- Hardware security key integration
|
||||
- Zero-knowledge encryption
|
||||
|
||||
### Shipping & Logistics
|
||||
|
||||
#### 1. Royal Mail Integration
|
||||
#### 2. Royal Mail Integration
|
||||
- API integration for label generation
|
||||
- Tracking number management
|
||||
- Automated shipping calculations
|
||||
@ -113,7 +145,7 @@ This roadmap outlines the development priorities and strategic direction for Lit
|
||||
- **Timeline**: January 2026
|
||||
- **Status**: 🔴 PLANNED
|
||||
|
||||
#### 2. Multi-Carrier Support
|
||||
#### 3. Multi-Carrier Support
|
||||
- Abstract shipping provider interface
|
||||
- Support for DHL, FedEx, UPS
|
||||
- Shipping rule engine
|
||||
@ -122,7 +154,7 @@ This roadmap outlines the development priorities and strategic direction for Lit
|
||||
|
||||
### Communication & Notifications
|
||||
|
||||
#### 3. Email Notification System
|
||||
#### 4. Email Notification System
|
||||
- Order confirmation emails
|
||||
- Shipping notifications
|
||||
- Payment status updates
|
||||
@ -130,7 +162,7 @@ This roadmap outlines the development priorities and strategic direction for Lit
|
||||
- **Timeline**: January 2026
|
||||
- **Status**: 🔴 PLANNED
|
||||
|
||||
#### 4. Enhanced Telegram Bot Features
|
||||
#### 5. Enhanced Telegram Bot Features
|
||||
- Rich media product browsing
|
||||
- Voice message support
|
||||
- Automated customer support responses
|
||||
@ -140,7 +172,7 @@ This roadmap outlines the development priorities and strategic direction for Lit
|
||||
|
||||
### Analytics & Reporting
|
||||
|
||||
#### 5. Advanced Analytics Dashboard
|
||||
#### 6. Advanced Analytics Dashboard
|
||||
- Sales trends and forecasting
|
||||
- Customer behavior analytics
|
||||
- Product performance metrics
|
||||
@ -148,7 +180,7 @@ This roadmap outlines the development priorities and strategic direction for Lit
|
||||
- **Timeline**: February 2026
|
||||
- **Status**: 🔴 PLANNED
|
||||
|
||||
#### 6. Financial Reporting
|
||||
#### 7. Financial Reporting
|
||||
- Automated tax calculations
|
||||
- Multi-currency reconciliation
|
||||
- Export to accounting software
|
||||
|
||||
733
docs/CHANNEL_LOCK_DESIGN.md
Normal file
733
docs/CHANNEL_LOCK_DESIGN.md
Normal file
@ -0,0 +1,733 @@
|
||||
# TeleBot Channel Lock & PIN Protection Design
|
||||
|
||||
**Status**: 📋 Documented - Ready for Implementation
|
||||
**Priority**: 🔒 HIGH - Security & Privacy Enhancement
|
||||
**Target**: Q4 2025 (October 2025)
|
||||
**Estimated Implementation**: 2-3 hours core functionality + 1-2 hours UX polish
|
||||
**Last Updated**: October 6, 2025
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Complete channel lock system for TeleBot that provides enterprise-grade privacy protection through a 4-digit PIN. When enabled, the entire Telegram conversation is locked with a single security gate, requiring PIN entry to access any functionality beyond the unlock screen.
|
||||
|
||||
### Key Benefits
|
||||
|
||||
✅ **Single Security Boundary** - One gate protects all features, not selective locks
|
||||
✅ **Screenshot Safe** - Locked screen shows no sensitive data
|
||||
✅ **Shared Device Safe** - Complete protection for shared/public devices
|
||||
✅ **Mobile Banking UX** - Familiar pattern from banking/crypto wallet apps
|
||||
✅ **No Data Loss** - All data preserved in session, just visibility controlled
|
||||
✅ **Privacy by Design** - User controls when and how data is visible
|
||||
✅ **Simple Implementation** - Early gate check, minimal code complexity
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Core Concept
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ ALL TELEGRAM UPDATES │
|
||||
│ (Messages, Callbacks, Commands) │
|
||||
└──────────────────┬──────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ SECURITY GATE │
|
||||
│ Is session locked? │
|
||||
└─────────┬───────────┘
|
||||
│
|
||||
┌─────────┴──────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
🔒 LOCKED ✅ UNLOCKED
|
||||
Show unlock Process normally
|
||||
screen only (full features)
|
||||
```
|
||||
|
||||
### State Model
|
||||
|
||||
```csharp
|
||||
public enum SessionState
|
||||
{
|
||||
Guest, // No PIN set, full access (backward compatible with existing users)
|
||||
Unlocked, // PIN set, currently unlocked (full access)
|
||||
Locked // PIN set, currently locked (GATE BLOCKS ALL ACTIONS)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User Experience Design
|
||||
|
||||
### 1. First-Time Setup (Optional)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 🔐 Secure Your Orders │
|
||||
├─────────────────────────────────────┤
|
||||
│ Protect your personal information │
|
||||
│ and order history with a 4-digit │
|
||||
│ PIN code. │
|
||||
│ │
|
||||
│ • Lock chat automatically │
|
||||
│ • Protect payment details │
|
||||
│ • Secure order history │
|
||||
│ │
|
||||
│ [✅ Set Up PIN] [⏭️ Skip] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Design Decisions:**
|
||||
- Completely optional - existing users continue with Guest mode
|
||||
- Clear value proposition - explain what PIN protects
|
||||
- No friction - skip option for users who don't need it
|
||||
- Re-prompt after 3 orders or 7 days (gentle nudge)
|
||||
|
||||
### 2. PIN Setup Flow
|
||||
|
||||
```
|
||||
Step 1: Enter New PIN
|
||||
┌─────────────────────────────────────┐
|
||||
│ 🔢 Create Your PIN │
|
||||
├─────────────────────────────────────┤
|
||||
│ PIN: ● ● ● ● │
|
||||
│ │
|
||||
│ [1] [2] [3] │
|
||||
│ [4] [5] [6] │
|
||||
│ [7] [8] [9] │
|
||||
│ [⬅️ Clear] [0] [✅ Next] │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
Step 2: Confirm PIN
|
||||
┌─────────────────────────────────────┐
|
||||
│ 🔢 Confirm Your PIN │
|
||||
├─────────────────────────────────────┤
|
||||
│ Enter your PIN again to confirm │
|
||||
│ │
|
||||
│ PIN: ● ● ● ● │
|
||||
│ │
|
||||
│ [Numeric keypad as above] │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
Step 3: Success
|
||||
┌─────────────────────────────────────┐
|
||||
│ ✅ PIN Protection Enabled │
|
||||
├─────────────────────────────────────┤
|
||||
│ Your chat is now protected with │
|
||||
│ a secure PIN. │
|
||||
│ │
|
||||
│ Auto-lock: 🏠 On Main Menu │
|
||||
│ │
|
||||
│ [⚙️ Settings] [🏠 Main Menu] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3. Locked State (Primary UX)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 🔒 Channel Locked │
|
||||
├─────────────────────────────────────┤
|
||||
│ Enter your 4-digit PIN to continue │
|
||||
│ │
|
||||
│ Locked at: 14:32 │
|
||||
│ │
|
||||
│ [🔓 Unlock] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Important:** This is the ONLY message shown when locked. No other features accessible.
|
||||
|
||||
### 4. Unlock Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 🔢 Enter PIN │
|
||||
├─────────────────────────────────────┤
|
||||
│ PIN: ● ● ○ ○ │
|
||||
│ │
|
||||
│ Attempts remaining: 3 │
|
||||
│ │
|
||||
│ [1] [2] [3] │
|
||||
│ [4] [5] [6] │
|
||||
│ [7] [8] [9] │
|
||||
│ [⬅️ Clear] [0] [✅ Submit] │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
After Successful Unlock:
|
||||
┌─────────────────────────────────────┐
|
||||
│ ✅ Unlocked │
|
||||
├─────────────────────────────────────┤
|
||||
│ Welcome back! │
|
||||
│ │
|
||||
│ [Returns to normal menu] │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
Failed Attempt:
|
||||
┌─────────────────────────────────────┐
|
||||
│ ❌ Incorrect PIN │
|
||||
├─────────────────────────────────────┤
|
||||
│ PIN: ○ ○ ○ ○ │
|
||||
│ │
|
||||
│ Attempts remaining: 2 │
|
||||
│ ⚠️ Account locks after 3 failures │
|
||||
│ │
|
||||
│ [Numeric keypad] │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
Account Locked (after 3 failures):
|
||||
┌─────────────────────────────────────┐
|
||||
│ 🚫 Account Temporarily Locked │
|
||||
├─────────────────────────────────────┤
|
||||
│ Too many failed attempts. │
|
||||
│ │
|
||||
│ Try again in: 5 minutes │
|
||||
│ │
|
||||
│ [❓ Forgot PIN?] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 5. Auto-Lock Modes
|
||||
|
||||
```
|
||||
⚙️ Security Settings
|
||||
├── 🔐 PIN Protection: ✅ Enabled
|
||||
│ ├── 📌 Change PIN
|
||||
│ └── ❌ Disable PIN (requires current PIN)
|
||||
│
|
||||
├── 🔒 Auto-Lock: 🏠 On Main Menu ▼
|
||||
│ │
|
||||
│ ├── ✋ Manual Only
|
||||
│ │ └── Lock only when "🔒 Lock" button clicked
|
||||
│ │
|
||||
│ ├── 🏠 On Main Menu (Recommended)
|
||||
│ │ └── Auto-lock when returning to main menu
|
||||
│ │
|
||||
│ ├── ⏰ After Inactivity
|
||||
│ │ └── Lock after [30 ▼] minutes idle
|
||||
│ │
|
||||
│ ├── 🚪 On Exit
|
||||
│ │ └── Lock on any "back to menu" action
|
||||
│ │
|
||||
│ └── 🔐 Always (Paranoid Mode)
|
||||
│ └── Lock after EVERY single action
|
||||
│
|
||||
├── 🗑️ Clear All Data (requires PIN)
|
||||
│ └── Permanently delete order history, cart, settings
|
||||
│
|
||||
└── ℹ️ Security Info
|
||||
├── PIN Last Changed: Oct 6, 2025
|
||||
├── Last Locked: 2 hours ago
|
||||
└── Failed Attempts Today: 0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Technical Implementation
|
||||
|
||||
### 1. Database Schema Changes
|
||||
|
||||
```csharp
|
||||
public class UserSession
|
||||
{
|
||||
// Existing fields...
|
||||
public Guid Id { get; set; }
|
||||
public long TelegramUserId { get; set; }
|
||||
public Cart Cart { get; set; }
|
||||
public List<ConversationMessage> Conversation { get; set; }
|
||||
|
||||
// NEW: Security & Lock State
|
||||
public SessionState State { get; set; } = SessionState.Guest;
|
||||
public string? PinHash { get; set; } // PBKDF2 hash, null = no PIN
|
||||
public DateTime? LastActivityAt { get; set; }
|
||||
public DateTime? LockedAt { get; set; }
|
||||
public int FailedPinAttempts { get; set; }
|
||||
public DateTime? LockoutUntil { get; set; }
|
||||
public SecuritySettings Security { get; set; } = new();
|
||||
public string? PinEntry { get; set; } // Temporary, in-memory only (not persisted)
|
||||
}
|
||||
|
||||
public class SecuritySettings
|
||||
{
|
||||
public bool PinEnabled { get; set; }
|
||||
public AutoLockMode AutoLock { get; set; } = AutoLockMode.OnMainMenu;
|
||||
public int AutoLockMinutes { get; set; } = 30;
|
||||
public DateTime? PinCreatedAt { get; set; }
|
||||
public DateTime? PinLastChangedAt { get; set; }
|
||||
}
|
||||
|
||||
public enum AutoLockMode
|
||||
{
|
||||
Manual, // Only lock when user clicks button
|
||||
OnMainMenu, // Lock when returning to main menu (default)
|
||||
OnInactivity, // Lock after X minutes idle
|
||||
OnExit, // Lock on any "back to menu" action
|
||||
Always // Lock after every single action (paranoid mode)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Security Gate Implementation
|
||||
|
||||
```csharp
|
||||
// CallbackHandler.cs - Primary entry point for all user interactions
|
||||
public async Task Handle(ITelegramBotClient bot, CallbackQuery callbackQuery, CancellationToken ct)
|
||||
{
|
||||
var telegramUser = callbackQuery.From;
|
||||
var session = await _sessionManager.GetOrCreateSessionAsync(telegramUser.Id);
|
||||
|
||||
// UPDATE ACTIVITY TIMESTAMP
|
||||
session.LastActivityAt = DateTime.UtcNow;
|
||||
|
||||
// SECURITY GATE - Check lock state BEFORE any other processing
|
||||
if (session.State == SessionState.Locked && !IsUnlockAction(callbackQuery.Data))
|
||||
{
|
||||
await ShowUnlockScreen(bot, callbackQuery);
|
||||
return; // STOP ALL PROCESSING - gate closed
|
||||
}
|
||||
|
||||
// Check if account is in lockout period
|
||||
if (session.LockoutUntil.HasValue && DateTime.UtcNow < session.LockoutUntil.Value)
|
||||
{
|
||||
await ShowLockoutScreen(bot, callbackQuery, session.LockoutUntil.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
// If unlocked or this is unlock action, continue normal flow
|
||||
await ProcessCallback(bot, callbackQuery, session);
|
||||
|
||||
// CHECK AUTO-LOCK CONDITIONS after action completes
|
||||
await CheckAndApplyAutoLock(session);
|
||||
}
|
||||
|
||||
private bool IsUnlockAction(string? callbackData)
|
||||
{
|
||||
return callbackData?.StartsWith("unlock") == true ||
|
||||
callbackData?.StartsWith("pin_entry:") == true ||
|
||||
callbackData == "show_pin_pad" ||
|
||||
callbackData == "pin_clear" ||
|
||||
callbackData?.StartsWith("pin_digit:") == true;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. PIN Management
|
||||
|
||||
```csharp
|
||||
// PIN Hashing (secure storage)
|
||||
public string HashPin(string pin)
|
||||
{
|
||||
using var rfc2898 = new Rfc2898DeriveBytes(
|
||||
pin,
|
||||
saltSize: 32,
|
||||
iterations: 100_000,
|
||||
HashAlgorithmName.SHA256
|
||||
);
|
||||
|
||||
var hash = Convert.ToBase64String(rfc2898.GetBytes(32));
|
||||
var salt = Convert.ToBase64String(rfc2898.Salt);
|
||||
|
||||
return $"{salt}:{hash}"; // Store both salt and hash
|
||||
}
|
||||
|
||||
// PIN Verification
|
||||
public bool VerifyPin(string enteredPin, string storedHash)
|
||||
{
|
||||
var parts = storedHash.Split(':');
|
||||
if (parts.Length != 2) return false;
|
||||
|
||||
var salt = Convert.FromBase64String(parts[0]);
|
||||
var hash = Convert.FromBase64String(parts[1]);
|
||||
|
||||
using var rfc2898 = new Rfc2898DeriveBytes(
|
||||
enteredPin,
|
||||
salt,
|
||||
iterations: 100_000,
|
||||
HashAlgorithmName.SHA256
|
||||
);
|
||||
|
||||
var enteredHash = rfc2898.GetBytes(32);
|
||||
return CryptographicOperations.FixedTimeEquals(hash, enteredHash);
|
||||
}
|
||||
|
||||
// PIN Entry Handling
|
||||
private async Task HandlePinDigit(ITelegramBotClient bot, CallbackQuery query, UserSession session, string digit)
|
||||
{
|
||||
if (session.PinEntry == null)
|
||||
session.PinEntry = "";
|
||||
|
||||
if (digit == "clear")
|
||||
{
|
||||
session.PinEntry = "";
|
||||
}
|
||||
else if (digit == "submit" && session.PinEntry.Length == 4)
|
||||
{
|
||||
await HandlePinSubmit(bot, query, session);
|
||||
return;
|
||||
}
|
||||
else if (session.PinEntry.Length < 4)
|
||||
{
|
||||
session.PinEntry += digit;
|
||||
}
|
||||
|
||||
// Refresh PIN pad with updated dots
|
||||
await ShowPinPad(bot, query, session);
|
||||
}
|
||||
|
||||
private async Task HandlePinSubmit(ITelegramBotClient bot, CallbackQuery query, UserSession session)
|
||||
{
|
||||
if (VerifyPin(session.PinEntry, session.PinHash!))
|
||||
{
|
||||
// SUCCESS
|
||||
session.State = SessionState.Unlocked;
|
||||
session.FailedPinAttempts = 0;
|
||||
session.PinEntry = null;
|
||||
|
||||
await bot.EditMessageTextAsync(
|
||||
query.Message!.Chat.Id,
|
||||
query.Message.MessageId,
|
||||
"✅ *Unlocked*\n\nWelcome back!",
|
||||
parseMode: ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.MainMenu()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FAILURE
|
||||
session.FailedPinAttempts++;
|
||||
session.PinEntry = null;
|
||||
|
||||
if (session.FailedPinAttempts >= 3)
|
||||
{
|
||||
// LOCKOUT
|
||||
session.LockoutUntil = DateTime.UtcNow.AddMinutes(5);
|
||||
await ShowLockoutScreen(bot, query, session.LockoutUntil.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ShowPinPad(bot, query, session, isError: true);
|
||||
}
|
||||
}
|
||||
|
||||
await _sessionManager.SaveSessionAsync(session);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Auto-Lock Logic
|
||||
|
||||
```csharp
|
||||
private async Task CheckAndApplyAutoLock(UserSession session)
|
||||
{
|
||||
// Don't lock if PIN not enabled or already locked
|
||||
if (!session.Security.PinEnabled || session.State == SessionState.Locked)
|
||||
return;
|
||||
|
||||
bool shouldLock = session.Security.AutoLock switch
|
||||
{
|
||||
AutoLockMode.Manual => false, // Never auto-lock
|
||||
|
||||
AutoLockMode.OnMainMenu =>
|
||||
session.CurrentMenu == "main" || session.LastAction == "menu",
|
||||
|
||||
AutoLockMode.OnInactivity =>
|
||||
(DateTime.UtcNow - session.LastActivityAt.GetValueOrDefault()).TotalMinutes
|
||||
>= session.Security.AutoLockMinutes,
|
||||
|
||||
AutoLockMode.OnExit =>
|
||||
session.CurrentMenu == "main" ||
|
||||
session.LastAction == "back" ||
|
||||
session.LastAction == "menu",
|
||||
|
||||
AutoLockMode.Always => true, // Lock after every action
|
||||
|
||||
_ => false
|
||||
};
|
||||
|
||||
if (shouldLock)
|
||||
{
|
||||
session.State = SessionState.Locked;
|
||||
session.LockedAt = DateTime.UtcNow;
|
||||
session.PinEntry = null; // Clear any temporary PIN entry
|
||||
await _sessionManager.SaveSessionAsync(session);
|
||||
|
||||
_logger.LogInformation(
|
||||
"Session {SessionId} auto-locked (mode: {Mode})",
|
||||
session.Id,
|
||||
session.Security.AutoLock
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. UI Components
|
||||
|
||||
```csharp
|
||||
// MenuBuilder.cs additions
|
||||
|
||||
public InlineKeyboardMarkup UnlockScreen()
|
||||
{
|
||||
return new InlineKeyboardMarkup(new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
InlineKeyboardButton.WithCallbackData("🔓 Unlock", "show_pin_pad")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public InlineKeyboardMarkup PinPad(UserSession session, bool isError = false)
|
||||
{
|
||||
var maskLength = session.PinEntry?.Length ?? 0;
|
||||
var mask = new string('●', maskLength) + new string('○', 4 - maskLength);
|
||||
|
||||
return new InlineKeyboardMarkup(new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
InlineKeyboardButton.WithCallbackData("1", "pin_digit:1"),
|
||||
InlineKeyboardButton.WithCallbackData("2", "pin_digit:2"),
|
||||
InlineKeyboardButton.WithCallbackData("3", "pin_digit:3")
|
||||
},
|
||||
new[]
|
||||
{
|
||||
InlineKeyboardButton.WithCallbackData("4", "pin_digit:4"),
|
||||
InlineKeyboardButton.WithCallbackData("5", "pin_digit:5"),
|
||||
InlineKeyboardButton.WithCallbackData("6", "pin_digit:6")
|
||||
},
|
||||
new[]
|
||||
{
|
||||
InlineKeyboardButton.WithCallbackData("7", "pin_digit:7"),
|
||||
InlineKeyboardButton.WithCallbackData("8", "pin_digit:8"),
|
||||
InlineKeyboardButton.WithCallbackData("9", "pin_digit:9")
|
||||
},
|
||||
new[]
|
||||
{
|
||||
InlineKeyboardButton.WithCallbackData("⬅️ Clear", "pin_clear"),
|
||||
InlineKeyboardButton.WithCallbackData("0", "pin_digit:0"),
|
||||
InlineKeyboardButton.WithCallbackData("✅ Submit", "pin_submit")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add lock button to main menu when PIN enabled
|
||||
public InlineKeyboardMarkup MainMenu(UserSession? session = null)
|
||||
{
|
||||
var buttons = new List<InlineKeyboardButton[]>
|
||||
{
|
||||
// ... existing menu items
|
||||
};
|
||||
|
||||
// Add lock button if PIN is enabled
|
||||
if (session?.Security.PinEnabled == true && session.State == SessionState.Unlocked)
|
||||
{
|
||||
buttons.Add(new[]
|
||||
{
|
||||
InlineKeyboardButton.WithCallbackData("🔒 Lock Chat", "lock_channel")
|
||||
});
|
||||
}
|
||||
|
||||
return new InlineKeyboardMarkup(buttons);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### 1. PIN Storage
|
||||
- ✅ PBKDF2 with 100,000 iterations (OWASP recommended)
|
||||
- ✅ 32-byte random salt per PIN
|
||||
- ✅ SHA-256 hash algorithm
|
||||
- ✅ Constant-time comparison (prevents timing attacks)
|
||||
- ❌ **Never** store PIN in plaintext
|
||||
|
||||
### 2. Brute Force Protection
|
||||
- ✅ 3 attempts before 5-minute lockout
|
||||
- ✅ Progressive lockout (future: 5min → 15min → 1hr → 24hr)
|
||||
- ✅ Failed attempt logging for audit trail
|
||||
- ✅ Rate limiting on unlock endpoint
|
||||
|
||||
### 3. Session Security
|
||||
- ✅ PinEntry stored in memory only, never persisted to database
|
||||
- ✅ Auto-clear PinEntry on lock/unlock/failure
|
||||
- ✅ Session state synchronized across all interactions
|
||||
- ✅ Activity timestamp updated on every interaction
|
||||
|
||||
### 4. Data Protection
|
||||
- ✅ All sensitive data (orders, payments, addresses) hidden when locked
|
||||
- ✅ No data exposed in locked state messages
|
||||
- ✅ Session data preserved but inaccessible
|
||||
- ✅ Optional "Clear All Data" requires PIN verification
|
||||
|
||||
---
|
||||
|
||||
## Migration & Backward Compatibility
|
||||
|
||||
### Existing Users (Guest Mode)
|
||||
- No disruption - continue using bot without PIN
|
||||
- Optional prompt after 3 orders or 7 days: "Would you like to secure your orders with a PIN?"
|
||||
- Can enable PIN anytime from Settings menu
|
||||
|
||||
### Database Migration
|
||||
```sql
|
||||
-- Add new columns to UserSessions table
|
||||
ALTER TABLE UserSessions ADD COLUMN State INTEGER DEFAULT 0; -- 0 = Guest
|
||||
ALTER TABLE UserSessions ADD COLUMN PinHash TEXT NULL;
|
||||
ALTER TABLE UserSessions ADD COLUMN LastActivityAt TEXT NULL;
|
||||
ALTER TABLE UserSessions ADD COLUMN LockedAt TEXT NULL;
|
||||
ALTER TABLE UserSessions ADD COLUMN FailedPinAttempts INTEGER DEFAULT 0;
|
||||
ALTER TABLE UserSessions ADD COLUMN LockoutUntil TEXT NULL;
|
||||
ALTER TABLE UserSessions ADD COLUMN SecuritySettings TEXT NULL; -- JSON
|
||||
|
||||
-- Add indexes for performance
|
||||
CREATE INDEX IX_UserSessions_State ON UserSessions(State);
|
||||
CREATE INDEX IX_UserSessions_LockoutUntil ON UserSessions(LockoutUntil);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- ✅ PIN hashing and verification
|
||||
- ✅ Auto-lock mode logic
|
||||
- ✅ Lockout calculation
|
||||
- ✅ PIN entry validation (4 digits only)
|
||||
|
||||
### Integration Tests
|
||||
- ✅ Full unlock flow (locked → pin entry → unlocked)
|
||||
- ✅ Failed attempt lockout enforcement
|
||||
- ✅ Auto-lock triggers (menu, inactivity, exit)
|
||||
- ✅ State transitions (Guest → Unlocked → Locked)
|
||||
|
||||
### E2E Tests (Playwright)
|
||||
- ✅ First-time PIN setup flow
|
||||
- ✅ Lock and unlock via menu
|
||||
- ✅ Auto-lock on main menu return
|
||||
- ✅ Failed attempts and lockout
|
||||
- ✅ PIN change workflow
|
||||
- ✅ Disable PIN and return to Guest mode
|
||||
|
||||
---
|
||||
|
||||
## Implementation Checklist
|
||||
|
||||
### Phase 1: Core Functionality (2-3 hours)
|
||||
- [ ] Add `SessionState`, `PinHash`, security fields to `UserSession` model
|
||||
- [ ] Create database migration for new columns
|
||||
- [ ] Implement `HashPin()` and `VerifyPin()` methods
|
||||
- [ ] Add security gate at top of `CallbackHandler.Handle()`
|
||||
- [ ] Create `ShowUnlockScreen()` method
|
||||
- [ ] Build PIN pad UI in `MenuBuilder.PinPad()`
|
||||
- [ ] Implement `HandlePinDigit()` and `HandlePinSubmit()`
|
||||
- [ ] Add lockout logic (3 attempts → 5 min timeout)
|
||||
- [ ] Implement manual lock button in main menu
|
||||
|
||||
### Phase 2: Auto-Lock (1 hour)
|
||||
- [ ] Create `CheckAndApplyAutoLock()` method
|
||||
- [ ] Implement all 5 auto-lock modes
|
||||
- [ ] Add activity timestamp tracking
|
||||
- [ ] Test auto-lock triggers
|
||||
|
||||
### Phase 3: Settings & Management (1 hour)
|
||||
- [ ] Create Security Settings menu
|
||||
- [ ] Implement PIN setup flow (new users)
|
||||
- [ ] Implement Change PIN flow
|
||||
- [ ] Implement Disable PIN flow (requires current PIN)
|
||||
- [ ] Add auto-lock mode selector
|
||||
- [ ] Add "Clear All Data" with PIN verification
|
||||
|
||||
### Phase 4: UX Polish (1-2 hours)
|
||||
- [ ] Add first-time setup prompt (optional, after 3 orders)
|
||||
- [ ] Improve error messages and feedback
|
||||
- [ ] Add security info display (last locked, failed attempts)
|
||||
- [ ] Add countdown timer for lockout screen
|
||||
- [ ] Implement "Forgot PIN?" recovery flow (contact support)
|
||||
- [ ] Add haptic/visual feedback for PIN entry
|
||||
|
||||
### Phase 5: Testing & Deployment (1 hour)
|
||||
- [ ] Write unit tests for PIN security
|
||||
- [ ] Write integration tests for lock flows
|
||||
- [ ] Manual E2E testing on Telegram
|
||||
- [ ] Security review (penetration testing)
|
||||
- [ ] Deploy to staging environment
|
||||
- [ ] User acceptance testing
|
||||
- [ ] Deploy to production with feature flag
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Short Term (Q1 2026)
|
||||
- **Biometric Unlock**: Support Telegram's WebApp biometric API
|
||||
- **PIN Complexity**: Option for 6-digit PIN or alphanumeric password
|
||||
- **Session Management**: "Lock all devices" from any session
|
||||
- **Audit Log**: View all unlock events and failed attempts
|
||||
|
||||
### Medium Term (Q2 2026)
|
||||
- **2FA Support**: Optional TOTP/authenticator app second factor
|
||||
- **Trusted Devices**: Remember devices, require PIN only on new devices
|
||||
- **Emergency Contacts**: Designate trusted contact for PIN recovery
|
||||
- **Secure Backup**: Encrypted backup of order history with recovery phrase
|
||||
|
||||
### Long Term (Q3-Q4 2026)
|
||||
- **Hardware Security**: Support for hardware security keys (YubiKey, etc.)
|
||||
- **Zero-Knowledge Encryption**: End-to-end encrypted order data
|
||||
- **Multi-Account**: Separate PINs for business vs personal shopping
|
||||
- **Compliance**: FIPS 140-2 certification for payment card industry
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### Security Metrics
|
||||
- ✅ Zero unauthorized access incidents
|
||||
- ✅ < 0.1% lockout rate (balance security vs UX)
|
||||
- ✅ 100% PIN hash security (PBKDF2 with strong parameters)
|
||||
|
||||
### User Adoption
|
||||
- 🎯 Target: 60% of active users enable PIN within 30 days
|
||||
- 🎯 Target: < 5% disable PIN after enabling
|
||||
- 🎯 Target: > 90% user satisfaction with lock/unlock UX
|
||||
|
||||
### Performance
|
||||
- ✅ < 100ms PIN verification time
|
||||
- ✅ < 500ms lock/unlock state transition
|
||||
- ✅ Zero impact on unlocked session performance
|
||||
|
||||
---
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Forgot PIN Flow**: Contact support vs security questions vs recovery phrase?
|
||||
- **Recommendation**: Contact support with identity verification (Telegram username + recent order ID)
|
||||
|
||||
2. **PIN Complexity**: Force 4 digits or allow stronger PINs?
|
||||
- **Recommendation**: Default 4 digits, optional 6-digit or alphanumeric in settings
|
||||
|
||||
3. **Session Expiry**: Should locked sessions expire and clear data after X days?
|
||||
- **Recommendation**: 90-day expiry with warning email/notification at 80 days
|
||||
|
||||
4. **Multi-Device**: If user has bot open on phone and desktop, lock both?
|
||||
- **Recommendation**: Yes, state is server-side, lock applies to all clients
|
||||
|
||||
5. **PIN Recovery**: Allow self-service PIN reset via email?
|
||||
- **Recommendation**: Phase 1 = support only, Phase 2 = email with order verification
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)
|
||||
- [Telegram Bot API Security Best Practices](https://core.telegram.org/bots/security)
|
||||
- [NIST Digital Identity Guidelines](https://pages.nist.gov/800-63-3/)
|
||||
- [PBKDF2 Implementation Guide](https://cryptobook.nakov.com/mac-and-key-derivation/pbkdf2)
|
||||
|
||||
---
|
||||
|
||||
**Document Version**: 1.0
|
||||
**Author**: SilverLabs Development Team
|
||||
**Review Date**: October 6, 2025
|
||||
**Next Review**: November 6, 2025 (post-implementation)
|
||||
Loading…
Reference in New Issue
Block a user