// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use {
    crate::{error::RightsRoutingError, walk_state::WalkStateUnit},
    fidl_fuchsia_io as fio,
    lazy_static::lazy_static,
    std::convert::From,
};

lazy_static! {
    // TODO: const initialization of bitflag types with bitwise-or is not supported in FIDL. Change
    // when supported.
    /// All rights corresponding to r*.
    pub static ref READ_RIGHTS: fio::Operations =
        fio::Operations::CONNECT
        | fio::Operations::ENUMERATE
        | fio::Operations::TRAVERSE
        | fio::Operations::READ_BYTES
        | fio::Operations::GET_ATTRIBUTES;
    /// All rights corresponding to w*.
    pub static ref WRITE_RIGHTS: fio::Operations =
        fio::Operations::CONNECT
        | fio::Operations::ENUMERATE
        | fio::Operations::TRAVERSE
        | fio::Operations::WRITE_BYTES
        | fio::Operations::MODIFY_DIRECTORY
        | fio::Operations::UPDATE_ATTRIBUTES;
    /// All rights corresponding to x*.
    pub static ref EXECUTE_RIGHTS: fio::Operations =
        fio::Operations::CONNECT
        | fio::Operations::ENUMERATE
        | fio::Operations::TRAVERSE
        | fio::Operations::EXECUTE;
    /// All rights corresponding to rw*.
    pub static ref READ_WRITE_RIGHTS: fio::Operations =
        fio::Operations::CONNECT
        | fio::Operations::ENUMERATE
        | fio::Operations::TRAVERSE
        | fio::Operations::READ_BYTES
        | fio::Operations::WRITE_BYTES
        | fio::Operations::MODIFY_DIRECTORY
        | fio::Operations::GET_ATTRIBUTES
        | fio::Operations::UPDATE_ATTRIBUTES;

    /// All the fio rights required to represent fio::OpenFlags::RIGHT_READABLE.
    static ref LEGACY_READABLE_RIGHTS: fio::Operations =
        fio::Operations::READ_BYTES
        | fio::Operations::GET_ATTRIBUTES
        | fio::Operations::TRAVERSE
        | fio::Operations::ENUMERATE;
    /// All the fio rights required to represent fio::OpenFlags::RIGHT_WRITABLE.
    static ref LEGACY_WRITABLE_RIGHTS: fio::Operations =
        fio::Operations::WRITE_BYTES
        | fio::Operations::UPDATE_ATTRIBUTES
        | fio::Operations::MODIFY_DIRECTORY;
    /// All the fio rights required to represent fio::OpenFlags::RIGHT_EXECUTABLE.
    static ref LEGACY_EXECUTABLE_RIGHTS: fio::Operations = fio::Operations::EXECUTE;
}

/// Opaque rights type to define new traits like PartialOrd on.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Rights(fio::Operations);

impl Rights {
    /// Converts new fuchsia.io directory rights to legacy fuchsia.io compatible rights. This will
    /// be remove once new rights are supported by component manager.
    pub fn into_legacy(&self) -> fio::OpenFlags {
        let mut flags = fio::OpenFlags::empty();
        let Self(rights) = self;
        // The `intersects` below is intentional. The translation from io2 to io rights is lossy
        // in the sense that a single io2 right may require an io right with coarser permissions.
        if rights.intersects(*LEGACY_READABLE_RIGHTS) {
            flags |= fio::OpenFlags::RIGHT_READABLE;
        }
        if rights.intersects(*LEGACY_WRITABLE_RIGHTS) {
            flags |= fio::OpenFlags::RIGHT_WRITABLE;
        }
        if rights.contains(fio::Operations::EXECUTE) {
            flags |= fio::OpenFlags::RIGHT_EXECUTABLE;
        }
        // Since there is no direct translation for connect in CV1 we must explicitly define it
        // here as both flags.
        //
        // TODO(fxbug.dev/60673): Is this correct? ReadBytes | Connect seems like it should translate to
        // READABLE | WRITABLE, not empty rights.
        if flags.is_empty() && rights.contains(fio::Operations::CONNECT) {
            flags |= fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE;
        }
        flags
    }
}

/// Allows creating rights from fio::Operations.
impl From<fio::Operations> for Rights {
    fn from(operations: fio::Operations) -> Self {
        Rights(operations)
    }
}

impl WalkStateUnit for Rights {
    type Error = RightsRoutingError;

    /// Ensures the next walk state of rights satisfies a monotonic increasing sequence. Used to
    /// verify the expectation that no right requested from a use, offer, or expose is missing as
    /// capability routing walks from the capability's consumer to its provider.
    fn validate_next(&self, next_rights: &Rights) -> Result<(), Self::Error> {
        if next_rights.0.contains(self.0) {
            Ok(())
        } else {
            Err(RightsRoutingError::Invalid)
        }
    }

    fn finalize_error() -> Self::Error {
        RightsRoutingError::MissingRightsSource
    }
}

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

    #[test]
    fn validate_next() {
        assert_matches!(
            Rights::from(fio::Operations::empty())
                .validate_next(&Rights::from(*LEGACY_READABLE_RIGHTS)),
            Ok(())
        );
        assert_matches!(
            Rights::from(fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES)
                .validate_next(&Rights::from(*LEGACY_READABLE_RIGHTS)),
            Ok(())
        );
        assert_matches!(
            Rights::from(Rights::from(*LEGACY_READABLE_RIGHTS)).validate_next(&Rights::from(
                fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES
            )),
            Err(RightsRoutingError::Invalid)
        );
        assert_matches!(
            Rights::from(fio::Operations::WRITE_BYTES).validate_next(&Rights::from(
                fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES
            )),
            Err(RightsRoutingError::Invalid)
        );
    }

    #[test]
    fn into_legacy() {
        assert_eq!(
            Rights::from(*LEGACY_READABLE_RIGHTS).into_legacy(),
            fio::OpenFlags::RIGHT_READABLE
        );
        assert_eq!(
            Rights::from(*LEGACY_WRITABLE_RIGHTS).into_legacy(),
            fio::OpenFlags::RIGHT_WRITABLE
        );
        assert_eq!(
            Rights::from(*LEGACY_EXECUTABLE_RIGHTS).into_legacy(),
            fio::OpenFlags::RIGHT_EXECUTABLE
        );
        assert_eq!(
            Rights::from(*LEGACY_READABLE_RIGHTS | *LEGACY_WRITABLE_RIGHTS).into_legacy(),
            fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE
        );
        assert_eq!(
            Rights::from(
                *LEGACY_READABLE_RIGHTS | *LEGACY_WRITABLE_RIGHTS | *LEGACY_EXECUTABLE_RIGHTS
            )
            .into_legacy(),
            fio::OpenFlags::RIGHT_READABLE
                | fio::OpenFlags::RIGHT_WRITABLE
                | fio::OpenFlags::RIGHT_EXECUTABLE
        );
        assert_eq!(
            Rights::from(fio::Operations::READ_BYTES).into_legacy(),
            fio::OpenFlags::RIGHT_READABLE
        );
        assert_eq!(
            Rights::from(fio::Operations::GET_ATTRIBUTES).into_legacy(),
            fio::OpenFlags::RIGHT_READABLE
        );
        assert_eq!(
            Rights::from(fio::Operations::TRAVERSE).into_legacy(),
            fio::OpenFlags::RIGHT_READABLE
        );
        assert_eq!(
            Rights::from(fio::Operations::ENUMERATE).into_legacy(),
            fio::OpenFlags::RIGHT_READABLE
        );
        assert_eq!(
            Rights::from(fio::Operations::WRITE_BYTES).into_legacy(),
            fio::OpenFlags::RIGHT_WRITABLE
        );
        assert_eq!(
            Rights::from(fio::Operations::UPDATE_ATTRIBUTES).into_legacy(),
            fio::OpenFlags::RIGHT_WRITABLE
        );
        assert_eq!(
            Rights::from(fio::Operations::MODIFY_DIRECTORY).into_legacy(),
            fio::OpenFlags::RIGHT_WRITABLE
        );
    }
}
