browsing 0.1.7

Browser automation: navigate, click, extract, screenshot. Standalone browser control via CDP.
Documentation
//! Browser permissions management via CDP Browser domain

use crate::browser::views::PermissionType;
use crate::error::Result;
use std::sync::Arc;

/// Manages browser permissions (camera, microphone, notifications, etc.)
#[derive(Debug, Clone)]
pub struct PermissionsManager {
    client: Arc<crate::browser::cdp::CdpClient>,
}

impl PermissionsManager {
    /// Create a new permissions manager
    pub fn new(client: Arc<crate::browser::cdp::CdpClient>) -> Self {
        Self { client }
    }

    /// Grant permissions for a specific origin.
    /// Common permissions: videoCapture, audioCapture, geolocation, notifications, clipboardReadWrite, displayCapture, sensors, etc.
    pub async fn grant(&self, origin: &str, permissions: Vec<PermissionType>) -> Result<()> {
        let perms: Vec<String> = permissions
            .into_iter()
            .map(|p| serde_json::to_string(&p).unwrap().trim_matches('"').to_string())
            .collect();

        self.client
            .send_command(
                "Browser.grantPermissions",
                serde_json::json!({
                    "origin": origin,
                    "permissions": perms,
                }),
            )
            .await?;
        Ok(())
    }

    /// Reset all permissions for a specific origin
    pub async fn reset(&self, origin: &str) -> Result<()> {
        self.client
            .send_command(
                "Browser.resetPermissions",
                serde_json::json!({ "origin": origin }),
            )
            .await?;
        Ok(())
    }

    /// Convenience: grant camera permission
    pub async fn grant_camera(&self, origin: &str) -> Result<()> {
        self.grant(origin, vec![PermissionType::VideoCapture]).await
    }

    /// Convenience: grant microphone permission
    pub async fn grant_microphone(&self, origin: &str) -> Result<()> {
        self.grant(origin, vec![PermissionType::AudioCapture]).await
    }

    /// Convenience: grant camera + microphone permissions
    pub async fn grant_camera_and_microphone(&self, origin: &str) -> Result<()> {
        self.grant(origin, vec![PermissionType::VideoCapture, PermissionType::AudioCapture])
            .await
    }

    /// Convenience: grant notifications permission
    pub async fn grant_notifications(&self, origin: &str) -> Result<()> {
        self.grant(origin, vec![PermissionType::Notifications]).await
    }

    /// Convenience: grant geolocation permission
    pub async fn grant_geolocation(&self, origin: &str) -> Result<()> {
        self.grant(origin, vec![PermissionType::Geolocation]).await
    }

    /// Convenience: grant clipboard access
    pub async fn grant_clipboard(&self, origin: &str) -> Result<()> {
        self.grant(origin, vec![PermissionType::ClipboardReadWrite]).await
    }

    /// Convenience: grant all common permissions for an origin
    pub async fn grant_all_common(&self, origin: &str) -> Result<()> {
        self.grant(
            origin,
            vec![
                PermissionType::VideoCapture,
                PermissionType::AudioCapture,
                PermissionType::Geolocation,
                PermissionType::Notifications,
                PermissionType::ClipboardReadWrite,
                PermissionType::DisplayCapture,
                PermissionType::Sensors,
            ],
        )
        .await
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_permission_type_serialization() {
        let perm = PermissionType::VideoCapture;
        let json = serde_json::to_string(&perm).unwrap();
        assert_eq!(json, "\"videoCapture\"");

        let perm = PermissionType::AudioCapture;
        let json = serde_json::to_string(&perm).unwrap();
        assert_eq!(json, "\"audioCapture\"");
    }

    #[test]
    fn test_permission_types_roundtrip() {
        let types = vec![
            PermissionType::VideoCapture,
            PermissionType::AudioCapture,
            PermissionType::Geolocation,
            PermissionType::Notifications,
            PermissionType::ClipboardReadWrite,
            PermissionType::DisplayCapture,
            PermissionType::Sensors,
            PermissionType::Nfc,
            PermissionType::Midi,
            PermissionType::MidiSysex,
            PermissionType::WakeLockScreen,
            PermissionType::WakeLockSystem,
            PermissionType::StorageAccess,
            PermissionType::WindowManagement,
            PermissionType::BackgroundSync,
            PermissionType::PaymentHandler,
        ];
        for t in types {
            let json = serde_json::to_string(&t).unwrap();
            assert!(!json.is_empty());
        }
    }
}