///|
pub struct InvokeContract {
route : String
plugin : String
command : String
mode : CommandMode
affinity : CommandExecutionAffinity
permission : Permission
request_schema : IpcSchema
response_schema : IpcSchema
allowed_windows : Array[String]
allowed_origins : Array[String]
requires_registered_handler : Bool
registered : Bool
registered_mode : CommandMode?
registered_permission : Permission?
exposed : Bool
operation_scope_configured : Bool
operation_scope_required : Bool
problems : Array[String]
} derive(Debug, Eq)
///|
pub struct InvokeContractReport {
contracts : Array[InvokeContract]
undeclared_routes : Array[String]
duplicate_routes : Array[String]
problems : Array[String]
} derive(Debug, Eq)
///|
pub fn CommandRegistry::invoke_contracts(
self : CommandRegistry,
profile : SecurityProfile,
) -> Array[InvokeContract] {
profile
.command_manifest()
.entries()
.map(fn(entry) {
InvokeContract::from_entry(profile, entry, self.commands.get(entry.route()))
})
}
///|
pub fn CommandRegistry::invoke_contract(
self : CommandRegistry,
profile : SecurityProfile,
route : String,
) -> InvokeContract? {
for contract in self.invoke_contracts(profile) {
if contract.route() == route {
return Some(contract)
}
}
None
}
///|
pub fn CommandRegistry::invoke_contract_report(
self : CommandRegistry,
profile : SecurityProfile,
) -> InvokeContractReport {
InvokeContractReport::from_registry(self, profile)
}
///|
pub fn AppManager::invoke_contracts(self : AppManager) -> Array[InvokeContract] {
self.registry.invoke_contracts(self.security_profile())
}
///|
pub fn AppManager::invoke_contract_report(
self : AppManager,
) -> InvokeContractReport {
self.registry.invoke_contract_report(self.security_profile())
}
///|
fn InvokeContract::from_entry(
profile : SecurityProfile,
entry : CommandManifestEntry,
command : RegisteredCommand?,
) -> InvokeContract {
let problems : Array[String] = []
let requires_registered_handler = entry.mode().requires_registered_handler()
let registered = command is Some(_)
let operation_scope_configured = invoke_contract_operation_scope_configured(
profile, entry,
)
let mut registered_mode : CommandMode? = None
let mut registered_permission : Permission? = None
let mut operation_scope_required = false
if entry.allowed_windows().is_empty() {
problems.push(
"command has no capability grant for any window: \{entry.route()}",
)
}
for problem in entry.request_schema().validate() {
problems.push("request schema invalid for \{entry.route()}: \{problem}")
}
for problem in entry.response_schema().validate() {
problems.push("response schema invalid for \{entry.route()}: \{problem}")
}
match command {
None =>
if requires_registered_handler {
problems.push(
"command has no registered native handler: \{entry.route()}",
)
}
Some(command) => {
registered_mode = Some(command.mode())
registered_permission = Some(command.permission())
operation_scope_required = command.requires_operation_scope()
if command.mode() != entry.mode() {
problems.push(
"registered handler mode mismatch for \{entry.route()}: expected \{entry.mode().name()} got \{command.mode().name()}",
)
}
if command.permission() != entry.permission() {
problems.push(
"registered handler permission mismatch for \{entry.route()}: expected \{entry.permission().name()} got \{command.permission().name()}",
)
}
if operation_scope_configured && !operation_scope_required {
problems.push(
"command has scoped capability grants but registered handler does not resolve an operation scope: \{entry.route()}",
)
}
}
}
{
route: entry.route(),
plugin: entry.plugin(),
command: entry.command(),
mode: entry.mode(),
affinity: entry.affinity(),
permission: entry.permission(),
request_schema: entry.request_schema(),
response_schema: entry.response_schema(),
allowed_windows: entry.allowed_windows(),
allowed_origins: entry.allowed_origins(),
requires_registered_handler,
registered,
registered_mode,
registered_permission,
exposed: invoke_contract_exposed(profile, entry.route()),
operation_scope_configured,
operation_scope_required,
problems,
}
}
///|
pub fn InvokeContract::route(self : InvokeContract) -> String {
self.route
}
///|
pub fn InvokeContract::plugin(self : InvokeContract) -> String {
self.plugin
}
///|
pub fn InvokeContract::command(self : InvokeContract) -> String {
self.command
}
///|
pub fn InvokeContract::mode(self : InvokeContract) -> CommandMode {
self.mode
}
///|
pub fn InvokeContract::affinity(
self : InvokeContract,
) -> CommandExecutionAffinity {
self.affinity
}
///|
pub fn InvokeContract::permission(self : InvokeContract) -> Permission {
self.permission
}
///|
pub fn InvokeContract::request_schema(self : InvokeContract) -> IpcSchema {
self.request_schema
}
///|
pub fn InvokeContract::response_schema(self : InvokeContract) -> IpcSchema {
self.response_schema
}
///|
pub fn InvokeContract::allowed_windows(self : InvokeContract) -> Array[String] {
self.allowed_windows.copy()
}
///|
pub fn InvokeContract::allowed_origins(self : InvokeContract) -> Array[String] {
self.allowed_origins.copy()
}
///|
pub fn InvokeContract::requires_registered_handler(
self : InvokeContract,
) -> Bool {
self.requires_registered_handler
}
///|
pub fn InvokeContract::registered(self : InvokeContract) -> Bool {
self.registered
}
///|
pub fn InvokeContract::registered_mode(self : InvokeContract) -> CommandMode? {
self.registered_mode
}
///|
pub fn InvokeContract::registered_permission(
self : InvokeContract,
) -> Permission? {
self.registered_permission
}
///|
pub fn InvokeContract::exposed(self : InvokeContract) -> Bool {
self.exposed
}
///|
pub fn InvokeContract::operation_scope_configured(
self : InvokeContract,
) -> Bool {
self.operation_scope_configured
}
///|
pub fn InvokeContract::operation_scope_required(self : InvokeContract) -> Bool {
self.operation_scope_required
}
///|
pub fn InvokeContract::problems(self : InvokeContract) -> Array[String] {
self.problems.copy()
}
///|
pub fn InvokeContract::ok(self : InvokeContract) -> Bool {
self.problems.is_empty()
}
///|
pub fn InvokeContract::dispatchable(self : InvokeContract) -> Bool {
self.ok() &&
self.exposed &&
(!self.requires_registered_handler || self.registered)
}
///|
pub fn InvokeContract::to_json(self : InvokeContract) -> String {
[
"{",
"\"route\":\{self.route.json_string()},",
"\"plugin\":\{self.plugin.json_string()},",
"\"command\":\{self.command.json_string()},",
"\"mode\":\{self.mode.name().json_string()},",
"\"affinity\":\{self.affinity.name().json_string()},",
"\"permission\":\{self.permission.name().json_string()},",
"\"requestSchema\":\{self.request_schema.to_json()},",
"\"responseSchema\":\{self.response_schema.to_json()},",
"\"allowedWindows\":[\{self.allowed_windows.map(fn(window) { window.json_string() }).join(",")}],",
"\"allowedOrigins\":[\{self.allowed_origins.map(fn(origin) { origin.json_string() }).join(",")}],",
"\"requiresRegisteredHandler\":\{self.requires_registered_handler.json_bool()},",
"\"registered\":\{self.registered.json_bool()},",
"\"registeredMode\":\{invoke_contract_mode_json(self.registered_mode)},",
"\"registeredPermission\":\{invoke_contract_permission_json(self.registered_permission)},",
"\"exposed\":\{self.exposed.json_bool()},",
"\"operationScopeConfigured\":\{self.operation_scope_configured.json_bool()},",
"\"operationScopeRequired\":\{self.operation_scope_required.json_bool()},",
"\"ok\":\{self.ok().json_bool()},",
"\"dispatchable\":\{self.dispatchable().json_bool()},",
"\"problems\":[\{self.problems.map(fn(problem) { problem.json_string() }).join(",")}]",
"}",
].join("")
}
///|
fn InvokeContractReport::from_registry(
registry : CommandRegistry,
profile : SecurityProfile,
) -> InvokeContractReport {
let contracts = registry.invoke_contracts(profile)
let undeclared_routes : Array[String] = []
let problems : Array[String] = []
let declared_routes = profile.command_manifest().routes()
for route in registry.routes() {
if !declared_routes.contains(route) {
undeclared_routes.push(route)
invoke_contract_push_unique(
problems,
"registered handler is not declared in command manifest: \{route}",
)
}
}
for route in registry.duplicate_routes {
invoke_contract_push_unique(
problems,
"registered command route must be unique: \{route}",
)
}
for problem in registry.validate() {
invoke_contract_push_unique(problems, problem)
}
{
contracts,
undeclared_routes,
duplicate_routes: registry.duplicate_routes.copy(),
problems,
}
}
///|
pub fn InvokeContractReport::contracts(
self : InvokeContractReport,
) -> Array[InvokeContract] {
self.contracts.copy()
}
///|
pub fn InvokeContractReport::undeclared_routes(
self : InvokeContractReport,
) -> Array[String] {
self.undeclared_routes.copy()
}
///|
pub fn InvokeContractReport::duplicate_routes(
self : InvokeContractReport,
) -> Array[String] {
self.duplicate_routes.copy()
}
///|
pub fn InvokeContractReport::problems(
self : InvokeContractReport,
) -> Array[String] {
let problems = self.problems.copy()
for contract in self.contracts {
for problem in contract.problems() {
invoke_contract_push_unique(problems, problem)
}
}
problems
}
///|
pub fn InvokeContractReport::ok(self : InvokeContractReport) -> Bool {
self.problems.is_empty() && self.contracts.all(fn(contract) { contract.ok() })
}
///|
pub fn InvokeContractReport::dispatchable_routes(
self : InvokeContractReport,
) -> Array[String] {
self.contracts
.filter(fn(contract) { contract.dispatchable() })
.map(fn(contract) { contract.route() })
}
///|
pub fn InvokeContractReport::to_json(self : InvokeContractReport) -> String {
[
"{",
"\"ok\":\{self.ok().json_bool()},",
"\"dispatchableRoutes\":[\{self.dispatchable_routes().map(fn(route) { route.json_string() }).join(",")}],",
"\"undeclaredRoutes\":[\{self.undeclared_routes.map(fn(route) { route.json_string() }).join(",")}],",
"\"duplicateRoutes\":[\{self.duplicate_routes.map(fn(route) { route.json_string() }).join(",")}],",
"\"problems\":[\{self.problems().map(fn(problem) { problem.json_string() }).join(",")}],",
"\"contracts\":[\{self.contracts.map(fn(contract) { contract.to_json() }).join(",")}]",
"}",
].join("")
}
///|
fn invoke_contract_exposed(profile : SecurityProfile, route : String) -> Bool {
profile.exposed_routes().contains(route)
}
///|
fn invoke_contract_operation_scope_configured(
profile : SecurityProfile,
entry : CommandManifestEntry,
) -> Bool {
match profile.permission_manifest().permission(entry.permission().name()) {
Some(permission) =>
permission
.grants()
.any(fn(grant) { !grant.operation_scopes().is_empty() })
None => false
}
}
///|
fn invoke_contract_mode_json(mode : CommandMode?) -> String {
match mode {
Some(mode) => mode.name().json_string()
None => "null"
}
}
///|
fn invoke_contract_permission_json(permission : Permission?) -> String {
match permission {
Some(permission) => permission.name().json_string()
None => "null"
}
}
///|
fn invoke_contract_push_unique(values : Array[String], value : String) -> Unit {
if !values.contains(value) {
values.push(value)
}
}