/api/program/on-usb

GET

Detects whether the CloudCoin Console program is running from a USB drive or removable storage device.

Description

The `/api/program/on-usb` endpoint determines if the CloudCoin Console server is running from a USB drive or other removable storage device. This is particularly useful for portable wallet deployments where users carry their CloudCoin wallets on USB flash drives, external hard drives, or SD cards.

💡 Use Cases

This endpoint is useful for:

  • Portable Wallet Detection - Identify when users are running CloudCoin from a USB drive
  • Security Recommendations - Warn users about USB drive security risks (physical theft, loss)
  • Backup Reminders - Prompt USB users to maintain cloud or desktop backups
  • Performance Adjustments - Optimize I/O operations for slower USB 2.0 drives
  • Auto-eject Warnings - Prevent users from removing USB drives during critical operations
  • Licensing/DRM - Implement portable licensing tied to USB storage
⚠️ Platform Support

USB drive detection varies by operating system:

  • Windows: Full support using GetDriveTypeA() Win32 API. Detects DRIVE_REMOVABLE type drives including USB flash drives, external hard drives, and SD card readers.
  • Linux/macOS: Currently returns false (placeholder implementation). Full support requires parsing /proc/mounts or equivalent system information.

Note: On Windows, the detection checks the drive letter (e.g., E:\, F:\) from the program's root path. Network drives and virtual drives are not classified as removable.

Parameters

This endpoint does not require any parameters.

Response

Returns a JSON object indicating whether the program is running from a USB or removable drive.

Response Properties

status string
Always "success" for this endpoint.
operation string
Always "program_on_usb".
on_usb boolean
true if running from a removable drive (USB flash drive, external HDD, SD card), false if running from internal storage (HDD, SSD, or non-removable drive).
root_path string
The full filesystem path where the CloudCoin Console program is located (e.g., E:\CloudCoin\Pro on Windows or /media/usb/CloudCoin/Pro on Linux).

Example Response (USB Drive - Windows)

{
  "status": "success",
  "operation": "program_on_usb",
  "on_usb": true,
  "root_path": "E:\\CloudCoin\\Pro"
}

Example Response (Internal Drive - Windows)

{
  "status": "success",
  "operation": "program_on_usb",
  "on_usb": false,
  "root_path": "C:\\Program Files\\CloudCoin\\Pro"
}

Example Response (Linux - Not Implemented)

{
  "status": "success",
  "operation": "program_on_usb",
  "on_usb": false,
  "root_path": "/home/user/CloudCoin/Pro"
}

Examples

JavaScript (fetch)

const API_HOST = 'http://localhost:8080';

async function checkUSBStorage() {
    try {
        const response = await fetch(`${API_HOST}/api/program/on-usb`);
        const result = await response.json();

        console.log(`Running from USB: ${result.on_usb}`);
        console.log(`Root path: ${result.root_path}`);

        if (result.on_usb) {
            // Show portable mode features
            displayPortableWalletUI();

            // Warn about USB-specific risks
            showSecurityWarning(
                'USB Drive Detected',
                'Your wallet is on removable storage. Keep your USB drive secure and maintain backups.'
            );

            // Enable auto-save before eject
            enableAutoSaveOnEject();
        } else {
            // Standard desktop installation
            displayStandardUI();
        }
    } catch (error) {
        console.error('Error checking USB status:', error);
    }
}

function displayPortableWalletUI() {
    // Add "Safely Eject" button
    const ejectBtn = document.createElement('button');
    ejectBtn.textContent = 'Safely Eject USB Drive';
    ejectBtn.onclick = safelyEjectUSB;
    document.body.appendChild(ejectBtn);
}

function showSecurityWarning(title, message) {
    // Display warning banner
    const banner = document.createElement('div');
    banner.className = 'warning-banner';
    banner.innerHTML = `${title}: ${message}`;
    document.body.prepend(banner);
}

function enableAutoSaveOnEject() {
    // Monitor for USB removal events
    window.addEventListener('beforeunload', (e) => {
        // Save wallet state before USB is ejected
        saveWalletState();
    });
}

checkUSBStorage();

cURL

# Check if running from USB drive
curl -X GET "http://localhost:8080/api/program/on-usb"

# With formatted output using jq
curl -X GET "http://localhost:8080/api/program/on-usb" | jq '.'

# Check USB status and extract boolean value
curl -s "http://localhost:8080/api/program/on-usb" | jq -r '.on_usb'

Go

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

const ApiHost = "http://localhost:8080"

type USBResponse struct {
    Status    string `json:"status"`
    Operation string `json:"operation"`
    OnUSB     bool   `json:"on_usb"`
    RootPath  string `json:"root_path"`
}

func main() {
    resp, err := http.Get(fmt.Sprintf("%s/api/program/on-usb", ApiHost))
    if err != nil {
        log.Fatalf("Failed to check USB status: %v", err)
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatalf("Failed to read response: %v", err)
    }

    var result USBResponse
    if err := json.Unmarshal(body, &result); err != nil {
        log.Fatalf("Failed to parse JSON: %v", err)
    }

    fmt.Printf("CloudCoin Console Location: %s\n", result.RootPath)

    if result.OnUSB {
        fmt.Println("⚠️  Running from USB drive (removable storage)")
        fmt.Println("Security Recommendations:")
        fmt.Println("  - Keep your USB drive physically secure")
        fmt.Println("  - Maintain encrypted backups on separate storage")
        fmt.Println("  - Use 'Safely Eject' before removing USB")
        fmt.Println("  - Consider using AES-256 encryption for wallet files")

        // Adjust settings for portable mode
        enablePortableMode()
    } else {
        fmt.Println("✓ Running from internal/fixed storage")

        // Use standard configuration
        enableStandardMode()
    }
}

func enablePortableMode() {
    // Reduce caching to minimize data loss on sudden USB removal
    fmt.Println("\nEnabling portable mode:")
    fmt.Println("  - Aggressive auto-save: Every 30 seconds")
    fmt.Println("  - Reduced cache size: 10 MB")
    fmt.Println("  - Safe-eject monitoring: Enabled")
}

func enableStandardMode() {
    fmt.Println("\nUsing standard mode:")
    fmt.Println("  - Auto-save: Every 5 minutes")
    fmt.Println("  - Cache size: 100 MB")
}

Python

import requests
import json
from datetime import datetime

API_HOST = 'http://localhost:8080'

def check_usb_storage():
    """Check if CloudCoin Console is running from USB drive"""
    try:
        response = requests.get(f'{API_HOST}/api/program/on-usb')
        result = response.json()

        on_usb = result.get('on_usb', False)
        root_path = result.get('root_path', 'Unknown')

        print(f'CloudCoin Location: {root_path}')
        print(f'USB Drive: {"Yes" if on_usb else "No"}')
        print()

        if on_usb:
            print('⚠️  PORTABLE WALLET DETECTED')
            print('=' * 50)
            print('Security Recommendations:')
            print('  1. Enable wallet encryption (AES-256)')
            print('  2. Maintain cloud/desktop backups')
            print('  3. Use "Safely Eject" before removing USB')
            print('  4. Keep USB drive in secure location')
            print('  5. Consider using a hardware wallet lock')
            print()

            # Configure for USB mode
            config = get_usb_configuration()
            apply_configuration(config)
        else:
            print('✓ Standard Installation')
            print('Using default desktop configuration')
            print()

            config = get_standard_configuration()
            apply_configuration(config)

        return result

    except requests.exceptions.RequestException as e:
        print(f'Error checking USB status: {e}')
        return None

def get_usb_configuration():
    """Get optimized configuration for USB drives"""
    return {
        'auto_save_interval': 30,  # seconds
        'cache_size_mb': 10,
        'enable_safe_eject_monitor': True,
        'io_buffer_size': 4096,  # Smaller buffer for USB 2.0
        'encryption_recommended': True,
        'backup_reminder_frequency': 'daily'
    }

def get_standard_configuration():
    """Get standard configuration for internal drives"""
    return {
        'auto_save_interval': 300,  # 5 minutes
        'cache_size_mb': 100,
        'enable_safe_eject_monitor': False,
        'io_buffer_size': 65536,  # Larger buffer for SSDs
        'encryption_recommended': False,
        'backup_reminder_frequency': 'weekly'
    }

def apply_configuration(config):
    """Apply configuration settings"""
    print('Configuration Applied:')
    for key, value in config.items():
        print(f'  {key}: {value}')

def monitor_usb_ejection():
    """Monitor for USB drive removal (Windows only)"""
    import time

    print('\nMonitoring USB drive (Press Ctrl+C to stop)...')

    try:
        while True:
            response = requests.get(f'{API_HOST}/api/program/on-usb')
            result = response.json()

            if not result.get('on_usb', True):
                print(f'\n[{datetime.now()}] WARNING: USB drive removed!')
                print('Wallet may no longer be accessible.')
                break

            time.sleep(5)  # Check every 5 seconds

    except KeyboardInterrupt:
        print('\nMonitoring stopped.')

if __name__ == '__main__':
    result = check_usb_storage()

    if result and result.get('on_usb'):
        # Optionally start USB ejection monitoring
        monitor = input('\nStart USB ejection monitoring? (y/n): ')
        if monitor.lower() == 'y':
            monitor_usb_ejection()

Implementation Details

The USB drive detection uses platform-specific system calls to identify removable storage:

// Windows implementation (filesystem.c)
bool is_usb_drive(const char* path) {
    #ifdef _WIN32
        if (strlen(path) < 3) return false;

        // Extract drive letter (e.g., "E:\")
        char drive[4] = {path[0], ':', '\\', '\0'};

        // Query Windows for drive type
        UINT drive_type = GetDriveTypeA(drive);

        // DRIVE_REMOVABLE = 2 (USB flash, SD cards, external drives)
        // DRIVE_FIXED = 3 (internal HDD/SSD)
        // DRIVE_REMOTE = 4 (network drives)
        // DRIVE_CDROM = 5 (CD/DVD drives)
        return (drive_type == DRIVE_REMOVABLE);
    #else
        // Linux/macOS: Requires parsing /proc/mounts
        // Currently not implemented (returns false)
        return false;
    #endif
}
Platform Detection Method Detects Status
Windows GetDriveTypeA() Win32 API USB flash drives, external HDDs, SD cards ✓ Fully Supported
Linux Requires /proc/mounts parsing USB mounts (e.g., /media/usb) ⚠️ Not Implemented
macOS Requires /Volumes analysis External drives mounted in /Volumes ⚠️ Not Implemented

Practical Applications

1. Security Warnings for Portable Wallets

Automatically display security recommendations when USB storage is detected:

async function initializeWallet() {
    const response = await fetch('/api/program/on-usb');
    const result = await response.json();

    if (result.on_usb) {
        // Show prominent security banner
        showSecurityBanner({
            title: 'Portable Wallet Detected',
            message: 'Your wallet is on removable storage.',
            recommendations: [
                'Enable AES-256 encryption for all coin files',
                'Create encrypted backups on cloud storage',
                'Use "Safely Eject" before removing USB',
                'Store USB drive in a secure, fireproof location'
            ],
            icon: '⚠️',
            dismissible: false
        });

        // Offer to enable encryption
        if (!walletIsEncrypted()) {
            offerEncryptionWizard();
        }
    }
}

2. Performance Optimization for USB 2.0

Adjust I/O buffer sizes and batch operations for slower USB drives:

async function getOptimalIOSettings() {
    const response = await fetch('/api/program/on-usb');
    const result = await response.json();

    const settings = {
        // USB 2.0: ~35 MB/s, USB 3.0: ~400 MB/s, SSD: ~500 MB/s
        bufferSize: result.on_usb ? 4096 : 65536,
        batchSize: result.on_usb ? 25 : 100,
        simultaneousOps: result.on_usb ? 1 : 4,
        cacheEnabled: !result.on_usb,  // Disable cache on USB
        autoSaveInterval: result.on_usb ? 30000 : 300000  // 30s vs 5min
    };

    console.log('I/O Settings:', settings);
    return settings;
}

async function importCoins(files) {
    const settings = await getOptimalIOSettings();

    // Process in smaller batches on USB to prevent timeouts
    for (let i = 0; i < files.length; i += settings.batchSize) {
        const batch = files.slice(i, i + settings.batchSize);
        await processBatchWithSettings(batch, settings);
    }
}

3. Safe Eject Monitoring

Prevent data loss by blocking USB removal during critical operations:

let criticalOperationInProgress = false;

async function detectCoins(coinFiles) {
    const response = await fetch('/api/program/on-usb');
    const result = await response.json();

    if (result.on_usb) {
        // Enable USB removal monitoring
        startUSBMonitoring();
        criticalOperationInProgress = true;
    }

    try {
        await performDetection(coinFiles);
    } finally {
        criticalOperationInProgress = false;
        if (result.on_usb) {
            stopUSBMonitoring();
        }
    }
}

function startUSBMonitoring() {
    // Poll USB status every 2 seconds
    window.usbMonitor = setInterval(async () => {
        const response = await fetch('/api/program/on-usb');
        const result = await response.json();

        if (!result.on_usb && criticalOperationInProgress) {
            // USB was removed during operation!
            showCriticalError(
                'USB Drive Removed',
                'Your wallet USB drive was removed during a critical operation. ' +
                'Data may be corrupted. Please reinsert the drive immediately.'
            );
            clearInterval(window.usbMonitor);
        }
    }, 2000);
}

function stopUSBMonitoring() {
    if (window.usbMonitor) {
        clearInterval(window.usbMonitor);
    }
}

4. Portable Licensing

Tie software licenses to USB drives for portable installations:

async function validatePortableLicense() {
    const response = await fetch('/api/program/on-usb');
    const result = await response.json();

    if (result.on_usb) {
        console.log('Portable wallet detected - no cloud sync required');

        // Check for license file on USB
        const licenseValid = await checkLocalLicense(result.root_path);

        if (licenseValid) {
            console.log('✓ Portable license validated');
            return true;
        } else {
            console.error('⚠️  No valid license found on USB drive');
            showLicensePrompt();
            return false;
        }
    } else {
        // Desktop installation - check online license
        return await validateOnlineLicense();
    }
}

async function checkLocalLicense(rootPath) {
    // Look for license.key file on USB
    const licenseResponse = await fetch(`/api/license/check?path=${rootPath}`);
    return licenseResponse.json();
}

Related Endpoints

/api/program/on-mobile

Check if the program is running on a mobile device (Android, iOS, ARM platforms).

/api/program/status

Get comprehensive program status including version, active wallet, and server time.

/api/wallet/list

List all configured wallets - useful for managing multiple USB wallets.