diff --git a/nuxt.config.ts b/nuxt.config.ts index 4953280..babc32a 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -1,4 +1,4 @@ -import tailwindcss from '@tailwindcss/vite' +//import tailwindcss from '@tailwindcss/vite' // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ @@ -99,7 +99,7 @@ export default defineNuxtConfig({ }, vite: { - plugins: [tailwindcss()], + //plugins: [tailwindcss()], // Better support for Tauri CLI output clearScreen: false, // Enable environment variables diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 759a0f2..609aa93 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -17,6 +17,17 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -62,6 +73,15 @@ version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "ashpd" version = "0.11.0" @@ -274,6 +294,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + [[package]] name = "bincode" version = "1.3.3" @@ -386,6 +412,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bzip2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea8dcd42434048e4f7a304411d9273a411f647446c1234a65ce0554923f4cff" +dependencies = [ + "libbz2-rs-sys", +] + [[package]] name = "cairo-rs" version = "0.18.5" @@ -440,7 +475,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -459,6 +494,8 @@ version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -514,6 +551,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "combine" version = "4.6.7" @@ -533,6 +580,18 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "convert_case" version = "0.4.0" @@ -627,6 +686,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.4.2" @@ -698,6 +772,33 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "darling" version = "0.20.10" @@ -739,6 +840,22 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +[[package]] +name = "deflate64" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "deranged" version = "0.4.0" @@ -749,6 +866,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "derive_more" version = "0.99.19" @@ -770,6 +898,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -890,6 +1019,30 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + [[package]] name = "embed-resource" version = "3.0.2" @@ -1020,6 +1173,12 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "field-offset" version = "0.3.6" @@ -1032,11 +1191,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", + "libz-rs-sys", "miniz_oxide", ] @@ -1081,9 +1241,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -1533,6 +1693,7 @@ name = "haex-hub" version = "0.1.0" dependencies = [ "base64 0.22.1", + "ed25519-dalek", "fs_extra", "hex", "mime", @@ -1540,10 +1701,10 @@ dependencies = [ "rusqlite", "serde", "serde_json", + "sha2", "sqlparser", "tauri", "tauri-build", - "tauri-plugin-android-fs", "tauri-plugin-dialog", "tauri-plugin-fs", "tauri-plugin-http", @@ -1552,11 +1713,12 @@ dependencies = [ "tauri-plugin-os", "tauri-plugin-persisted-scope", "tauri-plugin-store", - "thiserror 2.0.16", - "tokio", + "thiserror 2.0.17", "ts-rs", "uhlc", + "url", "uuid", + "zip", ] [[package]] @@ -1607,6 +1769,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "html5ever" version = "0.29.1" @@ -1887,9 +2058,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1937,6 +2108,15 @@ dependencies = [ "cfb", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "io-uring" version = "0.7.8" @@ -2024,6 +2204,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.2", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -2109,6 +2299,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "libbz2-rs-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7" + [[package]] name = "libc" version = "0.2.175" @@ -2147,6 +2343,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-rs-sys" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd" +dependencies = [ + "zlib-rs", +] + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -2187,6 +2392,16 @@ version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +[[package]] +name = "lzma-rust2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c60a23ffb90d527e23192f1246b14746e2f7f071cb84476dd879071696c18a4a" +dependencies = [ + "crc", + "sha2", +] + [[package]] name = "mac" version = "0.1.1" @@ -2305,7 +2520,7 @@ dependencies = [ "once_cell", "png", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "windows-sys 0.59.0", ] @@ -2775,10 +2990,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] -name = "percent-encoding" -version = "2.3.1" +name = "pbkdf2" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" @@ -2937,6 +3162,16 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.32" @@ -2990,6 +3225,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppmd-rust" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c834641d8ad1b348c9ee86dec3b9840d805acd5f24daa5f90c788951a52ff59b" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -3129,7 +3370,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2 0.5.8", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -3149,7 +3390,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.16", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -3338,7 +3579,7 @@ checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3646,9 +3887,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -3667,18 +3908,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -3813,10 +4054,21 @@ dependencies = [ ] [[package]] -name = "sha2" -version = "0.10.8" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -3838,6 +4090,15 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -3946,10 +4207,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" [[package]] -name = "sqlparser" -version = "0.58.0" +name = "spki" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4b661c54b1e4b603b37873a18c59920e4c51ea8ea2cf527d925424dbd4437c" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlparser" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4591acadbcf52f0af60eafbb2c003232b2b4cd8de5f0e9437cb8b1b59046cc0f" dependencies = [ "log", "recursive", @@ -4224,7 +4495,7 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tray-icon", "url", @@ -4277,7 +4548,7 @@ dependencies = [ "sha2", "syn 2.0.100", "tauri-utils", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "url", "uuid", @@ -4315,21 +4586,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "tauri-plugin-android-fs" -version = "12.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1387b55109ae9b8ad0521ac11f8ce827740f53c0e0ce74648d1cb2efe0fd9c09" -dependencies = [ - "percent-encoding", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-plugin-fs", - "thiserror 2.0.16", -] - [[package]] name = "tauri-plugin-dialog" version = "2.4.0" @@ -4344,7 +4600,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", ] @@ -4365,7 +4621,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.16", + "thiserror 2.0.17", "toml 0.9.5", "url", ] @@ -4388,7 +4644,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "url", "urlpattern", @@ -4408,7 +4664,7 @@ dependencies = [ "serde_repr", "tauri", "tauri-plugin", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "url", ] @@ -4429,7 +4685,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", "windows", "zbus", @@ -4450,7 +4706,7 @@ dependencies = [ "sys-locale", "tauri", "tauri-plugin", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4466,7 +4722,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin-fs", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4480,7 +4736,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", ] @@ -4503,7 +4759,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", "webkit2gtk", "webview2-com", @@ -4567,7 +4823,7 @@ dependencies = [ "serde_json", "serde_with", "swift-rs", - "thiserror 2.0.16", + "thiserror 2.0.17", "toml 0.9.5", "url", "urlpattern", @@ -4592,7 +4848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9" dependencies = [ "quick-xml 0.37.5", - "thiserror 2.0.16", + "thiserror 2.0.17", "windows", "windows-version", ] @@ -4641,11 +4897,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -4661,9 +4917,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -4951,7 +5207,7 @@ dependencies = [ "once_cell", "png", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "windows-sys 0.59.0", ] @@ -4967,7 +5223,7 @@ version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ef1b7a6d914a34127ed8e1fa927eb7088903787bcded4fa3eef8f85ee1568be" dependencies = [ - "thiserror 2.0.16", + "thiserror 2.0.17", "ts-rs-macros", ] @@ -5087,9 +5343,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", @@ -5405,7 +5661,7 @@ version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" dependencies = [ - "thiserror 2.0.16", + "thiserror 2.0.17", "windows", "windows-core 0.61.0", ] @@ -5965,7 +6221,7 @@ dependencies = [ "sha2", "soup3", "tao-macros", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", "webkit2gtk", "webkit2gtk-sys", @@ -6128,6 +6384,20 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] [[package]] name = "zerovec" @@ -6151,6 +6421,79 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "zip" +version = "5.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f852905151ac8d4d06fdca66520a661c09730a74c6d4e2b0f27b436b382e532" +dependencies = [ + "aes", + "arbitrary", + "bzip2", + "constant_time_eq", + "crc32fast", + "deflate64", + "flate2", + "getrandom 0.3.2", + "hmac", + "indexmap 2.8.0", + "lzma-rust2", + "memchr", + "pbkdf2", + "ppmd-rust", + "sha1", + "time", + "zeroize", + "zopfli", + "zstd", +] + +[[package]] +name = "zlib-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" + +[[package]] +name = "zopfli" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "zvariant" version = "5.7.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 290fa46..ddb382d 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -18,37 +18,38 @@ crate-type = ["staticlib", "cdylib", "rlib"] serde_json = "1.0.145" tauri-build = { version = "2.2", features = [] } -serde = { version = "1.0.226", features = ["derive"] } +serde = { version = "1.0.228", features = ["derive"] } [dependencies] rusqlite = { version = "0.37.0", features = [ "load_extension", "bundled-sqlcipher-vendored-openssl", "functions", ] } -#libsqlite3-sys = { version = "0.31", features = ["bundled-sqlcipher"] } + +#tauri-plugin-sql = { version = "2", features = ["sqlite"] }tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }#libsqlite3-sys = { version = "0.31", features = ["bundled-sqlcipher"] } #sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite"] } -tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] } -serde = { version = "1", features = ["derive"] } -hex = "0.4" -serde_json = "1.0.143" base64 = "0.22" -mime_guess = "2.0" -mime = "0.3" +ed25519-dalek = "2.1" fs_extra = "1.3.0" -sqlparser = { version = "0.58.0", features = ["visitor"] } -uhlc = "0.8" +hex = "0.4" +mime = "0.3" +mime_guess = "2.0" +serde = { version = "1", features = ["derive"] } +serde_json = "1.0.143" +sha2 = "0.10.9" +sqlparser = { version = "0.59.0", features = ["visitor"] } tauri = { version = "2.8.5", features = ["protocol-asset", "devtools"] } tauri-plugin-dialog = "2.4.0" tauri-plugin-fs = "2.4.0" -tauri-plugin-opener = "2.5.0" -tauri-plugin-os = "2.3" -tauri-plugin-store = "2.4.0" tauri-plugin-http = "2.5.2" tauri-plugin-notification = "2.3.1" +tauri-plugin-opener = "2.5.0" +tauri-plugin-os = "2.3" tauri-plugin-persisted-scope = "2.3.2" -tauri-plugin-android-fs = "12.0.1" -uuid = { version = "1.18.1", features = ["v4"] } +tauri-plugin-store = "2.4.0" +thiserror = "2.0.17" ts-rs = "11.0.1" -thiserror = "2.0.16" - -#tauri-plugin-sql = { version = "2", features = ["sqlite"] } +uhlc = "0.8" +uuid = { version = "1.18.1", features = ["v4"] } +zip = "5.1.1" +url = "2.5.7" diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 2df7842..cb47365 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -25,7 +25,6 @@ "fs:allow-download-read-recursive", "fs:allow-download-write-recursive", "fs:default", - "android-fs:default", { "identifier": "fs:scope", "allow": [{ "path": "**" }] diff --git a/src-tauri/database/index.ts b/src-tauri/database/index.ts index 3414ad1..26550f6 100644 --- a/src-tauri/database/index.ts +++ b/src-tauri/database/index.ts @@ -1,5 +1,5 @@ import { drizzle } from 'drizzle-orm/sqlite-proxy' // Adapter für Query Building ohne direkte Verbindung -import * as schema from './schemas/vault' // Importiere alles aus deiner Schema-Datei +import * as schema from './schemas/haex' // Importiere alles aus deiner Schema-Datei // sqlite-proxy benötigt eine (dummy) Ausführungsfunktion als Argument. // Diese wird in unserem Tauri-Workflow nie aufgerufen, da wir nur .toSQL() verwenden. diff --git a/src-tauri/database/migrations/0012_special_gwen_stacy.sql b/src-tauri/database/migrations/0012_special_gwen_stacy.sql new file mode 100644 index 0000000..5a78073 --- /dev/null +++ b/src-tauri/database/migrations/0012_special_gwen_stacy.sql @@ -0,0 +1,15 @@ +ALTER TABLE `haex_extension_permissions` RENAME COLUMN "resource" TO "resource_type";--> statement-breakpoint +ALTER TABLE `haex_extension_permissions` RENAME COLUMN "operation" TO "action";--> statement-breakpoint +ALTER TABLE `haex_extension_permissions` RENAME COLUMN "path" TO "target";--> statement-breakpoint +DROP INDEX `haex_extension_permissions_extension_id_resource_operation_path_unique`;--> statement-breakpoint +ALTER TABLE `haex_extension_permissions` ADD `constraints` text;--> statement-breakpoint +ALTER TABLE `haex_extension_permissions` ADD `status` text DEFAULT 'denied' NOT NULL;--> statement-breakpoint +ALTER TABLE `haex_extension_permissions` ADD `haex_timestamp` text;--> statement-breakpoint +CREATE UNIQUE INDEX `haex_extension_permissions_extension_id_resource_type_action_target_unique` ON `haex_extension_permissions` (`extension_id`,`resource_type`,`action`,`target`);--> statement-breakpoint +ALTER TABLE `haex_extensions` ADD `description` text;--> statement-breakpoint +ALTER TABLE `haex_extensions` ADD `entry` text;--> statement-breakpoint +ALTER TABLE `haex_extensions` ADD `homepage` text;--> statement-breakpoint +ALTER TABLE `haex_extensions` ADD `public_key` text;--> statement-breakpoint +ALTER TABLE `haex_extensions` ADD `signature` text;--> statement-breakpoint +ALTER TABLE `haex_extensions` ADD `haex_timestamp` text;--> statement-breakpoint +ALTER TABLE `haex_settings` ADD `haex_timestamp` text; \ No newline at end of file diff --git a/src-tauri/database/migrations/meta/0012_snapshot.json b/src-tauri/database/migrations/meta/0012_snapshot.json new file mode 100644 index 0000000..c580a7a --- /dev/null +++ b/src-tauri/database/migrations/meta/0012_snapshot.json @@ -0,0 +1,900 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "e4f45178-afcf-46e9-9a07-79b7bca88d88", + "prevId": "c8c0825d-c435-4a42-986a-a4f70e7f9e8b", + "tables": { + "haex_crdt_configs": { + "name": "haex_crdt_configs", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_crdt_logs": { + "name": "haex_crdt_logs", + "columns": { + "hlc_timestamp": { + "name": "hlc_timestamp", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "table_name": { + "name": "table_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "row_pks": { + "name": "row_pks", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "op_type": { + "name": "op_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_name": { + "name": "column_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "new_value": { + "name": "new_value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "old_value": { + "name": "old_value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_crdt_snapshots": { + "name": "haex_crdt_snapshots", + "columns": { + "snapshot_id": { + "name": "snapshot_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "created": { + "name": "created", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "epoch_hlc": { + "name": "epoch_hlc", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "location_url": { + "name": "location_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "file_size_bytes": { + "name": "file_size_bytes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_extension_permissions": { + "name": "haex_extension_permissions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "extension_id": { + "name": "extension_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "constraints": { + "name": "constraints", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'denied'" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haex_tombstone": { + "name": "haex_tombstone", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haex_timestamp": { + "name": "haex_timestamp", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "haex_extension_permissions_extension_id_resource_type_action_target_unique": { + "name": "haex_extension_permissions_extension_id_resource_type_action_target_unique", + "columns": [ + "extension_id", + "resource_type", + "action", + "target" + ], + "isUnique": true + } + }, + "foreignKeys": { + "haex_extension_permissions_extension_id_haex_extensions_id_fk": { + "name": "haex_extension_permissions_extension_id_haex_extensions_id_fk", + "tableFrom": "haex_extension_permissions", + "tableTo": "haex_extensions", + "columnsFrom": [ + "extension_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_extensions": { + "name": "haex_extensions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "entry": { + "name": "entry", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "homepage": { + "name": "homepage", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signature": { + "name": "signature", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haex_tombstone": { + "name": "haex_tombstone", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haex_timestamp": { + "name": "haex_timestamp", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_settings": { + "name": "haex_settings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haex_tombstone": { + "name": "haex_tombstone", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haex_timestamp": { + "name": "haex_timestamp", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_notifications": { + "name": "haex_notifications", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "alt": { + "name": "alt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "read": { + "name": "read", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "text": { + "name": "text", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "haex_tombstone": { + "name": "haex_tombstone", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_passwords_group_items": { + "name": "haex_passwords_group_items", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haex_tombstone": { + "name": "haex_tombstone", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": { + "name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk", + "tableFrom": "haex_passwords_group_items", + "tableTo": "haex_passwords_groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": { + "name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk", + "tableFrom": "haex_passwords_group_items", + "tableTo": "haex_passwords_item_details", + "columnsFrom": [ + "item_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "haex_passwords_group_items_item_id_group_id_pk": { + "columns": [ + "item_id", + "group_id" + ], + "name": "haex_passwords_group_items_item_id_group_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_passwords_groups": { + "name": "haex_passwords_groups", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haex_tombstone": { + "name": "haex_tombstone", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": { + "name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk", + "tableFrom": "haex_passwords_groups", + "tableTo": "haex_passwords_groups", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_passwords_item_details": { + "name": "haex_passwords_item_details", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haex_tombstone": { + "name": "haex_tombstone", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_passwords_item_history": { + "name": "haex_passwords_item_history", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "changed_property": { + "name": "changed_property", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "old_value": { + "name": "old_value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "new_value": { + "name": "new_value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "haex_tombstone": { + "name": "haex_tombstone", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": { + "name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk", + "tableFrom": "haex_passwords_item_history", + "tableTo": "haex_passwords_item_details", + "columnsFrom": [ + "item_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "haex_passwords_item_key_values": { + "name": "haex_passwords_item_key_values", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haex_tombstone": { + "name": "haex_tombstone", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": { + "name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk", + "tableFrom": "haex_passwords_item_key_values", + "tableTo": "haex_passwords_item_details", + "columnsFrom": [ + "item_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": { + "\"haex_extension_permissions\".\"resource\"": "\"haex_extension_permissions\".\"resource_type\"", + "\"haex_extension_permissions\".\"operation\"": "\"haex_extension_permissions\".\"action\"", + "\"haex_extension_permissions\".\"path\"": "\"haex_extension_permissions\".\"target\"" + } + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/src-tauri/database/migrations/meta/_journal.json b/src-tauri/database/migrations/meta/_journal.json index a77ec49..116cd06 100644 --- a/src-tauri/database/migrations/meta/_journal.json +++ b/src-tauri/database/migrations/meta/_journal.json @@ -85,6 +85,13 @@ "when": 1757968140525, "tag": "0011_illegal_thor_girl", "breakpoints": true + }, + { + "idx": 12, + "version": "6", + "when": 1759362109283, + "tag": "0012_special_gwen_stacy", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src-tauri/database/schemas/haex.ts b/src-tauri/database/schemas/haex.ts new file mode 100644 index 0000000..2dd11aa --- /dev/null +++ b/src-tauri/database/schemas/haex.ts @@ -0,0 +1,76 @@ +import { sql } from 'drizzle-orm' +import { + integer, + sqliteTable, + text, + unique, + type AnySQLiteColumn, +} from 'drizzle-orm/sqlite-core' +import tableNames from '../tableNames.json' + +export const haexSettings = sqliteTable(tableNames.haex.settings, { + id: text().primaryKey(), + key: text(), + type: text(), + value: text(), + haex_tombstone: integer({ mode: 'boolean' }), + haex_timestamp: text(), +}) +export type InsertHaexSettings = typeof haexSettings.$inferInsert +export type SelectHaexSettings = typeof haexSettings.$inferSelect + +export const haexExtensions = sqliteTable(tableNames.haex.extensions, { + id: text().primaryKey(), + author: text(), + description: text(), + entry: text(), + homepage: text(), + enabled: integer({ mode: 'boolean' }), + icon: text(), + name: text(), + public_key: text(), + signature: text(), + url: text(), + version: text(), + haex_tombstone: integer({ mode: 'boolean' }), + haex_timestamp: text(), +}) +export type InsertHaexExtensions = typeof haexExtensions.$inferInsert +export type SelectHaexExtensions = typeof haexExtensions.$inferSelect + +export const haexExtensionPermissions = sqliteTable( + tableNames.haex.extension_permissions, + { + id: text().primaryKey(), + extensionId: text('extension_id').references( + (): AnySQLiteColumn => haexExtensions.id, + ), + resourceType: text('resource_type', { + enum: ['fs', 'http', 'db', 'shell'], + }), + action: text({ enum: ['read', 'write'] }), + target: text(), + constraints: text({ mode: 'json' }), + status: text({ enum: ['ask', 'granted', 'denied'] }) + .notNull() + .default('denied'), + createdAt: text('created_at').default(sql`(CURRENT_TIMESTAMP)`), + updateAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate( + () => new Date(), + ), + haexTombstone: integer('haex_tombstone', { mode: 'boolean' }), + haexTimestamp: text('haex_timestamp'), + }, + (table) => [ + unique().on( + table.extensionId, + table.resourceType, + table.action, + table.target, + ), + ], +) +export type InserthaexExtensionPermissions = + typeof haexExtensionPermissions.$inferInsert +export type SelecthaexExtensionPermissions = + typeof haexExtensionPermissions.$inferSelect diff --git a/src-tauri/database/schemas/vault.ts b/src-tauri/database/schemas/vault.ts index bf2f301..4971aed 100644 --- a/src-tauri/database/schemas/vault.ts +++ b/src-tauri/database/schemas/vault.ts @@ -4,59 +4,10 @@ import { primaryKey, sqliteTable, text, - unique, type AnySQLiteColumn, } from 'drizzle-orm/sqlite-core' import tableNames from '../tableNames.json' -export const haexSettings = sqliteTable(tableNames.haex.settings, { - id: text().primaryKey(), - key: text(), - type: text(), - value: text(), - haex_tombstone: integer({ mode: 'boolean' }), -}) -export type InsertHaexSettings = typeof haexSettings.$inferInsert -export type SelectHaexSettings = typeof haexSettings.$inferSelect - -export const haexExtensions = sqliteTable(tableNames.haex.extensions, { - id: text().primaryKey(), - author: text(), - enabled: integer({ mode: 'boolean' }), - icon: text(), - name: text(), - url: text(), - version: text(), - haex_tombstone: integer({ mode: 'boolean' }), -}) -export type InsertHaexExtensions = typeof haexExtensions.$inferInsert -export type SelectHaexExtensions = typeof haexExtensions.$inferSelect - -export const haexExtensionPermissions = sqliteTable( - tableNames.haex.extension_permissions, - { - id: text().primaryKey(), - extensionId: text('extension_id').references( - (): AnySQLiteColumn => haexExtensions.id, - ), - resource: text({ enum: ['fs', 'http', 'db', 'shell'] }), - operation: text({ enum: ['read', 'write', 'create'] }), - path: text(), - createdAt: text('created_at').default(sql`(CURRENT_TIMESTAMP)`), - updateAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate( - () => new Date(), - ), - haex_tombstone: integer({ mode: 'boolean' }), - }, - (table) => [ - unique().on(table.extensionId, table.resource, table.operation, table.path), - ], -) -export type InserthaexExtensionPermissions = - typeof haexExtensionPermissions.$inferInsert -export type SelecthaexExtensionPermissions = - typeof haexExtensionPermissions.$inferSelect - export const haexNotifications = sqliteTable(tableNames.haex.notifications, { id: text().primaryKey(), alt: text(), diff --git a/src-tauri/database/vault.db b/src-tauri/database/vault.db index 3c09876..1200657 100644 Binary files a/src-tauri/database/vault.db and b/src-tauri/database/vault.db differ diff --git a/src-tauri/gen/schemas/acl-manifests.json b/src-tauri/gen/schemas/acl-manifests.json index aeda1a2..7f48833 100644 --- a/src-tauri/gen/schemas/acl-manifests.json +++ b/src-tauri/gen/schemas/acl-manifests.json @@ -1 +1 @@ -{"android-fs":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin","permissions":[]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-internal-toggle-maximize"]},"permissions":{"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"dialog":{"default_permission":{"identifier":"default","description":"This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n","permissions":["allow-ask","allow-confirm","allow-message","allow-save","allow-open"]},"permissions":{"allow-ask":{"identifier":"allow-ask","description":"Enables the ask command without any pre-configured scope.","commands":{"allow":["ask"],"deny":[]}},"allow-confirm":{"identifier":"allow-confirm","description":"Enables the confirm command without any pre-configured scope.","commands":{"allow":["confirm"],"deny":[]}},"allow-message":{"identifier":"allow-message","description":"Enables the message command without any pre-configured scope.","commands":{"allow":["message"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"deny-ask":{"identifier":"deny-ask","description":"Denies the ask command without any pre-configured scope.","commands":{"allow":[],"deny":["ask"]}},"deny-confirm":{"identifier":"deny-confirm","description":"Denies the confirm command without any pre-configured scope.","commands":{"allow":[],"deny":["confirm"]}},"deny-message":{"identifier":"deny-message","description":"Denies the message command without any pre-configured scope.","commands":{"allow":[],"deny":["message"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}}},"permission_sets":{},"global_scope_schema":null},"fs":{"default_permission":{"identifier":"default","description":"This set of permissions describes the what kind of\nfile system access the `fs` plugin has enabled or denied by default.\n\n#### Granted Permissions\n\nThis default permission set enables read access to the\napplication specific directories (AppConfig, AppData, AppLocalData, AppCache,\nAppLog) and all files and sub directories created in it.\nThe location of these directories depends on the operating system,\nwhere the application is run.\n\nIn general these directories need to be manually created\nby the application at runtime, before accessing files or folders\nin it is possible.\n\nTherefore, it is also allowed to create all of these folders via\nthe `mkdir` command.\n\n#### Denied Permissions\n\nThis default permission set prevents access to critical components\nof the Tauri application by default.\nOn Windows the webview data folder access is denied.\n","permissions":["create-app-specific-dirs","read-app-specific-dirs-recursive","deny-default"]},"permissions":{"allow-copy-file":{"identifier":"allow-copy-file","description":"Enables the copy_file command without any pre-configured scope.","commands":{"allow":["copy_file"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-exists":{"identifier":"allow-exists","description":"Enables the exists command without any pre-configured scope.","commands":{"allow":["exists"],"deny":[]}},"allow-fstat":{"identifier":"allow-fstat","description":"Enables the fstat command without any pre-configured scope.","commands":{"allow":["fstat"],"deny":[]}},"allow-ftruncate":{"identifier":"allow-ftruncate","description":"Enables the ftruncate command without any pre-configured scope.","commands":{"allow":["ftruncate"],"deny":[]}},"allow-lstat":{"identifier":"allow-lstat","description":"Enables the lstat command without any pre-configured scope.","commands":{"allow":["lstat"],"deny":[]}},"allow-mkdir":{"identifier":"allow-mkdir","description":"Enables the mkdir command without any pre-configured scope.","commands":{"allow":["mkdir"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-read":{"identifier":"allow-read","description":"Enables the read command without any pre-configured scope.","commands":{"allow":["read"],"deny":[]}},"allow-read-dir":{"identifier":"allow-read-dir","description":"Enables the read_dir command without any pre-configured scope.","commands":{"allow":["read_dir"],"deny":[]}},"allow-read-file":{"identifier":"allow-read-file","description":"Enables the read_file command without any pre-configured scope.","commands":{"allow":["read_file"],"deny":[]}},"allow-read-text-file":{"identifier":"allow-read-text-file","description":"Enables the read_text_file command without any pre-configured scope.","commands":{"allow":["read_text_file"],"deny":[]}},"allow-read-text-file-lines":{"identifier":"allow-read-text-file-lines","description":"Enables the read_text_file_lines command without any pre-configured scope.","commands":{"allow":["read_text_file_lines","read_text_file_lines_next"],"deny":[]}},"allow-read-text-file-lines-next":{"identifier":"allow-read-text-file-lines-next","description":"Enables the read_text_file_lines_next command without any pre-configured scope.","commands":{"allow":["read_text_file_lines_next"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-rename":{"identifier":"allow-rename","description":"Enables the rename command without any pre-configured scope.","commands":{"allow":["rename"],"deny":[]}},"allow-seek":{"identifier":"allow-seek","description":"Enables the seek command without any pre-configured scope.","commands":{"allow":["seek"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"allow-stat":{"identifier":"allow-stat","description":"Enables the stat command without any pre-configured scope.","commands":{"allow":["stat"],"deny":[]}},"allow-truncate":{"identifier":"allow-truncate","description":"Enables the truncate command without any pre-configured scope.","commands":{"allow":["truncate"],"deny":[]}},"allow-unwatch":{"identifier":"allow-unwatch","description":"Enables the unwatch command without any pre-configured scope.","commands":{"allow":["unwatch"],"deny":[]}},"allow-watch":{"identifier":"allow-watch","description":"Enables the watch command without any pre-configured scope.","commands":{"allow":["watch"],"deny":[]}},"allow-write":{"identifier":"allow-write","description":"Enables the write command without any pre-configured scope.","commands":{"allow":["write"],"deny":[]}},"allow-write-file":{"identifier":"allow-write-file","description":"Enables the write_file command without any pre-configured scope.","commands":{"allow":["write_file","open","write"],"deny":[]}},"allow-write-text-file":{"identifier":"allow-write-text-file","description":"Enables the write_text_file command without any pre-configured scope.","commands":{"allow":["write_text_file"],"deny":[]}},"create-app-specific-dirs":{"identifier":"create-app-specific-dirs","description":"This permissions allows to create the application specific directories.\n","commands":{"allow":["mkdir","scope-app-index"],"deny":[]}},"deny-copy-file":{"identifier":"deny-copy-file","description":"Denies the copy_file command without any pre-configured scope.","commands":{"allow":[],"deny":["copy_file"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-exists":{"identifier":"deny-exists","description":"Denies the exists command without any pre-configured scope.","commands":{"allow":[],"deny":["exists"]}},"deny-fstat":{"identifier":"deny-fstat","description":"Denies the fstat command without any pre-configured scope.","commands":{"allow":[],"deny":["fstat"]}},"deny-ftruncate":{"identifier":"deny-ftruncate","description":"Denies the ftruncate command without any pre-configured scope.","commands":{"allow":[],"deny":["ftruncate"]}},"deny-lstat":{"identifier":"deny-lstat","description":"Denies the lstat command without any pre-configured scope.","commands":{"allow":[],"deny":["lstat"]}},"deny-mkdir":{"identifier":"deny-mkdir","description":"Denies the mkdir command without any pre-configured scope.","commands":{"allow":[],"deny":["mkdir"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-read":{"identifier":"deny-read","description":"Denies the read command without any pre-configured scope.","commands":{"allow":[],"deny":["read"]}},"deny-read-dir":{"identifier":"deny-read-dir","description":"Denies the read_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["read_dir"]}},"deny-read-file":{"identifier":"deny-read-file","description":"Denies the read_file command without any pre-configured scope.","commands":{"allow":[],"deny":["read_file"]}},"deny-read-text-file":{"identifier":"deny-read-text-file","description":"Denies the read_text_file command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file"]}},"deny-read-text-file-lines":{"identifier":"deny-read-text-file-lines","description":"Denies the read_text_file_lines command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file_lines"]}},"deny-read-text-file-lines-next":{"identifier":"deny-read-text-file-lines-next","description":"Denies the read_text_file_lines_next command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file_lines_next"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-rename":{"identifier":"deny-rename","description":"Denies the rename command without any pre-configured scope.","commands":{"allow":[],"deny":["rename"]}},"deny-seek":{"identifier":"deny-seek","description":"Denies the seek command without any pre-configured scope.","commands":{"allow":[],"deny":["seek"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}},"deny-stat":{"identifier":"deny-stat","description":"Denies the stat command without any pre-configured scope.","commands":{"allow":[],"deny":["stat"]}},"deny-truncate":{"identifier":"deny-truncate","description":"Denies the truncate command without any pre-configured scope.","commands":{"allow":[],"deny":["truncate"]}},"deny-unwatch":{"identifier":"deny-unwatch","description":"Denies the unwatch command without any pre-configured scope.","commands":{"allow":[],"deny":["unwatch"]}},"deny-watch":{"identifier":"deny-watch","description":"Denies the watch command without any pre-configured scope.","commands":{"allow":[],"deny":["watch"]}},"deny-webview-data-linux":{"identifier":"deny-webview-data-linux","description":"This denies read access to the\n`$APPLOCALDATA` folder on linux as the webview data and configuration values are stored here.\nAllowing access can lead to sensitive information disclosure and should be well considered.","commands":{"allow":[],"deny":[]}},"deny-webview-data-windows":{"identifier":"deny-webview-data-windows","description":"This denies read access to the\n`$APPLOCALDATA/EBWebView` folder on windows as the webview data and configuration values are stored here.\nAllowing access can lead to sensitive information disclosure and should be well considered.","commands":{"allow":[],"deny":[]}},"deny-write":{"identifier":"deny-write","description":"Denies the write command without any pre-configured scope.","commands":{"allow":[],"deny":["write"]}},"deny-write-file":{"identifier":"deny-write-file","description":"Denies the write_file command without any pre-configured scope.","commands":{"allow":[],"deny":["write_file"]}},"deny-write-text-file":{"identifier":"deny-write-text-file","description":"Denies the write_text_file command without any pre-configured scope.","commands":{"allow":[],"deny":["write_text_file"]}},"read-all":{"identifier":"read-all","description":"This enables all read related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","read_file","read","open","read_text_file","read_text_file_lines","read_text_file_lines_next","seek","stat","lstat","fstat","exists","watch","unwatch"],"deny":[]}},"read-app-specific-dirs-recursive":{"identifier":"read-app-specific-dirs-recursive","description":"This permission allows recursive read functionality on the application\nspecific base directories. \n","commands":{"allow":["read_dir","read_file","read_text_file","read_text_file_lines","read_text_file_lines_next","exists","scope-app-recursive"],"deny":[]}},"read-dirs":{"identifier":"read-dirs","description":"This enables directory read and file metadata related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","stat","lstat","fstat","exists"],"deny":[]}},"read-files":{"identifier":"read-files","description":"This enables file read related commands without any pre-configured accessible paths.","commands":{"allow":["read_file","read","open","read_text_file","read_text_file_lines","read_text_file_lines_next","seek","stat","lstat","fstat","exists"],"deny":[]}},"read-meta":{"identifier":"read-meta","description":"This enables all index or metadata related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","stat","lstat","fstat","exists","size"],"deny":[]}},"scope":{"identifier":"scope","description":"An empty permission you can use to modify the global scope.","commands":{"allow":[],"deny":[]}},"scope-app":{"identifier":"scope-app","description":"This scope permits access to all files and list content of top level directories in the application folders.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/*"},{"path":"$APPDATA"},{"path":"$APPDATA/*"},{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/*"},{"path":"$APPCACHE"},{"path":"$APPCACHE/*"},{"path":"$APPLOG"},{"path":"$APPLOG/*"}]}},"scope-app-index":{"identifier":"scope-app-index","description":"This scope permits to list all files and folders in the application directories.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPDATA"},{"path":"$APPLOCALDATA"},{"path":"$APPCACHE"},{"path":"$APPLOG"}]}},"scope-app-recursive":{"identifier":"scope-app-recursive","description":"This scope permits recursive access to the complete application folders, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/**"},{"path":"$APPDATA"},{"path":"$APPDATA/**"},{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/**"},{"path":"$APPCACHE"},{"path":"$APPCACHE/**"},{"path":"$APPLOG"},{"path":"$APPLOG/**"}]}},"scope-appcache":{"identifier":"scope-appcache","description":"This scope permits access to all files and list content of top level directories in the `$APPCACHE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"},{"path":"$APPCACHE/*"}]}},"scope-appcache-index":{"identifier":"scope-appcache-index","description":"This scope permits to list all files and folders in the `$APPCACHE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"}]}},"scope-appcache-recursive":{"identifier":"scope-appcache-recursive","description":"This scope permits recursive access to the complete `$APPCACHE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"},{"path":"$APPCACHE/**"}]}},"scope-appconfig":{"identifier":"scope-appconfig","description":"This scope permits access to all files and list content of top level directories in the `$APPCONFIG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/*"}]}},"scope-appconfig-index":{"identifier":"scope-appconfig-index","description":"This scope permits to list all files and folders in the `$APPCONFIG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"}]}},"scope-appconfig-recursive":{"identifier":"scope-appconfig-recursive","description":"This scope permits recursive access to the complete `$APPCONFIG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/**"}]}},"scope-appdata":{"identifier":"scope-appdata","description":"This scope permits access to all files and list content of top level directories in the `$APPDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"},{"path":"$APPDATA/*"}]}},"scope-appdata-index":{"identifier":"scope-appdata-index","description":"This scope permits to list all files and folders in the `$APPDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"}]}},"scope-appdata-recursive":{"identifier":"scope-appdata-recursive","description":"This scope permits recursive access to the complete `$APPDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]}},"scope-applocaldata":{"identifier":"scope-applocaldata","description":"This scope permits access to all files and list content of top level directories in the `$APPLOCALDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/*"}]}},"scope-applocaldata-index":{"identifier":"scope-applocaldata-index","description":"This scope permits to list all files and folders in the `$APPLOCALDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"}]}},"scope-applocaldata-recursive":{"identifier":"scope-applocaldata-recursive","description":"This scope permits recursive access to the complete `$APPLOCALDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/**"}]}},"scope-applog":{"identifier":"scope-applog","description":"This scope permits access to all files and list content of top level directories in the `$APPLOG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"},{"path":"$APPLOG/*"}]}},"scope-applog-index":{"identifier":"scope-applog-index","description":"This scope permits to list all files and folders in the `$APPLOG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"}]}},"scope-applog-recursive":{"identifier":"scope-applog-recursive","description":"This scope permits recursive access to the complete `$APPLOG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"},{"path":"$APPLOG/**"}]}},"scope-audio":{"identifier":"scope-audio","description":"This scope permits access to all files and list content of top level directories in the `$AUDIO` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"},{"path":"$AUDIO/*"}]}},"scope-audio-index":{"identifier":"scope-audio-index","description":"This scope permits to list all files and folders in the `$AUDIO`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"}]}},"scope-audio-recursive":{"identifier":"scope-audio-recursive","description":"This scope permits recursive access to the complete `$AUDIO` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"},{"path":"$AUDIO/**"}]}},"scope-cache":{"identifier":"scope-cache","description":"This scope permits access to all files and list content of top level directories in the `$CACHE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"},{"path":"$CACHE/*"}]}},"scope-cache-index":{"identifier":"scope-cache-index","description":"This scope permits to list all files and folders in the `$CACHE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"}]}},"scope-cache-recursive":{"identifier":"scope-cache-recursive","description":"This scope permits recursive access to the complete `$CACHE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"},{"path":"$CACHE/**"}]}},"scope-config":{"identifier":"scope-config","description":"This scope permits access to all files and list content of top level directories in the `$CONFIG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"},{"path":"$CONFIG/*"}]}},"scope-config-index":{"identifier":"scope-config-index","description":"This scope permits to list all files and folders in the `$CONFIG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"}]}},"scope-config-recursive":{"identifier":"scope-config-recursive","description":"This scope permits recursive access to the complete `$CONFIG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"},{"path":"$CONFIG/**"}]}},"scope-data":{"identifier":"scope-data","description":"This scope permits access to all files and list content of top level directories in the `$DATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"},{"path":"$DATA/*"}]}},"scope-data-index":{"identifier":"scope-data-index","description":"This scope permits to list all files and folders in the `$DATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"}]}},"scope-data-recursive":{"identifier":"scope-data-recursive","description":"This scope permits recursive access to the complete `$DATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"},{"path":"$DATA/**"}]}},"scope-desktop":{"identifier":"scope-desktop","description":"This scope permits access to all files and list content of top level directories in the `$DESKTOP` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"},{"path":"$DESKTOP/*"}]}},"scope-desktop-index":{"identifier":"scope-desktop-index","description":"This scope permits to list all files and folders in the `$DESKTOP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"}]}},"scope-desktop-recursive":{"identifier":"scope-desktop-recursive","description":"This scope permits recursive access to the complete `$DESKTOP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"},{"path":"$DESKTOP/**"}]}},"scope-document":{"identifier":"scope-document","description":"This scope permits access to all files and list content of top level directories in the `$DOCUMENT` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"},{"path":"$DOCUMENT/*"}]}},"scope-document-index":{"identifier":"scope-document-index","description":"This scope permits to list all files and folders in the `$DOCUMENT`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"}]}},"scope-document-recursive":{"identifier":"scope-document-recursive","description":"This scope permits recursive access to the complete `$DOCUMENT` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"},{"path":"$DOCUMENT/**"}]}},"scope-download":{"identifier":"scope-download","description":"This scope permits access to all files and list content of top level directories in the `$DOWNLOAD` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"},{"path":"$DOWNLOAD/*"}]}},"scope-download-index":{"identifier":"scope-download-index","description":"This scope permits to list all files and folders in the `$DOWNLOAD`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"}]}},"scope-download-recursive":{"identifier":"scope-download-recursive","description":"This scope permits recursive access to the complete `$DOWNLOAD` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"},{"path":"$DOWNLOAD/**"}]}},"scope-exe":{"identifier":"scope-exe","description":"This scope permits access to all files and list content of top level directories in the `$EXE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"},{"path":"$EXE/*"}]}},"scope-exe-index":{"identifier":"scope-exe-index","description":"This scope permits to list all files and folders in the `$EXE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"}]}},"scope-exe-recursive":{"identifier":"scope-exe-recursive","description":"This scope permits recursive access to the complete `$EXE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"},{"path":"$EXE/**"}]}},"scope-font":{"identifier":"scope-font","description":"This scope permits access to all files and list content of top level directories in the `$FONT` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"},{"path":"$FONT/*"}]}},"scope-font-index":{"identifier":"scope-font-index","description":"This scope permits to list all files and folders in the `$FONT`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"}]}},"scope-font-recursive":{"identifier":"scope-font-recursive","description":"This scope permits recursive access to the complete `$FONT` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"},{"path":"$FONT/**"}]}},"scope-home":{"identifier":"scope-home","description":"This scope permits access to all files and list content of top level directories in the `$HOME` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"},{"path":"$HOME/*"}]}},"scope-home-index":{"identifier":"scope-home-index","description":"This scope permits to list all files and folders in the `$HOME`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"}]}},"scope-home-recursive":{"identifier":"scope-home-recursive","description":"This scope permits recursive access to the complete `$HOME` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"},{"path":"$HOME/**"}]}},"scope-localdata":{"identifier":"scope-localdata","description":"This scope permits access to all files and list content of top level directories in the `$LOCALDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"},{"path":"$LOCALDATA/*"}]}},"scope-localdata-index":{"identifier":"scope-localdata-index","description":"This scope permits to list all files and folders in the `$LOCALDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"}]}},"scope-localdata-recursive":{"identifier":"scope-localdata-recursive","description":"This scope permits recursive access to the complete `$LOCALDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"},{"path":"$LOCALDATA/**"}]}},"scope-log":{"identifier":"scope-log","description":"This scope permits access to all files and list content of top level directories in the `$LOG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"},{"path":"$LOG/*"}]}},"scope-log-index":{"identifier":"scope-log-index","description":"This scope permits to list all files and folders in the `$LOG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"}]}},"scope-log-recursive":{"identifier":"scope-log-recursive","description":"This scope permits recursive access to the complete `$LOG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"},{"path":"$LOG/**"}]}},"scope-picture":{"identifier":"scope-picture","description":"This scope permits access to all files and list content of top level directories in the `$PICTURE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"},{"path":"$PICTURE/*"}]}},"scope-picture-index":{"identifier":"scope-picture-index","description":"This scope permits to list all files and folders in the `$PICTURE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"}]}},"scope-picture-recursive":{"identifier":"scope-picture-recursive","description":"This scope permits recursive access to the complete `$PICTURE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"},{"path":"$PICTURE/**"}]}},"scope-public":{"identifier":"scope-public","description":"This scope permits access to all files and list content of top level directories in the `$PUBLIC` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"},{"path":"$PUBLIC/*"}]}},"scope-public-index":{"identifier":"scope-public-index","description":"This scope permits to list all files and folders in the `$PUBLIC`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"}]}},"scope-public-recursive":{"identifier":"scope-public-recursive","description":"This scope permits recursive access to the complete `$PUBLIC` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"},{"path":"$PUBLIC/**"}]}},"scope-resource":{"identifier":"scope-resource","description":"This scope permits access to all files and list content of top level directories in the `$RESOURCE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"},{"path":"$RESOURCE/*"}]}},"scope-resource-index":{"identifier":"scope-resource-index","description":"This scope permits to list all files and folders in the `$RESOURCE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"}]}},"scope-resource-recursive":{"identifier":"scope-resource-recursive","description":"This scope permits recursive access to the complete `$RESOURCE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"},{"path":"$RESOURCE/**"}]}},"scope-runtime":{"identifier":"scope-runtime","description":"This scope permits access to all files and list content of top level directories in the `$RUNTIME` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"},{"path":"$RUNTIME/*"}]}},"scope-runtime-index":{"identifier":"scope-runtime-index","description":"This scope permits to list all files and folders in the `$RUNTIME`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"}]}},"scope-runtime-recursive":{"identifier":"scope-runtime-recursive","description":"This scope permits recursive access to the complete `$RUNTIME` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"},{"path":"$RUNTIME/**"}]}},"scope-temp":{"identifier":"scope-temp","description":"This scope permits access to all files and list content of top level directories in the `$TEMP` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"},{"path":"$TEMP/*"}]}},"scope-temp-index":{"identifier":"scope-temp-index","description":"This scope permits to list all files and folders in the `$TEMP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"}]}},"scope-temp-recursive":{"identifier":"scope-temp-recursive","description":"This scope permits recursive access to the complete `$TEMP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"},{"path":"$TEMP/**"}]}},"scope-template":{"identifier":"scope-template","description":"This scope permits access to all files and list content of top level directories in the `$TEMPLATE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"},{"path":"$TEMPLATE/*"}]}},"scope-template-index":{"identifier":"scope-template-index","description":"This scope permits to list all files and folders in the `$TEMPLATE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"}]}},"scope-template-recursive":{"identifier":"scope-template-recursive","description":"This scope permits recursive access to the complete `$TEMPLATE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"},{"path":"$TEMPLATE/**"}]}},"scope-video":{"identifier":"scope-video","description":"This scope permits access to all files and list content of top level directories in the `$VIDEO` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"},{"path":"$VIDEO/*"}]}},"scope-video-index":{"identifier":"scope-video-index","description":"This scope permits to list all files and folders in the `$VIDEO`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"}]}},"scope-video-recursive":{"identifier":"scope-video-recursive","description":"This scope permits recursive access to the complete `$VIDEO` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"},{"path":"$VIDEO/**"}]}},"write-all":{"identifier":"write-all","description":"This enables all write related commands without any pre-configured accessible paths.","commands":{"allow":["mkdir","create","copy_file","remove","rename","truncate","ftruncate","write","write_file","write_text_file"],"deny":[]}},"write-files":{"identifier":"write-files","description":"This enables all file write related commands without any pre-configured accessible paths.","commands":{"allow":["create","copy_file","remove","rename","truncate","ftruncate","write","write_file","write_text_file"],"deny":[]}}},"permission_sets":{"allow-app-meta":{"identifier":"allow-app-meta","description":"This allows non-recursive read access to metadata of the application folders, including file listing and statistics.","permissions":["read-meta","scope-app-index"]},"allow-app-meta-recursive":{"identifier":"allow-app-meta-recursive","description":"This allows full recursive read access to metadata of the application folders, including file listing and statistics.","permissions":["read-meta","scope-app-recursive"]},"allow-app-read":{"identifier":"allow-app-read","description":"This allows non-recursive read access to the application folders.","permissions":["read-all","scope-app"]},"allow-app-read-recursive":{"identifier":"allow-app-read-recursive","description":"This allows full recursive read access to the complete application folders, files and subdirectories.","permissions":["read-all","scope-app-recursive"]},"allow-app-write":{"identifier":"allow-app-write","description":"This allows non-recursive write access to the application folders.","permissions":["write-all","scope-app"]},"allow-app-write-recursive":{"identifier":"allow-app-write-recursive","description":"This allows full recursive write access to the complete application folders, files and subdirectories.","permissions":["write-all","scope-app-recursive"]},"allow-appcache-meta":{"identifier":"allow-appcache-meta","description":"This allows non-recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-appcache-index"]},"allow-appcache-meta-recursive":{"identifier":"allow-appcache-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-appcache-recursive"]},"allow-appcache-read":{"identifier":"allow-appcache-read","description":"This allows non-recursive read access to the `$APPCACHE` folder.","permissions":["read-all","scope-appcache"]},"allow-appcache-read-recursive":{"identifier":"allow-appcache-read-recursive","description":"This allows full recursive read access to the complete `$APPCACHE` folder, files and subdirectories.","permissions":["read-all","scope-appcache-recursive"]},"allow-appcache-write":{"identifier":"allow-appcache-write","description":"This allows non-recursive write access to the `$APPCACHE` folder.","permissions":["write-all","scope-appcache"]},"allow-appcache-write-recursive":{"identifier":"allow-appcache-write-recursive","description":"This allows full recursive write access to the complete `$APPCACHE` folder, files and subdirectories.","permissions":["write-all","scope-appcache-recursive"]},"allow-appconfig-meta":{"identifier":"allow-appconfig-meta","description":"This allows non-recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-appconfig-index"]},"allow-appconfig-meta-recursive":{"identifier":"allow-appconfig-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-appconfig-recursive"]},"allow-appconfig-read":{"identifier":"allow-appconfig-read","description":"This allows non-recursive read access to the `$APPCONFIG` folder.","permissions":["read-all","scope-appconfig"]},"allow-appconfig-read-recursive":{"identifier":"allow-appconfig-read-recursive","description":"This allows full recursive read access to the complete `$APPCONFIG` folder, files and subdirectories.","permissions":["read-all","scope-appconfig-recursive"]},"allow-appconfig-write":{"identifier":"allow-appconfig-write","description":"This allows non-recursive write access to the `$APPCONFIG` folder.","permissions":["write-all","scope-appconfig"]},"allow-appconfig-write-recursive":{"identifier":"allow-appconfig-write-recursive","description":"This allows full recursive write access to the complete `$APPCONFIG` folder, files and subdirectories.","permissions":["write-all","scope-appconfig-recursive"]},"allow-appdata-meta":{"identifier":"allow-appdata-meta","description":"This allows non-recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-appdata-index"]},"allow-appdata-meta-recursive":{"identifier":"allow-appdata-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-appdata-recursive"]},"allow-appdata-read":{"identifier":"allow-appdata-read","description":"This allows non-recursive read access to the `$APPDATA` folder.","permissions":["read-all","scope-appdata"]},"allow-appdata-read-recursive":{"identifier":"allow-appdata-read-recursive","description":"This allows full recursive read access to the complete `$APPDATA` folder, files and subdirectories.","permissions":["read-all","scope-appdata-recursive"]},"allow-appdata-write":{"identifier":"allow-appdata-write","description":"This allows non-recursive write access to the `$APPDATA` folder.","permissions":["write-all","scope-appdata"]},"allow-appdata-write-recursive":{"identifier":"allow-appdata-write-recursive","description":"This allows full recursive write access to the complete `$APPDATA` folder, files and subdirectories.","permissions":["write-all","scope-appdata-recursive"]},"allow-applocaldata-meta":{"identifier":"allow-applocaldata-meta","description":"This allows non-recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-applocaldata-index"]},"allow-applocaldata-meta-recursive":{"identifier":"allow-applocaldata-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-applocaldata-recursive"]},"allow-applocaldata-read":{"identifier":"allow-applocaldata-read","description":"This allows non-recursive read access to the `$APPLOCALDATA` folder.","permissions":["read-all","scope-applocaldata"]},"allow-applocaldata-read-recursive":{"identifier":"allow-applocaldata-read-recursive","description":"This allows full recursive read access to the complete `$APPLOCALDATA` folder, files and subdirectories.","permissions":["read-all","scope-applocaldata-recursive"]},"allow-applocaldata-write":{"identifier":"allow-applocaldata-write","description":"This allows non-recursive write access to the `$APPLOCALDATA` folder.","permissions":["write-all","scope-applocaldata"]},"allow-applocaldata-write-recursive":{"identifier":"allow-applocaldata-write-recursive","description":"This allows full recursive write access to the complete `$APPLOCALDATA` folder, files and subdirectories.","permissions":["write-all","scope-applocaldata-recursive"]},"allow-applog-meta":{"identifier":"allow-applog-meta","description":"This allows non-recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.","permissions":["read-meta","scope-applog-index"]},"allow-applog-meta-recursive":{"identifier":"allow-applog-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.","permissions":["read-meta","scope-applog-recursive"]},"allow-applog-read":{"identifier":"allow-applog-read","description":"This allows non-recursive read access to the `$APPLOG` folder.","permissions":["read-all","scope-applog"]},"allow-applog-read-recursive":{"identifier":"allow-applog-read-recursive","description":"This allows full recursive read access to the complete `$APPLOG` folder, files and subdirectories.","permissions":["read-all","scope-applog-recursive"]},"allow-applog-write":{"identifier":"allow-applog-write","description":"This allows non-recursive write access to the `$APPLOG` folder.","permissions":["write-all","scope-applog"]},"allow-applog-write-recursive":{"identifier":"allow-applog-write-recursive","description":"This allows full recursive write access to the complete `$APPLOG` folder, files and subdirectories.","permissions":["write-all","scope-applog-recursive"]},"allow-audio-meta":{"identifier":"allow-audio-meta","description":"This allows non-recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.","permissions":["read-meta","scope-audio-index"]},"allow-audio-meta-recursive":{"identifier":"allow-audio-meta-recursive","description":"This allows full recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.","permissions":["read-meta","scope-audio-recursive"]},"allow-audio-read":{"identifier":"allow-audio-read","description":"This allows non-recursive read access to the `$AUDIO` folder.","permissions":["read-all","scope-audio"]},"allow-audio-read-recursive":{"identifier":"allow-audio-read-recursive","description":"This allows full recursive read access to the complete `$AUDIO` folder, files and subdirectories.","permissions":["read-all","scope-audio-recursive"]},"allow-audio-write":{"identifier":"allow-audio-write","description":"This allows non-recursive write access to the `$AUDIO` folder.","permissions":["write-all","scope-audio"]},"allow-audio-write-recursive":{"identifier":"allow-audio-write-recursive","description":"This allows full recursive write access to the complete `$AUDIO` folder, files and subdirectories.","permissions":["write-all","scope-audio-recursive"]},"allow-cache-meta":{"identifier":"allow-cache-meta","description":"This allows non-recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-cache-index"]},"allow-cache-meta-recursive":{"identifier":"allow-cache-meta-recursive","description":"This allows full recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-cache-recursive"]},"allow-cache-read":{"identifier":"allow-cache-read","description":"This allows non-recursive read access to the `$CACHE` folder.","permissions":["read-all","scope-cache"]},"allow-cache-read-recursive":{"identifier":"allow-cache-read-recursive","description":"This allows full recursive read access to the complete `$CACHE` folder, files and subdirectories.","permissions":["read-all","scope-cache-recursive"]},"allow-cache-write":{"identifier":"allow-cache-write","description":"This allows non-recursive write access to the `$CACHE` folder.","permissions":["write-all","scope-cache"]},"allow-cache-write-recursive":{"identifier":"allow-cache-write-recursive","description":"This allows full recursive write access to the complete `$CACHE` folder, files and subdirectories.","permissions":["write-all","scope-cache-recursive"]},"allow-config-meta":{"identifier":"allow-config-meta","description":"This allows non-recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-config-index"]},"allow-config-meta-recursive":{"identifier":"allow-config-meta-recursive","description":"This allows full recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-config-recursive"]},"allow-config-read":{"identifier":"allow-config-read","description":"This allows non-recursive read access to the `$CONFIG` folder.","permissions":["read-all","scope-config"]},"allow-config-read-recursive":{"identifier":"allow-config-read-recursive","description":"This allows full recursive read access to the complete `$CONFIG` folder, files and subdirectories.","permissions":["read-all","scope-config-recursive"]},"allow-config-write":{"identifier":"allow-config-write","description":"This allows non-recursive write access to the `$CONFIG` folder.","permissions":["write-all","scope-config"]},"allow-config-write-recursive":{"identifier":"allow-config-write-recursive","description":"This allows full recursive write access to the complete `$CONFIG` folder, files and subdirectories.","permissions":["write-all","scope-config-recursive"]},"allow-data-meta":{"identifier":"allow-data-meta","description":"This allows non-recursive read access to metadata of the `$DATA` folder, including file listing and statistics.","permissions":["read-meta","scope-data-index"]},"allow-data-meta-recursive":{"identifier":"allow-data-meta-recursive","description":"This allows full recursive read access to metadata of the `$DATA` folder, including file listing and statistics.","permissions":["read-meta","scope-data-recursive"]},"allow-data-read":{"identifier":"allow-data-read","description":"This allows non-recursive read access to the `$DATA` folder.","permissions":["read-all","scope-data"]},"allow-data-read-recursive":{"identifier":"allow-data-read-recursive","description":"This allows full recursive read access to the complete `$DATA` folder, files and subdirectories.","permissions":["read-all","scope-data-recursive"]},"allow-data-write":{"identifier":"allow-data-write","description":"This allows non-recursive write access to the `$DATA` folder.","permissions":["write-all","scope-data"]},"allow-data-write-recursive":{"identifier":"allow-data-write-recursive","description":"This allows full recursive write access to the complete `$DATA` folder, files and subdirectories.","permissions":["write-all","scope-data-recursive"]},"allow-desktop-meta":{"identifier":"allow-desktop-meta","description":"This allows non-recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.","permissions":["read-meta","scope-desktop-index"]},"allow-desktop-meta-recursive":{"identifier":"allow-desktop-meta-recursive","description":"This allows full recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.","permissions":["read-meta","scope-desktop-recursive"]},"allow-desktop-read":{"identifier":"allow-desktop-read","description":"This allows non-recursive read access to the `$DESKTOP` folder.","permissions":["read-all","scope-desktop"]},"allow-desktop-read-recursive":{"identifier":"allow-desktop-read-recursive","description":"This allows full recursive read access to the complete `$DESKTOP` folder, files and subdirectories.","permissions":["read-all","scope-desktop-recursive"]},"allow-desktop-write":{"identifier":"allow-desktop-write","description":"This allows non-recursive write access to the `$DESKTOP` folder.","permissions":["write-all","scope-desktop"]},"allow-desktop-write-recursive":{"identifier":"allow-desktop-write-recursive","description":"This allows full recursive write access to the complete `$DESKTOP` folder, files and subdirectories.","permissions":["write-all","scope-desktop-recursive"]},"allow-document-meta":{"identifier":"allow-document-meta","description":"This allows non-recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.","permissions":["read-meta","scope-document-index"]},"allow-document-meta-recursive":{"identifier":"allow-document-meta-recursive","description":"This allows full recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.","permissions":["read-meta","scope-document-recursive"]},"allow-document-read":{"identifier":"allow-document-read","description":"This allows non-recursive read access to the `$DOCUMENT` folder.","permissions":["read-all","scope-document"]},"allow-document-read-recursive":{"identifier":"allow-document-read-recursive","description":"This allows full recursive read access to the complete `$DOCUMENT` folder, files and subdirectories.","permissions":["read-all","scope-document-recursive"]},"allow-document-write":{"identifier":"allow-document-write","description":"This allows non-recursive write access to the `$DOCUMENT` folder.","permissions":["write-all","scope-document"]},"allow-document-write-recursive":{"identifier":"allow-document-write-recursive","description":"This allows full recursive write access to the complete `$DOCUMENT` folder, files and subdirectories.","permissions":["write-all","scope-document-recursive"]},"allow-download-meta":{"identifier":"allow-download-meta","description":"This allows non-recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.","permissions":["read-meta","scope-download-index"]},"allow-download-meta-recursive":{"identifier":"allow-download-meta-recursive","description":"This allows full recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.","permissions":["read-meta","scope-download-recursive"]},"allow-download-read":{"identifier":"allow-download-read","description":"This allows non-recursive read access to the `$DOWNLOAD` folder.","permissions":["read-all","scope-download"]},"allow-download-read-recursive":{"identifier":"allow-download-read-recursive","description":"This allows full recursive read access to the complete `$DOWNLOAD` folder, files and subdirectories.","permissions":["read-all","scope-download-recursive"]},"allow-download-write":{"identifier":"allow-download-write","description":"This allows non-recursive write access to the `$DOWNLOAD` folder.","permissions":["write-all","scope-download"]},"allow-download-write-recursive":{"identifier":"allow-download-write-recursive","description":"This allows full recursive write access to the complete `$DOWNLOAD` folder, files and subdirectories.","permissions":["write-all","scope-download-recursive"]},"allow-exe-meta":{"identifier":"allow-exe-meta","description":"This allows non-recursive read access to metadata of the `$EXE` folder, including file listing and statistics.","permissions":["read-meta","scope-exe-index"]},"allow-exe-meta-recursive":{"identifier":"allow-exe-meta-recursive","description":"This allows full recursive read access to metadata of the `$EXE` folder, including file listing and statistics.","permissions":["read-meta","scope-exe-recursive"]},"allow-exe-read":{"identifier":"allow-exe-read","description":"This allows non-recursive read access to the `$EXE` folder.","permissions":["read-all","scope-exe"]},"allow-exe-read-recursive":{"identifier":"allow-exe-read-recursive","description":"This allows full recursive read access to the complete `$EXE` folder, files and subdirectories.","permissions":["read-all","scope-exe-recursive"]},"allow-exe-write":{"identifier":"allow-exe-write","description":"This allows non-recursive write access to the `$EXE` folder.","permissions":["write-all","scope-exe"]},"allow-exe-write-recursive":{"identifier":"allow-exe-write-recursive","description":"This allows full recursive write access to the complete `$EXE` folder, files and subdirectories.","permissions":["write-all","scope-exe-recursive"]},"allow-font-meta":{"identifier":"allow-font-meta","description":"This allows non-recursive read access to metadata of the `$FONT` folder, including file listing and statistics.","permissions":["read-meta","scope-font-index"]},"allow-font-meta-recursive":{"identifier":"allow-font-meta-recursive","description":"This allows full recursive read access to metadata of the `$FONT` folder, including file listing and statistics.","permissions":["read-meta","scope-font-recursive"]},"allow-font-read":{"identifier":"allow-font-read","description":"This allows non-recursive read access to the `$FONT` folder.","permissions":["read-all","scope-font"]},"allow-font-read-recursive":{"identifier":"allow-font-read-recursive","description":"This allows full recursive read access to the complete `$FONT` folder, files and subdirectories.","permissions":["read-all","scope-font-recursive"]},"allow-font-write":{"identifier":"allow-font-write","description":"This allows non-recursive write access to the `$FONT` folder.","permissions":["write-all","scope-font"]},"allow-font-write-recursive":{"identifier":"allow-font-write-recursive","description":"This allows full recursive write access to the complete `$FONT` folder, files and subdirectories.","permissions":["write-all","scope-font-recursive"]},"allow-home-meta":{"identifier":"allow-home-meta","description":"This allows non-recursive read access to metadata of the `$HOME` folder, including file listing and statistics.","permissions":["read-meta","scope-home-index"]},"allow-home-meta-recursive":{"identifier":"allow-home-meta-recursive","description":"This allows full recursive read access to metadata of the `$HOME` folder, including file listing and statistics.","permissions":["read-meta","scope-home-recursive"]},"allow-home-read":{"identifier":"allow-home-read","description":"This allows non-recursive read access to the `$HOME` folder.","permissions":["read-all","scope-home"]},"allow-home-read-recursive":{"identifier":"allow-home-read-recursive","description":"This allows full recursive read access to the complete `$HOME` folder, files and subdirectories.","permissions":["read-all","scope-home-recursive"]},"allow-home-write":{"identifier":"allow-home-write","description":"This allows non-recursive write access to the `$HOME` folder.","permissions":["write-all","scope-home"]},"allow-home-write-recursive":{"identifier":"allow-home-write-recursive","description":"This allows full recursive write access to the complete `$HOME` folder, files and subdirectories.","permissions":["write-all","scope-home-recursive"]},"allow-localdata-meta":{"identifier":"allow-localdata-meta","description":"This allows non-recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-localdata-index"]},"allow-localdata-meta-recursive":{"identifier":"allow-localdata-meta-recursive","description":"This allows full recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-localdata-recursive"]},"allow-localdata-read":{"identifier":"allow-localdata-read","description":"This allows non-recursive read access to the `$LOCALDATA` folder.","permissions":["read-all","scope-localdata"]},"allow-localdata-read-recursive":{"identifier":"allow-localdata-read-recursive","description":"This allows full recursive read access to the complete `$LOCALDATA` folder, files and subdirectories.","permissions":["read-all","scope-localdata-recursive"]},"allow-localdata-write":{"identifier":"allow-localdata-write","description":"This allows non-recursive write access to the `$LOCALDATA` folder.","permissions":["write-all","scope-localdata"]},"allow-localdata-write-recursive":{"identifier":"allow-localdata-write-recursive","description":"This allows full recursive write access to the complete `$LOCALDATA` folder, files and subdirectories.","permissions":["write-all","scope-localdata-recursive"]},"allow-log-meta":{"identifier":"allow-log-meta","description":"This allows non-recursive read access to metadata of the `$LOG` folder, including file listing and statistics.","permissions":["read-meta","scope-log-index"]},"allow-log-meta-recursive":{"identifier":"allow-log-meta-recursive","description":"This allows full recursive read access to metadata of the `$LOG` folder, including file listing and statistics.","permissions":["read-meta","scope-log-recursive"]},"allow-log-read":{"identifier":"allow-log-read","description":"This allows non-recursive read access to the `$LOG` folder.","permissions":["read-all","scope-log"]},"allow-log-read-recursive":{"identifier":"allow-log-read-recursive","description":"This allows full recursive read access to the complete `$LOG` folder, files and subdirectories.","permissions":["read-all","scope-log-recursive"]},"allow-log-write":{"identifier":"allow-log-write","description":"This allows non-recursive write access to the `$LOG` folder.","permissions":["write-all","scope-log"]},"allow-log-write-recursive":{"identifier":"allow-log-write-recursive","description":"This allows full recursive write access to the complete `$LOG` folder, files and subdirectories.","permissions":["write-all","scope-log-recursive"]},"allow-picture-meta":{"identifier":"allow-picture-meta","description":"This allows non-recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.","permissions":["read-meta","scope-picture-index"]},"allow-picture-meta-recursive":{"identifier":"allow-picture-meta-recursive","description":"This allows full recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.","permissions":["read-meta","scope-picture-recursive"]},"allow-picture-read":{"identifier":"allow-picture-read","description":"This allows non-recursive read access to the `$PICTURE` folder.","permissions":["read-all","scope-picture"]},"allow-picture-read-recursive":{"identifier":"allow-picture-read-recursive","description":"This allows full recursive read access to the complete `$PICTURE` folder, files and subdirectories.","permissions":["read-all","scope-picture-recursive"]},"allow-picture-write":{"identifier":"allow-picture-write","description":"This allows non-recursive write access to the `$PICTURE` folder.","permissions":["write-all","scope-picture"]},"allow-picture-write-recursive":{"identifier":"allow-picture-write-recursive","description":"This allows full recursive write access to the complete `$PICTURE` folder, files and subdirectories.","permissions":["write-all","scope-picture-recursive"]},"allow-public-meta":{"identifier":"allow-public-meta","description":"This allows non-recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.","permissions":["read-meta","scope-public-index"]},"allow-public-meta-recursive":{"identifier":"allow-public-meta-recursive","description":"This allows full recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.","permissions":["read-meta","scope-public-recursive"]},"allow-public-read":{"identifier":"allow-public-read","description":"This allows non-recursive read access to the `$PUBLIC` folder.","permissions":["read-all","scope-public"]},"allow-public-read-recursive":{"identifier":"allow-public-read-recursive","description":"This allows full recursive read access to the complete `$PUBLIC` folder, files and subdirectories.","permissions":["read-all","scope-public-recursive"]},"allow-public-write":{"identifier":"allow-public-write","description":"This allows non-recursive write access to the `$PUBLIC` folder.","permissions":["write-all","scope-public"]},"allow-public-write-recursive":{"identifier":"allow-public-write-recursive","description":"This allows full recursive write access to the complete `$PUBLIC` folder, files and subdirectories.","permissions":["write-all","scope-public-recursive"]},"allow-resource-meta":{"identifier":"allow-resource-meta","description":"This allows non-recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.","permissions":["read-meta","scope-resource-index"]},"allow-resource-meta-recursive":{"identifier":"allow-resource-meta-recursive","description":"This allows full recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.","permissions":["read-meta","scope-resource-recursive"]},"allow-resource-read":{"identifier":"allow-resource-read","description":"This allows non-recursive read access to the `$RESOURCE` folder.","permissions":["read-all","scope-resource"]},"allow-resource-read-recursive":{"identifier":"allow-resource-read-recursive","description":"This allows full recursive read access to the complete `$RESOURCE` folder, files and subdirectories.","permissions":["read-all","scope-resource-recursive"]},"allow-resource-write":{"identifier":"allow-resource-write","description":"This allows non-recursive write access to the `$RESOURCE` folder.","permissions":["write-all","scope-resource"]},"allow-resource-write-recursive":{"identifier":"allow-resource-write-recursive","description":"This allows full recursive write access to the complete `$RESOURCE` folder, files and subdirectories.","permissions":["write-all","scope-resource-recursive"]},"allow-runtime-meta":{"identifier":"allow-runtime-meta","description":"This allows non-recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.","permissions":["read-meta","scope-runtime-index"]},"allow-runtime-meta-recursive":{"identifier":"allow-runtime-meta-recursive","description":"This allows full recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.","permissions":["read-meta","scope-runtime-recursive"]},"allow-runtime-read":{"identifier":"allow-runtime-read","description":"This allows non-recursive read access to the `$RUNTIME` folder.","permissions":["read-all","scope-runtime"]},"allow-runtime-read-recursive":{"identifier":"allow-runtime-read-recursive","description":"This allows full recursive read access to the complete `$RUNTIME` folder, files and subdirectories.","permissions":["read-all","scope-runtime-recursive"]},"allow-runtime-write":{"identifier":"allow-runtime-write","description":"This allows non-recursive write access to the `$RUNTIME` folder.","permissions":["write-all","scope-runtime"]},"allow-runtime-write-recursive":{"identifier":"allow-runtime-write-recursive","description":"This allows full recursive write access to the complete `$RUNTIME` folder, files and subdirectories.","permissions":["write-all","scope-runtime-recursive"]},"allow-temp-meta":{"identifier":"allow-temp-meta","description":"This allows non-recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.","permissions":["read-meta","scope-temp-index"]},"allow-temp-meta-recursive":{"identifier":"allow-temp-meta-recursive","description":"This allows full recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.","permissions":["read-meta","scope-temp-recursive"]},"allow-temp-read":{"identifier":"allow-temp-read","description":"This allows non-recursive read access to the `$TEMP` folder.","permissions":["read-all","scope-temp"]},"allow-temp-read-recursive":{"identifier":"allow-temp-read-recursive","description":"This allows full recursive read access to the complete `$TEMP` folder, files and subdirectories.","permissions":["read-all","scope-temp-recursive"]},"allow-temp-write":{"identifier":"allow-temp-write","description":"This allows non-recursive write access to the `$TEMP` folder.","permissions":["write-all","scope-temp"]},"allow-temp-write-recursive":{"identifier":"allow-temp-write-recursive","description":"This allows full recursive write access to the complete `$TEMP` folder, files and subdirectories.","permissions":["write-all","scope-temp-recursive"]},"allow-template-meta":{"identifier":"allow-template-meta","description":"This allows non-recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.","permissions":["read-meta","scope-template-index"]},"allow-template-meta-recursive":{"identifier":"allow-template-meta-recursive","description":"This allows full recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.","permissions":["read-meta","scope-template-recursive"]},"allow-template-read":{"identifier":"allow-template-read","description":"This allows non-recursive read access to the `$TEMPLATE` folder.","permissions":["read-all","scope-template"]},"allow-template-read-recursive":{"identifier":"allow-template-read-recursive","description":"This allows full recursive read access to the complete `$TEMPLATE` folder, files and subdirectories.","permissions":["read-all","scope-template-recursive"]},"allow-template-write":{"identifier":"allow-template-write","description":"This allows non-recursive write access to the `$TEMPLATE` folder.","permissions":["write-all","scope-template"]},"allow-template-write-recursive":{"identifier":"allow-template-write-recursive","description":"This allows full recursive write access to the complete `$TEMPLATE` folder, files and subdirectories.","permissions":["write-all","scope-template-recursive"]},"allow-video-meta":{"identifier":"allow-video-meta","description":"This allows non-recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.","permissions":["read-meta","scope-video-index"]},"allow-video-meta-recursive":{"identifier":"allow-video-meta-recursive","description":"This allows full recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.","permissions":["read-meta","scope-video-recursive"]},"allow-video-read":{"identifier":"allow-video-read","description":"This allows non-recursive read access to the `$VIDEO` folder.","permissions":["read-all","scope-video"]},"allow-video-read-recursive":{"identifier":"allow-video-read-recursive","description":"This allows full recursive read access to the complete `$VIDEO` folder, files and subdirectories.","permissions":["read-all","scope-video-recursive"]},"allow-video-write":{"identifier":"allow-video-write","description":"This allows non-recursive write access to the `$VIDEO` folder.","permissions":["write-all","scope-video"]},"allow-video-write-recursive":{"identifier":"allow-video-write-recursive","description":"This allows full recursive write access to the complete `$VIDEO` folder, files and subdirectories.","permissions":["write-all","scope-video-recursive"]},"deny-default":{"identifier":"deny-default","description":"This denies access to dangerous Tauri relevant files and folders by default.","permissions":["deny-webview-data-linux","deny-webview-data-windows"]}},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"description":"A path that can be accessed by the webview when using the fs APIs. FS scope path pattern.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},{"properties":{"path":{"description":"A path that can be accessed by the webview when using the fs APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"}},"required":["path"],"type":"object"}],"description":"FS scope entry.","title":"FsScopeEntry"}},"http":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\nfetch operations are available from the http plugin.\n\nThis enables all fetch operations but does not\nallow explicitly any origins to be fetched. This needs to\nbe manually configured before usage.\n\n#### Granted Permissions\n\nAll fetch operations are enabled.\n\n","permissions":["allow-fetch","allow-fetch-cancel","allow-fetch-read-body","allow-fetch-send"]},"permissions":{"allow-fetch":{"identifier":"allow-fetch","description":"Enables the fetch command without any pre-configured scope.","commands":{"allow":["fetch"],"deny":[]}},"allow-fetch-cancel":{"identifier":"allow-fetch-cancel","description":"Enables the fetch_cancel command without any pre-configured scope.","commands":{"allow":["fetch_cancel"],"deny":[]}},"allow-fetch-read-body":{"identifier":"allow-fetch-read-body","description":"Enables the fetch_read_body command without any pre-configured scope.","commands":{"allow":["fetch_read_body"],"deny":[]}},"allow-fetch-send":{"identifier":"allow-fetch-send","description":"Enables the fetch_send command without any pre-configured scope.","commands":{"allow":["fetch_send"],"deny":[]}},"deny-fetch":{"identifier":"deny-fetch","description":"Denies the fetch command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch"]}},"deny-fetch-cancel":{"identifier":"deny-fetch-cancel","description":"Denies the fetch_cancel command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_cancel"]}},"deny-fetch-read-body":{"identifier":"deny-fetch-read-body","description":"Denies the fetch_read_body command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_read_body"]}},"deny-fetch-send":{"identifier":"deny-fetch-send","description":"Denies the fetch_send command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_send"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"description":"A URL that can be accessed by the webview when using the HTTP APIs. Wildcards can be used following the URL pattern standard.\n\nSee [the URL Pattern spec](https://urlpattern.spec.whatwg.org/) for more information.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin on port 443\n\n- \"https://*:*\" : allows all HTTPS origin on any port\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"},{"properties":{"url":{"description":"A URL that can be accessed by the webview when using the HTTP APIs. Wildcards can be used following the URL pattern standard.\n\nSee [the URL Pattern spec](https://urlpattern.spec.whatwg.org/) for more information.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin on port 443\n\n- \"https://*:*\" : allows all HTTPS origin on any port\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"}},"required":["url"],"type":"object"}],"description":"HTTP scope entry.","title":"HttpScopeEntry"}},"notification":{"default_permission":{"identifier":"default","description":"This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n","permissions":["allow-is-permission-granted","allow-request-permission","allow-notify","allow-register-action-types","allow-register-listener","allow-cancel","allow-get-pending","allow-remove-active","allow-get-active","allow-check-permissions","allow-show","allow-batch","allow-list-channels","allow-delete-channel","allow-create-channel","allow-permission-state"]},"permissions":{"allow-batch":{"identifier":"allow-batch","description":"Enables the batch command without any pre-configured scope.","commands":{"allow":["batch"],"deny":[]}},"allow-cancel":{"identifier":"allow-cancel","description":"Enables the cancel command without any pre-configured scope.","commands":{"allow":["cancel"],"deny":[]}},"allow-check-permissions":{"identifier":"allow-check-permissions","description":"Enables the check_permissions command without any pre-configured scope.","commands":{"allow":["check_permissions"],"deny":[]}},"allow-create-channel":{"identifier":"allow-create-channel","description":"Enables the create_channel command without any pre-configured scope.","commands":{"allow":["create_channel"],"deny":[]}},"allow-delete-channel":{"identifier":"allow-delete-channel","description":"Enables the delete_channel command without any pre-configured scope.","commands":{"allow":["delete_channel"],"deny":[]}},"allow-get-active":{"identifier":"allow-get-active","description":"Enables the get_active command without any pre-configured scope.","commands":{"allow":["get_active"],"deny":[]}},"allow-get-pending":{"identifier":"allow-get-pending","description":"Enables the get_pending command without any pre-configured scope.","commands":{"allow":["get_pending"],"deny":[]}},"allow-is-permission-granted":{"identifier":"allow-is-permission-granted","description":"Enables the is_permission_granted command without any pre-configured scope.","commands":{"allow":["is_permission_granted"],"deny":[]}},"allow-list-channels":{"identifier":"allow-list-channels","description":"Enables the list_channels command without any pre-configured scope.","commands":{"allow":["list_channels"],"deny":[]}},"allow-notify":{"identifier":"allow-notify","description":"Enables the notify command without any pre-configured scope.","commands":{"allow":["notify"],"deny":[]}},"allow-permission-state":{"identifier":"allow-permission-state","description":"Enables the permission_state command without any pre-configured scope.","commands":{"allow":["permission_state"],"deny":[]}},"allow-register-action-types":{"identifier":"allow-register-action-types","description":"Enables the register_action_types command without any pre-configured scope.","commands":{"allow":["register_action_types"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-active":{"identifier":"allow-remove-active","description":"Enables the remove_active command without any pre-configured scope.","commands":{"allow":["remove_active"],"deny":[]}},"allow-request-permission":{"identifier":"allow-request-permission","description":"Enables the request_permission command without any pre-configured scope.","commands":{"allow":["request_permission"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"deny-batch":{"identifier":"deny-batch","description":"Denies the batch command without any pre-configured scope.","commands":{"allow":[],"deny":["batch"]}},"deny-cancel":{"identifier":"deny-cancel","description":"Denies the cancel command without any pre-configured scope.","commands":{"allow":[],"deny":["cancel"]}},"deny-check-permissions":{"identifier":"deny-check-permissions","description":"Denies the check_permissions command without any pre-configured scope.","commands":{"allow":[],"deny":["check_permissions"]}},"deny-create-channel":{"identifier":"deny-create-channel","description":"Denies the create_channel command without any pre-configured scope.","commands":{"allow":[],"deny":["create_channel"]}},"deny-delete-channel":{"identifier":"deny-delete-channel","description":"Denies the delete_channel command without any pre-configured scope.","commands":{"allow":[],"deny":["delete_channel"]}},"deny-get-active":{"identifier":"deny-get-active","description":"Denies the get_active command without any pre-configured scope.","commands":{"allow":[],"deny":["get_active"]}},"deny-get-pending":{"identifier":"deny-get-pending","description":"Denies the get_pending command without any pre-configured scope.","commands":{"allow":[],"deny":["get_pending"]}},"deny-is-permission-granted":{"identifier":"deny-is-permission-granted","description":"Denies the is_permission_granted command without any pre-configured scope.","commands":{"allow":[],"deny":["is_permission_granted"]}},"deny-list-channels":{"identifier":"deny-list-channels","description":"Denies the list_channels command without any pre-configured scope.","commands":{"allow":[],"deny":["list_channels"]}},"deny-notify":{"identifier":"deny-notify","description":"Denies the notify command without any pre-configured scope.","commands":{"allow":[],"deny":["notify"]}},"deny-permission-state":{"identifier":"deny-permission-state","description":"Denies the permission_state command without any pre-configured scope.","commands":{"allow":[],"deny":["permission_state"]}},"deny-register-action-types":{"identifier":"deny-register-action-types","description":"Denies the register_action_types command without any pre-configured scope.","commands":{"allow":[],"deny":["register_action_types"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-active":{"identifier":"deny-remove-active","description":"Denies the remove_active command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_active"]}},"deny-request-permission":{"identifier":"deny-request-permission","description":"Denies the request_permission command without any pre-configured scope.","commands":{"allow":[],"deny":["request_permission"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}}},"permission_sets":{},"global_scope_schema":null},"opener":{"default_permission":{"identifier":"default","description":"This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer","permissions":["allow-open-url","allow-reveal-item-in-dir","allow-default-urls"]},"permissions":{"allow-default-urls":{"identifier":"allow-default-urls","description":"This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"url":"mailto:*"},{"url":"tel:*"},{"url":"http://*"},{"url":"https://*"}]}},"allow-open-path":{"identifier":"allow-open-path","description":"Enables the open_path command without any pre-configured scope.","commands":{"allow":["open_path"],"deny":[]}},"allow-open-url":{"identifier":"allow-open-url","description":"Enables the open_url command without any pre-configured scope.","commands":{"allow":["open_url"],"deny":[]}},"allow-reveal-item-in-dir":{"identifier":"allow-reveal-item-in-dir","description":"Enables the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":["reveal_item_in_dir"],"deny":[]}},"deny-open-path":{"identifier":"deny-open-path","description":"Denies the open_path command without any pre-configured scope.","commands":{"allow":[],"deny":["open_path"]}},"deny-open-url":{"identifier":"deny-open-url","description":"Denies the open_url command without any pre-configured scope.","commands":{"allow":[],"deny":["open_url"]}},"deny-reveal-item-in-dir":{"identifier":"deny-reveal-item-in-dir","description":"Denies the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["reveal_item_in_dir"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this url with, for example: firefox."},"url":{"description":"A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"}},"required":["url"],"type":"object"},{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this path with, for example: xdg-open."},"path":{"description":"A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"}},"required":["path"],"type":"object"}],"definitions":{"Application":{"anyOf":[{"description":"Open in default application.","type":"null"},{"description":"If true, allow open with any application.","type":"boolean"},{"description":"Allow specific application to open with.","type":"string"}],"description":"Opener scope application."}},"description":"Opener scope entry.","title":"OpenerScopeEntry"}},"os":{"default_permission":{"identifier":"default","description":"This permission set configures which\noperating system information are available\nto gather from the frontend.\n\n#### Granted Permissions\n\nAll information except the host name are available.\n\n","permissions":["allow-arch","allow-exe-extension","allow-family","allow-locale","allow-os-type","allow-platform","allow-version"]},"permissions":{"allow-arch":{"identifier":"allow-arch","description":"Enables the arch command without any pre-configured scope.","commands":{"allow":["arch"],"deny":[]}},"allow-exe-extension":{"identifier":"allow-exe-extension","description":"Enables the exe_extension command without any pre-configured scope.","commands":{"allow":["exe_extension"],"deny":[]}},"allow-family":{"identifier":"allow-family","description":"Enables the family command without any pre-configured scope.","commands":{"allow":["family"],"deny":[]}},"allow-hostname":{"identifier":"allow-hostname","description":"Enables the hostname command without any pre-configured scope.","commands":{"allow":["hostname"],"deny":[]}},"allow-locale":{"identifier":"allow-locale","description":"Enables the locale command without any pre-configured scope.","commands":{"allow":["locale"],"deny":[]}},"allow-os-type":{"identifier":"allow-os-type","description":"Enables the os_type command without any pre-configured scope.","commands":{"allow":["os_type"],"deny":[]}},"allow-platform":{"identifier":"allow-platform","description":"Enables the platform command without any pre-configured scope.","commands":{"allow":["platform"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-arch":{"identifier":"deny-arch","description":"Denies the arch command without any pre-configured scope.","commands":{"allow":[],"deny":["arch"]}},"deny-exe-extension":{"identifier":"deny-exe-extension","description":"Denies the exe_extension command without any pre-configured scope.","commands":{"allow":[],"deny":["exe_extension"]}},"deny-family":{"identifier":"deny-family","description":"Denies the family command without any pre-configured scope.","commands":{"allow":[],"deny":["family"]}},"deny-hostname":{"identifier":"deny-hostname","description":"Denies the hostname command without any pre-configured scope.","commands":{"allow":[],"deny":["hostname"]}},"deny-locale":{"identifier":"deny-locale","description":"Denies the locale command without any pre-configured scope.","commands":{"allow":[],"deny":["locale"]}},"deny-os-type":{"identifier":"deny-os-type","description":"Denies the os_type command without any pre-configured scope.","commands":{"allow":[],"deny":["os_type"]}},"deny-platform":{"identifier":"deny-platform","description":"Denies the platform command without any pre-configured scope.","commands":{"allow":[],"deny":["platform"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"store":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n","permissions":["allow-load","allow-get-store","allow-set","allow-get","allow-has","allow-delete","allow-clear","allow-reset","allow-keys","allow-values","allow-entries","allow-length","allow-reload","allow-save"]},"permissions":{"allow-clear":{"identifier":"allow-clear","description":"Enables the clear command without any pre-configured scope.","commands":{"allow":["clear"],"deny":[]}},"allow-delete":{"identifier":"allow-delete","description":"Enables the delete command without any pre-configured scope.","commands":{"allow":["delete"],"deny":[]}},"allow-entries":{"identifier":"allow-entries","description":"Enables the entries command without any pre-configured scope.","commands":{"allow":["entries"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-get-store":{"identifier":"allow-get-store","description":"Enables the get_store command without any pre-configured scope.","commands":{"allow":["get_store"],"deny":[]}},"allow-has":{"identifier":"allow-has","description":"Enables the has command without any pre-configured scope.","commands":{"allow":["has"],"deny":[]}},"allow-keys":{"identifier":"allow-keys","description":"Enables the keys command without any pre-configured scope.","commands":{"allow":["keys"],"deny":[]}},"allow-length":{"identifier":"allow-length","description":"Enables the length command without any pre-configured scope.","commands":{"allow":["length"],"deny":[]}},"allow-load":{"identifier":"allow-load","description":"Enables the load command without any pre-configured scope.","commands":{"allow":["load"],"deny":[]}},"allow-reload":{"identifier":"allow-reload","description":"Enables the reload command without any pre-configured scope.","commands":{"allow":["reload"],"deny":[]}},"allow-reset":{"identifier":"allow-reset","description":"Enables the reset command without any pre-configured scope.","commands":{"allow":["reset"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"allow-set":{"identifier":"allow-set","description":"Enables the set command without any pre-configured scope.","commands":{"allow":["set"],"deny":[]}},"allow-values":{"identifier":"allow-values","description":"Enables the values command without any pre-configured scope.","commands":{"allow":["values"],"deny":[]}},"deny-clear":{"identifier":"deny-clear","description":"Denies the clear command without any pre-configured scope.","commands":{"allow":[],"deny":["clear"]}},"deny-delete":{"identifier":"deny-delete","description":"Denies the delete command without any pre-configured scope.","commands":{"allow":[],"deny":["delete"]}},"deny-entries":{"identifier":"deny-entries","description":"Denies the entries command without any pre-configured scope.","commands":{"allow":[],"deny":["entries"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-get-store":{"identifier":"deny-get-store","description":"Denies the get_store command without any pre-configured scope.","commands":{"allow":[],"deny":["get_store"]}},"deny-has":{"identifier":"deny-has","description":"Denies the has command without any pre-configured scope.","commands":{"allow":[],"deny":["has"]}},"deny-keys":{"identifier":"deny-keys","description":"Denies the keys command without any pre-configured scope.","commands":{"allow":[],"deny":["keys"]}},"deny-length":{"identifier":"deny-length","description":"Denies the length command without any pre-configured scope.","commands":{"allow":[],"deny":["length"]}},"deny-load":{"identifier":"deny-load","description":"Denies the load command without any pre-configured scope.","commands":{"allow":[],"deny":["load"]}},"deny-reload":{"identifier":"deny-reload","description":"Denies the reload command without any pre-configured scope.","commands":{"allow":[],"deny":["reload"]}},"deny-reset":{"identifier":"deny-reset","description":"Denies the reset command without any pre-configured scope.","commands":{"allow":[],"deny":["reset"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}},"deny-set":{"identifier":"deny-set","description":"Denies the set command without any pre-configured scope.","commands":{"allow":[],"deny":["set"]}},"deny-values":{"identifier":"deny-values","description":"Denies the values command without any pre-configured scope.","commands":{"allow":[],"deny":["values"]}}},"permission_sets":{},"global_scope_schema":null}} \ No newline at end of file +{"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-internal-toggle-maximize"]},"permissions":{"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"dialog":{"default_permission":{"identifier":"default","description":"This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n","permissions":["allow-ask","allow-confirm","allow-message","allow-save","allow-open"]},"permissions":{"allow-ask":{"identifier":"allow-ask","description":"Enables the ask command without any pre-configured scope.","commands":{"allow":["ask"],"deny":[]}},"allow-confirm":{"identifier":"allow-confirm","description":"Enables the confirm command without any pre-configured scope.","commands":{"allow":["confirm"],"deny":[]}},"allow-message":{"identifier":"allow-message","description":"Enables the message command without any pre-configured scope.","commands":{"allow":["message"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"deny-ask":{"identifier":"deny-ask","description":"Denies the ask command without any pre-configured scope.","commands":{"allow":[],"deny":["ask"]}},"deny-confirm":{"identifier":"deny-confirm","description":"Denies the confirm command without any pre-configured scope.","commands":{"allow":[],"deny":["confirm"]}},"deny-message":{"identifier":"deny-message","description":"Denies the message command without any pre-configured scope.","commands":{"allow":[],"deny":["message"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}}},"permission_sets":{},"global_scope_schema":null},"fs":{"default_permission":{"identifier":"default","description":"This set of permissions describes the what kind of\nfile system access the `fs` plugin has enabled or denied by default.\n\n#### Granted Permissions\n\nThis default permission set enables read access to the\napplication specific directories (AppConfig, AppData, AppLocalData, AppCache,\nAppLog) and all files and sub directories created in it.\nThe location of these directories depends on the operating system,\nwhere the application is run.\n\nIn general these directories need to be manually created\nby the application at runtime, before accessing files or folders\nin it is possible.\n\nTherefore, it is also allowed to create all of these folders via\nthe `mkdir` command.\n\n#### Denied Permissions\n\nThis default permission set prevents access to critical components\nof the Tauri application by default.\nOn Windows the webview data folder access is denied.\n","permissions":["create-app-specific-dirs","read-app-specific-dirs-recursive","deny-default"]},"permissions":{"allow-copy-file":{"identifier":"allow-copy-file","description":"Enables the copy_file command without any pre-configured scope.","commands":{"allow":["copy_file"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-exists":{"identifier":"allow-exists","description":"Enables the exists command without any pre-configured scope.","commands":{"allow":["exists"],"deny":[]}},"allow-fstat":{"identifier":"allow-fstat","description":"Enables the fstat command without any pre-configured scope.","commands":{"allow":["fstat"],"deny":[]}},"allow-ftruncate":{"identifier":"allow-ftruncate","description":"Enables the ftruncate command without any pre-configured scope.","commands":{"allow":["ftruncate"],"deny":[]}},"allow-lstat":{"identifier":"allow-lstat","description":"Enables the lstat command without any pre-configured scope.","commands":{"allow":["lstat"],"deny":[]}},"allow-mkdir":{"identifier":"allow-mkdir","description":"Enables the mkdir command without any pre-configured scope.","commands":{"allow":["mkdir"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-read":{"identifier":"allow-read","description":"Enables the read command without any pre-configured scope.","commands":{"allow":["read"],"deny":[]}},"allow-read-dir":{"identifier":"allow-read-dir","description":"Enables the read_dir command without any pre-configured scope.","commands":{"allow":["read_dir"],"deny":[]}},"allow-read-file":{"identifier":"allow-read-file","description":"Enables the read_file command without any pre-configured scope.","commands":{"allow":["read_file"],"deny":[]}},"allow-read-text-file":{"identifier":"allow-read-text-file","description":"Enables the read_text_file command without any pre-configured scope.","commands":{"allow":["read_text_file"],"deny":[]}},"allow-read-text-file-lines":{"identifier":"allow-read-text-file-lines","description":"Enables the read_text_file_lines command without any pre-configured scope.","commands":{"allow":["read_text_file_lines","read_text_file_lines_next"],"deny":[]}},"allow-read-text-file-lines-next":{"identifier":"allow-read-text-file-lines-next","description":"Enables the read_text_file_lines_next command without any pre-configured scope.","commands":{"allow":["read_text_file_lines_next"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-rename":{"identifier":"allow-rename","description":"Enables the rename command without any pre-configured scope.","commands":{"allow":["rename"],"deny":[]}},"allow-seek":{"identifier":"allow-seek","description":"Enables the seek command without any pre-configured scope.","commands":{"allow":["seek"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"allow-stat":{"identifier":"allow-stat","description":"Enables the stat command without any pre-configured scope.","commands":{"allow":["stat"],"deny":[]}},"allow-truncate":{"identifier":"allow-truncate","description":"Enables the truncate command without any pre-configured scope.","commands":{"allow":["truncate"],"deny":[]}},"allow-unwatch":{"identifier":"allow-unwatch","description":"Enables the unwatch command without any pre-configured scope.","commands":{"allow":["unwatch"],"deny":[]}},"allow-watch":{"identifier":"allow-watch","description":"Enables the watch command without any pre-configured scope.","commands":{"allow":["watch"],"deny":[]}},"allow-write":{"identifier":"allow-write","description":"Enables the write command without any pre-configured scope.","commands":{"allow":["write"],"deny":[]}},"allow-write-file":{"identifier":"allow-write-file","description":"Enables the write_file command without any pre-configured scope.","commands":{"allow":["write_file","open","write"],"deny":[]}},"allow-write-text-file":{"identifier":"allow-write-text-file","description":"Enables the write_text_file command without any pre-configured scope.","commands":{"allow":["write_text_file"],"deny":[]}},"create-app-specific-dirs":{"identifier":"create-app-specific-dirs","description":"This permissions allows to create the application specific directories.\n","commands":{"allow":["mkdir","scope-app-index"],"deny":[]}},"deny-copy-file":{"identifier":"deny-copy-file","description":"Denies the copy_file command without any pre-configured scope.","commands":{"allow":[],"deny":["copy_file"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-exists":{"identifier":"deny-exists","description":"Denies the exists command without any pre-configured scope.","commands":{"allow":[],"deny":["exists"]}},"deny-fstat":{"identifier":"deny-fstat","description":"Denies the fstat command without any pre-configured scope.","commands":{"allow":[],"deny":["fstat"]}},"deny-ftruncate":{"identifier":"deny-ftruncate","description":"Denies the ftruncate command without any pre-configured scope.","commands":{"allow":[],"deny":["ftruncate"]}},"deny-lstat":{"identifier":"deny-lstat","description":"Denies the lstat command without any pre-configured scope.","commands":{"allow":[],"deny":["lstat"]}},"deny-mkdir":{"identifier":"deny-mkdir","description":"Denies the mkdir command without any pre-configured scope.","commands":{"allow":[],"deny":["mkdir"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-read":{"identifier":"deny-read","description":"Denies the read command without any pre-configured scope.","commands":{"allow":[],"deny":["read"]}},"deny-read-dir":{"identifier":"deny-read-dir","description":"Denies the read_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["read_dir"]}},"deny-read-file":{"identifier":"deny-read-file","description":"Denies the read_file command without any pre-configured scope.","commands":{"allow":[],"deny":["read_file"]}},"deny-read-text-file":{"identifier":"deny-read-text-file","description":"Denies the read_text_file command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file"]}},"deny-read-text-file-lines":{"identifier":"deny-read-text-file-lines","description":"Denies the read_text_file_lines command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file_lines"]}},"deny-read-text-file-lines-next":{"identifier":"deny-read-text-file-lines-next","description":"Denies the read_text_file_lines_next command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file_lines_next"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-rename":{"identifier":"deny-rename","description":"Denies the rename command without any pre-configured scope.","commands":{"allow":[],"deny":["rename"]}},"deny-seek":{"identifier":"deny-seek","description":"Denies the seek command without any pre-configured scope.","commands":{"allow":[],"deny":["seek"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}},"deny-stat":{"identifier":"deny-stat","description":"Denies the stat command without any pre-configured scope.","commands":{"allow":[],"deny":["stat"]}},"deny-truncate":{"identifier":"deny-truncate","description":"Denies the truncate command without any pre-configured scope.","commands":{"allow":[],"deny":["truncate"]}},"deny-unwatch":{"identifier":"deny-unwatch","description":"Denies the unwatch command without any pre-configured scope.","commands":{"allow":[],"deny":["unwatch"]}},"deny-watch":{"identifier":"deny-watch","description":"Denies the watch command without any pre-configured scope.","commands":{"allow":[],"deny":["watch"]}},"deny-webview-data-linux":{"identifier":"deny-webview-data-linux","description":"This denies read access to the\n`$APPLOCALDATA` folder on linux as the webview data and configuration values are stored here.\nAllowing access can lead to sensitive information disclosure and should be well considered.","commands":{"allow":[],"deny":[]}},"deny-webview-data-windows":{"identifier":"deny-webview-data-windows","description":"This denies read access to the\n`$APPLOCALDATA/EBWebView` folder on windows as the webview data and configuration values are stored here.\nAllowing access can lead to sensitive information disclosure and should be well considered.","commands":{"allow":[],"deny":[]}},"deny-write":{"identifier":"deny-write","description":"Denies the write command without any pre-configured scope.","commands":{"allow":[],"deny":["write"]}},"deny-write-file":{"identifier":"deny-write-file","description":"Denies the write_file command without any pre-configured scope.","commands":{"allow":[],"deny":["write_file"]}},"deny-write-text-file":{"identifier":"deny-write-text-file","description":"Denies the write_text_file command without any pre-configured scope.","commands":{"allow":[],"deny":["write_text_file"]}},"read-all":{"identifier":"read-all","description":"This enables all read related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","read_file","read","open","read_text_file","read_text_file_lines","read_text_file_lines_next","seek","stat","lstat","fstat","exists","watch","unwatch"],"deny":[]}},"read-app-specific-dirs-recursive":{"identifier":"read-app-specific-dirs-recursive","description":"This permission allows recursive read functionality on the application\nspecific base directories. \n","commands":{"allow":["read_dir","read_file","read_text_file","read_text_file_lines","read_text_file_lines_next","exists","scope-app-recursive"],"deny":[]}},"read-dirs":{"identifier":"read-dirs","description":"This enables directory read and file metadata related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","stat","lstat","fstat","exists"],"deny":[]}},"read-files":{"identifier":"read-files","description":"This enables file read related commands without any pre-configured accessible paths.","commands":{"allow":["read_file","read","open","read_text_file","read_text_file_lines","read_text_file_lines_next","seek","stat","lstat","fstat","exists"],"deny":[]}},"read-meta":{"identifier":"read-meta","description":"This enables all index or metadata related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","stat","lstat","fstat","exists","size"],"deny":[]}},"scope":{"identifier":"scope","description":"An empty permission you can use to modify the global scope.","commands":{"allow":[],"deny":[]}},"scope-app":{"identifier":"scope-app","description":"This scope permits access to all files and list content of top level directories in the application folders.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/*"},{"path":"$APPDATA"},{"path":"$APPDATA/*"},{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/*"},{"path":"$APPCACHE"},{"path":"$APPCACHE/*"},{"path":"$APPLOG"},{"path":"$APPLOG/*"}]}},"scope-app-index":{"identifier":"scope-app-index","description":"This scope permits to list all files and folders in the application directories.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPDATA"},{"path":"$APPLOCALDATA"},{"path":"$APPCACHE"},{"path":"$APPLOG"}]}},"scope-app-recursive":{"identifier":"scope-app-recursive","description":"This scope permits recursive access to the complete application folders, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/**"},{"path":"$APPDATA"},{"path":"$APPDATA/**"},{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/**"},{"path":"$APPCACHE"},{"path":"$APPCACHE/**"},{"path":"$APPLOG"},{"path":"$APPLOG/**"}]}},"scope-appcache":{"identifier":"scope-appcache","description":"This scope permits access to all files and list content of top level directories in the `$APPCACHE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"},{"path":"$APPCACHE/*"}]}},"scope-appcache-index":{"identifier":"scope-appcache-index","description":"This scope permits to list all files and folders in the `$APPCACHE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"}]}},"scope-appcache-recursive":{"identifier":"scope-appcache-recursive","description":"This scope permits recursive access to the complete `$APPCACHE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"},{"path":"$APPCACHE/**"}]}},"scope-appconfig":{"identifier":"scope-appconfig","description":"This scope permits access to all files and list content of top level directories in the `$APPCONFIG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/*"}]}},"scope-appconfig-index":{"identifier":"scope-appconfig-index","description":"This scope permits to list all files and folders in the `$APPCONFIG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"}]}},"scope-appconfig-recursive":{"identifier":"scope-appconfig-recursive","description":"This scope permits recursive access to the complete `$APPCONFIG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/**"}]}},"scope-appdata":{"identifier":"scope-appdata","description":"This scope permits access to all files and list content of top level directories in the `$APPDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"},{"path":"$APPDATA/*"}]}},"scope-appdata-index":{"identifier":"scope-appdata-index","description":"This scope permits to list all files and folders in the `$APPDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"}]}},"scope-appdata-recursive":{"identifier":"scope-appdata-recursive","description":"This scope permits recursive access to the complete `$APPDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]}},"scope-applocaldata":{"identifier":"scope-applocaldata","description":"This scope permits access to all files and list content of top level directories in the `$APPLOCALDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/*"}]}},"scope-applocaldata-index":{"identifier":"scope-applocaldata-index","description":"This scope permits to list all files and folders in the `$APPLOCALDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"}]}},"scope-applocaldata-recursive":{"identifier":"scope-applocaldata-recursive","description":"This scope permits recursive access to the complete `$APPLOCALDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/**"}]}},"scope-applog":{"identifier":"scope-applog","description":"This scope permits access to all files and list content of top level directories in the `$APPLOG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"},{"path":"$APPLOG/*"}]}},"scope-applog-index":{"identifier":"scope-applog-index","description":"This scope permits to list all files and folders in the `$APPLOG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"}]}},"scope-applog-recursive":{"identifier":"scope-applog-recursive","description":"This scope permits recursive access to the complete `$APPLOG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"},{"path":"$APPLOG/**"}]}},"scope-audio":{"identifier":"scope-audio","description":"This scope permits access to all files and list content of top level directories in the `$AUDIO` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"},{"path":"$AUDIO/*"}]}},"scope-audio-index":{"identifier":"scope-audio-index","description":"This scope permits to list all files and folders in the `$AUDIO`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"}]}},"scope-audio-recursive":{"identifier":"scope-audio-recursive","description":"This scope permits recursive access to the complete `$AUDIO` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"},{"path":"$AUDIO/**"}]}},"scope-cache":{"identifier":"scope-cache","description":"This scope permits access to all files and list content of top level directories in the `$CACHE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"},{"path":"$CACHE/*"}]}},"scope-cache-index":{"identifier":"scope-cache-index","description":"This scope permits to list all files and folders in the `$CACHE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"}]}},"scope-cache-recursive":{"identifier":"scope-cache-recursive","description":"This scope permits recursive access to the complete `$CACHE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"},{"path":"$CACHE/**"}]}},"scope-config":{"identifier":"scope-config","description":"This scope permits access to all files and list content of top level directories in the `$CONFIG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"},{"path":"$CONFIG/*"}]}},"scope-config-index":{"identifier":"scope-config-index","description":"This scope permits to list all files and folders in the `$CONFIG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"}]}},"scope-config-recursive":{"identifier":"scope-config-recursive","description":"This scope permits recursive access to the complete `$CONFIG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"},{"path":"$CONFIG/**"}]}},"scope-data":{"identifier":"scope-data","description":"This scope permits access to all files and list content of top level directories in the `$DATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"},{"path":"$DATA/*"}]}},"scope-data-index":{"identifier":"scope-data-index","description":"This scope permits to list all files and folders in the `$DATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"}]}},"scope-data-recursive":{"identifier":"scope-data-recursive","description":"This scope permits recursive access to the complete `$DATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"},{"path":"$DATA/**"}]}},"scope-desktop":{"identifier":"scope-desktop","description":"This scope permits access to all files and list content of top level directories in the `$DESKTOP` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"},{"path":"$DESKTOP/*"}]}},"scope-desktop-index":{"identifier":"scope-desktop-index","description":"This scope permits to list all files and folders in the `$DESKTOP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"}]}},"scope-desktop-recursive":{"identifier":"scope-desktop-recursive","description":"This scope permits recursive access to the complete `$DESKTOP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"},{"path":"$DESKTOP/**"}]}},"scope-document":{"identifier":"scope-document","description":"This scope permits access to all files and list content of top level directories in the `$DOCUMENT` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"},{"path":"$DOCUMENT/*"}]}},"scope-document-index":{"identifier":"scope-document-index","description":"This scope permits to list all files and folders in the `$DOCUMENT`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"}]}},"scope-document-recursive":{"identifier":"scope-document-recursive","description":"This scope permits recursive access to the complete `$DOCUMENT` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"},{"path":"$DOCUMENT/**"}]}},"scope-download":{"identifier":"scope-download","description":"This scope permits access to all files and list content of top level directories in the `$DOWNLOAD` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"},{"path":"$DOWNLOAD/*"}]}},"scope-download-index":{"identifier":"scope-download-index","description":"This scope permits to list all files and folders in the `$DOWNLOAD`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"}]}},"scope-download-recursive":{"identifier":"scope-download-recursive","description":"This scope permits recursive access to the complete `$DOWNLOAD` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"},{"path":"$DOWNLOAD/**"}]}},"scope-exe":{"identifier":"scope-exe","description":"This scope permits access to all files and list content of top level directories in the `$EXE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"},{"path":"$EXE/*"}]}},"scope-exe-index":{"identifier":"scope-exe-index","description":"This scope permits to list all files and folders in the `$EXE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"}]}},"scope-exe-recursive":{"identifier":"scope-exe-recursive","description":"This scope permits recursive access to the complete `$EXE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"},{"path":"$EXE/**"}]}},"scope-font":{"identifier":"scope-font","description":"This scope permits access to all files and list content of top level directories in the `$FONT` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"},{"path":"$FONT/*"}]}},"scope-font-index":{"identifier":"scope-font-index","description":"This scope permits to list all files and folders in the `$FONT`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"}]}},"scope-font-recursive":{"identifier":"scope-font-recursive","description":"This scope permits recursive access to the complete `$FONT` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"},{"path":"$FONT/**"}]}},"scope-home":{"identifier":"scope-home","description":"This scope permits access to all files and list content of top level directories in the `$HOME` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"},{"path":"$HOME/*"}]}},"scope-home-index":{"identifier":"scope-home-index","description":"This scope permits to list all files and folders in the `$HOME`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"}]}},"scope-home-recursive":{"identifier":"scope-home-recursive","description":"This scope permits recursive access to the complete `$HOME` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"},{"path":"$HOME/**"}]}},"scope-localdata":{"identifier":"scope-localdata","description":"This scope permits access to all files and list content of top level directories in the `$LOCALDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"},{"path":"$LOCALDATA/*"}]}},"scope-localdata-index":{"identifier":"scope-localdata-index","description":"This scope permits to list all files and folders in the `$LOCALDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"}]}},"scope-localdata-recursive":{"identifier":"scope-localdata-recursive","description":"This scope permits recursive access to the complete `$LOCALDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"},{"path":"$LOCALDATA/**"}]}},"scope-log":{"identifier":"scope-log","description":"This scope permits access to all files and list content of top level directories in the `$LOG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"},{"path":"$LOG/*"}]}},"scope-log-index":{"identifier":"scope-log-index","description":"This scope permits to list all files and folders in the `$LOG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"}]}},"scope-log-recursive":{"identifier":"scope-log-recursive","description":"This scope permits recursive access to the complete `$LOG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"},{"path":"$LOG/**"}]}},"scope-picture":{"identifier":"scope-picture","description":"This scope permits access to all files and list content of top level directories in the `$PICTURE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"},{"path":"$PICTURE/*"}]}},"scope-picture-index":{"identifier":"scope-picture-index","description":"This scope permits to list all files and folders in the `$PICTURE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"}]}},"scope-picture-recursive":{"identifier":"scope-picture-recursive","description":"This scope permits recursive access to the complete `$PICTURE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"},{"path":"$PICTURE/**"}]}},"scope-public":{"identifier":"scope-public","description":"This scope permits access to all files and list content of top level directories in the `$PUBLIC` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"},{"path":"$PUBLIC/*"}]}},"scope-public-index":{"identifier":"scope-public-index","description":"This scope permits to list all files and folders in the `$PUBLIC`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"}]}},"scope-public-recursive":{"identifier":"scope-public-recursive","description":"This scope permits recursive access to the complete `$PUBLIC` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"},{"path":"$PUBLIC/**"}]}},"scope-resource":{"identifier":"scope-resource","description":"This scope permits access to all files and list content of top level directories in the `$RESOURCE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"},{"path":"$RESOURCE/*"}]}},"scope-resource-index":{"identifier":"scope-resource-index","description":"This scope permits to list all files and folders in the `$RESOURCE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"}]}},"scope-resource-recursive":{"identifier":"scope-resource-recursive","description":"This scope permits recursive access to the complete `$RESOURCE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"},{"path":"$RESOURCE/**"}]}},"scope-runtime":{"identifier":"scope-runtime","description":"This scope permits access to all files and list content of top level directories in the `$RUNTIME` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"},{"path":"$RUNTIME/*"}]}},"scope-runtime-index":{"identifier":"scope-runtime-index","description":"This scope permits to list all files and folders in the `$RUNTIME`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"}]}},"scope-runtime-recursive":{"identifier":"scope-runtime-recursive","description":"This scope permits recursive access to the complete `$RUNTIME` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"},{"path":"$RUNTIME/**"}]}},"scope-temp":{"identifier":"scope-temp","description":"This scope permits access to all files and list content of top level directories in the `$TEMP` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"},{"path":"$TEMP/*"}]}},"scope-temp-index":{"identifier":"scope-temp-index","description":"This scope permits to list all files and folders in the `$TEMP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"}]}},"scope-temp-recursive":{"identifier":"scope-temp-recursive","description":"This scope permits recursive access to the complete `$TEMP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"},{"path":"$TEMP/**"}]}},"scope-template":{"identifier":"scope-template","description":"This scope permits access to all files and list content of top level directories in the `$TEMPLATE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"},{"path":"$TEMPLATE/*"}]}},"scope-template-index":{"identifier":"scope-template-index","description":"This scope permits to list all files and folders in the `$TEMPLATE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"}]}},"scope-template-recursive":{"identifier":"scope-template-recursive","description":"This scope permits recursive access to the complete `$TEMPLATE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"},{"path":"$TEMPLATE/**"}]}},"scope-video":{"identifier":"scope-video","description":"This scope permits access to all files and list content of top level directories in the `$VIDEO` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"},{"path":"$VIDEO/*"}]}},"scope-video-index":{"identifier":"scope-video-index","description":"This scope permits to list all files and folders in the `$VIDEO`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"}]}},"scope-video-recursive":{"identifier":"scope-video-recursive","description":"This scope permits recursive access to the complete `$VIDEO` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"},{"path":"$VIDEO/**"}]}},"write-all":{"identifier":"write-all","description":"This enables all write related commands without any pre-configured accessible paths.","commands":{"allow":["mkdir","create","copy_file","remove","rename","truncate","ftruncate","write","write_file","write_text_file"],"deny":[]}},"write-files":{"identifier":"write-files","description":"This enables all file write related commands without any pre-configured accessible paths.","commands":{"allow":["create","copy_file","remove","rename","truncate","ftruncate","write","write_file","write_text_file"],"deny":[]}}},"permission_sets":{"allow-app-meta":{"identifier":"allow-app-meta","description":"This allows non-recursive read access to metadata of the application folders, including file listing and statistics.","permissions":["read-meta","scope-app-index"]},"allow-app-meta-recursive":{"identifier":"allow-app-meta-recursive","description":"This allows full recursive read access to metadata of the application folders, including file listing and statistics.","permissions":["read-meta","scope-app-recursive"]},"allow-app-read":{"identifier":"allow-app-read","description":"This allows non-recursive read access to the application folders.","permissions":["read-all","scope-app"]},"allow-app-read-recursive":{"identifier":"allow-app-read-recursive","description":"This allows full recursive read access to the complete application folders, files and subdirectories.","permissions":["read-all","scope-app-recursive"]},"allow-app-write":{"identifier":"allow-app-write","description":"This allows non-recursive write access to the application folders.","permissions":["write-all","scope-app"]},"allow-app-write-recursive":{"identifier":"allow-app-write-recursive","description":"This allows full recursive write access to the complete application folders, files and subdirectories.","permissions":["write-all","scope-app-recursive"]},"allow-appcache-meta":{"identifier":"allow-appcache-meta","description":"This allows non-recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-appcache-index"]},"allow-appcache-meta-recursive":{"identifier":"allow-appcache-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-appcache-recursive"]},"allow-appcache-read":{"identifier":"allow-appcache-read","description":"This allows non-recursive read access to the `$APPCACHE` folder.","permissions":["read-all","scope-appcache"]},"allow-appcache-read-recursive":{"identifier":"allow-appcache-read-recursive","description":"This allows full recursive read access to the complete `$APPCACHE` folder, files and subdirectories.","permissions":["read-all","scope-appcache-recursive"]},"allow-appcache-write":{"identifier":"allow-appcache-write","description":"This allows non-recursive write access to the `$APPCACHE` folder.","permissions":["write-all","scope-appcache"]},"allow-appcache-write-recursive":{"identifier":"allow-appcache-write-recursive","description":"This allows full recursive write access to the complete `$APPCACHE` folder, files and subdirectories.","permissions":["write-all","scope-appcache-recursive"]},"allow-appconfig-meta":{"identifier":"allow-appconfig-meta","description":"This allows non-recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-appconfig-index"]},"allow-appconfig-meta-recursive":{"identifier":"allow-appconfig-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-appconfig-recursive"]},"allow-appconfig-read":{"identifier":"allow-appconfig-read","description":"This allows non-recursive read access to the `$APPCONFIG` folder.","permissions":["read-all","scope-appconfig"]},"allow-appconfig-read-recursive":{"identifier":"allow-appconfig-read-recursive","description":"This allows full recursive read access to the complete `$APPCONFIG` folder, files and subdirectories.","permissions":["read-all","scope-appconfig-recursive"]},"allow-appconfig-write":{"identifier":"allow-appconfig-write","description":"This allows non-recursive write access to the `$APPCONFIG` folder.","permissions":["write-all","scope-appconfig"]},"allow-appconfig-write-recursive":{"identifier":"allow-appconfig-write-recursive","description":"This allows full recursive write access to the complete `$APPCONFIG` folder, files and subdirectories.","permissions":["write-all","scope-appconfig-recursive"]},"allow-appdata-meta":{"identifier":"allow-appdata-meta","description":"This allows non-recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-appdata-index"]},"allow-appdata-meta-recursive":{"identifier":"allow-appdata-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-appdata-recursive"]},"allow-appdata-read":{"identifier":"allow-appdata-read","description":"This allows non-recursive read access to the `$APPDATA` folder.","permissions":["read-all","scope-appdata"]},"allow-appdata-read-recursive":{"identifier":"allow-appdata-read-recursive","description":"This allows full recursive read access to the complete `$APPDATA` folder, files and subdirectories.","permissions":["read-all","scope-appdata-recursive"]},"allow-appdata-write":{"identifier":"allow-appdata-write","description":"This allows non-recursive write access to the `$APPDATA` folder.","permissions":["write-all","scope-appdata"]},"allow-appdata-write-recursive":{"identifier":"allow-appdata-write-recursive","description":"This allows full recursive write access to the complete `$APPDATA` folder, files and subdirectories.","permissions":["write-all","scope-appdata-recursive"]},"allow-applocaldata-meta":{"identifier":"allow-applocaldata-meta","description":"This allows non-recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-applocaldata-index"]},"allow-applocaldata-meta-recursive":{"identifier":"allow-applocaldata-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-applocaldata-recursive"]},"allow-applocaldata-read":{"identifier":"allow-applocaldata-read","description":"This allows non-recursive read access to the `$APPLOCALDATA` folder.","permissions":["read-all","scope-applocaldata"]},"allow-applocaldata-read-recursive":{"identifier":"allow-applocaldata-read-recursive","description":"This allows full recursive read access to the complete `$APPLOCALDATA` folder, files and subdirectories.","permissions":["read-all","scope-applocaldata-recursive"]},"allow-applocaldata-write":{"identifier":"allow-applocaldata-write","description":"This allows non-recursive write access to the `$APPLOCALDATA` folder.","permissions":["write-all","scope-applocaldata"]},"allow-applocaldata-write-recursive":{"identifier":"allow-applocaldata-write-recursive","description":"This allows full recursive write access to the complete `$APPLOCALDATA` folder, files and subdirectories.","permissions":["write-all","scope-applocaldata-recursive"]},"allow-applog-meta":{"identifier":"allow-applog-meta","description":"This allows non-recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.","permissions":["read-meta","scope-applog-index"]},"allow-applog-meta-recursive":{"identifier":"allow-applog-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.","permissions":["read-meta","scope-applog-recursive"]},"allow-applog-read":{"identifier":"allow-applog-read","description":"This allows non-recursive read access to the `$APPLOG` folder.","permissions":["read-all","scope-applog"]},"allow-applog-read-recursive":{"identifier":"allow-applog-read-recursive","description":"This allows full recursive read access to the complete `$APPLOG` folder, files and subdirectories.","permissions":["read-all","scope-applog-recursive"]},"allow-applog-write":{"identifier":"allow-applog-write","description":"This allows non-recursive write access to the `$APPLOG` folder.","permissions":["write-all","scope-applog"]},"allow-applog-write-recursive":{"identifier":"allow-applog-write-recursive","description":"This allows full recursive write access to the complete `$APPLOG` folder, files and subdirectories.","permissions":["write-all","scope-applog-recursive"]},"allow-audio-meta":{"identifier":"allow-audio-meta","description":"This allows non-recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.","permissions":["read-meta","scope-audio-index"]},"allow-audio-meta-recursive":{"identifier":"allow-audio-meta-recursive","description":"This allows full recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.","permissions":["read-meta","scope-audio-recursive"]},"allow-audio-read":{"identifier":"allow-audio-read","description":"This allows non-recursive read access to the `$AUDIO` folder.","permissions":["read-all","scope-audio"]},"allow-audio-read-recursive":{"identifier":"allow-audio-read-recursive","description":"This allows full recursive read access to the complete `$AUDIO` folder, files and subdirectories.","permissions":["read-all","scope-audio-recursive"]},"allow-audio-write":{"identifier":"allow-audio-write","description":"This allows non-recursive write access to the `$AUDIO` folder.","permissions":["write-all","scope-audio"]},"allow-audio-write-recursive":{"identifier":"allow-audio-write-recursive","description":"This allows full recursive write access to the complete `$AUDIO` folder, files and subdirectories.","permissions":["write-all","scope-audio-recursive"]},"allow-cache-meta":{"identifier":"allow-cache-meta","description":"This allows non-recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-cache-index"]},"allow-cache-meta-recursive":{"identifier":"allow-cache-meta-recursive","description":"This allows full recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-cache-recursive"]},"allow-cache-read":{"identifier":"allow-cache-read","description":"This allows non-recursive read access to the `$CACHE` folder.","permissions":["read-all","scope-cache"]},"allow-cache-read-recursive":{"identifier":"allow-cache-read-recursive","description":"This allows full recursive read access to the complete `$CACHE` folder, files and subdirectories.","permissions":["read-all","scope-cache-recursive"]},"allow-cache-write":{"identifier":"allow-cache-write","description":"This allows non-recursive write access to the `$CACHE` folder.","permissions":["write-all","scope-cache"]},"allow-cache-write-recursive":{"identifier":"allow-cache-write-recursive","description":"This allows full recursive write access to the complete `$CACHE` folder, files and subdirectories.","permissions":["write-all","scope-cache-recursive"]},"allow-config-meta":{"identifier":"allow-config-meta","description":"This allows non-recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-config-index"]},"allow-config-meta-recursive":{"identifier":"allow-config-meta-recursive","description":"This allows full recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-config-recursive"]},"allow-config-read":{"identifier":"allow-config-read","description":"This allows non-recursive read access to the `$CONFIG` folder.","permissions":["read-all","scope-config"]},"allow-config-read-recursive":{"identifier":"allow-config-read-recursive","description":"This allows full recursive read access to the complete `$CONFIG` folder, files and subdirectories.","permissions":["read-all","scope-config-recursive"]},"allow-config-write":{"identifier":"allow-config-write","description":"This allows non-recursive write access to the `$CONFIG` folder.","permissions":["write-all","scope-config"]},"allow-config-write-recursive":{"identifier":"allow-config-write-recursive","description":"This allows full recursive write access to the complete `$CONFIG` folder, files and subdirectories.","permissions":["write-all","scope-config-recursive"]},"allow-data-meta":{"identifier":"allow-data-meta","description":"This allows non-recursive read access to metadata of the `$DATA` folder, including file listing and statistics.","permissions":["read-meta","scope-data-index"]},"allow-data-meta-recursive":{"identifier":"allow-data-meta-recursive","description":"This allows full recursive read access to metadata of the `$DATA` folder, including file listing and statistics.","permissions":["read-meta","scope-data-recursive"]},"allow-data-read":{"identifier":"allow-data-read","description":"This allows non-recursive read access to the `$DATA` folder.","permissions":["read-all","scope-data"]},"allow-data-read-recursive":{"identifier":"allow-data-read-recursive","description":"This allows full recursive read access to the complete `$DATA` folder, files and subdirectories.","permissions":["read-all","scope-data-recursive"]},"allow-data-write":{"identifier":"allow-data-write","description":"This allows non-recursive write access to the `$DATA` folder.","permissions":["write-all","scope-data"]},"allow-data-write-recursive":{"identifier":"allow-data-write-recursive","description":"This allows full recursive write access to the complete `$DATA` folder, files and subdirectories.","permissions":["write-all","scope-data-recursive"]},"allow-desktop-meta":{"identifier":"allow-desktop-meta","description":"This allows non-recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.","permissions":["read-meta","scope-desktop-index"]},"allow-desktop-meta-recursive":{"identifier":"allow-desktop-meta-recursive","description":"This allows full recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.","permissions":["read-meta","scope-desktop-recursive"]},"allow-desktop-read":{"identifier":"allow-desktop-read","description":"This allows non-recursive read access to the `$DESKTOP` folder.","permissions":["read-all","scope-desktop"]},"allow-desktop-read-recursive":{"identifier":"allow-desktop-read-recursive","description":"This allows full recursive read access to the complete `$DESKTOP` folder, files and subdirectories.","permissions":["read-all","scope-desktop-recursive"]},"allow-desktop-write":{"identifier":"allow-desktop-write","description":"This allows non-recursive write access to the `$DESKTOP` folder.","permissions":["write-all","scope-desktop"]},"allow-desktop-write-recursive":{"identifier":"allow-desktop-write-recursive","description":"This allows full recursive write access to the complete `$DESKTOP` folder, files and subdirectories.","permissions":["write-all","scope-desktop-recursive"]},"allow-document-meta":{"identifier":"allow-document-meta","description":"This allows non-recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.","permissions":["read-meta","scope-document-index"]},"allow-document-meta-recursive":{"identifier":"allow-document-meta-recursive","description":"This allows full recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.","permissions":["read-meta","scope-document-recursive"]},"allow-document-read":{"identifier":"allow-document-read","description":"This allows non-recursive read access to the `$DOCUMENT` folder.","permissions":["read-all","scope-document"]},"allow-document-read-recursive":{"identifier":"allow-document-read-recursive","description":"This allows full recursive read access to the complete `$DOCUMENT` folder, files and subdirectories.","permissions":["read-all","scope-document-recursive"]},"allow-document-write":{"identifier":"allow-document-write","description":"This allows non-recursive write access to the `$DOCUMENT` folder.","permissions":["write-all","scope-document"]},"allow-document-write-recursive":{"identifier":"allow-document-write-recursive","description":"This allows full recursive write access to the complete `$DOCUMENT` folder, files and subdirectories.","permissions":["write-all","scope-document-recursive"]},"allow-download-meta":{"identifier":"allow-download-meta","description":"This allows non-recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.","permissions":["read-meta","scope-download-index"]},"allow-download-meta-recursive":{"identifier":"allow-download-meta-recursive","description":"This allows full recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.","permissions":["read-meta","scope-download-recursive"]},"allow-download-read":{"identifier":"allow-download-read","description":"This allows non-recursive read access to the `$DOWNLOAD` folder.","permissions":["read-all","scope-download"]},"allow-download-read-recursive":{"identifier":"allow-download-read-recursive","description":"This allows full recursive read access to the complete `$DOWNLOAD` folder, files and subdirectories.","permissions":["read-all","scope-download-recursive"]},"allow-download-write":{"identifier":"allow-download-write","description":"This allows non-recursive write access to the `$DOWNLOAD` folder.","permissions":["write-all","scope-download"]},"allow-download-write-recursive":{"identifier":"allow-download-write-recursive","description":"This allows full recursive write access to the complete `$DOWNLOAD` folder, files and subdirectories.","permissions":["write-all","scope-download-recursive"]},"allow-exe-meta":{"identifier":"allow-exe-meta","description":"This allows non-recursive read access to metadata of the `$EXE` folder, including file listing and statistics.","permissions":["read-meta","scope-exe-index"]},"allow-exe-meta-recursive":{"identifier":"allow-exe-meta-recursive","description":"This allows full recursive read access to metadata of the `$EXE` folder, including file listing and statistics.","permissions":["read-meta","scope-exe-recursive"]},"allow-exe-read":{"identifier":"allow-exe-read","description":"This allows non-recursive read access to the `$EXE` folder.","permissions":["read-all","scope-exe"]},"allow-exe-read-recursive":{"identifier":"allow-exe-read-recursive","description":"This allows full recursive read access to the complete `$EXE` folder, files and subdirectories.","permissions":["read-all","scope-exe-recursive"]},"allow-exe-write":{"identifier":"allow-exe-write","description":"This allows non-recursive write access to the `$EXE` folder.","permissions":["write-all","scope-exe"]},"allow-exe-write-recursive":{"identifier":"allow-exe-write-recursive","description":"This allows full recursive write access to the complete `$EXE` folder, files and subdirectories.","permissions":["write-all","scope-exe-recursive"]},"allow-font-meta":{"identifier":"allow-font-meta","description":"This allows non-recursive read access to metadata of the `$FONT` folder, including file listing and statistics.","permissions":["read-meta","scope-font-index"]},"allow-font-meta-recursive":{"identifier":"allow-font-meta-recursive","description":"This allows full recursive read access to metadata of the `$FONT` folder, including file listing and statistics.","permissions":["read-meta","scope-font-recursive"]},"allow-font-read":{"identifier":"allow-font-read","description":"This allows non-recursive read access to the `$FONT` folder.","permissions":["read-all","scope-font"]},"allow-font-read-recursive":{"identifier":"allow-font-read-recursive","description":"This allows full recursive read access to the complete `$FONT` folder, files and subdirectories.","permissions":["read-all","scope-font-recursive"]},"allow-font-write":{"identifier":"allow-font-write","description":"This allows non-recursive write access to the `$FONT` folder.","permissions":["write-all","scope-font"]},"allow-font-write-recursive":{"identifier":"allow-font-write-recursive","description":"This allows full recursive write access to the complete `$FONT` folder, files and subdirectories.","permissions":["write-all","scope-font-recursive"]},"allow-home-meta":{"identifier":"allow-home-meta","description":"This allows non-recursive read access to metadata of the `$HOME` folder, including file listing and statistics.","permissions":["read-meta","scope-home-index"]},"allow-home-meta-recursive":{"identifier":"allow-home-meta-recursive","description":"This allows full recursive read access to metadata of the `$HOME` folder, including file listing and statistics.","permissions":["read-meta","scope-home-recursive"]},"allow-home-read":{"identifier":"allow-home-read","description":"This allows non-recursive read access to the `$HOME` folder.","permissions":["read-all","scope-home"]},"allow-home-read-recursive":{"identifier":"allow-home-read-recursive","description":"This allows full recursive read access to the complete `$HOME` folder, files and subdirectories.","permissions":["read-all","scope-home-recursive"]},"allow-home-write":{"identifier":"allow-home-write","description":"This allows non-recursive write access to the `$HOME` folder.","permissions":["write-all","scope-home"]},"allow-home-write-recursive":{"identifier":"allow-home-write-recursive","description":"This allows full recursive write access to the complete `$HOME` folder, files and subdirectories.","permissions":["write-all","scope-home-recursive"]},"allow-localdata-meta":{"identifier":"allow-localdata-meta","description":"This allows non-recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-localdata-index"]},"allow-localdata-meta-recursive":{"identifier":"allow-localdata-meta-recursive","description":"This allows full recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-localdata-recursive"]},"allow-localdata-read":{"identifier":"allow-localdata-read","description":"This allows non-recursive read access to the `$LOCALDATA` folder.","permissions":["read-all","scope-localdata"]},"allow-localdata-read-recursive":{"identifier":"allow-localdata-read-recursive","description":"This allows full recursive read access to the complete `$LOCALDATA` folder, files and subdirectories.","permissions":["read-all","scope-localdata-recursive"]},"allow-localdata-write":{"identifier":"allow-localdata-write","description":"This allows non-recursive write access to the `$LOCALDATA` folder.","permissions":["write-all","scope-localdata"]},"allow-localdata-write-recursive":{"identifier":"allow-localdata-write-recursive","description":"This allows full recursive write access to the complete `$LOCALDATA` folder, files and subdirectories.","permissions":["write-all","scope-localdata-recursive"]},"allow-log-meta":{"identifier":"allow-log-meta","description":"This allows non-recursive read access to metadata of the `$LOG` folder, including file listing and statistics.","permissions":["read-meta","scope-log-index"]},"allow-log-meta-recursive":{"identifier":"allow-log-meta-recursive","description":"This allows full recursive read access to metadata of the `$LOG` folder, including file listing and statistics.","permissions":["read-meta","scope-log-recursive"]},"allow-log-read":{"identifier":"allow-log-read","description":"This allows non-recursive read access to the `$LOG` folder.","permissions":["read-all","scope-log"]},"allow-log-read-recursive":{"identifier":"allow-log-read-recursive","description":"This allows full recursive read access to the complete `$LOG` folder, files and subdirectories.","permissions":["read-all","scope-log-recursive"]},"allow-log-write":{"identifier":"allow-log-write","description":"This allows non-recursive write access to the `$LOG` folder.","permissions":["write-all","scope-log"]},"allow-log-write-recursive":{"identifier":"allow-log-write-recursive","description":"This allows full recursive write access to the complete `$LOG` folder, files and subdirectories.","permissions":["write-all","scope-log-recursive"]},"allow-picture-meta":{"identifier":"allow-picture-meta","description":"This allows non-recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.","permissions":["read-meta","scope-picture-index"]},"allow-picture-meta-recursive":{"identifier":"allow-picture-meta-recursive","description":"This allows full recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.","permissions":["read-meta","scope-picture-recursive"]},"allow-picture-read":{"identifier":"allow-picture-read","description":"This allows non-recursive read access to the `$PICTURE` folder.","permissions":["read-all","scope-picture"]},"allow-picture-read-recursive":{"identifier":"allow-picture-read-recursive","description":"This allows full recursive read access to the complete `$PICTURE` folder, files and subdirectories.","permissions":["read-all","scope-picture-recursive"]},"allow-picture-write":{"identifier":"allow-picture-write","description":"This allows non-recursive write access to the `$PICTURE` folder.","permissions":["write-all","scope-picture"]},"allow-picture-write-recursive":{"identifier":"allow-picture-write-recursive","description":"This allows full recursive write access to the complete `$PICTURE` folder, files and subdirectories.","permissions":["write-all","scope-picture-recursive"]},"allow-public-meta":{"identifier":"allow-public-meta","description":"This allows non-recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.","permissions":["read-meta","scope-public-index"]},"allow-public-meta-recursive":{"identifier":"allow-public-meta-recursive","description":"This allows full recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.","permissions":["read-meta","scope-public-recursive"]},"allow-public-read":{"identifier":"allow-public-read","description":"This allows non-recursive read access to the `$PUBLIC` folder.","permissions":["read-all","scope-public"]},"allow-public-read-recursive":{"identifier":"allow-public-read-recursive","description":"This allows full recursive read access to the complete `$PUBLIC` folder, files and subdirectories.","permissions":["read-all","scope-public-recursive"]},"allow-public-write":{"identifier":"allow-public-write","description":"This allows non-recursive write access to the `$PUBLIC` folder.","permissions":["write-all","scope-public"]},"allow-public-write-recursive":{"identifier":"allow-public-write-recursive","description":"This allows full recursive write access to the complete `$PUBLIC` folder, files and subdirectories.","permissions":["write-all","scope-public-recursive"]},"allow-resource-meta":{"identifier":"allow-resource-meta","description":"This allows non-recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.","permissions":["read-meta","scope-resource-index"]},"allow-resource-meta-recursive":{"identifier":"allow-resource-meta-recursive","description":"This allows full recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.","permissions":["read-meta","scope-resource-recursive"]},"allow-resource-read":{"identifier":"allow-resource-read","description":"This allows non-recursive read access to the `$RESOURCE` folder.","permissions":["read-all","scope-resource"]},"allow-resource-read-recursive":{"identifier":"allow-resource-read-recursive","description":"This allows full recursive read access to the complete `$RESOURCE` folder, files and subdirectories.","permissions":["read-all","scope-resource-recursive"]},"allow-resource-write":{"identifier":"allow-resource-write","description":"This allows non-recursive write access to the `$RESOURCE` folder.","permissions":["write-all","scope-resource"]},"allow-resource-write-recursive":{"identifier":"allow-resource-write-recursive","description":"This allows full recursive write access to the complete `$RESOURCE` folder, files and subdirectories.","permissions":["write-all","scope-resource-recursive"]},"allow-runtime-meta":{"identifier":"allow-runtime-meta","description":"This allows non-recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.","permissions":["read-meta","scope-runtime-index"]},"allow-runtime-meta-recursive":{"identifier":"allow-runtime-meta-recursive","description":"This allows full recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.","permissions":["read-meta","scope-runtime-recursive"]},"allow-runtime-read":{"identifier":"allow-runtime-read","description":"This allows non-recursive read access to the `$RUNTIME` folder.","permissions":["read-all","scope-runtime"]},"allow-runtime-read-recursive":{"identifier":"allow-runtime-read-recursive","description":"This allows full recursive read access to the complete `$RUNTIME` folder, files and subdirectories.","permissions":["read-all","scope-runtime-recursive"]},"allow-runtime-write":{"identifier":"allow-runtime-write","description":"This allows non-recursive write access to the `$RUNTIME` folder.","permissions":["write-all","scope-runtime"]},"allow-runtime-write-recursive":{"identifier":"allow-runtime-write-recursive","description":"This allows full recursive write access to the complete `$RUNTIME` folder, files and subdirectories.","permissions":["write-all","scope-runtime-recursive"]},"allow-temp-meta":{"identifier":"allow-temp-meta","description":"This allows non-recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.","permissions":["read-meta","scope-temp-index"]},"allow-temp-meta-recursive":{"identifier":"allow-temp-meta-recursive","description":"This allows full recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.","permissions":["read-meta","scope-temp-recursive"]},"allow-temp-read":{"identifier":"allow-temp-read","description":"This allows non-recursive read access to the `$TEMP` folder.","permissions":["read-all","scope-temp"]},"allow-temp-read-recursive":{"identifier":"allow-temp-read-recursive","description":"This allows full recursive read access to the complete `$TEMP` folder, files and subdirectories.","permissions":["read-all","scope-temp-recursive"]},"allow-temp-write":{"identifier":"allow-temp-write","description":"This allows non-recursive write access to the `$TEMP` folder.","permissions":["write-all","scope-temp"]},"allow-temp-write-recursive":{"identifier":"allow-temp-write-recursive","description":"This allows full recursive write access to the complete `$TEMP` folder, files and subdirectories.","permissions":["write-all","scope-temp-recursive"]},"allow-template-meta":{"identifier":"allow-template-meta","description":"This allows non-recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.","permissions":["read-meta","scope-template-index"]},"allow-template-meta-recursive":{"identifier":"allow-template-meta-recursive","description":"This allows full recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.","permissions":["read-meta","scope-template-recursive"]},"allow-template-read":{"identifier":"allow-template-read","description":"This allows non-recursive read access to the `$TEMPLATE` folder.","permissions":["read-all","scope-template"]},"allow-template-read-recursive":{"identifier":"allow-template-read-recursive","description":"This allows full recursive read access to the complete `$TEMPLATE` folder, files and subdirectories.","permissions":["read-all","scope-template-recursive"]},"allow-template-write":{"identifier":"allow-template-write","description":"This allows non-recursive write access to the `$TEMPLATE` folder.","permissions":["write-all","scope-template"]},"allow-template-write-recursive":{"identifier":"allow-template-write-recursive","description":"This allows full recursive write access to the complete `$TEMPLATE` folder, files and subdirectories.","permissions":["write-all","scope-template-recursive"]},"allow-video-meta":{"identifier":"allow-video-meta","description":"This allows non-recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.","permissions":["read-meta","scope-video-index"]},"allow-video-meta-recursive":{"identifier":"allow-video-meta-recursive","description":"This allows full recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.","permissions":["read-meta","scope-video-recursive"]},"allow-video-read":{"identifier":"allow-video-read","description":"This allows non-recursive read access to the `$VIDEO` folder.","permissions":["read-all","scope-video"]},"allow-video-read-recursive":{"identifier":"allow-video-read-recursive","description":"This allows full recursive read access to the complete `$VIDEO` folder, files and subdirectories.","permissions":["read-all","scope-video-recursive"]},"allow-video-write":{"identifier":"allow-video-write","description":"This allows non-recursive write access to the `$VIDEO` folder.","permissions":["write-all","scope-video"]},"allow-video-write-recursive":{"identifier":"allow-video-write-recursive","description":"This allows full recursive write access to the complete `$VIDEO` folder, files and subdirectories.","permissions":["write-all","scope-video-recursive"]},"deny-default":{"identifier":"deny-default","description":"This denies access to dangerous Tauri relevant files and folders by default.","permissions":["deny-webview-data-linux","deny-webview-data-windows"]}},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"description":"A path that can be accessed by the webview when using the fs APIs. FS scope path pattern.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},{"properties":{"path":{"description":"A path that can be accessed by the webview when using the fs APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"}},"required":["path"],"type":"object"}],"description":"FS scope entry.","title":"FsScopeEntry"}},"http":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\nfetch operations are available from the http plugin.\n\nThis enables all fetch operations but does not\nallow explicitly any origins to be fetched. This needs to\nbe manually configured before usage.\n\n#### Granted Permissions\n\nAll fetch operations are enabled.\n\n","permissions":["allow-fetch","allow-fetch-cancel","allow-fetch-read-body","allow-fetch-send"]},"permissions":{"allow-fetch":{"identifier":"allow-fetch","description":"Enables the fetch command without any pre-configured scope.","commands":{"allow":["fetch"],"deny":[]}},"allow-fetch-cancel":{"identifier":"allow-fetch-cancel","description":"Enables the fetch_cancel command without any pre-configured scope.","commands":{"allow":["fetch_cancel"],"deny":[]}},"allow-fetch-read-body":{"identifier":"allow-fetch-read-body","description":"Enables the fetch_read_body command without any pre-configured scope.","commands":{"allow":["fetch_read_body"],"deny":[]}},"allow-fetch-send":{"identifier":"allow-fetch-send","description":"Enables the fetch_send command without any pre-configured scope.","commands":{"allow":["fetch_send"],"deny":[]}},"deny-fetch":{"identifier":"deny-fetch","description":"Denies the fetch command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch"]}},"deny-fetch-cancel":{"identifier":"deny-fetch-cancel","description":"Denies the fetch_cancel command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_cancel"]}},"deny-fetch-read-body":{"identifier":"deny-fetch-read-body","description":"Denies the fetch_read_body command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_read_body"]}},"deny-fetch-send":{"identifier":"deny-fetch-send","description":"Denies the fetch_send command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_send"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"description":"A URL that can be accessed by the webview when using the HTTP APIs. Wildcards can be used following the URL pattern standard.\n\nSee [the URL Pattern spec](https://urlpattern.spec.whatwg.org/) for more information.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin on port 443\n\n- \"https://*:*\" : allows all HTTPS origin on any port\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"},{"properties":{"url":{"description":"A URL that can be accessed by the webview when using the HTTP APIs. Wildcards can be used following the URL pattern standard.\n\nSee [the URL Pattern spec](https://urlpattern.spec.whatwg.org/) for more information.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin on port 443\n\n- \"https://*:*\" : allows all HTTPS origin on any port\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"}},"required":["url"],"type":"object"}],"description":"HTTP scope entry.","title":"HttpScopeEntry"}},"notification":{"default_permission":{"identifier":"default","description":"This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n","permissions":["allow-is-permission-granted","allow-request-permission","allow-notify","allow-register-action-types","allow-register-listener","allow-cancel","allow-get-pending","allow-remove-active","allow-get-active","allow-check-permissions","allow-show","allow-batch","allow-list-channels","allow-delete-channel","allow-create-channel","allow-permission-state"]},"permissions":{"allow-batch":{"identifier":"allow-batch","description":"Enables the batch command without any pre-configured scope.","commands":{"allow":["batch"],"deny":[]}},"allow-cancel":{"identifier":"allow-cancel","description":"Enables the cancel command without any pre-configured scope.","commands":{"allow":["cancel"],"deny":[]}},"allow-check-permissions":{"identifier":"allow-check-permissions","description":"Enables the check_permissions command without any pre-configured scope.","commands":{"allow":["check_permissions"],"deny":[]}},"allow-create-channel":{"identifier":"allow-create-channel","description":"Enables the create_channel command without any pre-configured scope.","commands":{"allow":["create_channel"],"deny":[]}},"allow-delete-channel":{"identifier":"allow-delete-channel","description":"Enables the delete_channel command without any pre-configured scope.","commands":{"allow":["delete_channel"],"deny":[]}},"allow-get-active":{"identifier":"allow-get-active","description":"Enables the get_active command without any pre-configured scope.","commands":{"allow":["get_active"],"deny":[]}},"allow-get-pending":{"identifier":"allow-get-pending","description":"Enables the get_pending command without any pre-configured scope.","commands":{"allow":["get_pending"],"deny":[]}},"allow-is-permission-granted":{"identifier":"allow-is-permission-granted","description":"Enables the is_permission_granted command without any pre-configured scope.","commands":{"allow":["is_permission_granted"],"deny":[]}},"allow-list-channels":{"identifier":"allow-list-channels","description":"Enables the list_channels command without any pre-configured scope.","commands":{"allow":["list_channels"],"deny":[]}},"allow-notify":{"identifier":"allow-notify","description":"Enables the notify command without any pre-configured scope.","commands":{"allow":["notify"],"deny":[]}},"allow-permission-state":{"identifier":"allow-permission-state","description":"Enables the permission_state command without any pre-configured scope.","commands":{"allow":["permission_state"],"deny":[]}},"allow-register-action-types":{"identifier":"allow-register-action-types","description":"Enables the register_action_types command without any pre-configured scope.","commands":{"allow":["register_action_types"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-active":{"identifier":"allow-remove-active","description":"Enables the remove_active command without any pre-configured scope.","commands":{"allow":["remove_active"],"deny":[]}},"allow-request-permission":{"identifier":"allow-request-permission","description":"Enables the request_permission command without any pre-configured scope.","commands":{"allow":["request_permission"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"deny-batch":{"identifier":"deny-batch","description":"Denies the batch command without any pre-configured scope.","commands":{"allow":[],"deny":["batch"]}},"deny-cancel":{"identifier":"deny-cancel","description":"Denies the cancel command without any pre-configured scope.","commands":{"allow":[],"deny":["cancel"]}},"deny-check-permissions":{"identifier":"deny-check-permissions","description":"Denies the check_permissions command without any pre-configured scope.","commands":{"allow":[],"deny":["check_permissions"]}},"deny-create-channel":{"identifier":"deny-create-channel","description":"Denies the create_channel command without any pre-configured scope.","commands":{"allow":[],"deny":["create_channel"]}},"deny-delete-channel":{"identifier":"deny-delete-channel","description":"Denies the delete_channel command without any pre-configured scope.","commands":{"allow":[],"deny":["delete_channel"]}},"deny-get-active":{"identifier":"deny-get-active","description":"Denies the get_active command without any pre-configured scope.","commands":{"allow":[],"deny":["get_active"]}},"deny-get-pending":{"identifier":"deny-get-pending","description":"Denies the get_pending command without any pre-configured scope.","commands":{"allow":[],"deny":["get_pending"]}},"deny-is-permission-granted":{"identifier":"deny-is-permission-granted","description":"Denies the is_permission_granted command without any pre-configured scope.","commands":{"allow":[],"deny":["is_permission_granted"]}},"deny-list-channels":{"identifier":"deny-list-channels","description":"Denies the list_channels command without any pre-configured scope.","commands":{"allow":[],"deny":["list_channels"]}},"deny-notify":{"identifier":"deny-notify","description":"Denies the notify command without any pre-configured scope.","commands":{"allow":[],"deny":["notify"]}},"deny-permission-state":{"identifier":"deny-permission-state","description":"Denies the permission_state command without any pre-configured scope.","commands":{"allow":[],"deny":["permission_state"]}},"deny-register-action-types":{"identifier":"deny-register-action-types","description":"Denies the register_action_types command without any pre-configured scope.","commands":{"allow":[],"deny":["register_action_types"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-active":{"identifier":"deny-remove-active","description":"Denies the remove_active command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_active"]}},"deny-request-permission":{"identifier":"deny-request-permission","description":"Denies the request_permission command without any pre-configured scope.","commands":{"allow":[],"deny":["request_permission"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}}},"permission_sets":{},"global_scope_schema":null},"opener":{"default_permission":{"identifier":"default","description":"This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer","permissions":["allow-open-url","allow-reveal-item-in-dir","allow-default-urls"]},"permissions":{"allow-default-urls":{"identifier":"allow-default-urls","description":"This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"url":"mailto:*"},{"url":"tel:*"},{"url":"http://*"},{"url":"https://*"}]}},"allow-open-path":{"identifier":"allow-open-path","description":"Enables the open_path command without any pre-configured scope.","commands":{"allow":["open_path"],"deny":[]}},"allow-open-url":{"identifier":"allow-open-url","description":"Enables the open_url command without any pre-configured scope.","commands":{"allow":["open_url"],"deny":[]}},"allow-reveal-item-in-dir":{"identifier":"allow-reveal-item-in-dir","description":"Enables the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":["reveal_item_in_dir"],"deny":[]}},"deny-open-path":{"identifier":"deny-open-path","description":"Denies the open_path command without any pre-configured scope.","commands":{"allow":[],"deny":["open_path"]}},"deny-open-url":{"identifier":"deny-open-url","description":"Denies the open_url command without any pre-configured scope.","commands":{"allow":[],"deny":["open_url"]}},"deny-reveal-item-in-dir":{"identifier":"deny-reveal-item-in-dir","description":"Denies the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["reveal_item_in_dir"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this url with, for example: firefox."},"url":{"description":"A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"}},"required":["url"],"type":"object"},{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this path with, for example: xdg-open."},"path":{"description":"A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"}},"required":["path"],"type":"object"}],"definitions":{"Application":{"anyOf":[{"description":"Open in default application.","type":"null"},{"description":"If true, allow open with any application.","type":"boolean"},{"description":"Allow specific application to open with.","type":"string"}],"description":"Opener scope application."}},"description":"Opener scope entry.","title":"OpenerScopeEntry"}},"os":{"default_permission":{"identifier":"default","description":"This permission set configures which\noperating system information are available\nto gather from the frontend.\n\n#### Granted Permissions\n\nAll information except the host name are available.\n\n","permissions":["allow-arch","allow-exe-extension","allow-family","allow-locale","allow-os-type","allow-platform","allow-version"]},"permissions":{"allow-arch":{"identifier":"allow-arch","description":"Enables the arch command without any pre-configured scope.","commands":{"allow":["arch"],"deny":[]}},"allow-exe-extension":{"identifier":"allow-exe-extension","description":"Enables the exe_extension command without any pre-configured scope.","commands":{"allow":["exe_extension"],"deny":[]}},"allow-family":{"identifier":"allow-family","description":"Enables the family command without any pre-configured scope.","commands":{"allow":["family"],"deny":[]}},"allow-hostname":{"identifier":"allow-hostname","description":"Enables the hostname command without any pre-configured scope.","commands":{"allow":["hostname"],"deny":[]}},"allow-locale":{"identifier":"allow-locale","description":"Enables the locale command without any pre-configured scope.","commands":{"allow":["locale"],"deny":[]}},"allow-os-type":{"identifier":"allow-os-type","description":"Enables the os_type command without any pre-configured scope.","commands":{"allow":["os_type"],"deny":[]}},"allow-platform":{"identifier":"allow-platform","description":"Enables the platform command without any pre-configured scope.","commands":{"allow":["platform"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-arch":{"identifier":"deny-arch","description":"Denies the arch command without any pre-configured scope.","commands":{"allow":[],"deny":["arch"]}},"deny-exe-extension":{"identifier":"deny-exe-extension","description":"Denies the exe_extension command without any pre-configured scope.","commands":{"allow":[],"deny":["exe_extension"]}},"deny-family":{"identifier":"deny-family","description":"Denies the family command without any pre-configured scope.","commands":{"allow":[],"deny":["family"]}},"deny-hostname":{"identifier":"deny-hostname","description":"Denies the hostname command without any pre-configured scope.","commands":{"allow":[],"deny":["hostname"]}},"deny-locale":{"identifier":"deny-locale","description":"Denies the locale command without any pre-configured scope.","commands":{"allow":[],"deny":["locale"]}},"deny-os-type":{"identifier":"deny-os-type","description":"Denies the os_type command without any pre-configured scope.","commands":{"allow":[],"deny":["os_type"]}},"deny-platform":{"identifier":"deny-platform","description":"Denies the platform command without any pre-configured scope.","commands":{"allow":[],"deny":["platform"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"store":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n","permissions":["allow-load","allow-get-store","allow-set","allow-get","allow-has","allow-delete","allow-clear","allow-reset","allow-keys","allow-values","allow-entries","allow-length","allow-reload","allow-save"]},"permissions":{"allow-clear":{"identifier":"allow-clear","description":"Enables the clear command without any pre-configured scope.","commands":{"allow":["clear"],"deny":[]}},"allow-delete":{"identifier":"allow-delete","description":"Enables the delete command without any pre-configured scope.","commands":{"allow":["delete"],"deny":[]}},"allow-entries":{"identifier":"allow-entries","description":"Enables the entries command without any pre-configured scope.","commands":{"allow":["entries"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-get-store":{"identifier":"allow-get-store","description":"Enables the get_store command without any pre-configured scope.","commands":{"allow":["get_store"],"deny":[]}},"allow-has":{"identifier":"allow-has","description":"Enables the has command without any pre-configured scope.","commands":{"allow":["has"],"deny":[]}},"allow-keys":{"identifier":"allow-keys","description":"Enables the keys command without any pre-configured scope.","commands":{"allow":["keys"],"deny":[]}},"allow-length":{"identifier":"allow-length","description":"Enables the length command without any pre-configured scope.","commands":{"allow":["length"],"deny":[]}},"allow-load":{"identifier":"allow-load","description":"Enables the load command without any pre-configured scope.","commands":{"allow":["load"],"deny":[]}},"allow-reload":{"identifier":"allow-reload","description":"Enables the reload command without any pre-configured scope.","commands":{"allow":["reload"],"deny":[]}},"allow-reset":{"identifier":"allow-reset","description":"Enables the reset command without any pre-configured scope.","commands":{"allow":["reset"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"allow-set":{"identifier":"allow-set","description":"Enables the set command without any pre-configured scope.","commands":{"allow":["set"],"deny":[]}},"allow-values":{"identifier":"allow-values","description":"Enables the values command without any pre-configured scope.","commands":{"allow":["values"],"deny":[]}},"deny-clear":{"identifier":"deny-clear","description":"Denies the clear command without any pre-configured scope.","commands":{"allow":[],"deny":["clear"]}},"deny-delete":{"identifier":"deny-delete","description":"Denies the delete command without any pre-configured scope.","commands":{"allow":[],"deny":["delete"]}},"deny-entries":{"identifier":"deny-entries","description":"Denies the entries command without any pre-configured scope.","commands":{"allow":[],"deny":["entries"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-get-store":{"identifier":"deny-get-store","description":"Denies the get_store command without any pre-configured scope.","commands":{"allow":[],"deny":["get_store"]}},"deny-has":{"identifier":"deny-has","description":"Denies the has command without any pre-configured scope.","commands":{"allow":[],"deny":["has"]}},"deny-keys":{"identifier":"deny-keys","description":"Denies the keys command without any pre-configured scope.","commands":{"allow":[],"deny":["keys"]}},"deny-length":{"identifier":"deny-length","description":"Denies the length command without any pre-configured scope.","commands":{"allow":[],"deny":["length"]}},"deny-load":{"identifier":"deny-load","description":"Denies the load command without any pre-configured scope.","commands":{"allow":[],"deny":["load"]}},"deny-reload":{"identifier":"deny-reload","description":"Denies the reload command without any pre-configured scope.","commands":{"allow":[],"deny":["reload"]}},"deny-reset":{"identifier":"deny-reset","description":"Denies the reset command without any pre-configured scope.","commands":{"allow":[],"deny":["reset"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}},"deny-set":{"identifier":"deny-set","description":"Denies the set command without any pre-configured scope.","commands":{"allow":[],"deny":["set"]}},"deny-values":{"identifier":"deny-values","description":"Denies the values command without any pre-configured scope.","commands":{"allow":[],"deny":["values"]}}},"permission_sets":{},"global_scope_schema":null}} \ No newline at end of file diff --git a/src-tauri/gen/schemas/capabilities.json b/src-tauri/gen/schemas/capabilities.json index 792fa5c..6f5d73c 100644 --- a/src-tauri/gen/schemas/capabilities.json +++ b/src-tauri/gen/schemas/capabilities.json @@ -1 +1 @@ -{"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main"],"permissions":["core:default","core:webview:allow-create-webview-window","core:webview:allow-create-webview","core:webview:allow-webview-show","core:webview:default","core:window:allow-create","core:window:allow-get-all-windows","core:window:allow-show","core:window:default","dialog:default","fs:allow-appconfig-read-recursive","fs:allow-appconfig-write-recursive","fs:allow-appdata-read-recursive","fs:allow-appdata-write-recursive","fs:allow-read-file","fs:allow-read-dir","fs:allow-resource-read-recursive","fs:allow-resource-write-recursive","fs:allow-download-read-recursive","fs:allow-download-write-recursive","fs:default","android-fs:default",{"identifier":"fs:scope","allow":[{"path":"**"}]},"http:allow-fetch-send","http:allow-fetch","http:default","notification:allow-create-channel","notification:allow-list-channels","notification:allow-notify","notification:default","opener:allow-open-url","opener:default","os:allow-hostname","os:default","store:default"]}} \ No newline at end of file +{"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main"],"permissions":["core:default","core:webview:allow-create-webview-window","core:webview:allow-create-webview","core:webview:allow-webview-show","core:webview:default","core:window:allow-create","core:window:allow-get-all-windows","core:window:allow-show","core:window:default","dialog:default","fs:allow-appconfig-read-recursive","fs:allow-appconfig-write-recursive","fs:allow-appdata-read-recursive","fs:allow-appdata-write-recursive","fs:allow-read-file","fs:allow-read-dir","fs:allow-resource-read-recursive","fs:allow-resource-write-recursive","fs:allow-download-read-recursive","fs:allow-download-write-recursive","fs:default",{"identifier":"fs:scope","allow":[{"path":"**"}]},"http:allow-fetch-send","http:allow-fetch","http:default","notification:allow-create-channel","notification:allow-list-channels","notification:allow-notify","notification:default","opener:allow-open-url","opener:default","os:allow-hostname","os:default","store:default"]}} \ No newline at end of file diff --git a/src-tauri/gen/schemas/desktop-schema.json b/src-tauri/gen/schemas/desktop-schema.json index 1d9a470..b3824e5 100644 --- a/src-tauri/gen/schemas/desktop-schema.json +++ b/src-tauri/gen/schemas/desktop-schema.json @@ -2270,12 +2270,6 @@ "Identifier": { "description": "Permission identifier", "oneOf": [ - { - "description": "Default permissions for the plugin", - "type": "string", - "const": "android-fs:default", - "markdownDescription": "Default permissions for the plugin" - }, { "description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`", "type": "string", diff --git a/src-tauri/gen/schemas/linux-schema.json b/src-tauri/gen/schemas/linux-schema.json index 1d9a470..b3824e5 100644 --- a/src-tauri/gen/schemas/linux-schema.json +++ b/src-tauri/gen/schemas/linux-schema.json @@ -2270,12 +2270,6 @@ "Identifier": { "description": "Permission identifier", "oneOf": [ - { - "description": "Default permissions for the plugin", - "type": "string", - "const": "android-fs:default", - "markdownDescription": "Default permissions for the plugin" - }, { "description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`", "type": "string", diff --git a/src-tauri/src/crdt/hlc.rs b/src-tauri/src/crdt/hlc.rs index 1722217..47201d2 100644 --- a/src-tauri/src/crdt/hlc.rs +++ b/src-tauri/src/crdt/hlc.rs @@ -10,8 +10,8 @@ use std::{ sync::{Arc, Mutex}, time::Duration, }; -use tauri::{AppHandle, Wry}; -use tauri_plugin_store::{Store, StoreExt}; +use tauri::AppHandle; +use tauri_plugin_store::StoreExt; use thiserror::Error; use uhlc::{HLCBuilder, Timestamp, HLC, ID}; use uuid::Uuid; diff --git a/src-tauri/src/crdt/transformer.rs b/src-tauri/src/crdt/transformer.rs index c6dfb6d..f790ef9 100644 --- a/src-tauri/src/crdt/transformer.rs +++ b/src-tauri/src/crdt/transformer.rs @@ -755,6 +755,7 @@ impl CrdtTransformer { selection: del_stmt.selection.clone(), returning: None, or: None, + limit: None, }; } Ok(()) diff --git a/src-tauri/src/crdt/trigger.rs b/src-tauri/src/crdt/trigger.rs index e26570d..cc83f46 100644 --- a/src-tauri/src/crdt/trigger.rs +++ b/src-tauri/src/crdt/trigger.rs @@ -1,3 +1,4 @@ +// src-tauri/src/crdt/trigger.rs use crate::table_names::TABLE_CRDT_LOGS; use rusqlite::{Connection, Result as RusqliteResult, Row, Transaction}; use serde::Serialize; @@ -11,7 +12,7 @@ const UPDATE_TRIGGER_TPL: &str = "z_crdt_{TABLE_NAME}_update"; //const SYNC_ACTIVE_KEY: &str = "sync_active"; pub const TOMBSTONE_COLUMN: &str = "haex_tombstone"; -pub const HLC_TIMESTAMP_COLUMN: &str = "haex_hlc_timestamp"; +pub const HLC_TIMESTAMP_COLUMN: &str = "haex_timestamp"; #[derive(Debug)] pub enum CrdtSetupError { diff --git a/src-tauri/src/database/core.rs b/src-tauri/src/database/core.rs index deefe1b..e744caa 100644 --- a/src-tauri/src/database/core.rs +++ b/src-tauri/src/database/core.rs @@ -1,7 +1,5 @@ // src-tauri/src/database/core.rs -use std::collections::HashMap; - use crate::database::error::DatabaseError; use crate::database::DbConnection; use base64::{engine::general_purpose::STANDARD, Engine as _}; @@ -14,6 +12,7 @@ use serde_json::Value as JsonValue; use sqlparser::ast::{Query, Select, SetExpr, Statement, TableFactor, TableObject}; use sqlparser::dialect::SQLiteDialect; use sqlparser::parser::Parser; +use std::collections::HashMap; /// Öffnet und initialisiert eine Datenbank mit Verschlüsselung pub fn open_and_init_db(path: &str, key: &str, create: bool) -> Result { @@ -376,6 +375,7 @@ fn extract_tables_from_set_expr_recursive(set_expr: &SetExpr, tables: &mut Vec {} } } diff --git a/src-tauri/src/extension/core.rs b/src-tauri/src/extension/core.rs deleted file mode 100644 index 55c94ea..0000000 --- a/src-tauri/src/extension/core.rs +++ /dev/null @@ -1,528 +0,0 @@ -/// src-tauri/src/extension/core.rs -use crate::extension::database::permissions::DbExtensionPermission; -use crate::extension::error::ExtensionError; -use crate::extension::permission_manager::ExtensionPermissions; -use mime; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::fmt; -use std::fs; -use std::path::PathBuf; -use std::sync::Mutex; -use std::time::{Duration, SystemTime}; -use tauri::{ - http::{Request, Response}, - AppHandle, Error as TauriError, Manager, Runtime, UriSchemeContext, -}; - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct ExtensionManifest { - pub id: String, - pub name: String, - pub version: String, - pub author: Option, - pub entry: String, - pub icon: Option, - pub permissions: ExtensionPermissions, - pub homepage: Option, - pub description: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct ExtensionInfoResponse { - pub key_hash: String, - pub name: String, - pub full_id: String, - pub version: String, - pub display_name: Option, - pub namespace: Option, - pub allowed_origin: String, -} - -impl ExtensionInfoResponse { - pub fn from_extension(extension: &Extension) -> Self { - // Bestimme die allowed_origin basierend auf Tauri-Konfiguration - let allowed_origin = get_tauri_origin(); - - Self { - key_hash: calculate_key_hash(&extension.manifest.id), - name: extension.manifest.name.clone(), - full_id: format!( - "{}/{}@{}", - calculate_key_hash(&extension.manifest.id), - extension.manifest.name, - extension.manifest.version - ), - version: extension.manifest.version.clone(), - display_name: Some(extension.manifest.name.clone()), - namespace: extension.manifest.author.clone(), - allowed_origin, - } - } -} - -fn get_tauri_origin() -> String { - #[cfg(target_os = "windows")] - { - "https://tauri.localhost".to_string() - } - - #[cfg(target_os = "macos")] - { - "tauri://localhost".to_string() - } - - #[cfg(target_os = "linux")] - { - "tauri://localhost".to_string() - } - - #[cfg(target_os = "android")] - { - "tauri://localhost".to_string() - } - - #[cfg(target_os = "ios")] - { - "tauri://localhost".to_string() - } -} - -// Dummy-Funktion für Key Hash (du implementierst das richtig mit SHA-256) -fn calculate_key_hash(id: &str) -> String { - // TODO: Implementiere SHA-256 Hash vom Public Key - // Für jetzt nur Placeholder - format!("{:0<20}", id.chars().take(20).collect::()) -} -/// Extension source type (production vs development) -#[derive(Debug, Clone)] -pub enum ExtensionSource { - Production { - path: PathBuf, - version: String, - }, - Development { - dev_server_url: String, - manifest_path: PathBuf, - auto_reload: bool, - }, -} - -/// Complete extension data structure -#[derive(Debug, Clone)] -pub struct Extension { - pub id: String, - pub name: String, - pub source: ExtensionSource, - pub manifest: ExtensionManifest, - pub enabled: bool, - pub last_accessed: SystemTime, -} - -/// Cached permission data for performance -#[derive(Debug, Clone)] -pub struct CachedPermission { - pub permissions: Vec, - pub cached_at: SystemTime, - pub ttl: Duration, -} - -/// Enhanced extension manager -#[derive(Default)] -pub struct ExtensionManager { - pub production_extensions: Mutex>, - pub dev_extensions: Mutex>, - pub permission_cache: Mutex>, -} - -impl ExtensionManager { - pub fn new() -> Self { - Self::default() - } - - pub fn add_production_extension(&self, extension: Extension) -> Result<(), ExtensionError> { - if extension.id.is_empty() { - return Err(ExtensionError::ValidationError { - reason: "Extension ID cannot be empty".to_string(), - }); - } - - // Validate filesystem permissions - /* if let Some(fs_perms) = &extension.manifest.permissions.filesystem { - fs_perms.validate()?; - } - */ - match &extension.source { - ExtensionSource::Production { .. } => { - let mut extensions = self.production_extensions.lock().unwrap(); - extensions.insert(extension.id.clone(), extension); - Ok(()) - } - _ => Err(ExtensionError::ValidationError { - reason: "Expected Production source".to_string(), - }), - } - } - - pub fn add_dev_extension(&self, extension: Extension) -> Result<(), ExtensionError> { - if extension.id.is_empty() { - return Err(ExtensionError::ValidationError { - reason: "Extension ID cannot be empty".to_string(), - }); - } - - // Validate filesystem permissions - /* if let Some(fs_perms) = &extension.manifest.permissions.filesystem { - fs_perms.validate()?; - } */ - - match &extension.source { - ExtensionSource::Development { .. } => { - let mut extensions = self.dev_extensions.lock().unwrap(); - extensions.insert(extension.id.clone(), extension); - Ok(()) - } - _ => Err(ExtensionError::ValidationError { - reason: "Expected Development source".to_string(), - }), - } - } - - pub fn get_extension(&self, extension_id: &str) -> Option { - // Dev extensions take priority - let dev_extensions = self.dev_extensions.lock().unwrap(); - if let Some(extension) = dev_extensions.get(extension_id) { - return Some(extension.clone()); - } - - // Then check production - let prod_extensions = self.production_extensions.lock().unwrap(); - prod_extensions.get(extension_id).cloned() - } - - pub fn remove_extension(&self, extension_id: &str) -> Result<(), ExtensionError> { - { - let mut dev_extensions = self.dev_extensions.lock().unwrap(); - if dev_extensions.remove(extension_id).is_some() { - return Ok(()); - } - } - - { - let mut prod_extensions = self.production_extensions.lock().unwrap(); - if prod_extensions.remove(extension_id).is_some() { - return Ok(()); - } - } - - Err(ExtensionError::NotFound { - id: extension_id.to_string(), - }) - } -} - -// For backward compatibility -#[derive(Default)] -pub struct ExtensionState { - pub extensions: Mutex>, -} - -impl ExtensionState { - pub fn add_extension(&self, path: String, manifest: ExtensionManifest) { - let mut extensions = self.extensions.lock().unwrap(); - extensions.insert(path, manifest); - } - - pub fn get_extension(&self, addon_id: &str) -> Option { - let extensions = self.extensions.lock().unwrap(); - extensions.values().find(|p| p.name == addon_id).cloned() - } -} - -#[derive(Deserialize, Debug)] -struct ExtensionInfo { - id: String, - version: String, -} - -#[derive(Debug)] -enum DataProcessingError { - HexDecoding(hex::FromHexError), - Utf8Conversion(std::string::FromUtf8Error), - JsonParsing(serde_json::Error), -} - -// Implementierung von Display für benutzerfreundliche Fehlermeldungen -impl fmt::Display for DataProcessingError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - DataProcessingError::HexDecoding(e) => write!(f, "Hex-Dekodierungsfehler: {}", e), - DataProcessingError::Utf8Conversion(e) => { - write!(f, "UTF-8-Konvertierungsfehler: {}", e) - } - DataProcessingError::JsonParsing(e) => write!(f, "JSON-Parsing-Fehler: {}", e), - } - } -} - -// Implementierung von std::error::Error (optional, aber gute Praxis für bibliotheksähnlichen Code) -impl std::error::Error for DataProcessingError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - DataProcessingError::HexDecoding(e) => Some(e), - DataProcessingError::Utf8Conversion(e) => Some(e), - DataProcessingError::JsonParsing(e) => Some(e), - } - } -} - -// Implementierung von From-Traits für einfache Verwendung des '?'-Operators -impl From for DataProcessingError { - fn from(err: hex::FromHexError) -> Self { - DataProcessingError::HexDecoding(err) - } -} - -impl From for DataProcessingError { - fn from(err: std::string::FromUtf8Error) -> Self { - DataProcessingError::Utf8Conversion(err) - } -} - -impl From for DataProcessingError { - fn from(err: serde_json::Error) -> Self { - DataProcessingError::JsonParsing(err) - } -} - -pub fn copy_directory(source: String, destination: String) -> Result<(), String> { - println!( - "Kopiere Verzeichnis von '{}' nach '{}'", - source, destination - ); - - let source_path = PathBuf::from(&source); - let destination_path = PathBuf::from(&destination); - - if !source_path.exists() || !source_path.is_dir() { - return Err(format!( - "Quellverzeichnis '{}' nicht gefunden oder ist kein Verzeichnis.", - source - )); - } - - // Optionen für fs_extra::dir::copy - let mut options = fs_extra::dir::CopyOptions::new(); - options.overwrite = true; // Überschreibe Zieldateien, falls sie existieren - options.copy_inside = true; // Kopiere den *Inhalt* des Quellordners in den Zielordner - // options.content_only = true; // Alternative: nur Inhalt kopieren, Zielordner muss existieren - options.buffer_size = 64000; // Standard-Puffergröße, kann angepasst werden - - // Führe die Kopieroperation aus - match fs_extra::dir::copy(&source_path, &destination_path, &options) { - Ok(bytes_copied) => { - println!("Verzeichnis erfolgreich kopiert ({} bytes)", bytes_copied); - Ok(()) // Erfolg signalisieren - } - Err(e) => { - eprintln!("Fehler beim Kopieren des Verzeichnisses: {}", e); - Err(format!("Fehler beim Kopieren: {}", e.to_string())) // Fehler als String zurückgeben - } - } -} - -pub fn resolve_secure_extension_asset_path( - app_handle: &AppHandle, - extension_id: &str, - extension_version: &str, - requested_asset_path: &str, -) -> Result { - // 1. Validiere die Extension ID - if extension_id.is_empty() - || !extension_id - .chars() - .all(|c| c.is_ascii_alphanumeric() || c == '-') - { - return Err(format!("Ungültige Extension ID: {}", extension_id)); - } - - if extension_version.is_empty() - || !extension_version - .chars() - .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '.') - { - return Err(format!( - "Ungültige Extension Version: {}", - extension_version - )); - } - - // 2. Bestimme das Basisverzeichnis für alle Erweiterungen (Resource Directory) - let base_extensions_dir = app_handle - .path() - .app_data_dir() // Korrekt für Ressourcen - // Wenn du stattdessen App Local Data willst: .app_local_data_dir() - .map_err(|e: TauriError| format!("Basis-Verzeichnis nicht gefunden: {}", e))? - .join("extensions"); - - // 3. Verzeichnis für die spezifische Erweiterung - let specific_extension_dir = - base_extensions_dir.join(format!("{}/{}", extension_id, extension_version)); - - // 4. Bereinige den angeforderten Asset-Pfad - let clean_relative_path = requested_asset_path - .replace('\\', "/") - .trim_start_matches('/') - .split('/') - .filter(|&part| !part.is_empty() && part != "." && part != "..") - .collect::(); - - if clean_relative_path.as_os_str().is_empty() && requested_asset_path != "/" { - return Err("Leerer oder ungültiger Asset-Pfad".to_string()); - } - - // 5. Setze den finalen Pfad zusammen - let final_path = specific_extension_dir.join(clean_relative_path); - - // 6. SICHERHEITSCHECK (wie vorher) - match final_path.canonicalize() { - Ok(canonical_path) => { - let canonical_base = specific_extension_dir.canonicalize().map_err(|e| { - format!( - "Kann Basis-Pfad '{}' nicht kanonisieren: {}", - specific_extension_dir.display(), - e - ) - })?; - if canonical_path.starts_with(&canonical_base) { - Ok(canonical_path) - } else { - eprintln!( /* ... Sicherheitswarnung ... */ ); - Err("Ungültiger oder nicht erlaubter Asset-Pfad (kanonisch)".to_string()) - } - } - Err(_) => { - // Fehler bei canonicalize (z.B. Pfad existiert nicht) - if final_path.starts_with(&specific_extension_dir) { - Ok(final_path) // Nicht-kanonisierten Pfad zurückgeben - } else { - eprintln!( /* ... Sicherheitswarnung ... */ ); - Err("Ungültiger oder nicht erlaubter Asset-Pfad (nicht kanonisiert)".to_string()) - } - } - } -} - -pub fn extension_protocol_handler( - context: &UriSchemeContext<'_, R>, - request: &Request>, -) -> Result>, Box> { - let uri_ref = request.uri(); - println!("Protokoll Handler für: {}", uri_ref); - - let host = uri_ref - .host() - .ok_or("Kein Host (Extension ID) in URI gefunden")? - .to_string(); - - let path_str = uri_ref.path(); - let segments_iter = path_str.split('/').filter(|s| !s.is_empty()); - let resource_segments: Vec<&str> = segments_iter.collect(); - let raw_asset_path = resource_segments.join("/"); - let asset_to_load = if raw_asset_path.is_empty() { - "index.html" - } else { - &raw_asset_path - }; - - match process_hex_encoded_json(&host) { - Ok(info) => { - println!("Daten erfolgreich verarbeitet:"); - println!(" ID: {}", info.id); - println!(" Version: {}", info.version); - let absolute_secure_path = resolve_secure_extension_asset_path( - context.app_handle(), - &info.id, - &info.version, - &asset_to_load, - )?; - - println!("absolute_secure_path: {}", absolute_secure_path.display()); - - if absolute_secure_path.exists() && absolute_secure_path.is_file() { - match fs::read(&absolute_secure_path) { - Ok(content) => { - let mime_type = mime_guess::from_path(&absolute_secure_path) - .first_or(mime::APPLICATION_OCTET_STREAM) - .to_string(); - let content_length = content.len(); - println!( - "Liefere {} ({}, {} bytes) ", // Content-Length zum Log hinzugefügt - absolute_secure_path.display(), - mime_type, - content_length - ); - Response::builder() - .status(200) - .header("Content-Type", mime_type) - .header("Content-Length", content_length.to_string()) // <-- HIER HINZUGEFÜGT - // Optional, aber gut für Streaming-Fähigkeit: - .header("Accept-Ranges", "bytes") - .body(content) - .map_err(|e| e.into()) - } - Err(e) => { - eprintln!( - "Fehler beim Lesen der Datei {}: {}", - absolute_secure_path.display(), - e - ); - let status_code = if e.kind() == std::io::ErrorKind::NotFound { - 404 - } else if e.kind() == std::io::ErrorKind::PermissionDenied { - 403 - } else { - 500 - }; - - Response::builder() - .status(status_code) - .body(Vec::new()) // Leerer Body für Fehler - .map_err(|e| e.into()) // Wandle http::Error in Box um - } - } - } else { - // Datei nicht gefunden oder es ist keine Datei - eprintln!( - "Asset nicht gefunden oder ist kein File: {}", - absolute_secure_path.display() - ); - Response::builder() - .status(404) // HTTP 404 Not Found - .body(Vec::new()) - .map_err(|e| e.into()) - } - } - Err(e) => { - eprintln!("Fehler bei der Datenverarbeitung: {}", e); - - Response::builder() - .status(500) - .body(Vec::new()) // Leerer Body für Fehler - .map_err(|e| e.into()) - } - } -} - -fn process_hex_encoded_json(hex_input: &str) -> Result { - // Schritt 1: Hex-String zu Bytes dekodieren - let bytes = hex::decode(hex_input)?; // Konvertiert hex::FromHexError automatisch - - // Schritt 2: Bytes zu UTF-8-String konvertieren - let json_string = String::from_utf8(bytes)?; // Konvertiert FromUtf8Error automatisch - - // Schritt 3: JSON-String zu Struktur parsen - let extension_info: ExtensionInfo = serde_json::from_str(&json_string)?; // Konvertiert serde_json::Error automatisch - - Ok(extension_info) -} diff --git a/src-tauri/src/extension/core/manager.rs b/src-tauri/src/extension/core/manager.rs new file mode 100644 index 0000000..923f068 --- /dev/null +++ b/src-tauri/src/extension/core/manager.rs @@ -0,0 +1,311 @@ +// src-tauri/src/extension/core/manager.rs + +use crate::extension::core::manifest::{EditablePermissions, ExtensionManifest, ExtensionPreview}; +use crate::extension::core::types::{copy_directory, Extension, ExtensionSource}; +use crate::extension::crypto::ExtensionCrypto; +use crate::extension::error::ExtensionError; +use crate::extension::permissions::manager::PermissionManager; +use crate::extension::permissions::types::{ExtensionPermission, PermissionStatus}; +use crate::AppState; +use std::collections::HashMap; +use std::fs::File; +use std::path::PathBuf; +use std::sync::Mutex; +use std::time::{Duration, SystemTime}; +use tauri::{AppHandle, Manager, State}; +use zip::ZipArchive; + +#[derive(Debug, Clone)] +pub struct CachedPermission { + pub permissions: Vec, + pub cached_at: SystemTime, + pub ttl: Duration, +} + +#[derive(Default)] +pub struct ExtensionManager { + pub production_extensions: Mutex>, + pub dev_extensions: Mutex>, + pub permission_cache: Mutex>, +} + +impl ExtensionManager { + pub fn new() -> Self { + Self::default() + } + + pub fn get_base_extension_dir( + &self, + app_handle: &AppHandle, + ) -> Result { + let path = app_handle + .path() + .app_local_data_dir() + .map_err(|e| ExtensionError::Filesystem { + source: std::io::Error::new(std::io::ErrorKind::NotFound, e.to_string()), + })? + .join("extensions"); + Ok(path) + } + + pub fn get_extension_dir( + &self, + app_handle: &AppHandle, + extension_id: &str, + extension_version: &str, + ) -> Result { + let specific_extension_dir = self + .get_base_extension_dir(app_handle)? + .join(extension_id) + .join(extension_version); + + Ok(specific_extension_dir) + } + + pub fn add_production_extension(&self, extension: Extension) -> Result<(), ExtensionError> { + if extension.id.is_empty() { + return Err(ExtensionError::ValidationError { + reason: "Extension ID cannot be empty".to_string(), + }); + } + + match &extension.source { + ExtensionSource::Production { .. } => { + let mut extensions = self.production_extensions.lock().unwrap(); + extensions.insert(extension.id.clone(), extension); + Ok(()) + } + _ => Err(ExtensionError::ValidationError { + reason: "Expected Production source".to_string(), + }), + } + } + + pub fn add_dev_extension(&self, extension: Extension) -> Result<(), ExtensionError> { + if extension.id.is_empty() { + return Err(ExtensionError::ValidationError { + reason: "Extension ID cannot be empty".to_string(), + }); + } + + match &extension.source { + ExtensionSource::Development { .. } => { + let mut extensions = self.dev_extensions.lock().unwrap(); + extensions.insert(extension.id.clone(), extension); + Ok(()) + } + _ => Err(ExtensionError::ValidationError { + reason: "Expected Development source".to_string(), + }), + } + } + + pub fn get_extension(&self, extension_id: &str) -> Option { + let dev_extensions = self.dev_extensions.lock().unwrap(); + if let Some(extension) = dev_extensions.get(extension_id) { + return Some(extension.clone()); + } + + let prod_extensions = self.production_extensions.lock().unwrap(); + prod_extensions.get(extension_id).cloned() + } + + pub fn remove_extension(&self, extension_id: &str) -> Result<(), ExtensionError> { + { + let mut dev_extensions = self.dev_extensions.lock().unwrap(); + if dev_extensions.remove(extension_id).is_some() { + return Ok(()); + } + } + + { + let mut prod_extensions = self.production_extensions.lock().unwrap(); + if prod_extensions.remove(extension_id).is_some() { + return Ok(()); + } + } + + Err(ExtensionError::NotFound { + id: extension_id.to_string(), + }) + } + + pub async fn remove_extension_internal( + &self, + app_handle: &AppHandle, + extension_id: String, + extension_version: String, + state: &State<'_, AppState>, + ) -> Result<(), ExtensionError> { + PermissionManager::delete_permissions(state, &extension_id).await?; + self.remove_extension(&extension_id)?; + + let extension_dir = + self.get_extension_dir(app_handle, &extension_id, &extension_version)?; + + if extension_dir.exists() { + std::fs::remove_dir_all(&extension_dir) + .map_err(|e| ExtensionError::Filesystem { source: e })?; + } + + Ok(()) + } + + pub async fn preview_extension_internal( + &self, + source_path: String, + ) -> Result { + let source = PathBuf::from(&source_path); + + let temp = std::env::temp_dir().join(format!("haexhub_preview_{}", uuid::Uuid::new_v4())); + std::fs::create_dir_all(&temp).map_err(|e| ExtensionError::Filesystem { source: e })?; + + let file = File::open(&source).map_err(|e| ExtensionError::Filesystem { source: e })?; + let mut archive = + ZipArchive::new(file).map_err(|e| ExtensionError::InstallationFailed { + reason: format!("Invalid ZIP: {}", e), + })?; + + archive + .extract(&temp) + .map_err(|e| ExtensionError::InstallationFailed { + reason: format!("Cannot extract ZIP: {}", e), + })?; + + let manifest_path = temp.join("manifest.json"); + let manifest_content = + std::fs::read_to_string(&manifest_path).map_err(|e| ExtensionError::ManifestError { + reason: format!("Cannot read manifest: {}", e), + })?; + + let manifest: ExtensionManifest = serde_json::from_str(&manifest_content)?; + + let content_hash = ExtensionCrypto::hash_directory(&temp) + .map_err(|e| ExtensionError::SignatureVerificationFailed { reason: e })?; + + let is_valid_signature = ExtensionCrypto::verify_signature( + &manifest.public_key, + &content_hash, + &manifest.signature, + ) + .is_ok(); + + let key_hash = manifest.calculate_key_hash()?; + let editable_permissions = manifest.to_editable_permissions(); + + std::fs::remove_dir_all(&temp).ok(); + + Ok(ExtensionPreview { + manifest, + is_valid_signature, + key_hash, + editable_permissions, + }) + } + + pub async fn install_extension_with_permissions_internal( + &self, + app_handle: AppHandle, + source_path: String, + custom_permissions: EditablePermissions, + state: &State<'_, AppState>, + ) -> Result { + let source = PathBuf::from(&source_path); + + let temp = std::env::temp_dir().join(format!("haexhub_ext_{}", uuid::Uuid::new_v4())); + std::fs::create_dir_all(&temp).map_err(|e| ExtensionError::Filesystem { source: e })?; + + let file = File::open(&source).map_err(|e| ExtensionError::Filesystem { source: e })?; + let mut archive = + ZipArchive::new(file).map_err(|e| ExtensionError::InstallationFailed { + reason: format!("Invalid ZIP: {}", e), + })?; + + archive + .extract(&temp) + .map_err(|e| ExtensionError::InstallationFailed { + reason: format!("Cannot extract ZIP: {}", e), + })?; + + let manifest_path = temp.join("manifest.json"); + let manifest_content = + std::fs::read_to_string(&manifest_path).map_err(|e| ExtensionError::ManifestError { + reason: format!("Cannot read manifest: {}", e), + })?; + + let manifest: ExtensionManifest = serde_json::from_str(&manifest_content)?; + + let content_hash = ExtensionCrypto::hash_directory(&temp) + .map_err(|e| ExtensionError::SignatureVerificationFailed { reason: e })?; + + ExtensionCrypto::verify_signature(&manifest.public_key, &content_hash, &manifest.signature) + .map_err(|e| ExtensionError::SignatureVerificationFailed { reason: e })?; + + let key_hash = manifest.calculate_key_hash()?; + let full_extension_id = format!("{}-{}", key_hash, manifest.id); + + let extensions_dir = app_handle + .path() + .app_data_dir() + .map_err(|e| ExtensionError::Filesystem { + source: std::io::Error::new(std::io::ErrorKind::NotFound, e.to_string()), + })? + .join("extensions") + .join(&full_extension_id) + .join(&manifest.version); + + std::fs::create_dir_all(&extensions_dir) + .map_err(|e| ExtensionError::Filesystem { source: e })?; + + copy_directory( + temp.to_string_lossy().to_string(), + extensions_dir.to_string_lossy().to_string(), + )?; + + std::fs::remove_dir_all(&temp).ok(); + + let permissions = custom_permissions.to_internal_permissions(&full_extension_id); + + let granted_permissions: Vec<_> = permissions + .into_iter() + .filter(|p| p.status == PermissionStatus::Granted) + .collect(); + + PermissionManager::save_permissions(state, &full_extension_id, &granted_permissions) + .await?; + + let extension = Extension { + id: full_extension_id.clone(), + name: manifest.name.clone(), + source: ExtensionSource::Production { + path: extensions_dir.clone(), + version: manifest.version.clone(), + }, + manifest: manifest.clone(), + enabled: true, + last_accessed: SystemTime::now(), + }; + + self.add_production_extension(extension)?; + + Ok(full_extension_id) + } +} + +// Backward compatibility +#[derive(Default)] +pub struct ExtensionState { + pub extensions: Mutex>, +} + +impl ExtensionState { + pub fn add_extension(&self, path: String, manifest: ExtensionManifest) { + let mut extensions = self.extensions.lock().unwrap(); + extensions.insert(path, manifest); + } + + pub fn get_extension(&self, addon_id: &str) -> Option { + let extensions = self.extensions.lock().unwrap(); + extensions.values().find(|p| p.name == addon_id).cloned() + } +} diff --git a/src-tauri/src/extension/core/manifest.rs b/src-tauri/src/extension/core/manifest.rs new file mode 100644 index 0000000..2ae35ea --- /dev/null +++ b/src-tauri/src/extension/core/manifest.rs @@ -0,0 +1,250 @@ +// src-tauri/src/extension/core/manifest.rs + +use crate::extension::crypto::ExtensionCrypto; +use crate::extension::error::ExtensionError; +use crate::extension::permissions::types::{ + Action, DbConstraints, ExtensionPermission, FsConstraints, HttpConstraints, + PermissionConstraints, PermissionStatus, ResourceType, ShellConstraints, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ExtensionManifest { + pub id: String, + pub name: String, + pub version: String, + pub author: Option, + pub entry: String, + pub icon: Option, + pub public_key: String, + pub signature: String, + pub permissions: ExtensionManifestPermissions, + pub homepage: Option, + pub description: Option, +} + +impl ExtensionManifest { + pub fn calculate_key_hash(&self) -> Result { + ExtensionCrypto::calculate_key_hash(&self.public_key) + .map_err(|e| ExtensionError::InvalidPublicKey { reason: e }) + } + + pub fn full_extension_id(&self) -> Result { + let key_hash = self.calculate_key_hash()?; + Ok(format!("{}-{}", key_hash, self.id)) + } + + pub fn to_editable_permissions(&self) -> EditablePermissions { + let mut permissions = Vec::new(); + + if let Some(db) = &self.permissions.database { + for resource in &db.read { + permissions.push(EditablePermission { + resource_type: "db".to_string(), + action: "read".to_string(), + target: resource.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + for resource in &db.write { + permissions.push(EditablePermission { + resource_type: "db".to_string(), + action: "write".to_string(), + target: resource.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + } + + if let Some(fs) = &self.permissions.filesystem { + for path in &fs.read { + permissions.push(EditablePermission { + resource_type: "fs".to_string(), + action: "read".to_string(), + target: path.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + for path in &fs.write { + permissions.push(EditablePermission { + resource_type: "fs".to_string(), + action: "write".to_string(), + target: path.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + } + + if let Some(http_list) = &self.permissions.http { + for domain in http_list { + permissions.push(EditablePermission { + resource_type: "http".to_string(), + action: "read".to_string(), + target: domain.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + } + + if let Some(shell_list) = &self.permissions.shell { + for command in shell_list { + permissions.push(EditablePermission { + resource_type: "shell".to_string(), + action: "read".to_string(), + target: command.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + } + + EditablePermissions { permissions } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +pub struct ExtensionManifestPermissions { + #[serde(default)] + pub database: Option, + #[serde(default)] + pub filesystem: Option, + #[serde(default)] + pub http: Option>, + #[serde(default)] + pub shell: Option>, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +pub struct DatabaseManifestPermissions { + #[serde(default)] + pub read: Vec, + #[serde(default)] + pub write: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +pub struct FilesystemManifestPermissions { + #[serde(default)] + pub read: Vec, + #[serde(default)] + pub write: Vec, +} + +// Editable Permissions für UI +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct EditablePermissions { + pub permissions: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct EditablePermission { + pub resource_type: String, + pub action: String, + pub target: String, + pub constraints: Option, + pub status: String, +} + +impl EditablePermissions { + pub fn to_internal_permissions(&self, extension_id: &str) -> Vec { + self.permissions + .iter() + .map(|p| ExtensionPermission { + id: uuid::Uuid::new_v4().to_string(), + extension_id: extension_id.to_string(), + resource_type: match p.resource_type.as_str() { + "fs" => ResourceType::Fs, + "http" => ResourceType::Http, + "db" => ResourceType::Db, + "shell" => ResourceType::Shell, + _ => ResourceType::Fs, + }, + action: match p.action.as_str() { + "read" => Action::Read, + "write" => Action::Write, + _ => Action::Read, + }, + target: p.target.clone(), + constraints: p + .constraints + .as_ref() + .and_then(|c| Self::parse_constraints(&p.resource_type, c)), + status: match p.status.as_str() { + "granted" => PermissionStatus::Granted, + "denied" => PermissionStatus::Denied, + "ask" => PermissionStatus::Ask, + _ => PermissionStatus::Denied, + }, + haex_timestamp: None, + haex_tombstone: None, + }) + .collect() + } + + fn parse_constraints( + resource_type: &str, + json_value: &serde_json::Value, + ) -> Option { + match resource_type { + "db" => serde_json::from_value::(json_value.clone()) + .ok() + .map(PermissionConstraints::Database), + "fs" => serde_json::from_value::(json_value.clone()) + .ok() + .map(PermissionConstraints::Filesystem), + "http" => serde_json::from_value::(json_value.clone()) + .ok() + .map(PermissionConstraints::Http), + "shell" => serde_json::from_value::(json_value.clone()) + .ok() + .map(PermissionConstraints::Shell), + _ => None, + } + } +} + +#[derive(Serialize, Deserialize)] +pub struct ExtensionPreview { + pub manifest: ExtensionManifest, + pub is_valid_signature: bool, + pub key_hash: String, + pub editable_permissions: EditablePermissions, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ExtensionInfoResponse { + pub key_hash: String, + pub name: String, + pub full_id: String, + pub version: String, + pub display_name: Option, + pub namespace: Option, + pub allowed_origin: String, +} + +impl ExtensionInfoResponse { + pub fn from_extension( + extension: &crate::extension::core::types::Extension, + ) -> Result { + use crate::extension::core::types::get_tauri_origin; + + let allowed_origin = get_tauri_origin(); + let key_hash = extension.manifest.calculate_key_hash()?; + let full_id = extension.manifest.full_extension_id()?; + + Ok(Self { + key_hash, + name: extension.manifest.name.clone(), + full_id, + version: extension.manifest.version.clone(), + display_name: Some(extension.manifest.name.clone()), + namespace: extension.manifest.author.clone(), + allowed_origin, + }) + } +} diff --git a/src-tauri/src/extension/core/mod.rs b/src-tauri/src/extension/core/mod.rs new file mode 100644 index 0000000..ded9a99 --- /dev/null +++ b/src-tauri/src/extension/core/mod.rs @@ -0,0 +1,10 @@ +// src-tauri/src/extension/core/mod.rs + +pub mod manager; +pub mod manifest; +pub mod protocol; +pub mod types; + +pub use manager::*; +pub use manifest::*; +pub use protocol::*; diff --git a/src-tauri/src/extension/core/protocol.rs b/src-tauri/src/extension/core/protocol.rs new file mode 100644 index 0000000..65e91ec --- /dev/null +++ b/src-tauri/src/extension/core/protocol.rs @@ -0,0 +1,252 @@ +// src-tauri/src/extension/core/protocol.rs + +use crate::extension::error::ExtensionError; +use crate::AppState; +use mime; +use serde::Deserialize; +use std::fmt; +use std::fs; +use std::path::PathBuf; +use tauri::http::{Request, Response}; +use tauri::{AppHandle, State}; + +#[derive(Deserialize, Debug)] +struct ExtensionInfo { + id: String, + version: String, +} + +#[derive(Debug)] +enum DataProcessingError { + HexDecoding(hex::FromHexError), + Utf8Conversion(std::string::FromUtf8Error), + JsonParsing(serde_json::Error), +} + +impl fmt::Display for DataProcessingError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DataProcessingError::HexDecoding(e) => write!(f, "Hex-Dekodierungsfehler: {}", e), + DataProcessingError::Utf8Conversion(e) => { + write!(f, "UTF-8-Konvertierungsfehler: {}", e) + } + DataProcessingError::JsonParsing(e) => write!(f, "JSON-Parsing-Fehler: {}", e), + } + } +} + +impl std::error::Error for DataProcessingError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + DataProcessingError::HexDecoding(e) => Some(e), + DataProcessingError::Utf8Conversion(e) => Some(e), + DataProcessingError::JsonParsing(e) => Some(e), + } + } +} + +impl From for DataProcessingError { + fn from(err: hex::FromHexError) -> Self { + DataProcessingError::HexDecoding(err) + } +} + +impl From for DataProcessingError { + fn from(err: std::string::FromUtf8Error) -> Self { + DataProcessingError::Utf8Conversion(err) + } +} + +impl From for DataProcessingError { + fn from(err: serde_json::Error) -> Self { + DataProcessingError::JsonParsing(err) + } +} + +pub fn resolve_secure_extension_asset_path( + app_handle: &AppHandle, + state: State, + extension_id: &str, + extension_version: &str, + requested_asset_path: &str, +) -> Result { + if extension_id.is_empty() + || !extension_id + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '-') + { + return Err(ExtensionError::ValidationError { + reason: format!("Invalid extension ID: {}", extension_id), + }); + } + + if extension_version.is_empty() + || !extension_version + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '.') + { + return Err(ExtensionError::ValidationError { + reason: format!("Invalid extension version: {}", extension_version), + }); + } + + let specific_extension_dir = + state + .extension_manager + .get_extension_dir(app_handle, extension_id, extension_version)?; + + let clean_relative_path = requested_asset_path + .replace('\\', "/") + .trim_start_matches('/') + .split('/') + .filter(|&part| !part.is_empty() && part != "." && part != "..") + .collect::(); + + if clean_relative_path.as_os_str().is_empty() && requested_asset_path != "/" { + return Err(ExtensionError::ValidationError { + reason: "Empty or invalid asset path".to_string(), + }); + } + + let final_path = specific_extension_dir.join(clean_relative_path); + + match final_path.canonicalize() { + Ok(canonical_path) => { + let canonical_base = specific_extension_dir + .canonicalize() + .map_err(|e| ExtensionError::Filesystem { source: e })?; + if canonical_path.starts_with(&canonical_base) { + Ok(canonical_path) + } else { + eprintln!( + "SECURITY WARNING: Path traversal attempt blocked: {}", + requested_asset_path + ); + Err(ExtensionError::SecurityViolation { + reason: format!("Path traversal attempt: {}", requested_asset_path), + }) + } + } + Err(_) => { + if final_path.starts_with(&specific_extension_dir) { + Ok(final_path) + } else { + eprintln!( + "SECURITY WARNING: Invalid asset path: {}", + requested_asset_path + ); + Err(ExtensionError::SecurityViolation { + reason: format!("Invalid asset path: {}", requested_asset_path), + }) + } + } + } +} + +pub fn extension_protocol_handler( + state: State, + app_handle: &AppHandle, + request: &Request>, +) -> Result>, Box> { + let uri_ref = request.uri(); + println!("Protokoll Handler für: {}", uri_ref); + + let host = uri_ref + .host() + .ok_or("Kein Host (Extension ID) in URI gefunden")? + .to_string(); + + let path_str = uri_ref.path(); + let segments_iter = path_str.split('/').filter(|s| !s.is_empty()); + let resource_segments: Vec<&str> = segments_iter.collect(); + let raw_asset_path = resource_segments.join("/"); + let asset_to_load = if raw_asset_path.is_empty() { + "index.html" + } else { + &raw_asset_path + }; + + match process_hex_encoded_json(&host) { + Ok(info) => { + println!("Daten erfolgreich verarbeitet:"); + println!(" ID: {}", info.id); + println!(" Version: {}", info.version); + let absolute_secure_path = resolve_secure_extension_asset_path( + app_handle, + state, + &info.id, + &info.version, + &asset_to_load, + )?; + + println!("absolute_secure_path: {}", absolute_secure_path.display()); + + if absolute_secure_path.exists() && absolute_secure_path.is_file() { + match fs::read(&absolute_secure_path) { + Ok(content) => { + let mime_type = mime_guess::from_path(&absolute_secure_path) + .first_or(mime::APPLICATION_OCTET_STREAM) + .to_string(); + let content_length = content.len(); + println!( + "Liefere {} ({}, {} bytes) ", + absolute_secure_path.display(), + mime_type, + content_length + ); + Response::builder() + .status(200) + .header("Content-Type", mime_type) + .header("Content-Length", content_length.to_string()) + .header("Accept-Ranges", "bytes") + .body(content) + .map_err(|e| e.into()) + } + Err(e) => { + eprintln!( + "Fehler beim Lesen der Datei {}: {}", + absolute_secure_path.display(), + e + ); + let status_code = if e.kind() == std::io::ErrorKind::NotFound { + 404 + } else if e.kind() == std::io::ErrorKind::PermissionDenied { + 403 + } else { + 500 + }; + + Response::builder() + .status(status_code) + .body(Vec::new()) + .map_err(|e| e.into()) + } + } + } else { + eprintln!( + "Asset nicht gefunden oder ist kein File: {}", + absolute_secure_path.display() + ); + Response::builder() + .status(404) + .body(Vec::new()) + .map_err(|e| e.into()) + } + } + Err(e) => { + eprintln!("Fehler bei der Datenverarbeitung: {}", e); + + Response::builder() + .status(500) + .body(Vec::new()) + .map_err(|e| e.into()) + } + } +} + +fn process_hex_encoded_json(hex_input: &str) -> Result { + let bytes = hex::decode(hex_input)?; + let json_string = String::from_utf8(bytes)?; + let extension_info: ExtensionInfo = serde_json::from_str(&json_string)?; + Ok(extension_info) +} diff --git a/src-tauri/src/extension/core/types.rs b/src-tauri/src/extension/core/types.rs new file mode 100644 index 0000000..ac77169 --- /dev/null +++ b/src-tauri/src/extension/core/types.rs @@ -0,0 +1,94 @@ +// src-tauri/src/extension/core/types.rs + +use crate::extension::core::manifest::ExtensionManifest; +use std::path::PathBuf; +use std::time::SystemTime; + +/// Extension source type (production vs development) +#[derive(Debug, Clone)] +pub enum ExtensionSource { + Production { + path: PathBuf, + version: String, + }, + Development { + dev_server_url: String, + manifest_path: PathBuf, + auto_reload: bool, + }, +} + +/// Complete extension data structure +#[derive(Debug, Clone)] +pub struct Extension { + pub id: String, + pub name: String, + pub source: ExtensionSource, + pub manifest: ExtensionManifest, + pub enabled: bool, + pub last_accessed: SystemTime, +} + +pub fn get_tauri_origin() -> String { + #[cfg(target_os = "windows")] + { + "https://tauri.localhost".to_string() + } + + #[cfg(target_os = "macos")] + { + "tauri://localhost".to_string() + } + + #[cfg(target_os = "linux")] + { + "tauri://localhost".to_string() + } + + #[cfg(target_os = "android")] + { + "tauri://localhost".to_string() + } + + #[cfg(target_os = "ios")] + { + "tauri://localhost".to_string() + } +} + +pub fn copy_directory( + source: String, + destination: String, +) -> Result<(), crate::extension::error::ExtensionError> { + use crate::extension::error::ExtensionError; + use std::path::PathBuf; + + println!( + "Kopiere Verzeichnis von '{}' nach '{}'", + source, destination + ); + + let source_path = PathBuf::from(&source); + let destination_path = PathBuf::from(&destination); + + if !source_path.exists() || !source_path.is_dir() { + return Err(ExtensionError::Filesystem { + source: std::io::Error::new( + std::io::ErrorKind::NotFound, + format!("Source directory '{}' not found", source), + ), + }); + } + + let mut options = fs_extra::dir::CopyOptions::new(); + options.overwrite = true; + options.copy_inside = true; + options.buffer_size = 64000; + + fs_extra::dir::copy(&source_path, &destination_path, &options).map_err(|e| { + ExtensionError::Filesystem { + source: std::io::Error::new(std::io::ErrorKind::Other, e.to_string()), + } + })?; + Ok(()) +} diff --git a/src-tauri/src/extension/core_old.rs b/src-tauri/src/extension/core_old.rs new file mode 100644 index 0000000..9414e09 --- /dev/null +++ b/src-tauri/src/extension/core_old.rs @@ -0,0 +1,973 @@ +/// src-tauri/src/extension/core.rs +use crate::extension::crypto::ExtensionCrypto; +use crate::extension::error::ExtensionError; +use crate::extension::permissions::manager::PermissionManager; +use crate::extension::permissions::types::{ + Action, DbConstraints, ExtensionPermission, FsConstraints, HttpConstraints, + PermissionConstraints, PermissionStatus, ResourceType, ShellConstraints, +}; +use crate::AppState; +use mime; +use serde::{Deserialize, Serialize}; +use sha2::Digest; +use sha2::Sha256; +use std::collections::HashMap; +use std::fmt; +use std::fs; +use std::fs::File; +use std::path::PathBuf; +use std::sync::Mutex; +use std::time::{Duration, SystemTime}; +use tauri::State; +use tauri::{ + http::{Request, Response}, + AppHandle, Manager, Runtime, UriSchemeContext, +}; +use zip::ZipArchive; + +#[derive(Serialize, Deserialize)] +pub struct ExtensionPreview { + pub manifest: ExtensionManifest, + pub is_valid_signature: bool, + pub key_hash: String, + pub editable_permissions: EditablePermissions, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct EditablePermissions { + pub permissions: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct EditablePermission { + pub resource_type: String, + pub action: String, + pub target: String, + pub constraints: Option, + pub status: String, +} + +impl EditablePermissions { + /// Konvertiert EditablePermissions zu internen ExtensionPermissions + pub fn to_internal_permissions(&self, extension_id: &str) -> Vec { + self.permissions + .iter() + .map(|p| ExtensionPermission { + id: uuid::Uuid::new_v4().to_string(), + extension_id: extension_id.to_string(), + resource_type: match p.resource_type.as_str() { + "fs" => ResourceType::Fs, + "http" => ResourceType::Http, + "db" => ResourceType::Db, + "shell" => ResourceType::Shell, + _ => ResourceType::Fs, // Fallback + }, + action: match p.action.as_str() { + "read" => Action::Read, + "write" => Action::Write, + _ => Action::Read, // Fallback + }, + target: p.target.clone(), + constraints: p + .constraints + .as_ref() + .and_then(|c| Self::parse_constraints(&p.resource_type, c)), + status: match p.status.as_str() { + "granted" => PermissionStatus::Granted, + "denied" => PermissionStatus::Denied, + "ask" => PermissionStatus::Ask, + _ => PermissionStatus::Denied, // Fallback + }, + haex_timestamp: None, + haex_tombstone: None, + }) + .collect() + } + + fn parse_constraints( + resource_type: &str, + json_value: &serde_json::Value, + ) -> Option { + match resource_type { + "db" => serde_json::from_value::(json_value.clone()) + .ok() + .map(PermissionConstraints::Database), + "fs" => serde_json::from_value::(json_value.clone()) + .ok() + .map(PermissionConstraints::Filesystem), + "http" => serde_json::from_value::(json_value.clone()) + .ok() + .map(PermissionConstraints::Http), + "shell" => serde_json::from_value::(json_value.clone()) + .ok() + .map(PermissionConstraints::Shell), + _ => None, + } + } + + /// Filtert nur granted Permissions + pub fn filter_granted(&self) -> Vec { + self.permissions + .iter() + .filter(|p| p.status == "granted") + .cloned() + .collect() + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ExtensionManifest { + pub id: String, + pub name: String, + pub version: String, + pub author: Option, + pub entry: String, + pub icon: Option, + pub public_key: String, + pub signature: String, + pub permissions: ExtensionManifestPermissions, + pub homepage: Option, + pub description: Option, +} + +impl ExtensionManifest { + /// Berechnet den Key Hash für diese Extension + pub fn calculate_key_hash(&self) -> Result { + ExtensionCrypto::calculate_key_hash(&self.public_key) + .map_err(|e| ExtensionError::InvalidPublicKey { reason: e }) + } + + /// Generiert die vollständige Extension ID mit Key Hash Prefix + pub fn full_extension_id(&self) -> Result { + let key_hash = self.calculate_key_hash()?; + Ok(format!("{}-{}", key_hash, self.id)) + } + pub fn to_editable_permissions(&self) -> EditablePermissions { + let mut database = Vec::new(); + let mut filesystem = Vec::new(); + let mut http = Vec::new(); + + if let Some(db) = &self.permissions.database { + for resource in &db.read { + database.push(EditableDatabasePermission { + operation: "read".to_string(), + resource: resource.clone(), + status: PermissionStatus::Granted, + }); + } + for resource in &db.write { + database.push(EditableDatabasePermission { + operation: "write".to_string(), + resource: resource.clone(), + status: PermissionStatus::Granted, + }); + } + } + + if let Some(fs) = &self.permissions.filesystem { + for path in &fs.read { + filesystem.push(EditableFilesystemPermission { + operation: "read".to_string(), + path: path.clone(), + status: PermissionStatus::Granted, + }); + } + for path in &fs.write { + filesystem.push(EditableFilesystemPermission { + operation: "write".to_string(), + path: path.clone(), + status: PermissionStatus::Granted, + }); + } + } + + if let Some(http_list) = &self.permissions.http { + for domain in http_list { + http.push(EditableHttpPermission { + domain: domain.clone(), + status: PermissionStatus::Granted, + }); + } + } + + EditablePermissions { + database, + filesystem, + http, + } + } +} + +impl ExtensionManifest { + /// Konvertiert Manifest zu EditablePermissions (neue Version) + pub fn to_editable_permissions(&self) -> EditablePermissions { + let mut permissions = Vec::new(); + + // Database Permissions + if let Some(db) = &self.permissions.database { + for resource in &db.read { + permissions.push(EditablePermission { + resource_type: "db".to_string(), + action: "read".to_string(), + target: resource.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + for resource in &db.write { + permissions.push(EditablePermission { + resource_type: "db".to_string(), + action: "write".to_string(), + target: resource.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + } + + // Filesystem Permissions + if let Some(fs) = &self.permissions.filesystem { + for path in &fs.read { + permissions.push(EditablePermission { + resource_type: "fs".to_string(), + action: "read".to_string(), + target: path.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + for path in &fs.write { + permissions.push(EditablePermission { + resource_type: "fs".to_string(), + action: "write".to_string(), + target: path.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + } + + // HTTP Permissions + if let Some(http_list) = &self.permissions.http { + for domain in http_list { + permissions.push(EditablePermission { + resource_type: "http".to_string(), + action: "read".to_string(), // HTTP ist meist read + target: domain.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + } + + // Shell Permissions + if let Some(shell_list) = &self.permissions.shell { + for command in shell_list { + permissions.push(EditablePermission { + resource_type: "shell".to_string(), + action: "read".to_string(), // Shell hat keine action mehr im Schema + target: command.clone(), + constraints: None, + status: "granted".to_string(), + }); + } + } + + EditablePermissions { permissions } + } +} +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ExtensionInfoResponse { + pub key_hash: String, + pub name: String, + pub full_id: String, + pub version: String, + pub display_name: Option, + pub namespace: Option, + pub allowed_origin: String, +} + +impl ExtensionInfoResponse { + pub fn from_extension(extension: &Extension) -> Result { + // Bestimme die allowed_origin basierend auf Tauri-Konfiguration + let allowed_origin = get_tauri_origin(); + let key_hash = extension + .manifest + .calculate_key_hash() + .map_err(|e| ExtensionError::InvalidPublicKey { reason: e })?; + let full_id = extension + .manifest + .full_extension_id() + .map_err(|e| ExtensionError::InvalidPublicKey { reason: e })?; + + Ok(Self { + key_hash, + name: extension.manifest.name.clone(), + full_id, + version: extension.manifest.version.clone(), + display_name: Some(extension.manifest.name.clone()), + namespace: extension.manifest.author.clone(), + allowed_origin, + }) + } +} + +fn get_tauri_origin() -> String { + #[cfg(target_os = "windows")] + { + "https://tauri.localhost".to_string() + } + + #[cfg(target_os = "macos")] + { + "tauri://localhost".to_string() + } + + #[cfg(target_os = "linux")] + { + "tauri://localhost".to_string() + } + + #[cfg(target_os = "android")] + { + "tauri://localhost".to_string() + } + + #[cfg(target_os = "ios")] + { + "tauri://localhost".to_string() + } +} + +/// Extension source type (production vs development) +#[derive(Debug, Clone)] +pub enum ExtensionSource { + Production { + path: PathBuf, + version: String, + }, + Development { + dev_server_url: String, + manifest_path: PathBuf, + auto_reload: bool, + }, +} + +/// Complete extension data structure +#[derive(Debug, Clone)] +pub struct Extension { + pub id: String, + pub name: String, + pub source: ExtensionSource, + pub manifest: ExtensionManifest, + pub enabled: bool, + pub last_accessed: SystemTime, +} + +/// Cached permission data for performance +#[derive(Debug, Clone)] +pub struct CachedPermission { + pub permissions: Vec, + pub cached_at: SystemTime, + pub ttl: Duration, +} + +/// Enhanced extension manager +#[derive(Default)] +pub struct ExtensionManager { + pub production_extensions: Mutex>, + pub dev_extensions: Mutex>, + pub permission_cache: Mutex>, +} + +impl ExtensionManager { + pub fn new() -> Self { + Self::default() + } + + pub fn get_base_extension_dir(&self, app_handle: AppHandle) -> Result { + let path = app_handle + .path() + .app_local_data_dir() // Korrekt für Ressourcen + // Wenn du stattdessen App Local Data willst: .app_local_data_dir() + .map_err(|e| ExtensionError::Filesystem { + source: std::io::Error::new(std::io::ErrorKind::NotFound, e.to_string()), + })? + .join("extensions"); + Ok(path) + } + + pub fn get_extension_dir( + &self, + app_handle: AppHandle, + extension_id: &str, + extension_version: &str, + ) -> Result { + let specific_extension_dir = self + .get_base_extension_dir(app_handle)? + .join(extension_id) + .join(extension_version); + + Ok(specific_extension_dir) + } + + pub fn add_production_extension(&self, extension: Extension) -> Result<(), ExtensionError> { + if extension.id.is_empty() { + return Err(ExtensionError::ValidationError { + reason: "Extension ID cannot be empty".to_string(), + }); + } + + // Validate filesystem permissions + /* if let Some(fs_perms) = &extension.manifest.permissions.filesystem { + fs_perms.validate()?; + } + */ + match &extension.source { + ExtensionSource::Production { .. } => { + let mut extensions = self.production_extensions.lock().unwrap(); + extensions.insert(extension.id.clone(), extension); + Ok(()) + } + _ => Err(ExtensionError::ValidationError { + reason: "Expected Production source".to_string(), + }), + } + } + + pub fn add_dev_extension(&self, extension: Extension) -> Result<(), ExtensionError> { + if extension.id.is_empty() { + return Err(ExtensionError::ValidationError { + reason: "Extension ID cannot be empty".to_string(), + }); + } + + // Validate filesystem permissions + /* if let Some(fs_perms) = &extension.manifest.permissions.filesystem { + fs_perms.validate()?; + } */ + + match &extension.source { + ExtensionSource::Development { .. } => { + let mut extensions = self.dev_extensions.lock().unwrap(); + extensions.insert(extension.id.clone(), extension); + Ok(()) + } + _ => Err(ExtensionError::ValidationError { + reason: "Expected Development source".to_string(), + }), + } + } + + pub fn get_extension(&self, extension_id: &str) -> Option { + // Dev extensions take priority + let dev_extensions = self.dev_extensions.lock().unwrap(); + if let Some(extension) = dev_extensions.get(extension_id) { + return Some(extension.clone()); + } + + // Then check production + let prod_extensions = self.production_extensions.lock().unwrap(); + prod_extensions.get(extension_id).cloned() + } + + pub fn remove_extension(&self, extension_id: &str) -> Result<(), ExtensionError> { + { + let mut dev_extensions = self.dev_extensions.lock().unwrap(); + if dev_extensions.remove(extension_id).is_some() { + return Ok(()); + } + } + + { + let mut prod_extensions = self.production_extensions.lock().unwrap(); + if prod_extensions.remove(extension_id).is_some() { + return Ok(()); + } + } + + Err(ExtensionError::NotFound { + id: extension_id.to_string(), + }) + } + + pub async fn remove_extension_internal( + &self, + app_handle: AppHandle, + extension_id: String, + extension_version: String, + state: &State<'_, AppState>, + ) -> Result<(), ExtensionError> { + // Permissions löschen (verwendet jetzt die neue Methode) + PermissionManager::delete_permissions(state, &extension_id).await?; + + // Extension aus Manager entfernen + self.remove_extension(&extension_id)?; + + let extension_dir = + self.get_extension_dir(app_handle, &extension_id, &extension_version)?; + + // Dateien löschen + if extension_dir.exists() { + std::fs::remove_dir_all(&extension_dir) + .map_err(|e| ExtensionError::Filesystem { source: e })?; + } + + Ok(()) + } + + pub async fn preview_extension_internal( + &self, + source_path: String, + ) -> Result { + let source = PathBuf::from(&source_path); + + // ZIP in temp entpacken + let temp = std::env::temp_dir().join(format!("haexhub_preview_{}", uuid::Uuid::new_v4())); + std::fs::create_dir_all(&temp).map_err(|e| ExtensionError::Filesystem { source: e })?; + + let file = File::open(&source).map_err(|e| ExtensionError::Filesystem { source: e })?; + let mut archive = + ZipArchive::new(file).map_err(|e| ExtensionError::InstallationFailed { + reason: format!("Invalid ZIP: {}", e), + })?; + + archive + .extract(&temp) + .map_err(|e| ExtensionError::InstallationFailed { + reason: format!("Cannot extract ZIP: {}", e), + })?; + + // Manifest laden + let manifest_path = temp.join("manifest.json"); + let manifest_content = + std::fs::read_to_string(&manifest_path).map_err(|e| ExtensionError::ManifestError { + reason: format!("Cannot read manifest: {}", e), + })?; + + let manifest: ExtensionManifest = serde_json::from_str(&manifest_content)?; + + // Signatur verifizieren + let content_hash = ExtensionCrypto::hash_directory(&temp) + .map_err(|e| ExtensionError::SignatureVerificationFailed { reason: e })?; + + let is_valid_signature = ExtensionCrypto::verify_signature( + &manifest.public_key, + &content_hash, + &manifest.signature, + ) + .is_ok(); + + let key_hash = manifest.calculate_key_hash()?; + + // Editable permissions erstellen + let editable_permissions = manifest.to_editable_permissions(); + + // Cleanup + std::fs::remove_dir_all(&temp).ok(); + + Ok(ExtensionPreview { + manifest, + is_valid_signature, + key_hash, + editable_permissions, + }) + } + + pub async fn install_extension_with_permissions_internal( + &self, + app_handle: AppHandle, + source_path: String, + custom_permissions: EditablePermissions, + state: &State<'_, AppState>, + ) -> Result { + let source = PathBuf::from(&source_path); + + // 1. ZIP entpacken + let temp = std::env::temp_dir().join(format!("haexhub_ext_{}", uuid::Uuid::new_v4())); + std::fs::create_dir_all(&temp).map_err(|e| ExtensionError::Filesystem { source: e })?; + + let file = File::open(&source).map_err(|e| ExtensionError::Filesystem { source: e })?; + let mut archive = + ZipArchive::new(file).map_err(|e| ExtensionError::InstallationFailed { + reason: format!("Invalid ZIP: {}", e), + })?; + + archive + .extract(&temp) + .map_err(|e| ExtensionError::InstallationFailed { + reason: format!("Cannot extract ZIP: {}", e), + })?; + + // 2. Manifest laden + let manifest_path = temp.join("manifest.json"); + let manifest_content = + std::fs::read_to_string(&manifest_path).map_err(|e| ExtensionError::ManifestError { + reason: format!("Cannot read manifest: {}", e), + })?; + + let manifest: ExtensionManifest = serde_json::from_str(&manifest_content)?; + + // 3. Signatur verifizieren + let content_hash = ExtensionCrypto::hash_directory(&temp) + .map_err(|e| ExtensionError::SignatureVerificationFailed { reason: e })?; + + ExtensionCrypto::verify_signature(&manifest.public_key, &content_hash, &manifest.signature) + .map_err(|e| ExtensionError::SignatureVerificationFailed { reason: e })?; + + // 4. Key Hash berechnen + let key_hash = manifest.calculate_key_hash()?; + let full_extension_id = format!("{}-{}", key_hash, manifest.id); + + // 5. Zielverzeichnis + let extensions_dir = app_handle + .path() + .app_data_dir() + .map_err(|e| ExtensionError::Filesystem { + source: std::io::Error::new(std::io::ErrorKind::NotFound, e.to_string()), + })? + .join("extensions") + .join(&full_extension_id) + .join(&manifest.version); + + std::fs::create_dir_all(&extensions_dir) + .map_err(|e| ExtensionError::Filesystem { source: e })?; + + // 6. Dateien kopieren + copy_directory( + temp.to_string_lossy().to_string(), + extensions_dir.to_string_lossy().to_string(), + )?; + + // 7. Temp aufräumen + std::fs::remove_dir_all(&temp).ok(); + + // 8. Custom Permissions konvertieren und speichern + let permissions = custom_permissions.to_internal_permissions(&full_extension_id); + let granted_permissions = permissions.filter_granted(); + PermissionManager::save_permissions(&state.db, &granted_permissions).await?; + + // 9. Extension registrieren + let extension = Extension { + id: full_extension_id.clone(), + name: manifest.name.clone(), + source: ExtensionSource::Production { + path: extensions_dir.clone(), + version: manifest.version.clone(), + }, + manifest: manifest.clone(), + enabled: true, + last_accessed: SystemTime::now(), + }; + + state + .extension_manager + .add_production_extension(extension)?; + + Ok(full_extension_id) + } +} + +// For backward compatibility +#[derive(Default)] +pub struct ExtensionState { + pub extensions: Mutex>, +} + +impl ExtensionState { + pub fn add_extension(&self, path: String, manifest: ExtensionManifest) { + let mut extensions = self.extensions.lock().unwrap(); + extensions.insert(path, manifest); + } + + pub fn get_extension(&self, addon_id: &str) -> Option { + let extensions = self.extensions.lock().unwrap(); + extensions.values().find(|p| p.name == addon_id).cloned() + } +} + +#[derive(Deserialize, Debug)] +struct ExtensionInfo { + id: String, + version: String, +} + +#[derive(Debug)] +enum DataProcessingError { + HexDecoding(hex::FromHexError), + Utf8Conversion(std::string::FromUtf8Error), + JsonParsing(serde_json::Error), +} + +// Implementierung von Display für benutzerfreundliche Fehlermeldungen +impl fmt::Display for DataProcessingError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DataProcessingError::HexDecoding(e) => write!(f, "Hex-Dekodierungsfehler: {}", e), + DataProcessingError::Utf8Conversion(e) => { + write!(f, "UTF-8-Konvertierungsfehler: {}", e) + } + DataProcessingError::JsonParsing(e) => write!(f, "JSON-Parsing-Fehler: {}", e), + } + } +} + +// Implementierung von std::error::Error (optional, aber gute Praxis für bibliotheksähnlichen Code) +impl std::error::Error for DataProcessingError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + DataProcessingError::HexDecoding(e) => Some(e), + DataProcessingError::Utf8Conversion(e) => Some(e), + DataProcessingError::JsonParsing(e) => Some(e), + } + } +} + +// Implementierung von From-Traits für einfache Verwendung des '?'-Operators +impl From for DataProcessingError { + fn from(err: hex::FromHexError) -> Self { + DataProcessingError::HexDecoding(err) + } +} + +impl From for DataProcessingError { + fn from(err: std::string::FromUtf8Error) -> Self { + DataProcessingError::Utf8Conversion(err) + } +} + +impl From for DataProcessingError { + fn from(err: serde_json::Error) -> Self { + DataProcessingError::JsonParsing(err) + } +} + +pub fn copy_directory(source: String, destination: String) -> Result<(), ExtensionError> { + println!( + "Kopiere Verzeichnis von '{}' nach '{}'", + source, destination + ); + + let source_path = PathBuf::from(&source); + let destination_path = PathBuf::from(&destination); + + if !source_path.exists() || !source_path.is_dir() { + return Err(ExtensionError::Filesystem { + source: std::io::Error::new( + std::io::ErrorKind::NotFound, + format!("Source directory '{}' not found", source), + ), + }); + } + + // Optionen für fs_extra::dir::copy + let mut options = fs_extra::dir::CopyOptions::new(); + options.overwrite = true; // Überschreibe Zieldateien, falls sie existieren + options.copy_inside = true; // Kopiere den *Inhalt* des Quellordners in den Zielordner + // options.content_only = true; // Alternative: nur Inhalt kopieren, Zielordner muss existieren + options.buffer_size = 64000; // Standard-Puffergröße, kann angepasst werden + + // Führe die Kopieroperation aus + fs_extra::dir::copy(&source_path, &destination_path, &options).map_err(|e| { + ExtensionError::Filesystem { + source: std::io::Error::new(std::io::ErrorKind::Other, e.to_string()), + } + })?; + Ok(()) +} + +pub fn resolve_secure_extension_asset_path( + app_handle: AppHandle, + state: State, + extension_id: &str, + extension_version: &str, + requested_asset_path: &str, +) -> Result { + // 1. Validiere die Extension ID + if extension_id.is_empty() + || !extension_id + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '-') + { + return Err(ExtensionError::ValidationError { + reason: format!("Invalid extension ID: {}", extension_id), + }); + } + + if extension_version.is_empty() + || !extension_version + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '.') + { + return Err(ExtensionError::ValidationError { + reason: format!("Invalid extension version: {}", extension_version), + }); + } + + // 3. Verzeichnis für die spezifische Erweiterung + let specific_extension_dir = + state + .extension_manager + .get_extension_dir(app_handle, extension_id, extension_version)?; + + // 4. Bereinige den angeforderten Asset-Pfad + let clean_relative_path = requested_asset_path + .replace('\\', "/") + .trim_start_matches('/') + .split('/') + .filter(|&part| !part.is_empty() && part != "." && part != "..") + .collect::(); + + if clean_relative_path.as_os_str().is_empty() && requested_asset_path != "/" { + return Err(ExtensionError::ValidationError { + reason: "Empty or invalid asset path".to_string(), + }); + } + + // 5. Setze den finalen Pfad zusammen + let final_path = specific_extension_dir.join(clean_relative_path); + + // 6. SICHERHEITSCHECK + match final_path.canonicalize() { + Ok(canonical_path) => { + let canonical_base = specific_extension_dir + .canonicalize() + .map_err(|e| ExtensionError::Filesystem { source: e })?; + if canonical_path.starts_with(&canonical_base) { + Ok(canonical_path) + } else { + eprintln!( /* ... Sicherheitswarnung ... */ ); + Err(ExtensionError::SecurityViolation { + reason: format!("Path traversal attempt: {}", requested_asset_path), + }) + } + } + Err(_) => { + // Fehler bei canonicalize (z.B. Pfad existiert nicht) + if final_path.starts_with(&specific_extension_dir) { + Ok(final_path) // Nicht-kanonisierten Pfad zurückgeben + } else { + eprintln!( /* ... Sicherheitswarnung ... */ ); + Err(ExtensionError::SecurityViolation { + reason: format!("Invalid asset path: {}", requested_asset_path), + }) + } + } + } +} + +pub fn extension_protocol_handler( + state: State, + app_handle: AppHandle, + request: &Request>, +) -> Result>, Box> { + let uri_ref = request.uri(); + println!("Protokoll Handler für: {}", uri_ref); + + let host = uri_ref + .host() + .ok_or("Kein Host (Extension ID) in URI gefunden")? + .to_string(); + + let path_str = uri_ref.path(); + let segments_iter = path_str.split('/').filter(|s| !s.is_empty()); + let resource_segments: Vec<&str> = segments_iter.collect(); + let raw_asset_path = resource_segments.join("/"); + let asset_to_load = if raw_asset_path.is_empty() { + "index.html" + } else { + &raw_asset_path + }; + + match process_hex_encoded_json(&host) { + Ok(info) => { + println!("Daten erfolgreich verarbeitet:"); + println!(" ID: {}", info.id); + println!(" Version: {}", info.version); + let absolute_secure_path = resolve_secure_extension_asset_path( + app_handle, + state, + &info.id, + &info.version, + &asset_to_load, + )?; + + println!("absolute_secure_path: {}", absolute_secure_path.display()); + + if absolute_secure_path.exists() && absolute_secure_path.is_file() { + match fs::read(&absolute_secure_path) { + Ok(content) => { + let mime_type = mime_guess::from_path(&absolute_secure_path) + .first_or(mime::APPLICATION_OCTET_STREAM) + .to_string(); + let content_length = content.len(); + println!( + "Liefere {} ({}, {} bytes) ", // Content-Length zum Log hinzugefügt + absolute_secure_path.display(), + mime_type, + content_length + ); + Response::builder() + .status(200) + .header("Content-Type", mime_type) + .header("Content-Length", content_length.to_string()) // <-- HIER HINZUGEFÜGT + // Optional, aber gut für Streaming-Fähigkeit: + .header("Accept-Ranges", "bytes") + .body(content) + .map_err(|e| e.into()) + } + Err(e) => { + eprintln!( + "Fehler beim Lesen der Datei {}: {}", + absolute_secure_path.display(), + e + ); + let status_code = if e.kind() == std::io::ErrorKind::NotFound { + 404 + } else if e.kind() == std::io::ErrorKind::PermissionDenied { + 403 + } else { + 500 + }; + + Response::builder() + .status(status_code) + .body(Vec::new()) // Leerer Body für Fehler + .map_err(|e| e.into()) // Wandle http::Error in Box um + } + } + } else { + // Datei nicht gefunden oder es ist keine Datei + eprintln!( + "Asset nicht gefunden oder ist kein File: {}", + absolute_secure_path.display() + ); + Response::builder() + .status(404) // HTTP 404 Not Found + .body(Vec::new()) + .map_err(|e| e.into()) + } + } + Err(e) => { + eprintln!("Fehler bei der Datenverarbeitung: {}", e); + + Response::builder() + .status(500) + .body(Vec::new()) // Leerer Body für Fehler + .map_err(|e| e.into()) + } + } +} + +fn process_hex_encoded_json(hex_input: &str) -> Result { + // Schritt 1: Hex-String zu Bytes dekodieren + let bytes = hex::decode(hex_input)?; // Konvertiert hex::FromHexError automatisch + + // Schritt 2: Bytes zu UTF-8-String konvertieren + let json_string = String::from_utf8(bytes)?; // Konvertiert FromUtf8Error automatisch + + // Schritt 3: JSON-String zu Struktur parsen + let extension_info: ExtensionInfo = serde_json::from_str(&json_string)?; // Konvertiert serde_json::Error automatisch + + Ok(extension_info) +} diff --git a/src-tauri/src/extension/crypto.rs b/src-tauri/src/extension/crypto.rs new file mode 100644 index 0000000..9941d32 --- /dev/null +++ b/src-tauri/src/extension/crypto.rs @@ -0,0 +1,74 @@ +// src-tauri/src/extension/crypto.rs +use ed25519_dalek::{Signature, Verifier, VerifyingKey}; +use sha2::{Digest, Sha256}; + +pub struct ExtensionCrypto; + +impl ExtensionCrypto { + /// Berechnet Hash vom Public Key (wie im SDK) + pub fn calculate_key_hash(public_key_hex: &str) -> Result { + let public_key_bytes = + hex::decode(public_key_hex).map_err(|e| format!("Invalid public key hex: {}", e))?; + + let public_key = VerifyingKey::from_bytes(&public_key_bytes.try_into().unwrap()) + .map_err(|e| format!("Invalid public key: {}", e))?; + + let mut hasher = Sha256::new(); + hasher.update(public_key.as_bytes()); + let result = hasher.finalize(); + + // Ersten 20 Hex-Zeichen (10 Bytes) - wie im SDK + Ok(hex::encode(&result[..10])) + } + + /// Verifiziert Extension-Signatur + pub fn verify_signature( + public_key_hex: &str, + content_hash_hex: &str, + signature_hex: &str, + ) -> Result<(), String> { + let public_key_bytes = + hex::decode(public_key_hex).map_err(|e| format!("Invalid public key: {}", e))?; + let public_key = VerifyingKey::from_bytes(&public_key_bytes.try_into().unwrap()) + .map_err(|e| format!("Invalid public key: {}", e))?; + + let signature_bytes = + hex::decode(signature_hex).map_err(|e| format!("Invalid signature: {}", e))?; + let signature = Signature::from_bytes(&signature_bytes.try_into().unwrap()); + + let content_hash = + hex::decode(content_hash_hex).map_err(|e| format!("Invalid content hash: {}", e))?; + + public_key + .verify(&content_hash, &signature) + .map_err(|e| format!("Signature verification failed: {}", e)) + } + + /// Berechnet Hash eines Verzeichnisses (für Verifikation) + pub fn hash_directory(dir: &std::path::Path) -> Result { + use std::fs; + + let mut hasher = Sha256::new(); + let mut entries: Vec<_> = fs::read_dir(dir) + .map_err(|e| format!("Cannot read directory: {}", e))? + .filter_map(|e| e.ok()) + .collect(); + + // Sortieren für deterministische Hashes + entries.sort_by_key(|e| e.path()); + + for entry in entries { + let path = entry.path(); + if path.is_file() { + let content = fs::read(&path) + .map_err(|e| format!("Cannot read file {}: {}", path.display(), e))?; + hasher.update(&content); + } else if path.is_dir() { + let subdir_hash = Self::hash_directory(&path)?; + hasher.update(hex::decode(&subdir_hash).unwrap()); + } + } + + Ok(hex::encode(hasher.finalize())) + } +} diff --git a/src-tauri/src/extension/database/executor.rs b/src-tauri/src/extension/database/executor.rs new file mode 100644 index 0000000..207887c --- /dev/null +++ b/src-tauri/src/extension/database/executor.rs @@ -0,0 +1,153 @@ +// src-tauri/src/extension/database/executor.rs (neu) + +use crate::crdt::hlc::HlcService; +use crate::crdt::transformer::CrdtTransformer; +use crate::crdt::trigger; +use crate::database::core::{parse_sql_statements, ValueConverter}; +use crate::database::error::DatabaseError; +use rusqlite::{params_from_iter, Transaction}; +use serde_json::Value as JsonValue; +use sqlparser::ast::Statement; +use std::collections::HashSet; + +/// SQL-Executor OHNE Berechtigungsprüfung - für interne Nutzung +pub struct SqlExecutor; + +impl SqlExecutor { + /// Führt SQL aus (mit CRDT-Transformation) - OHNE Permission-Check + pub fn execute_internal( + tx: &Transaction, + hlc_service: &HlcService, + sql: &str, + params: &[JsonValue], + ) -> Result, DatabaseError> { + // Parameter validation + let total_placeholders = sql.matches('?').count(); + if total_placeholders != params.len() { + return Err(DatabaseError::ParameterMismatchError { + expected: total_placeholders, + provided: params.len(), + sql: sql.to_string(), + }); + } + + // SQL parsing + let mut ast_vec = parse_sql_statements(sql)?; + + let transformer = CrdtTransformer::new(); + + // Generate HLC timestamp + let hlc_timestamp = + hlc_service + .new_timestamp_and_persist(tx) + .map_err(|e| DatabaseError::HlcError { + reason: e.to_string(), + })?; + + // Transform statements + let mut modified_schema_tables = HashSet::new(); + for statement in &mut ast_vec { + if let Some(table_name) = + transformer.transform_execute_statement(statement, &hlc_timestamp)? + { + modified_schema_tables.insert(table_name); + } + } + + // Convert parameters + let sql_values = ValueConverter::convert_params(params)?; + + // Execute statements + for statement in ast_vec { + let sql_str = statement.to_string(); + + tx.execute(&sql_str, params_from_iter(sql_values.iter())) + .map_err(|e| DatabaseError::ExecutionError { + sql: sql_str.clone(), + table: None, + reason: e.to_string(), + })?; + + if let Statement::CreateTable(create_table_details) = statement { + let table_name_str = create_table_details.name.to_string(); + trigger::setup_triggers_for_table(tx, &table_name_str, false)?; + } + } + + Ok(modified_schema_tables) + } + + /// Führt SELECT aus (mit CRDT-Transformation) - OHNE Permission-Check + pub fn select_internal( + conn: &rusqlite::Connection, + sql: &str, + params: &[JsonValue], + ) -> Result, DatabaseError> { + // Parameter validation + let total_placeholders = sql.matches('?').count(); + if total_placeholders != params.len() { + return Err(DatabaseError::ParameterMismatchError { + expected: total_placeholders, + provided: params.len(), + sql: sql.to_string(), + }); + } + + let mut ast_vec = parse_sql_statements(sql)?; + + if ast_vec.is_empty() { + return Ok(vec![]); + } + + // Validate that all statements are queries + for stmt in &ast_vec { + if !matches!(stmt, Statement::Query(_)) { + return Err(DatabaseError::ExecutionError { + sql: sql.to_string(), + reason: "Only SELECT statements are allowed".to_string(), + table: None, + }); + } + } + + let sql_params = ValueConverter::convert_params(params)?; + let transformer = CrdtTransformer::new(); + + let last_statement = ast_vec.pop().unwrap(); + let mut stmt_to_execute = last_statement; + + transformer.transform_select_statement(&mut stmt_to_execute)?; + let transformed_sql = stmt_to_execute.to_string(); + + let mut prepared_stmt = + conn.prepare(&transformed_sql) + .map_err(|e| DatabaseError::ExecutionError { + sql: transformed_sql.clone(), + reason: e.to_string(), + table: None, + })?; + + let column_names: Vec = prepared_stmt + .column_names() + .into_iter() + .map(|s| s.to_string()) + .collect(); + + let rows = prepared_stmt + .query_map(params_from_iter(sql_params.iter()), |row| { + crate::extension::database::row_to_json_value(row, &column_names) + }) + .map_err(|e| DatabaseError::QueryError { + reason: e.to_string(), + })?; + + let mut results = Vec::new(); + for row_result in rows { + results.push(row_result.map_err(|e| DatabaseError::RowProcessingError { + reason: e.to_string(), + })?); + } + + Ok(results) + } +} diff --git a/src-tauri/src/extension/database/mod.rs b/src-tauri/src/extension/database/mod.rs index c2b9211..6ca6fa8 100644 --- a/src-tauri/src/extension/database/mod.rs +++ b/src-tauri/src/extension/database/mod.rs @@ -1,14 +1,15 @@ // src-tauri/src/extension/database/mod.rs -pub mod permissions; +pub mod executor; use crate::crdt::hlc::HlcService; use crate::crdt::transformer::CrdtTransformer; use crate::crdt::trigger; use crate::database::core::{parse_sql_statements, with_connection, ValueConverter}; use crate::database::error::DatabaseError; use crate::extension::error::ExtensionError; +use crate::extension::permissions::validator::SqlPermissionValidator; use crate::AppState; -use permissions::{check_read_permission, check_write_permission}; + use rusqlite::params_from_iter; use rusqlite::types::Value as SqlValue; use rusqlite::Transaction; @@ -116,7 +117,7 @@ pub async fn extension_sql_execute( hlc_service: State<'_, HlcService>, ) -> Result, ExtensionError> { // Permission check - check_write_permission(&state.db, &extension_id, sql).await?; + SqlPermissionValidator::validate_sql(&state, &extension_id, sql).await?; // Parameter validation validate_params(sql, ¶ms)?; @@ -186,7 +187,7 @@ pub async fn extension_sql_select( state: State<'_, AppState>, ) -> Result, ExtensionError> { // Permission check - check_read_permission(&state.db, &extension_id, sql).await?; + SqlPermissionValidator::validate_sql(&state, &extension_id, sql).await?; // Parameter validation validate_params(sql, ¶ms)?; diff --git a/src-tauri/src/extension/database/permissions.rs b/src-tauri/src/extension/database/permissions.rs deleted file mode 100644 index d4bfcad..0000000 --- a/src-tauri/src/extension/database/permissions.rs +++ /dev/null @@ -1,278 +0,0 @@ -// src-tauri/src/extension/database/permissions.rs - -use crate::database::core::{ - extract_table_names_from_sql, parse_single_statement, with_connection, -}; -use crate::database::error::DatabaseError; -use crate::database::DbConnection; -use crate::extension::error::ExtensionError; - -use serde::{Deserialize, Serialize}; -use sqlparser::ast::{Statement, TableFactor, TableObject}; - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct DbExtensionPermission { - pub id: String, - pub extension_id: String, - pub resource: String, - pub operation: String, -} - -/// Prüft Leseberechtigungen für eine Extension -pub async fn check_read_permission( - connection: &DbConnection, - extension_id: &str, - sql: &str, -) -> Result<(), ExtensionError> { - let statement = parse_single_statement(sql).map_err(|e| DatabaseError::ParseError { - reason: e.to_string(), - sql: sql.to_string(), - })?; - - match statement { - Statement::Query(query) => { - let tables = extract_table_names_from_sql(&query.to_string())?; - check_table_permissions(connection, extension_id, &tables, "read").await - } - _ => Err(DatabaseError::UnsupportedStatement { - reason: "Only SELECT statements are allowed for read operations".to_string(), - sql: sql.to_string(), - } - .into()), - } -} - -/// Prüft Schreibberechtigungen für eine Extension -pub async fn check_write_permission( - connection: &DbConnection, - extension_id: &str, - sql: &str, -) -> Result<(), ExtensionError> { - let statement = parse_single_statement(sql).map_err(|e| DatabaseError::ParseError { - reason: e.to_string(), - sql: sql.to_string(), - })?; - - match statement { - Statement::Insert(insert) => { - let table_name = extract_table_name_from_insert(&insert)?; - check_single_table_permission(connection, extension_id, &table_name, "write").await - } - Statement::Update { table, .. } => { - let table_name = extract_table_name_from_table_factor(&table.relation)?; - check_single_table_permission(connection, extension_id, &table_name, "write").await - } - Statement::Delete(delete) => { - // DELETE wird durch CRDT-Transform zu UPDATE mit tombstone = 1 - let table_name = extract_table_name_from_delete(&delete)?; - check_single_table_permission(connection, extension_id, &table_name, "write").await - } - Statement::CreateTable(create_table) => { - let table_name = create_table.name.to_string(); - check_single_table_permission(connection, extension_id, &table_name, "create").await - } - Statement::AlterTable { name, .. } => { - let table_name = name.to_string(); - check_single_table_permission(connection, extension_id, &table_name, "alter").await - } - Statement::Drop { names, .. } => { - // Für DROP können mehrere Tabellen angegeben sein - let table_names: Vec = names.iter().map(|name| name.to_string()).collect(); - check_table_permissions(connection, extension_id, &table_names, "drop").await - } - _ => Err(DatabaseError::UnsupportedStatement { - reason: "SQL Statement is not allowed".to_string(), - sql: sql.to_string(), - } - .into()), - } -} - -/// Extrahiert Tabellenname aus INSERT-Statement -fn extract_table_name_from_insert( - insert: &sqlparser::ast::Insert, -) -> Result { - match &insert.table { - TableObject::TableName(name) => Ok(name.to_string()), - _ => Err(DatabaseError::NoTableError { - sql: insert.to_string(), - } - .into()), - } -} - -/// Extrahiert Tabellenname aus TableFactor -fn extract_table_name_from_table_factor( - table_factor: &TableFactor, -) -> Result { - match table_factor { - TableFactor::Table { name, .. } => Ok(name.to_string()), - _ => Err(DatabaseError::StatementError { - reason: "Complex table references not supported".to_string(), - } - .into()), - } -} - -/// Extrahiert Tabellenname aus DELETE-Statement -fn extract_table_name_from_delete( - delete: &sqlparser::ast::Delete, -) -> Result { - use sqlparser::ast::FromTable; - - let table_name = match &delete.from { - FromTable::WithFromKeyword(tables) | FromTable::WithoutKeyword(tables) => { - if !tables.is_empty() { - extract_table_name_from_table_factor(&tables[0].relation)? - } else if !delete.tables.is_empty() { - delete.tables[0].to_string() - } else { - return Err(DatabaseError::NoTableError { - sql: delete.to_string(), - } - .into()); - } - } - }; - - Ok(table_name) -} - -/// Prüft Berechtigung für eine einzelne Tabelle -async fn check_single_table_permission( - connection: &DbConnection, - extension_id: &str, - table_name: &str, - operation: &str, -) -> Result<(), ExtensionError> { - check_table_permissions( - connection, - extension_id, - &[table_name.to_string()], - operation, - ) - .await -} - -/// Prüft Berechtigungen für mehrere Tabellen -async fn check_table_permissions( - connection: &DbConnection, - extension_id: &str, - table_names: &[String], - operation: &str, -) -> Result<(), ExtensionError> { - let permissions = - get_extension_permissions(connection, extension_id, "database", operation).await?; - - for table_name in table_names { - let has_permission = permissions - .iter() - .any(|perm| perm.resource.contains(table_name)); - - if !has_permission { - return Err(ExtensionError::permission_denied( - extension_id, - operation, - &format!("table '{}'", table_name), - )); - } - } - - Ok(()) -} - -/// Ruft die Berechtigungen einer Extension aus der Datenbank ab -pub async fn get_extension_permissions( - connection: &DbConnection, - extension_id: &str, - resource: &str, - operation: &str, -) -> Result, DatabaseError> { - with_connection(connection, |conn| { - let mut stmt = conn - .prepare( - "SELECT id, extension_id, resource, operation, path - FROM haex_vault_extension_permissions - WHERE extension_id = ?1 AND resource = ?2 AND operation = ?3", - ) - .map_err(|e| DatabaseError::PrepareError { - reason: e.to_string(), - })?; - - let rows = stmt - .query_map([extension_id, resource, operation], |row| { - Ok(DbExtensionPermission { - id: row.get(0)?, - extension_id: row.get(1)?, - resource: row.get(2)?, - operation: row.get(3)?, - }) - }) - .map_err(|e| DatabaseError::QueryError { - reason: e.to_string(), - })?; - - let mut permissions = Vec::new(); - for row_result in rows { - let permission = row_result.map_err(|e| DatabaseError::DatabaseError { - reason: e.to_string(), - })?; - permissions.push(permission); - } - - Ok(permissions) - }) -} - -#[cfg(test)] -mod tests { - use crate::extension::error::ExtensionError; - - use super::*; - - #[test] - fn test_parse_single_statement() { - let sql = "SELECT * FROM users"; - let result = parse_single_statement(sql); - assert!(result.is_ok()); - assert!(matches!(result.unwrap(), Statement::Query(_))); - } - - #[test] - fn test_parse_invalid_sql() { - let sql = "INVALID SQL"; - let result = parse_single_statement(sql); - // parse_single_statement gibt DatabaseError zurück, nicht DatabaseError - assert!(result.is_err()); - // Wenn du spezifischer sein möchtest, kannst du den DatabaseError-Typ prüfen: - match result { - Err(DatabaseError::ParseError { .. }) => { - // Test erfolgreich - wir haben einen ParseError erhalten - } - Err(other) => { - // Andere DatabaseError-Varianten sind auch akzeptabel für ungültiges SQL - println!("Received other DatabaseError: {:?}", other); - } - Ok(_) => panic!("Expected error for invalid SQL"), - } - } - - /* #[test] - fn test_permission_error_access_denied() { - let error = ExtensionError::access_denied("ext1", "read", "table1", "not allowed"); - match error { - ExtensionError::AccessDenied { - extension_id, - operation, - resource, - reason, - } => { - assert_eq!(extension_id, "ext1"); - assert_eq!(operation, "read"); - assert_eq!(resource, "table1"); - assert_eq!(reason, "not allowed"); - } - _ => panic!("Expected AccessDenied error"), - } - } */ -} diff --git a/src-tauri/src/extension/error.rs b/src-tauri/src/extension/error.rs index 9bffeae..ac284d5 100644 --- a/src-tauri/src/extension/error.rs +++ b/src-tauri/src/extension/error.rs @@ -1,9 +1,36 @@ -/// src-tauri/src/extension/error.rs +// src-tauri/src/extension/error.rs use thiserror::Error; use crate::database::error::DatabaseError; -/// Comprehensive error type for extension operations +/// Error codes for frontend handling +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ExtensionErrorCode { + SecurityViolation = 1000, + NotFound = 1001, + PermissionDenied = 1002, + Database = 2000, + Filesystem = 2001, + Http = 2002, + Shell = 2003, + Manifest = 3000, + Validation = 3001, + InvalidPublicKey = 4000, + InvalidSignature = 4001, + SignatureVerificationFailed = 4002, + CalculateHash = 4003, + Installation = 5000, +} + +impl serde::Serialize for ExtensionErrorCode { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_u16(*self as u16) + } +} + #[derive(Error, Debug)] pub enum ExtensionError { #[error("Security violation: {reason}")] @@ -29,15 +56,10 @@ pub enum ExtensionError { Filesystem { #[from] source: std::io::Error, - // oder: source: FilesystemError, }, #[error("HTTP request failed: {reason}")] - Http { - reason: String, - #[source] - source: Option>, - }, + Http { reason: String }, #[error("Shell command failed: {reason}")] Shell { @@ -45,29 +67,51 @@ pub enum ExtensionError { exit_code: Option, }, - /* #[error("IO error: {source}")] - Io { - #[from] - source: std::io::Error, - }, */ #[error("Manifest error: {reason}")] ManifestError { reason: String }, #[error("Validation error: {reason}")] ValidationError { reason: String }, - #[error("Dev server error: {reason}")] - DevServerError { reason: String }, + #[error("Invalid Public Key: {reason}")] + InvalidPublicKey { reason: String }, - #[error("Serialization error: {reason}")] - SerializationError { reason: String }, + #[error("Invalid Signature: {reason}")] + InvalidSignature { reason: String }, - #[error("Configuration error: {reason}")] - ConfigError { reason: String }, + #[error("Error during hash calculation: {reason}")] + CalculateHashError { reason: String }, + + #[error("Signature verification failed: {reason}")] + SignatureVerificationFailed { reason: String }, + + #[error("Extension installation failed: {reason}")] + InstallationFailed { reason: String }, } impl ExtensionError { - /// Convenience constructor for permission denied errors + /// Get error code for this error + pub fn code(&self) -> ExtensionErrorCode { + match self { + ExtensionError::SecurityViolation { .. } => ExtensionErrorCode::SecurityViolation, + ExtensionError::NotFound { .. } => ExtensionErrorCode::NotFound, + ExtensionError::PermissionDenied { .. } => ExtensionErrorCode::PermissionDenied, + ExtensionError::Database { .. } => ExtensionErrorCode::Database, + ExtensionError::Filesystem { .. } => ExtensionErrorCode::Filesystem, + ExtensionError::Http { .. } => ExtensionErrorCode::Http, + ExtensionError::Shell { .. } => ExtensionErrorCode::Shell, + ExtensionError::ManifestError { .. } => ExtensionErrorCode::Manifest, + ExtensionError::ValidationError { .. } => ExtensionErrorCode::Validation, + ExtensionError::InvalidPublicKey { .. } => ExtensionErrorCode::InvalidPublicKey, + ExtensionError::InvalidSignature { .. } => ExtensionErrorCode::InvalidSignature, + ExtensionError::SignatureVerificationFailed { .. } => { + ExtensionErrorCode::SignatureVerificationFailed + } + ExtensionError::InstallationFailed { .. } => ExtensionErrorCode::Installation, + ExtensionError::CalculateHashError { .. } => ExtensionErrorCode::CalculateHash, + } + } + pub fn permission_denied(extension_id: &str, operation: &str, resource: &str) -> Self { Self::PermissionDenied { extension_id: extension_id.to_string(), @@ -76,34 +120,6 @@ impl ExtensionError { } } - /// Convenience constructor for HTTP errors - pub fn http_error(reason: &str) -> Self { - Self::Http { - reason: reason.to_string(), - source: None, - } - } - - /// Convenience constructor for HTTP errors with source - pub fn http_error_with_source( - reason: &str, - source: Box, - ) -> Self { - Self::Http { - reason: reason.to_string(), - source: Some(source), - } - } - - /// Convenience constructor for shell errors - pub fn shell_error(reason: &str, exit_code: Option) -> Self { - Self::Shell { - reason: reason.to_string(), - exit_code, - } - } - - /// Check if this error is related to permissions pub fn is_permission_error(&self) -> bool { matches!( self, @@ -111,11 +127,9 @@ impl ExtensionError { ) } - /// Extract extension ID if available pub fn extension_id(&self) -> Option<&str> { match self { ExtensionError::PermissionDenied { extension_id, .. } => Some(extension_id), - ExtensionError::Database { source } => source.extension_id(), _ => None, } } @@ -128,29 +142,12 @@ impl serde::Serialize for ExtensionError { { use serde::ser::SerializeStruct; - let mut state = serializer.serialize_struct("ExtensionError", 3)?; + let mut state = serializer.serialize_struct("ExtensionError", 4)?; - // Error type as discriminator - let error_type = match self { - ExtensionError::SecurityViolation { .. } => "SecurityViolation", - ExtensionError::NotFound { .. } => "NotFound", - ExtensionError::PermissionDenied { .. } => "PermissionDenied", - ExtensionError::Database { .. } => "Database", - ExtensionError::Filesystem { .. } => "Filesystem", - ExtensionError::Http { .. } => "Http", - ExtensionError::Shell { .. } => "Shell", - //ExtensionError::Io { .. } => "Io", - ExtensionError::ManifestError { .. } => "ManifestError", - ExtensionError::ValidationError { .. } => "ValidationError", - ExtensionError::DevServerError { .. } => "DevServerError", - ExtensionError::SerializationError { .. } => "SerializationError", - ExtensionError::ConfigError { .. } => "ConfigError", - }; - - state.serialize_field("type", error_type)?; + state.serialize_field("code", &self.code())?; + state.serialize_field("type", &format!("{:?}", self))?; state.serialize_field("message", &self.to_string())?; - // Add extension_id if available if let Some(ext_id) = self.extension_id() { state.serialize_field("extension_id", ext_id)?; } else { @@ -161,54 +158,16 @@ impl serde::Serialize for ExtensionError { } } -// For Tauri command serialization +impl From for String { + fn from(error: ExtensionError) -> Self { + serde_json::to_string(&error).unwrap_or_else(|_| error.to_string()) + } +} + impl From for ExtensionError { fn from(err: serde_json::Error) -> Self { - ExtensionError::SerializationError { + ExtensionError::ManifestError { reason: err.to_string(), } } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::database::error::DatabaseError; - - /* #[test] - fn test_database_error_conversion() { - let db_error = DatabaseError::access_denied("ext1", "read", "users", "no permission"); - let ext_error: ExtensionError = db_error.into(); - - assert!(ext_error.is_permission_error()); - assert_eq!(ext_error.extension_id(), Some("ext1")); - } */ - - #[test] - fn test_permission_denied_constructor() { - let error = ExtensionError::permission_denied("ext1", "write", "config.json"); - - match error { - ExtensionError::PermissionDenied { - extension_id, - operation, - resource, - } => { - assert_eq!(extension_id, "ext1"); - assert_eq!(operation, "write"); - assert_eq!(resource, "config.json"); - } - _ => panic!("Expected PermissionDenied error"), - } - } - - #[test] - fn test_serialization() { - let error = ExtensionError::permission_denied("ext1", "read", "database"); - let serialized = serde_json::to_string(&error).unwrap(); - - // Basic check that it serializes properly - assert!(serialized.contains("PermissionDenied")); - assert!(serialized.contains("ext1")); - } -} diff --git a/src-tauri/src/extension/mod.rs b/src-tauri/src/extension/mod.rs index a4485e4..c4e484c 100644 --- a/src-tauri/src/extension/mod.rs +++ b/src-tauri/src/extension/mod.rs @@ -1,19 +1,184 @@ -use crate::extension::core::{ExtensionInfoResponse, ExtensionManager}; -use tauri::State; +/// src-tauri/src/extension/mod.rs +use crate::{ + extension::{ + core::{EditablePermissions, ExtensionInfoResponse, ExtensionPreview}, + error::ExtensionError, + }, + AppState, +}; +use tauri::{AppHandle, State}; pub mod core; +pub mod crypto; pub mod database; pub mod error; pub mod filesystem; -pub mod permission_manager; +pub mod permissions; #[tauri::command] pub fn get_extension_info( extension_id: String, - extension_manager: State, + state: State, ) -> Result { - let extension = extension_manager + let extension = state + .extension_manager .get_extension(&extension_id) .ok_or_else(|| format!("Extension nicht gefunden: {}", extension_id))?; - Ok(ExtensionInfoResponse::from_extension(&extension)) + ExtensionInfoResponse::from_extension(&extension).map_err(|e| format!("{:?}", e)) +} + +#[tauri::command] +pub fn get_all_extensions(state: State) -> Result, String> { + let mut extensions = Vec::new(); + + // Production Extensions + { + let prod_exts = state + .extension_manager + .production_extensions + .lock() + .unwrap(); + for ext in prod_exts.values() { + extensions.push(ExtensionInfoResponse::from_extension(ext)?); + } + } + + // Dev Extensions + { + let dev_exts = state.extension_manager.dev_extensions.lock().unwrap(); + for ext in dev_exts.values() { + extensions.push(ExtensionInfoResponse::from_extension(ext)?); + } + } + + Ok(extensions) +} + +#[tauri::command] +pub async fn preview_extension( + state: State<'_, AppState>, + source_path: String, +) -> Result { + state + .extension_manager + .preview_extension_internal(source_path) + .await +} + +#[tauri::command] +pub async fn install_extension_with_permissions( + app_handle: AppHandle, + source_path: String, + custom_permissions: EditablePermissions, + state: State<'_, AppState>, +) -> Result { + state + .extension_manager + .install_extension_with_permissions_internal( + app_handle, + source_path, + custom_permissions, + &state, + ) + .await +} +/* #[tauri::command] +pub async fn install_extension( + app_handle: AppHandle, + source_path: String, + state: State<'_, AppState>, +) -> Result { + let source = PathBuf::from(&source_path); + + // Manifest laden + let manifest_path = source.join("manifest.json"); + let manifest_content = std::fs::read_to_string(&manifest_path) + .map_err(|e| format!("Manifest konnte nicht gelesen werden: {}", e))?; + + let manifest: ExtensionManifest = serde_json::from_str(&manifest_content) + .map_err(|e| format!("Manifest ist ungültig: {}", e))?; + + // Signatur verifizieren + let content_hash = ExtensionCrypto::hash_directory(&source)?; + ExtensionCrypto::verify_signature(&manifest.public_key, &content_hash, &manifest.signature)?; + + // Key Hash berechnen + let key_hash = manifest.calculate_key_hash()?; + let full_extension_id = format!("{}-{}", key_hash, manifest.id); + + // Zielverzeichnis mit Key Hash Prefix + let extensions_dir = app_handle + .path() + .app_data_dir() + .map_err(|e| format!("App-Datenverzeichnis nicht gefunden: {}", e))? + .join("extensions") + .join(&full_extension_id) // <- z.B. "a3f5b9c2d1e8f4-haex-pass" + .join(&manifest.version); + + // Extension-Dateien kopieren + std::fs::create_dir_all(&extensions_dir) + .map_err(|e| format!("Verzeichnis konnte nicht erstellt werden: {}", e))?; + + let source_to_copy = if source.join("dist").exists() { + source.join("dist") // Kopiere aus dist/ + } else { + source.clone() // Kopiere direkt + }; + + copy_directory( + source_to_copy.to_string_lossy().to_string(), + extensions_dir.to_string_lossy().to_string(), + )?; + + // Permissions speichern + let permissions = manifest.to_internal_permissions(); + PermissionManager::save_permissions(&state.db, &permissions) + .await + .map_err(|e| format!("Fehler beim Speichern der Permissions: {:?}", e))?; + + // Extension registrieren + let extension = Extension { + id: full_extension_id.clone(), + name: manifest.name.clone(), + source: ExtensionSource::Production { + path: extensions_dir.clone(), + version: manifest.version.clone(), + }, + manifest: manifest.clone(), + enabled: true, + last_accessed: SystemTime::now(), + }; + + state + .extension_manager + .add_production_extension(extension) + .map_err(|e| format!("Extension konnte nicht hinzugefügt werden: {:?}", e))?; + + Ok(full_extension_id) +} + */ +#[tauri::command] +pub async fn remove_extension( + app_handle: AppHandle, + extension_id: String, + extension_version: String, + state: State<'_, AppState>, +) -> Result<(), ExtensionError> { + state + .extension_manager + .remove_extension_internal(&app_handle, extension_id, extension_version, &state) + .await +} + +#[tauri::command] +pub fn is_extension_installed( + extension_id: String, + extension_version: String, + state: State<'_, AppState>, +) -> Result { + if let Some(ext) = state.extension_manager.get_extension(&extension_id) { + Ok(ext.manifest.version == extension_version) + } else { + Ok(false) + } } diff --git a/src-tauri/src/extension/permission_manager.rs b/src-tauri/src/extension/permission_manager.rs deleted file mode 100644 index 0298c13..0000000 --- a/src-tauri/src/extension/permission_manager.rs +++ /dev/null @@ -1,297 +0,0 @@ -/// src-tauri/src/extension/permission_manager.rs - -use crate::extension::error::ExtensionError; -use crate::database::DbConnection; -use crate::extension::database::permissions::DbExtensionPermission; -use serde::{Deserialize, Serialize}; -use tauri::Url; -use std::path::Path; - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct ExtensionPermissions { - pub database: Vec, - pub filesystem: Vec, - pub http: Vec, - pub shell: Vec, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct FilesystemPermission { - pub extension_id: String, - pub operation: String, // read, write, create, delete - pub path: String, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct HttpPermission { - pub extension_id: String, - pub operation: String, // get, post, put, delete - pub domain: String, - pub path_pattern: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct ShellPermission { - pub extension_id: String, - pub command: String, - pub arguments: Vec, -} - -/// Zentraler Permission Manager -pub struct PermissionManager; - -impl PermissionManager { - /// Prüft Datenbankberechtigungen - pub async fn check_database_permission( - connection: &DbConnection, - extension_id: &str, - operation: &str, - table_name: &str, - ) -> Result<(), ExtensionError> { - let permissions = Self::get_database_permissions(connection, extension_id, operation).await?; - - let has_permission = permissions - .iter() - .any(|perm| perm.resource.contains(table_name)); - - if !has_permission { - return Err(ExtensionError::permission_denied( - extension_id, - operation, - &format!("database table '{}'", table_name), - )); - } - - Ok(()) - } - - /// Prüft Dateisystem-Berechtigungen - pub async fn check_filesystem_permission( - connection: &DbConnection, - extension_id: &str, - operation: &str, - file_path: &Path, - ) -> Result<(), ExtensionError> { - let permissions = Self::get_filesystem_permissions(connection, extension_id, operation).await?; - - let file_path_str = file_path.to_string_lossy(); - let has_permission = permissions.iter().any(|perm| { - // Prüfe, ob der Pfad mit einem erlaubten Pfad beginnt oder übereinstimmt - file_path_str.starts_with(&perm.path) || - // Oder ob es ein Wildcard-Match gibt - Self::matches_path_pattern(&perm.path, &file_path_str) - }); - - if !has_permission { - return Err(ExtensionError::permission_denied( - extension_id, - operation, - &format!("filesystem path '{}'", file_path_str), - )); - } - - Ok(()) - } - - /// Prüft HTTP-Berechtigungen - pub async fn check_http_permission( - connection: &DbConnection, - extension_id: &str, - method: &str, - url: &str, - ) -> Result<(), ExtensionError> { - let permissions = Self::get_http_permissions(connection, extension_id, method).await?; - - let url_parsed = Url::parse(url).map_err(|e| { - ExtensionError::ValidationError { - reason: format!("Invalid URL: {}", e), - } - })?; - - let domain = url_parsed.host_str().unwrap_or(""); - let path = url_parsed.path(); - - let has_permission = permissions.iter().any(|perm| { - // Prüfe Domain - let domain_matches = perm.domain == "*" || - perm.domain == domain || - domain.ends_with(&format!(".{}", perm.domain)); - - // Prüfe Pfad (falls spezifiziert) - let path_matches = perm.path_pattern.as_ref() - .map(|pattern| Self::matches_path_pattern(pattern, path)) - .unwrap_or(true); - - domain_matches && path_matches - }); - - if !has_permission { - return Err(ExtensionError::permission_denied( - extension_id, - method, - &format!("HTTP request to '{}'", url), - )); - } - - Ok(()) - } - - /// Prüft Shell-Berechtigungen - pub async fn check_shell_permission( - connection: &DbConnection, - extension_id: &str, - command: &str, - args: &[String], - ) -> Result<(), ExtensionError> { - let permissions = Self::get_shell_permissions(connection, extension_id).await?; - - let has_permission = permissions.iter().any(|perm| { - // Prüfe Command - if perm.command != command && perm.command != "*" { - return false; - } - - // Prüfe Arguments (falls spezifiziert) - if !perm.arguments.is_empty() { - // Alle erforderlichen Args müssen vorhanden sein - perm.arguments.iter().all(|required_arg| { - args.iter().any(|actual_arg| { - required_arg == actual_arg || required_arg == "*" - }) - }) - } else { - true - } - }); - - if !has_permission { - return Err(ExtensionError::permission_denied( - extension_id, - "execute", - &format!("shell command '{}' with args {:?}", command, args), - )); - } - - Ok(()) - } - - // Private Helper-Methoden - - async fn get_database_permissions( - connection: &DbConnection, - extension_id: &str, - operation: &str, - ) -> Result, ExtensionError> { - // Verwende die bestehende Funktion aus dem permissions.rs - crate::extension::database::permissions::get_extension_permissions( - connection, - extension_id, - "database", - operation - ).await.map_err(ExtensionError::from) - } - - async fn get_filesystem_permissions( - connection: &DbConnection, - extension_id: &str, - operation: &str, - ) -> Result, ExtensionError> { - // Implementierung für Filesystem-Permissions - // Ähnlich wie get_database_permissions, aber für filesystem Tabelle - todo!("Implementiere Filesystem-Permission-Loading") - } - - async fn get_http_permissions( - connection: &DbConnection, - extension_id: &str, - method: &str, - ) -> Result, ExtensionError> { - // Implementierung für HTTP-Permissions - todo!("Implementiere HTTP-Permission-Loading") - } - - async fn get_shell_permissions( - connection: &DbConnection, - extension_id: &str, - ) -> Result, ExtensionError> { - // Implementierung für Shell-Permissions - todo!("Implementiere Shell-Permission-Loading") - } - - fn matches_path_pattern(pattern: &str, path: &str) -> bool { - // Einfache Wildcard-Implementierung - if pattern.ends_with('*') { - let prefix = &pattern[..pattern.len() - 1]; - path.starts_with(prefix) - } else if pattern.starts_with('*') { - let suffix = &pattern[1..]; - path.ends_with(suffix) - } else { - pattern == path - } - } -} - -// Convenience-Funktionen für die verschiedenen Subsysteme -impl PermissionManager { - /// Convenience für Datei lesen - pub async fn can_read_file( - connection: &DbConnection, - extension_id: &str, - file_path: &Path, - ) -> Result<(), ExtensionError> { - Self::check_filesystem_permission(connection, extension_id, "read", file_path).await - } - - /// Convenience für Datei schreiben - pub async fn can_write_file( - connection: &DbConnection, - extension_id: &str, - file_path: &Path, - ) -> Result<(), ExtensionError> { - Self::check_filesystem_permission(connection, extension_id, "write", file_path).await - } - - /// Convenience für HTTP GET - pub async fn can_http_get( - connection: &DbConnection, - extension_id: &str, - url: &str, - ) -> Result<(), ExtensionError> { - Self::check_http_permission(connection, extension_id, "GET", url).await - } - - /// Convenience für HTTP POST - pub async fn can_http_post( - connection: &DbConnection, - extension_id: &str, - url: &str, - ) -> Result<(), ExtensionError> { - Self::check_http_permission(connection, extension_id, "POST", url).await - } - - /// Convenience für Shell-Befehl - pub async fn can_execute_command( - connection: &DbConnection, - extension_id: &str, - command: &str, - args: &[String], - ) -> Result<(), ExtensionError> { - Self::check_shell_permission(connection, extension_id, command, args).await - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_path_pattern_matching() { - assert!(PermissionManager::matches_path_pattern("/home/user/*", "/home/user/documents/file.txt")); - assert!(PermissionManager::matches_path_pattern("*.txt", "/path/to/file.txt")); - assert!(PermissionManager::matches_path_pattern("/exact/path", "/exact/path")); - - assert!(!PermissionManager::matches_path_pattern("/home/user/*", "/etc/passwd")); - assert!(!PermissionManager::matches_path_pattern("*.txt", "/path/to/file.pdf")); - } -} \ No newline at end of file diff --git a/src-tauri/src/extension/permissions/manager.rs b/src-tauri/src/extension/permissions/manager.rs new file mode 100644 index 0000000..031b063 --- /dev/null +++ b/src-tauri/src/extension/permissions/manager.rs @@ -0,0 +1,650 @@ +use crate::AppState; +use crate::database::core::with_connection; +use crate::database::error::DatabaseError; +use crate::extension::database::executor::SqlExecutor; +use crate::extension::error::ExtensionError; +use crate::extension::permissions::types::{Action, DbConstraints, ExtensionPermission, FsConstraints, HttpConstraints, PermissionConstraints, PermissionStatus, ResourceType, ShellConstraints}; +use serde_json; +use serde_json::json; +use std::path::Path; +use tauri::State; +use url::Url; + +pub struct PermissionManager; + +impl PermissionManager { + /// Speichert alle Permissions einer Extension + pub async fn save_permissions( + app_state: &State<'_, AppState>, + extension_id: &str, + permissions: &[ExtensionPermission], + ) -> Result<(), ExtensionError> { + with_connection(&app_state.db, |conn| { + let tx = conn.transaction().map_err(DatabaseError::from)?; + + let hlc_service = app_state + .hlc + .lock() + .map_err(|_| DatabaseError::MutexPoisoned { + reason: "Failed to lock HLC service".to_string(), + })?; + + for perm in permissions { + let resource_type_str = format!("{:?}", perm.resource_type).to_lowercase(); + let action_str = format!("{:?}", perm.action).to_lowercase(); + + let constraints_json = perm + .constraints + .as_ref() + .map(|c| serde_json::to_string(c).ok()) + .flatten(); + + let sql = "INSERT INTO haex_extension_permissions + (id, extension_id, resource_type, action, target, constraints, status) + VALUES (?, ?, ?, ?, ?, ?, ?)"; + + let params = vec![ + json!(perm.id), + json!(extension_id), + json!(resource_type_str), + json!(action_str), + json!(perm.target), + json!(constraints_json), + json!(perm.status.as_str()), + ]; + + SqlExecutor::execute_internal(&tx, &hlc_service, sql, ¶ms)?; + } + + tx.commit().map_err(DatabaseError::from)?; + Ok(()) + }) + .map_err(ExtensionError::from) + } + + /// Aktualisiert eine Permission + pub async fn update_permission( + app_state: &State<'_, AppState>, + permission: &ExtensionPermission, + ) -> Result<(), ExtensionError> { + with_connection(&app_state.db, |conn| { + let tx = conn.transaction().map_err(DatabaseError::from)?; + + let hlc_service = app_state + .hlc + .lock() + .map_err(|_| DatabaseError::MutexPoisoned { + reason: "Failed to lock HLC service".to_string(), + })?; + + let resource_type_str = format!("{:?}", permission.resource_type).to_lowercase(); + let action_str = format!("{:?}", permission.action).to_lowercase(); + + let constraints_json = permission + .constraints + .as_ref() + .map(|c| serde_json::to_string(c).ok()) + .flatten(); + + let sql = "UPDATE haex_extension_permissions + SET resource_type = ?, action = ?, target = ?, constraints = ?, status = ? + WHERE id = ?"; + + let params = vec![ + json!(resource_type_str), + json!(action_str), + json!(permission.target), + json!(constraints_json), + json!(permission.status.as_str()), + json!(permission.id), + ]; + + SqlExecutor::execute_internal(&tx, &hlc_service, sql, ¶ms)?; + + tx.commit().map_err(DatabaseError::from)?; + Ok(()) + }) + .map_err(ExtensionError::from) + } + + /// Ändert den Status einer Permission + pub async fn update_permission_status( + app_state: &State<'_, AppState>, + permission_id: &str, + new_status: PermissionStatus, + ) -> Result<(), ExtensionError> { + with_connection(&app_state.db, |conn| { + let tx = conn.transaction().map_err(DatabaseError::from)?; + + let hlc_service = app_state + .hlc + .lock() + .map_err(|_| DatabaseError::MutexPoisoned { + reason: "Failed to lock HLC service".to_string(), + })?; + + let sql = "UPDATE haex_extension_permissions + SET status = ? + WHERE id = ?"; + + let params = vec![json!(new_status.as_str()), json!(permission_id)]; + + SqlExecutor::execute_internal(&tx, &hlc_service, sql, ¶ms)?; + + tx.commit().map_err(DatabaseError::from)?; + Ok(()) + }) + .map_err(ExtensionError::from) + } + + /// Löscht alle Permissions einer Extension + pub async fn delete_permission( + app_state: &State<'_, AppState>, + permission_id: &str, + ) -> Result<(), ExtensionError> { + with_connection(&app_state.db, |conn| { + let tx = conn.transaction().map_err(DatabaseError::from)?; + + let hlc_service = app_state.hlc.lock() + .map_err(|_| DatabaseError::MutexPoisoned { + reason: "Failed to lock HLC service".to_string(), + })?; + + // Echtes DELETE - wird vom CrdtTransformer zu UPDATE umgewandelt + let sql = "DELETE FROM haex_extension_permissions WHERE id = ?"; + + let params = vec![json!(permission_id)]; + + SqlExecutor::execute_internal(&tx, &hlc_service, sql, ¶ms)?; + + tx.commit().map_err(DatabaseError::from)?; + Ok(()) + }).map_err(ExtensionError::from) + } + + /// Löscht alle Permissions einer Extension (Soft-Delete) + pub async fn delete_permissions( + app_state: &State<'_, AppState>, + extension_id: &str, + ) -> Result<(), ExtensionError> { + with_connection(&app_state.db, |conn| { + let tx = conn.transaction().map_err(DatabaseError::from)?; + + let hlc_service = app_state.hlc.lock() + .map_err(|_| DatabaseError::MutexPoisoned { + reason: "Failed to lock HLC service".to_string(), + })?; + + // Echtes DELETE - wird vom CrdtTransformer zu UPDATE umgewandelt + let sql = "DELETE FROM haex_extension_permissions WHERE extension_id = ?"; + + let params = vec![json!(extension_id)]; + + SqlExecutor::execute_internal(&tx, &hlc_service, sql, ¶ms)?; + + tx.commit().map_err(DatabaseError::from)?; + Ok(()) + }).map_err(ExtensionError::from) + } + /// Lädt alle Permissions einer Extension + pub async fn get_permissions( + app_state: &State<'_, AppState>, + extension_id: &str, + ) -> Result, ExtensionError> { + with_connection(&app_state.db, |conn| { + let sql = "SELECT id, extension_id, resource_type, action, target, constraints, status, haex_timestamp, haex_tombstone + FROM haex_extension_permissions + WHERE extension_id = ?"; + + let params = vec![json!(extension_id)]; + + // SELECT nutzt select_internal + let results = SqlExecutor::select_internal(conn, sql, ¶ms)?; + + // Parse JSON results zu ExtensionPermission + let permissions = results + .into_iter() + .map(|row| Self::parse_permission_from_json(row)) + .collect::, _>>()?; + + Ok(permissions) + }).map_err(ExtensionError::from) + } + + // Helper für JSON -> ExtensionPermission Konvertierung + fn parse_permission_from_json(json: serde_json::Value) -> Result { + + let obj = json.as_object().ok_or_else(|| DatabaseError::SerializationError { + reason: "Expected JSON object".to_string(), + })?; + + let resource_type = Self::parse_resource_type( + obj.get("resource_type") + .and_then(|v| v.as_str()) + .ok_or_else(|| DatabaseError::SerializationError { + reason: "Missing resource_type".to_string(), + })? + )?; + + let action = Self::parse_action( + obj.get("action") + .and_then(|v| v.as_str()) + .ok_or_else(|| DatabaseError::SerializationError { + reason: "Missing action".to_string(), + })? + )?; + + let status = PermissionStatus::from_str( + obj.get("status") + .and_then(|v| v.as_str()) + .ok_or_else(|| DatabaseError::SerializationError { + reason: "Missing status".to_string(), + })? + )?; // Jetzt funktioniert das ? + + let constraints = obj.get("constraints") + .and_then(|v| v.as_str()) + .map(|json_str| Self::parse_constraints(&resource_type, json_str)) + .transpose()?; + + Ok(ExtensionPermission { + id: obj.get("id") + .and_then(|v| v.as_str()) + .ok_or_else(|| DatabaseError::SerializationError { + reason: "Missing id".to_string(), + })? + .to_string(), + extension_id: obj.get("extension_id") + .and_then(|v| v.as_str()) + .ok_or_else(|| DatabaseError::SerializationError { + reason: "Missing extension_id".to_string(), + })? + .to_string(), + resource_type, + action, + target: obj.get("target") + .and_then(|v| v.as_str()) + .ok_or_else(|| DatabaseError::SerializationError { + reason: "Missing target".to_string(), + })? + .to_string(), + constraints, + status, + haex_timestamp: obj.get("haex_timestamp") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + haex_tombstone: obj.get("haex_tombstone") + .and_then(|v| v.as_i64()) + .map(|i| i == 1), + }) + } + + /// Prüft Datenbankberechtigungen + pub async fn check_database_permission( + app_state: &State<'_, AppState>, + extension_id: &str, + action: Action, + table_name: &str, + ) -> Result<(), ExtensionError> { + let permissions = Self::get_permissions(app_state, extension_id).await?; + + let has_permission = permissions + .iter() + .filter(|perm| perm.status == PermissionStatus::Granted) // NUR granted! + .filter(|perm| perm.resource_type == ResourceType::Db) + .filter(|perm| perm.action == action) // action ist nicht mehr Option + .any(|perm| { + if perm.target != "*" && perm.target != table_name { + return false; + } + true + }); + + if !has_permission { + return Err(ExtensionError::permission_denied( + extension_id, + &format!("{:?}", action), + &format!("database table '{}'", table_name), + )); + } + + Ok(()) + } + + /// Prüft Dateisystem-Berechtigungen + pub async fn check_filesystem_permission( + app_state: &State<'_, AppState>, + extension_id: &str, + action: Action, + file_path: &Path, + ) -> Result<(), ExtensionError> { + let permissions = Self::get_permissions(app_state, extension_id).await?; + + let file_path_str = file_path.to_string_lossy(); + + let has_permission = permissions + .iter() + .filter(|perm| perm.status == PermissionStatus::Granted) + .filter(|perm| perm.resource_type == ResourceType::Fs) + .filter(|perm| perm.action == action) + .any(|perm| { + if !Self::matches_path_pattern(&perm.target, &file_path_str) { + return false; + } + + if let Some(PermissionConstraints::Filesystem(constraints)) = &perm.constraints { + if let Some(allowed_ext) = &constraints.allowed_extensions { + if let Some(ext) = file_path.extension() { + let ext_str = format!(".{}", ext.to_string_lossy()); + if !allowed_ext.contains(&ext_str) { + return false; + } + } else { + return false; + } + } + } + + true + }); + + if !has_permission { + return Err(ExtensionError::permission_denied( + extension_id, + &format!("{:?}", action), + &format!("filesystem path '{}'", file_path_str), + )); + } + + Ok(()) + } + + /// Prüft HTTP-Berechtigungen + pub async fn check_http_permission( + app_state: &State<'_, AppState>, + extension_id: &str, + method: &str, + url: &str, + ) -> Result<(), ExtensionError> { + let permissions = Self::get_permissions(app_state, extension_id).await?; + + let url_parsed = Url::parse(url).map_err(|e| ExtensionError::ValidationError { + reason: format!("Invalid URL: {}", e), + })?; + + let domain = url_parsed.host_str().unwrap_or(""); + + let has_permission = permissions + .iter() + .filter(|perm| perm.status == PermissionStatus::Granted) + .filter(|perm| perm.resource_type == ResourceType::Http) + .any(|perm| { + let domain_matches = perm.target == "*" + || perm.target == domain + || domain.ends_with(&format!(".{}", perm.target)); + + if !domain_matches { + return false; + } + + if let Some(PermissionConstraints::Http(constraints)) = &perm.constraints { + if let Some(methods) = &constraints.methods { + if !methods.iter().any(|m| m.eq_ignore_ascii_case(method)) { + return false; + } + } + } + + true + }); + + if !has_permission { + return Err(ExtensionError::permission_denied( + extension_id, + method, + &format!("HTTP request to '{}'", url), + )); + } + + Ok(()) + } + + /// Prüft Shell-Berechtigungen + pub async fn check_shell_permission( + app_state: &State<'_, AppState>, + extension_id: &str, + command: &str, + args: &[String], + ) -> Result<(), ExtensionError> { + let permissions = Self::get_permissions(app_state, extension_id).await?; + + let has_permission = permissions + .iter() + .filter(|perm| perm.status == PermissionStatus::Granted) + .filter(|perm| perm.resource_type == ResourceType::Shell) + .any(|perm| { + if perm.target != command && perm.target != "*" { + return false; + } + + if let Some(PermissionConstraints::Shell(constraints)) = &perm.constraints { + if let Some(allowed_subcommands) = &constraints.allowed_subcommands { + if !args.is_empty() { + if !allowed_subcommands.contains(&args[0]) + && !allowed_subcommands.contains(&"*".to_string()) + { + return false; + } + } + } + + if let Some(forbidden) = &constraints.forbidden_args { + if args.iter().any(|arg| forbidden.contains(arg)) { + return false; + } + } + + if let Some(allowed_flags) = &constraints.allowed_flags { + let user_flags: Vec<_> = + args.iter().filter(|arg| arg.starts_with('-')).collect(); + + for flag in user_flags { + if !allowed_flags.contains(flag) + && !allowed_flags.contains(&"*".to_string()) + { + return false; + } + } + } + } + + true + }); + + if !has_permission { + return Err(ExtensionError::permission_denied( + extension_id, + "execute", + &format!("shell command '{}' with args {:?}", command, args), + )); + } + + Ok(()) + } + + // Helper-Methoden - müssen DatabaseError statt ExtensionError zurückgeben + fn parse_resource_type(s: &str) -> Result { + match s { + "fs" => Ok(ResourceType::Fs), + "http" => Ok(ResourceType::Http), + "db" => Ok(ResourceType::Db), + "shell" => Ok(ResourceType::Shell), + _ => Err(DatabaseError::SerializationError { + reason: format!("Unknown resource type: {}", s), + }), + } + } + + fn parse_action(s: &str) -> Result { + match s { + "read" => Ok(Action::Read), + "write" => Ok(Action::Write), + _ => Err(DatabaseError::SerializationError { + reason: format!("Unknown action: {}", s), + }), + } + } + + fn parse_constraints( + resource_type: &ResourceType, + json: &str, + ) -> Result { + match resource_type { + ResourceType::Db => { + let constraints: DbConstraints = serde_json::from_str(json) + .map_err(|e| DatabaseError::SerializationError { + reason: format!("Failed to parse DB constraints: {}", e), + })?; + Ok(PermissionConstraints::Database(constraints)) + } + ResourceType::Fs => { + let constraints: FsConstraints = serde_json::from_str(json) + .map_err(|e| DatabaseError::SerializationError { + reason: format!("Failed to parse FS constraints: {}", e), + })?; + Ok(PermissionConstraints::Filesystem(constraints)) + } + ResourceType::Http => { + let constraints: HttpConstraints = serde_json::from_str(json) + .map_err(|e| DatabaseError::SerializationError { + reason: format!("Failed to parse HTTP constraints: {}", e), + })?; + Ok(PermissionConstraints::Http(constraints)) + } + ResourceType::Shell => { + let constraints: ShellConstraints = serde_json::from_str(json) + .map_err(|e| DatabaseError::SerializationError { + reason: format!("Failed to parse Shell constraints: {}", e), + })?; + Ok(PermissionConstraints::Shell(constraints)) + } + } + } + + fn matches_path_pattern(pattern: &str, path: &str) -> bool { + if pattern.ends_with("/*") { + let prefix = &pattern[..pattern.len() - 2]; + return path.starts_with(prefix); + } + + if pattern.starts_with("*.") { + let suffix = &pattern[1..]; + return path.ends_with(suffix); + } + + if pattern.contains('*') { + let parts: Vec<&str> = pattern.split('*').collect(); + if parts.len() == 2 { + return path.starts_with(parts[0]) && path.ends_with(parts[1]); + } + } + + pattern == path || pattern == "*" + } + + + +} + +// Convenience-Funktionen für die verschiedenen Subsysteme +impl PermissionManager { + // Convenience-Methoden + pub async fn can_read_file( + app_state: &State<'_, AppState>, + extension_id: &str, + file_path: &Path, + ) -> Result<(), ExtensionError> { + Self::check_filesystem_permission(app_state, extension_id, Action::Read, file_path).await + } + + pub async fn can_write_file( + app_state: &State<'_, AppState>, + extension_id: &str, + file_path: &Path, + ) -> Result<(), ExtensionError> { + Self::check_filesystem_permission(app_state, extension_id, Action::Write, file_path).await + } + + pub async fn can_read_table( + app_state: &State<'_, AppState>, + extension_id: &str, + table_name: &str, + ) -> Result<(), ExtensionError> { + Self::check_database_permission(app_state, extension_id, Action::Read, table_name).await + } + + pub async fn can_write_table( + app_state: &State<'_, AppState>, + extension_id: &str, + table_name: &str, + ) -> Result<(), ExtensionError> { + Self::check_database_permission(app_state, extension_id, Action::Write, table_name).await + } + + pub async fn can_http_get( + app_state: &State<'_, AppState>, + extension_id: &str, + url: &str, + ) -> Result<(), ExtensionError> { + Self::check_http_permission(app_state, extension_id, "GET", url).await + } + + pub async fn can_http_post( + app_state: &State<'_, AppState>, + extension_id: &str, + url: &str, + ) -> Result<(), ExtensionError> { + Self::check_http_permission(app_state, extension_id, "POST", url).await + } + + pub async fn can_execute_command( + app_state: &State<'_, AppState>, + extension_id: &str, + command: &str, + args: &[String], + ) -> Result<(), ExtensionError> { + Self::check_shell_permission(app_state, extension_id, command, args).await + } + + pub async fn grant_permission( + app_state: &State<'_, AppState>, + permission_id: &str, + ) -> Result<(), ExtensionError> { + Self::update_permission_status(app_state, permission_id, PermissionStatus::Granted).await + } + + pub async fn deny_permission( + app_state: &State<'_, AppState>, + permission_id: &str, + ) -> Result<(), ExtensionError> { + Self::update_permission_status(app_state, permission_id, PermissionStatus::Denied).await + } + + pub async fn ask_permission( + app_state: &State<'_, AppState>, + permission_id: &str, + ) -> Result<(), ExtensionError> { + Self::update_permission_status(app_state, permission_id, PermissionStatus::Ask).await + } + + pub async fn get_ask_permissions( + app_state: &State<'_, AppState>, + extension_id: &str, + ) -> Result, ExtensionError> { + let all_permissions = Self::get_permissions(app_state, extension_id).await?; + Ok(all_permissions + .into_iter() + .filter(|perm| perm.status == PermissionStatus::Ask) + .collect()) + } +} diff --git a/src-tauri/src/extension/permissions/mod.rs b/src-tauri/src/extension/permissions/mod.rs new file mode 100644 index 0000000..740af61 --- /dev/null +++ b/src-tauri/src/extension/permissions/mod.rs @@ -0,0 +1,3 @@ +pub mod manager; +pub mod types; +pub mod validator; diff --git a/src-tauri/src/extension/permissions/types.rs b/src-tauri/src/extension/permissions/types.rs new file mode 100644 index 0000000..c4104c4 --- /dev/null +++ b/src-tauri/src/extension/permissions/types.rs @@ -0,0 +1,156 @@ +use serde::{Deserialize, Serialize}; + +use crate::database::error::DatabaseError; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ExtensionPermission { + pub id: String, + pub extension_id: String, + pub resource_type: ResourceType, + pub action: Action, + pub target: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub constraints: Option, + pub status: PermissionStatus, + + // CRDT Felder + #[serde(skip_serializing_if = "Option::is_none")] + pub haex_tombstone: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub haex_timestamp: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum ResourceType { + Fs, + Http, + Db, + Shell, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum Action { + Read, + Write, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum PermissionStatus { + Ask, + Granted, + Denied, +} + +impl PermissionStatus { + pub fn as_str(&self) -> &str { + match self { + PermissionStatus::Ask => "ask", + PermissionStatus::Granted => "granted", + PermissionStatus::Denied => "denied", + } + } + + pub fn from_str(s: &str) -> Result { + match s { + "ask" => Ok(PermissionStatus::Ask), + "granted" => Ok(PermissionStatus::Granted), + "denied" => Ok(PermissionStatus::Denied), + _ => Err(DatabaseError::SerializationError { + reason: format!("Unknown permission status: {}", s), + }), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(untagged)] +pub enum PermissionConstraints { + Database(DbConstraints), + Filesystem(FsConstraints), + Http(HttpConstraints), + Shell(ShellConstraints), +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct DbConstraints { + #[serde(skip_serializing_if = "Option::is_none")] + pub where_clause: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub columns: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct FsConstraints { + #[serde(skip_serializing_if = "Option::is_none")] + pub max_file_size: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_extensions: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub recursive: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct HttpConstraints { + #[serde(skip_serializing_if = "Option::is_none")] + pub methods: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub rate_limit: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct RateLimit { + pub requests: u32, + pub per_minutes: u32, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ShellConstraints { + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_subcommands: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_flags: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub forbidden_args: Option>, +} + +// Wenn du weiterhin gruppierte Permissions brauchst: +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct EditablePermissions { + pub permissions: Vec, +} + +// Oder gruppiert nach Typ: +impl EditablePermissions { + pub fn database_permissions(&self) -> Vec<&ExtensionPermission> { + self.permissions + .iter() + .filter(|p| p.resource_type == ResourceType::Db) + .collect() + } + + pub fn filesystem_permissions(&self) -> Vec<&ExtensionPermission> { + self.permissions + .iter() + .filter(|p| p.resource_type == ResourceType::Fs) + .collect() + } + + pub fn http_permissions(&self) -> Vec<&ExtensionPermission> { + self.permissions + .iter() + .filter(|p| p.resource_type == ResourceType::Http) + .collect() + } + + pub fn shell_permissions(&self) -> Vec<&ExtensionPermission> { + self.permissions + .iter() + .filter(|p| p.resource_type == ResourceType::Shell) + .collect() + } +} diff --git a/src-tauri/src/extension/permissions/validator.rs b/src-tauri/src/extension/permissions/validator.rs new file mode 100644 index 0000000..bba9dc6 --- /dev/null +++ b/src-tauri/src/extension/permissions/validator.rs @@ -0,0 +1,201 @@ +// src-tauri/src/extension/permissions/validator.rs + +use crate::database::core::{extract_table_names_from_sql, parse_single_statement}; +use crate::database::error::DatabaseError; +use crate::extension::error::ExtensionError; +use crate::extension::permissions::manager::PermissionManager; +use crate::extension::permissions::types::Action; +use crate::AppState; +use sqlparser::ast::{Statement, TableFactor, TableObject}; +use tauri::State; + +pub struct SqlPermissionValidator; + +impl SqlPermissionValidator { + /// Validiert ein SQL-Statement gegen die Permissions einer Extension + pub async fn validate_sql( + app_state: &State<'_, AppState>, + extension_id: &str, + sql: &str, + ) -> Result<(), ExtensionError> { + let statement = parse_single_statement(sql).map_err(|e| DatabaseError::ParseError { + reason: e.to_string(), + sql: sql.to_string(), + })?; + + match &statement { + Statement::Query(_) => { + Self::validate_read_statement(app_state, extension_id, sql).await + } + Statement::Insert(_) | Statement::Update { .. } | Statement::Delete(_) => { + Self::validate_write_statement(app_state, extension_id, &statement).await + } + Statement::CreateTable(_) => { + Self::validate_create_statement(app_state, extension_id, &statement).await + } + Statement::AlterTable { .. } | Statement::Drop { .. } => { + Self::validate_schema_statement(app_state, extension_id, &statement).await + } + _ => Err(ExtensionError::ValidationError { + reason: format!("Statement type not allowed: {}", sql), + }), + } + } + + /// Validiert READ-Operationen (SELECT) + async fn validate_read_statement( + app_state: &State<'_, AppState>, + extension_id: &str, + sql: &str, + ) -> Result<(), ExtensionError> { + let tables = extract_table_names_from_sql(sql)?; + + for table_name in tables { + PermissionManager::check_database_permission( + app_state, + extension_id, + Action::Read, + &table_name, + ) + .await?; + } + + Ok(()) + } + + /// Validiert WRITE-Operationen (INSERT, UPDATE, DELETE) + async fn validate_write_statement( + app_state: &State<'_, AppState>, + extension_id: &str, + statement: &Statement, + ) -> Result<(), ExtensionError> { + let table_names = Self::extract_table_names_from_statement(statement)?; + + for table_name in table_names { + PermissionManager::check_database_permission( + app_state, + extension_id, + Action::Write, + &table_name, + ) + .await?; + } + + Ok(()) + } + + /// Validiert CREATE TABLE + async fn validate_create_statement( + app_state: &State<'_, AppState>, + extension_id: &str, + statement: &Statement, + ) -> Result<(), ExtensionError> { + if let Statement::CreateTable(create_table) = statement { + let table_name = create_table.name.to_string(); + + // Prüfe ob Extension überhaupt CREATE-Rechte hat (z.B. auf "*") + PermissionManager::check_database_permission( + app_state, + extension_id, + Action::Write, + &table_name, + ) + .await?; + } + + Ok(()) + } + + /// Validiert Schema-Änderungen (ALTER, DROP) + async fn validate_schema_statement( + app_state: &State<'_, AppState>, + extension_id: &str, + statement: &Statement, + ) -> Result<(), ExtensionError> { + let table_names = Self::extract_table_names_from_statement(statement)?; + + for table_name in table_names { + // ALTER/DROP benötigen WRITE-Rechte + PermissionManager::check_database_permission( + app_state, + extension_id, + Action::Write, + &table_name, + ) + .await?; + } + + Ok(()) + } + + /// Extrahiert alle Tabellennamen aus einem Statement + fn extract_table_names_from_statement( + statement: &Statement, + ) -> Result, ExtensionError> { + match statement { + Statement::Insert(insert) => Ok(vec![Self::extract_table_name_from_insert(insert)?]), + Statement::Update { table, .. } => { + Ok(vec![Self::extract_table_name_from_table_factor( + &table.relation, + )?]) + } + Statement::Delete(delete) => Ok(vec![Self::extract_table_name_from_delete(delete)?]), + Statement::CreateTable(create_table) => Ok(vec![create_table.name.to_string()]), + Statement::AlterTable { name, .. } => Ok(vec![name.to_string()]), + Statement::Drop { names, .. } => { + Ok(names.iter().map(|name| name.to_string()).collect()) + } + _ => Ok(vec![]), + } + } + + /// Extrahiert Tabellenname aus INSERT + fn extract_table_name_from_insert( + insert: &sqlparser::ast::Insert, + ) -> Result { + match &insert.table { + TableObject::TableName(name) => Ok(name.to_string()), + _ => Err(DatabaseError::NoTableError { + sql: insert.to_string(), + } + .into()), + } + } + + /// Extrahiert Tabellenname aus TableFactor + fn extract_table_name_from_table_factor( + table_factor: &TableFactor, + ) -> Result { + match table_factor { + TableFactor::Table { name, .. } => Ok(name.to_string()), + _ => Err(DatabaseError::StatementError { + reason: "Complex table references not supported".to_string(), + } + .into()), + } + } + + /// Extrahiert Tabellenname aus DELETE + fn extract_table_name_from_delete( + delete: &sqlparser::ast::Delete, + ) -> Result { + use sqlparser::ast::FromTable; + + let table_name = match &delete.from { + FromTable::WithFromKeyword(tables) | FromTable::WithoutKeyword(tables) => { + if !tables.is_empty() { + Self::extract_table_name_from_table_factor(&tables[0].relation)? + } else if !delete.tables.is_empty() { + delete.tables[0].to_string() + } else { + return Err(DatabaseError::NoTableError { + sql: delete.to_string(), + } + .into()); + } + } + }; + + Ok(table_name) + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index dffe792..fcfde1e 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,28 +1,22 @@ -//mod browser; -//mod android_storage; mod crdt; mod database; mod extension; - -//mod models; +use crate::{ + crdt::hlc::HlcService, + database::DbConnection, + extension::core::{ExtensionManager, ExtensionState}, +}; +use std::sync::{Arc, Mutex}; +use tauri::Manager; pub mod table_names { include!(concat!(env!("OUT_DIR"), "/tableNames.rs")); } -use std::sync::{Arc, Mutex}; - -use crate::{crdt::hlc::HlcService, database::DbConnection, extension::core::ExtensionState}; - -/* use crate::{ - crdt::hlc::HlcService, - database::{AppState, DbConnection}, - extension::core::ExtensionState, -}; */ - pub struct AppState { pub db: DbConnection, - pub hlc: Mutex, // Kein Arc hier nötig, da der ganze AppState von Tauri in einem Arc verwaltet wird. + pub hlc: Mutex, + pub extension_manager: ExtensionManager, } #[cfg_attr(mobile, tauri::mobile_entry_point)] @@ -31,26 +25,27 @@ pub fn run() { tauri::Builder::default() .register_uri_scheme_protocol(protocol_name, move |context, request| { - match extension::core::extension_protocol_handler(&context, &request) { - Ok(response) => response, // Wenn der Handler Ok ist, gib die Response direkt zurück + // Hole den AppState aus dem Context + let app_handle = context.app_handle(); + let state = app_handle.state::(); + + // Rufe den Handler mit allen benötigten Parametern auf + match extension::core::extension_protocol_handler(state, &app_handle, &request) { + Ok(response) => response, Err(e) => { - // Wenn der Handler einen Fehler zurückgibt, logge ihn und erstelle eine Fehler-Response eprintln!( "Fehler im Custom Protocol Handler für URI '{}': {}", request.uri(), e ); - // Erstelle eine HTTP 500 Fehler-Response - // Du kannst hier auch spezifischere Fehler-Responses bauen, falls gewünscht. tauri::http::Response::builder() .status(500) - .header("Content-Type", "text/plain") // Optional, aber gut für Klarheit + .header("Content-Type", "text/plain") .body(Vec::from(format!( "Interner Serverfehler im Protokollhandler: {}", e ))) .unwrap_or_else(|build_err| { - // Fallback, falls selbst das Erstellen der Fehler-Response fehlschlägt eprintln!("Konnte Fehler-Response nicht erstellen: {}", build_err); tauri::http::Response::builder() .status(500) @@ -60,11 +55,10 @@ pub fn run() { } } }) - /* .manage(database::DbConnection(Arc::new(Mutex::new(None)))) - .manage(crdt::hlc::HlcService::new()) */ .manage(AppState { db: DbConnection(Arc::new(Mutex::new(None))), - hlc: Mutex::new(HlcService::new()), // Starte mit einem uninitialisierten HLC + hlc: Mutex::new(HlcService::new()), + extension_manager: ExtensionManager::new(), }) .manage(ExtensionState::default()) .plugin(tauri_plugin_dialog::init()) @@ -75,7 +69,6 @@ pub fn run() { .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_persisted_scope::init()) .plugin(tauri_plugin_store::Builder::new().build()) - //.plugin(tauri_plugin_android_fs::init()) .invoke_handler(tauri::generate_handler![ database::create_encrypted_database, database::delete_vault, @@ -86,36 +79,13 @@ pub fn run() { database::vault_exists, extension::database::extension_sql_execute, extension::database::extension_sql_select, - //database::update_hlc_from_remote, - /* extension::copy_directory, - extension::database::extension_sql_select, */ + extension::get_all_extensions, + extension::get_extension_info, + extension::install_extension_with_permissions, + extension::is_extension_installed, + extension::preview_extension, + extension::remove_extension, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } - -/* fn extension_protocol_handler( - app_handle: &tauri::AppHandle, // Beachten Sie die Signaturänderung in neueren Tauri-Versionen - request: &tauri::http::Request>, -) -> Result>, Box> { - let uri_str = request.uri().to_string(); -let parsed_url = match Url::parse(&uri_str) { - Ok(url) => url, - Err(e) => { - eprintln!("Fehler beim Parsen der URL '{}': {}", uri_str, e); - return Ok(tauri::http::ResponseBuilder::new().status(400).body(Vec::from("Ungültige URL"))?); - } -}; - -let plugin_id = parsed_url.host_str().ok_or_else(|| "Fehlende Plugin-ID in der URL".to_string())?; -let path_segments: Vec<&str> = parsed_url.path_segments().ok_or_else(|| "URL hat keinen Pfad".to_string())?.collect(); - -if path_segments.len() < 2 { - eprintln!("Unvollständiger Pfad in URL: {}", uri_str); - return Ok(tauri::http::Response::new().status(400).body(Vec::from("Unvollständiger Pfad"))?); -} - -let version = path_segments; -let file_path = path_segments[1..].join("/"); - Ok(tauri::http::Response::builder()::new().status(404).body(Vec::new())?) -} */ diff --git a/src/components/haex/extension/card.vue b/src/components/haex/extension/card.vue index 35ac6b9..256f3cf 100644 --- a/src/components/haex/extension/card.vue +++ b/src/components/haex/extension/card.vue @@ -4,20 +4,9 @@ v-bind="$attrs" >
- - - - - + + +
@@ -44,6 +33,7 @@
--> + hier klicken
- +
    -
  • -
    - - -
    -
  • -
-
- - - - -
    -
  • +
  • - + :id="Object.keys(read).at(0)" + type="checkbox" + class="checkbox" + :checked="Object.values(read).at(0)" + /> +
-
+ - +
    -
  • +
  • - + :id="Object.keys(write).at(0)" + type="checkbox" + class="checkbox" + :checked="Object.values(write).at(0)" + /> +
-
+ + + + + +
    +
  • +
    + + +
    +
  • +
+
- de: - permission: - read: Lesen - write: Schreiben - create: Erstellen +de: + permission: + read: Lesen + write: Schreiben + create: Erstellen - en: - permission: - read: Read - write: Write - create: Create +en: + permission: + read: Read + write: Write + create: Create diff --git a/src/components/haex/extension/manifest/permissions/filesystem.vue b/src/components/haex/extension/manifest/permissions/filesystem.vue index 46f031d..5cebc37 100644 --- a/src/components/haex/extension/manifest/permissions/filesystem.vue +++ b/src/components/haex/extension/manifest/permissions/filesystem.vue @@ -1,38 +1,56 @@ - de: - permission: - read: Lesen - write: Schreiben +de: + permission: + read: Lesen + write: Schreiben - en: - permission: - read: Read - write: Write +en: + permission: + read: Read + write: Write diff --git a/src/components/haex/extension/manifest/permissions/http.vue b/src/components/haex/extension/manifest/permissions/http.vue index 0d6c464..47bde8f 100644 --- a/src/components/haex/extension/manifest/permissions/http.vue +++ b/src/components/haex/extension/manifest/permissions/http.vue @@ -1,33 +1,43 @@ - de: - http: - access: Internet Zugriff +de: + http: + access: Internet Zugriff - en: - http: - access: Internet Access +en: + http: + access: Internet Access diff --git a/src/composables/extensionContextBroadcast.ts b/src/composables/extensionContextBroadcast.ts index fc2a2c2..9e24880 100644 --- a/src/composables/extensionContextBroadcast.ts +++ b/src/composables/extensionContextBroadcast.ts @@ -1,15 +1,17 @@ -/** - * Broadcasts context changes to all active extensions - */ +// composables/extensionContextBroadcast.ts export const useExtensionContextBroadcast = () => { - const extensionIframes = ref([]) + // Globaler State für alle aktiven IFrames + const extensionIframes = useState>( + 'extension-iframes', + () => new Set(), + ) const registerExtensionIframe = (iframe: HTMLIFrameElement) => { - extensionIframes.value.push(iframe) + extensionIframes.value.add(iframe) } const unregisterExtensionIframe = (iframe: HTMLIFrameElement) => { - extensionIframes.value = extensionIframes.value.filter((f) => f !== iframe) + extensionIframes.value.delete(iframe) } const broadcastContextChange = (context: { diff --git a/src/composables/extensionMessageHandler.ts b/src/composables/extensionMessageHandler.ts index 561d731..1285ff0 100644 --- a/src/composables/extensionMessageHandler.ts +++ b/src/composables/extensionMessageHandler.ts @@ -1,4 +1,6 @@ -import type { IHaexHubExtensionLink } from '~/types/haexhub' +// composables/extensionMessageHandler.ts +import { invoke } from '@tauri-apps/api/core' +import type { IHaexHubExtension } from '~/types/haexhub' interface ExtensionRequest { id: string @@ -7,119 +9,124 @@ interface ExtensionRequest { timestamp: number } -interface ExtensionResponse { - id: string - result?: unknown - error?: { - code: string - message: string - details?: unknown - } -} +// Globaler Handler - nur einmal registriert +let globalHandlerRegistered = false +const iframeRegistry = new Map() -export const useExtensionMessageHandler = ( - iframeRef: Ref, - extension: ComputedRef, -) => { - const handleMessage = async (event: MessageEvent) => { - // Security: Only accept messages from our iframe - if (!iframeRef.value || event.source !== iframeRef.value.contentWindow) { - return +const registerGlobalMessageHandler = () => { + if (globalHandlerRegistered) return + + window.addEventListener('message', async (event: MessageEvent) => { + // Finde die Extension für dieses IFrame + let extension: IHaexHubExtension | undefined + let sourceIframe: HTMLIFrameElement | undefined + + for (const [iframe, ext] of iframeRegistry.entries()) { + if (event.source === iframe.contentWindow) { + extension = ext + sourceIframe = iframe + break + } + } + + if (!extension || !sourceIframe) { + return // Message ist nicht von einem registrierten IFrame } const request = event.data as ExtensionRequest - // Validate request structure if (!request.id || !request.method) { console.error('Invalid extension request:', request) return } - console.log('[HaexHub] Extension request:', request.method, request.params) + console.log( + `[HaexHub] ${extension.name} request:`, + request.method, + request.params, + ) try { let result: unknown - // Route request to appropriate handler if (request.method.startsWith('extension.')) { - result = await handleExtensionMethod(request, extension) + result = await handleExtensionMethodAsync(request, extension) } else if (request.method.startsWith('db.')) { - result = await handleDatabaseMethod(request, extension) + result = await handleDatabaseMethodAsync(request, extension) + } else if (request.method.startsWith('fs.')) { + result = await handleFilesystemMethodAsync(request, extension) + } else if (request.method.startsWith('http.')) { + result = await handleHttpMethodAsync(request, extension) } else if (request.method.startsWith('permissions.')) { - result = await handlePermissionsMethod(request, extension) + result = await handlePermissionsMethodAsync(request, extension) } else if (request.method.startsWith('context.')) { - result = await handleContextMethod(request) - } else if (request.method.startsWith('search.')) { - result = await handleSearchMethod(request, extension) + result = await handleContextMethodAsync(request) } else { throw new Error(`Unknown method: ${request.method}`) } - // Send success response - sendResponse(iframeRef.value, { - id: request.id, - result, - }) + sourceIframe.contentWindow?.postMessage( + { + id: request.id, + result, + }, + '*', + ) } catch (error) { console.error('[HaexHub] Extension request error:', error) - // Send error response - sendResponse(iframeRef.value, { - id: request.id, - error: { - code: 'INTERNAL_ERROR', - message: error instanceof Error ? error.message : 'Unknown error', - details: error, + sourceIframe.contentWindow?.postMessage( + { + id: request.id, + error: { + code: 'INTERNAL_ERROR', + message: error instanceof Error ? error.message : 'Unknown error', + details: error, + }, }, - }) + '*', + ) } - } - - const sendResponse = ( - iframe: HTMLIFrameElement, - response: ExtensionResponse, - ) => { - iframe.contentWindow?.postMessage(response, '*') - } - - // Register/unregister message listener - onMounted(() => { - window.addEventListener('message', handleMessage) }) + globalHandlerRegistered = true +} + +export const useExtensionMessageHandler = ( + iframeRef: Ref, + extension: ComputedRef, +) => { + // Registriere globalen Handler beim ersten Aufruf + registerGlobalMessageHandler() + + // Registriere dieses IFrame + watchEffect(() => { + if (iframeRef.value && extension.value) { + iframeRegistry.set(iframeRef.value, extension.value) + } + }) + + // Cleanup beim Unmount onUnmounted(() => { - window.removeEventListener('message', handleMessage) + if (iframeRef.value) { + iframeRegistry.delete(iframeRef.value) + } }) - - return { - handleMessage, - } } // ========================================== // Extension Methods // ========================================== -async function handleExtensionMethod( +async function handleExtensionMethodAsync( request: ExtensionRequest, - extension: ComputedRef, + extension: IHaexHubExtension, // Direkter Typ, kein ComputedRef mehr ) { switch (request.method) { case 'extension.getInfo': - return { - keyHash: extension.value?.id || '', // TODO: Real key hash - name: extension.value?.name || '', - fullId: `${extension.value?.id}/${extension.value?.name}@${extension.value?.version}`, - version: extension.value?.version || '', - displayName: extension.value?.name, - namespace: extension.value?.author, - allowedOrigin: window.location.origin, // "tauri://localhost" - } - - case 'extensions.getDependencies': - // TODO: Implement dependencies from manifest - return [] - + return await invoke('get_extension_info', { + extensionId: extension.id, + }) default: throw new Error(`Unknown extension method: ${request.method}`) } @@ -129,47 +136,41 @@ async function handleExtensionMethod( // Database Methods // ========================================== -async function handleDatabaseMethod( +async function handleDatabaseMethodAsync( request: ExtensionRequest, - extension: ComputedRef, + extension: IHaexHubExtension, // Direkter Typ ) { - const { currentVault } = useVaultStore() - if (!currentVault) { - throw new Error('No vault available') + const params = request.params as { + query?: string + params?: unknown[] } - if (!extension.value) { - throw new Error('Extension not found') - } - - const params = request.params as { query?: string; params?: unknown[] } - switch (request.method) { case 'db.query': { - // Validate permission - await validateDatabaseAccess(extension.value, params.query || '', 'read') - - // Execute query - const result = await currentVault.drizzle.execute(params.query || '') + const rows = await invoke('extension_sql_select', { + sql: params.query || '', + params: params.params || [], + extensionId: extension.id, + }) return { - rows: result.rows || [], + rows, rowsAffected: 0, lastInsertId: undefined, } } case 'db.execute': { - // Validate permission - await validateDatabaseAccess(extension.value, params.query || '', 'write') - - // Execute query - const result = await currentVault.drizzle.execute(params.query || '') + await invoke('extension_sql_execute', { + sql: params.query || '', + params: params.params || [], + extensionId: extension.id, + }) return { rows: [], - rowsAffected: result.rowsAffected || 0, - lastInsertId: result.lastInsertId, + rowsAffected: 1, + lastInsertId: undefined, } } @@ -177,18 +178,14 @@ async function handleDatabaseMethod( const statements = (request.params as { statements?: string[] }).statements || [] - // Validate all statements for (const stmt of statements) { - await validateDatabaseAccess(extension.value, stmt, 'write') + await invoke('extension_sql_execute', { + sql: stmt, + params: [], + extensionId: extension.id, + }) } - // Execute transaction - await currentVault.drizzle.transaction(async (tx) => { - for (const stmt of statements) { - await tx.execute(stmt) - } - }) - return { success: true } } @@ -196,125 +193,63 @@ async function handleDatabaseMethod( throw new Error(`Unknown database method: ${request.method}`) } } - // ========================================== -// Permission Validation +// Filesystem Methods (TODO) // ========================================== -async function validateDatabaseAccess( - extension: IHaexHubExtensionLink, - query: string, - operation: 'read' | 'write', -): Promise { - // Extract table name from query - const tableMatch = query.match(/(?:FROM|INTO|UPDATE|TABLE)\s+(\w+)/i) - if (!tableMatch) { - throw new Error('Could not extract table name from query') - } - - const tableName = tableMatch[1] - - // Check if it's the extension's own table - const extensionPrefix = `${extension.id}_${extension.name?.replace(/-/g, '_')}_` - const isOwnTable = tableName.startsWith(extensionPrefix) - - if (isOwnTable) { - // Own tables: always allowed - return - } - - // External table: Check permissions - const hasPermission = await checkDatabasePermission( - extension.id, - tableName, - operation, - ) - - if (!hasPermission) { - throw new Error(`Permission denied: ${operation} access to ${tableName}`) - } -} - -async function checkDatabasePermission( - extensionId: string, - tableName: string, - operation: 'read' | 'write', -): Promise { - // TODO: Query permissions from database - // SELECT * FROM db_extension_permissions - // WHERE extension_id = ? AND resource = ? AND operation = ? - - console.warn('TODO: Implement permission check', { - extensionId, - tableName, - operation, - }) - - // For now: deny by default - return false -} - -// ========================================== -// Permission Methods -// ========================================== - -async function handlePermissionsMethod( +async function handleFilesystemMethodAsync( request: ExtensionRequest, - extension: ComputedRef, + extension: IHaexHubExtension, ) { - switch (request.method) { - case 'permissions.database.request': { - const params = request.params as { - resource: string - operation: 'read' | 'write' - reason?: string - } + if (!request || !extension) return + // TODO: Implementiere Filesystem Commands im Backend + throw new Error('Filesystem methods not yet implemented') +} - // TODO: Show user dialog to grant/deny permission - console.log('[HaexHub] Permission request:', params) +// ========================================== +// HTTP Methods (TODO) +// ========================================== - // For now: return ASK - return { - status: 'ask', - permanent: false, - } - } - - case 'permissions.database.check': { - const params = request.params as { - resource: string - operation: 'read' | 'write' - } - - const hasPermission = await checkDatabasePermission( - extension.value?.id || '', - params.resource, - params.operation, - ) - - return { - status: hasPermission ? 'granted' : 'denied', - permanent: true, - } - } - - default: - throw new Error(`Unknown permission method: ${request.method}`) +async function handleHttpMethodAsync( + request: ExtensionRequest, + extension: IHaexHubExtension, +) { + if (!extension || !request) { + throw new Error('Extension not found') } + + // TODO: Implementiere HTTP Commands im Backend + throw new Error('HTTP methods not yet implemented') +} + +// ========================================== +// Permission Methods (TODO) +// ========================================== + +async function handlePermissionsMethodAsync( + request: ExtensionRequest, + extension: IHaexHubExtension, +) { + if (!extension || !request) { + throw new Error('Extension not found') + } + + // TODO: Implementiere Permission Request UI + throw new Error('Permission methods not yet implemented') } // ========================================== // Context Methods // ========================================== -async function handleContextMethod(request: ExtensionRequest) { - const { theme } = useThemeStore() +async function handleContextMethodAsync(request: ExtensionRequest) { + const { currentTheme } = storeToRefs(useUiStore()) const { locale } = useI18n() switch (request.method) { case 'context.get': return { - theme: theme.value || 'system', + theme: currentTheme.value || 'system', locale: locale.value, platform: detectPlatform(), } @@ -330,29 +265,3 @@ function detectPlatform(): 'desktop' | 'mobile' | 'tablet' { if (width < 1024) return 'tablet' return 'desktop' } - -// ========================================== -// Search Methods -// ========================================== - -async function handleSearchMethod( - request: ExtensionRequest, - extension: ComputedRef, -) { - switch (request.method) { - case 'search.respond': { - const params = request.params as { - requestId: string - results: unknown[] - } - - // TODO: Store search results for display - console.log('[HaexHub] Search results from extension:', params) - - return { success: true } - } - - default: - throw new Error(`Unknown search method: ${request.method}`) - } -} diff --git a/src/pages/vault.vue b/src/pages/vault.vue index 8e7275e..8841b78 100644 --- a/src/pages/vault.vue +++ b/src/pages/vault.vue @@ -1,7 +1,7 @@
- +
diff --git a/src/pages/vault/[vaultId]/extensions/index.vue b/src/pages/vault/[vaultId]/extensions/index.vue index f31d160..6735bfc 100644 --- a/src/pages/vault/[vaultId]/extensions/index.vue +++ b/src/pages/vault/[vaultId]/extensions/index.vue @@ -31,18 +31,17 @@ class="size-full md:size-2/3 md:translate-x-1/5 md:translate-y-1/3" />
- - - - - + + +
@@ -93,7 +92,7 @@ const extension = reactive<{ path: '', }) -const loadExtensionManifestAsync = async () => { +/* const loadExtensionManifestAsync = async () => { try { extension.path = await open({ directory: true, recursive: true }) if (!extension.path) return @@ -111,7 +110,7 @@ const loadExtensionManifestAsync = async () => { add({ color: 'error', description: JSON.stringify(error) }) await addNotificationAsync({ text: JSON.stringify(error), type: 'error' }) } -} +} */ const { add } = useToast() const { addNotificationAsync } = useNotificationStore() diff --git a/src/pages/vault/[vaultId]/index.vue b/src/pages/vault/[vaultId]/index.vue index bac1141..b6b8f6c 100644 --- a/src/pages/vault/[vaultId]/index.vue +++ b/src/pages/vault/[vaultId]/index.vue @@ -1,12 +1,12 @@