# OTP Service Documentation

## Overview

The `OTPService` class provides a comprehensive, secure, and reusable solution for handling One-Time Password (OTP) operations across the Deywuro application. This service centralizes all OTP-related functionality and provides robust security features.

## Features

### 🔒 Security Features
- **Cryptographically Secure OTP Generation**: Uses `random_int()` for unpredictable OTPs
- **Rate Limiting**: Prevents SMS bombing attacks (3 requests per hour per phone)
- **Session Management**: Secure session tokens for OTP operations
- **CSRF Protection**: All endpoints require CSRF tokens
- **Input Validation**: Comprehensive validation for all inputs
- **OTP Expiration**: 5-minute expiration for all OTPs

### 🚀 Performance Features
- **Caching**: Uses Laravel Cache for OTP storage and rate limiting
- **Efficient Session Management**: Lightweight session token system
- **Reusable Components**: Single service for all OTP operations

## Service Methods

### Core OTP Operations

#### `generateOTP(): string`
Generates a cryptographically secure 6-digit OTP.

```php
$otpService = new OTPService();
$otp = $otpService->generateOTP(); // Returns "123456"
```

#### `generateSessionToken(): string`
Generates a 64-character random session token.

```php
$sessionToken = $otpService->generateSessionToken();
```

#### `processOTPRequest(string $phone, string $sessionToken, string $source = 'DEYWURO', string $messageTemplate = null): array`
Complete OTP request processing with all security checks.

```php
$result = $otpService->processOTPRequest($phone, $sessionToken);
// Returns: ['code' => 0, 'msg' => 'OTP sent successfully']
```

#### `completeOTPVerification(string $phone, string $sessionToken, string $userOTP): array`
Complete OTP verification process.

```php
$result = $otpService->completeOTPVerification($phone, $sessionToken, $userOtp);
// Returns: ['code' => 0, 'msg' => 'OTP verified successfully']
```

### Session Management

#### `createRegistrationSession(string $sessionToken, array $additionalData = []): void`
Creates a new registration session.

```php
$otpService->createRegistrationSession($sessionToken, [
    'user_type' => 'reseller',
    'registration_step' => 'phone_verification'
]);
```

#### `verifySessionToken(string $sessionToken): bool`
Verifies if a session token exists and is valid.

```php
$isValid = $otpService->verifySessionToken($sessionToken);
```

#### `getSessionData(string $sessionToken): ?array`
Retrieves session data.

```php
$sessionData = $otpService->getSessionData($sessionToken);
```

#### `updateSessionData(string $sessionToken, array $data): void`
Updates session data.

```php
$otpService->updateSessionData($sessionToken, [
    'phone_verified' => true,
    'verified_phone' => $phone
]);
```

#### `cleanupSession(string $sessionToken): void`
Cleans up session data.

```php
$otpService->cleanupSession($sessionToken);
```

### Rate Limiting

#### `isRateLimited(string $phone, int $maxAttempts = 3, int $windowMinutes = 60): bool`
Checks if a phone number is rate limited.

```php
$isLimited = $otpService->isRateLimited($phone);
```

#### `getRemainingAttempts(string $phone, int $maxAttempts = 3): int`
Gets remaining OTP attempts for a phone number.

```php
$remaining = $otpService->getRemainingAttempts($phone);
```

#### `clearRateLimit(string $phone): void`
Clears rate limit for a phone number (admin function).

```php
$otpService->clearRateLimit($phone);
```

### SMS Operations

#### `sendOTPSMS(string $phone, string $otp, string $source = 'DEYWURO', string $messageTemplate = null): array`
Sends OTP via SMS with customizable message template.

```php
$result = $otpService->sendOTPSMS($phone, $otp, 'DEYWURO', "Your OTP is {otp}");
```

#### `sendSMS(string $message, string $phone, string $source): array`
Sends any SMS message.

```php
$result = $otpService->sendSMS("Hello World", $phone, "DEYWURO");
```

### Utility Methods

#### `validatePhoneNumber(string $phone): bool`
Validates phone number format.

```php
$isValid = $otpService->validatePhoneNumber($phone);
```

#### `isSessionExpired(string $sessionToken): bool`
Checks if a session has expired.

```php
$isExpired = $otpService->isSessionExpired($sessionToken);
```

## Usage Examples

### 1. Reseller Registration OTP

```php
// In CompanyController
public function resellerOtp(Request $request)
{
    $validator = Validator::make($request->all(), [
        'phone' => 'required|digits_between:10,20',
        'session_token' => 'required|string|min:32'
    ]);

    if ($validator->fails()) {
        return response()->json(['code' => 400, 'msg' => 'Invalid request parameters']);
    }

    $phone = SmsTools::format_gh_number($request->input('phone'));
    $sessionToken = $request->input('session_token');

    $otpService = new OTPService();
    $result = $otpService->processOTPRequest($phone, $sessionToken);

    return response()->json($result);
}
```

### 2. Regular Registration OTP

```php
// In CompanyController
public function sendOTP(Request $request)
{
    $validator = Validator::make($request->all(), [
        'phone' => 'required|digits_between:10,20',
        'session_token' => 'required|string|min:32'
    ]);

    if ($validator->fails()) {
        return response()->json(['code' => 400, 'msg' => 'Invalid request parameters']);
    }

    $phone = SmsTools::format_gh_number($request->input('phone'));
    $sessionToken = $request->input('session_token');

    $otpService = new OTPService();
    $result = $otpService->processOTPRequest($phone, $sessionToken, 'DEYWURO', "Hello, your registration OTP is {otp}. Valid for 5 minutes.");

    return response()->json($result);
}
```

### 3. Mobile Money OTP

```php
// In CompanyController
public function sendMomoOTP(Request $request)
{
    $validator = Validator::make($request->all(), [
        'phone' => 'required|digits_between:10,20',
        'session_token' => 'required|string|min:32'
    ]);

    if ($validator->fails()) {
        return response()->json(['code' => 400, 'msg' => 'Invalid request parameters']);
    }

    $phone = SmsTools::format_gh_number($request->input('phone'));
    $sessionToken = $request->input('session_token');

    $otpService = new OTPService();
    $result = $otpService->processOTPRequest($phone, $sessionToken, 'DEYWURO', "Hello, your Mobile Money Number OTP is {otp}. Valid for 5 minutes.");

    return response()->json($result);
}
```

## Frontend Integration

### JavaScript Implementation

```javascript
$(document).ready(function () {
    let sessionToken = null;
    
    // Generate session token on page load
    $.post('/company/session/generate', {
        _token: '{{csrf_token()}}'
    })
    .done(function(data) {
        sessionToken = data.session_token;
    })
    .fail(function() {
        console.error('Failed to generate session token');
    });

    // Send OTP request
    $('.otp-btn').on('click', function (e) {
        e.preventDefault();

        if (!sessionToken) {
            alert('Session not initialized. Please refresh the page.');
            return;
        }

        if (mobile.val() === '') {
            alert('Please enter a phone number');
            return;
        }

        $.post('/company/otp/send', {
            _token: '{{csrf_token()}}',
            phone: mobile.val(),
            session_token: sessionToken
        })
        .done(function (data) {
            if (data.code === 0) {
                let userOtp = prompt('An OTP has been sent to ' + mobile.val() + ' \nEnter OTP received Via SMS');
                if (userOtp) {
                    verifyOtp(userOtp);
                }
            } else if (data.code === 429) {
                alert('Too many OTP requests. Please try again later.');
            } else {
                alert('Request for OTP failed. Please try again.');
            }
        })
        .fail(function () {
            alert('Request for OTP failed. Please try again.');
        });
    });

    function verifyOtp(userOtp) {
        if (!userOtp || userOtp === '') {
            return;
        }

        $.post('/company/otp/verify', {
            _token: '{{csrf_token()}}',
            phone: mobile.val(),
            otp: userOtp,
            session_token: sessionToken
        })
        .done(function (data) {
            if (data.code === 0) {
                submit.show();
                otpBtn.hide();
                mobile.attr('readonly', true);
                alert('OTP verified successfully!');
            } else {
                let retryOtp = prompt('Wrong OTP! Try again. \nEnter OTP received Via SMS');
                if (retryOtp) {
                    verifyOtp(retryOtp);
                }
            }
        })
        .fail(function () {
            alert('OTP verification failed. Please try again.');
        });
    }
});
```

## API Endpoints

### Reseller Registration
- `POST /company/reseller/otp/send` - Send OTP for reseller registration
- `POST /company/reseller/otp/verify` - Verify OTP for reseller registration
- `POST /company/reseller/session/generate` - Generate session token
- `POST /company/reseller/session/cleanup` - Cleanup session

### Regular Registration
- `POST /company/otp/send` - Send OTP for regular registration
- `POST /company/otp/verify` - Verify OTP for regular registration
- `POST /company/momo/otp/send` - Send OTP for mobile money verification
- `POST /company/momo/otp/verify` - Verify OTP for mobile money verification
- `POST /company/session/generate` - Generate session token
- `POST /company/session/cleanup` - Cleanup session

## Configuration

### Cache Configuration
Ensure your cache driver is properly configured in `config/cache.php`:

```php
'default' => env('CACHE_DRIVER', 'file'),
```

### Session Configuration
Review session configuration in `config/session.php`:

```php
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => false,
```

## Security Considerations

### Rate Limiting
- Maximum 3 OTP requests per phone number per hour
- Rate limit is stored in cache with 1-hour expiration
- Admin can clear rate limits if needed

### Session Security
- 64-character random session tokens
- Session data stored server-side
- Automatic cleanup on page unload
- 24-hour session expiration

### OTP Security
- 6-digit cryptographically secure random numbers
- 5-minute expiration time
- One-time use (deleted after verification)
- No predictable patterns

### Input Validation
- Phone number format validation
- CSRF token validation
- Request method validation
- Input sanitization

## Error Handling

### Response Codes
- `0` - Success
- `400` - Bad Request (invalid parameters)
- `401` - Unauthorized (invalid session/OTP)
- `405` - Method Not Allowed
- `429` - Too Many Requests (rate limited)
- `500` - Internal Server Error

### Error Messages
All error responses include descriptive messages for debugging and user feedback.

## Testing

### Unit Tests
```php
class OTPServiceTest extends TestCase
{
    public function test_otp_generation_is_secure()
    {
        $otpService = new OTPService();
        
        $otp1 = $otpService->generateOTP();
        $otp2 = $otpService->generateOTP();
        
        $this->assertEquals(6, strlen($otp1));
        $this->assertNotEquals($otp1, $otp2);
    }

    public function test_rate_limiting_works()
    {
        $otpService = new OTPService();
        $phone = '233244123456';
        
        // Clear any existing rate limit
        $otpService->clearRateLimit($phone);
        
        // First three requests should work
        $this->assertFalse($otpService->isRateLimited($phone));
        $otpService->incrementRateLimit($phone);
        $this->assertFalse($otpService->isRateLimited($phone));
        $otpService->incrementRateLimit($phone);
        $this->assertFalse($otpService->isRateLimited($phone));
        $otpService->incrementRateLimit($phone);
        
        // Fourth request should be rate limited
        $this->assertTrue($otpService->isRateLimited($phone));
    }
}
```

## Migration Guide

### From Legacy OTP System
1. Replace hardcoded secrets with service calls
2. Update AJAX calls to use new endpoints
3. Implement session token management
4. Handle new response codes
5. Update error handling

### Benefits of New System
- **Centralized Logic**: All OTP operations in one service
- **Better Security**: Comprehensive security features
- **Easier Maintenance**: Single point of modification
- **Reusability**: Can be used across different parts of the application
- **Testing**: Easier to unit test OTP functionality

### Configuration Options
- Configurable rate limits per user type
- Customizable OTP expiration times
- Flexible message templates
- Multiple SMS providers support

## Conclusion

The `OTPService` provides a robust, secure, and maintainable solution for OTP operations. It centralizes all OTP-related functionality while providing comprehensive security features and easy integration across the application. 
