mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 12:37:00 +01:00
1116 UI hints (#1199)
This commit is contained in:
parent
33b8fe0967
commit
3589376525
83
Cargo.lock
generated
83
Cargo.lock
generated
|
@ -166,7 +166,7 @@ version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
|
checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"concurrent-queue",
|
"concurrent-queue 1.2.4",
|
||||||
"event-listener",
|
"event-listener",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
]
|
]
|
||||||
|
@ -196,15 +196,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-executor"
|
name = "async-executor"
|
||||||
version = "1.4.1"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965"
|
checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-lock",
|
||||||
"async-task",
|
"async-task",
|
||||||
"concurrent-queue",
|
"concurrent-queue 2.0.0",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"once_cell",
|
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ checksum = "e8121296a9f05be7f34aa4196b1747243b3b62e048bb7906f644f3fbfc490cf7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-lock",
|
"async-lock",
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"concurrent-queue",
|
"concurrent-queue 1.2.4",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
@ -626,9 +626,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.74"
|
version = "1.0.76"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574"
|
checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
]
|
]
|
||||||
|
@ -809,6 +809,15 @@ dependencies = [
|
||||||
"cache-padded",
|
"cache-padded",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "concurrent-queue"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console"
|
name = "console"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
|
@ -1105,9 +1114,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxx"
|
name = "cxx"
|
||||||
version = "1.0.80"
|
version = "1.0.81"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a"
|
checksum = "97abf9f0eca9e52b7f81b945524e76710e6cb2366aead23b7d4fbf72e281f888"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cxxbridge-flags",
|
"cxxbridge-flags",
|
||||||
|
@ -1117,9 +1126,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxx-build"
|
name = "cxx-build"
|
||||||
version = "1.0.80"
|
version = "1.0.81"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827"
|
checksum = "7cc32cc5fea1d894b77d269ddb9f192110069a8a9c1f1d441195fba90553dea3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
|
@ -1132,15 +1141,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxxbridge-flags"
|
name = "cxxbridge-flags"
|
||||||
version = "1.0.80"
|
version = "1.0.81"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a"
|
checksum = "8ca220e4794c934dc6b1207c3b42856ad4c302f2df1712e9f8d2eec5afaacf1f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxxbridge-macro"
|
name = "cxxbridge-macro"
|
||||||
version = "1.0.80"
|
version = "1.0.81"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7"
|
checksum = "b846f081361125bfc8dc9d3940c84e1fd83ba54bbca7b17cd29483c828be0704"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -2036,9 +2045,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.14.22"
|
version = "0.14.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064"
|
checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
|
@ -2060,9 +2069,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-rustls"
|
name = "hyper-rustls"
|
||||||
version = "0.23.0"
|
version = "0.23.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac"
|
checksum = "59df7c4e19c950e6e0e868dcc0a300b09a9b88e9ec55bd879ca819087a77355d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"hyper",
|
"hyper",
|
||||||
|
@ -2290,6 +2299,7 @@ dependencies = [
|
||||||
"base32",
|
"base32",
|
||||||
"base64urlsafedata",
|
"base64urlsafedata",
|
||||||
"last-git-commit",
|
"last-git-commit",
|
||||||
|
"num_enum",
|
||||||
"scim_proto",
|
"scim_proto",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -2543,7 +2553,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ldap3_client"
|
name = "ldap3_client"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/kanidm/ldap3.git#6b0d146d3f85a32add3bdc3639ba4146822eb861"
|
source = "git+https://github.com/kanidm/ldap3.git#1adbd017d02a60e09967572706cb22b1394d927b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.13.1",
|
"base64 0.13.1",
|
||||||
"base64urlsafedata",
|
"base64urlsafedata",
|
||||||
|
@ -2562,7 +2572,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ldap3_proto"
|
name = "ldap3_proto"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/kanidm/ldap3.git#6b0d146d3f85a32add3bdc3639ba4146822eb861"
|
source = "git+https://github.com/kanidm/ldap3.git#1adbd017d02a60e09967572706cb22b1394d927b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"lber",
|
"lber",
|
||||||
|
@ -2959,9 +2969,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oauth2"
|
name = "oauth2"
|
||||||
version = "4.2.3"
|
version = "4.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6d62c436394991641b970a92e23e8eeb4eb9bca74af4f5badc53bcd568daadbd"
|
checksum = "eeaf26a72311c087f8c5ba617c96fac67a5c04f430e716ac8d8ab2de62e23368"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.13.1",
|
"base64 0.13.1",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -3091,9 +3101,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.3.1"
|
version = "6.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9"
|
checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "overload"
|
name = "overload"
|
||||||
|
@ -4799,9 +4809,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.2.1"
|
version = "1.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83"
|
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.8",
|
"getrandom 0.2.8",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -5031,9 +5041,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webauthn-authenticator-rs"
|
name = "webauthn-authenticator-rs"
|
||||||
version = "0.4.7"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d30dcdffd0c5dfa110246701399efcc09962c1bb565f61a5d7fe995645ff6f21"
|
checksum = "dbc33594bd26aabc90ce6d081d98617f5d16803660187f88912dead3ac2a9784"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"authenticator-ctap2-2021",
|
"authenticator-ctap2-2021",
|
||||||
"base64urlsafedata",
|
"base64urlsafedata",
|
||||||
|
@ -5045,14 +5055,15 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
|
"uuid",
|
||||||
"webauthn-rs-proto",
|
"webauthn-rs-proto",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webauthn-rs"
|
name = "webauthn-rs"
|
||||||
version = "0.4.7"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d5984278a28dc397c565fd79ee1aba67b74fa365c4eea489f7258b3f902422f"
|
checksum = "2db00711c712414e93b019c4596315085792215bc2ac2d5872f9e8913b0a6316"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64urlsafedata",
|
"base64urlsafedata",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -5064,9 +5075,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webauthn-rs-core"
|
name = "webauthn-rs-core"
|
||||||
version = "0.4.7"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6528b4769d8fbe020e0e8c2e66bab6035982a2e9c3f8dac384120718f4763f4"
|
checksum = "8ef9a989b5cd2c39c52850c4bc36ebc88907a06ceacf7f80e45d78a308944b9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.13.1",
|
"base64 0.13.1",
|
||||||
"base64urlsafedata",
|
"base64urlsafedata",
|
||||||
|
@ -5088,9 +5099,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webauthn-rs-proto"
|
name = "webauthn-rs-proto"
|
||||||
version = "0.4.7"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09e9a265574f8d7b8f8c94c4488bb491a82d7b8e183003a4512d3dceb88efd98"
|
checksum = "585c7662de492733e6ea11e2726270bf34f5d7f8dbd08cd089830fbb3639a229"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64urlsafedata",
|
"base64urlsafedata",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
|
|
@ -158,10 +158,10 @@ wasm-bindgen = "^0.2.81"
|
||||||
wasm-bindgen-futures = "^0.4.30"
|
wasm-bindgen-futures = "^0.4.30"
|
||||||
wasm-bindgen-test = "0.3.33"
|
wasm-bindgen-test = "0.3.33"
|
||||||
|
|
||||||
webauthn-authenticator-rs = "0.4.7"
|
webauthn-authenticator-rs = "0.4.8"
|
||||||
webauthn-rs = "0.4.7"
|
webauthn-rs = "0.4.8"
|
||||||
webauthn-rs-core = "0.4.7"
|
webauthn-rs-core = "0.4.8"
|
||||||
webauthn-rs-proto = "0.4.7"
|
webauthn-rs-proto = "0.4.8"
|
||||||
# webauthn-authenticator-rs = { path = "../webauthn-rs/webauthn-authenticator-rs" }
|
# webauthn-authenticator-rs = { path = "../webauthn-rs/webauthn-authenticator-rs" }
|
||||||
# webauthn-rs = { path = "../webauthn-rs/webauthn-rs" }
|
# webauthn-rs = { path = "../webauthn-rs/webauthn-rs" }
|
||||||
# webauthn-rs-core = { path = "../webauthn-rs/webauthn-rs-core" }
|
# webauthn-rs-core = { path = "../webauthn-rs/webauthn-rs-core" }
|
||||||
|
|
|
@ -18,6 +18,7 @@ wasm = ["webauthn-rs-proto/wasm"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base32.workspace = true
|
base32.workspace = true
|
||||||
base64urlsafedata.workspace = true
|
base64urlsafedata.workspace = true
|
||||||
|
num_enum.workspace = true
|
||||||
scim_proto.workspace = true
|
scim_proto.workspace = true
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use num_enum::TryFromPrimitive;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use webauthn_rs_proto::{
|
use webauthn_rs_proto::{
|
||||||
|
@ -315,10 +317,34 @@ impl fmt::Display for AuthType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
|
#[derive(TryFromPrimitive)]
|
||||||
|
#[repr(u16)]
|
||||||
pub enum UiHint {
|
pub enum UiHint {
|
||||||
PosixAccount,
|
ExperimentalFeatures = 0,
|
||||||
|
PosixAccount = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for UiHint {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
UiHint::PosixAccount => write!(f, "PosixAccount"),
|
||||||
|
UiHint::ExperimentalFeatures => write!(f, "ExperimentalFeatures"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for UiHint {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"PosixAccount" => Ok(UiHint::PosixAccount),
|
||||||
|
"ExperimentalFeatures" => Ok(UiHint::ExperimentalFeatures),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
|
|
@ -139,7 +139,7 @@ fn from_vec_dbval1(attr_val: Vec<DbValueV1>) -> Result<DbValueSetV2, OperationEr
|
||||||
let vs: Result<Vec<_>, _> = viter
|
let vs: Result<Vec<_>, _> = viter
|
||||||
.map(|dbv| {
|
.map(|dbv| {
|
||||||
if let DbValueV1::IndexType(s) = dbv {
|
if let DbValueV1::IndexType(s) = dbv {
|
||||||
Ok(s)
|
u16::try_from(s).map_err(|_| OperationError::InvalidValueState)
|
||||||
} else {
|
} else {
|
||||||
Err(OperationError::InvalidValueState)
|
Err(OperationError::InvalidValueState)
|
||||||
}
|
}
|
||||||
|
|
|
@ -495,7 +495,7 @@ pub enum DbValueSetV2 {
|
||||||
#[serde(rename = "SY")]
|
#[serde(rename = "SY")]
|
||||||
SyntaxType(Vec<u16>),
|
SyntaxType(Vec<u16>),
|
||||||
#[serde(rename = "IN")]
|
#[serde(rename = "IN")]
|
||||||
IndexType(Vec<usize>),
|
IndexType(Vec<u16>),
|
||||||
#[serde(rename = "RF")]
|
#[serde(rename = "RF")]
|
||||||
Reference(Vec<Uuid>),
|
Reference(Vec<Uuid>),
|
||||||
#[serde(rename = "JF")]
|
#[serde(rename = "JF")]
|
||||||
|
@ -550,11 +550,13 @@ pub enum DbValueSetV2 {
|
||||||
JwsKeyRs256(Vec<Vec<u8>>),
|
JwsKeyRs256(Vec<Vec<u8>>),
|
||||||
#[serde(rename = "AS")]
|
#[serde(rename = "AS")]
|
||||||
Oauth2Session(Vec<DbValueOauth2Session>),
|
Oauth2Session(Vec<DbValueOauth2Session>),
|
||||||
|
#[serde(rename = "UH")]
|
||||||
|
UiHint(Vec<u16>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DbValueSetV2 {
|
impl DbValueSetV2 {
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
match &self {
|
match self {
|
||||||
DbValueSetV2::Utf8(set) => set.len(),
|
DbValueSetV2::Utf8(set) => set.len(),
|
||||||
DbValueSetV2::Iutf8(set) => set.len(),
|
DbValueSetV2::Iutf8(set) => set.len(),
|
||||||
DbValueSetV2::Iname(set) => set.len(),
|
DbValueSetV2::Iname(set) => set.len(),
|
||||||
|
@ -589,6 +591,7 @@ impl DbValueSetV2 {
|
||||||
DbValueSetV2::Oauth2Session(set) => set.len(),
|
DbValueSetV2::Oauth2Session(set) => set.len(),
|
||||||
DbValueSetV2::JwsKeyEs256(set) => set.len(),
|
DbValueSetV2::JwsKeyEs256(set) => set.len(),
|
||||||
DbValueSetV2::JwsKeyRs256(set) => set.len(),
|
DbValueSetV2::JwsKeyRs256(set) => set.len(),
|
||||||
|
DbValueSetV2::UiHint(set) => set.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::constants::uuids::*;
|
||||||
use crate::constants::values::*;
|
use crate::constants::values::*;
|
||||||
use crate::entry::{Entry, EntryInit, EntryInitNew, EntryNew};
|
use crate::entry::{Entry, EntryInit, EntryInitNew, EntryNew};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
use kanidm_proto::v1::UiHint;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use uuid::{uuid, Uuid};
|
use uuid::{uuid, Uuid};
|
||||||
|
@ -477,6 +478,28 @@ pub const JSON_IDM_ALL_ACCOUNTS: &str = r#"{
|
||||||
}
|
}
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref E_IDM_UI_ENABLE_EXPERIMENTAL_FEATURES: EntryInitNew = entry_init!(
|
||||||
|
("class", CLASS_OBJECT.clone()),
|
||||||
|
("class", CLASS_GROUP.clone()),
|
||||||
|
(
|
||||||
|
"name",
|
||||||
|
Value::new_iname("idm_ui_enable_experimental_features")
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"uuid",
|
||||||
|
Value::new_uuid(UUID_IDM_UI_ENABLE_EXPERIMENTAL_FEATURES)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"description",
|
||||||
|
Value::new_utf8s(
|
||||||
|
"Members of this group will have access to experimental web UI features."
|
||||||
|
)
|
||||||
|
),
|
||||||
|
("grant_ui_hint", Value::UiHint(UiHint::ExperimentalFeatures))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// This must be the last group to init to include the UUID of the other high priv groups.
|
/// This must be the last group to init to include the UUID of the other high priv groups.
|
||||||
pub const JSON_IDM_HIGH_PRIVILEGE_V1: &str = r#"{
|
pub const JSON_IDM_HIGH_PRIVILEGE_V1: &str = r#"{
|
||||||
"attrs": {
|
"attrs": {
|
||||||
|
|
|
@ -1262,6 +1262,37 @@ pub const JSON_SCHEMA_ATTR_SYNC_COOKIE: &str = r#"{
|
||||||
}
|
}
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
|
pub const JSON_SCHEMA_ATTR_GRANT_UI_HINT: &str = r#"{
|
||||||
|
"attrs": {
|
||||||
|
"class": [
|
||||||
|
"object",
|
||||||
|
"system",
|
||||||
|
"attributetype"
|
||||||
|
],
|
||||||
|
"description": [
|
||||||
|
"A ui hint that is granted via membership to a group"
|
||||||
|
],
|
||||||
|
"index": [
|
||||||
|
"EQUALITY"
|
||||||
|
],
|
||||||
|
"unique": [
|
||||||
|
"false"
|
||||||
|
],
|
||||||
|
"multivalue": [
|
||||||
|
"true"
|
||||||
|
],
|
||||||
|
"attributename": [
|
||||||
|
"grant_ui_hint"
|
||||||
|
],
|
||||||
|
"syntax": [
|
||||||
|
"UIHINT"
|
||||||
|
],
|
||||||
|
"uuid": [
|
||||||
|
"00000000-0000-0000-0000-ffff00000119"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}"#;
|
||||||
|
|
||||||
// === classes ===
|
// === classes ===
|
||||||
|
|
||||||
pub const JSON_SCHEMA_CLASS_PERSON: &str = r#"
|
pub const JSON_SCHEMA_CLASS_PERSON: &str = r#"
|
||||||
|
@ -1337,7 +1368,8 @@ pub const JSON_SCHEMA_CLASS_GROUP: &str = r#"
|
||||||
"group"
|
"group"
|
||||||
],
|
],
|
||||||
"systemmay": [
|
"systemmay": [
|
||||||
"member"
|
"member",
|
||||||
|
"grant_ui_hint"
|
||||||
],
|
],
|
||||||
"systemmust": [
|
"systemmust": [
|
||||||
"name",
|
"name",
|
||||||
|
|
|
@ -55,6 +55,9 @@ pub const UUID_IDM_ALL_ACCOUNTS: Uuid = uuid!("00000000-0000-0000-0000-000000000
|
||||||
pub const _UUID_IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV: Uuid =
|
pub const _UUID_IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV: Uuid =
|
||||||
uuid!("00000000-0000-0000-0000-000000000037");
|
uuid!("00000000-0000-0000-0000-000000000037");
|
||||||
|
|
||||||
|
pub const UUID_IDM_UI_ENABLE_EXPERIMENTAL_FEATURES: Uuid =
|
||||||
|
uuid!("00000000-0000-0000-0000-000000000038");
|
||||||
|
|
||||||
//
|
//
|
||||||
pub const _UUID_IDM_HIGH_PRIVILEGE: Uuid = uuid!("00000000-0000-0000-0000-000000001000");
|
pub const _UUID_IDM_HIGH_PRIVILEGE: Uuid = uuid!("00000000-0000-0000-0000-000000001000");
|
||||||
|
|
||||||
|
@ -206,6 +209,7 @@ pub const _UUID_SCHEMA_ATTR_SYNC_TOKEN_SESSION: Uuid =
|
||||||
pub const _UUID_SCHEMA_ATTR_SYNC_COOKIE: Uuid = uuid!("00000000-0000-0000-0000-ffff00000116");
|
pub const _UUID_SCHEMA_ATTR_SYNC_COOKIE: Uuid = uuid!("00000000-0000-0000-0000-ffff00000116");
|
||||||
pub const _UUID_SCHEMA_ATTR_OAUTH2_SESSION: Uuid = uuid!("00000000-0000-0000-0000-ffff00000117");
|
pub const _UUID_SCHEMA_ATTR_OAUTH2_SESSION: Uuid = uuid!("00000000-0000-0000-0000-ffff00000117");
|
||||||
pub const UUID_SCHEMA_ATTR_ACP_RECEIVER_GROUP: Uuid = uuid!("00000000-0000-0000-0000-ffff00000118");
|
pub const UUID_SCHEMA_ATTR_ACP_RECEIVER_GROUP: Uuid = uuid!("00000000-0000-0000-0000-ffff00000118");
|
||||||
|
pub const _UUID_SCHEMA_ATTR_GRANT_UI_HINT: Uuid = uuid!("00000000-0000-0000-0000-ffff00000119");
|
||||||
|
|
||||||
// System and domain infos
|
// System and domain infos
|
||||||
// I'd like to strongly criticise william of the past for making poor choices about these allocations.
|
// I'd like to strongly criticise william of the past for making poor choices about these allocations.
|
||||||
|
|
|
@ -39,6 +39,7 @@ lazy_static! {
|
||||||
pub static ref CLASS_ACCOUNT: Value = Value::new_class("account");
|
pub static ref CLASS_ACCOUNT: Value = Value::new_class("account");
|
||||||
pub static ref CLASS_DOMAIN_INFO: Value = Value::new_class("domain_info");
|
pub static ref CLASS_DOMAIN_INFO: Value = Value::new_class("domain_info");
|
||||||
pub static ref CLASS_DYNGROUP: Value = Value::new_class("dyngroup");
|
pub static ref CLASS_DYNGROUP: Value = Value::new_class("dyngroup");
|
||||||
|
pub static ref CLASS_GROUP: Value = Value::new_class("group");
|
||||||
pub static ref CLASS_MEMBEROF: Value = Value::new_class("memberof");
|
pub static ref CLASS_MEMBEROF: Value = Value::new_class("memberof");
|
||||||
pub static ref CLASS_OBJECT: Value = Value::new_class("object");
|
pub static ref CLASS_OBJECT: Value = Value::new_class("object");
|
||||||
pub static ref CLASS_RECYCLED: Value = Value::new_class("recycled");
|
pub static ref CLASS_RECYCLED: Value = Value::new_class("recycled");
|
||||||
|
|
|
@ -33,6 +33,7 @@ use compact_jwt::JwsSigner;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use kanidm_proto::v1::{
|
use kanidm_proto::v1::{
|
||||||
ConsistencyError, Entry as ProtoEntry, Filter as ProtoFilter, OperationError, SchemaError,
|
ConsistencyError, Entry as ProtoEntry, Filter as ProtoFilter, OperationError, SchemaError,
|
||||||
|
UiHint,
|
||||||
};
|
};
|
||||||
use ldap3_proto::simple::{LdapPartialAttribute, LdapSearchResultEntry};
|
use ldap3_proto::simple::{LdapPartialAttribute, LdapSearchResultEntry};
|
||||||
use smartstring::alias::String as AttrString;
|
use smartstring::alias::String as AttrString;
|
||||||
|
@ -1973,6 +1974,12 @@ impl<VALID, STATE> Entry<VALID, STATE> {
|
||||||
self.attrs.get(attr).and_then(|vs| vs.as_devicekey_map())
|
self.attrs.get(attr).and_then(|vs| vs.as_devicekey_map())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
/// Get the set of passkeys on this account, if any are present.
|
||||||
|
pub fn get_ava_uihint(&self, attr: &str) -> Option<&BTreeSet<UiHint>> {
|
||||||
|
self.attrs.get(attr).and_then(|vs| vs.as_uihint_set())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
/// Return a single secret value, if valid to transform this value.
|
/// Return a single secret value, if valid to transform this value.
|
||||||
pub fn get_ava_single_secret(&self, attr: &str) -> Option<&str> {
|
pub fn get_ava_single_secret(&self, attr: &str) -> Option<&str> {
|
||||||
|
|
|
@ -91,7 +91,13 @@ macro_rules! try_from_entry {
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let mut ui_hints = BTreeSet::default();
|
// Provide hints from groups.
|
||||||
|
let mut ui_hints: BTreeSet<_> = groups
|
||||||
|
.iter()
|
||||||
|
.map(|group: &Group| group.ui_hints.iter())
|
||||||
|
.flatten()
|
||||||
|
.copied()
|
||||||
|
.collect();
|
||||||
|
|
||||||
if $value.attribute_equality("class", &PVCLASS_POSIXACCOUNT) {
|
if $value.attribute_equality("class", &PVCLASS_POSIXACCOUNT) {
|
||||||
ui_hints.insert(UiHint::PosixAccount);
|
ui_hints.insert(UiHint::PosixAccount);
|
||||||
|
@ -670,9 +676,10 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::constants::JSON_ANONYMOUS_V1;
|
use crate::event::{CreateEvent, ModifyEvent};
|
||||||
// use crate::entry::{Entry, EntryNew, EntrySealed};
|
use crate::prelude::*;
|
||||||
// use crate::idm::account::Account;
|
use async_std::task;
|
||||||
|
use kanidm_proto::v1::{AuthType, UiHint};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_idm_account_from_anonymous() {
|
fn test_idm_account_from_anonymous() {
|
||||||
|
@ -682,14 +689,94 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_idm_account_from_real() {
|
fn test_idm_account_ui_hints() {
|
||||||
// For now, nothing, but later, we'll test different types of cred
|
run_idm_test!(|_qs: &QueryServer,
|
||||||
// passing.
|
idms: &IdmServer,
|
||||||
}
|
_idms_delayed: &mut IdmServerDelayed| {
|
||||||
|
let ct = duration_from_epoch_now();
|
||||||
|
let mut idms_prox_write = task::block_on(idms.proxy_write(ct.clone()));
|
||||||
|
|
||||||
#[test]
|
let target_uuid = Uuid::new_v4();
|
||||||
fn test_idm_account_set_credential() {
|
|
||||||
// Using a real entry, set a credential back to it's entry.
|
// Create a user. So far no ui hints.
|
||||||
// In the end, this boils down to a modify operation on the Value
|
// Create a service account
|
||||||
|
let e = entry_init!(
|
||||||
|
("class", Value::new_class("object")),
|
||||||
|
("class", Value::new_class("account")),
|
||||||
|
("class", Value::new_class("person")),
|
||||||
|
("name", Value::new_iname("testaccount")),
|
||||||
|
("uuid", Value::new_uuid(target_uuid)),
|
||||||
|
("description", Value::new_utf8s("testaccount")),
|
||||||
|
("displayname", Value::new_utf8s("Test Account"))
|
||||||
|
);
|
||||||
|
|
||||||
|
let ce = CreateEvent::new_internal(vec![e]);
|
||||||
|
assert!(idms_prox_write.qs_write.create(&ce).is_ok());
|
||||||
|
|
||||||
|
let account = idms_prox_write
|
||||||
|
.target_to_account(&target_uuid)
|
||||||
|
.expect("account must exist");
|
||||||
|
let session_id = uuid::Uuid::new_v4();
|
||||||
|
let uat = account
|
||||||
|
.to_userauthtoken(session_id, ct, AuthType::Passkey, None)
|
||||||
|
.expect("Unable to create uat");
|
||||||
|
|
||||||
|
// Check the ui hints are as expected.
|
||||||
|
assert!(uat.ui_hints.is_empty());
|
||||||
|
|
||||||
|
// Modify the user to be a posix account, ensure they get the hint.
|
||||||
|
let me_posix = unsafe {
|
||||||
|
ModifyEvent::new_internal_invalid(
|
||||||
|
filter!(f_eq("name", PartialValue::new_iname("testaccount"))),
|
||||||
|
ModifyList::new_list(vec![
|
||||||
|
Modify::Present(
|
||||||
|
AttrString::from("class"),
|
||||||
|
Value::new_class("posixaccount"),
|
||||||
|
),
|
||||||
|
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
|
||||||
|
|
||||||
|
// Check the ui hints are as expected.
|
||||||
|
let account = idms_prox_write
|
||||||
|
.target_to_account(&target_uuid)
|
||||||
|
.expect("account must exist");
|
||||||
|
let session_id = uuid::Uuid::new_v4();
|
||||||
|
let uat = account
|
||||||
|
.to_userauthtoken(session_id, ct, AuthType::Passkey, None)
|
||||||
|
.expect("Unable to create uat");
|
||||||
|
|
||||||
|
assert!(uat.ui_hints.len() == 1);
|
||||||
|
assert!(uat.ui_hints.contains(&UiHint::PosixAccount));
|
||||||
|
|
||||||
|
// Add a group with a ui hint, and then check they get the hint.
|
||||||
|
let e = entry_init!(
|
||||||
|
("class", Value::new_class("object")),
|
||||||
|
("class", Value::new_class("group")),
|
||||||
|
("name", Value::new_iname("test_uihint_group")),
|
||||||
|
("member", Value::Refer(target_uuid)),
|
||||||
|
("grant_ui_hint", Value::UiHint(UiHint::ExperimentalFeatures))
|
||||||
|
);
|
||||||
|
|
||||||
|
let ce = CreateEvent::new_internal(vec![e]);
|
||||||
|
assert!(idms_prox_write.qs_write.create(&ce).is_ok());
|
||||||
|
|
||||||
|
// Check the ui hints are as expected.
|
||||||
|
let account = idms_prox_write
|
||||||
|
.target_to_account(&target_uuid)
|
||||||
|
.expect("account must exist");
|
||||||
|
let session_id = uuid::Uuid::new_v4();
|
||||||
|
let uat = account
|
||||||
|
.to_userauthtoken(session_id, ct, AuthType::Passkey, None)
|
||||||
|
.expect("Unable to create uat");
|
||||||
|
|
||||||
|
assert!(uat.ui_hints.len() == 2);
|
||||||
|
assert!(uat.ui_hints.contains(&UiHint::PosixAccount));
|
||||||
|
assert!(uat.ui_hints.contains(&UiHint::ExperimentalFeatures));
|
||||||
|
|
||||||
|
assert!(idms_prox_write.commit().is_ok());
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
use kanidm_proto::v1::UiHint;
|
||||||
use kanidm_proto::v1::{Group as ProtoGroup, OperationError};
|
use kanidm_proto::v1::{Group as ProtoGroup, OperationError};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -10,6 +13,7 @@ pub struct Group {
|
||||||
spn: String,
|
spn: String,
|
||||||
uuid: Uuid,
|
uuid: Uuid,
|
||||||
// We'll probably add policy and claims later to this
|
// We'll probably add policy and claims later to this
|
||||||
|
pub ui_hints: BTreeSet<UiHint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! try_from_account_e {
|
macro_rules! try_from_account_e {
|
||||||
|
@ -23,13 +27,21 @@ macro_rules! try_from_account_e {
|
||||||
})?;
|
})?;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Setup the user private group
|
||||||
let spn = $value.get_ava_single_proto_string("spn").ok_or(
|
let spn = $value.get_ava_single_proto_string("spn").ok_or(
|
||||||
OperationError::InvalidAccountState("Missing attribute: spn".to_string()),
|
OperationError::InvalidAccountState("Missing attribute: spn".to_string()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let uuid = $value.get_uuid();
|
let uuid = $value.get_uuid();
|
||||||
|
|
||||||
let upg = Group { spn, uuid };
|
// We could allow ui hints on the user direct in the future?
|
||||||
|
let ui_hints = BTreeSet::default();
|
||||||
|
|
||||||
|
let upg = Group {
|
||||||
|
spn,
|
||||||
|
uuid,
|
||||||
|
ui_hints,
|
||||||
|
};
|
||||||
|
|
||||||
let mut groups: Vec<Group> = match $value.get_ava_as_refuuid("memberof") {
|
let mut groups: Vec<Group> = match $value.get_ava_as_refuuid("memberof") {
|
||||||
Some(riter) => {
|
Some(riter) => {
|
||||||
|
@ -111,7 +123,16 @@ impl Group {
|
||||||
|
|
||||||
let uuid = value.get_uuid();
|
let uuid = value.get_uuid();
|
||||||
|
|
||||||
Ok(Group { spn, uuid })
|
let ui_hints = value
|
||||||
|
.get_ava_uihint("grant_ui_hint")
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
Ok(Group {
|
||||||
|
spn,
|
||||||
|
uuid,
|
||||||
|
ui_hints,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_proto(&self) -> ProtoGroup {
|
pub fn to_proto(&self) -> ProtoGroup {
|
||||||
|
|
|
@ -197,6 +197,7 @@ impl SchemaAttribute {
|
||||||
// These are just insensitive string lookups on the hex-ified kid.
|
// These are just insensitive string lookups on the hex-ified kid.
|
||||||
SyntaxType::JwsKeyEs256 => matches!(v, PartialValue::Iutf8(_)),
|
SyntaxType::JwsKeyEs256 => matches!(v, PartialValue::Iutf8(_)),
|
||||||
SyntaxType::JwsKeyRs256 => matches!(v, PartialValue::Iutf8(_)),
|
SyntaxType::JwsKeyRs256 => matches!(v, PartialValue::Iutf8(_)),
|
||||||
|
SyntaxType::UiHint => matches!(v, PartialValue::UiHint(_)),
|
||||||
};
|
};
|
||||||
if r {
|
if r {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -243,6 +244,7 @@ impl SchemaAttribute {
|
||||||
SyntaxType::Oauth2Session => matches!(v, Value::Oauth2Session(_, _)),
|
SyntaxType::Oauth2Session => matches!(v, Value::Oauth2Session(_, _)),
|
||||||
SyntaxType::JwsKeyEs256 => matches!(v, Value::JwsKeyEs256(_)),
|
SyntaxType::JwsKeyEs256 => matches!(v, Value::JwsKeyEs256(_)),
|
||||||
SyntaxType::JwsKeyRs256 => matches!(v, Value::JwsKeyRs256(_)),
|
SyntaxType::JwsKeyRs256 => matches!(v, Value::JwsKeyRs256(_)),
|
||||||
|
SyntaxType::UiHint => matches!(v, Value::UiHint(_)),
|
||||||
};
|
};
|
||||||
if r {
|
if r {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
// This is really only used for long lived, high level types that need clone
|
// This is really only used for long lived, high level types that need clone
|
||||||
// that otherwise can't be cloned. Think Mutex.
|
// that otherwise can't be cloned. Think Mutex.
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use concread::arcache::{ARCache, ARCacheBuilder, ARCacheReadTxn};
|
use concread::arcache::{ARCache, ARCacheBuilder, ARCacheReadTxn};
|
||||||
use concread::cowcell::*;
|
use concread::cowcell::*;
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use kanidm_proto::v1::{ConsistencyError, SchemaError};
|
use kanidm_proto::v1::{ConsistencyError, SchemaError, UiHint};
|
||||||
use tokio::sync::{Semaphore, SemaphorePermit};
|
use tokio::sync::{Semaphore, SemaphorePermit};
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
|
@ -517,6 +518,9 @@ pub trait QueryServerTransaction<'a> {
|
||||||
SyntaxType::JwsKeyEs256 => Err(OperationError::InvalidAttribute("JwsKeyEs256 Values can not be supplied through modification".to_string())),
|
SyntaxType::JwsKeyEs256 => Err(OperationError::InvalidAttribute("JwsKeyEs256 Values can not be supplied through modification".to_string())),
|
||||||
SyntaxType::JwsKeyRs256 => Err(OperationError::InvalidAttribute("JwsKeyRs256 Values can not be supplied through modification".to_string())),
|
SyntaxType::JwsKeyRs256 => Err(OperationError::InvalidAttribute("JwsKeyRs256 Values can not be supplied through modification".to_string())),
|
||||||
SyntaxType::Oauth2Session => Err(OperationError::InvalidAttribute("Oauth2Session Values can not be supplied through modification".to_string())),
|
SyntaxType::Oauth2Session => Err(OperationError::InvalidAttribute("Oauth2Session Values can not be supplied through modification".to_string())),
|
||||||
|
SyntaxType::UiHint => UiHint::from_str(value)
|
||||||
|
.map(Value::UiHint)
|
||||||
|
.map_err(|()| OperationError::InvalidAttribute("Invalid uihint syntax".to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -645,6 +649,11 @@ pub trait QueryServerTransaction<'a> {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
SyntaxType::UiHint => UiHint::from_str(value)
|
||||||
|
.map(PartialValue::UiHint)
|
||||||
|
.map_err(|()| {
|
||||||
|
OperationError::InvalidAttribute("Invalid uihint syntax".to_string())
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -2682,6 +2691,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
JSON_SCHEMA_ATTR_OAUTH2_PREFER_SHORT_USERNAME,
|
JSON_SCHEMA_ATTR_OAUTH2_PREFER_SHORT_USERNAME,
|
||||||
JSON_SCHEMA_ATTR_SYNC_TOKEN_SESSION,
|
JSON_SCHEMA_ATTR_SYNC_TOKEN_SESSION,
|
||||||
JSON_SCHEMA_ATTR_SYNC_COOKIE,
|
JSON_SCHEMA_ATTR_SYNC_COOKIE,
|
||||||
|
JSON_SCHEMA_ATTR_GRANT_UI_HINT,
|
||||||
JSON_SCHEMA_CLASS_PERSON,
|
JSON_SCHEMA_CLASS_PERSON,
|
||||||
JSON_SCHEMA_CLASS_ORGPERSON,
|
JSON_SCHEMA_CLASS_ORGPERSON,
|
||||||
JSON_SCHEMA_CLASS_GROUP,
|
JSON_SCHEMA_CLASS_GROUP,
|
||||||
|
@ -2848,13 +2858,26 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
debug_assert!(res.is_ok());
|
debug_assert!(res.is_ok());
|
||||||
res?;
|
res?;
|
||||||
|
|
||||||
|
let idm_entries = [E_IDM_UI_ENABLE_EXPERIMENTAL_FEATURES.clone()];
|
||||||
|
|
||||||
|
let res: Result<(), _> = idm_entries
|
||||||
|
.into_iter()
|
||||||
|
.try_for_each(|entry| self.internal_migrate_or_create(entry));
|
||||||
|
if res.is_ok() {
|
||||||
|
admin_debug!("initialise_idm -> result Ok!");
|
||||||
|
} else {
|
||||||
|
admin_error!(?res, "initialise_idm p3 -> result");
|
||||||
|
}
|
||||||
|
debug_assert!(res.is_ok());
|
||||||
|
res?;
|
||||||
|
|
||||||
self.changed_schema.set(true);
|
self.changed_schema.set(true);
|
||||||
self.changed_acp.set(true);
|
self.changed_acp.set(true);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "info", name = "reload_schema", skip(self))]
|
#[instrument(level = "debug", name = "reload_schema", skip(self))]
|
||||||
fn reload_schema(&mut self) -> Result<(), OperationError> {
|
fn reload_schema(&mut self) -> Result<(), OperationError> {
|
||||||
// supply entries to the writable schema to reload from.
|
// supply entries to the writable schema to reload from.
|
||||||
// find all attributes.
|
// find all attributes.
|
||||||
|
|
|
@ -12,6 +12,8 @@ use std::time::Duration;
|
||||||
use compact_jwt::JwsSigner;
|
use compact_jwt::JwsSigner;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use kanidm_proto::v1::Filter as ProtoFilter;
|
use kanidm_proto::v1::Filter as ProtoFilter;
|
||||||
|
use kanidm_proto::v1::UiHint;
|
||||||
|
use num_enum::TryFromPrimitive;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sshkeys::PublicKey as SshPublicKey;
|
use sshkeys::PublicKey as SshPublicKey;
|
||||||
|
@ -72,14 +74,6 @@ pub struct Address {
|
||||||
pub country: String,
|
pub country: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, Hash)]
|
|
||||||
pub enum IndexType {
|
|
||||||
Equality,
|
|
||||||
Presence,
|
|
||||||
SubString,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum IntentTokenState {
|
pub enum IntentTokenState {
|
||||||
Valid {
|
Valid {
|
||||||
|
@ -95,6 +89,27 @@ pub enum IntentTokenState {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(
|
||||||
|
Debug,
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
Deserialize,
|
||||||
|
Serialize,
|
||||||
|
Hash,
|
||||||
|
TryFromPrimitive,
|
||||||
|
)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum IndexType {
|
||||||
|
Equality,
|
||||||
|
Presence,
|
||||||
|
SubString,
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for IndexType {
|
impl TryFrom<&str> for IndexType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
|
@ -111,19 +126,6 @@ impl TryFrom<&str> for IndexType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<usize> for IndexType {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
0 => Ok(IndexType::Equality),
|
|
||||||
1 => Ok(IndexType::Presence),
|
|
||||||
2 => Ok(IndexType::SubString),
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexType {
|
impl IndexType {
|
||||||
pub fn as_idx_str(&self) -> &str {
|
pub fn as_idx_str(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
|
@ -132,14 +134,6 @@ impl IndexType {
|
||||||
IndexType::SubString => "sub",
|
IndexType::SubString => "sub",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_usize(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
IndexType::Equality => 0,
|
|
||||||
IndexType::Presence => 1,
|
|
||||||
IndexType::SubString => 2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for IndexType {
|
impl fmt::Display for IndexType {
|
||||||
|
@ -157,7 +151,19 @@ impl fmt::Display for IndexType {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Hash, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
|
#[derive(
|
||||||
|
Hash,
|
||||||
|
Debug,
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
Deserialize,
|
||||||
|
Serialize,
|
||||||
|
TryFromPrimitive,
|
||||||
|
)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
pub enum SyntaxType {
|
pub enum SyntaxType {
|
||||||
Utf8String = 0,
|
Utf8String = 0,
|
||||||
|
@ -189,6 +195,7 @@ pub enum SyntaxType {
|
||||||
JwsKeyEs256 = 26,
|
JwsKeyEs256 = 26,
|
||||||
JwsKeyRs256 = 27,
|
JwsKeyRs256 = 27,
|
||||||
Oauth2Session = 28,
|
Oauth2Session = 28,
|
||||||
|
UiHint = 29,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for SyntaxType {
|
impl TryFrom<&str> for SyntaxType {
|
||||||
|
@ -227,45 +234,7 @@ impl TryFrom<&str> for SyntaxType {
|
||||||
"JWS_KEY_ES256" => Ok(SyntaxType::JwsKeyEs256),
|
"JWS_KEY_ES256" => Ok(SyntaxType::JwsKeyEs256),
|
||||||
"JWS_KEY_RS256" => Ok(SyntaxType::JwsKeyRs256),
|
"JWS_KEY_RS256" => Ok(SyntaxType::JwsKeyRs256),
|
||||||
"OAUTH2SESSION" => Ok(SyntaxType::Oauth2Session),
|
"OAUTH2SESSION" => Ok(SyntaxType::Oauth2Session),
|
||||||
_ => Err(()),
|
"UIHINT" => Ok(SyntaxType::UiHint),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<u16> for SyntaxType {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(value: u16) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
0 => Ok(SyntaxType::Utf8String),
|
|
||||||
1 => Ok(SyntaxType::Utf8StringInsensitive),
|
|
||||||
2 => Ok(SyntaxType::Uuid),
|
|
||||||
3 => Ok(SyntaxType::Boolean),
|
|
||||||
4 => Ok(SyntaxType::SyntaxId),
|
|
||||||
5 => Ok(SyntaxType::IndexId),
|
|
||||||
6 => Ok(SyntaxType::ReferenceUuid),
|
|
||||||
7 => Ok(SyntaxType::JsonFilter),
|
|
||||||
8 => Ok(SyntaxType::Credential),
|
|
||||||
9 => Ok(SyntaxType::SecretUtf8String),
|
|
||||||
10 => Ok(SyntaxType::SshKey),
|
|
||||||
11 => Ok(SyntaxType::SecurityPrincipalName),
|
|
||||||
12 => Ok(SyntaxType::Uint32),
|
|
||||||
13 => Ok(SyntaxType::Cid),
|
|
||||||
14 => Ok(SyntaxType::Utf8StringIname),
|
|
||||||
15 => Ok(SyntaxType::NsUniqueId),
|
|
||||||
16 => Ok(SyntaxType::DateTime),
|
|
||||||
17 => Ok(SyntaxType::EmailAddress),
|
|
||||||
18 => Ok(SyntaxType::Url),
|
|
||||||
19 => Ok(SyntaxType::OauthScope),
|
|
||||||
20 => Ok(SyntaxType::OauthScopeMap),
|
|
||||||
21 => Ok(SyntaxType::PrivateBinary),
|
|
||||||
22 => Ok(SyntaxType::IntentToken),
|
|
||||||
23 => Ok(SyntaxType::Passkey),
|
|
||||||
24 => Ok(SyntaxType::DeviceKey),
|
|
||||||
25 => Ok(SyntaxType::Session),
|
|
||||||
26 => Ok(SyntaxType::JwsKeyEs256),
|
|
||||||
27 => Ok(SyntaxType::JwsKeyRs256),
|
|
||||||
28 => Ok(SyntaxType::Oauth2Session),
|
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,6 +272,7 @@ impl fmt::Display for SyntaxType {
|
||||||
SyntaxType::JwsKeyEs256 => "JWS_KEY_ES256",
|
SyntaxType::JwsKeyEs256 => "JWS_KEY_ES256",
|
||||||
SyntaxType::JwsKeyRs256 => "JWS_KEY_RS256",
|
SyntaxType::JwsKeyRs256 => "JWS_KEY_RS256",
|
||||||
SyntaxType::Oauth2Session => "OAUTH2SESSION",
|
SyntaxType::Oauth2Session => "OAUTH2SESSION",
|
||||||
|
SyntaxType::UiHint => "UIHINT",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,6 +318,7 @@ pub enum PartialValue {
|
||||||
// Float64(f64),
|
// Float64(f64),
|
||||||
RestrictedString(String),
|
RestrictedString(String),
|
||||||
IntentToken(String),
|
IntentToken(String),
|
||||||
|
UiHint(UiHint),
|
||||||
|
|
||||||
Passkey(Uuid),
|
Passkey(Uuid),
|
||||||
DeviceKey(Uuid),
|
DeviceKey(Uuid),
|
||||||
|
@ -697,7 +668,7 @@ impl PartialValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_idx_eq_key(&self) -> String {
|
pub fn get_idx_eq_key(&self) -> String {
|
||||||
match &self {
|
match self {
|
||||||
PartialValue::Utf8(s)
|
PartialValue::Utf8(s)
|
||||||
| PartialValue::Iutf8(s)
|
| PartialValue::Iutf8(s)
|
||||||
| PartialValue::Iname(s)
|
| PartialValue::Iname(s)
|
||||||
|
@ -736,6 +707,7 @@ impl PartialValue {
|
||||||
PartialValue::IntentToken(u) => u.clone(),
|
PartialValue::IntentToken(u) => u.clone(),
|
||||||
PartialValue::TrustedDeviceEnrollment(u) => u.as_hyphenated().to_string(),
|
PartialValue::TrustedDeviceEnrollment(u) => u.as_hyphenated().to_string(),
|
||||||
PartialValue::Session(u) => u.as_hyphenated().to_string(),
|
PartialValue::Session(u) => u.as_hyphenated().to_string(),
|
||||||
|
PartialValue::UiHint(u) => (*u as u16).to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,6 +782,7 @@ pub enum Value {
|
||||||
|
|
||||||
JwsKeyEs256(JwsSigner),
|
JwsKeyEs256(JwsSigner),
|
||||||
JwsKeyRs256(JwsSigner),
|
JwsKeyRs256(JwsSigner),
|
||||||
|
UiHint(UiHint),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Value {
|
impl PartialEq for Value {
|
||||||
|
|
|
@ -20,9 +20,9 @@ impl ValueSetIndex {
|
||||||
self.set.insert(s)
|
self.set.insert(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_dbvs2(data: Vec<usize>) -> Result<ValueSet, OperationError> {
|
pub fn from_dbvs2(data: Vec<u16>) -> Result<ValueSet, OperationError> {
|
||||||
let set: Result<_, _> = data.into_iter().map(IndexType::try_from).collect();
|
let set: Result<_, _> = data.into_iter().map(IndexType::try_from).collect();
|
||||||
let set = set.map_err(|()| OperationError::InvalidValueState)?;
|
let set = set.map_err(|_| OperationError::InvalidValueState)?;
|
||||||
Ok(Box::new(ValueSetIndex { set }))
|
Ok(Box::new(ValueSetIndex { set }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ impl ValueSetT for ValueSetIndex {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_db_valueset_v2(&self) -> DbValueSetV2 {
|
fn to_db_valueset_v2(&self) -> DbValueSetV2 {
|
||||||
DbValueSetV2::IndexType(self.set.iter().map(|s| s.to_usize()).collect())
|
DbValueSetV2::IndexType(self.set.iter().map(|s| *s as u16).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_partialvalue_iter(&self) -> Box<dyn Iterator<Item = PartialValue> + '_> {
|
fn to_partialvalue_iter(&self) -> Box<dyn Iterator<Item = PartialValue> + '_> {
|
||||||
|
|
|
@ -4,6 +4,7 @@ use compact_jwt::JwsSigner;
|
||||||
use dyn_clone::DynClone;
|
use dyn_clone::DynClone;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use kanidm_proto::v1::Filter as ProtoFilter;
|
use kanidm_proto::v1::Filter as ProtoFilter;
|
||||||
|
use kanidm_proto::v1::UiHint;
|
||||||
use smolset::SmolSet;
|
use smolset::SmolSet;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
// use std::fmt::Debug;
|
// use std::fmt::Debug;
|
||||||
|
@ -36,6 +37,7 @@ mod session;
|
||||||
mod spn;
|
mod spn;
|
||||||
mod ssh;
|
mod ssh;
|
||||||
mod syntax;
|
mod syntax;
|
||||||
|
mod uihint;
|
||||||
mod uint32;
|
mod uint32;
|
||||||
mod url;
|
mod url;
|
||||||
mod utf8;
|
mod utf8;
|
||||||
|
@ -60,6 +62,7 @@ pub use self::session::{ValueSetOauth2Session, ValueSetSession};
|
||||||
pub use self::spn::ValueSetSpn;
|
pub use self::spn::ValueSetSpn;
|
||||||
pub use self::ssh::ValueSetSshKey;
|
pub use self::ssh::ValueSetSshKey;
|
||||||
pub use self::syntax::ValueSetSyntax;
|
pub use self::syntax::ValueSetSyntax;
|
||||||
|
pub use self::uihint::ValueSetUiHint;
|
||||||
pub use self::uint32::ValueSetUint32;
|
pub use self::uint32::ValueSetUint32;
|
||||||
pub use self::url::ValueSetUrl;
|
pub use self::url::ValueSetUrl;
|
||||||
pub use self::utf8::ValueSetUtf8;
|
pub use self::utf8::ValueSetUtf8;
|
||||||
|
@ -495,6 +498,16 @@ pub trait ValueSetT: std::fmt::Debug + DynClone {
|
||||||
debug_assert!(false);
|
debug_assert!(false);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_uihint_set(&self) -> Option<&BTreeSet<UiHint>> {
|
||||||
|
debug_assert!(false);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_uihint_iter(&self) -> Option<Box<dyn Iterator<Item = UiHint> + '_>> {
|
||||||
|
debug_assert!(false);
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for ValueSet {
|
impl PartialEq for ValueSet {
|
||||||
|
@ -546,6 +559,7 @@ pub fn from_result_value_iter(
|
||||||
Value::PublicBinary(t, b) => ValueSetPublicBinary::new(t, b),
|
Value::PublicBinary(t, b) => ValueSetPublicBinary::new(t, b),
|
||||||
Value::IntentToken(u, s) => ValueSetIntentToken::new(u, s),
|
Value::IntentToken(u, s) => ValueSetIntentToken::new(u, s),
|
||||||
Value::EmailAddress(a, _) => ValueSetEmailAddress::new(a),
|
Value::EmailAddress(a, _) => ValueSetEmailAddress::new(a),
|
||||||
|
Value::UiHint(u) => ValueSetUiHint::new(u),
|
||||||
Value::PhoneNumber(_, _)
|
Value::PhoneNumber(_, _)
|
||||||
| Value::Passkey(_, _, _)
|
| Value::Passkey(_, _, _)
|
||||||
| Value::DeviceKey(_, _, _)
|
| Value::DeviceKey(_, _, _)
|
||||||
|
@ -608,6 +622,7 @@ pub fn from_value_iter(mut iter: impl Iterator<Item = Value>) -> Result<ValueSet
|
||||||
Value::JwsKeyRs256(k) => ValueSetJwsKeyRs256::new(k),
|
Value::JwsKeyRs256(k) => ValueSetJwsKeyRs256::new(k),
|
||||||
Value::Session(u, m) => ValueSetSession::new(u, m),
|
Value::Session(u, m) => ValueSetSession::new(u, m),
|
||||||
Value::Oauth2Session(u, m) => ValueSetOauth2Session::new(u, m),
|
Value::Oauth2Session(u, m) => ValueSetOauth2Session::new(u, m),
|
||||||
|
Value::UiHint(u) => ValueSetUiHint::new(u),
|
||||||
Value::PhoneNumber(_, _) | Value::TrustedDeviceEnrollment(_) => {
|
Value::PhoneNumber(_, _) | Value::TrustedDeviceEnrollment(_) => {
|
||||||
debug_assert!(false);
|
debug_assert!(false);
|
||||||
return Err(OperationError::InvalidValueState);
|
return Err(OperationError::InvalidValueState);
|
||||||
|
@ -654,6 +669,7 @@ pub fn from_db_valueset_v2(dbvs: DbValueSetV2) -> Result<ValueSet, OperationErro
|
||||||
DbValueSetV2::Oauth2Session(set) => ValueSetOauth2Session::from_dbvs2(set),
|
DbValueSetV2::Oauth2Session(set) => ValueSetOauth2Session::from_dbvs2(set),
|
||||||
DbValueSetV2::JwsKeyEs256(set) => ValueSetJwsKeyEs256::from_dbvs2(&set),
|
DbValueSetV2::JwsKeyEs256(set) => ValueSetJwsKeyEs256::from_dbvs2(&set),
|
||||||
DbValueSetV2::JwsKeyRs256(set) => ValueSetJwsKeyEs256::from_dbvs2(&set),
|
DbValueSetV2::JwsKeyRs256(set) => ValueSetJwsKeyEs256::from_dbvs2(&set),
|
||||||
|
DbValueSetV2::UiHint(set) => ValueSetUiHint::from_dbvs2(set),
|
||||||
DbValueSetV2::PhoneNumber(_, _) | DbValueSetV2::TrustedDeviceEnrollment(_) => {
|
DbValueSetV2::PhoneNumber(_, _) | DbValueSetV2::TrustedDeviceEnrollment(_) => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ impl ValueSetSyntax {
|
||||||
|
|
||||||
pub fn from_dbvs2(data: Vec<u16>) -> Result<ValueSet, OperationError> {
|
pub fn from_dbvs2(data: Vec<u16>) -> Result<ValueSet, OperationError> {
|
||||||
let set: Result<_, _> = data.into_iter().map(SyntaxType::try_from).collect();
|
let set: Result<_, _> = data.into_iter().map(SyntaxType::try_from).collect();
|
||||||
let set = set.map_err(|()| OperationError::InvalidValueState)?;
|
let set = set.map_err(|_| OperationError::InvalidValueState)?;
|
||||||
Ok(Box::new(ValueSetSyntax { set }))
|
Ok(Box::new(ValueSetSyntax { set }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
126
kanidmd/lib/src/valueset/uihint.rs
Normal file
126
kanidmd/lib/src/valueset/uihint.rs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::schema::SchemaAttribute;
|
||||||
|
use crate::valueset::{DbValueSetV2, ValueSet};
|
||||||
|
|
||||||
|
use kanidm_proto::v1::UiHint;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ValueSetUiHint {
|
||||||
|
set: BTreeSet<UiHint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueSetUiHint {
|
||||||
|
pub fn new(s: UiHint) -> Box<Self> {
|
||||||
|
let mut set = BTreeSet::new();
|
||||||
|
set.insert(s);
|
||||||
|
Box::new(ValueSetUiHint { set })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, s: UiHint) -> bool {
|
||||||
|
self.set.insert(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_dbvs2(data: Vec<u16>) -> Result<ValueSet, OperationError> {
|
||||||
|
let set: Result<_, _> = data.into_iter().map(UiHint::try_from).collect();
|
||||||
|
let set = set.map_err(|_| OperationError::InvalidValueState)?;
|
||||||
|
Ok(Box::new(ValueSetUiHint { set }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueSetT for ValueSetUiHint {
|
||||||
|
fn insert_checked(&mut self, value: Value) -> Result<bool, OperationError> {
|
||||||
|
match value {
|
||||||
|
Value::UiHint(s) => Ok(self.set.insert(s)),
|
||||||
|
_ => Err(OperationError::InvalidValueState),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.set.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&mut self, pv: &PartialValue) -> bool {
|
||||||
|
match pv {
|
||||||
|
PartialValue::UiHint(s) => self.set.remove(s),
|
||||||
|
_ => {
|
||||||
|
debug_assert!(false);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains(&self, pv: &PartialValue) -> bool {
|
||||||
|
match pv {
|
||||||
|
PartialValue::UiHint(s) => self.set.contains(&s),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn substring(&self, _pv: &PartialValue) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lessthan(&self, _pv: &PartialValue) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.set.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_idx_eq_keys(&self) -> Vec<String> {
|
||||||
|
self.set.iter().map(|u| (*u as u16).to_string()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn syntax(&self) -> SyntaxType {
|
||||||
|
SyntaxType::UiHint
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _schema_attr: &SchemaAttribute) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_proto_string_clone_iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
|
||||||
|
Box::new(self.set.iter().map(|u| u.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_db_valueset_v2(&self) -> DbValueSetV2 {
|
||||||
|
DbValueSetV2::UiHint(self.set.iter().map(|u| *u as u16).collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_partialvalue_iter(&self) -> Box<dyn Iterator<Item = PartialValue> + '_> {
|
||||||
|
Box::new(self.set.iter().copied().map(|i| PartialValue::UiHint(i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_value_iter(&self) -> Box<dyn Iterator<Item = Value> + '_> {
|
||||||
|
Box::new(self.set.iter().copied().map(|i| Value::UiHint(i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equal(&self, other: &ValueSet) -> bool {
|
||||||
|
if let Some(other) = other.as_uihint_set() {
|
||||||
|
&self.set == other
|
||||||
|
} else {
|
||||||
|
debug_assert!(false);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge(&mut self, other: &ValueSet) -> Result<(), OperationError> {
|
||||||
|
if let Some(b) = other.as_uihint_set() {
|
||||||
|
mergesets!(self.set, b)
|
||||||
|
} else {
|
||||||
|
debug_assert!(false);
|
||||||
|
Err(OperationError::InvalidValueState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_uihint_set(&self) -> Option<&BTreeSet<UiHint>> {
|
||||||
|
Some(&self.set)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_uihint_iter(&self) -> Option<Box<dyn Iterator<Item = UiHint> + '_>> {
|
||||||
|
Some(Box::new(self.set.iter().copied()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -233,7 +233,7 @@ function addBorrowedObject(obj) {
|
||||||
}
|
}
|
||||||
function __wbg_adapter_48(arg0, arg1, arg2) {
|
function __wbg_adapter_48(arg0, arg1, arg2) {
|
||||||
try {
|
try {
|
||||||
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__ha86bc8783d36be0a(arg0, arg1, addBorrowedObject(arg2));
|
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h2f44da981a3bd620(arg0, arg1, addBorrowedObject(arg2));
|
||||||
} finally {
|
} finally {
|
||||||
heap[stack_pointer++] = undefined;
|
heap[stack_pointer++] = undefined;
|
||||||
}
|
}
|
||||||
|
@ -261,11 +261,11 @@ function makeClosure(arg0, arg1, dtor, f) {
|
||||||
return real;
|
return real;
|
||||||
}
|
}
|
||||||
function __wbg_adapter_51(arg0, arg1, arg2) {
|
function __wbg_adapter_51(arg0, arg1, arg2) {
|
||||||
wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h36bbc8108d49feb4(arg0, arg1, addHeapObject(arg2));
|
wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h10a3687bc3b2a4bb(arg0, arg1, addHeapObject(arg2));
|
||||||
}
|
}
|
||||||
|
|
||||||
function __wbg_adapter_54(arg0, arg1, arg2) {
|
function __wbg_adapter_54(arg0, arg1, arg2) {
|
||||||
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hc4ba360e62a5fa4a(arg0, arg1, addHeapObject(arg2));
|
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h6d8a3152557e4ad6(arg0, arg1, addHeapObject(arg2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -345,25 +345,12 @@ async function load(module, imports) {
|
||||||
function getImports() {
|
function getImports() {
|
||||||
const imports = {};
|
const imports = {};
|
||||||
imports.wbg = {};
|
imports.wbg = {};
|
||||||
imports.wbg.__wbindgen_is_undefined = function(arg0) {
|
|
||||||
const ret = getObject(arg0) === undefined;
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbindgen_in = function(arg0, arg1) {
|
|
||||||
const ret = getObject(arg0) in getObject(arg1);
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
|
imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
|
||||||
const obj = getObject(arg1);
|
const obj = getObject(arg1);
|
||||||
const ret = typeof(obj) === 'number' ? obj : undefined;
|
const ret = typeof(obj) === 'number' ? obj : undefined;
|
||||||
getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret;
|
getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret;
|
||||||
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
|
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_boolean_get = function(arg0) {
|
|
||||||
const v = getObject(arg0);
|
|
||||||
const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
|
imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
|
||||||
const obj = getObject(arg1);
|
const obj = getObject(arg1);
|
||||||
const ret = typeof(obj) === 'string' ? obj : undefined;
|
const ret = typeof(obj) === 'string' ? obj : undefined;
|
||||||
|
@ -372,23 +359,14 @@ function getImports() {
|
||||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_is_bigint = function(arg0) {
|
|
||||||
const ret = typeof(getObject(arg0)) === 'bigint';
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbindgen_is_object = function(arg0) {
|
|
||||||
const val = getObject(arg0);
|
|
||||||
const ret = typeof(val) === 'object' && val !== null;
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbindgen_is_string = function(arg0) {
|
|
||||||
const ret = typeof(getObject(arg0)) === 'string';
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbindgen_bigint_from_i64 = function(arg0) {
|
imports.wbg.__wbindgen_bigint_from_i64 = function(arg0) {
|
||||||
const ret = arg0;
|
const ret = arg0;
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
|
imports.wbg.__wbindgen_jsval_eq = function(arg0, arg1) {
|
||||||
|
const ret = getObject(arg0) === getObject(arg1);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
imports.wbg.__wbindgen_bigint_from_u64 = function(arg0) {
|
imports.wbg.__wbindgen_bigint_from_u64 = function(arg0) {
|
||||||
const ret = BigInt.asUintN(64, arg0);
|
const ret = BigInt.asUintN(64, arg0);
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
|
@ -405,13 +383,35 @@ function getImports() {
|
||||||
const ret = getStringFromWasm0(arg0, arg1);
|
const ret = getStringFromWasm0(arg0, arg1);
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_jsval_eq = function(arg0, arg1) {
|
|
||||||
const ret = getObject(arg0) === getObject(arg1);
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
|
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
|
||||||
takeObject(arg0);
|
takeObject(arg0);
|
||||||
};
|
};
|
||||||
|
imports.wbg.__wbindgen_is_undefined = function(arg0) {
|
||||||
|
const ret = getObject(arg0) === undefined;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_in = function(arg0, arg1) {
|
||||||
|
const ret = getObject(arg0) in getObject(arg1);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_boolean_get = function(arg0) {
|
||||||
|
const v = getObject(arg0);
|
||||||
|
const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_is_bigint = function(arg0) {
|
||||||
|
const ret = typeof(getObject(arg0)) === 'bigint';
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_is_object = function(arg0) {
|
||||||
|
const val = getObject(arg0);
|
||||||
|
const ret = typeof(val) === 'object' && val !== null;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_is_string = function(arg0) {
|
||||||
|
const ret = typeof(getObject(arg0)) === 'string';
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
imports.wbg.__wbindgen_cb_drop = function(arg0) {
|
imports.wbg.__wbindgen_cb_drop = function(arg0) {
|
||||||
const obj = takeObject(arg0).original;
|
const obj = takeObject(arg0).original;
|
||||||
if (obj.cnt-- == 1) {
|
if (obj.cnt-- == 1) {
|
||||||
|
@ -421,7 +421,7 @@ function getImports() {
|
||||||
const ret = false;
|
const ret = false;
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
imports.wbg.__wbg_modalhidebyid_4a1a18ce4b8f3393 = function(arg0, arg1) {
|
imports.wbg.__wbg_modalhidebyid_130cc6453fa7b55b = function(arg0, arg1) {
|
||||||
modal_hide_by_id(getStringFromWasm0(arg0, arg1));
|
modal_hide_by_id(getStringFromWasm0(arg0, arg1));
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_number_new = function(arg0) {
|
imports.wbg.__wbindgen_number_new = function(arg0) {
|
||||||
|
@ -539,6 +539,43 @@ function getImports() {
|
||||||
const ret = getObject(arg0).querySelector(getStringFromWasm0(arg1, arg2));
|
const ret = getObject(arg0).querySelector(getStringFromWasm0(arg1, arg2));
|
||||||
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
||||||
}, arguments) };
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_log_4b5638ad60bdc54a = function(arg0) {
|
||||||
|
console.log(getObject(arg0));
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_value_ccb32485ee1b3928 = function(arg0, arg1) {
|
||||||
|
const ret = getObject(arg1).value;
|
||||||
|
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len0 = WASM_VECTOR_LEN;
|
||||||
|
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||||
|
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_setvalue_df64bc6794c098f2 = function(arg0, arg1, arg2) {
|
||||||
|
getObject(arg0).value = getStringFromWasm0(arg1, arg2);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_new_2d0053ee81e4dd2a = function() { return handleError(function () {
|
||||||
|
const ret = new Headers();
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_get_31b57952dfc2c6cc = function() { return handleError(function (arg0, arg1, arg2, arg3) {
|
||||||
|
const ret = getObject(arg1).get(getStringFromWasm0(arg2, arg3));
|
||||||
|
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
var len0 = WASM_VECTOR_LEN;
|
||||||
|
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||||
|
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_set_992c1d31586b2957 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||||
|
getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_instanceof_HtmlFormElement_1c489ff7e99e43d3 = function(arg0) {
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
result = getObject(arg0) instanceof HTMLFormElement;
|
||||||
|
} catch {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
const ret = result;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
imports.wbg.__wbg_getItem_845e475f85f593e4 = function() { return handleError(function (arg0, arg1, arg2, arg3) {
|
imports.wbg.__wbg_getItem_845e475f85f593e4 = function() { return handleError(function (arg0, arg1, arg2, arg3) {
|
||||||
const ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3));
|
const ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3));
|
||||||
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
@ -552,6 +589,16 @@ function getImports() {
|
||||||
imports.wbg.__wbg_setItem_9c469d634d0c321c = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
imports.wbg.__wbg_setItem_9c469d634d0c321c = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||||
getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
|
getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
|
||||||
}, arguments) };
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_new_ca4d3a3eca340210 = function() { return handleError(function () {
|
||||||
|
const ret = new URLSearchParams();
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_add_89a4f3b0846cf0aa = function() { return handleError(function (arg0, arg1, arg2) {
|
||||||
|
getObject(arg0).add(getStringFromWasm0(arg1, arg2));
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_remove_1a26eb5d822902ed = function() { return handleError(function (arg0, arg1, arg2) {
|
||||||
|
getObject(arg0).remove(getStringFromWasm0(arg1, arg2));
|
||||||
|
}, arguments) };
|
||||||
imports.wbg.__wbg_pathname_78a642e573bf8169 = function(arg0, arg1) {
|
imports.wbg.__wbg_pathname_78a642e573bf8169 = function(arg0, arg1) {
|
||||||
const ret = getObject(arg1).pathname;
|
const ret = getObject(arg1).pathname;
|
||||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
@ -573,69 +620,6 @@ function getImports() {
|
||||||
const ret = new URL(getStringFromWasm0(arg0, arg1));
|
const ret = new URL(getStringFromWasm0(arg0, arg1));
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
}, arguments) };
|
}, arguments) };
|
||||||
imports.wbg.__wbg_new_ca4d3a3eca340210 = function() { return handleError(function () {
|
|
||||||
const ret = new URLSearchParams();
|
|
||||||
return addHeapObject(ret);
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_new_2d0053ee81e4dd2a = function() { return handleError(function () {
|
|
||||||
const ret = new Headers();
|
|
||||||
return addHeapObject(ret);
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_get_31b57952dfc2c6cc = function() { return handleError(function (arg0, arg1, arg2, arg3) {
|
|
||||||
const ret = getObject(arg1).get(getStringFromWasm0(arg2, arg3));
|
|
||||||
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
||||||
var len0 = WASM_VECTOR_LEN;
|
|
||||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
|
||||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_set_992c1d31586b2957 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
|
||||||
getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_value_ccb32485ee1b3928 = function(arg0, arg1) {
|
|
||||||
const ret = getObject(arg1).value;
|
|
||||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
||||||
const len0 = WASM_VECTOR_LEN;
|
|
||||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
|
||||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbg_setvalue_df64bc6794c098f2 = function(arg0, arg1, arg2) {
|
|
||||||
getObject(arg0).value = getStringFromWasm0(arg1, arg2);
|
|
||||||
};
|
|
||||||
imports.wbg.__wbg_url_1c013f0875e97715 = function(arg0, arg1) {
|
|
||||||
const ret = getObject(arg1).url;
|
|
||||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
||||||
const len0 = WASM_VECTOR_LEN;
|
|
||||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
|
||||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbg_headers_85824e993aa739bf = function(arg0) {
|
|
||||||
const ret = getObject(arg0).headers;
|
|
||||||
return addHeapObject(ret);
|
|
||||||
};
|
|
||||||
imports.wbg.__wbg_newwithstr_fdce36db91ec5f92 = function() { return handleError(function (arg0, arg1) {
|
|
||||||
const ret = new Request(getStringFromWasm0(arg0, arg1));
|
|
||||||
return addHeapObject(ret);
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_newwithstrandinit_05d7180788420c40 = function() { return handleError(function (arg0, arg1, arg2) {
|
|
||||||
const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2));
|
|
||||||
return addHeapObject(ret);
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_add_89a4f3b0846cf0aa = function() { return handleError(function (arg0, arg1, arg2) {
|
|
||||||
getObject(arg0).add(getStringFromWasm0(arg1, arg2));
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_remove_1a26eb5d822902ed = function() { return handleError(function (arg0, arg1, arg2) {
|
|
||||||
getObject(arg0).remove(getStringFromWasm0(arg1, arg2));
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_instanceof_HtmlFormElement_1c489ff7e99e43d3 = function(arg0) {
|
|
||||||
let result;
|
|
||||||
try {
|
|
||||||
result = getObject(arg0) instanceof HTMLFormElement;
|
|
||||||
} catch {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
const ret = result;
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbg_instanceof_HtmlInputElement_970e4026de0fccff = function(arg0) {
|
imports.wbg.__wbg_instanceof_HtmlInputElement_970e4026de0fccff = function(arg0) {
|
||||||
let result;
|
let result;
|
||||||
try {
|
try {
|
||||||
|
@ -659,6 +643,40 @@ function getImports() {
|
||||||
imports.wbg.__wbg_setvalue_e5b519cca37d82a7 = function(arg0, arg1, arg2) {
|
imports.wbg.__wbg_setvalue_e5b519cca37d82a7 = function(arg0, arg1, arg2) {
|
||||||
getObject(arg0).value = getStringFromWasm0(arg1, arg2);
|
getObject(arg0).value = getStringFromWasm0(arg1, arg2);
|
||||||
};
|
};
|
||||||
|
imports.wbg.__wbg_create_53c6ddb068a22172 = function() { return handleError(function (arg0, arg1) {
|
||||||
|
const ret = getObject(arg0).create(getObject(arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_get_da97585bbb5a63bb = function() { return handleError(function (arg0, arg1) {
|
||||||
|
const ret = getObject(arg0).get(getObject(arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_href_90ff36b5040e3b76 = function(arg0, arg1) {
|
||||||
|
const ret = getObject(arg1).href;
|
||||||
|
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len0 = WASM_VECTOR_LEN;
|
||||||
|
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||||
|
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_url_1c013f0875e97715 = function(arg0, arg1) {
|
||||||
|
const ret = getObject(arg1).url;
|
||||||
|
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len0 = WASM_VECTOR_LEN;
|
||||||
|
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||||
|
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_headers_85824e993aa739bf = function(arg0) {
|
||||||
|
const ret = getObject(arg0).headers;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_newwithstr_fdce36db91ec5f92 = function() { return handleError(function (arg0, arg1) {
|
||||||
|
const ret = new Request(getStringFromWasm0(arg0, arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_newwithstrandinit_05d7180788420c40 = function() { return handleError(function (arg0, arg1, arg2) {
|
||||||
|
const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
imports.wbg.__wbg_instanceof_Element_33bd126d58f2021b = function(arg0) {
|
imports.wbg.__wbg_instanceof_Element_33bd126d58f2021b = function(arg0) {
|
||||||
let result;
|
let result;
|
||||||
try {
|
try {
|
||||||
|
@ -702,21 +720,6 @@ function getImports() {
|
||||||
imports.wbg.__wbg_focus_adfe4cc61e2c09bc = function() { return handleError(function (arg0) {
|
imports.wbg.__wbg_focus_adfe4cc61e2c09bc = function() { return handleError(function (arg0) {
|
||||||
getObject(arg0).focus();
|
getObject(arg0).focus();
|
||||||
}, arguments) };
|
}, arguments) };
|
||||||
imports.wbg.__wbg_create_53c6ddb068a22172 = function() { return handleError(function (arg0, arg1) {
|
|
||||||
const ret = getObject(arg0).create(getObject(arg1));
|
|
||||||
return addHeapObject(ret);
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_get_da97585bbb5a63bb = function() { return handleError(function (arg0, arg1) {
|
|
||||||
const ret = getObject(arg0).get(getObject(arg1));
|
|
||||||
return addHeapObject(ret);
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_href_90ff36b5040e3b76 = function(arg0, arg1) {
|
|
||||||
const ret = getObject(arg1).href;
|
|
||||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
||||||
const len0 = WASM_VECTOR_LEN;
|
|
||||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
|
||||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbg_credentials_eab5c0bffc3e9cc5 = function(arg0) {
|
imports.wbg.__wbg_credentials_eab5c0bffc3e9cc5 = function(arg0) {
|
||||||
const ret = getObject(arg0).credentials;
|
const ret = getObject(arg0).credentials;
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
|
@ -746,12 +749,6 @@ function getImports() {
|
||||||
imports.wbg.__wbg_preventDefault_3209279b490de583 = function(arg0) {
|
imports.wbg.__wbg_preventDefault_3209279b490de583 = function(arg0) {
|
||||||
getObject(arg0).preventDefault();
|
getObject(arg0).preventDefault();
|
||||||
};
|
};
|
||||||
imports.wbg.__wbg_addEventListener_1fc744729ac6dc27 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
|
||||||
getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4));
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_removeEventListener_b10f1a66647f3aa0 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
|
||||||
getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), arg4 !== 0);
|
|
||||||
}, arguments) };
|
|
||||||
imports.wbg.__wbg_newwithform_6b545e9ddaccc455 = function() { return handleError(function (arg0) {
|
imports.wbg.__wbg_newwithform_6b545e9ddaccc455 = function() { return handleError(function (arg0) {
|
||||||
const ret = new FormData(getObject(arg0));
|
const ret = new FormData(getObject(arg0));
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
|
@ -760,6 +757,12 @@ function getImports() {
|
||||||
const ret = getObject(arg0).get(getStringFromWasm0(arg1, arg2));
|
const ret = getObject(arg0).get(getStringFromWasm0(arg1, arg2));
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
|
imports.wbg.__wbg_addEventListener_1fc744729ac6dc27 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||||
|
getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4));
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_removeEventListener_b10f1a66647f3aa0 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||||
|
getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), arg4 !== 0);
|
||||||
|
}, arguments) };
|
||||||
imports.wbg.__wbg_parentElement_0cffb3ceb0f107bd = function(arg0) {
|
imports.wbg.__wbg_parentElement_0cffb3ceb0f107bd = function(arg0) {
|
||||||
const ret = getObject(arg0).parentElement;
|
const ret = getObject(arg0).parentElement;
|
||||||
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
||||||
|
@ -1037,16 +1040,16 @@ function getImports() {
|
||||||
const ret = wasm.memory;
|
const ret = wasm.memory;
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_closure_wrapper5651 = function(arg0, arg1, arg2) {
|
imports.wbg.__wbindgen_closure_wrapper4757 = function(arg0, arg1, arg2) {
|
||||||
const ret = makeMutClosure(arg0, arg1, 1343, __wbg_adapter_48);
|
const ret = makeMutClosure(arg0, arg1, 1013, __wbg_adapter_48);
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_closure_wrapper5814 = function(arg0, arg1, arg2) {
|
imports.wbg.__wbindgen_closure_wrapper4941 = function(arg0, arg1, arg2) {
|
||||||
const ret = makeClosure(arg0, arg1, 1378, __wbg_adapter_51);
|
const ret = makeClosure(arg0, arg1, 1037, __wbg_adapter_51);
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_closure_wrapper6542 = function(arg0, arg1, arg2) {
|
imports.wbg.__wbindgen_closure_wrapper5597 = function(arg0, arg1, arg2) {
|
||||||
const ret = makeMutClosure(arg0, arg1, 1635, __wbg_adapter_54);
|
const ret = makeMutClosure(arg0, arg1, 1287, __wbg_adapter_54);
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -5,7 +5,7 @@
|
||||||
"James Hodgkinson <james@terminaloutcomes.com>"
|
"James Hodgkinson <james@terminaloutcomes.com>"
|
||||||
],
|
],
|
||||||
"description": "Kanidm Server Web User Interface",
|
"description": "Kanidm Server Web User Interface",
|
||||||
"version": "1.1.0-alpha.10",
|
"version": "1.1.0-alpha.11-dev",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use gloo::console;
|
use gloo::console;
|
||||||
use kanidm_proto::v1::UserAuthToken;
|
use kanidm_proto::v1::{UserAuthToken, UiHint};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
@ -236,6 +236,8 @@ impl ViewsApp {
|
||||||
fn view_authenticated(&self, ctx: &Context<Self>, uat: &UserAuthToken) -> Html {
|
fn view_authenticated(&self, ctx: &Context<Self>, uat: &UserAuthToken) -> Html {
|
||||||
let current_user_uat = uat.clone();
|
let current_user_uat = uat.clone();
|
||||||
|
|
||||||
|
let ui_hint_experimental = uat.ui_hints.contains(&UiHint::ExperimentalFeatures);
|
||||||
|
|
||||||
// WARN set dash-body against body here?
|
// WARN set dash-body against body here?
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
|
@ -247,41 +249,48 @@ impl ViewsApp {
|
||||||
<button class="navbar-toggler bg-light" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
<button class="navbar-toggler bg-light" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<img src="/pkg/img/favicon.png" />
|
<img src="/pkg/img/favicon.png" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-md-0">
|
<ul class="navbar-nav me-auto mb-2 mb-md-0">
|
||||||
<li class="mb-1">
|
|
||||||
<Link<ViewRoute> classes="nav-link" to={ViewRoute::Apps}>
|
|
||||||
<span data-feather="file"></span>
|
|
||||||
{ "Apps" }
|
|
||||||
</Link<ViewRoute>>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="mb-1">
|
<li class="mb-1">
|
||||||
<Link<ViewRoute> classes="nav-link" to={ViewRoute::Profile}>
|
<Link<ViewRoute> classes="nav-link" to={ViewRoute::Apps}>
|
||||||
<span data-feather="file"></span>
|
<span data-feather="file"></span>
|
||||||
{ "Profile" }
|
{ "Apps" }
|
||||||
</Link<ViewRoute>>
|
</Link<ViewRoute>>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="mb-1">
|
if ui_hint_experimental {
|
||||||
<Link<ViewRoute> classes="nav-link" to={ViewRoute::Security}>
|
<li class="mb-1">
|
||||||
<span data-feather="file"></span>
|
<Link<ViewRoute> classes="nav-link" to={ViewRoute::Profile}>
|
||||||
{ "Security" }
|
<span data-feather="file"></span>
|
||||||
</Link<ViewRoute>>
|
{ "Profile" }
|
||||||
</li>
|
</Link<ViewRoute>>
|
||||||
// TODO: the admin link should only show up if you're an admin
|
</li>
|
||||||
<li class="mb-1">
|
}
|
||||||
<Link<AdminRoute> classes="nav-link" to={AdminRoute::AdminMenu}>
|
|
||||||
<span data-feather="file"></span>
|
<li class="mb-1">
|
||||||
{ "Admin" }
|
<Link<ViewRoute> classes="nav-link" to={ViewRoute::Security}>
|
||||||
</Link<AdminRoute>>
|
<span data-feather="file"></span>
|
||||||
</li>
|
{ "Security" }
|
||||||
<li class="mb-1">
|
</Link<ViewRoute>>
|
||||||
<a class="nav-link" href="#"
|
</li>
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target={format!("#{}", crate::constants::ID_SIGNOUTMODAL)}
|
if ui_hint_experimental {
|
||||||
>{"Sign out"}</a>
|
<li class="mb-1">
|
||||||
</li>
|
<Link<AdminRoute> classes="nav-link" to={AdminRoute::AdminMenu}>
|
||||||
|
<span data-feather="file"></span>
|
||||||
|
{ "Admin" }
|
||||||
|
</Link<AdminRoute>>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
|
||||||
|
<li class="mb-1">
|
||||||
|
<a class="nav-link" href="#"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target={format!("#{}", crate::constants::ID_SIGNOUTMODAL)}
|
||||||
|
>{"Sign out"}</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<form class="d-flex">
|
<form class="d-flex">
|
||||||
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" />
|
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" />
|
||||||
|
|
Loading…
Reference in a new issue