498 lines
12 KiB
Markdown
498 lines
12 KiB
Markdown
# Flash Call OTP System — Setup Guide
|
|
|
|
## Table of Contents
|
|
|
|
1. [Prerequisites](#1-prerequisites)
|
|
2. [Server Setup (PHP Backend)](#2-server-setup-php-backend)
|
|
3. [Android Caller App Setup](#3-android-caller-app-setup)
|
|
4. [Flutter Receiver App Setup](#4-flutter-receiver-app-setup)
|
|
5. [End-to-End Testing](#5-end-to-end-testing)
|
|
6. [Troubleshooting](#6-troubleshooting)
|
|
|
|
---
|
|
|
|
## 1. Prerequisites
|
|
|
|
### Server Requirements
|
|
|
|
- Ubuntu 20.04+ or similar Linux distribution
|
|
- PHP 8.1+ with phpredis extension
|
|
- MySQL 8.0+ or MariaDB 10.6+
|
|
- Redis 6.0+
|
|
- Nginx 1.18+
|
|
- Certbot (Let's Encrypt) for SSL
|
|
- Composer (optional, for dependency management)
|
|
|
|
### Android Caller App Requirements
|
|
|
|
- Android Studio Hedgehog (2023.1.1) or newer
|
|
- Android device running Android 8.0 (API 26) or higher
|
|
- Active SIM card installed in the device
|
|
- Stable internet connection (Wi-Fi recommended)
|
|
|
|
### Flutter Receiver App Requirements
|
|
|
|
- Flutter 3.16+ with Dart 3.x
|
|
- Android device for full auto-read testing
|
|
- iOS device for SMS AutoFill testing (optional)
|
|
- Xcode 15+ (for iOS builds)
|
|
|
|
---
|
|
|
|
## 2. Server Setup (PHP Backend)
|
|
|
|
### 2.1 Install Required Packages
|
|
|
|
```bash
|
|
sudo apt update
|
|
sudo apt install -y nginx php8.1-fpm php8.1-mysql php8.1-redis php8.1-mbstring php8.1-xml php8.1-curl mysql-server redis-server
|
|
```
|
|
|
|
### 2.2 Configure MySQL
|
|
|
|
```bash
|
|
sudo mysql_secure_installation
|
|
```
|
|
|
|
Log in to MySQL and create the database and user:
|
|
|
|
```bash
|
|
sudo mysql -u root -p
|
|
```
|
|
|
|
```sql
|
|
CREATE DATABASE otp-db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
CREATE USER 'otp-user'@'localhost' IDENTIFIED BY 'tCO1zuHWVKjTnryDDInL';
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON otp_db.* TO 'otp-user'@'localhost';
|
|
FLUSH PRIVILEGES;
|
|
EXIT;
|
|
```
|
|
|
|
### 2.3 Import Database Schema
|
|
|
|
```bash
|
|
mysql -u otp_user -p otp_db < /path/to/backend/database.sql
|
|
```
|
|
|
|
Verify the tables were created:
|
|
|
|
```bash
|
|
mysql -u otp_user -p otp_db -e "SHOW TABLES;"
|
|
```
|
|
|
|
You should see: `api_logs`, `caller_devices`, `otp_requests`
|
|
|
|
### 2.4 Configure Redis
|
|
|
|
Edit Redis configuration for security:
|
|
|
|
```bash
|
|
sudo nano /etc/redis/redis.conf
|
|
```
|
|
|
|
Set the following:
|
|
|
|
```
|
|
bind 127.0.0.1
|
|
protected-mode yes
|
|
# requirepass YOUR_REDIS_PASSWORD # Uncomment and set if needed
|
|
```
|
|
|
|
Restart Redis:
|
|
|
|
```bash
|
|
sudo systemctl restart redis-server
|
|
sudo systemctl enable redis-server
|
|
```
|
|
|
|
Test connection:
|
|
|
|
```bash
|
|
redis-cli ping
|
|
# Should return: PONG
|
|
```
|
|
|
|
### 2.5 Deploy PHP Backend
|
|
|
|
Create the web root directory:
|
|
|
|
```bash
|
|
sudo mkdir -p /var/www/otp.intaleqapp.com/public
|
|
sudo chown -R www-data:www-data /var/www/otp.intaleqapp.com
|
|
```
|
|
|
|
Copy the backend files:
|
|
|
|
```bash
|
|
# Copy the entire backend directory
|
|
cp -r backend/* /var/www/otp.intaleqapp.com/
|
|
|
|
# The structure should be:
|
|
# /var/www/otp.intaleqapp.com/
|
|
# ├── api/
|
|
# │ ├── request-otp.php
|
|
# │ ├── pending-call.php
|
|
# │ ├── call-done.php
|
|
# │ ├── verify-otp.php
|
|
# │ ├── register-device.php
|
|
# │ ├── pending-sms.php
|
|
# │ └── sms-done.php
|
|
# ├── includes/
|
|
# │ ├── Database.php
|
|
# │ ├── Redis.php
|
|
# │ ├── RateLimit.php
|
|
# │ ├── Auth.php
|
|
# │ └── Logger.php
|
|
# ├── config.php
|
|
# ├── .htaccess
|
|
# ├── database.sql
|
|
# ├── nginx.conf
|
|
# └── logs/
|
|
```
|
|
|
|
Set permissions:
|
|
|
|
```bash
|
|
sudo chown -R www-data:www-data /var/www/otp.intaleqapp.com
|
|
sudo chmod -R 755 /var/www/otp.intaleqapp.com
|
|
sudo chmod -R 775 /var/www/otp.intaleqapp.com/logs
|
|
```
|
|
|
|
### 2.6 Configure config.php
|
|
|
|
Edit the configuration file with your production credentials:
|
|
|
|
```bash
|
|
sudo nano /var/www/otp.intaleqapp.com/config.php
|
|
```
|
|
|
|
Update these critical values:
|
|
|
|
```php
|
|
define('DB_PASS', 'YOUR_ACTUAL_STRONG_PASSWORD');
|
|
define('APP_KEY', 'GENERATE_A_SECURE_RANDOM_KEY_HERE');
|
|
define('DEVICE_KEY', 'GENERATE_A_DIFFERENT_SECURE_KEY_HERE');
|
|
```
|
|
|
|
Generate secure keys:
|
|
|
|
```bash
|
|
openssl rand -hex 32
|
|
```
|
|
|
|
### 2.7 Configure Nginx
|
|
|
|
Copy the nginx configuration:
|
|
|
|
```bash
|
|
sudo cp /var/www/otp.intaleqapp.com/nginx.conf /etc/nginx/sites-available/otp.intaleqapp.com
|
|
sudo ln -s /etc/nginx/sites-available/otp.intaleqapp.com /etc/nginx/sites-enabled/
|
|
```
|
|
|
|
Test the configuration:
|
|
|
|
```bash
|
|
sudo nginx -t
|
|
```
|
|
|
|
Reload Nginx:
|
|
|
|
```bash
|
|
sudo systemctl reload nginx
|
|
```
|
|
|
|
### 2.8 Install SSL Certificate
|
|
|
|
```bash
|
|
sudo apt install certbot python3-certbot-nginx
|
|
sudo certbot --nginx -d otp.intaleqapp.com
|
|
```
|
|
|
|
Follow the prompts. Certbot will automatically modify the Nginx config for SSL.
|
|
|
|
Set up auto-renewal:
|
|
|
|
```bash
|
|
sudo crontab -e
|
|
# Add: 0 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"
|
|
```
|
|
|
|
### 2.9 Configure PHP-FPM
|
|
|
|
Ensure PHP-FPM is running:
|
|
|
|
```bash
|
|
sudo systemctl enable php8.1-fpm
|
|
sudo systemctl start php8.1-fpm
|
|
```
|
|
|
|
Check the socket path matches your nginx config:
|
|
|
|
```bash
|
|
ls -la /var/run/php/php8.1-fpm.sock
|
|
```
|
|
|
|
### 2.10 Verify the Backend
|
|
|
|
Test the health endpoint:
|
|
|
|
```bash
|
|
curl https://otp.intaleqapp.com/health
|
|
# Should return: {"status":"ok"}
|
|
```
|
|
|
|
Test the OTP request (will fail without valid app_key, but confirms routing works):
|
|
|
|
```bash
|
|
curl -X POST https://otp.intaleqapp.com/api/request-otp \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"phone":"+962790000000","app_key":"wrong_key"}'
|
|
# Should return: {"success":false,"message":"invalid_app_key"}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Android Caller App Setup
|
|
|
|
### 3.1 Build the App
|
|
|
|
1. Open Android Studio
|
|
2. Select "Open an existing project"
|
|
3. Navigate to the `caller-app/` directory
|
|
4. Wait for Gradle sync to complete
|
|
5. Connect your Android device (with USB debugging enabled)
|
|
6. Click Run ▶️
|
|
|
|
### 3.2 First-Time Setup on the Device
|
|
|
|
1. **Install the APK** on the cheap Android phone with SIM card
|
|
2. **Grant all permissions** when prompted:
|
|
- Phone (CALL_PHONE)
|
|
- Phone State (READ_PHONE_STATE)
|
|
- SMS (SEND_SMS)
|
|
3. **Disable Battery Optimization** — the app will prompt you; select "Don't optimize" for Flash OTP Caller
|
|
4. On the main screen:
|
|
- **Device ID**: Auto-generated UUID (note this down)
|
|
- **Phone Number**: Enter the phone number of the SIM in this device (e.g., +96279XXXXXXX)
|
|
- **App Key**: Enter the DEVICE_KEY from your server's config.php
|
|
- **SIM Slot**: Select 0 (or 1 for dual SIM)
|
|
5. Tap **"Register Device"** — you should see a success message
|
|
6. Tap **"Start Service"** — the notification should show "Flash OTP Caller — Active"
|
|
|
|
### 3.3 Verify Service is Running
|
|
|
|
- Check the persistent notification in the status bar
|
|
- The status indicator should show "Service Running ✅"
|
|
- The live log area should start showing "Polling..." messages
|
|
- Verify on the server that the device is registered:
|
|
|
|
```bash
|
|
mysql -u otp_user -p otp_db -e "SELECT * FROM caller_devices;"
|
|
```
|
|
|
|
### 3.4 Keep the App Running
|
|
|
|
- **Lock the app** in recent apps (prevent it from being killed)
|
|
- On Xiaomi/OPPO/Vivo: Enable "Auto-start" in security settings
|
|
- On Samsung: Disable "Put app to sleep" in battery settings
|
|
- Keep the phone plugged into charger if possible
|
|
- Use a dedicated SIM card with an active plan that can make calls and send SMS
|
|
|
|
---
|
|
|
|
## 4. Flutter Receiver App Setup
|
|
|
|
### 4.1 Build the App
|
|
|
|
```bash
|
|
cd receiver-app/
|
|
flutter pub get
|
|
flutter run
|
|
```
|
|
|
|
For APK build:
|
|
|
|
```bash
|
|
flutter build apk --release
|
|
```
|
|
|
|
For iOS (macOS only):
|
|
|
|
```bash
|
|
cd receiver-app/
|
|
flutter pub get
|
|
cd ios/
|
|
pod install
|
|
cd ..
|
|
flutter run
|
|
```
|
|
|
|
### 4.2 Testing on Android
|
|
|
|
1. Install the app on a test phone (Phone B)
|
|
2. Open the app
|
|
3. Enter the phone number of Phone B (with +962 prefix)
|
|
4. Ensure "Android" is selected as device type
|
|
5. Tap "Send OTP"
|
|
6. Phone A (Caller device) should call Phone B within 3-6 seconds
|
|
7. The call will come from a number like +96279XX{OTP4digits}
|
|
8. Phone B's call log will detect the missed call
|
|
9. The app extracts the last 4 digits as OTP
|
|
10. Auto-verifies with the backend
|
|
11. Success screen appears
|
|
|
|
### 4.3 Testing on iOS
|
|
|
|
1. Install the app on an iPhone
|
|
2. Open the app
|
|
3. Enter the phone number of the iPhone (with +962 prefix)
|
|
4. Toggle device type to "iOS"
|
|
5. Tap "Send OTP"
|
|
6. The Caller Android device will send an SMS
|
|
7. iOS keyboard will show the AutoFill suggestion
|
|
8. Tap the suggestion (one tap only)
|
|
9. The app auto-submits the OTP
|
|
10. Success screen appears
|
|
|
|
---
|
|
|
|
## 5. End-to-End Testing
|
|
|
|
### Complete Test Flow
|
|
|
|
1. **Server**: Confirm health endpoint returns `{"status":"ok"}`
|
|
2. **Caller Device**: Ensure service is running with "Service Running ✅"
|
|
3. **Receiver App**: Enter phone number and tap "Send OTP"
|
|
4. **Timing**: Call should arrive within 3-6 seconds
|
|
5. **Auto-detect**: Receiver app should detect the missed call within 1-2 seconds
|
|
6. **Verification**: Success screen should appear without any user input
|
|
7. **Database check**: Verify the record in `otp_requests` has `verified_at` set
|
|
|
|
### Testing Individual API Endpoints
|
|
|
|
```bash
|
|
# Request OTP
|
|
curl -X POST https://otp.intaleqapp.com/api/request-otp \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"phone":"+962790000001","app_key":"YOUR_APP_KEY","device_type":"android"}'
|
|
|
|
# Verify OTP
|
|
curl -X POST https://otp.intaleqapp.com/api/verify-otp \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"phone":"+962790000001","otp":"1234","app_key":"YOUR_APP_KEY"}'
|
|
|
|
# Check pending calls (Caller App)
|
|
curl "https://otp.intaleqapp.com/api/pending-call?device_id=DEVICE_XXX&app_key=YOUR_DEVICE_KEY"
|
|
|
|
# Check pending SMS (Caller App)
|
|
curl "https://otp.intaleqapp.com/api/pending-sms?device_id=DEVICE_XXX&app_key=YOUR_DEVICE_KEY"
|
|
|
|
# Register device
|
|
curl -X POST https://otp.intaleqapp.com/api/register-device \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"device_id":"DEVICE_001","phone_number":"+962790000000","sim_slot":0,"app_key":"YOUR_DEVICE_KEY"}'
|
|
```
|
|
|
|
### Monitoring
|
|
|
|
Check server logs:
|
|
|
|
```bash
|
|
# Nginx access log
|
|
sudo tail -f /var/log/nginx/otp.intaleqapp.com.access.log
|
|
|
|
# PHP error log
|
|
sudo tail -f /var/log/php8.1-fpm/error.log
|
|
|
|
# Application log
|
|
tail -f /var/www/otp.intaleqapp.com/logs/api.log
|
|
```
|
|
|
|
Check Redis:
|
|
|
|
```bash
|
|
redis-cli
|
|
> KEYS otp:*
|
|
> TTL otp:+962790000001
|
|
> GET otp:+962790000001
|
|
```
|
|
|
|
Check MySQL:
|
|
|
|
```sql
|
|
-- Recent OTP requests
|
|
SELECT * FROM otp_requests ORDER BY created_at DESC LIMIT 10;
|
|
|
|
-- Active devices
|
|
SELECT * FROM caller_devices WHERE is_active = 1;
|
|
|
|
-- Today's stats
|
|
SELECT status, COUNT(*) as count
|
|
FROM otp_requests
|
|
WHERE DATE(created_at) = CURDATE()
|
|
GROUP BY status;
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Troubleshooting
|
|
|
|
### Caller Device Not Receiving Tasks
|
|
|
|
1. Check the device is registered: `SELECT * FROM caller_devices WHERE device_id = 'YOUR_DEVICE_ID';`
|
|
2. Check `is_active = 1` and `last_seen` is recent
|
|
3. Check the Caller App has internet access
|
|
4. Check the app_key matches DEVICE_KEY in config.php
|
|
5. Restart the CallerService
|
|
|
|
### Calls Not Going Through
|
|
|
|
1. Verify CALL_PHONE permission is granted
|
|
2. Check the SIM card has credit/plan for making calls
|
|
3. Check the phone number format in the task
|
|
4. Try manually dialing the number from the phone app
|
|
5. Check if Do Not Disturb mode is off
|
|
|
|
### SMS Not Sending
|
|
|
|
1. Verify SEND_SMS permission is granted
|
|
2. Check the SIM card can send SMS
|
|
3. Check the destination number format
|
|
4. Test sending a manual SMS from the device
|
|
|
|
### OTP Auto-detect Not Working (Flutter App)
|
|
|
|
1. Verify READ_CALL_LOG and READ_PHONE_STATE permissions are granted
|
|
2. Check the phone actually received a missed call
|
|
3. Verify the call type is detected as "missed" (not "rejected")
|
|
4. If the user answers the call, it won't be in the missed call log
|
|
5. Try the manual entry fallback
|
|
|
|
### iOS AutoFill Not Working
|
|
|
|
1. Ensure the SMS format includes `@otp.intaleqapp.com #{OTP}` at the end
|
|
2. The domain must match the app's associated domain
|
|
3. Test with a real device (simulators don't receive SMS)
|
|
4. Check that `AutofillHints.oneTimeCode` is set on the text field
|
|
5. The SMS must come from a phone number, not an alphanumeric sender
|
|
|
|
### Rate Limiting Issues
|
|
|
|
1. Check Redis is running: `redis-cli ping`
|
|
2. Clear rate limit for a phone: `redis-cli DEL rate_limit:otp:+962790000001`
|
|
3. Adjust limits in config.php if needed
|
|
|
|
### Database Connection Errors
|
|
|
|
1. Verify MySQL is running: `sudo systemctl status mysql`
|
|
2. Check credentials in config.php
|
|
3. Test connection: `mysql -u otp_user -p -h localhost otp_db`
|
|
4. Check PHP-FPM error log
|
|
|
|
### High Server Load
|
|
|
|
1. Check the polling interval (3 seconds default)
|
|
2. Consider increasing to 5 seconds if many devices are connected
|
|
3. Use Redis for session data, MySQL for persistent storage only
|
|
4. Monitor with `top`, `htop`, or `mysqladmin processlist`
|