Application-Level Implementation

Application-Level Implementation

Node.js/Express Implementation

// Basic implementation
app.use((req, res, next) => {
    res.setHeader('Permissions-Policy', 
        'camera=(), microphone=(), geolocation=(), payment=()'
    );
    next();
});

// Dynamic policy based on route
const permissionsPolicies = {
    default: {
        camera: [],
        microphone: [],
        geolocation: [],
        payment: [],
        usb: []
    },
    videoChat: {
        camera: ['self'],
        microphone: ['self'],
        'display-capture': ['self'],
        fullscreen: ['self']
    },
    maps: {
        geolocation: ['self', 'https://maps.googleapis.com']
    },
    checkout: {
        payment: ['self', 'https://stripe.com', 'https://paypal.com']
    }
};

function buildPermissionsPolicy(config) {
    return Object.entries(config)
        .map(([feature, allowlist]) => {
            const sources = allowlist.length > 0 ? allowlist.join(' ') : '';
            return `${feature}=(${sources})`;
        })
        .join(', ');
}

app.use((req, res, next) => {
    let policyConfig = permissionsPolicies.default;
    
    if (req.path.startsWith('/video-chat')) {
        policyConfig = { ...policyConfig, ...permissionsPolicies.videoChat };
    } else if (req.path.startsWith('/maps')) {
        policyConfig = { ...policyConfig, ...permissionsPolicies.maps };
    } else if (req.path.startsWith('/checkout')) {
        policyConfig = { ...policyConfig, ...permissionsPolicies.checkout };
    }
    
    res.setHeader('Permissions-Policy', buildPermissionsPolicy(policyConfig));
    next();
});

Feature Detection and Progressive Enhancement

// Client-side feature detection with policy awareness
class FeatureDetector {
    async checkPermission(feature) {
        // Map feature names to permission names
        const permissionMap = {
            'camera': 'camera',
            'microphone': 'microphone',
            'geolocation': 'geolocation',
            'notifications': 'notifications',
            'persistent-storage': 'persistent-storage'
        };
        
        const permissionName = permissionMap[feature];
        
        if (!permissionName || !navigator.permissions) {
            return 'unsupported';
        }
        
        try {
            const result = await navigator.permissions.query({ name: permissionName });
            return result.state; // 'granted', 'denied', or 'prompt'
        } catch (error) {
            console.error(`Permission query failed for ${feature}:`, error);
            return 'error';
        }
    }
    
    async enableFeature(feature, enableCallback, fallbackCallback) {
        const permission = await this.checkPermission(feature);
        
        if (permission === 'granted') {
            enableCallback();
        } else if (permission === 'prompt') {
            // Request permission through user action
            const button = document.querySelector(`[data-feature="${feature}"]`);
            button?.addEventListener('click', async () => {
                try {
                    await enableCallback();
                } catch (error) {
                    fallbackCallback(error);
                }
            });
        } else {
            fallbackCallback(new Error(`${feature} permission denied`));
        }
    }
}

// Usage example
const detector = new FeatureDetector();

// Check camera permission
detector.enableFeature(
    'camera',
    async () => {
        const stream = await navigator.mediaDevices.getUserMedia({ video: true });
        // Use camera stream
    },
    (error) => {
        console.log('Camera not available:', error);
        // Show alternative UI
    }
);