///|
let application_permission_id = "app"
///|
fn resolve_window_permission_policy(
window_id : String,
policy : BridgePagePolicy,
manifest : @manifest.AppManifest,
permission_base_path : String,
command_extensions : Map[String, @proton_command.AppCommandExtensionSpec],
registered_ops : Array[String],
) -> WindowPermissionPolicy raise AppConfigurationError {
let grants : Array[ResolvedPermissionGrant] = []
let identities : Map[String, Unit] = Map([])
for configured in manifest.permission_grants() {
guard configured.window() == window_id else { continue }
let source_origin = permission_source_origin(configured.origin(), policy)
let extension_id = configured.extension()
let identity = source_origin + "\u{0}" + extension_id
guard !identities.contains(identity) else {
raise InvalidPermissionGrant(
detail="window " +
window_id +
" resolves more than one grant for " +
source_origin +
" and " +
extension_id,
)
}
let ops = permission_extension_ops(
extension_id, manifest, command_extensions, registered_ops,
)
let resolved_scope = resolve_permission_scope(
extension_id,
configured.scope(),
permission_base_path,
command_extensions,
)
guard ops.length() > 0 else {
raise InvalidPermissionGrant(
detail="extension " +
extension_id +
" does not own any registered operation",
)
}
identities[identity] = ()
grants.push(ResolvedPermissionGrant::{
source_origin,
extension_id,
ops,
scope: resolved_scope,
})
}
WindowPermissionPolicy::{ grants, }
}
///|
fn resolve_permission_scope(
extension_id : String,
scope : Json,
permission_base_path : String,
command_extensions : Map[String, @proton_command.AppCommandExtensionSpec],
) -> Json raise AppConfigurationError {
if extension_id == application_permission_id {
guard scope is Object(fields) else {
raise InvalidPermissionGrant(
detail="app permission scope must be an object",
)
}
for _, _ in fields {
raise InvalidPermissionGrant(
detail="app commands do not accept a permission scope",
)
}
return scope
}
let spec = match command_extensions.get(extension_id) {
Some(spec) => spec
None =>
raise InvalidPermissionGrant(
detail="extension " + extension_id + " is not registered",
)
}
spec.resolve_permission(scope, permission_base_path) catch {
error =>
raise InvalidPermissionGrant(
detail="extension " +
extension_id +
" rejected its permission scope: " +
error.message(),
)
}
}
///|
fn permission_source_origin(
origin : @manifest.PermissionOrigin,
policy : BridgePagePolicy,
) -> String {
match origin {
App => "app"
Entry =>
match policy.entry_origin {
Some(origin) => origin
None => "app"
}
}
}
///|
fn permission_extension_ops(
extension_id : String,
manifest : @manifest.AppManifest,
command_extensions : Map[String, @proton_command.AppCommandExtensionSpec],
registered_ops : Array[String],
) -> Array[String] raise AppConfigurationError {
if extension_id == application_permission_id {
let extension_ops : Map[String, Unit] = Map([])
for _, spec in command_extensions {
for op in spec.op_names() {
extension_ops[op] = ()
}
}
return registered_ops.filter(op => !extension_ops.contains(op))
}
match manifest.extension_setting(extension_id) {
Some(setting) if setting.is_enabled() => ()
Some(_) =>
raise InvalidPermissionGrant(
detail="extension " + extension_id + " is disabled",
)
None =>
raise InvalidPermissionGrant(
detail="extension " + extension_id + " is not enabled",
)
}
match command_extensions.get(extension_id) {
Some(spec) => spec.op_names()
None =>
raise InvalidPermissionGrant(
detail="extension " + extension_id + " is not registered",
)
}
}
///|
fn validate_registered_capabilities_have_grants(
manifest : @manifest.AppManifest,
command_extensions : Map[String, @proton_command.AppCommandExtensionSpec],
registered_ops : Array[String],
) -> Unit raise AppConfigurationError {
let window_ids : Map[String, Unit] = { "main": () }
for window in manifest.windows {
window_ids[window.id] = ()
}
let granted : Map[String, Unit] = Map([])
for grant in manifest.permission_grants() {
guard window_ids.contains(grant.window()) else {
raise InvalidPermissionGrant(
detail="permission references unknown window " + grant.window(),
)
}
granted[grant.extension()] = ()
}
let app_ops = permission_extension_ops(
application_permission_id, manifest, command_extensions, registered_ops,
)
if app_ops.length() > 0 && !granted.contains(application_permission_id) {
raise MissingPermissionGrant(extension_id=application_permission_id)
}
for id in enabled_command_extension_order(manifest, command_extensions) {
if !granted.contains(id) {
raise MissingPermissionGrant(extension_id=id)
}
}
}
///|
fn WindowPermissionPolicy::native_grants(
self : WindowPermissionPolicy,
command_extensions : Map[String, @proton_command.AppCommandExtensionSpec],
) -> Array[@native.BridgeGrantConfig] raise AppConfigurationError {
let source_order : Array[String] = []
for grant in self.grants {
if !source_order.contains(grant.source_origin) {
source_order.push(grant.source_origin)
}
}
let native_grants : Array[@native.BridgeGrantConfig] = []
for source_origin in source_order {
let ops : Array[String] = []
let extensions : Array[@native.BridgeExtensionConfig] = []
let initialization_units : Array[@native.BridgeInitializationUnit] = []
for grant in self.grants {
guard grant.source_origin == source_origin else { continue }
for op in grant.ops {
ops.push(op)
}
guard grant.extension_id != application_permission_id else { continue }
let frontend = bridge_frontend_config_for_extension(
grant.extension_id,
command_extensions[grant.extension_id],
)
for extension in frontend.extensions {
extensions.push(extension)
}
for unit in frontend.initialization_units {
initialization_units.push(unit)
}
}
native_grants.push(
@native.BridgeGrantConfig::new(
source_origin,
ops~,
extensions~,
initialization_units~,
),
)
}
native_grants
}
///|
fn WindowPermissionPolicy::grant_for_request(
self : WindowPermissionPolicy,
source_origin : String,
op : String,
) -> ResolvedPermissionGrant? {
for grant in self.grants {
if grant.source_origin == source_origin && grant.ops.contains(op) {
return Some(grant)
}
}
None
}