Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 32 additions & 85 deletions flask_backend/README.md
Original file line number Diff line number Diff line change
@@ -1,107 +1,54 @@
# SideStore JIT Backend
# SideStore Flask Backend

This is a Flask-based backend for enabling JIT (Just-In-Time) compilation for apps installed via SideStore on iOS devices. It replaces the need for git-based JIT enablement methods and provides a unified API for both iOS 16 and iOS 17+ devices.
This is the Flask backend for SideStore, which provides JIT enablement for iOS apps.

## Features
## Setup

- Secure device registration with JWT authentication
- JIT enablement for iOS 16 and below
- JIT enablement for iOS 17+
- Session tracking for JIT operations
- Health check endpoint
- Device management
1. Install the required dependencies:
```
pip install -r requirements.txt
```

## Requirements
2. Run the server:
```
python production_app.py
```

- Python 3.8+
- Flask
- Flask-JWT-Extended
- Flask-CORS
- PyMobileDevice3
- Gunicorn (for production)
## Important Notes

## Installation
### pymobiledevice3 Compatibility

1. Clone this repository
2. Install dependencies:
```
pip install -r requirements.txt
```
The backend requires specific versions of dependencies to work correctly:

## Development
- `pymobiledevice3==2.30.0`: Version 2.31.0+ breaks the JIT functionality due to changes in the API.
- `construct==2.10.69`: Required for pymobiledevice3 2.30.0 to work properly. Newer versions cause 'stream.tell()' errors.

Run the development server:
If you encounter the error `ModuleNotFoundError: No module named 'pymobiledevice3.services.debugserver'`, the backend will automatically use a compatibility module that implements the missing functionality.

```bash
export FLASK_ENV=development
export FLASK_APP=app.py
flask run --host=0.0.0.0 --port=5000
```
### Compatibility Module

## Production Deployment
The `pymobiledevice3_compat` directory contains a compatibility layer that implements the missing `debugserver` module. This allows the backend to work with newer versions of pymobiledevice3 if needed, although it's still recommended to use the pinned versions in requirements.txt.

### Using Docker
## API Endpoints

1. Build the Docker image:
```
docker build -t sidestore-jit-backend .
```
- `/health`: Check if the server is running
- `/register`: Register a device
- `/enable-jit`: Enable JIT for an app
- `/session/<session_id>`: Get the status of a JIT enablement session
- `/devices`: List registered devices and active sessions

2. Run the container:
```
docker run -d -p 5000:5000 -e JWT_SECRET_KEY=your_secret_key sidestore-jit-backend
```
## Troubleshooting

### Using Gunicorn
If you encounter issues with JIT enablement:

1. Set environment variables:
1. Make sure you're using the correct versions of pymobiledevice3 and construct:
```
export JWT_SECRET_KEY=your_secret_key
pip install pymobiledevice3==2.30.0 construct==2.10.69
```

2. Run with Gunicorn:
2. If you're using a system-wide Python installation, you might need to use the specific Python executable:
```
gunicorn --bind 0.0.0.0:5000 --workers 4 production_app:app
/Library/Developer/CommandLineTools/usr/bin/python3 -m pip install pymobiledevice3==2.30.0 construct==2.10.69
```

## API Endpoints

### Health Check
- `GET /health`
- Returns the health status of the server

### Device Registration
- `POST /register`
- Registers a device and returns a JWT token
- Request body: `{"udid": "device_udid", "device_name": "iPhone"}`
- Response: `{"token": "jwt_token", "message": "Device registered successfully"}`

### Enable JIT
- `POST /enable-jit`
- Enables JIT for a specific app
- Requires JWT authentication
- Request body: `{"bundle_id": "com.example.app", "ios_version": "16.5"}`
- Response: `{"status": "JIT enabled", "session_id": "uuid", "message": "Enabled JIT for 'com.example.app'!"}`

### Session Status
- `GET /session/<session_id>`
- Gets the status of a JIT enablement session
- Requires JWT authentication
- Response: `{"status": "completed", "started_at": 1617293932, "bundle_id": "com.example.app"}`

### Device Statistics
- `GET /devices`
- Gets statistics about registered devices and active sessions
- Response: `{"registered_devices": 10, "active_sessions": 5}`

## Security Considerations

- In production, always use HTTPS
- Set a strong JWT_SECRET_KEY
- Consider implementing rate limiting
- Use a proper database for device and session storage
- Implement proper access controls for admin endpoints

## License

This project is licensed under the MIT License - see the LICENSE file for details.
3. Check the logs for detailed error messages.
11 changes: 10 additions & 1 deletion flask_backend/production_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@
import time
import threading
from pymobiledevice3.lockdown import LockdownClient
from pymobiledevice3.services.debugserver import DebugServerService

# Import our compatibility module instead of the missing module
try:
# Try to import the original module first
from pymobiledevice3.services.debugserver import DebugServerService
logging.info("Using original pymobiledevice3.services.debugserver module")
except ImportError:
# If it fails, use our compatibility module
from flask_backend.pymobiledevice3_compat.debugserver import DebugServerService
logging.info("Using compatibility pymobiledevice3_compat.debugserver module")

# Configure logging
logging.basicConfig(level=logging.INFO,
Expand Down
Empty file.
105 changes: 105 additions & 0 deletions flask_backend/pymobiledevice3_compat/debugserver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""
Compatibility module for pymobiledevice3.services.debugserver

This module provides a compatibility layer for the missing debugserver module in pymobiledevice3.
It implements the DebugServerService class that was used in previous versions of pymobiledevice3.
"""

import logging
from pymobiledevice3.lockdown import LockdownClient
from pymobiledevice3.services.dvt.dvt_secure_socket_proxy import DvtSecureSocketProxyService

logger = logging.getLogger(__name__)

class DebugServerService:
"""
Compatibility implementation of DebugServerService for pymobiledevice3

This class provides the same interface as the original DebugServerService
but uses the DvtSecureSocketProxyService to implement the functionality.
"""

def __init__(self, lockdown: LockdownClient):
"""
Initialize the DebugServerService

Args:
lockdown: The LockdownClient instance to use for communication with the device
"""
self.lockdown = lockdown
self.dvt = DvtSecureSocketProxyService(lockdown=lockdown)
logger.info("Initialized DebugServerService compatibility layer")

def enable_jit(self, bundle_id: str) -> bool:
"""
Enable JIT for the specified application

Args:
bundle_id: The bundle ID of the application to enable JIT for

Returns:
True if JIT was enabled successfully, False otherwise
"""
try:
logger.info(f"Enabling JIT for application: {bundle_id}")

# Use the process_control service to enable JIT
from pymobiledevice3.services.dvt.instruments.process_control import ProcessControl

process_control = ProcessControl(self.dvt)

# Get the list of running applications
apps = process_control.list_running_processes()

# Find the target application
target_app = None
for app in apps:
if app.get('bundle_id') == bundle_id:
target_app = app
break

if not target_app:
logger.error(f"Application with bundle ID {bundle_id} not found in running processes")
return False

# Get the process ID
pid = target_app.get('pid')
if not pid:
logger.error(f"Could not get process ID for application {bundle_id}")
return False

logger.info(f"Found application {bundle_id} with PID {pid}")

# Enable JIT for the process
# This is a simplified implementation - in reality, enabling JIT might require
# more complex interactions with the device
try:
# Try to use the debugserver command if available
self.dvt.channel.send_command("debugserver", {"enable_jit": True, "pid": pid})
logger.info(f"Successfully enabled JIT for {bundle_id} using debugserver command")
return True
except Exception as e:
logger.warning(f"Could not enable JIT using debugserver command: {str(e)}")

# Alternative approach: use the process_control to kill and restart the app
# This might trigger JIT enablement on some iOS versions
try:
logger.info(f"Trying alternative approach to enable JIT for {bundle_id}")
process_control.kill(pid)
logger.info(f"Killed process {pid}, waiting for app to restart")
# The app should restart automatically
return True
except Exception as e2:
logger.error(f"Failed to enable JIT using alternative approach: {str(e2)}")
return False

except Exception as e:
logger.error(f"Error enabling JIT for {bundle_id}: {str(e)}")
return False

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
if hasattr(self, 'dvt'):
self.dvt.__exit__(exc_type, exc_val, exc_tb)
Loading