diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..7e11055a --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.wasm binary diff --git a/Cargo.lock b/Cargo.lock index 80e3f70c..4958875c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -107,9 +116,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8589c784ff02ac80dafc5e4116c3a2a3743ac5e0c902483518a88eec6559cf99" +checksum = "345fd392ab01f746c717b1357165b76f0b67a60192007b234058c9045fdcf695" dependencies = [ "brotli", "flate2", @@ -542,6 +551,21 @@ dependencies = [ "syn", ] +[[package]] +name = "backtrace" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base16ct" version = "0.1.1" @@ -658,9 +682,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "byte-tools" @@ -708,6 +732,9 @@ name = "cc" version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -879,6 +906,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if", +] + [[package]] name = "cpufeatures" version = "0.2.2" @@ -888,6 +924,95 @@ dependencies = [ "libc", ] +[[package]] +name = "cranelift-bforest" +version = "0.84.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fa7c3188913c2d11a361e0431e135742372a2709a99b103e79758e11a0a797e" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.84.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29285f70fd396a8f64455a15a6e1d390322e4a5f5186de513141313211b0a23e" +dependencies = [ + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "gimli", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.84.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057eac2f202ec95aebfd8d495e88560ac085f6a415b3c6c28529dc5eb116a141" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.84.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75d93869efd18874a9341cfd8ad66bcb08164e86357a694a0e939d29e87410b9" + +[[package]] +name = "cranelift-entity" +version = "0.84.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e34bd7a1fefa902c90a921b36323f17a398b788fa56a75f07a29d83b6e28808" +dependencies = [ + "serde", +] + +[[package]] +name = "cranelift-frontend" +version = "0.84.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457018dd2d6ee300953978f63215b5edf3ae42dbdf8c7c038972f10394599f72" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-native" +version = "0.84.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bba027cc41bf1d0eee2ddf16caba2ee1be682d0214520fff0129d2c6557fda89" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.84.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b17639ced10b9916c9be120d38c872ea4f9888aa09248568b10056ef0559bfa" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools", + "log", + "smallvec", + "wasmparser", + "wasmtime-types", +] + [[package]] name = "crc" version = "2.1.0" @@ -937,6 +1062,31 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + [[package]] name = "crossbeam-queue" version = "0.3.5" @@ -959,9 +1109,9 @@ dependencies = [ [[package]] name = "crypto-bigint" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3e45371ac6a1370324b085acb466f24b07d4d66da6999a42c8ce655bd14e0e" +checksum = "78a4e0fb04deabeb711eb20bd1179f1524c06f7e6975ebccc495f678a635887b" dependencies = [ "generic-array 0.14.5", "rand_core", @@ -1126,6 +1276,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs" version = "4.0.0" @@ -1146,6 +1306,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dotenv" version = "0.15.0" @@ -1219,6 +1390,40 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_logger" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "event-listener" version = "2.5.2" @@ -1231,6 +1436,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "fastrand" version = "1.7.0" @@ -1266,6 +1477,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "file-per-thread-logger" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e16290574b39ee41c71aeb90ae960c504ebaf1e2a1c87bd52aa56ed6e1a02f" +dependencies = [ + "env_logger", + "log", +] + [[package]] name = "fixedbitset" version = "0.4.1" @@ -1274,13 +1495,11 @@ checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" [[package]] name = "flate2" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" dependencies = [ - "cfg-if", "crc32fast", - "libc", "miniz_oxide", ] @@ -1407,6 +1626,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.12.4" @@ -1447,6 +1675,17 @@ dependencies = [ "polyval", ] +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + [[package]] name = "globset" version = "0.4.8" @@ -1666,6 +1905,12 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.19" @@ -1770,12 +2015,13 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" dependencies = [ "autocfg", "hashbrown", + "serde", ] [[package]] @@ -1814,6 +2060,12 @@ version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e85a1509a128c855368e135cffcde7eac17d8e1083f41e2b98c58bc1a5074be" +[[package]] +name = "io-lifetimes" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6" + [[package]] name = "iovec" version = "0.1.4" @@ -1859,6 +2111,24 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +[[package]] +name = "ittapi-rs" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f712648a1ad72fbfb7adc2772c331e8d90f022f8cf30cbabefba2878dd3172b0" +dependencies = [ + "cc", +] + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.57" @@ -1868,6 +2138,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-patch" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f995a3c8f2bc3dd52a18a583e90f9ec109c047fa1603a853e46bcda14d2e279d" +dependencies = [ + "serde", + "serde_json", + "treediff", +] + [[package]] name = "language-tags" version = "0.3.2" @@ -1886,6 +2167,12 @@ dependencies = [ "spin", ] +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "lettre" version = "0.10.0-rc.6" @@ -1933,6 +2220,12 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +[[package]] +name = "linux-raw-sys" +version = "0.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5284f00d480e1c39af34e72f8ad60b94f47007e3481cd3b731c1d67190ddc7b7" + [[package]] name = "lock_api" version = "0.4.7" @@ -1952,6 +2245,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + [[package]] name = "maplit" version = "1.0.2" @@ -2009,6 +2311,7 @@ dependencies = [ "mas-email", "mas-handlers", "mas-http", + "mas-policy", "mas-router", "mas-static-files", "mas-storage", @@ -2118,6 +2421,7 @@ dependencies = [ "mas-http", "mas-iana", "mas-jose", + "mas-policy", "mas-router", "mas-storage", "mas-templates", @@ -2228,6 +2532,22 @@ dependencies = [ "url", ] +[[package]] +name = "mas-policy" +version = "0.1.0" +dependencies = [ + "anyhow", + "mas-data-model", + "oauth2-types", + "opa-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "wasmtime", +] + [[package]] name = "mas-router" version = "0.1.0" @@ -2351,6 +2671,24 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memfd" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6627dc657574b49d6ad27105ed671822be56e0d2547d413bfbf3e8d8fa92e7a" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.16" @@ -2375,9 +2713,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" dependencies = [ "adler", ] @@ -2394,6 +2732,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "more-asserts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" + [[package]] name = "multimap" version = "0.8.3" @@ -2498,12 +2842,48 @@ dependencies = [ "url", ] +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "crc32fast", + "hashbrown", + "indexmap", + "memchr", +] + [[package]] name = "once_cell" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +[[package]] +name = "opa-wasm" +version = "0.1.0" +source = "git+https://github.com/matrix-org/rust-opa-wasm.git#47586f82ca39390aeed7bb56b8220395899f3176" +dependencies = [ + "anyhow", + "base64", + "digest 0.10.3", + "hex", + "hmac", + "json-patch", + "md-5", + "semver", + "serde", + "serde_json", + "sha1", + "sha2 0.10.2", + "sprintf", + "thiserror", + "tokio", + "tracing", + "wasmtime", +] + [[package]] name = "opaque-debug" version = "0.2.3" @@ -2634,9 +3014,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.0.1" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435" +checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" [[package]] name = "p256" @@ -2662,9 +3042,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core 0.9.3", @@ -2832,9 +3212,9 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" dependencies = [ "fixedbitset", "indexmap", @@ -3060,6 +3440,15 @@ dependencies = [ "prost", ] +[[package]] +name = "psm" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871372391786ccec00d3c5d3d6608905b3d4db263639cfe075d3b60a736d115a" +dependencies = [ + "cc", +] + [[package]] name = "quote" version = "1.0.18" @@ -3105,6 +3494,30 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + [[package]] name = "redox_syscall" version = "0.2.13" @@ -3126,10 +3539,22 @@ dependencies = [ ] [[package]] -name = "regex" -version = "1.5.5" +name = "regalloc2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "904196c12c9f55d3aea578613219f493ced8e05b3d0c6a42d11cb4142d8b4879" +dependencies = [ + "fxhash", + "log", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", @@ -3147,9 +3572,21 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "region" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi", +] [[package]] name = "remove_dir_all" @@ -3278,6 +3715,12 @@ dependencies = [ "walkdir", ] +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc_version" version = "0.4.0" @@ -3287,6 +3730,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.33.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938a344304321a9da4973b9ff4f9f8db9caf4597dfd9dda6a60b523340a0fff0" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "winapi", +] + [[package]] name = "rustls" version = "0.19.1" @@ -3601,6 +4058,17 @@ dependencies = [ "digest 0.10.3", ] +[[package]] +name = "sha1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + [[package]] name = "sha2" version = "0.9.9" @@ -3665,6 +4133,12 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +[[package]] +name = "slice-group-by" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" + [[package]] name = "slug" version = "0.1.4" @@ -3706,6 +4180,12 @@ dependencies = [ "der", ] +[[package]] +name = "sprintf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "082cb9266c8691c70a98442f8f893ba3549f02f64e128cb096dac92e1c428340" + [[package]] name = "sqlformat" version = "0.1.8" @@ -3813,6 +4293,12 @@ dependencies = [ "tokio-rustls 0.22.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "stringprep" version = "0.1.2" @@ -3875,6 +4361,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" +[[package]] +name = "target-lexicon" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" + [[package]] name = "tempfile" version = "3.3.0" @@ -4033,7 +4525,7 @@ dependencies = [ "mio", "num_cpus", "once_cell", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", "socket2", @@ -4125,6 +4617,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + [[package]] name = "tonic" version = "0.6.2" @@ -4325,6 +4826,15 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "treediff" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "761e8d5ad7ce14bb82b7e61ccc0ca961005a275a060b9644a2431aa11553c2ff" +dependencies = [ + "serde_json", +] + [[package]] name = "try-lock" version = "0.2.3" @@ -4449,6 +4959,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "unicode_categories" version = "0.1.1" @@ -4601,6 +5117,219 @@ version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +[[package]] +name = "wasmparser" +version = "0.84.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77dc97c22bb5ce49a47b745bed8812d30206eff5ef3af31424f2c1820c0974b2" +dependencies = [ + "indexmap", +] + +[[package]] +name = "wasmtime" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfdd1101bdfa0414a19018ec0a091951a20b695d4d04f858d49f6c4cc53cd8dd" +dependencies = [ + "anyhow", + "async-trait", + "backtrace", + "bincode", + "cfg-if", + "indexmap", + "lazy_static", + "libc", + "log", + "object", + "once_cell", + "paste", + "psm", + "rayon", + "region", + "serde", + "target-lexicon", + "wasmparser", + "wasmtime-cache", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-jit", + "wasmtime-runtime", + "wat", + "winapi", +] + +[[package]] +name = "wasmtime-cache" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79da81ed0724392948ad7a0fb5088ff1bd15fa937356c8c037c6b1c8b5473cde" +dependencies = [ + "anyhow", + "base64", + "bincode", + "directories-next", + "file-per-thread-logger", + "log", + "rustix", + "serde", + "sha2 0.9.9", + "toml", + "winapi", + "zstd", +] + +[[package]] +name = "wasmtime-cranelift" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e78edcfb0daa9a9579ac379d00e2d5a5b2a60c0d653c8c95e8412f2166acb9" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli", + "log", + "more-asserts", + "object", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4201389132ec467981980549574b33fc70d493b40f2c045c8ce5c7b54fbad97e" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli", + "indexmap", + "log", + "more-asserts", + "object", + "serde", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-fiber" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba6777a84b44f9a384b5c9d511ae3d86534438b7e25d928b8e8e858ecad5df2" +dependencies = [ + "cc", + "rustix", + "winapi", +] + +[[package]] +name = "wasmtime-jit" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1587ca7752d00862faa540d00fd28e5ccf1ac61ba19756449193f1153cb2b127" +dependencies = [ + "addr2line", + "anyhow", + "bincode", + "cfg-if", + "cpp_demangle", + "gimli", + "ittapi-rs", + "log", + "object", + "region", + "rustc-demangle", + "rustix", + "serde", + "target-lexicon", + "thiserror", + "wasmtime-environ", + "wasmtime-jit-debug", + "wasmtime-runtime", + "winapi", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b27233ab6c8934b23171c64f215f902ef19d18c1712b46a0674286d1ef28d5dd" +dependencies = [ + "lazy_static", + "object", + "rustix", +] + +[[package]] +name = "wasmtime-runtime" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d3b0b8f13db47db59d616e498fe45295819d04a55f9921af29561827bdb816" +dependencies = [ + "anyhow", + "backtrace", + "cc", + "cfg-if", + "indexmap", + "libc", + "log", + "mach", + "memfd", + "memoffset", + "more-asserts", + "rand", + "region", + "rustix", + "thiserror", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-jit-debug", + "winapi", +] + +[[package]] +name = "wasmtime-types" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1630d9dca185299bec7f557a7e73b28742fe5590caf19df001422282a0a98ad1" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wast" +version = "41.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f882898b8b817cc4edc16aa3692fdc087b356edc8cc0c2164f5b5181e31c3870" +dependencies = [ + "leb128", + "memchr", + "unicode-width", +] + +[[package]] +name = "wat" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48b3b9b3e39e66c7fd3f8be785e74444d216260f491e93369e317ed6482ff80f" +dependencies = [ + "wast", +] + [[package]] name = "watchman_client" version = "0.7.2" @@ -4797,3 +5526,32 @@ name = "zeroize" version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94693807d016b2f2d2e14420eb3bfcca689311ff775dcf113d74ea624b7cdf07" + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.1+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" +dependencies = [ + "cc", + "libc", +] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index eac83046..312a7784 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -36,6 +36,7 @@ mas-config = { path = "../config" } mas-email = { path = "../email" } mas-handlers = { path = "../handlers" } mas-http = { path = "../http" } +mas-policy = { path = "../policy" } mas-router = { path = "../router" } mas-static-files = { path = "../static-files" } mas-storage = { path = "../storage" } diff --git a/crates/cli/src/commands/server.rs b/crates/cli/src/commands/server.rs index e614f867..9eab383f 100644 --- a/crates/cli/src/commands/server.rs +++ b/crates/cli/src/commands/server.rs @@ -25,6 +25,7 @@ use hyper::Server; use mas_config::RootConfig; use mas_email::{MailTransport, Mailer}; use mas_http::ServerLayer; +use mas_policy::PolicyFactory; use mas_router::UrlBuilder; use mas_storage::MIGRATOR; use mas_tasks::TaskQueue; @@ -176,6 +177,20 @@ impl Options { let encrypter = config.secrets.encrypter(); + // Load and compile the WASM policies + let mut policy = tokio::fs::File::open(&config.policy.wasm_module) + .await + .context("failed to open OPA WASM policy file")?; + let policy_factory = PolicyFactory::load( + &mut policy, + config.policy.data.clone().unwrap_or_default(), + config.policy.login_entrypoint.clone(), + config.policy.register_entrypoint.clone(), + config.policy.client_registration_entrypoint.clone(), + ) + .await?; + let policy_factory = Arc::new(policy_factory); + // Load and compile the templates let templates = Templates::load_from_config(&config.templates) .await @@ -217,6 +232,7 @@ impl Options { &mailer, &url_builder, &matrix_config, + &policy_factory, ) .fallback(static_files) .layer(ServerLayer::default()); diff --git a/crates/config/src/sections/mod.rs b/crates/config/src/sections/mod.rs index 73c0b0a9..6d11f2f9 100644 --- a/crates/config/src/sections/mod.rs +++ b/crates/config/src/sections/mod.rs @@ -22,6 +22,7 @@ mod database; mod email; mod http; mod matrix; +mod policy; mod secrets; mod telemetry; mod templates; @@ -33,6 +34,7 @@ pub use self::{ email::{EmailConfig, EmailSmtpMode, EmailTransportConfig}, http::HttpConfig, matrix::MatrixConfig, + policy::PolicyConfig, secrets::{Encrypter, SecretsConfig}, telemetry::{ MetricsConfig, MetricsExporterConfig, Propagator, TelemetryConfig, TracingConfig, @@ -79,6 +81,10 @@ pub struct RootConfig { /// Configuration related to the homeserver #[serde(default)] pub matrix: MatrixConfig, + + /// Configuration related to the OPA policies + #[serde(default)] + pub policy: PolicyConfig, } #[async_trait] @@ -98,6 +104,7 @@ impl ConfigurationSection<'_> for RootConfig { email: EmailConfig::generate().await?, secrets: SecretsConfig::generate().await?, matrix: MatrixConfig::generate().await?, + policy: PolicyConfig::generate().await?, }) } @@ -112,6 +119,7 @@ impl ConfigurationSection<'_> for RootConfig { email: EmailConfig::test(), secrets: SecretsConfig::test(), matrix: MatrixConfig::test(), + policy: PolicyConfig::test(), } } } diff --git a/crates/config/src/sections/policy.rs b/crates/config/src/sections/policy.rs new file mode 100644 index 00000000..6ae4a160 --- /dev/null +++ b/crates/config/src/sections/policy.rs @@ -0,0 +1,90 @@ +// Copyright 2022 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::path::PathBuf; + +use async_trait::async_trait; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use super::ConfigurationSection; + +fn default_wasm_module() -> PathBuf { + "./policies/policy.wasm".into() +} + +fn default_client_registration_endpoint() -> String { + "client_registration/allow".to_string() +} + +fn default_login_endpoint() -> String { + "login/allow".to_string() +} + +fn default_register_endpoint() -> String { + "register/allow".to_string() +} + +/// Application secrets +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct PolicyConfig { + /// Path to the WASM module + #[serde(default = "default_wasm_module")] + pub wasm_module: PathBuf, + + /// Entrypoint to use when evaluating client registrations + #[serde(default = "default_client_registration_endpoint")] + pub client_registration_entrypoint: String, + + /// Entrypoint to use when evaluating user logins + #[serde(default = "default_login_endpoint")] + pub login_entrypoint: String, + + /// Entrypoint to use when evaluating user registrations + #[serde(default = "default_register_endpoint")] + pub register_entrypoint: String, + + /// Arbitrary data to pass to the policy + #[serde(default)] + pub data: Option, +} + +impl Default for PolicyConfig { + fn default() -> Self { + Self { + wasm_module: default_wasm_module(), + client_registration_entrypoint: default_client_registration_endpoint(), + login_entrypoint: default_login_endpoint(), + register_entrypoint: default_register_endpoint(), + data: None, + } + } +} + +#[async_trait] +impl ConfigurationSection<'_> for PolicyConfig { + fn path() -> &'static str { + "policy" + } + + async fn generate() -> anyhow::Result { + Ok(Self::default()) + } + + fn test() -> Self { + Self::default() + } +} diff --git a/crates/handlers/Cargo.toml b/crates/handlers/Cargo.toml index 8f6cf9f0..8e7d9fde 100644 --- a/crates/handlers/Cargo.toml +++ b/crates/handlers/Cargo.toml @@ -62,6 +62,7 @@ mas-email = { path = "../email" } mas-http = { path = "../http" } mas-iana = { path = "../iana" } mas-jose = { path = "../jose" } +mas-policy = { path = "../policy" } mas-storage = { path = "../storage" } mas-templates = { path = "../templates" } mas-router = { path = "../router" } diff --git a/crates/handlers/src/lib.rs b/crates/handlers/src/lib.rs index fd44500e..7b03cd26 100644 --- a/crates/handlers/src/lib.rs +++ b/crates/handlers/src/lib.rs @@ -34,6 +34,7 @@ use mas_config::{Encrypter, MatrixConfig}; use mas_email::Mailer; use mas_http::CorsLayerExt; use mas_jose::StaticKeystore; +use mas_policy::PolicyFactory; use mas_router::{Route, UrlBuilder}; use mas_templates::{ErrorContext, Templates}; use sqlx::PgPool; @@ -46,7 +47,11 @@ mod oauth2; mod views; #[must_use] -#[allow(clippy::too_many_lines, clippy::missing_panics_doc)] +#[allow( + clippy::too_many_lines, + clippy::missing_panics_doc, + clippy::too_many_arguments +)] pub fn router( pool: &PgPool, templates: &Templates, @@ -55,6 +60,7 @@ pub fn router( mailer: &Mailer, url_builder: &UrlBuilder, matrix_config: &MatrixConfig, + policy_factory: &Arc, ) -> Router where B: HttpBody + Send + 'static, @@ -233,4 +239,5 @@ where .layer(Extension(url_builder.clone())) .layer(Extension(mailer.clone())) .layer(Extension(matrix_config.clone())) + .layer(Extension(policy_factory.clone())) } diff --git a/crates/handlers/src/oauth2/registration.rs b/crates/handlers/src/oauth2/registration.rs index fdb34fee..115d50fd 100644 --- a/crates/handlers/src/oauth2/registration.rs +++ b/crates/handlers/src/oauth2/registration.rs @@ -12,9 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::sync::Arc; + use axum::{response::IntoResponse, Extension, Json}; use hyper::StatusCode; use mas_iana::oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod}; +use mas_policy::PolicyFactory; use mas_storage::oauth2::client::insert_client; use oauth2_types::{ errors::{INVALID_CLIENT_METADATA, INVALID_REDIRECT_URI, SERVER_ERROR}, @@ -31,11 +34,17 @@ pub(crate) enum RouteError { #[error(transparent)] Internal(Box), + #[error(transparent)] + Anyhow(#[from] anyhow::Error), + #[error("invalid redirect uri")] InvalidRedirectUri, #[error("invalid client metadata")] InvalidClientMetadata, + + #[error("denied by the policy")] + PolicyDenied, } impl From for RouteError { @@ -47,9 +56,12 @@ impl From for RouteError { impl IntoResponse for RouteError { fn into_response(self) -> axum::response::Response { match self { - Self::Internal(_) => (StatusCode::INTERNAL_SERVER_ERROR, Json(SERVER_ERROR)), + Self::Internal(_) | Self::Anyhow(_) => { + (StatusCode::INTERNAL_SERVER_ERROR, Json(SERVER_ERROR)) + } Self::InvalidRedirectUri => (StatusCode::BAD_REQUEST, Json(INVALID_REDIRECT_URI)), Self::InvalidClientMetadata => (StatusCode::BAD_REQUEST, Json(INVALID_CLIENT_METADATA)), + Self::PolicyDenied => (StatusCode::UNAUTHORIZED, Json(INVALID_CLIENT_METADATA)), } .into_response() } @@ -58,6 +70,7 @@ impl IntoResponse for RouteError { #[tracing::instrument(skip_all, err)] pub(crate) async fn post( Extension(pool): Extension, + Extension(policy_factory): Extension>, Json(body): Json, ) -> Result { info!(?body, "Client registration"); @@ -105,6 +118,12 @@ pub(crate) async fn post( return Err(RouteError::InvalidClientMetadata); } + let mut policy = policy_factory.instanciate().await?; + let allowed = policy.evaluate_client_registration(&body).await?; + if !allowed { + return Err(RouteError::PolicyDenied); + } + // Grab a txn let mut txn = pool.begin().await?; diff --git a/crates/policy/Cargo.toml b/crates/policy/Cargo.toml new file mode 100644 index 00000000..968fd093 --- /dev/null +++ b/crates/policy/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "mas-policy" +version = "0.1.0" +authors = ["Quentin Gliech "] +edition = "2021" +license = "Apache-2.0" + +[dependencies] +anyhow = "1.0.31" +opa-wasm = { git = "https://github.com/matrix-org/rust-opa-wasm.git" } +serde = { version = "1.0.31", features = ["derive"] } +serde_json = "1.0.31" +thiserror = "1.0.31" +tokio = { version = "1.18.2", features = ["io-util", "rt"] } +tracing = "0.1.34" +wasmtime = "0.37.0" + +mas-data-model = { path = "../data-model" } +oauth2-types = { path = "../oauth2-types" } diff --git a/crates/policy/src/lib.rs b/crates/policy/src/lib.rs new file mode 100644 index 00000000..2802a975 --- /dev/null +++ b/crates/policy/src/lib.rs @@ -0,0 +1,175 @@ +// Copyright 2022 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use anyhow::bail; +use oauth2_types::registration::ClientMetadata; +use opa_wasm::Runtime; +use serde::Deserialize; +use thiserror::Error; +use tokio::io::{AsyncRead, AsyncReadExt}; +use wasmtime::{Config, Engine, Module, Store}; + +#[derive(Debug, Error)] +pub enum LoadError { + #[error("failed to read module")] + Read(#[from] tokio::io::Error), + + #[error("failed to create WASM engine")] + Engine(#[source] anyhow::Error), + + #[error("module compilation task crashed")] + CompilationTask(#[from] tokio::task::JoinError), + + #[error("failed to compile WASM module")] + Compilation(#[source] anyhow::Error), +} + +pub struct PolicyFactory { + engine: Engine, + module: Module, + data: serde_json::Value, + login_entrypoint: String, + register_entrypoint: String, + client_registration_entrypoint: String, +} + +impl PolicyFactory { + pub async fn load( + mut source: impl AsyncRead + std::marker::Unpin, + data: serde_json::Value, + login_entrypoint: String, + register_entrypoint: String, + client_registration_entrypoint: String, + ) -> Result { + let mut config = Config::default(); + config.async_support(true); + config.cranelift_opt_level(wasmtime::OptLevel::Speed); + let engine = Engine::new(&config).map_err(LoadError::Engine)?; + let mut buf = Vec::new(); + source.read_to_end(&mut buf).await?; + let (engine, module) = tokio::task::spawn_blocking(move || { + let module = Module::new(&engine, buf); + (engine, module) + }) + .await?; + let module = module.map_err(LoadError::Compilation)?; + + Ok(Self { + engine, + module, + data, + login_entrypoint, + register_entrypoint, + client_registration_entrypoint, + }) + } + + pub async fn instanciate(&self) -> Result { + let mut store = Store::new(&self.engine, ()); + let runtime = Runtime::new(&mut store, &self.module).await?; + + // Check that we have the required entrypoints + let entrypoints = runtime.entrypoints(); + + for e in [ + self.login_entrypoint.as_str(), + self.register_entrypoint.as_str(), + ] { + if !entrypoints.contains(e) { + bail!("missing entrypoint {e}") + } + } + + let instance = runtime.with_data(&mut store, &self.data).await?; + + Ok(Policy { + store, + instance, + login_entrypoint: self.login_entrypoint.clone(), + register_entrypoint: self.register_entrypoint.clone(), + client_registration_entrypoint: self.client_registration_entrypoint.clone(), + }) + } +} + +#[derive(Deserialize)] +struct EvaluationResult { + result: bool, +} + +pub struct Policy { + store: Store<()>, + instance: opa_wasm::Policy, + login_entrypoint: String, + register_entrypoint: String, + client_registration_entrypoint: String, +} + +impl Policy { + pub async fn evaluate_login( + &mut self, + user: &mas_data_model::User<()>, + ) -> Result { + let user = serde_json::to_value(user)?; + let input = serde_json::json!({ "user": user }); + + let [res]: [EvaluationResult; 1] = self + .instance + .evaluate(&mut self.store, &self.login_entrypoint, &input) + .await?; + + Ok(res.result) + } + + pub async fn evaluate_register( + &mut self, + username: &str, + email: &str, + ) -> Result { + let input = serde_json::json!({ + "user": { + "username": username, + "email": email + } + }); + + let [res]: [EvaluationResult; 1] = self + .instance + .evaluate(&mut self.store, &self.register_entrypoint, &input) + .await?; + + Ok(res.result) + } + + pub async fn evaluate_client_registration( + &mut self, + client_metadata: &ClientMetadata, + ) -> Result { + let client_metadata = serde_json::to_value(client_metadata)?; + let input = serde_json::json!({ + "client_metadata": client_metadata, + }); + + let [res]: [EvaluationResult; 1] = self + .instance + .evaluate( + &mut self.store, + &self.client_registration_entrypoint, + &input, + ) + .await?; + + Ok(res.result) + } +} diff --git a/policies/Makefile b/policies/Makefile new file mode 100644 index 00000000..34f228a2 --- /dev/null +++ b/policies/Makefile @@ -0,0 +1,5 @@ +policy.wasm: client_registration.rego login.rego register.rego + opa build -t wasm -e "client_registration/allow" -e "login/allow" -e "register/allow" $^ + tar xzf bundle.tar.gz /policy.wasm + rm -f bundle.tar.gz + touch $@ diff --git a/policies/client_registration.rego b/policies/client_registration.rego new file mode 100644 index 00000000..37cf5f16 --- /dev/null +++ b/policies/client_registration.rego @@ -0,0 +1,19 @@ +package client_registration + +import future.keywords.in + + +secure_url(x) { + is_string(x) + startswith(x, "https://") +} + +default allow := false + +allow { + secure_url(input.client_metadata.client_uri) + secure_url(input.client_metadata.tos_uri) + secure_url(input.client_metadata.policy_uri) + some redirect_uri in input.client_metadata.redirect_uris + secure_url(redirect_uri) +} diff --git a/policies/login.rego b/policies/login.rego new file mode 100644 index 00000000..8154fff2 --- /dev/null +++ b/policies/login.rego @@ -0,0 +1,3 @@ +package login + +allow := true diff --git a/policies/policy.wasm b/policies/policy.wasm new file mode 100644 index 00000000..2e50bf6e Binary files /dev/null and b/policies/policy.wasm differ diff --git a/policies/register.rego b/policies/register.rego new file mode 100644 index 00000000..8e6aa412 --- /dev/null +++ b/policies/register.rego @@ -0,0 +1,3 @@ +package register + +allow := true