From b87161ceb8d02fcd5f8e15155c5b722be60cbe08 Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Sun, 14 Jul 2024 21:43:52 -0700 Subject: [PATCH] Use external plugin adapter authority to validate --- .../src/plugins/external_plugin_adapters.rs | 48 ++++++++++ programs/mpl-core/src/processor/burn.rs | 2 +- .../update_external_plugin_adapter.rs | 92 ++++++++++--------- programs/mpl-core/src/state/asset.rs | 10 +- programs/mpl-core/src/state/collection.rs | 10 +- 5 files changed, 106 insertions(+), 56 deletions(-) diff --git a/programs/mpl-core/src/plugins/external_plugin_adapters.rs b/programs/mpl-core/src/plugins/external_plugin_adapters.rs index ceb25fb4..d4ba7828 100644 --- a/programs/mpl-core/src/plugins/external_plugin_adapters.rs +++ b/programs/mpl-core/src/plugins/external_plugin_adapters.rs @@ -7,6 +7,7 @@ use strum::EnumCount; use crate::{ error::MplCoreError, + plugins::lifecycle::{approve, reject}, state::{AssetV1, SolanaAccount}, }; @@ -198,6 +199,53 @@ impl ExternalPluginAdapter { } } + /// Validate the add external plugin adapter lifecycle event. + pub(crate) fn validate_update_external_plugin_adapter( + external_plugin_adapter: &ExternalPluginAdapter, + ctx: &PluginValidationContext, + ) -> Result { + let resolved_authorities = ctx + .resolved_authorities + .ok_or(MplCoreError::InvalidAuthority)?; + let base_result = if resolved_authorities.contains(ctx.self_authority) { + solana_program::msg!("Base: Approved"); + ValidationResult::Approved + } else { + ValidationResult::Pass + }; + + let result = match external_plugin_adapter { + ExternalPluginAdapter::LifecycleHook(lifecycle_hook) => { + lifecycle_hook.validate_update_external_plugin_adapter(ctx) + } + ExternalPluginAdapter::Oracle(oracle) => { + oracle.validate_update_external_plugin_adapter(ctx) + } + ExternalPluginAdapter::DataStore(app_data) => { + app_data.validate_update_external_plugin_adapter(ctx) + } + }?; + + match (&base_result, &result) { + (ValidationResult::Approved, ValidationResult::Approved) => { + approve!() + } + (ValidationResult::Approved, ValidationResult::Rejected) => { + reject!() + } + (ValidationResult::Rejected, ValidationResult::Approved) => { + reject!() + } + (ValidationResult::Rejected, ValidationResult::Rejected) => { + reject!() + } + (ValidationResult::Pass, _) => Ok(result), + (ValidationResult::ForceApproved, _) => unreachable!(), + (_, ValidationResult::Pass) => Ok(base_result), + (_, ValidationResult::ForceApproved) => unreachable!(), + } + } + /// Load and deserialize a plugin from an offset in the account. pub fn load(account: &AccountInfo, offset: usize) -> Result { let mut bytes: &[u8] = &(*account.data).borrow()[offset..]; diff --git a/programs/mpl-core/src/processor/burn.rs b/programs/mpl-core/src/processor/burn.rs index 98dae2c1..0a125d3f 100644 --- a/programs/mpl-core/src/processor/burn.rs +++ b/programs/mpl-core/src/processor/burn.rs @@ -9,7 +9,7 @@ use crate::{ state::{AssetV1, CollectionV1, CompressionProof, Key, SolanaAccount, Wrappable}, utils::{ close_program_account, load_key, rebuild_account_state_from_proof_data, resolve_authority, - validate_asset_permissions, validate_collection_permissions, verify_proof, + validate_asset_permissions, verify_proof, }, }; diff --git a/programs/mpl-core/src/processor/update_external_plugin_adapter.rs b/programs/mpl-core/src/processor/update_external_plugin_adapter.rs index 3cafc18f..100de6ef 100644 --- a/programs/mpl-core/src/processor/update_external_plugin_adapter.rs +++ b/programs/mpl-core/src/processor/update_external_plugin_adapter.rs @@ -11,13 +11,13 @@ use crate::{ }, plugins::{ fetch_wrapped_external_plugin_adapter, find_external_plugin_adapter, ExternalPluginAdapter, - ExternalPluginAdapterKey, ExternalPluginAdapterUpdateInfo, Plugin, PluginHeaderV1, - PluginRegistryV1, PluginType, + ExternalPluginAdapterKey, ExternalPluginAdapterUpdateInfo, PluginHeaderV1, + PluginRegistryV1, PluginValidationContext, ValidationResult, }, state::{AssetV1, CollectionV1, DataBlob, Key, SolanaAccount}, utils::{ - load_key, resize_or_reallocate_account, resolve_authority, validate_asset_permissions, - validate_collection_permissions, + fetch_core_data, load_key, resize_or_reallocate_account, resolve_authority, + resolve_pubkey_to_authorities, resolve_pubkey_to_authorities_collection, }, }; @@ -56,33 +56,38 @@ pub(crate) fn update_external_plugin_adapter<'a>( return Err(MplCoreError::NotAvailable.into()); } - let (_, plugin) = + let (mut asset, plugin_header, plugin_registry) = + fetch_core_data::(ctx.accounts.asset)?; + let resolved_authorities = + resolve_pubkey_to_authorities(authority, ctx.accounts.collection, &asset)?; + let (external_registry_record_authority, external_plugin_adapter) = fetch_wrapped_external_plugin_adapter::(ctx.accounts.asset, None, &args.key)?; - let (mut asset, plugin_header, plugin_registry) = validate_asset_permissions( + let validation_ctx = PluginValidationContext { accounts, - authority, - ctx.accounts.asset, - ctx.accounts.collection, - None, - None, - Some(&plugin), - AssetV1::check_update_external_plugin_adapter, - CollectionV1::check_update_external_plugin_adapter, - PluginType::check_update_external_plugin_adapter, - AssetV1::validate_update_external_plugin_adapter, - CollectionV1::validate_update_external_plugin_adapter, - Plugin::validate_update_external_plugin_adapter, - None, - None, - )?; + asset_info: Some(ctx.accounts.asset), + collection_info: ctx.accounts.collection, + self_authority: &external_registry_record_authority, + authority_info: authority, + resolved_authorities: Some(&resolved_authorities), + new_owner: None, + target_plugin: None, + }; + + if ExternalPluginAdapter::validate_update_external_plugin_adapter( + &external_plugin_adapter, + &validation_ctx, + )? != ValidationResult::Approved + { + return Err(MplCoreError::InvalidAuthority.into()); + } // Increment sequence number and save only if it is `Some(_)`. asset.increment_seq_and_save(ctx.accounts.asset)?; process_update_external_plugin_adapter( asset, - plugin, + external_plugin_adapter, args.key, args.update_info, plugin_header, @@ -123,30 +128,35 @@ pub(crate) fn update_collection_external_plugin_adapter<'a>( } } - let (_, plugin) = fetch_wrapped_external_plugin_adapter::( - ctx.accounts.collection, - None, - &args.key, - )?; + let (collection, plugin_header, plugin_registry) = + fetch_core_data::(ctx.accounts.collection)?; + let resolved_authorities = + resolve_pubkey_to_authorities_collection(authority, ctx.accounts.collection)?; + let (external_registry_record_authority, external_plugin_adapter) = + fetch_wrapped_external_plugin_adapter::(ctx.accounts.collection, None, &args.key)?; - // Validate collection permissions. - let (collection, plugin_header, plugin_registry) = validate_collection_permissions( + let validation_ctx = PluginValidationContext { accounts, - authority, - ctx.accounts.collection, - None, - Some(&plugin), - CollectionV1::check_update_external_plugin_adapter, - PluginType::check_update_external_plugin_adapter, - CollectionV1::validate_update_external_plugin_adapter, - Plugin::validate_update_external_plugin_adapter, - None, - None, - )?; + asset_info: None, + collection_info: Some(ctx.accounts.collection), + self_authority: &external_registry_record_authority, + authority_info: authority, + resolved_authorities: Some(&resolved_authorities), + new_owner: None, + target_plugin: None, + }; + + if ExternalPluginAdapter::validate_update_external_plugin_adapter( + &external_plugin_adapter, + &validation_ctx, + )? != ValidationResult::Approved + { + return Err(MplCoreError::InvalidAuthority.into()); + } process_update_external_plugin_adapter( collection, - plugin, + external_plugin_adapter, args.key, args.update_info, plugin_header, diff --git a/programs/mpl-core/src/state/asset.rs b/programs/mpl-core/src/state/asset.rs index 44655511..fac6b655 100644 --- a/programs/mpl-core/src/state/asset.rs +++ b/programs/mpl-core/src/state/asset.rs @@ -125,7 +125,7 @@ impl AssetV1 { /// Check permissions for the update external plugin adapter lifecycle event. pub fn check_update_external_plugin_adapter() -> CheckResult { - CheckResult::CanApprove + CheckResult::None } /// Validate the add plugin lifecycle event. @@ -328,15 +328,11 @@ impl AssetV1 { /// Validate the update external plugin adapter lifecycle event. pub fn validate_update_external_plugin_adapter( &self, - authority_info: &AccountInfo, + _authority_info: &AccountInfo, _: Option<&Plugin>, _plugin: Option<&ExternalPluginAdapter>, ) -> Result { - if self.update_authority == UpdateAuthority::Address(*authority_info.key) { - approve!() - } else { - abstain!() - } + abstain!() } } diff --git a/programs/mpl-core/src/state/collection.rs b/programs/mpl-core/src/state/collection.rs index c4056576..18803383 100644 --- a/programs/mpl-core/src/state/collection.rs +++ b/programs/mpl-core/src/state/collection.rs @@ -110,7 +110,7 @@ impl CollectionV1 { /// Check permissions for the update external plugin adapter lifecycle event. pub fn check_update_external_plugin_adapter() -> CheckResult { - CheckResult::CanApprove + CheckResult::None } /// Validate the add plugin lifecycle event. @@ -293,15 +293,11 @@ impl CollectionV1 { /// Validate the update external plugin adapter lifecycle event. pub fn validate_update_external_plugin_adapter( &self, - authority_info: &AccountInfo, + _authority_info: &AccountInfo, _: Option<&Plugin>, _plugin: Option<&ExternalPluginAdapter>, ) -> Result { - if self.update_authority == *authority_info.key { - approve!() - } else { - abstain!() - } + abstain!() } /// Increment size of the Collection