Started chasing noise, found some code to delete... (#1768)

logging changes:

* Offering auth mechanisms -> debug
* 404's aren't really warnings
* double tombstone message, one goes to debug

other changes:

* CSP changes to allow the bootstrap images to load
* more testing javascriptfile things, I R 
* it's nice to know where things are
* putting non-rust web things in static/ instead of src/
* RequestCredentials::SameOrigin is the default, also adding a utility function to save dupe code. Wow this saved... kilobytes.
* removing commented code, fixing up codespell config
* clippyisms
* wtf, gha
* dee-gloo-ing some things
* adding some ubuntu build test things
* sigh rustwasm/wasm-pack/issues/1138
* more do_request things
* packaging things
* hilarious dev env setup script
* updated script works, all the UI works, including the experimental UI for naughty crabs
* deb package fixes
* fixed some notes
* setup experimental UI tweaks
This commit is contained in:
James Hodgkinson 2023-06-27 11:38:22 +10:00 committed by GitHub
parent 23eb4283e9
commit cc1cc691f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
81 changed files with 891 additions and 974 deletions

View file

@ -1,5 +1,5 @@
--- ---
name: "Build Debian Packages" name: "Build Deb Packages"
"on": "on":
push: push:
@ -31,25 +31,33 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Install dependencies - name: install curl
run: | run: |
apt-get update && \ apt-get update && apt-get install -y curl
apt-get install -y \
lsb-release \
libpam0g-dev \
libudev-dev \
libssl-dev \
libsqlite3-dev \
pkg-config \
make \
curl \
sudo
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Setup sccache - name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.3 uses: mozilla-actions/sccache-action@v0.0.3
with: with:
version: "v0.4.2" version: "v0.4.2"
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install dependencies
run: |
scripts/install_ubuntu_dependencies.sh
# apt-get update && \
# apt-get install -y \
# lsb-release \
# libpam0g-dev \
# libudev-dev \
# libssl-dev \
# libsqlite3-dev \
# pkg-config \
# make \
# curl \
# sudo \
# build-essential \
# rsync
- name: Install wasm-pack
run: cargo install wasm-pack
- name: Build packages - name: Build packages
run: | run: |
make -f platform/debian/Makefile debs/all make -f platform/debian/Makefile debs/all

View file

@ -16,21 +16,20 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install dependencies # - name: Check arch
run: | # run: |
sudo apt-get update && # uname -a
sudo apt-get install -y \
libpam0g-dev \
libudev-dev \
libssl-dev \
libsqlite3-dev \
pkg-config
- name: Setup sccache - name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.3 uses: mozilla-actions/sccache-action@v0.0.3
with: with:
version: "v0.4.2" version: "v0.4.2"
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install wasm-pack - name: Install wasm-pack
run: cargo install wasm-pack run: cargo install wasm-pack
- name: Install dependencies
run: |
scripts/install_ubuntu_dependencies.sh
# https://github.com/browser-actions/setup-chrome # https://github.com/browser-actions/setup-chrome
- name: Install Chrome Headless - name: Install Chrome Headless
uses: browser-actions/setup-chrome@latest uses: browser-actions/setup-chrome@latest
@ -45,5 +44,6 @@ jobs:
# docs here: # docs here:
# https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/browsers.html # https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/browsers.html
- run: make webui - run: make webui
- run: wasm-pack test --headless --chrome - name: "Run wasm-pack test"
run: make webui/test
continue-on-error: true continue-on-error: true

14
Cargo.lock generated
View file

@ -1215,6 +1215,7 @@ dependencies = [
"clap", "clap",
"clap_complete", "clap_complete",
"fs2", "fs2",
"is-terminal",
"kanidm_lib_file_permissions", "kanidm_lib_file_permissions",
"kanidm_proto", "kanidm_proto",
"kanidmd_core", "kanidmd_core",
@ -2383,6 +2384,18 @@ version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
[[package]]
name = "is-terminal"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
dependencies = [
"hermit-abi 0.3.1",
"io-lifetimes",
"rustix",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@ -2718,7 +2731,6 @@ version = "1.1.0-beta.13"
dependencies = [ dependencies = [
"compact_jwt", "compact_jwt",
"gloo", "gloo",
"gloo-net",
"js-sys", "js-sys",
"kanidm_proto", "kanidm_proto",
"qrcode", "qrcode",

View file

@ -122,7 +122,7 @@ codespell:
--skip='./book/book/*' \ --skip='./book/book/*' \
--skip='./docs/*,./.git' \ --skip='./docs/*,./.git' \
--skip='./rlm_python/mods-available/eap' \ --skip='./rlm_python/mods-available/eap' \
--skip='./server/web_ui/src/external,./server/web_ui/pkg/external' \ --skip='./server/web_ui/static/external,./server/web_ui/pkg/external' \
--skip='./server/lib/src/constants/system_config.rs,./pykanidm/site,./server/lib/src/constants/*.json' --skip='./server/lib/src/constants/system_config.rs,./pykanidm/site,./server/lib/src/constants/*.json'
.PHONY: test/pykanidm/pytest .PHONY: test/pykanidm/pytest
@ -255,3 +255,7 @@ cert/clean:
.PHONY: webui .PHONY: webui
webui: ## Build the WASM web frontend webui: ## Build the WASM web frontend
cd server/web_ui && ./build_wasm_release.sh cd server/web_ui && ./build_wasm_release.sh
.PHONY: webui/test
webui/test: ## Run wasm-pack test
cd server/web_ui && wasm-pack test --headless --chrome

View file

@ -19,6 +19,8 @@ git and compiler tools. You should install this first.
You will need [rustup](https://rustup.rs/) to install a Rust toolchain. You will need [rustup](https://rustup.rs/) to install a Rust toolchain.
To build the Web UI you'll need [wasm-pack](https://rustwasm.github.io/wasm-pack/) (`cargo install wasm-pack`).
#### SUSE / OpenSUSE #### SUSE / OpenSUSE
You will need to install rustup and our build dependencies with: You will need to install rustup and our build dependencies with:

View file

@ -128,8 +128,8 @@ alias kanidm="docker run ..."
## Initializing the configuration ## Initializing the configuration
The client requires a configuration file to connect to the server. The client requires a configuration file to connect to the server. This should be at
This should be at `/etc/kanidm/config` or `~/.config/kanidm`, and configures the kanidm command line tool. `/etc/kanidm/config` or `~/.config/kanidm`, and configures the kanidm command line tool.
Here is a minimal example: Here is a minimal example:

View file

@ -1,5 +1,4 @@
# This should be at /etc/kanidm/config or ~/.config/kanidm, and configures the kanidm command line tool # This should be at /etc/kanidm/config or ~/.config/kanidm, and configures the kanidm command line tool
# to point at the local dev server and ignore TLS security. # to point at the local dev server and trust the CA security.
uri = "https://localhost:8443" uri="https://localhost:8443"
verify_ca = false verify_ca="/tmp/kanidm/ca.pem"
verify_hostnames = false

View file

@ -11,8 +11,8 @@ tls_key = "/tmp/kanidm/key.pem"
# NOTE: this is overridden by environment variables at runtime # NOTE: this is overridden by environment variables at runtime
# Defaults to "info" # Defaults to "info"
# #
log_level = "info" # log_level = "info"
# log_level = "debug" log_level = "debug"
# log_level = "trace" # log_level = "trace"
domain = "localhost" domain = "localhost"

View file

@ -3,23 +3,23 @@ name = "kanidm_client"
description = "Kanidm Client Library" description = "Kanidm Client Library"
documentation = "https://docs.rs/kanidm_client/latest/kanidm_client/" documentation = "https://docs.rs/kanidm_client/latest/kanidm_client/"
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[dependencies] [dependencies]
tracing.workspace = true tracing = { workspace = true }
reqwest = { workspace = true, default-features = false } reqwest = { workspace = true, default-features = false }
kanidm_proto.workspace = true kanidm_proto = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true serde_json = { workspace = true }
time = { workspace = true, features = ["serde", "std"] } time = { workspace = true, features = ["serde", "std"] }
tokio = { workspace = true, features = ["rt", "net", "time", "macros", "sync", "signal"] } tokio = { workspace = true, features = ["rt", "net", "time", "macros", "sync", "signal"] }
toml.workspace = true toml = { workspace = true }
uuid = { workspace = true, features = ["serde", "v4"] } uuid = { workspace = true, features = ["serde", "v4"] }
url = { workspace = true, features = ["serde"] } url = { workspace = true, features = ["serde"] }
webauthn-rs-proto = { workspace = true, features = ["wasm"] } webauthn-rs-proto = { workspace = true, features = ["wasm"] }

View file

@ -7,20 +7,20 @@ edition = "2021"
tpm = ["dep:tss-esapi"] tpm = ["dep:tss-esapi"]
[dependencies] [dependencies]
argon2.workspace = true argon2 = { workspace = true }
base64.workspace = true base64 = { workspace = true }
base64urlsafedata.workspace = true base64urlsafedata = { workspace = true }
hex.workspace = true hex = { workspace = true }
kanidm_proto.workspace = true kanidm_proto = { workspace = true }
# We need to explicitly ask for openssl-sys so that we get the version propagated # We need to explicitly ask for openssl-sys so that we get the version propagated
# into the build.rs for legacy feature checks. # into the build.rs for legacy feature checks.
openssl-sys.workspace = true openssl-sys = { workspace = true }
openssl.workspace = true openssl = { workspace = true }
rand.workspace = true rand = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
tracing.workspace = true tracing = { workspace = true }
tss-esapi = { workspace = true, optional = true } tss-esapi = { workspace = true, optional = true }
[dev-dependencies] [dev-dependencies]
sketching.workspace = true sketching = { workspace = true }

View file

@ -5,13 +5,13 @@ documentation = "https://docs.rs/kanidm/latest/kanidm/"
# We do not have tests in this pkg # We do not have tests in this pkg
autotests = false autotests = false
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[lib] [lib]
name = "profiles" name = "profiles"
@ -19,8 +19,8 @@ path = "src/lib.rs"
[dependencies] [dependencies]
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
toml.workspace = true toml = { workspace = true }
base64.workspace = true base64 = { workspace = true }
[build-dependencies] [build-dependencies]
base64.workspace = true base64 = { workspace = true }

View file

@ -3,18 +3,18 @@ name = "sketching"
# We do not have tests in this pkg # We do not have tests in this pkg
autotests = false autotests = false
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[dependencies] [dependencies]
async-trait.workspace = true async-trait = { workspace = true }
num_enum.workspace = true num_enum = { workspace = true }
tide.workspace = true tide = { workspace = true }
tracing = { workspace = true, features = ["attributes"] } tracing = { workspace = true, features = ["attributes"] }
tracing-subscriber = { workspace = true, features = ["env-filter"] } tracing-subscriber = { workspace = true, features = ["env-filter"] }
tracing-forest = { workspace = true, features = ["uuid", "smallvec", "tokio", "env-filter"] } tracing-forest = { workspace = true, features = ["uuid", "smallvec", "tokio", "env-filter"] }

View file

@ -76,6 +76,12 @@ impl TreeMiddleware {
status = format_args!("{} - {}", status as u16, status.canonical_reason()), status = format_args!("{} - {}", status as u16, status.canonical_reason()),
"Client error --> Response sent" "Client error --> Response sent"
); );
} else if status == 404 {
// because not-found isn't really an error, is it?
request_info!(
status = format_args!("{} - {}", status as u16, status.canonical_reason()),
"--> Response sent"
);
} else { } else {
request_warn!( request_warn!(
status = format_args!("{} - {}", status as u16, status.canonical_reason()), status = format_args!("{} - {}", status as u16, status.canonical_reason()),

View file

@ -3,31 +3,31 @@ name = "kanidm_proto"
description = "Kanidm Protocol Bindings for serde" description = "Kanidm Protocol Bindings for serde"
documentation = "https://docs.rs/kanidm_proto/latest/kanidm_proto/" documentation = "https://docs.rs/kanidm_proto/latest/kanidm_proto/"
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[features] [features]
wasm = ["webauthn-rs-proto/wasm"] wasm = ["webauthn-rs-proto/wasm"]
[dependencies] [dependencies]
base32.workspace = true base32 = { workspace = true }
base64urlsafedata.workspace = true base64urlsafedata = { workspace = true }
num_enum.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 }
time = { workspace = true, features = ["serde", "std"] } time = { workspace = true, features = ["serde", "std"] }
tracing.workspace = true tracing = { workspace = true }
url = { workspace = true, features = ["serde"] } url = { workspace = true, features = ["serde"] }
urlencoding.workspace = true urlencoding = { workspace = true }
uuid = { workspace = true, features = ["serde"] } uuid = { workspace = true, features = ["serde"] }
webauthn-rs-proto.workspace = true webauthn-rs-proto = { workspace = true }
[target.'cfg(not(target_family = "wasm"))'.dependencies] [target.'cfg(not(target_family = "wasm"))'.dependencies]
last-git-commit.workspace = true last-git-commit = { workspace = true }

View file

@ -1099,7 +1099,7 @@ pub struct CUSessionToken {
pub token: String, pub token: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum CURequest { pub enum CURequest {
PrimaryRemove, PrimaryRemove,

View file

@ -0,0 +1,19 @@
#!/bin/bash
set -e
ERROR=0
if [ -z "$(which cargo)" ]; then
echo "You don't have cargo / rust installed!"
echo "Go to <https://www.rust-lang.org/tools/install> for instructions!"
ERROR=1
fi
if [ -z "$(which wasm-pack)" ]; then
echo "You don't have wasm-pack installed! Installing it now..."
cargo install wasm-pack
fi
if [ $ERROR -eq 1 ]; then
exit 1
fi

View file

@ -0,0 +1,60 @@
#!/bin/bash
set -e
if [ "$(whoami)" == "root" ]; then
SUDOCMD=""
else
SUDOCMD="sudo "
fi
${SUDOCMD} apt-get update &&
${SUDOCMD} apt-get install -y \
libpam0g-dev \
libudev-dev \
libssl-dev \
libsqlite3-dev \
pkg-config \
curl \
rsync \
build-essential
if [ -z "$(which cargo)" ]; then
if [ -f "$HOME/.cargo/env" ]; then
#shellcheck disable=SC1091
source "$HOME/.cargo/env"
elif [ "${INSTALL_RUST}" == "1" ]; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
#shellcheck disable=SC1091
source "$HOME/.cargo/env"
fi
fi
ERROR=0
if [ -z "$(which cargo)" ]; then
echo "You don't have cargo / rust installed!"
echo "Go to <https://www.rust-lang.org/tools/install> for instructions!"
echo ""
echo "Or run this script with INSTALL_RUST=1 to install it for you."
ERROR=1
fi
if [ $ERROR -eq 0 ] && [ -z "$(which wasm-pack)" ]; then
echo "You don't have wasm-pack installed! Installing it now..."
cargo install wasm-pack
fi
if [ $ERROR -eq 0 ] && [ -z "$(which wasm-bindgen)" ]; then
echo "You don't have wasm-bindgen installed! Installing it now..."
cargo install -f wasm-bindgen-cli
fi
if [ $ERROR -eq 1 ]; then
exit 1
fi
echo "Woo, all ready to go!"
#shellcheck disable=SC2016
echo 'You might need to load the env: source "$HOME/.cargo/env"'

125
scripts/setup_dev_environment.sh Executable file
View file

@ -0,0 +1,125 @@
#!/bin/bash
# run this, it'll set up a bunch of default stuff
# - reset the admin and idm_admin users
# - set up a test user
# - set up a test group
# - set up a test oauth2 rp (https://kanidm.com)
# - prompt to reset testuser's creds online
set -e
# if they passed --help then output the help
if [ "${1}" == "--help" ]; then
echo "Usage: $0 [--remove-db]"
echo " --remove-db: remove the existing DB before running"
exit 0
fi
# if --remove-db is in the command line args then remove the DB
if [ -z "${REMOVE_TEST_DB}" ]; then
if [ "${1}" == "--remove-db" ]; then
REMOVE_TEST_DB=1
else
REMOVE_TEST_DB=0
fi
fi
if [ ! -f run_insecure_dev_server.sh ]; then
echo "Please run from the server/daemon dir!"
exit 1
fi
# wait for them to shut down the server if it's running...
while true
do
if [ "$(pgrep kanidmd | wc -l )" -eq 0 ]; then
break
fi
echo "Stop the kanidmd server first please!"
sleep 1
done
# defaults
KANIDM_CONFIG="../../examples/insecure_server.toml"
KANIDM_URL="$(rg origin "${KANIDM_CONFIG}" | awk '{print $NF}' | tr -d '"')"
KANIDM_CA_PATH="/tmp/kanidm/ca.pem"
# needed for the CLI tools to do their thing
export KANIDM_URL
export KANIDM_CA_PATH
export KANIDM_CONFIG
# string things
TEST_USER_NAME="testuser"
TEST_USER_DISPLAY="Test Crab"
TEST_GROUP="test_users"
OAUTH2_RP_ID="test_oauth2"
OAUTH2_RP_DISPLAY="test_oauth2"
# commands to run things
KANIDM="cargo run --manifest-path ../../Cargo.toml --bin kanidm -- "
KANIDMD="cargo run -p daemon --bin kanidmd -- "
if [ "${REMOVE_TEST_DB}" -eq 1 ]; then
echo "Removing the existing DB!"
rm /tmp/kanidm/kanidm.db || true
fi
echo "Reset the admin user"
ADMIN_PASS=$(${KANIDMD} recover-account admin -o json 2>&1 | rg recovery | rg result | jq -r .result )
echo "admin pass: '${ADMIN_PASS}'"
echo "Reset the idm_admin user"
IDM_ADMIN_PASS=$(${KANIDMD} recover-account idm_admin -o json 2>&1 | rg recovery | rg result | jq -r .result)
echo "idm_admin pass: '${IDM_ADMIN_PASS}'"
while true
do
echo "Waiting for you to start the server... testing ${KANIDM_URL}"
curl --cacert "${KANIDM_CA_PATH}" -fs "${KANIDM_URL}" > /dev/null && break
sleep 2
done
echo "login with admin"
${KANIDM} login -D admin --password "${ADMIN_PASS}"
echo "login with idm_admin"
${KANIDM} login -D idm_admin --password "${IDM_ADMIN_PASS}"
# create group test_users
${KANIDM} group create "${TEST_GROUP}" -D idm_admin
# create testuser (person)
${KANIDM} person create "${TEST_USER_NAME}" "${TEST_USER_DISPLAY}" -D idm_admin
echo "Adding ${TEST_USER_NAME} to ${TEST_GROUP}"
${KANIDM} group add-members "${TEST_GROUP}" "${TEST_USER_NAME}" -D idm_admin
echo "Enable experimental UI for admin idm_admin ${TEST_USER_NAME}"
${KANIDM} group add-members idm_ui_enable_experimental_features admin idm_admin "${TEST_USER_NAME}"
# create oauth2 rp
echo "Creating the OAuth2 RP"
${KANIDM} system oauth2 create "${OAUTH2_RP_ID}" "${OAUTH2_RP_DISPLAY}" "https://kanidm.com" -D admin
echo "Creating the OAuth2 RP Scope Map"
${KANIDM} system oauth2 update-scope-map "${OAUTH2_RP_ID}" "${TEST_GROUP}" openid -D admin
echo "Creating the OAuth2 RP Supplemental Scope Map"
${KANIDM} system oauth2 update-sup-scope-map "${OAUTH2_RP_ID}" "${TEST_GROUP}" admin -D admin
echo "Creating the OAuth2 RP Secondary Supplemental Crab-baite Scope Map.... wait, no that's not a thing."
# config auth2
echo "Pulling secret for the OAuth2 RP"
${KANIDM} system oauth2 show-basic-secret -o json "${OAUTH2_RP_ID}" -D admin
echo "Creating cred reset link for ${TEST_USER_NAME}"
${KANIDM} person credential create-reset-token "${TEST_USER_NAME}" -D idm_admin
echo "Done!"
echo "###################################"
echo "admin password: ${ADMIN_PASS}"
echo "idm_admin password: ${IDM_ADMIN_PASS}"
echo "UI URL: ${KANIDM_URL}"
echo "###################################"

View file

@ -38,7 +38,7 @@ tokio-openssl = { workspace = true }
tokio-util = { workspace = true, features = ["codec"] } tokio-util = { workspace = true, features = ["codec"] }
toml = {workspace = true} toml = {workspace = true}
tracing = { workspace = true, features = ["attributes"] } tracing = { workspace = true, features = ["attributes"] }
urlencoding.workspace = true urlencoding = { workspace = true }
uuid = { workspace = true, features = ["serde", "v4" ] } uuid = { workspace = true, features = ["serde", "v4" ] }
[build-dependencies] [build-dependencies]

View file

@ -77,7 +77,7 @@ impl ServerConfig {
} }
} }
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default)] #[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq)]
pub enum ServerRole { pub enum ServerRole {
#[default] #[default]
WriteReplica, WriteReplica,

View file

@ -200,6 +200,8 @@ impl<State: Clone + Send + Sync + 'static> tide::Middleware<State>
"base-uri 'self'", "base-uri 'self'",
// nobody wants to be in a frame // nobody wants to be in a frame
"frame-ancestors 'none'", "frame-ancestors 'none'",
// allow inline images because bootstrap
"img-src 'self' data:",
] ]
.join(";"), .join(";"),
); );

View file

@ -52,16 +52,42 @@ impl JavaScriptFile {
/// returns a `<script>` HTML tag /// returns a `<script>` HTML tag
fn as_tag(self) -> String { fn as_tag(self) -> String {
let typeattr = match self.filetype { let typeattr = match self.filetype {
Some(val) => format!("type=\"{}\" ", val), Some(val) => {
format!(" type=\"{}\"", val.as_str())
}
_ => String::from(""), _ => String::from(""),
}; };
format!( format!(
r#"<script src="/pkg/{}" integrity="{}" {}></script>"#, r#"<script src="/pkg/{}" integrity="{}"{}></script>"#,
self.filepath, self.hash, typeattr, self.filepath, &self.hash, &typeattr,
) )
} }
} }
#[test]
fn test_javscriptfile() {
// make sure it outputs what we think it does
use JavaScriptFile;
let jsf = JavaScriptFile {
filepath: "wasmloader.js",
hash: "sha384-1234567890".to_string(),
filetype: Some("module".to_string()),
};
assert_eq!(
jsf.as_tag(),
r#"<script src="/pkg/wasmloader.js" integrity="sha384-1234567890" type="module"></script>"#
);
let jsf = JavaScriptFile {
filepath: "wasmloader.js",
hash: "sha384-1234567890".to_string(),
filetype: None,
};
assert_eq!(
jsf.as_tag(),
r#"<script src="/pkg/wasmloader.js" integrity="sha384-1234567890"></script>"#
);
}
#[derive(Clone)] #[derive(Clone)]
pub struct AppState { pub struct AppState {
pub status_ref: &'static StatusActor, pub status_ref: &'static StatusActor,
@ -352,8 +378,7 @@ pub fn generate_integrity_hash(filename: String) -> Result<String, String> {
pub async fn create_https_server( pub async fn create_https_server(
address: String, address: String,
domain: String, domain: &String,
// opt_tls_params: Option<SslAcceptorBuilder>,
opt_tls_params: Option<&TlsConfiguration>, opt_tls_params: Option<&TlsConfiguration>,
role: ServerRole, role: ServerRole,
trust_x_forward_for: bool, trust_x_forward_for: bool,

View file

@ -51,7 +51,7 @@ use tokio::sync::broadcast;
use crate::actors::v1_read::QueryServerReadV1; use crate::actors::v1_read::QueryServerReadV1;
use crate::actors::v1_write::QueryServerWriteV1; use crate::actors::v1_write::QueryServerWriteV1;
use crate::config::Configuration; use crate::config::{Configuration, ServerRole};
use crate::interval::IntervalActor; use crate::interval::IntervalActor;
// === internal setup helpers // === internal setup helpers
@ -914,7 +914,7 @@ pub async fn create_server_core(
// ⚠️ only start the sockets and listeners in non-config-test modes. // ⚠️ only start the sockets and listeners in non-config-test modes.
let h = self::https::create_https_server( let h = self::https::create_https_server(
config.address, config.address,
config.domain, &config.domain,
config.tls_config.as_ref(), config.tls_config.as_ref(),
config.role, config.role,
config.trust_x_forward_for, config.trust_x_forward_for,
@ -927,7 +927,11 @@ pub async fn create_server_core(
) )
.await?; .await?;
admin_info!("ready to rock! 🪨 "); if config.role != ServerRole::WriteReplicaNoUI {
admin_info!("ready to rock! 🪨 UI available at: {}", config.origin);
} else {
admin_info!("ready to rock! 🪨");
}
Some(h) Some(h)
}; };

View file

@ -3,13 +3,13 @@ name = "daemon"
description = "Kanidm Server Daemon" description = "Kanidm Server Daemon"
documentation = "https://docs.rs/kanidm/latest/kanidm/" documentation = "https://docs.rs/kanidm/latest/kanidm/"
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -18,27 +18,28 @@ name = "kanidmd"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
kanidm_proto.workspace = true kanidm_proto = { workspace = true }
kanidmd_core.workspace = true kanidmd_core = { workspace = true }
kanidm_lib_file_permissions.workspace = true kanidm_lib_file_permissions = { workspace = true }
sketching.workspace = true sketching = { workspace = true }
fs2.workspace = true fs2 = { workspace = true }
clap = { workspace = true, features = ["env"] } clap = { workspace = true, features = ["env"] }
reqwest = { workspace = true } reqwest = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "signal"] } tokio = { workspace = true, features = ["rt-multi-thread", "macros", "signal"] }
toml = { workspace = true } toml = { workspace = true }
is-terminal = "0.4.7"
[target.'cfg(target_family = "windows")'.dependencies] [target.'cfg(target_family = "windows")'.dependencies]
whoami.workspace = true whoami = { workspace = true }
[target.'cfg(not(target_family = "windows"))'.dependencies] [target.'cfg(not(target_family = "windows"))'.dependencies]
users.workspace = true users = { workspace = true }
tikv-jemallocator.workspace = true tikv-jemallocator = { workspace = true }
[build-dependencies] [build-dependencies]
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
clap = { workspace = true, features = ["derive"] } clap = { workspace = true, features = ["derive"] }
clap_complete.workspace = true clap_complete = { workspace = true }
profiles.workspace = true profiles = { workspace = true }

View file

@ -126,7 +126,7 @@ async fn main() -> ExitCode {
}; };
// if they specified it in the environment then that overrides everything // if they specified it in the environment then that overrides everything
let log_level = match EnvFilter::try_from_default_env() { let log_filter = match EnvFilter::try_from_default_env() {
Ok(val) => val, Ok(val) => val,
Err(_e) => { Err(_e) => {
// we couldn't get it from the env, so we'll try the config file! // we couldn't get it from the env, so we'll try the config file!
@ -140,14 +140,25 @@ async fn main() -> ExitCode {
.into() .into()
} }
}; };
// TODO: only send to stderr when we're not in a TTY
tracing_forest::worker_task() tracing_forest::worker_task()
.set_global(true) .set_global(true)
.set_tag(sketching::event_tagger) .set_tag(sketching::event_tagger)
// Fall back to stderr // Fall back to stderr
.map_sender(|sender| sender.or_stderr()) .map_sender(|sender| sender.or_stderr())
.build_on(|subscriber| subscriber .build_on(|subscriber|{
.with(log_level) let sub = subscriber.with(log_filter);
) // this does NOT work, it just adds a layer.
// if std::io::stdout().is_terminal() {
// println!("Stdout is a terminal");
// sub.with(sketching::tracing_subscriber::fmt::layer().with_writer(std::io::stderr))
// } else {
// println!("Stdout is not a terminal");
// sub.with(sketching::tracing_subscriber::fmt::layer().with_writer(std::io::stderr))
// }
sub
})
.on(async { .on(async {
// Get information on the windows username // Get information on the windows username
#[cfg(target_family = "windows")] #[cfg(target_family = "windows")]

View file

@ -7,7 +7,7 @@ edition = "2021"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
proc-macro2.workspace = true proc-macro2 = { workspace = true }
quote.workspace = true quote = { workspace = true }
syn.workspace = true syn = { workspace = true }

View file

@ -3,13 +3,13 @@ name = "kanidmd_lib"
description = "Kanidm Server Backend Library" description = "Kanidm Server Backend Library"
documentation = "https://docs.rs/kanidm/latest/kanidm/" documentation = "https://docs.rs/kanidm/latest/kanidm/"
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[lib] [lib]
name = "kanidmd_lib" name = "kanidmd_lib"
@ -20,73 +20,73 @@ name = "scaling_10k"
harness = false harness = false
[dependencies] [dependencies]
async-trait.workspace = true async-trait = { workspace = true }
base64.workspace = true base64 = { workspace = true }
base64urlsafedata.workspace = true base64urlsafedata = { workspace = true }
compact_jwt = { workspace = true, features = ["openssl"] } compact_jwt = { workspace = true, features = ["openssl"] }
concread.workspace = true concread = { workspace = true }
dyn-clone.workspace = true dyn-clone = { workspace = true }
fernet = { workspace = true, features = ["fernet_danger_timestamps"] } fernet = { workspace = true, features = ["fernet_danger_timestamps"] }
filetime.workspace = true filetime = { workspace = true }
futures-util.workspace = true futures-util = { workspace = true }
hashbrown.workspace = true hashbrown = { workspace = true }
idlset.workspace = true idlset = { workspace = true }
kanidm_proto.workspace = true kanidm_proto = { workspace = true }
kanidm_lib_crypto.workspace = true kanidm_lib_crypto = { workspace = true }
lazy_static.workspace = true lazy_static = { workspace = true }
ldap3_proto.workspace = true ldap3_proto = { workspace = true }
libc.workspace = true libc = { workspace = true }
libsqlite3-sys.workspace = true libsqlite3-sys = { workspace = true }
num_enum.workspace = true num_enum = { workspace = true }
# We need to explicitly ask for openssl-sys so that we get the version propagated # We need to explicitly ask for openssl-sys so that we get the version propagated
# into the build.rs for legacy feature checks. # into the build.rs for legacy feature checks.
openssl-sys.workspace = true openssl-sys = { workspace = true }
openssl.workspace = true openssl = { workspace = true }
rand.workspace = true rand = { workspace = true }
regex = { workspace = true, features = ["std", "perf", "perf-inline", "unicode", "unicode-gencat"] } regex = { workspace = true, features = ["std", "perf", "perf-inline", "unicode", "unicode-gencat"] }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_cbor.workspace = true serde_cbor = { workspace = true }
serde_json.workspace = true serde_json = { workspace = true }
sketching.workspace = true sketching = { workspace = true }
smartstring = { workspace = true, features = ["serde"] } smartstring = { workspace = true, features = ["serde"] }
smolset.workspace = true smolset = { workspace = true }
sshkeys.workspace = true sshkeys = { workspace = true }
tide.workspace = true tide = { workspace = true }
time = { workspace = true, features = ["serde", "std"] } time = { workspace = true, features = ["serde", "std"] }
tokio = { workspace = true, features = ["net", "sync", "time", "rt"] } tokio = { workspace = true, features = ["net", "sync", "time", "rt"] }
tokio-util = { workspace = true, features = ["codec"] } tokio-util = { workspace = true, features = ["codec"] }
toml.workspace = true toml = { workspace = true }
touch.workspace = true touch = { workspace = true }
nonempty = { workspace = true, features = ["serialize"] } nonempty = { workspace = true, features = ["serialize"] }
tracing = { workspace = true, features = ["attributes"] } tracing = { workspace = true, features = ["attributes"] }
url = { workspace = true, features = ["serde"] } url = { workspace = true, features = ["serde"] }
urlencoding.workspace = true urlencoding = { workspace = true }
uuid = { workspace = true, features = ["serde", "v4" ] } uuid = { workspace = true, features = ["serde", "v4" ] }
webauthn-rs = { workspace = true, features = ["resident-key-support", "preview-features", "danger-credential-internals"] } webauthn-rs = { workspace = true, features = ["resident-key-support", "preview-features", "danger-credential-internals"] }
webauthn-rs-core.workspace = true webauthn-rs-core = { workspace = true }
zxcvbn.workspace = true zxcvbn = { workspace = true }
# because windows really can't build without the bundled one # because windows really can't build without the bundled one
[target.'cfg(target_family = "windows")'.dependencies] [target.'cfg(target_family = "windows")'.dependencies]
rusqlite = { workspace = true, features = ["bundled"] } rusqlite = { workspace = true, features = ["bundled"] }
whoami.workspace = true whoami = { workspace = true }
[target.'cfg(not(target_family = "windows"))'.dependencies] [target.'cfg(not(target_family = "windows"))'.dependencies]
rusqlite.workspace = true rusqlite = { workspace = true }
users.workspace = true users = { workspace = true }
[features] [features]
# default = [ "libsqlite3-sys/bundled", "openssl/vendored" ] # default = [ "libsqlite3-sys/bundled", "openssl/vendored" ]
[dev-dependencies] [dev-dependencies]
criterion = { workspace = true, features = ["html_reports"] } criterion = { workspace = true, features = ["html_reports"] }
webauthn-authenticator-rs.workspace = true webauthn-authenticator-rs = { workspace = true }
futures.workspace = true futures = { workspace = true }
kanidmd_lib_macros.workspace = true kanidmd_lib_macros = { workspace = true }
[build-dependencies] [build-dependencies]
profiles.workspace = true profiles = { workspace = true }

View file

@ -1254,7 +1254,7 @@ impl<'a> BackendWriteTransaction<'a> {
})?; })?;
if entries.is_empty() { if entries.is_empty() {
admin_info!("No entries affected - reap_tombstones operation success"); admin_debug!("No entries affected - reap_tombstones operation success");
return Ok(0); return Ok(0);
} }

View file

@ -815,7 +815,7 @@ impl AuthSession {
// of what's next, or ordering. // of what's next, or ordering.
let valid_mechs = auth_session.valid_auth_mechs(); let valid_mechs = auth_session.valid_auth_mechs();
security_info!(?valid_mechs, "Offering auth mechanisms"); security_debug!(?valid_mechs, "Offering auth mechanisms");
let as_state = AuthState::Choose(valid_mechs); let as_state = AuthState::Choose(valid_mechs);
(Some(auth_session), as_state) (Some(auth_session), as_state)
} }

View file

@ -39,7 +39,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
])))?; ])))?;
if rc.is_empty() { if rc.is_empty() {
admin_info!("No recycled present - purge operation success"); admin_info!("No recycled items present - purge operation success");
return Ok(()); return Ok(());
} }

View file

@ -7,8 +7,8 @@ edition = "2021"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
proc-macro2.workspace = true proc-macro2 = { workspace = true }
quote.workspace = true quote = { workspace = true }
syn.workspace = true syn = { workspace = true }

View file

@ -3,40 +3,40 @@ name = "kanidmd_testkit"
description = "Kanidm Server Test Framework" description = "Kanidm Server Test Framework"
documentation = "https://docs.rs/kanidm/latest/kanidm/" documentation = "https://docs.rs/kanidm/latest/kanidm/"
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[lib] [lib]
name = "kanidmd_testkit" name = "kanidmd_testkit"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
kanidm_client.workspace = true kanidm_client = { workspace = true }
kanidm_proto.workspace = true kanidm_proto = { workspace = true }
kanidmd_core.workspace = true kanidmd_core = { workspace = true }
kanidmd_lib.workspace = true kanidmd_lib = { workspace = true }
url = { workspace = true, features = ["serde"] } url = { workspace = true, features = ["serde"] }
reqwest = { workspace = true, default-features = false } reqwest = { workspace = true, default-features = false }
sketching.workspace = true sketching = { workspace = true }
testkit-macros.workspace = true testkit-macros = { workspace = true }
tracing = { workspace = true, features = ["attributes"] } tracing = { workspace = true, features = ["attributes"] }
tokio = { workspace = true, features = ["net", "sync", "io-util", "macros"] } tokio = { workspace = true, features = ["net", "sync", "io-util", "macros"] }
[build-dependencies] [build-dependencies]
profiles.workspace = true profiles = { workspace = true }
[dev-dependencies] [dev-dependencies]
compact_jwt.workspace = true compact_jwt = { workspace = true }
serde_json.workspace = true serde_json = { workspace = true }
webauthn-authenticator-rs.workspace = true webauthn-authenticator-rs = { workspace = true }
oauth2_ext = { workspace = true, default-features = false } oauth2_ext = { workspace = true, default-features = false }
futures.workspace = true futures = { workspace = true }
time.workspace = true time = { workspace = true }

View file

@ -22,9 +22,6 @@ repository = "https://github.com/kanidm/kanidm/"
# homepage = { workspace = true } # homepage = { workspace = true }
# repository = { workspace = true } # repository = { workspace = true }
# These are ignored because the crate is in a workspace
#[profile.release]
# less code to include into binary
[lib] [lib]
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
@ -33,7 +30,6 @@ crate-type = ["cdylib", "rlib"]
compact_jwt = { workspace = true, default-features = false, features = ["unsafe_release_without_verify"] } compact_jwt = { workspace = true, default-features = false, features = ["unsafe_release_without_verify"] }
# gloo = "^0.8.0" # gloo = "^0.8.0"
gloo = { workspace = true } gloo = { workspace = true }
gloo-net = { workspace = true }
js-sys = { workspace = true } js-sys = { workspace = true }
kanidm_proto = { workspace = true, features = ["wasm"] } kanidm_proto = { workspace = true, features = ["wasm"] }
qrcode = { workspace = true, features = ["svg"] } qrcode = { workspace = true, features = ["svg"] }

View file

@ -16,6 +16,11 @@ if [ -z "$(which rsync)" ]; then
exit 1 exit 1
fi fi
if [ -z "$(which wasm-pack)" ]; then
echo "Cannot find wasm-pack which is needed to build the UI, quitting!"
exit 1
fi
if [ "$(find ./pkg/ -name 'kanidmd*' | wc -l)" -gt 0 ]; then if [ "$(find ./pkg/ -name 'kanidmd*' | wc -l)" -gt 0 ]; then
echo "Cleaning up" echo "Cleaning up"
rm pkg/kanidmd* rm pkg/kanidmd*
@ -23,13 +28,10 @@ fi
# we can disable this since we want it to expand # we can disable this since we want it to expand
# shellcheck disable=SC2086 # shellcheck disable=SC2086
wasm-pack build ${BUILD_FLAGS} --target web || exit 1 wasm-pack build ${BUILD_FLAGS} --target web --mode no-install --no-pack || exit 1
touch ./pkg/ANYTHING_HERE_WILL_BE_DELETED_ADD_TO_SRC && \ touch ./pkg/ANYTHING_HERE_WILL_BE_DELETED_ADD_TO_SRC && \
rsync --delete-after -r --copy-links -v ./src/img/ ./pkg/img/ && \ rsync --delete-after -r --copy-links -v ./static/* ./pkg/ && \
rsync --delete-after -r --copy-links -v ./src/external/ ./pkg/external/ && \
cp ../../README.md ./pkg/ cp ../../README.md ./pkg/
cp ../../LICENSE.md ./pkg/ cp ../../LICENSE.md ./pkg/
cp ./src/style.css ./pkg/style.css && \
cp ./src/wasmloader.js ./pkg/wasmloader.js && \
rm ./pkg/.gitignore rm ./pkg/.gitignore

View file

@ -234,24 +234,24 @@ 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__hd63bd1cb9b35210b(arg0, arg1, addBorrowedObject(arg2)); wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd11765386bfbbb1b(arg0, arg1, addBorrowedObject(arg2));
} finally { } finally {
heap[stack_pointer++] = undefined; heap[stack_pointer++] = undefined;
} }
} }
function __wbg_adapter_51(arg0, arg1, arg2) { function __wbg_adapter_51(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h4a4d23d6ebf5b8fa(arg0, arg1, addHeapObject(arg2));
}
function __wbg_adapter_54(arg0, arg1, arg2) {
try { try {
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hf7e9e605a1806538(arg0, arg1, addBorrowedObject(arg2)); wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h13182848512d5ace(arg0, arg1, addBorrowedObject(arg2));
} finally { } finally {
heap[stack_pointer++] = undefined; heap[stack_pointer++] = undefined;
} }
} }
function __wbg_adapter_54(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h9e05cfbc2276f207(arg0, arg1, addHeapObject(arg2));
}
/** /**
*/ */
export function run_app() { export function run_app() {
@ -330,10 +330,6 @@ async function __wbg_load(module, imports) {
function __wbg_get_imports() { function __wbg_get_imports() {
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_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;
@ -369,6 +365,10 @@ function __wbg_get_imports() {
const ret = getObject(arg0); const ret = getObject(arg0);
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbindgen_is_undefined = function(arg0) {
const ret = getObject(arg0) === undefined;
return ret;
};
imports.wbg.__wbindgen_in = function(arg0, arg1) { imports.wbg.__wbindgen_in = function(arg0, arg1) {
const ret = getObject(arg0) in getObject(arg1); const ret = getObject(arg0) in getObject(arg1);
return ret; return ret;
@ -643,20 +643,6 @@ function __wbg_get_imports() {
imports.wbg.__wbg_remove_8ae45e50cb58bb66 = function() { return handleError(function (arg0, arg1, arg2) { imports.wbg.__wbg_remove_8ae45e50cb58bb66 = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).remove(getStringFromWasm0(arg1, arg2)); getObject(arg0).remove(getStringFromWasm0(arg1, arg2));
}, arguments) }; }, arguments) };
imports.wbg.__wbg_instanceof_WorkerGlobalScope_d9d741da0fb130ce = function(arg0) {
let result;
try {
result = getObject(arg0) instanceof WorkerGlobalScope;
} catch {
result = false;
}
const ret = result;
return ret;
};
imports.wbg.__wbg_fetch_8eaf01857a5bb21f = function(arg0, arg1) {
const ret = getObject(arg0).fetch(getObject(arg1));
return addHeapObject(ret);
};
imports.wbg.__wbg_instanceof_Element_4622f5da1249a3eb = function(arg0) { imports.wbg.__wbg_instanceof_Element_4622f5da1249a3eb = function(arg0) {
let result; let result;
try { try {
@ -711,10 +697,6 @@ function __wbg_get_imports() {
imports.wbg.__wbg_focus_dbcbbbb2a04c0e1f = function() { return handleError(function (arg0) { imports.wbg.__wbg_focus_dbcbbbb2a04c0e1f = function() { return handleError(function (arg0) {
getObject(arg0).focus(); getObject(arg0).focus();
}, arguments) }; }, arguments) };
imports.wbg.__wbg_new_1eead62f64ca15ce = function() { return handleError(function () {
const ret = new Headers();
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_get_2e9aab260014946d = function() { return handleError(function (arg0, arg1, arg2, arg3) { imports.wbg.__wbg_get_2e9aab260014946d = function() { return handleError(function (arg0, arg1, arg2, arg3) {
const ret = getObject(arg1).get(getStringFromWasm0(arg2, arg3)); const ret = getObject(arg1).get(getStringFromWasm0(arg2, arg3));
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@ -725,29 +707,14 @@ function __wbg_get_imports() {
imports.wbg.__wbg_set_b34caba58723c454 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { imports.wbg.__wbg_set_b34caba58723c454 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
}, arguments) }; }, arguments) };
imports.wbg.__wbg_url_fda63503ced387ff = function(arg0, arg1) {
const ret = getObject(arg1).url;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbg_headers_b439dcff02e808e5 = function(arg0) { imports.wbg.__wbg_headers_b439dcff02e808e5 = function(arg0) {
const ret = getObject(arg0).headers; const ret = getObject(arg0).headers;
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbg_newwithstr_3d9bc779603a93c7 = function() { return handleError(function (arg0, arg1) {
const ret = new Request(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_newwithstrandinit_cad5cd6038c7ff5d = function() { return handleError(function (arg0, arg1, arg2) { imports.wbg.__wbg_newwithstrandinit_cad5cd6038c7ff5d = function() { return handleError(function (arg0, arg1, arg2) {
const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2)); const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2));
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments) };
imports.wbg.__wbg_new_2a98b9c4a51bdc04 = function() { return handleError(function () {
const ret = new URLSearchParams();
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_create_c7e40b6b88186cbf = function() { return handleError(function (arg0, arg1) { imports.wbg.__wbg_create_c7e40b6b88186cbf = function() { return handleError(function (arg0, arg1) {
const ret = getObject(arg0).create(getObject(arg1)); const ret = getObject(arg0).create(getObject(arg1));
return addHeapObject(ret); return addHeapObject(ret);
@ -782,10 +749,6 @@ function __wbg_get_imports() {
const ret = getObject(arg0).json(); const ret = getObject(arg0).json();
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments) };
imports.wbg.__wbg_text_a667ac1770538491 = function() { return handleError(function (arg0) {
const ret = getObject(arg0).text();
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_log_1d3ae0273d8f4f8a = function(arg0) { imports.wbg.__wbg_log_1d3ae0273d8f4f8a = function(arg0) {
console.log(getObject(arg0)); console.log(getObject(arg0));
}; };
@ -1090,10 +1053,6 @@ function __wbg_get_imports() {
const ret = Object.is(getObject(arg0), getObject(arg1)); const ret = Object.is(getObject(arg0), getObject(arg1));
return ret; return ret;
}; };
imports.wbg.__wbg_toString_a8e343996af880e9 = function(arg0) {
const ret = getObject(arg0).toString();
return addHeapObject(ret);
};
imports.wbg.__wbg_resolve_53698b95aaf7fcf8 = function(arg0) { imports.wbg.__wbg_resolve_53698b95aaf7fcf8 = function(arg0) {
const ret = Promise.resolve(getObject(arg0)); const ret = Promise.resolve(getObject(arg0));
return addHeapObject(ret); return addHeapObject(ret);
@ -1159,16 +1118,16 @@ function __wbg_get_imports() {
const ret = wasm.memory; const ret = wasm.memory;
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbindgen_closure_wrapper4681 = function(arg0, arg1, arg2) { imports.wbg.__wbindgen_closure_wrapper4628 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1097, __wbg_adapter_48); const ret = makeMutClosure(arg0, arg1, 1074, __wbg_adapter_48);
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbindgen_closure_wrapper5482 = function(arg0, arg1, arg2) { imports.wbg.__wbindgen_closure_wrapper5401 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1396, __wbg_adapter_51); const ret = makeMutClosure(arg0, arg1, 1357, __wbg_adapter_51);
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbindgen_closure_wrapper5489 = function(arg0, arg1, arg2) { imports.wbg.__wbindgen_closure_wrapper6520 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1400, __wbg_adapter_54); const ret = makeMutClosure(arg0, arg1, 1431, __wbg_adapter_54);
return addHeapObject(ret); return addHeapObject(ret);
}; };

View file

@ -1,24 +0,0 @@
{
"name": "kanidmd_web_ui",
"collaborators": [
"William Brown <william@blackhats.net.au>",
"James Hodgkinson <james@terminaloutcomes.com>"
],
"description": "Kanidm Server Web User Interface",
"version": "1.1.0-beta.13",
"license": "MPL-2.0",
"repository": {
"type": "git",
"url": "https://github.com/kanidm/kanidm/"
},
"files": [
"kanidmd_web_ui_bg.wasm",
"kanidmd_web_ui.js",
"LICENSE.md"
],
"module": "kanidmd_web_ui.js",
"homepage": "https://github.com/kanidm/kanidm/",
"sideEffects": [
"./snippets/*"
]
}

View file

@ -9,8 +9,9 @@ use crate::components::alpha_warning_banner;
use crate::constants::{ use crate::constants::{
CSS_BREADCRUMB_ITEM, CSS_BREADCRUMB_ITEM_ACTIVE, CSS_CELL, CSS_DT, CSS_TABLE, CSS_BREADCRUMB_ITEM, CSS_BREADCRUMB_ITEM_ACTIVE, CSS_CELL, CSS_DT, CSS_TABLE,
}; };
use crate::utils::{do_alert_error, do_page_header, init_request}; use crate::utils::{do_alert_error, do_page_header};
use crate::views::AdminRoute; use crate::views::AdminRoute;
use crate::{do_request, RequestMethod};
impl From<GetError> for AdminListAccountsMsg { impl From<GetError> for AdminListAccountsMsg {
fn from(ge: GetError) -> Self { fn from(ge: GetError) -> Self {
@ -93,24 +94,21 @@ pub async fn get_accounts() -> Result<AdminListAccountsMsg, GetError> {
]; ];
for (endpoint, object_type) in endpoints { for (endpoint, object_type) in endpoints {
let request = init_request(endpoint); let (_, _, value, _) = match do_request(endpoint, RequestMethod::GET, None).await {
let response = match request.send().await { Ok(val) => val,
Ok(value) => value,
Err(error) => { Err(error) => {
return Err(GetError { return Err(GetError {
err: format!("{:?}", error), err: format!("{:?}", error),
}) })
} }
}; };
#[allow(clippy::panic)] // TODO: this kind of thing comes back when you're logged out: SerdeError(Error("invalid type: string \"sessionexpired\", expected a sequence", line: 1, column: 16))', server/web_ui/src/components/admin_accounts.rs:107:27
let data: Vec<Entity> = match response.json().await { let data: Vec<Entity> = match serde_wasm_bindgen::from_value(value) {
Ok(value) => value, Ok(value) => value,
// TODO: this kind of thing comes back when you're logged out: SerdeError(Error("invalid type: string \"sessionexpired\", expected a sequence", line: 1, column: 16))', server/web_ui/src/components/admin_accounts.rs:107:27
Err(error) => { Err(error) => {
return Err(GetError { return Err(GetError {
err: format!("Failed to grab the account data into JSON: {:?}", error), err: format!("Failed to grab the account data into JSON: {:?}", error),
}) });
} }
}; };
@ -544,41 +542,59 @@ impl Component for AdminViewServiceAccount {
/// pull the details for a single person by UUID /// pull the details for a single person by UUID
pub async fn get_person(uuid: &str) -> Result<AdminViewPersonMsg, GetError> { pub async fn get_person(uuid: &str) -> Result<AdminViewPersonMsg, GetError> {
let request = init_request(format!("/v1/person/{}", uuid).as_str()); let (_, _, value, _) = match do_request(
let response = match request.send().await { format!("/v1/person/{}", uuid).as_str(),
Ok(value) => value, RequestMethod::GET,
None,
)
.await
{
Ok(val) => val,
Err(error) => { Err(error) => {
return Err(GetError { return Err(GetError {
err: format!("{:?}", error), err: format!("{:?}", error),
}) })
} }
}; };
#[allow(clippy::panic)]
let data: Entity = match response.json().await { let data: Entity = match serde_wasm_bindgen::from_value(value) {
Ok(value) => value, Ok(value) => value,
Err(error) => panic!("Failed to grab the person data into JSON: {:?}", error), Err(error) => {
return Err(GetError {
err: format!("{:?}", error),
});
}
}; };
Ok(AdminViewPersonMsg::Responded { response: data }) Ok(AdminViewPersonMsg::Responded { response: data })
} }
/// pull the details for a single service_account by UUID /// pull the details for a single service_account by UUID
pub async fn get_service_account(uuid: &str) -> Result<AdminViewServiceAccountMsg, GetError> { pub async fn get_service_account(uuid: &str) -> Result<AdminViewServiceAccountMsg, GetError> {
let request = init_request(format!("/v1/service_account/{}", uuid).as_str()); let (_, _, value, _) = match do_request(
let response = match request.send().await { format!("/v1/service_account/{}", uuid).as_str(),
RequestMethod::GET,
None,
)
.await
{
Ok(val) => val,
Err(error) => {
return Err(GetError {
err: format!(
"Failed to grab the service_account data into JSON: {:?}",
error
),
})
}
};
let data: Entity = match serde_wasm_bindgen::from_value(value) {
Ok(value) => value, Ok(value) => value,
Err(error) => { Err(error) => {
return Err(GetError { return Err(GetError {
err: format!("{:?}", error), err: format!("{:?}", error),
}) });
} }
}; };
#[allow(clippy::panic)]
let data: Entity = match response.json().await {
Ok(value) => value,
Err(error) => panic!(
"Failed to grab the service account data into JSON: {:?}",
error
),
};
Ok(AdminViewServiceAccountMsg::Responded { response: data }) Ok(AdminViewServiceAccountMsg::Responded { response: data })
} }

View file

@ -7,8 +7,9 @@ use yew_router::prelude::Link;
use crate::components::admin_menu::{Entity, EntityType, GetError}; use crate::components::admin_menu::{Entity, EntityType, GetError};
use crate::components::alpha_warning_banner; use crate::components::alpha_warning_banner;
use crate::constants::{CSS_BREADCRUMB_ITEM, CSS_BREADCRUMB_ITEM_ACTIVE, CSS_CELL, CSS_TABLE}; use crate::constants::{CSS_BREADCRUMB_ITEM, CSS_BREADCRUMB_ITEM_ACTIVE, CSS_CELL, CSS_TABLE};
use crate::utils::{do_alert_error, do_page_header, init_request}; use crate::utils::{do_alert_error, do_page_header};
use crate::views::AdminRoute; use crate::views::AdminRoute;
use crate::{do_request, RequestMethod};
impl From<GetError> for AdminListGroupsMsg { impl From<GetError> for AdminListGroupsMsg {
fn from(ge: GetError) -> Self { fn from(ge: GetError) -> Self {
@ -70,20 +71,23 @@ pub async fn get_groups() -> Result<AdminListGroupsMsg, GetError> {
let endpoints = [("/v1/group", EntityType::Group)]; let endpoints = [("/v1/group", EntityType::Group)];
for (endpoint, object_type) in endpoints { for (endpoint, object_type) in endpoints {
let request = init_request(endpoint); let (_, _, value, _) = match do_request(endpoint, RequestMethod::GET, None).await {
let response = match request.send().await { Ok(val) => val,
Err(error) => {
return Err(GetError {
err: format!("Failed to grab the group data into JSON: {:?}", error),
})
}
};
let data: Vec<Entity> = match serde_wasm_bindgen::from_value(value) {
Ok(value) => value, Ok(value) => value,
Err(error) => { Err(error) => {
return Err(GetError { return Err(GetError {
err: format!("{:?}", error), err: format!("{:?}", error),
}) });
} }
}; };
#[allow(clippy::panic)]
let data: Vec<Entity> = match response.json().await {
Ok(value) => value,
Err(error) => panic!("Failed to grab the group data into JSON: {:?}", error),
};
for entity in data.iter() { for entity in data.iter() {
let mut new_entity = entity.to_owned(); let mut new_entity = entity.to_owned();
@ -360,19 +364,23 @@ impl Component for AdminViewGroup {
/// pull the details for a single group by UUID /// pull the details for a single group by UUID
pub async fn get_group(groupid: &str) -> Result<AdminViewGroupMsg, GetError> { pub async fn get_group(groupid: &str) -> Result<AdminViewGroupMsg, GetError> {
let request = init_request(format!("/v1/group/{}", groupid).as_str()); let endpoint = format!("/v1/group/{}", groupid);
let response = match request.send().await { let (_, _, value, _) = match do_request(&endpoint, RequestMethod::GET, None).await {
Ok(value) => value, Ok(val) => val,
Err(error) => { Err(error) => {
return Err(GetError { return Err(GetError {
err: format!("{:?}", error), err: format!("{:?}", error),
}) })
} }
}; };
#[allow(clippy::panic)]
let data: Entity = match response.json().await { let data: Entity = match serde_wasm_bindgen::from_value(value) {
Ok(value) => value, Ok(value) => value,
Err(error) => panic!("Failed to grab the group data into JSON: {:?}", error), Err(error) => {
return Err(GetError {
err: format!("{:?}", error),
});
}
}; };
Ok(AdminViewGroupMsg::Responded { response: data }) Ok(AdminViewGroupMsg::Responded { response: data })
} }

View file

@ -7,8 +7,9 @@ use yew_router::prelude::Link;
use crate::components::admin_menu::{Entity, EntityType, GetError}; use crate::components::admin_menu::{Entity, EntityType, GetError};
use crate::components::alpha_warning_banner; use crate::components::alpha_warning_banner;
use crate::constants::{CSS_BREADCRUMB_ITEM, CSS_BREADCRUMB_ITEM_ACTIVE, CSS_CELL, CSS_TABLE}; use crate::constants::{CSS_BREADCRUMB_ITEM, CSS_BREADCRUMB_ITEM_ACTIVE, CSS_CELL, CSS_TABLE};
use crate::utils::{do_alert_error, do_page_header, init_request}; use crate::utils::{do_alert_error, do_page_header};
use crate::views::AdminRoute; use crate::views::AdminRoute;
use crate::{do_request, RequestMethod};
impl From<GetError> for AdminListOAuth2Msg { impl From<GetError> for AdminListOAuth2Msg {
fn from(ge: GetError) -> Self { fn from(ge: GetError) -> Self {
@ -71,22 +72,25 @@ pub async fn get_entities() -> Result<AdminListOAuth2Msg, GetError> {
let endpoints = [("/v1/oauth2", EntityType::OAuth2RP)]; let endpoints = [("/v1/oauth2", EntityType::OAuth2RP)];
for (endpoint, object_type) in endpoints { for (endpoint, object_type) in endpoints {
let request = init_request(endpoint); let (_, _, value, _) = match do_request(endpoint, RequestMethod::GET, None).await {
let response = match request.send().await { Ok(val) => val,
Ok(value) => value,
Err(error) => { Err(error) => {
return Err(GetError { return Err(GetError {
err: format!("{:?}", error), err: format!("{:?}", error),
}) })
} }
}; };
#[allow(clippy::panic)]
let data: Vec<Entity> = match response.json().await { let data: Vec<Entity> = match serde_wasm_bindgen::from_value(value) {
Ok(value) => value, Ok(value) => value,
Err(error) => panic!("Failed to grab the OAuth2 RP data into JSON: {:?}", error), Err(error) => {
return Err(GetError {
err: format!("Failed to grab the oauth2 data into JSON: {:?}", error),
});
}
}; };
for entity in data.iter() { for entity in data.into_iter() {
let mut new_entity = entity.to_owned(); let mut new_entity = entity.to_owned();
new_entity.object_type = object_type.clone(); new_entity.object_type = object_type.clone();
@ -96,8 +100,9 @@ pub async fn get_entities() -> Result<AdminListOAuth2Msg, GetError> {
.attrs .attrs
.uuid .uuid
.first() .first()
.expect("Failed to grab the SPN for an account."); .map(|e| e.to_owned())
oauth2_objects.insert(entity_id.to_string(), new_entity); .unwrap_or(String::from("Unknown entity name!"));
oauth2_objects.insert(entity_id, new_entity);
} }
} }
@ -401,17 +406,17 @@ impl Component for AdminViewOAuth2 {
} }
pub async fn get_oauth2_rp(rs_name: &str) -> Result<AdminViewOAuth2Msg, GetError> { pub async fn get_oauth2_rp(rs_name: &str) -> Result<AdminViewOAuth2Msg, GetError> {
let request = init_request(format!("/v1/oauth2/{}", rs_name).as_str()); let endpoint = format!("/v1/oauth2/{}", rs_name);
let response = match request.send().await { let (_, _, value, _) = match do_request(&endpoint, RequestMethod::GET, None).await {
Ok(value) => value, Ok(val) => val,
Err(error) => { Err(error) => {
return Err(GetError { return Err(GetError {
err: format!("{:?}", error), err: format!("{:?}", error),
}) })
} }
}; };
#[allow(clippy::panic)]
let data: Entity = match response.json().await { let data: Entity = match serde_wasm_bindgen::from_value(value) {
Ok(value) => { Ok(value) => {
console::log!(format!("{:?}", value)); console::log!(format!("{:?}", value));
value value

View file

@ -1,8 +1,7 @@
use kanidm_proto::v1::{SingleStringRequest, UserAuthToken}; use kanidm_proto::v1::{SingleStringRequest, UserAuthToken};
use uuid::Uuid; use uuid::Uuid;
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt};
use wasm_bindgen_futures::JsFuture; use web_sys::{FormData, HtmlFormElement};
use web_sys::{FormData, HtmlFormElement, Request, RequestInit, RequestMode, Response};
use yew::prelude::*; use yew::prelude::*;
use crate::error::*; use crate::error::*;
@ -250,32 +249,14 @@ impl ChangeUnixPassword {
}) })
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to change request"); .expect_throw("Failed to change request");
let mut opts = RequestInit::new();
opts.method("PUT");
opts.mode(RequestMode::SameOrigin);
opts.body(Some(&changereq_jsvalue));
let uri = format!("/v1/person/{}/_unix/_credential", id); let uri = format!("/v1/person/{}/_unix/_credential", id);
let (kopid, status, value, _) =
let request = Request::new_with_str_and_init(uri.as_str(), &opts)?; crate::do_request(&uri, crate::RequestMethod::PUT, Some(changereq_jsvalue)).await?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
if status == 200 { if status == 200 {
Ok(Msg::Success) Ok(Msg::Success)
} else { } else {
let headers = resp.headers(); let emsg = value.as_string().unwrap_or_default();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }
} }

View file

@ -10,9 +10,6 @@ use wasm_bindgen::UnwrapThrowExt;
use web_sys::Node; use web_sys::Node;
use crate::error::*; use crate::error::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestCredentials, RequestInit, RequestMode, Response};
enum State { enum State {
Valid, Valid,
@ -237,35 +234,17 @@ impl Component for CreateResetCode {
impl CreateResetCode { impl CreateResetCode {
async fn credential_get_update_intent_token(id: String) -> Result<Msg, FetchError> { async fn credential_get_update_intent_token(id: String) -> Result<Msg, FetchError> {
let mut opts = RequestInit::new();
opts.method("GET");
opts.mode(RequestMode::SameOrigin);
opts.credentials(RequestCredentials::SameOrigin);
let uri = format!("/v1/person/{}/_credential/_update_intent?ttl=0", id); let uri = format!("/v1/person/{}/_credential/_update_intent?ttl=0", id);
let request = Request::new_with_str_and_init(uri.as_str(), &opts)?; let (kopid, status, value, _) =
crate::do_request(&uri, crate::RequestMethod::GET, None).await?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?;
let token: CUIntentToken = let token: CUIntentToken =
serde_wasm_bindgen::from_value(jsval).expect_throw("Invalid response type"); serde_wasm_bindgen::from_value(value).expect_throw("Invalid response type");
Ok(Msg::Ready { token }) Ok(Msg::Ready { token })
} else { } else {
let headers = resp.headers(); let emsg = value.as_string().unwrap_or_default();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
// let jsval_json = JsFuture::from(resp.json()?).await?; // let jsval_json = JsFuture::from(resp.json()?).await?;
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }

View file

@ -1,14 +1,14 @@
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
use gloo::console; use gloo::console;
use kanidm_proto::v1::{CURequest, CUSessionToken, CUStatus}; use kanidm_proto::v1::{CURequest, CUSessionToken, CUStatus};
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen::{JsValue, UnwrapThrowExt};
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestInit, RequestMode, Response};
use yew::prelude::*; use yew::prelude::*;
use super::reset::{EventBusMsg, ModalProps}; use super::reset::{EventBusMsg, ModalProps};
use crate::do_request;
use crate::error::*; use crate::error::*;
use crate::utils; use crate::utils;
use crate::RequestMethod;
enum State { enum State {
Init, Init,
@ -50,37 +50,21 @@ impl DeleteApp {
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise pw curequest"); .expect_throw("Failed to serialise pw curequest");
let mut opts = RequestInit::new(); let (kopid, status, value, _) = do_request(
opts.method("POST"); "/v1/credential/_update",
opts.mode(RequestMode::SameOrigin); RequestMethod::POST,
Some(req_jsvalue),
opts.body(Some(&req_jsvalue)); )
.await?;
let request = Request::new_with_str_and_init("/v1/credential/_update", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
let headers = resp.headers();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?; let custatus: CUStatus =
let status: CUStatus = serde_wasm_bindgen::from_value(value).expect_throw("Invalid response type");
serde_wasm_bindgen::from_value(jsval).expect_throw("Invalid response type");
cb.emit(EventBusMsg::UpdateStatus { status }); cb.emit(EventBusMsg::UpdateStatus { status: custatus });
Ok(Msg::Success) Ok(Msg::Success)
} else { } else {
let text = JsFuture::from(resp.text()?).await?; let emsg = value.as_string().unwrap_or_default();
let emsg = text.as_string().unwrap_or_default();
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }
} }

View file

@ -1,14 +1,13 @@
use gloo::console; use gloo::console;
use kanidm_proto::v1::{CURegState, CURequest, CUSessionToken, CUStatus}; use kanidm_proto::v1::{CURegState, CURequest, CUSessionToken, CUStatus};
use kanidm_proto::webauthn::{CreationChallengeResponse, RegisterPublicKeyCredential}; use kanidm_proto::webauthn::{CreationChallengeResponse, RegisterPublicKeyCredential};
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen::{JsValue, UnwrapThrowExt};
use wasm_bindgen_futures::JsFuture; use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestInit, RequestMode, Response};
use yew::prelude::*; use yew::prelude::*;
use super::reset::{EventBusMsg, ModalProps}; use super::reset::{EventBusMsg, ModalProps};
use crate::error::*;
use crate::utils; use crate::utils;
use crate::{do_request, error::*, RequestMethod};
pub struct PasskeyModalApp { pub struct PasskeyModalApp {
state: State, state: State,
@ -61,30 +60,16 @@ impl PasskeyModalApp {
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise pw curequest"); .expect_throw("Failed to serialise pw curequest");
let mut opts = RequestInit::new(); let (kopid, status, value, _) = do_request(
opts.method("POST"); "/v1/credential/_update",
opts.mode(RequestMode::SameOrigin); RequestMethod::POST,
Some(req_jsvalue),
opts.body(Some(&req_jsvalue)); )
.await?;
let request = Request::new_with_str_and_init("/v1/credential/_update", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
let headers = resp.headers();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?;
let status: CUStatus = let status: CUStatus =
serde_wasm_bindgen::from_value(jsval).expect_throw("Invalid response type"); serde_wasm_bindgen::from_value(value).expect_throw("Invalid response type");
cb.emit(EventBusMsg::UpdateStatus { cb.emit(EventBusMsg::UpdateStatus {
status: status.clone(), status: status.clone(),
@ -102,8 +87,7 @@ impl PasskeyModalApp {
CURegState::None => Msg::Success, CURegState::None => Msg::Success,
}) })
} else { } else {
let text = JsFuture::from(resp.text()?).await?; let emsg = value.as_string().unwrap_or_default();
let emsg = text.as_string().unwrap_or_default();
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }
} }

View file

@ -2,14 +2,13 @@
use gloo::console; use gloo::console;
use kanidm_proto::v1::{CURegState, CURequest, CUSessionToken, CUStatus}; use kanidm_proto::v1::{CURegState, CURequest, CUSessionToken, CUStatus};
use uuid::Uuid; use uuid::Uuid;
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen::{JsValue, UnwrapThrowExt};
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestInit, RequestMode, Response};
use yew::prelude::*; use yew::prelude::*;
use super::reset::{EventBusMsg, PasskeyRemoveModalProps}; use super::reset::{EventBusMsg, PasskeyRemoveModalProps};
use crate::error::*; use crate::error::*;
use crate::utils; use crate::utils;
use crate::{do_request, RequestMethod};
pub struct PasskeyRemoveModalApp { pub struct PasskeyRemoveModalApp {
state: State, state: State,
@ -70,30 +69,17 @@ impl PasskeyRemoveModalApp {
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise pw curequest"); .expect_throw("Failed to serialise pw curequest");
let mut opts = RequestInit::new(); // this really should require a DELETE not a post!
opts.method("POST"); let (kopid, status, value, _) = do_request(
opts.mode(RequestMode::SameOrigin); "/v1/credential/_update",
RequestMethod::POST,
opts.body(Some(&req_jsvalue)); Some(req_jsvalue),
)
let request = Request::new_with_str_and_init("/v1/credential/_update", &opts)?; .await?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
let headers = resp.headers();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?;
let status: CUStatus = let status: CUStatus =
serde_wasm_bindgen::from_value(jsval).expect_throw("Invalid response type"); serde_wasm_bindgen::from_value(value).expect_throw("Invalid response type");
cb.emit(EventBusMsg::UpdateStatus { cb.emit(EventBusMsg::UpdateStatus {
status: status.clone(), status: status.clone(),
@ -111,8 +97,7 @@ impl PasskeyRemoveModalApp {
CURegState::None => Msg::Success, CURegState::None => Msg::Success,
}) })
} else { } else {
let text = JsFuture::from(resp.text()?).await?; let emsg = value.as_string().unwrap_or_default();
let emsg = text.as_string().unwrap_or_default();
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }
} }

View file

@ -1,13 +1,13 @@
use gloo::console; use gloo::console;
use kanidm_proto::v1::{CURequest, CUSessionToken, CUStatus, OperationError, PasswordFeedback}; use kanidm_proto::v1::{CURequest, CUSessionToken, CUStatus, OperationError, PasswordFeedback};
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen::{JsValue, UnwrapThrowExt};
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestInit, RequestMode, Response};
use yew::prelude::*; use yew::prelude::*;
use super::reset::{EventBusMsg, ModalProps}; use super::reset::{EventBusMsg, ModalProps};
use crate::error::*; use crate::error::*;
use crate::utils; use crate::utils;
use crate::{do_request, RequestMethod};
enum PwState { enum PwState {
Init, Init,
@ -57,38 +57,24 @@ impl PwModalApp {
} }
async fn submit_password_update(token: CUSessionToken, pw: String) -> Result<Msg, FetchError> { async fn submit_password_update(token: CUSessionToken, pw: String) -> Result<Msg, FetchError> {
let intentreq_jsvalue = serde_json::to_string(&(CURequest::Password(pw), token)) let req_jsvalue = serde_json::to_string(&(CURequest::Password(pw), token))
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise pw curequest"); .expect_throw("Failed to serialise pw curequest");
let mut opts = RequestInit::new(); let (kopid, status, value, _) = do_request(
opts.method("POST"); "/v1/credential/_update",
opts.mode(RequestMode::SameOrigin); RequestMethod::POST,
Some(req_jsvalue),
opts.body(Some(&intentreq_jsvalue)); )
.await?;
let request = Request::new_with_str_and_init("/v1/credential/_update", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
let headers = resp.headers();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?;
let status: CUStatus = let status: CUStatus =
serde_wasm_bindgen::from_value(jsval).expect_throw("Invalid response type"); serde_wasm_bindgen::from_value(value).expect_throw("Invalid response type");
Ok(Msg::PasswordResponseSuccess { status }) Ok(Msg::PasswordResponseSuccess { status })
} else if status == 400 { } else if status == 400 {
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let jsval = JsFuture::from(resp.json()?).await?;
let status: OperationError = let status: OperationError =
serde_wasm_bindgen::from_value(jsval).expect_throw("Invalid response type"); serde_wasm_bindgen::from_value(value).expect_throw("Invalid response type");
match status { match status {
OperationError::PasswordQuality(feedback) => { OperationError::PasswordQuality(feedback) => {
Ok(Msg::PasswordResponseQuality { feedback }) Ok(Msg::PasswordResponseQuality { feedback })
@ -99,9 +85,7 @@ impl PwModalApp {
}), }),
} }
} else { } else {
let kopid = headers.get("x-kanidm-opid").ok().flatten(); let emsg = value.as_string().unwrap_or_default();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }
} }

View file

@ -3,9 +3,7 @@ use kanidm_proto::v1::{
CUIntentToken, CUSessionToken, CUStatus, CredentialDetail, CredentialDetailType, CUIntentToken, CUSessionToken, CUStatus, CredentialDetail, CredentialDetailType,
}; };
use uuid::Uuid; use uuid::Uuid;
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen::{JsValue, UnwrapThrowExt};
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestInit, RequestMode, Response};
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
@ -15,7 +13,7 @@ use super::passkeyremove::PasskeyRemoveModalApp;
use super::pwmodal::PwModalApp; use super::pwmodal::PwModalApp;
use super::totpmodal::TotpModalApp; use super::totpmodal::TotpModalApp;
use super::totpremove::TotpRemoveComp; use super::totpremove::TotpRemoveComp;
use crate::error::*; use crate::{do_request, error::*, RequestMethod};
use crate::{models, utils}; use crate::{models, utils};
// use std::rc::Rc; // use std::rc::Rc;
@ -577,37 +575,23 @@ impl CredentialResetApp {
} }
async fn exchange_intent_token(token: String) -> Result<Msg, FetchError> { async fn exchange_intent_token(token: String) -> Result<Msg, FetchError> {
let intentreq_jsvalue = serde_json::to_string(&CUIntentToken { token }) let req_jsvalue = serde_json::to_string(&CUIntentToken { token })
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise intent request"); .expect_throw("Failed to serialise intent request");
let mut opts = RequestInit::new(); let (kopid, status, value, _) = do_request(
opts.method("POST"); "/v1/credential/_exchange_intent",
opts.mode(RequestMode::SameOrigin); RequestMethod::POST,
Some(req_jsvalue),
opts.body(Some(&intentreq_jsvalue)); )
.await?;
let request = Request::new_with_str_and_init("/v1/credential/_exchange_intent", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
let headers = resp.headers();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?;
let (token, status): (CUSessionToken, CUStatus) = let (token, status): (CUSessionToken, CUStatus) =
serde_wasm_bindgen::from_value(jsval).expect_throw("Invalid response type"); serde_wasm_bindgen::from_value(value).expect_throw("Invalid response type");
Ok(Msg::BeginSession { token, status }) Ok(Msg::BeginSession { token, status })
} else { } else {
let kopid = headers.get("x-kanidm-opid").ok().flatten(); let emsg = value.as_string().unwrap_or_default();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }
} }
@ -617,30 +601,13 @@ impl CredentialResetApp {
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise session token"); .expect_throw("Failed to serialise session token");
let mut opts = RequestInit::new(); let (kopid, status, value, _) =
opts.method("POST"); do_request(url, RequestMethod::POST, Some(req_jsvalue)).await?;
opts.mode(RequestMode::SameOrigin);
opts.body(Some(&req_jsvalue));
let request = Request::new_with_str_and_init(url, &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
let headers = resp.headers();
if status == 200 { if status == 200 {
Ok(Msg::Success) Ok(Msg::Success)
} else { } else {
let kopid = headers.get("x-kanidm-opid").ok().flatten(); let emsg = value.as_string().unwrap_or_default();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }
} }

View file

@ -3,14 +3,14 @@ use gloo::console;
use kanidm_proto::v1::{CURegState, CURequest, CUSessionToken, CUStatus, TotpSecret}; use kanidm_proto::v1::{CURegState, CURequest, CUSessionToken, CUStatus, TotpSecret};
use qrcode::render::svg; use qrcode::render::svg;
use qrcode::QrCode; use qrcode::QrCode;
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen::{JsValue, UnwrapThrowExt};
use wasm_bindgen_futures::JsFuture; use web_sys::Node;
use web_sys::{Node, Request, RequestCredentials, RequestInit, RequestMode, Response};
use yew::prelude::*; use yew::prelude::*;
use super::reset::{EventBusMsg, ModalProps}; use super::reset::{EventBusMsg, ModalProps};
use crate::error::*; use crate::error::*;
use crate::utils; use crate::utils;
use crate::{do_request, RequestMethod};
enum TotpState { enum TotpState {
Init, Init,
@ -74,31 +74,15 @@ impl TotpModalApp {
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise pw curequest"); .expect_throw("Failed to serialise pw curequest");
let mut opts = RequestInit::new(); let (kopid, status, value, _) = do_request(
opts.method("POST"); "/v1/credential/_update",
opts.mode(RequestMode::SameOrigin); RequestMethod::POST,
opts.credentials(RequestCredentials::SameOrigin); Some(req_jsvalue),
)
opts.body(Some(&req_jsvalue)); .await?;
let request = Request::new_with_str_and_init("/v1/credential/_update", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
let headers = resp.headers();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?;
let status: CUStatus = let status: CUStatus =
serde_wasm_bindgen::from_value(jsval).expect_throw("Invalid response type"); serde_wasm_bindgen::from_value(value).expect_throw("Invalid response type");
cb.emit(EventBusMsg::UpdateStatus { cb.emit(EventBusMsg::UpdateStatus {
status: status.clone(), status: status.clone(),
@ -115,8 +99,7 @@ impl TotpModalApp {
CURegState::TotpInvalidSha1 => Msg::TotpInvalidSha1, CURegState::TotpInvalidSha1 => Msg::TotpInvalidSha1,
}) })
} else { } else {
let text = JsFuture::from(resp.text()?).await?; let emsg = value.as_string().unwrap_or_default();
let emsg = text.as_string().unwrap_or_default();
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }
} }

View file

@ -2,12 +2,11 @@ use super::reset::{EventBusMsg, TotpRemoveProps};
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
use gloo::console; use gloo::console;
use kanidm_proto::v1::{CURequest, CUSessionToken, CUStatus}; use kanidm_proto::v1::{CURequest, CUSessionToken, CUStatus};
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen::{JsValue, UnwrapThrowExt};
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestInit, RequestMode, Response};
use crate::do_request;
use crate::error::*; use crate::error::*;
use crate::utils; use crate::RequestMethod;
use yew::prelude::*; use yew::prelude::*;
pub enum Msg { pub enum Msg {
@ -108,37 +107,21 @@ impl TotpRemoveComp {
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise pw curequest"); .expect_throw("Failed to serialise pw curequest");
let mut opts = RequestInit::new(); let (kopid, status, value, _) = do_request(
opts.method("POST"); "/v1/credential/_update",
opts.mode(RequestMode::SameOrigin); RequestMethod::POST,
Some(req_jsvalue),
opts.body(Some(&req_jsvalue)); )
.await?;
let request = Request::new_with_str_and_init("/v1/credential/_update", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
let headers = resp.headers();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?;
let status: CUStatus = let status: CUStatus =
serde_wasm_bindgen::from_value(jsval).expect_throw("Invalid response type"); serde_wasm_bindgen::from_value(value).expect_throw("Invalid response type");
cb.emit(EventBusMsg::UpdateStatus { status }); cb.emit(EventBusMsg::UpdateStatus { status });
Ok(Msg::Success) Ok(Msg::Success)
} else { } else {
let text = JsFuture::from(resp.text()?).await?; let emsg = value.as_string().unwrap_or_default();
let emsg = text.as_string().unwrap_or_default();
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }
} }

View file

@ -11,7 +11,11 @@
#![deny(clippy::needless_pass_by_value)] #![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)] #![deny(clippy::trivially_copy_pass_by_ref)]
use error::FetchError;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::JsFuture;
use web_sys::{Headers, Request, RequestInit, RequestMode, Response};
#[macro_use] #[macro_use]
mod macros; mod macros;
@ -35,3 +39,57 @@ pub fn run_app() -> Result<(), JsValue> {
gloo::console::debug!(kanidm_proto::utils::get_version("kanidmd_web_ui")); gloo::console::debug!(kanidm_proto::utils::get_version("kanidmd_web_ui"));
Ok(()) Ok(())
} }
#[derive(Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum RequestMethod {
GET,
POST,
PUT,
}
impl ToString for RequestMethod {
fn to_string(&self) -> String {
match self {
RequestMethod::PUT => "PUT".to_string(),
RequestMethod::POST => "POST".to_string(),
RequestMethod::GET => "GET".to_string(),
}
}
}
/// Build and send a request to the backend, with some standard headers and pull back
/// (kopid, status, json, headers)
pub async fn do_request(
uri: &str,
method: RequestMethod,
body: Option<JsValue>,
) -> Result<(Option<String>, u16, JsValue, Headers), FetchError> {
let mut opts = RequestInit::new();
opts.method(&method.to_string());
opts.mode(RequestMode::SameOrigin);
opts.credentials(web_sys::RequestCredentials::SameOrigin);
if let Some(body) = body {
#[cfg(debug_assertions)]
if method == RequestMethod::GET {
gloo::console::debug!("This seems odd, you've supplied a body with a GET request?")
}
opts.body(Some(&body));
}
let request = Request::new_with_str_and_init(uri, &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
let headers: Headers = resp.headers();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
Ok((kopid, status, JsFuture::from(resp.json()?).await?, headers))
}

View file

@ -6,18 +6,15 @@ use kanidm_proto::v1::{
}; };
use kanidm_proto::webauthn::PublicKeyCredential; use kanidm_proto::webauthn::PublicKeyCredential;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::{spawn_local, JsFuture}; use wasm_bindgen_futures::{spawn_local, JsFuture};
use web_sys::{ use web_sys::CredentialRequestOptions;
CredentialRequestOptions, Request, RequestCredentials, RequestInit, RequestMode, Response,
};
use yew::prelude::*; use yew::prelude::*;
use yew::virtual_dom::VNode; use yew::virtual_dom::VNode;
use yew_router::prelude::*; use yew_router::prelude::*;
use crate::constants::{CLASS_BUTTON_DARK, CLASS_DIV_LOGIN_BUTTON, CLASS_DIV_LOGIN_FIELD}; use crate::constants::{CLASS_BUTTON_DARK, CLASS_DIV_LOGIN_BUTTON, CLASS_DIV_LOGIN_FIELD};
use crate::error::FetchError; use crate::error::FetchError;
use crate::{models, utils}; use crate::{do_request, models, utils, RequestMethod};
pub struct LoginApp { pub struct LoginApp {
state: LoginState, state: LoginState,
@ -105,48 +102,26 @@ impl LoginApp {
issue: AuthIssueSession::Cookie, issue: AuthIssueSession::Cookie,
}, },
}; };
let authreq_jsvalue = serde_json::to_string(&authreq) let req_jsvalue = serde_json::to_string(&authreq)
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise authreq"); .expect_throw("Failed to serialise authreq");
let mut opts = RequestInit::new(); let (kopid, status, value, _) =
opts.method("POST"); do_request("/v1/auth", RequestMethod::POST, Some(req_jsvalue)).await?;
opts.mode(RequestMode::SameOrigin);
opts.credentials(RequestCredentials::SameOrigin);
opts.body(Some(&authreq_jsvalue));
let request = Request::new_with_str_and_init("/v1/auth", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value
.dyn_into()
.expect_throw("Invalid response type - auth_init::Response");
let status = resp.status();
let headers = resp.headers();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?; let state: AuthResponse = serde_wasm_bindgen::from_value(value)
let state: AuthResponse = serde_wasm_bindgen::from_value(jsval)
.expect_throw("Invalid response type - auth_init::AuthResponse"); .expect_throw("Invalid response type - auth_init::AuthResponse");
Ok(LoginAppMsg::Start(state)) Ok(LoginAppMsg::Start(state))
} else if status == 404 { } else if status == 404 {
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let text = JsFuture::from(resp.text()?).await?;
console::error!(format!( console::error!(format!(
"User not found: {:?}. Operation ID: {:?}", "User not found: {:?}. Operation ID: {:?}",
text, kopid value.as_string().unwrap_or_default(),
kopid
)); ));
Ok(LoginAppMsg::UnknownUser) Ok(LoginAppMsg::UnknownUser)
} else { } else {
let kopid = headers.get("x-kanidm-opid").ok().flatten(); let emsg = value.as_string().unwrap_or_default();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
Ok(LoginAppMsg::Error { emsg, kopid }) Ok(LoginAppMsg::Error { emsg, kopid })
} }
} }
@ -156,45 +131,23 @@ impl LoginApp {
let authreq_jsvalue = serde_json::to_string(&issue) let authreq_jsvalue = serde_json::to_string(&issue)
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise authreq"); .expect_throw("Failed to serialise authreq");
let url = "/v1/reauth";
let mut opts = RequestInit::new(); let (kopid, status, value, _) =
opts.method("POST"); do_request(url, RequestMethod::POST, Some(authreq_jsvalue)).await?;
opts.mode(RequestMode::SameOrigin);
opts.credentials(RequestCredentials::SameOrigin);
opts.body(Some(&authreq_jsvalue));
let request = Request::new_with_str_and_init("/v1/reauth", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value
.dyn_into()
.expect_throw("Invalid response type - reauth_init::Response");
let status = resp.status();
let headers = resp.headers();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?; let state: AuthResponse = serde_wasm_bindgen::from_value(value)
let state: AuthResponse = serde_wasm_bindgen::from_value(jsval)
.expect_throw("Invalid response type - auth_init::AuthResponse"); .expect_throw("Invalid response type - auth_init::AuthResponse");
Ok(LoginAppMsg::Next(state)) Ok(LoginAppMsg::Next(state))
} else if status == 404 { } else if status == 404 {
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let text = JsFuture::from(resp.text()?).await?;
console::error!(format!( console::error!(format!(
"User not found: {:?}. Operation ID: {:?}", "User not found: {:?}. Operation ID: {:?}",
text, kopid value.as_string(),
kopid
)); ));
Ok(LoginAppMsg::UnknownUser) Ok(LoginAppMsg::UnknownUser)
} else { } else {
let kopid = headers.get("x-kanidm-opid").ok().flatten(); let emsg = value.as_string().unwrap_or_default();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
Ok(LoginAppMsg::Error { emsg, kopid }) Ok(LoginAppMsg::Error { emsg, kopid })
} }
} }
@ -204,30 +157,11 @@ impl LoginApp {
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise authreq"); .expect_throw("Failed to serialise authreq");
let mut opts = RequestInit::new(); let (kopid, status, value, _) =
opts.method("POST"); do_request("/v1/auth", RequestMethod::POST, Some(authreq_jsvalue)).await?;
opts.mode(RequestMode::SameOrigin);
opts.credentials(RequestCredentials::SameOrigin);
opts.body(Some(&authreq_jsvalue));
let request = Request::new_with_str_and_init("/v1/auth", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set content-type header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value
.dyn_into()
.expect_throw("Invalid response type - auth_step::Response");
let status = resp.status();
let headers = resp.headers();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?; let state: AuthResponse = serde_wasm_bindgen::from_value(value)
let state: AuthResponse = serde_wasm_bindgen::from_value(jsval)
.map_err(|e| { .map_err(|e| {
console::error!(format!("auth_step::AuthResponse: {:?}", e)); console::error!(format!("auth_step::AuthResponse: {:?}", e));
e e
@ -235,9 +169,7 @@ impl LoginApp {
.expect_throw("Invalid response type - auth_step::AuthResponse"); .expect_throw("Invalid response type - auth_step::AuthResponse");
Ok(LoginAppMsg::Next(state)) Ok(LoginAppMsg::Next(state))
} else { } else {
let kopid = headers.get("x-kanidm-opid").ok().flatten(); let emsg = value.as_string()
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string()
.unwrap_or_else(|| "Unhandled error, please report this along with the operation ID below to your administrator. 😔".to_string()); .unwrap_or_else(|| "Unhandled error, please report this along with the operation ID below to your administrator. 😔".to_string());
Ok(LoginAppMsg::Error { emsg, kopid }) Ok(LoginAppMsg::Error { emsg, kopid })
} }
@ -247,6 +179,7 @@ impl LoginApp {
fn button_start_again(&self, ctx: &Context<Self>) -> VNode { fn button_start_again(&self, ctx: &Context<Self>) -> VNode {
html! { html! {
<div class="col-md-auto text-center"> <div class="col-md-auto text-center">
// TODO: this doesn't seem to work if you failed to login
<button type="button" class={CLASS_BUTTON_DARK} onclick={ ctx.link().callback(|_| LoginAppMsg::Restart) } >{" Start Again "}</button> <button type="button" class={CLASS_BUTTON_DARK} onclick={ ctx.link().callback(|_| LoginAppMsg::Restart) } >{" Start Again "}</button>
</div> </div>
} }

View file

@ -1,4 +1,3 @@
// use anyhow::Error;
use gloo::console; use gloo::console;
pub use kanidm_proto::oauth2::{ pub use kanidm_proto::oauth2::{
AccessTokenRequest, AccessTokenResponse, AuthorisationRequest, AuthorisationResponse, AccessTokenRequest, AccessTokenResponse, AuthorisationRequest, AuthorisationResponse,
@ -6,12 +5,12 @@ pub use kanidm_proto::oauth2::{
}; };
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt};
use wasm_bindgen_futures::JsFuture; use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestCredentials, RequestInit, RequestMode, RequestRedirect, Response}; use web_sys::{Request, RequestInit, RequestMode, RequestRedirect, Response};
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
use crate::error::*;
use crate::manager::Route; use crate::manager::Route;
use crate::{do_request, error::*, RequestMethod};
use crate::{models, utils}; use crate::{models, utils};
use std::collections::BTreeSet; use std::collections::BTreeSet;
@ -70,31 +69,15 @@ impl From<FetchError> for Oauth2Msg {
impl Oauth2App { impl Oauth2App {
async fn fetch_session_valid() -> Result<Oauth2Msg, FetchError> { async fn fetch_session_valid() -> Result<Oauth2Msg, FetchError> {
let mut opts = RequestInit::new(); let (kopid, status, value, _) =
opts.method("GET"); do_request("/v1/auth/valid", RequestMethod::GET, None).await?;
opts.mode(RequestMode::SameOrigin);
opts.credentials(RequestCredentials::SameOrigin);
let request = Request::new_with_str_and_init("/v1/auth/valid", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
if status == 200 { if status == 200 {
Ok(Oauth2Msg::TokenValid) Ok(Oauth2Msg::TokenValid)
} else if status == 401 { } else if status == 401 {
Ok(Oauth2Msg::LoginRequired) Ok(Oauth2Msg::LoginRequired)
} else { } else {
let headers = resp.headers(); let emsg = value.as_string().unwrap_or_default();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
// let jsval_json = JsFuture::from(resp.json()?).await?; // let jsval_json = JsFuture::from(resp.json()?).await?;
Ok(Oauth2Msg::Error { emsg, kopid }) Ok(Oauth2Msg::Error { emsg, kopid })
} }
@ -105,29 +88,15 @@ impl Oauth2App {
.map(|s| JsValue::from(&s)) .map(|s| JsValue::from(&s))
.expect_throw("Failed to serialise authreq"); .expect_throw("Failed to serialise authreq");
let mut opts = RequestInit::new(); let (kopid, status, value, headers) = do_request(
opts.method("POST"); "/oauth2/authorise",
opts.mode(RequestMode::SameOrigin); RequestMethod::POST,
opts.credentials(RequestCredentials::SameOrigin); Some(authreq_jsvalue),
)
opts.body(Some(&authreq_jsvalue)); .await?;
let request = Request::new_with_str_and_init("/oauth2/authorise", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
let headers = resp.headers();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?; let state: AuthorisationResponse = serde_wasm_bindgen::from_value(value)
let state: AuthorisationResponse = serde_wasm_bindgen::from_value(jsval)
.map_err(|e| { .map_err(|e| {
let e_msg = format!("serde error -> {:?}", e); let e_msg = format!("serde error -> {:?}", e);
console::error!(e_msg.as_str()); console::error!(e_msg.as_str());
@ -159,8 +128,7 @@ impl Oauth2App {
} else if status == 403 { } else if status == 403 {
Ok(Oauth2Msg::AccessDenied { kopid }) Ok(Oauth2Msg::AccessDenied { kopid })
} else { } else {
let text = JsFuture::from(resp.text()?).await?; let emsg = value.as_string().unwrap_or_default();
let emsg = text.as_string().unwrap_or_default();
Ok(Oauth2Msg::Error { emsg, kopid }) Ok(Oauth2Msg::Error { emsg, kopid })
} }
} }
@ -173,8 +141,7 @@ impl Oauth2App {
let mut opts = RequestInit::new(); let mut opts = RequestInit::new();
opts.method("POST"); opts.method("POST");
opts.mode(RequestMode::SameOrigin); opts.mode(RequestMode::SameOrigin);
opts.redirect(RequestRedirect::Manual); opts.redirect(RequestRedirect::Manual); // can't replace with do_request because of this
opts.credentials(RequestCredentials::SameOrigin);
opts.body(Some(&consentreq_jsvalue)); opts.body(Some(&consentreq_jsvalue));

View file

@ -1,10 +1,9 @@
use gloo::console; use gloo::console;
use gloo_net::http::Request;
use url::Url; use url::Url;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_bindgen::{JsCast, UnwrapThrowExt}; use wasm_bindgen::{JsCast, UnwrapThrowExt};
pub use web_sys::InputEvent; pub use web_sys::InputEvent;
use web_sys::{Document, HtmlElement, HtmlInputElement, RequestCredentials, RequestMode, Window}; use web_sys::{Document, HtmlElement, HtmlInputElement, Window};
use yew::virtual_dom::VNode; use yew::virtual_dom::VNode;
use yew::{html, Html}; use yew::{html, Html};
@ -94,14 +93,6 @@ pub fn do_footer() -> VNode {
} }
} }
/// Builds a request object to a server-local endpoint with the usual requirements
pub fn init_request(endpoint: &str) -> gloo_net::http::Request {
Request::new(endpoint)
.mode(RequestMode::SameOrigin)
.credentials(RequestCredentials::SameOrigin)
.header("content-type", "application/json")
}
pub fn do_alert_error(alert_title: &str, alert_message: Option<&str>) -> Html { pub fn do_alert_error(alert_title: &str, alert_message: Option<&str>) -> Html {
html! { html! {
<div class="container"> <div class="container">

View file

@ -4,11 +4,8 @@ use yew::prelude::*;
use crate::constants::{CSS_CARD, CSS_LINK_DARK_STRETCHED, CSS_PAGE_HEADER}; use crate::constants::{CSS_CARD, CSS_LINK_DARK_STRETCHED, CSS_PAGE_HEADER};
use crate::error::FetchError; use crate::error::FetchError;
use crate::utils; use crate::{do_request, RequestMethod};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestCredentials, RequestInit, RequestMode, Response};
use kanidm_proto::internal::AppLink; use kanidm_proto::internal::AppLink;
@ -182,33 +179,15 @@ impl AppsApp {
} }
async fn fetch_user_apps() -> Result<Msg, FetchError> { async fn fetch_user_apps() -> Result<Msg, FetchError> {
let mut opts = RequestInit::new(); let (kopid, status, value, _) =
opts.method("GET"); do_request("/v1/self/_applinks", RequestMethod::GET, None).await?;
opts.mode(RequestMode::SameOrigin);
opts.credentials(RequestCredentials::SameOrigin);
let request = Request::new_with_str_and_init("/v1/self/_applinks", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?; let apps: Vec<AppLink> = serde_wasm_bindgen::from_value(value)
let apps: Vec<AppLink> = serde_wasm_bindgen::from_value(jsval)
.expect_throw("Invalid response type - auth_init::AuthResponse"); .expect_throw("Invalid response type - auth_init::AuthResponse");
Ok(Msg::Ready { apps }) Ok(Msg::Ready { apps })
} else { } else {
let headers = resp.headers(); let emsg = value.as_string().unwrap_or_default();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }
} }

View file

@ -1,16 +1,14 @@
use gloo::console; use gloo::console;
use kanidm_proto::v1::{UiHint, UserAuthToken}; use kanidm_proto::v1::{UiHint, UserAuthToken};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use wasm_bindgen::{JsCast, UnwrapThrowExt}; use wasm_bindgen::UnwrapThrowExt;
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestCredentials, RequestInit, RequestMode, Response};
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
use crate::components::{admin_accounts, admin_groups, admin_menu, admin_oauth2}; use crate::components::{admin_accounts, admin_groups, admin_menu, admin_oauth2};
use crate::error::*;
use crate::manager::Route; use crate::manager::Route;
use crate::{models, utils}; use crate::models;
use crate::{do_request, error::*, RequestMethod};
mod apps; mod apps;
mod profile; mod profile;
@ -328,62 +326,25 @@ impl ViewsApp {
} }
async fn check_session_valid() -> Result<ViewsMsg, FetchError> { async fn check_session_valid() -> Result<ViewsMsg, FetchError> {
let mut opts = RequestInit::new(); let (kopid, status, value, _) =
opts.method("GET"); do_request("/v1/auth/valid", RequestMethod::GET, None).await?;
opts.mode(RequestMode::SameOrigin);
opts.credentials(RequestCredentials::SameOrigin);
let request = Request::new_with_str_and_init("/v1/auth/valid", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request))
.await
.map_err(|e| {
console::error!(&format!("fetch request failed {:?}", e));
e
})?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
if status == 200 { if status == 200 {
Ok(ViewsMsg::Verified) Ok(ViewsMsg::Verified)
} else if status == 401 { } else if status == 401 {
Ok(ViewsMsg::LogoutComplete) Ok(ViewsMsg::LogoutComplete)
} else { } else {
let headers = resp.headers(); let emsg = value.as_string().unwrap_or_default();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
Ok(ViewsMsg::Error { emsg, kopid }) Ok(ViewsMsg::Error { emsg, kopid })
} }
} }
async fn fetch_user_data() -> Result<ViewsMsg, FetchError> { async fn fetch_user_data() -> Result<ViewsMsg, FetchError> {
let mut opts = RequestInit::new(); let (kopid, status, value, _) =
opts.method("GET"); do_request("/v1/self/_uat", RequestMethod::GET, None).await?;
opts.mode(RequestMode::SameOrigin);
opts.credentials(RequestCredentials::SameOrigin);
let request = Request::new_with_str_and_init("/v1/self/_uat", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?; let uat: UserAuthToken = serde_wasm_bindgen::from_value(value)
let uat: UserAuthToken = serde_wasm_bindgen::from_value(jsval)
.map_err(|e| { .map_err(|e| {
let e_msg = format!("serde error -> {:?}", e); let e_msg = format!("serde error -> {:?}", e);
console::error!(e_msg.as_str()); console::error!(e_msg.as_str());
@ -392,39 +353,18 @@ impl ViewsApp {
Ok(ViewsMsg::ProfileInfoReceived { uat }) Ok(ViewsMsg::ProfileInfoReceived { uat })
} else { } else {
let headers = resp.headers(); let emsg = value.as_string().unwrap_or_default();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
Ok(ViewsMsg::Error { emsg, kopid }) Ok(ViewsMsg::Error { emsg, kopid })
} }
} }
async fn fetch_logout() -> Result<ViewsMsg, FetchError> { async fn fetch_logout() -> Result<ViewsMsg, FetchError> {
let mut opts = RequestInit::new(); let (kopid, status, value, _) = do_request("/v1/logout", RequestMethod::GET, None).await?;
opts.method("GET");
opts.mode(RequestMode::SameOrigin);
opts.credentials(RequestCredentials::SameOrigin);
let request = Request::new_with_str_and_init("/v1/logout", &opts)?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
if status == 200 { if status == 200 {
Ok(ViewsMsg::LogoutComplete) Ok(ViewsMsg::LogoutComplete)
} else { } else {
let headers = resp.headers(); let emsg = value.as_string().unwrap_or_default();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
Ok(ViewsMsg::Error { emsg, kopid }) Ok(ViewsMsg::Error { emsg, kopid })
} }
} }

View file

@ -2,9 +2,7 @@
use gloo::console; use gloo::console;
use kanidm_proto::v1::{CUSessionToken, CUStatus, UiHint, UserAuthToken}; use kanidm_proto::v1::{CUSessionToken, CUStatus, UiHint, UserAuthToken};
use time::format_description::well_known::Rfc3339; use time::format_description::well_known::Rfc3339;
use wasm_bindgen::{JsCast, UnwrapThrowExt}; use wasm_bindgen::UnwrapThrowExt;
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestCredentials, RequestInit, RequestMode, Response};
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
@ -13,8 +11,8 @@ use crate::components::create_reset_code::CreateResetCode;
use crate::constants::CSS_PAGE_HEADER; use crate::constants::CSS_PAGE_HEADER;
use crate::error::*; use crate::error::*;
use crate::manager::Route; use crate::manager::Route;
use crate::models;
use crate::views::{ViewProps, ViewRoute}; use crate::views::{ViewProps, ViewRoute};
use crate::{models, utils};
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
// Page state // Page state
@ -240,35 +238,16 @@ impl ProfileApp {
} }
async fn request_credential_update(id: String) -> Result<Msg, FetchError> { async fn request_credential_update(id: String) -> Result<Msg, FetchError> {
let mut opts = RequestInit::new();
opts.method("GET");
opts.mode(RequestMode::SameOrigin);
opts.credentials(RequestCredentials::SameOrigin);
let uri = format!("/v1/person/{}/_credential/_update", id); let uri = format!("/v1/person/{}/_credential/_update", id);
let (kopid, status, value, _headers) =
let request = Request::new_with_str_and_init(uri.as_str(), &opts)?; crate::do_request(&uri, crate::RequestMethod::GET, None).await?;
request
.headers()
.set("content-type", "application/json")
.expect_throw("failed to set header");
let window = utils::window();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
let status = resp.status();
if status == 200 { if status == 200 {
let jsval = JsFuture::from(resp.json()?).await?;
let (token, status): (CUSessionToken, CUStatus) = let (token, status): (CUSessionToken, CUStatus) =
serde_wasm_bindgen::from_value(jsval).expect_throw("Invalid response type"); serde_wasm_bindgen::from_value(value).expect_throw("Invalid response type");
Ok(Msg::BeginCredentialUpdate { token, status }) Ok(Msg::BeginCredentialUpdate { token, status })
} else { } else {
let headers = resp.headers(); let emsg = value.as_string().unwrap_or_default();
let kopid = headers.get("x-kanidm-opid").ok().flatten();
let text = JsFuture::from(resp.text()?).await?;
let emsg = text.as_string().unwrap_or_default();
// let jsval_json = JsFuture::from(resp.json()?).await?; // let jsval_json = JsFuture::from(resp.json()?).await?;
Ok(Msg::Error { emsg, kopid }) Ok(Msg::Error { emsg, kopid })
} }

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View file

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View file

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View file

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View file

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View file

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -3,39 +3,39 @@ name = "kanidm-ipa-sync"
description = "Kanidm Client Tools" description = "Kanidm Client Tools"
documentation = "https://kanidm.github.io/kanidm/stable/" documentation = "https://kanidm.github.io/kanidm/stable/"
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[dependencies] [dependencies]
base64urlsafedata.workspace = true base64urlsafedata = { workspace = true }
clap = { workspace = true, features = ["derive", "env"] } clap = { workspace = true, features = ["derive", "env"] }
chrono.workspace = true chrono = { workspace = true }
cron.workspace = true cron = { workspace = true }
kanidm_client.workspace = true kanidm_client = { workspace = true }
kanidm_proto.workspace = true kanidm_proto = { workspace = true }
tokio = { workspace = true, features = ["rt", "macros", "net"] } tokio = { workspace = true, features = ["rt", "macros", "net"] }
tracing.workspace = true tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] } tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] }
ldap3_client.workspace = true ldap3_client = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true serde_json = { workspace = true }
toml.workspace = true toml = { workspace = true }
url = { workspace = true, features = ["serde"] } url = { workspace = true, features = ["serde"] }
uuid = { workspace = true, features = ["serde"] } uuid = { workspace = true, features = ["serde"] }
# For file metadata, should this me moved out? # For file metadata, should this me moved out?
kanidmd_lib.workspace = true kanidmd_lib = { workspace = true }
[target.'cfg(target_family = "unix")'.dependencies] [target.'cfg(target_family = "unix")'.dependencies]
users.workspace = true users = { workspace = true }
[build-dependencies] [build-dependencies]
clap = { workspace = true, features = ["derive"] } clap = { workspace = true, features = ["derive"] }
clap_complete.workspace = true clap_complete = { workspace = true }

View file

@ -3,39 +3,39 @@ name = "kanidm-ldap-sync"
description = "Kanidm Client Tools" description = "Kanidm Client Tools"
documentation = "https://kanidm.github.io/kanidm/stable/" documentation = "https://kanidm.github.io/kanidm/stable/"
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[dependencies] [dependencies]
base64urlsafedata.workspace = true base64urlsafedata = { workspace = true }
clap = { workspace = true, features = ["derive", "env"] } clap = { workspace = true, features = ["derive", "env"] }
chrono.workspace = true chrono = { workspace = true }
cron.workspace = true cron = { workspace = true }
kanidm_client.workspace = true kanidm_client = { workspace = true }
kanidm_proto.workspace = true kanidm_proto = { workspace = true }
tokio = { workspace = true, features = ["rt", "macros", "net"] } tokio = { workspace = true, features = ["rt", "macros", "net"] }
tracing.workspace = true tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] } tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] }
ldap3_client.workspace = true ldap3_client = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true serde_json = { workspace = true }
toml.workspace = true toml = { workspace = true }
url = { workspace = true, features = ["serde"] } url = { workspace = true, features = ["serde"] }
uuid = { workspace = true, features = ["serde"] } uuid = { workspace = true, features = ["serde"] }
# For file metadata, should this me moved out? # For file metadata, should this me moved out?
kanidmd_lib.workspace = true kanidmd_lib = { workspace = true }
[target.'cfg(target_family = "unix")'.dependencies] [target.'cfg(target_family = "unix")'.dependencies]
users.workspace = true users = { workspace = true }
[build-dependencies] [build-dependencies]
clap = { workspace = true, features = ["derive"] } clap = { workspace = true, features = ["derive"] }
clap_complete.workspace = true clap_complete = { workspace = true }

View file

@ -3,42 +3,42 @@ name = "orca"
description = "Orca - load testing for LDAP and Kanidm" description = "Orca - load testing for LDAP and Kanidm"
documentation = "https://docs.rs/kanidm/latest/kanidm/" documentation = "https://docs.rs/kanidm/latest/kanidm/"
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[[bin]] [[bin]]
name = "orca" name = "orca"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
clap.workspace = true clap = { workspace = true }
crossbeam.workspace = true crossbeam = { workspace = true }
csv.workspace = true csv = { workspace = true }
dialoguer.workspace = true dialoguer = { workspace = true }
futures-util = { workspace = true, features = ["sink"] } futures-util = { workspace = true, features = ["sink"] }
kanidm_client.workspace = true kanidm_client = { workspace = true }
kanidm_proto.workspace = true kanidm_proto = { workspace = true }
ldap3_proto.workspace = true ldap3_proto = { workspace = true }
mathru.workspace = true mathru = { workspace = true }
openssl.workspace = true openssl = { workspace = true }
rand.workspace = true rand = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true serde_json = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread"] } tokio = { workspace = true, features = ["rt-multi-thread"] }
tokio-openssl.workspace = true tokio-openssl = { workspace = true }
tokio-util = { workspace = true, features = ["codec"] } tokio-util = { workspace = true, features = ["codec"] }
toml.workspace = true toml = { workspace = true }
tracing.workspace = true tracing = { workspace = true }
tracing-subscriber.workspace = true tracing-subscriber = { workspace = true }
uuid = { workspace = true, features = ["serde", "v4" ] } uuid = { workspace = true, features = ["serde", "v4" ] }
[target.'cfg(not(target_family = "windows"))'.dependencies] [target.'cfg(not(target_family = "windows"))'.dependencies]
tikv-jemallocator.workspace = true tikv-jemallocator = { workspace = true }
[build-dependencies] [build-dependencies]
profiles.workspace = true profiles = { workspace = true }

View file

@ -3,13 +3,13 @@ name = "kanidm_unix_int"
description = "Kanidm Unix Integration Clients" description = "Kanidm Unix Integration Clients"
documentation = "https://docs.rs/kanidm/latest/kanidm/" documentation = "https://docs.rs/kanidm/latest/kanidm/"
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[features] [features]
default = ["unix"] default = ["unix"]
@ -42,40 +42,40 @@ name = "kanidm_unix_common"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
bytes.workspace = true bytes = { workspace = true }
clap = { workspace = true, features = ["derive", "env"] } clap = { workspace = true, features = ["derive", "env"] }
csv.workspace = true csv = { workspace = true }
futures.workspace = true futures = { workspace = true }
libc.workspace = true libc = { workspace = true }
libsqlite3-sys.workspace = true libsqlite3-sys = { workspace = true }
lru.workspace = true lru = { workspace = true }
kanidm_client.workspace = true kanidm_client = { workspace = true }
kanidm_proto.workspace = true kanidm_proto = { workspace = true }
kanidm_lib_crypto.workspace = true kanidm_lib_crypto = { workspace = true }
kanidm_lib_file_permissions.workspace = true kanidm_lib_file_permissions = { workspace = true }
notify-debouncer-full.workspace = true notify-debouncer-full = { workspace = true }
rpassword.workspace = true rpassword = { workspace = true }
rusqlite.workspace = true rusqlite = { workspace = true }
selinux = { workspace = true, optional = true } selinux = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true serde_json = { workspace = true }
sketching.workspace = true sketching = { workspace = true }
toml.workspace = true toml = { workspace = true }
tokio = { workspace = true, features = ["rt", "fs", "macros", "sync", "time", "net", "io-util"] } tokio = { workspace = true, features = ["rt", "fs", "macros", "sync", "time", "net", "io-util"] }
tokio-util = { workspace = true, features = ["codec"] } tokio-util = { workspace = true, features = ["codec"] }
tracing.workspace = true tracing = { workspace = true }
tss-esapi = { workspace = true, optional = true } tss-esapi = { workspace = true, optional = true }
reqwest = { workspace = true, default-features = false } reqwest = { workspace = true, default-features = false }
walkdir.workspace = true walkdir = { workspace = true }
[target.'cfg(not(target_family = "windows"))'.dependencies] [target.'cfg(not(target_family = "windows"))'.dependencies]
users.workspace = true users = { workspace = true }
[dev-dependencies] [dev-dependencies]
kanidmd_core.workspace = true kanidmd_core = { workspace = true }
[build-dependencies] [build-dependencies]
clap = { workspace = true, features = ["derive"] } clap = { workspace = true, features = ["derive"] }
clap_complete.workspace = true clap_complete = { workspace = true }
profiles.workspace = true profiles = { workspace = true }

View file

@ -2,13 +2,13 @@
name = "pam_kanidm" name = "pam_kanidm"
links = "pam" links = "pam"
version.workspace = true version = { workspace = true }
authors.workspace = true authors = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
edition.workspace = true edition = { workspace = true }
license.workspace = true license = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
repository.workspace = true repository = { workspace = true }
[lib] [lib]
name = "pam_kanidm" name = "pam_kanidm"
@ -16,8 +16,8 @@ crate-type = [ "cdylib" ]
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
kanidm_unix_int.workspace = true kanidm_unix_int = { workspace = true }
libc.workspace = true libc = { workspace = true }
[build-dependencies] [build-dependencies]
pkg-config.workspace = true pkg-config = { workspace = true }